From 0b6257796a4db2df37e566118d8e54ca07baa858 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 17 Feb 2025 15:57:47 +0300 Subject: [PATCH 01/54] Updated on 2026-08-14 --- .../main/java/com/tangem/tap/MainActivity.kt | 4 - .../tangem/tap/routing/utils/ChildFactory.kt | 32 +++++- features/send/api/build.gradle.kts | 7 ++ .../tangem/features/send/api/SendComponent.kt | 20 ++++ .../send/api/navigation/SendRouter.kt | 8 -- features/send/impl/build.gradle.kts | 1 + .../send/impl/DefaultSendComponent.kt | 35 ++++++ .../features/send/impl/di/SendModule.kt | 38 +++++++ .../features/send/impl/di/SendRouterModule.kt | 25 ----- .../send/impl/navigation/DefaultSendRouter.kt | 9 +- .../send/impl/navigation/InnerSendRouter.kt | 3 +- .../send/impl/presentation/SendFragment.kt | 78 -------------- .../{viewmodel => model}/SendClickIntents.kt | 2 +- .../SendViewModel.kt => model/SendModel.kt} | 101 +++++++++--------- .../state/SendEventStateFactory.kt | 2 +- .../presentation/state/SendStateFactory.kt | 2 +- .../impl/presentation/state/SendUiState.kt | 2 +- .../impl/presentation/state/StateRouter.kt | 2 +- .../state/confirm/SendNotificationFactory.kt | 2 +- .../presentation/state/fee/FeeConverter.kt | 2 +- .../state/fee/FeeNotificationFactory.kt | 2 +- .../presentation/state/fee/FeeStateFactory.kt | 2 +- .../state/fee/SendFeeCustomFieldConverter.kt | 2 +- .../fee/custom/BitcoinCustomFeeConverter.kt | 2 +- .../fee/custom/EthereumCustomFeeConverter.kt | 2 +- .../custom/EthereumEIPCustomFeeConverter.kt | 2 +- .../EthereumLegacyCustomFeeConverter.kt | 2 +- .../fee/custom/KaspaCustomFeeConverter.kt | 2 +- .../state/previewdata/SendClickIntentsStub.kt | 2 +- .../SendRecipientAddressFieldConverter.kt | 2 +- .../SendRecipientMemoFieldConverter.kt | 2 +- .../recipient/SendRecipientStateConverter.kt | 2 +- .../ui/fee/SendSpeedAndFeeContent.kt | 2 +- .../presentation/ui/fee/SendSpeedSelector.kt | 2 +- .../ui/recipient/SendRecipientContent.kt | 2 +- 35 files changed, 204 insertions(+), 201 deletions(-) create mode 100644 features/send/api/src/main/kotlin/com/tangem/features/send/api/SendComponent.kt delete mode 100644 features/send/api/src/main/kotlin/com/tangem/features/send/api/navigation/SendRouter.kt create mode 100644 features/send/impl/src/main/java/com/tangem/features/send/impl/DefaultSendComponent.kt create mode 100644 features/send/impl/src/main/java/com/tangem/features/send/impl/di/SendModule.kt delete mode 100644 features/send/impl/src/main/java/com/tangem/features/send/impl/di/SendRouterModule.kt delete mode 100644 features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/SendFragment.kt rename features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/{viewmodel => model}/SendClickIntents.kt (96%) rename features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/{viewmodel/SendViewModel.kt => model/SendModel.kt} (94%) diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 0e5b92b3ea..c96a550db8 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -64,7 +64,6 @@ import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnaly 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 @@ -147,9 +146,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac @Inject lateinit var walletConnectInteractor: WalletConnectInteractor - @Inject - lateinit var sendRouter: SendRouter - @Inject lateinit var qrScanningRouter: QrScanningRouter diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index ad15758549..10fc7890b2 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -14,7 +14,7 @@ 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.send.api.SendComponent import com.tangem.features.swap.SwapComponent import com.tangem.features.staking.api.StakingComponent import com.tangem.features.tester.api.TesterRouter @@ -58,9 +58,9 @@ 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, @@ -235,10 +235,23 @@ internal class ChildFactory @Inject constructor( componentFactory = swapComponentFactory, ) } + 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.AccessCodeRecovery, is AppRoute.AppCurrencySelector, is AppRoute.SaveWallet, - is AppRoute.Send, is AppRoute.AppSettings, is AppRoute.CardSettings, is AppRoute.DetailsSecurity, @@ -278,7 +291,18 @@ internal class ChildFactory @Inject constructor( 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() }) diff --git a/features/send/api/build.gradle.kts b/features/send/api/build.gradle.kts index eb561fcf20..b5867a273b 100644 --- a/features/send/api/build.gradle.kts +++ b/features/send/api/build.gradle.kts @@ -10,6 +10,13 @@ android { } dependencies { + /** Core */ + implementation(projects.core.decompose) + implementation(projects.core.ui) + + /** Domain models */ + implementation(projects.domain.wallets.models) + implementation(projects.domain.tokens.models) /** AndroidX */ implementation(deps.androidx.fragment.ktx) diff --git a/features/send/api/src/main/kotlin/com/tangem/features/send/api/SendComponent.kt b/features/send/api/src/main/kotlin/com/tangem/features/send/api/SendComponent.kt new file mode 100644 index 0000000000..987d2e79dc --- /dev/null +++ b/features/send/api/src/main/kotlin/com/tangem/features/send/api/SendComponent.kt @@ -0,0 +1,20 @@ +package com.tangem.features.send.api + +import com.tangem.core.decompose.factory.ComponentFactory +import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWalletId + +interface SendComponent : ComposableContentComponent { + + data class Params( + val userWalletId: UserWalletId, + val currency: CryptoCurrency, + val transactionId: String? = null, + val amount: String? = null, + val tag: String? = null, + val destinationAddress: String? = null, + ) + + interface Factory : ComponentFactory +} \ No newline at end of file diff --git a/features/send/api/src/main/kotlin/com/tangem/features/send/api/navigation/SendRouter.kt b/features/send/api/src/main/kotlin/com/tangem/features/send/api/navigation/SendRouter.kt deleted file mode 100644 index 286f908ad8..0000000000 --- a/features/send/api/src/main/kotlin/com/tangem/features/send/api/navigation/SendRouter.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.features.send.api.navigation - -import androidx.fragment.app.Fragment - -interface SendRouter { - - fun getEntryFragment(): Fragment -} \ No newline at end of file diff --git a/features/send/impl/build.gradle.kts b/features/send/impl/build.gradle.kts index 176864f05a..2126c0ac09 100644 --- a/features/send/impl/build.gradle.kts +++ b/features/send/impl/build.gradle.kts @@ -50,6 +50,7 @@ dependencies { implementation(projects.core.analytics) implementation(projects.core.analytics.models) implementation(projects.core.datasource) + implementation(projects.core.decompose) /** Common */ implementation(projects.common.ui) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/DefaultSendComponent.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/DefaultSendComponent.kt new file mode 100644 index 0000000000..e08ff5f208 --- /dev/null +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/DefaultSendComponent.kt @@ -0,0 +1,35 @@ +package com.tangem.features.send.impl + +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.features.send.api.SendComponent +import com.tangem.features.send.impl.presentation.model.SendModel +import com.tangem.features.send.impl.presentation.ui.SendScreen +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +internal class DefaultSendComponent @AssistedInject constructor( + @Assisted appComponentContext: AppComponentContext, + @Assisted params: SendComponent.Params, +) : SendComponent, AppComponentContext by appComponentContext { + + private val model: SendModel = getOrCreateModel(params) + + @Composable + override fun Content(modifier: Modifier) { + val currentState = model.stateRouter.currentState.collectAsStateWithLifecycle() + val uiState by model.uiState.collectAsStateWithLifecycle() + + SendScreen(uiState, currentState.value) + } + + @AssistedFactory + interface Factory : SendComponent.Factory { + override fun create(context: AppComponentContext, params: SendComponent.Params): DefaultSendComponent + } +} \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/di/SendModule.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/di/SendModule.kt new file mode 100644 index 0000000000..da5936ec7d --- /dev/null +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/di/SendModule.kt @@ -0,0 +1,38 @@ +package com.tangem.features.send.impl.di + +import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.DecomposeComponent +import com.tangem.core.decompose.model.Model +import com.tangem.features.send.api.SendComponent +import com.tangem.features.send.impl.DefaultSendComponent +import com.tangem.features.send.impl.navigation.DefaultSendRouter +import com.tangem.features.send.impl.navigation.InnerSendRouter +import com.tangem.features.send.impl.presentation.model.SendModel +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 SendModule { + + @Binds + fun bindComponentFactory(factory: DefaultSendComponent.Factory): SendComponent.Factory + + @Binds + @IntoMap + @ClassKey(SendModel::class) + fun bindModel(model: SendModel): Model +} + +@Module +@InstallIn(DecomposeComponent::class) +internal interface SendModelModule { + + @Binds + @ComponentScoped + fun bindRouter(router: DefaultSendRouter): InnerSendRouter +} \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/di/SendRouterModule.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/di/SendRouterModule.kt deleted file mode 100644 index b99742c742..0000000000 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/di/SendRouterModule.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.tangem.features.send.impl.di - -import com.tangem.common.routing.AppRouter -import com.tangem.core.navigation.url.UrlOpener -import com.tangem.features.send.api.navigation.SendRouter -import com.tangem.features.send.impl.navigation.DefaultSendRouter -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.components.ActivityComponent -import dagger.hilt.android.scopes.ActivityScoped - -/** - * DI module provides implementation of [SendRouter] - */ -@Module -@InstallIn(ActivityComponent::class) -internal object SendRouterModule { - - @Provides - @ActivityScoped - fun provideSendRouter(appRouter: AppRouter, urlOpener: UrlOpener): SendRouter { - return DefaultSendRouter(appRouter, urlOpener) - } -} \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/navigation/DefaultSendRouter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/navigation/DefaultSendRouter.kt index ed9f1f7b14..fabef6c208 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/navigation/DefaultSendRouter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/navigation/DefaultSendRouter.kt @@ -1,21 +1,20 @@ package com.tangem.features.send.impl.navigation -import androidx.fragment.app.Fragment import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRouter +import com.tangem.core.decompose.di.ComponentScoped import com.tangem.core.navigation.url.UrlOpener import com.tangem.domain.qrscanning.models.SourceType import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.features.send.impl.presentation.SendFragment +import javax.inject.Inject -internal class DefaultSendRouter( +@ComponentScoped +internal class DefaultSendRouter @Inject constructor( private val router: AppRouter, private val urlOpener: UrlOpener, ) : InnerSendRouter { - override fun getEntryFragment(): Fragment = SendFragment.create() - override fun openUrl(url: String) { urlOpener.openUrl(url) } diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/navigation/InnerSendRouter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/navigation/InnerSendRouter.kt index f061eaba01..9774e13bfe 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/navigation/InnerSendRouter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/navigation/InnerSendRouter.kt @@ -2,9 +2,8 @@ package com.tangem.features.send.impl.navigation import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.features.send.api.navigation.SendRouter -interface InnerSendRouter : SendRouter { +interface InnerSendRouter { /** Open website by [url] */ fun openUrl(url: String) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/SendFragment.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/SendFragment.kt deleted file mode 100644 index 48899c5eb3..0000000000 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/SendFragment.kt +++ /dev/null @@ -1,78 +0,0 @@ -package com.tangem.features.send.impl.presentation - -import android.os.Bundle -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.AppRoute -import com.tangem.common.routing.AppRouter -import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.ui.UiDependencies -import com.tangem.core.ui.screen.ComposeFragment -import com.tangem.features.send.api.navigation.SendRouter -import com.tangem.features.send.impl.navigation.InnerSendRouter -import com.tangem.features.send.impl.presentation.state.StateRouter -import com.tangem.features.send.impl.presentation.ui.SendScreen -import com.tangem.features.send.impl.presentation.viewmodel.SendViewModel -import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject - -/** - * Send fragment - */ -@AndroidEntryPoint -internal class SendFragment : ComposeFragment() { - - @Inject - override lateinit var uiDependencies: UiDependencies - - @Inject - lateinit var router: SendRouter - - @Inject - lateinit var appRouter: AppRouter - - @Inject - lateinit var analyticsEventsHandler: AnalyticsEventHandler - - private val viewModel by viewModels() - private val innerSendRouter: InnerSendRouter - get() = requireNotNull(router as? InnerSendRouter) { - "innerSendRouter should be instance of InnerSendRouter" - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - lifecycle.addObserver(viewModel) - - val isEditingDisabled = arguments?.getString(AppRoute.Send.TRANSACTION_ID_KEY) != null - viewModel.setRouter( - innerSendRouter, - StateRouter( - appRouter = appRouter, - isEditingDisabled = isEditingDisabled, - analyticsEventsHandler = analyticsEventsHandler, - ), - ) - } - - @Composable - override fun ScreenContent(modifier: Modifier) { - val currentState = viewModel.stateRouter.currentState.collectAsStateWithLifecycle() - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - - SendScreen(uiState, currentState.value) - } - - override fun onDestroy() { - lifecycle.removeObserver(viewModel) - super.onDestroy() - } - - companion object { - /** Create send fragment instance */ - fun create(): SendFragment = SendFragment() - } -} \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendClickIntents.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendClickIntents.kt similarity index 96% rename from features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendClickIntents.kt rename to features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendClickIntents.kt index e77536f76c..8ec20b06ce 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendClickIntents.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendClickIntents.kt @@ -1,4 +1,4 @@ -package com.tangem.features.send.impl.presentation.viewmodel +package com.tangem.features.send.impl.presentation.model import com.tangem.common.ui.amountScreen.AmountScreenClickIntents import com.tangem.common.ui.notifications.NotificationUM diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendModel.kt similarity index 94% rename from features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt rename to features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendModel.kt index 945c953dba..6c91254744 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendModel.kt @@ -1,20 +1,21 @@ -package com.tangem.features.send.impl.presentation.viewmodel +package com.tangem.features.send.impl.presentation.model -import android.os.Bundle import android.os.SystemClock -import androidx.lifecycle.* +import androidx.compose.runtime.Stable import arrow.core.Either import arrow.core.getOrElse import arrow.core.left import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.TransactionData import com.tangem.blockchain.common.transaction.TransactionFee -import com.tangem.common.routing.AppRoute -import com.tangem.common.routing.bundle.unbundle +import com.tangem.common.routing.AppRouter import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary import com.tangem.common.ui.notifications.NotificationUM import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.model.Model +import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.navigation.share.ShareManager import com.tangem.core.ui.utils.parseBigDecimal import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase @@ -47,6 +48,7 @@ import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.domain.wallets.usecase.GetWalletsUseCase +import com.tangem.features.send.api.SendComponent import com.tangem.features.send.impl.navigation.InnerSendRouter import com.tangem.features.send.impl.presentation.analytics.EnterAddressSource import com.tangem.features.send.impl.presentation.analytics.SendAnalyticEvents @@ -63,7 +65,6 @@ import com.tangem.utils.Provider import com.tangem.utils.coroutines.* import com.tangem.utils.extensions.orZero import com.tangem.utils.extensions.stripZeroPlainString -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.* import kotlinx.coroutines.flow.* import timber.log.Timber @@ -73,9 +74,10 @@ import javax.inject.Inject import kotlin.properties.Delegates @Suppress("LongParameterList", "TooManyFunctions", "LargeClass") -@HiltViewModel -internal class SendViewModel @Inject constructor( - private val dispatchers: CoroutineDispatcherProvider, +@Stable +@ComponentScoped +internal class SendModel @Inject constructor( + override val dispatchers: CoroutineDispatcherProvider, private val getUserWalletUseCase: GetUserWalletUseCase, private val getCryptoCurrencyStatusSyncUseCase: GetCryptoCurrencyStatusSyncUseCase, private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, @@ -109,31 +111,31 @@ internal class SendViewModel @Inject constructor( private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, private val shareManager: ShareManager, @DelayedWork private val coroutineScope: CoroutineScope, + private val innerRouter: InnerSendRouter, + private val appRouter: AppRouter, + paramsContainer: ParamsContainer, validateTransactionUseCase: ValidateTransactionUseCase, getCurrencyCheckUseCase: GetCurrencyCheckUseCase, isFeeApproximateUseCase: IsFeeApproximateUseCase, getBalanceNotEnoughForFeeWarningUseCase: GetBalanceNotEnoughForFeeWarningUseCase, - savedStateHandle: SavedStateHandle, -) : ViewModel(), DefaultLifecycleObserver, SendClickIntents { +) : Model(), SendClickIntents { - private val userWalletId: UserWalletId = savedStateHandle.get(AppRoute.Send.USER_WALLET_ID_KEY) - ?.unbundle(UserWalletId.serializer()) - ?: error("This screen can't open without `UserWalletId`") + private val params = paramsContainer.require() - private val cryptoCurrency: CryptoCurrency = savedStateHandle.get(AppRoute.Send.CRYPTO_CURRENCY_KEY) - ?.unbundle(CryptoCurrency.serializer()) - ?: error("This screen can't open without `CryptoCurrency`") - - private val transactionId: String? = savedStateHandle[AppRoute.Send.TRANSACTION_ID_KEY] - private val amount: String? = savedStateHandle[AppRoute.Send.AMOUNT_KEY] - private val destinationAddress: String? = savedStateHandle[AppRoute.Send.DESTINATION_ADDRESS_KEY] - private val memo: String? = savedStateHandle[AppRoute.Send.TAG_KEY] + private val userWalletId: UserWalletId = params.userWalletId + private val cryptoCurrency: CryptoCurrency = params.currency + private val transactionId: String? = params.transactionId + private val amount: String? = params.amount + private val destinationAddress: String? = params.destinationAddress + private val memo: String? = params.tag private val selectedAppCurrencyFlow: StateFlow = createSelectedAppCurrencyFlow() - private var innerRouter: InnerSendRouter by Delegates.notNull() - var stateRouter: StateRouter by Delegates.notNull() - private set + val stateRouter = StateRouter( + appRouter = appRouter, + isEditingDisabled = transactionId != null, + analyticsEventsHandler = analyticsEventHandler, + ) private val stateFactory = SendStateFactory( clickIntents = this, @@ -234,33 +236,26 @@ internal class SendViewModel @Inject constructor( subscribeOnCurrencyStatusUpdates() subscribeOnBalanceHidden() getTapHelpPreviewAvailability() - } - override fun onCreate(owner: LifecycleOwner) { onStateActive() } - override fun onCleared() { - super.onCleared() + override fun onDestroy() { + super.onDestroy() balanceHidingJobHolder.cancel() balanceJobHolder.cancel() stateRouter.clear() } - fun setRouter(router: InnerSendRouter, stateRouter: StateRouter) { - innerRouter = router - this.stateRouter = stateRouter - } - private fun subscribeOnQRScannerResult() { listenToQrScanningUseCase(SourceType.SEND) .getOrElse { emptyFlow() } .onEach(::onQrCodeScanned) - .launchIn(viewModelScope) + .launchIn(modelScope) } private fun subscribeOnCurrencyStatusUpdates() { - viewModelScope.launch { + modelScope.launch { getUserWalletUseCase(userWalletId).fold( ifRight = { wallet -> userWallet = wallet @@ -289,7 +284,7 @@ internal class SendViewModel @Inject constructor( .onEach { uiState.value = stateFactory.getOnHideBalanceState(isBalanceHidden = it.isBalanceHidden) } - .launchIn(viewModelScope) + .launchIn(modelScope) .saveIn(balanceHidingJobHolder) } @@ -310,7 +305,7 @@ internal class SendViewModel @Inject constructor( } private fun getTapHelpPreviewAvailability() { - viewModelScope.launch { + modelScope.launch { isTapHelpPreviewEnabled = isSendTapHelpEnabledUseCase().getOrElse { false } } } @@ -362,7 +357,7 @@ internal class SendViewModel @Inject constructor( maybeAppCurrency.getOrElse { AppCurrency.Default } } .stateIn( - scope = viewModelScope, + scope = modelScope, started = SharingStarted.Eagerly, initialValue = AppCurrency.Default, ) @@ -395,13 +390,13 @@ internal class SendViewModel @Inject constructor( private fun getWalletsAndRecent() { getUserWallets() - viewModelScope.launch { + modelScope.launch { getTxHistory() } } private fun getUserWallets() { - viewModelScope.launch { + modelScope.launch { runCatching { waitForDelay(delay = RECENT_LOAD_DELAY) { getWalletsUseCase.invokeSync() @@ -466,7 +461,7 @@ internal class SendViewModel @Inject constructor( else -> Unit } } - .launchIn(viewModelScope) + .launchIn(modelScope) } private fun updateNotifications() { @@ -475,7 +470,7 @@ internal class SendViewModel @Inject constructor( .distinctUntilChanged() .onEach { uiState.value = stateFactory.getSendNotificationState(notifications = it) } .flowOn(dispatchers.main) - .launchIn(viewModelScope) + .launchIn(modelScope) .saveIn(sendNotificationsJobHolder) } @@ -485,7 +480,7 @@ internal class SendViewModel @Inject constructor( .distinctUntilChanged() .onEach { uiState.value = feeStateFactory.getFeeNotificationState(notifications = it) } .flowOn(dispatchers.main) - .launchIn(viewModelScope) + .launchIn(modelScope) .saveIn(feeNotificationsJobHolder) } @@ -573,7 +568,7 @@ internal class SendViewModel @Inject constructor( val cardInfo = getCardInfoUseCase(userWallet.scanResponse).getOrNull() ?: return - viewModelScope.launch { + modelScope.launch { sendFeedbackEmailUseCase(type = FeedbackEmailType.TransactionSendingProblem(cardInfo = cardInfo)) } } @@ -615,7 +610,7 @@ internal class SendViewModel @Inject constructor( } private fun cancelFeeRequest() { - viewModelScope.launch { + modelScope.launch { feeJobHolder.cancel() } } @@ -660,7 +655,7 @@ internal class SendViewModel @Inject constructor( // region recipient state clicks override fun onRecipientAddressValueChange(value: String, type: EnterAddressSource?) { - viewModelScope.launch { + modelScope.launch { if (!checkIfXrpAddressValue(value)) { uiState.value = recipientStateFactory.onRecipientAddressValueChange(value, isValuePasted = type != null) uiState.value = recipientStateFactory.getOnRecipientAddressValidationStarted() @@ -680,7 +675,7 @@ internal class SendViewModel @Inject constructor( } override fun onRecipientMemoValueChange(value: String, isValuePasted: Boolean) { - viewModelScope.launch { + modelScope.launch { if (!checkIfXrpAddressValue(value)) { uiState.value = recipientStateFactory.getOnRecipientMemoValueChange(value, isValuePasted) uiState.value = recipientStateFactory.getOnRecipientAddressValidationStarted() @@ -758,7 +753,7 @@ internal class SendViewModel @Inject constructor( } private fun loadFee() { - viewModelScope.launch { + modelScope.launch { val isShowStatus = uiState.value.feeState?.fee == null if (isShowStatus) { uiState.value = feeStateFactory.onFeeOnLoadingState() @@ -911,7 +906,7 @@ internal class SendViewModel @Inject constructor( reduceAmountBy = uiState.value.sendState?.reduceAmountBy ?: BigDecimal.ZERO, ) - viewModelScope.launch { + modelScope.launch { createTransactionUseCase( amount = receivingAmount.convertToSdkAmount(cryptoCurrency), fee = fee, @@ -969,7 +964,7 @@ internal class SendViewModel @Inject constructor( val receivingUserWallet = userWallets.firstOrNull { it.address == destinationAddress } ?: return - viewModelScope.launch { + modelScope.launch { addCryptoCurrenciesUseCase( userWalletId = receivingUserWallet.userWalletId, cryptoCurrency = cryptoCurrency, @@ -1031,7 +1026,7 @@ internal class SendViewModel @Inject constructor( val noErrorNotifications = sendState.notifications.none { it is NotificationUM.Error } if (!isSuccess && noErrorNotifications) { - viewModelScope.launch { + modelScope.launch { val feeUpdatedState = callFeeUseCase()?.fold( ifRight = { uiState.value = stateFactory.getSendingStateUpdate(isSending = false) @@ -1065,7 +1060,7 @@ internal class SendViewModel @Inject constructor( } private fun setNeverToShowTapHelp() { - viewModelScope.launch { + modelScope.launch { neverShowTapHelpUseCase() } uiState.value = stateFactory.getHiddenTapHelpState() diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendEventStateFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendEventStateFactory.kt index 1258c831fb..9d95fd1d61 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendEventStateFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendEventStateFactory.kt @@ -8,7 +8,7 @@ import com.tangem.domain.transaction.error.SendTransactionError import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState import com.tangem.features.send.impl.presentation.state.fee.FeeStateFactory import com.tangem.features.send.impl.presentation.state.fee.FeeType -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import com.tangem.utils.Provider import java.math.BigDecimal diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt index 030e8e81c7..4502a628ec 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt @@ -18,7 +18,7 @@ import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState import com.tangem.features.send.impl.presentation.state.fee.SendFeeStateConverter import com.tangem.features.send.impl.presentation.state.fee.checkFeeCoverage import com.tangem.features.send.impl.presentation.state.recipient.SendRecipientStateConverter -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import com.tangem.utils.Provider import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt index ab01823bca..fd0769ac99 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt @@ -10,7 +10,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.features.send.impl.presentation.domain.SendRecipientListContent import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState import com.tangem.features.send.impl.presentation.state.fields.SendTextField -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import kotlinx.collections.immutable.ImmutableList import java.math.BigDecimal diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/StateRouter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/StateRouter.kt index 6335c3b154..809f8ada16 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/StateRouter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/StateRouter.kt @@ -12,7 +12,7 @@ internal class StateRouter( private val analyticsEventsHandler: AnalyticsEventHandler, private val isEditingDisabled: Boolean, ) { - private var mutableCurrentState: MutableStateFlow = MutableStateFlow(getInitState()) + private val mutableCurrentState: MutableStateFlow = MutableStateFlow(getInitState()) val currentState: StateFlow get() = mutableCurrentState diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt index ea3dc027aa..87b25f2824 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt @@ -34,7 +34,7 @@ import com.tangem.features.send.impl.presentation.state.SendUiState import com.tangem.features.send.impl.presentation.state.SendUiStateType import com.tangem.features.send.impl.presentation.state.StateRouter import com.tangem.features.send.impl.presentation.state.fee.* -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import com.tangem.lib.crypto.BlockchainUtils import com.tangem.lib.crypto.BlockchainUtils.isTezos import com.tangem.utils.Provider diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeConverter.kt index 4c557fecbb..54424e3b07 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeConverter.kt @@ -9,7 +9,7 @@ import com.tangem.features.send.impl.presentation.state.StateRouter import com.tangem.features.send.impl.presentation.state.fee.custom.BitcoinCustomFeeConverter import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter import com.tangem.features.send.impl.presentation.state.fee.custom.KaspaCustomFeeConverter -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import com.tangem.utils.Provider import com.tangem.utils.converter.Converter diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeNotificationFactory.kt index 96985ed40d..6eaa94816c 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeNotificationFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeNotificationFactory.kt @@ -4,7 +4,7 @@ import com.tangem.common.ui.notifications.NotificationsFactory.addFeeUnreachable import com.tangem.features.send.impl.presentation.state.SendUiState import com.tangem.features.send.impl.presentation.state.SendUiStateType import com.tangem.features.send.impl.presentation.state.StateRouter -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import com.tangem.utils.Provider import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeStateFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeStateFactory.kt index 83e40651a2..0ff24473ac 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeStateFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeStateFactory.kt @@ -14,7 +14,7 @@ import com.tangem.domain.transaction.usecase.IsFeeApproximateUseCase import com.tangem.features.send.impl.presentation.state.SendStates import com.tangem.features.send.impl.presentation.state.SendUiState import com.tangem.features.send.impl.presentation.state.StateRouter -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import com.tangem.utils.Provider import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeCustomFieldConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeCustomFieldConverter.kt index 23571ac345..71f672a60a 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeCustomFieldConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeCustomFieldConverter.kt @@ -9,7 +9,7 @@ import com.tangem.features.send.impl.presentation.state.fee.custom.BitcoinCustom import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter import com.tangem.features.send.impl.presentation.state.fee.custom.KaspaCustomFeeConverter import com.tangem.features.send.impl.presentation.state.fields.SendTextField -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import com.tangem.utils.Provider import com.tangem.utils.converter.Converter import kotlinx.collections.immutable.ImmutableList diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/BitcoinCustomFeeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/BitcoinCustomFeeConverter.kt index 2b7aa838e5..a88f105554 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/BitcoinCustomFeeConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/BitcoinCustomFeeConverter.kt @@ -15,7 +15,7 @@ import com.tangem.features.send.impl.R import com.tangem.features.send.impl.presentation.state.StateRouter import com.tangem.features.send.impl.presentation.state.fee.checkExceedBalance import com.tangem.features.send.impl.presentation.state.fields.SendTextField -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import com.tangem.lib.crypto.BlockchainUtils.isUseBitcoinFeeConverter import com.tangem.utils.Provider import kotlinx.collections.immutable.ImmutableList diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt index b65735aeb2..e8695d1e87 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt @@ -14,7 +14,7 @@ import com.tangem.features.send.impl.R import com.tangem.features.send.impl.presentation.state.StateRouter import com.tangem.features.send.impl.presentation.state.fee.checkExceedBalance import com.tangem.features.send.impl.presentation.state.fields.SendTextField -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import com.tangem.utils.Provider import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumEIPCustomFeeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumEIPCustomFeeConverter.kt index 14a249de6c..f436dd3051 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumEIPCustomFeeConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumEIPCustomFeeConverter.kt @@ -18,7 +18,7 @@ import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCusto import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter.Companion.GAS_DECIMALS import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter.Companion.GIGA_DECIMALS import com.tangem.features.send.impl.presentation.state.fields.SendTextField -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import com.tangem.utils.Provider import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumLegacyCustomFeeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumLegacyCustomFeeConverter.kt index b4058dd76d..cf8e3881b7 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumLegacyCustomFeeConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumLegacyCustomFeeConverter.kt @@ -18,7 +18,7 @@ import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCusto import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter.Companion.GAS_DECIMALS import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter.Companion.GIGA_DECIMALS import com.tangem.features.send.impl.presentation.state.fields.SendTextField -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import com.tangem.utils.Provider import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/KaspaCustomFeeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/KaspaCustomFeeConverter.kt index 769bd3ee75..b361065b43 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/KaspaCustomFeeConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/KaspaCustomFeeConverter.kt @@ -13,7 +13,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.features.send.impl.R import com.tangem.features.send.impl.presentation.state.fields.SendTextField -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import com.tangem.utils.Provider import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/SendClickIntentsStub.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/SendClickIntentsStub.kt index ca5adcd00a..482afa6bda 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/SendClickIntentsStub.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/SendClickIntentsStub.kt @@ -4,7 +4,7 @@ import com.tangem.common.ui.notifications.NotificationUM import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.features.send.impl.presentation.analytics.EnterAddressSource import com.tangem.features.send.impl.presentation.state.fee.FeeType -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import java.math.BigDecimal @Suppress("TooManyFunctions") diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientAddressFieldConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientAddressFieldConverter.kt index 2365bc31e2..a14a303ab2 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientAddressFieldConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientAddressFieldConverter.kt @@ -6,7 +6,7 @@ import androidx.compose.ui.text.input.KeyboardType import com.tangem.core.ui.extensions.resourceReference import com.tangem.features.send.impl.R import com.tangem.features.send.impl.presentation.state.fields.SendTextField -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import com.tangem.utils.converter.Converter internal class SendRecipientAddressFieldConverter( diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientMemoFieldConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientMemoFieldConverter.kt index 273b6e0b6f..ad0c05fda2 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientMemoFieldConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientMemoFieldConverter.kt @@ -9,7 +9,7 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.model.Network import com.tangem.features.send.impl.R import com.tangem.features.send.impl.presentation.state.fields.SendTextField -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import com.tangem.utils.Provider import com.tangem.utils.converter.Converter diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientStateConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientStateConverter.kt index 9b3f770fcf..7829d19b85 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientStateConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientStateConverter.kt @@ -3,7 +3,7 @@ package com.tangem.features.send.impl.presentation.state.recipient import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.features.send.impl.presentation.state.SendStates import com.tangem.features.send.impl.presentation.state.recipient.utils.* -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import com.tangem.utils.Provider import com.tangem.utils.converter.Converter diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedAndFeeContent.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedAndFeeContent.kt index dedf7fa608..cbb85ab5e8 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedAndFeeContent.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedAndFeeContent.kt @@ -20,7 +20,7 @@ import com.tangem.features.send.impl.presentation.state.fee.FeeType import com.tangem.features.send.impl.presentation.state.previewdata.FeeStatePreviewData import com.tangem.features.send.impl.presentation.state.previewdata.SendClickIntentsStub import com.tangem.features.send.impl.presentation.ui.common.notifications -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents private const val FEE_SELECTOR_KEY = "FEE_SELECTOR_KEY" private const val FEE_CUSTOM_KEY = "FEE_CUSTOM_KEY" diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelector.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelector.kt index 2c83d49d07..1e8293ea4b 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelector.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelector.kt @@ -25,7 +25,7 @@ import com.tangem.features.send.impl.presentation.state.SendStates import com.tangem.features.send.impl.presentation.state.fee.FeeType import com.tangem.features.send.impl.presentation.state.previewdata.FeeStatePreviewData import com.tangem.features.send.impl.presentation.state.previewdata.SendClickIntentsStub -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents @Suppress("LongMethod") @Composable diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/recipient/SendRecipientContent.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/recipient/SendRecipientContent.kt index aaa589bde5..4838a3a3e3 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/recipient/SendRecipientContent.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/recipient/SendRecipientContent.kt @@ -32,7 +32,7 @@ import com.tangem.features.send.impl.presentation.state.SendStates import com.tangem.features.send.impl.presentation.state.fields.SendTextField import com.tangem.features.send.impl.presentation.state.previewdata.RecipientStatePreviewData import com.tangem.features.send.impl.presentation.state.previewdata.SendClickIntentsStub -import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents +import com.tangem.features.send.impl.presentation.model.SendClickIntents import kotlinx.collections.immutable.ImmutableList private const val ADDRESS_FIELD_KEY = "ADDRESS_FIELD_KEY" From ed2eca7e8b2dc8d05316a45dd054a1b445e366b8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 18 Feb 2025 20:05:09 +0300 Subject: [PATCH 02/54] Updated on 2026-08-14 --- .../tap/features/home/DefaultHomeComponent.kt | 74 ++++++++++++++++++ .../tangem/tap/features/home/HomeFragment.kt | 75 ------------------- .../home/{HomeViewModel.kt => HomeModel.kt} | 17 +++-- .../tap/features/home/api/HomeComponent.kt | 9 +++ .../tap/features/home/di/HomeFeatureModule.kt | 25 +++++++ .../tangem/tap/routing/utils/ChildFactory.kt | 18 ++++- 6 files changed, 133 insertions(+), 85 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/home/DefaultHomeComponent.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt rename app/src/main/java/com/tangem/tap/features/home/{HomeViewModel.kt => HomeModel.kt} (93%) create mode 100644 app/src/main/java/com/tangem/tap/features/home/api/HomeComponent.kt create mode 100644 app/src/main/java/com/tangem/tap/features/home/di/HomeFeatureModule.kt diff --git a/app/src/main/java/com/tangem/tap/features/home/DefaultHomeComponent.kt b/app/src/main/java/com/tangem/tap/features/home/DefaultHomeComponent.kt new file mode 100644 index 0000000000..a7a853a86a --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/home/DefaultHomeComponent.kt @@ -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 { + + private val model: HomeModel = getOrCreateModel() + + private var homeState: MutableState = 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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt deleted file mode 100644 index 2379b399a9..0000000000 --- a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt +++ /dev/null @@ -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 { - - @Inject - override lateinit var uiDependencies: UiDependencies - - private var homeState: MutableState = mutableStateOf(store.state.homeState) - - private val viewModel by viewModels() - - 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, - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/HomeViewModel.kt b/app/src/main/java/com/tangem/tap/features/home/HomeModel.kt similarity index 93% rename from app/src/main/java/com/tangem/tap/features/home/HomeViewModel.kt rename to app/src/main/java/com/tangem/tap/features/home/HomeModel.kt index f0b0d760e6..91a72ef7ed 100644 --- a/app/src/main/java/com/tangem/tap/features/home/HomeViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/home/HomeModel.kt @@ -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.ComponentScoped +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 +@ComponentScoped +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( diff --git a/app/src/main/java/com/tangem/tap/features/home/api/HomeComponent.kt b/app/src/main/java/com/tangem/tap/features/home/api/HomeComponent.kt new file mode 100644 index 0000000000..0c63e10a1c --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/home/api/HomeComponent.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/di/HomeFeatureModule.kt b/app/src/main/java/com/tangem/tap/features/home/di/HomeFeatureModule.kt new file mode 100644 index 0000000000..9f92cc5583 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/home/di/HomeFeatureModule.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index 10fc7890b2..d8483ca2db 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -27,7 +27,7 @@ import com.tangem.tap.features.details.ui.cardsettings.coderecovery.AccessCodeRe 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.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 @@ -61,6 +61,7 @@ internal class ChildFactory @Inject constructor( private val sendComponentFactory: SendComponent.Factory, private val stakingComponentFactory: StakingComponent.Factory, private val swapComponentFactory: SwapComponent.Factory, + private val homeComponentFactory: HomeComponent.Factory, private val tokenDetailsRouter: TokenDetailsRouter, private val walletRouter: WalletRouter, private val qrScanningRouter: QrScanningRouter, @@ -249,13 +250,20 @@ internal class ChildFactory @Inject constructor( componentFactory = sendComponentFactory, ) } + is AppRoute.Home -> { + createComponentChild( + contextProvider = contextProvider(route, contextFactory), + params = Unit, + componentFactory = homeComponentFactory, + ) + } is AppRoute.AccessCodeRecovery, is AppRoute.AppCurrencySelector, is AppRoute.SaveWallet, is AppRoute.AppSettings, is AppRoute.CardSettings, is AppRoute.DetailsSecurity, - is AppRoute.Home, + is AppRoute.OnboardingNote, is AppRoute.OnboardingOther, is AppRoute.OnboardingTwins, @@ -328,7 +336,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) { From 89184e29e09cd261550f67cad4e6b26f2a9ede10 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 18 Feb 2025 19:02:14 +0200 Subject: [PATCH 03/54] Updated on 2026-08-14 --- app/build.gradle.kts | 6 +++--- common/ui-charts/build.gradle.kts | 6 +++--- common/ui/build.gradle.kts | 4 ++-- core/datasource/build.gradle.kts | 4 ++-- data/card/build.gradle.kts | 6 +++--- data/common/build.gradle.kts | 4 ++-- data/feedback/build.gradle.kts | 4 ++-- data/manage-tokens/build.gradle.kts | 4 ++-- data/markets/build.gradle.kts | 2 +- data/onramp/build.gradle.kts | 4 ++-- data/qr-scanning/build.gradle.kts | 2 +- data/staking/build.gradle.kts | 4 ++-- data/tokens/build.gradle.kts | 4 ++-- data/transaction/build.gradle.kts | 4 ++-- data/txhistory/build.gradle.kts | 2 +- data/visa/build.gradle.kts | 4 ++-- data/wallets/build.gradle.kts | 2 +- domain/card/build.gradle.kts | 4 ++-- domain/demo/build.gradle.kts | 4 ++-- domain/legacy/build.gradle.kts | 6 +++--- domain/models/build.gradle.kts | 2 +- domain/staking/build.gradle.kts | 2 +- domain/tokens/build.gradle.kts | 2 +- domain/transaction/build.gradle.kts | 6 +++--- domain/wallets/build.gradle.kts | 4 ++-- domain/wallets/models/build.gradle.kts | 2 +- features/details/impl/build.gradle.kts | 4 ++-- features/onboarding-v2/impl/build.gradle.kts | 4 ++-- features/onboarding/build.gradle.kts | 6 +++--- features/qr-scanning/impl/build.gradle.kts | 2 +- features/referral/data/build.gradle.kts | 2 +- features/referral/domain/build.gradle.kts | 2 +- features/send/impl/build.gradle.kts | 4 ++-- features/staking/impl/build.gradle.kts | 4 ++-- features/swap/data/build.gradle.kts | 2 +- features/swap/domain/build.gradle.kts | 4 ++-- features/tester/impl/build.gradle.kts | 2 +- features/tokendetails/impl/build.gradle.kts | 4 ++-- features/wallet/impl/build.gradle.kts | 4 ++-- gradle/dependencies.toml | 19 ------------------- gradle/tangem_dependencies.toml | 18 ++++++++++++++++++ libs/blockchain-sdk/build.gradle.kts | 4 ++-- libs/crypto/build.gradle.kts | 2 +- libs/tangem-sdk-api/build.gradle.kts | 4 ++-- plugins/configuration/settings.gradle.kts | 3 +++ settings.gradle.kts | 4 ++++ 46 files changed, 101 insertions(+), 95 deletions(-) create mode 100644 gradle/tangem_dependencies.toml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index cce042451f..f3177619a4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -222,11 +222,11 @@ dependencies { exclude(group = "com.google.protobuf", module = "protobuf-javalite") } /** Tangem libraries */ - implementation(deps.tangem.blockchain) { + implementation(tangemDeps.blockchain) { exclude(module = "joda-time") } - implementation(deps.tangem.card.core) - implementation(deps.tangem.card.android) { + implementation(tangemDeps.card.core) + implementation(tangemDeps.card.android) { exclude(module = "joda-time") } diff --git a/common/ui-charts/build.gradle.kts b/common/ui-charts/build.gradle.kts index 58bf27c3a5..0520d97bb3 100644 --- a/common/ui-charts/build.gradle.kts +++ b/common/ui-charts/build.gradle.kts @@ -13,9 +13,9 @@ dependencies { implementation(projects.core.ui) /** Compose */ - implementation(deps.tangem.vico.core) - implementation(deps.tangem.vico.compose) - implementation(deps.tangem.vico.compose.m3) + implementation(tangemDeps.vico.core) + implementation(tangemDeps.vico.compose) + implementation(tangemDeps.vico.compose.m3) implementation(deps.lifecycle.compose) implementation(deps.compose.foundation) diff --git a/common/ui/build.gradle.kts b/common/ui/build.gradle.kts index 709c410a9f..6a6f96f728 100644 --- a/common/ui/build.gradle.kts +++ b/common/ui/build.gradle.kts @@ -38,8 +38,8 @@ dependencies { implementation(projects.domain.onramp.models) implementation(projects.domain.promo.models) - implementation(deps.tangem.card.core) - implementation(deps.tangem.blockchain) { + implementation(tangemDeps.card.core) + implementation(tangemDeps.blockchain) { exclude(module = "joda-time") } } \ No newline at end of file diff --git a/core/datasource/build.gradle.kts b/core/datasource/build.gradle.kts index 3c417c187c..2e43145350 100644 --- a/core/datasource/build.gradle.kts +++ b/core/datasource/build.gradle.kts @@ -34,8 +34,8 @@ dependencies { implementation(projects.domain.models) /** Tangem libraries */ - implementation(deps.tangem.blockchain) - implementation(deps.tangem.card.core) + implementation(tangemDeps.blockchain) + implementation(tangemDeps.card.core) /** DI */ implementation(deps.hilt.android) diff --git a/data/card/build.gradle.kts b/data/card/build.gradle.kts index eb80b3d8cf..6d546bc04d 100644 --- a/data/card/build.gradle.kts +++ b/data/card/build.gradle.kts @@ -13,15 +13,15 @@ android { dependencies { implementation(deps.androidx.datastore) - implementation(deps.tangem.blockchain) { + implementation(tangemDeps.blockchain) { exclude(module = "joda-time") } implementation(deps.hilt.android) kapt(deps.hilt.kapt) - implementation(deps.tangem.card.android) - implementation(deps.tangem.card.core) + implementation(tangemDeps.card.android) + implementation(tangemDeps.card.core) implementation(projects.core.datasource) implementation(projects.core.utils) diff --git a/data/common/build.gradle.kts b/data/common/build.gradle.kts index 5a5b6c1d85..96dc4861ca 100644 --- a/data/common/build.gradle.kts +++ b/data/common/build.gradle.kts @@ -19,8 +19,8 @@ dependencies { implementation(projects.domain.tokens.models) /* Libs - SDK */ - implementation(deps.tangem.blockchain) - implementation(deps.tangem.card.core) + implementation(tangemDeps.blockchain) + implementation(tangemDeps.card.core) implementation(projects.libs.blockchainSdk) /* DI */ diff --git a/data/feedback/build.gradle.kts b/data/feedback/build.gradle.kts index 5f75809008..42c689a596 100644 --- a/data/feedback/build.gradle.kts +++ b/data/feedback/build.gradle.kts @@ -21,8 +21,8 @@ dependencies { // endregion // region Tangem libraries - implementation(deps.tangem.blockchain) - implementation(deps.tangem.card.core) + implementation(tangemDeps.blockchain) + implementation(tangemDeps.card.core) // endregion // Other libraries diff --git a/data/manage-tokens/build.gradle.kts b/data/manage-tokens/build.gradle.kts index a8373e38ff..d303cffc3f 100644 --- a/data/manage-tokens/build.gradle.kts +++ b/data/manage-tokens/build.gradle.kts @@ -33,8 +33,8 @@ dependencies { implementation(projects.libs.blockchainSdk) /** Tangem SDKs */ - implementation(deps.tangem.blockchain) - implementation(deps.tangem.card.core) + implementation(tangemDeps.blockchain) + implementation(tangemDeps.card.core) /** AndroidX */ implementation(deps.androidx.datastore) diff --git a/data/markets/build.gradle.kts b/data/markets/build.gradle.kts index 9e8f4d07a7..9f3c3fc995 100644 --- a/data/markets/build.gradle.kts +++ b/data/markets/build.gradle.kts @@ -41,7 +41,7 @@ dependencies { implementation(deps.moshi) implementation(deps.moshi.kotlin) implementation(deps.timber) - implementation(deps.tangem.blockchain) + implementation(tangemDeps.blockchain) kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) kaptForObfuscatingVariants(deps.retrofit.response.type.keeper) // endregion diff --git a/data/onramp/build.gradle.kts b/data/onramp/build.gradle.kts index dd8b614228..fc4b8695b8 100644 --- a/data/onramp/build.gradle.kts +++ b/data/onramp/build.gradle.kts @@ -52,8 +52,8 @@ dependencies { implementation(projects.libs.blockchainSdk) implementation(projects.libs.crypto) - implementation(deps.tangem.card.core) - implementation(deps.tangem.blockchain) { + implementation(tangemDeps.card.core) + implementation(tangemDeps.blockchain) { exclude(module = "joda-time") } diff --git a/data/qr-scanning/build.gradle.kts b/data/qr-scanning/build.gradle.kts index 1c801589b7..a422fdbd4a 100644 --- a/data/qr-scanning/build.gradle.kts +++ b/data/qr-scanning/build.gradle.kts @@ -20,7 +20,7 @@ dependencies { implementation(projects.core.ui) /** SdK */ - implementation(deps.tangem.blockchain) + implementation(tangemDeps.blockchain) /** DI */ implementation(deps.hilt.android) diff --git a/data/staking/build.gradle.kts b/data/staking/build.gradle.kts index 511b6f79b0..ee2849d585 100644 --- a/data/staking/build.gradle.kts +++ b/data/staking/build.gradle.kts @@ -54,8 +54,8 @@ dependencies { implementation(projects.libs.blockchainSdk) implementation(projects.libs.crypto) - implementation(deps.tangem.card.core) - implementation(deps.tangem.blockchain) { + implementation(tangemDeps.card.core) + implementation(tangemDeps.blockchain) { exclude(module = "joda-time") } diff --git a/data/tokens/build.gradle.kts b/data/tokens/build.gradle.kts index b268688860..003cc83849 100644 --- a/data/tokens/build.gradle.kts +++ b/data/tokens/build.gradle.kts @@ -33,8 +33,8 @@ dependencies { implementation(projects.libs.blockchainSdk) /** Tangem SDKs */ - implementation(deps.tangem.blockchain) - implementation(deps.tangem.card.core) + implementation(tangemDeps.blockchain) + implementation(tangemDeps.card.core) /** AndroidX */ implementation(deps.androidx.datastore) diff --git a/data/transaction/build.gradle.kts b/data/transaction/build.gradle.kts index 709f743912..0426e68bbc 100644 --- a/data/transaction/build.gradle.kts +++ b/data/transaction/build.gradle.kts @@ -13,8 +13,8 @@ android { dependencies { /** Tangem SDKs */ - implementation(deps.tangem.blockchain) - implementation(deps.tangem.card.core) + implementation(tangemDeps.blockchain) + implementation(tangemDeps.card.core) /** Core */ implementation(projects.core.datasource) diff --git a/data/txhistory/build.gradle.kts b/data/txhistory/build.gradle.kts index 3a8e769a69..23bb1bd73d 100644 --- a/data/txhistory/build.gradle.kts +++ b/data/txhistory/build.gradle.kts @@ -25,7 +25,7 @@ dependencies { implementation(deps.androidx.paging.runtime) implementation(deps.timber) implementation(deps.jodatime) - implementation(deps.tangem.blockchain) + implementation(tangemDeps.blockchain) implementation(deps.hilt.core) kapt(deps.hilt.kapt) diff --git a/data/visa/build.gradle.kts b/data/visa/build.gradle.kts index 5a74bcefe0..b2f273b514 100644 --- a/data/visa/build.gradle.kts +++ b/data/visa/build.gradle.kts @@ -43,8 +43,8 @@ dependencies { kaptForObfuscatingVariants(deps.retrofit.response.type.keeper) /** Libs - Tangem */ - implementation(deps.tangem.blockchain) - implementation(deps.tangem.card.core) + implementation(tangemDeps.blockchain) + implementation(tangemDeps.card.core) /** DI */ implementation(deps.hilt.core) diff --git a/data/wallets/build.gradle.kts b/data/wallets/build.gradle.kts index 2f37436631..46c3ad34e3 100644 --- a/data/wallets/build.gradle.kts +++ b/data/wallets/build.gradle.kts @@ -13,7 +13,7 @@ android { dependencies { /** Tangem libraries */ - implementation(deps.tangem.blockchain) // android-library + implementation(tangemDeps.blockchain) // android-library /** Core */ implementation(projects.core.datasource) diff --git a/domain/card/build.gradle.kts b/domain/card/build.gradle.kts index d317bafbf5..a5aa3d005f 100644 --- a/domain/card/build.gradle.kts +++ b/domain/card/build.gradle.kts @@ -20,8 +20,8 @@ dependencies { implementation(projects.domain.tokens.models) implementation(projects.domain.wallets.models) - implementation(deps.tangem.card.core) - implementation(deps.tangem.blockchain) { + implementation(tangemDeps.card.core) + implementation(tangemDeps.blockchain) { exclude(module = "joda-time") } diff --git a/domain/demo/build.gradle.kts b/domain/demo/build.gradle.kts index a9e6de5249..83c77bfc66 100644 --- a/domain/demo/build.gradle.kts +++ b/domain/demo/build.gradle.kts @@ -9,6 +9,6 @@ android { } dependencies { - implementation(deps.tangem.blockchain) - implementation(deps.tangem.card.core) + implementation(tangemDeps.blockchain) + implementation(tangemDeps.card.core) } \ No newline at end of file diff --git a/domain/legacy/build.gradle.kts b/domain/legacy/build.gradle.kts index f87e9728c8..8a3a831cbe 100644 --- a/domain/legacy/build.gradle.kts +++ b/domain/legacy/build.gradle.kts @@ -25,11 +25,11 @@ dependencies { implementation(projects.domain.txhistory.models) implementation(projects.domain.wallets.models) /** Tangem libraries */ - implementation(deps.tangem.blockchain) { + implementation(tangemDeps.blockchain) { exclude(module = "joda-time") } - implementation(deps.tangem.card.core) - implementation(deps.tangem.card.android) { + implementation(tangemDeps.card.core) + implementation(tangemDeps.card.android) { exclude(module = "joda-time") } diff --git a/domain/models/build.gradle.kts b/domain/models/build.gradle.kts index fec72be756..aeafc373d1 100644 --- a/domain/models/build.gradle.kts +++ b/domain/models/build.gradle.kts @@ -10,7 +10,7 @@ plugins { dependencies { api(projects.domain.visa.models) - implementation(deps.tangem.card.core) + implementation(tangemDeps.card.core) implementation(deps.moshi.kotlin) implementation(deps.moshi.adapters) implementation(deps.kotlin.serialization) diff --git a/domain/staking/build.gradle.kts b/domain/staking/build.gradle.kts index a0caf393f8..917cd0ad5f 100644 --- a/domain/staking/build.gradle.kts +++ b/domain/staking/build.gradle.kts @@ -23,7 +23,7 @@ dependencies { implementation(projects.features.staking.api) - implementation(deps.tangem.blockchain) { + implementation(tangemDeps.blockchain) { exclude(module = "joda-time") } } \ No newline at end of file diff --git a/domain/tokens/build.gradle.kts b/domain/tokens/build.gradle.kts index 3e8fc1ea6a..9382289ad6 100644 --- a/domain/tokens/build.gradle.kts +++ b/domain/tokens/build.gradle.kts @@ -50,7 +50,7 @@ dependencies { /** Tests */ testImplementation(deps.test.junit) testImplementation(deps.test.coroutine) - testImplementation(deps.tangem.blockchain) { + testImplementation(tangemDeps.blockchain) { exclude(module = "joda-time") } } \ No newline at end of file diff --git a/domain/transaction/build.gradle.kts b/domain/transaction/build.gradle.kts index b54aeca082..f798f98dc8 100644 --- a/domain/transaction/build.gradle.kts +++ b/domain/transaction/build.gradle.kts @@ -16,11 +16,11 @@ dependencies { implementation(projects.core.ui) /** Tangem SDKs */ - implementation(deps.tangem.card.core) - implementation(deps.tangem.card.android) { + implementation(tangemDeps.card.core) + implementation(tangemDeps.card.android) { exclude(module = "joda-time") } - implementation(deps.tangem.blockchain) + implementation(tangemDeps.blockchain) implementation(projects.domain.models) implementation(projects.domain.legacy) diff --git a/domain/wallets/build.gradle.kts b/domain/wallets/build.gradle.kts index 9972fdc9c7..616cbdcc21 100644 --- a/domain/wallets/build.gradle.kts +++ b/domain/wallets/build.gradle.kts @@ -26,7 +26,7 @@ dependencies { // endregion // region Tangem libraries - implementation(deps.tangem.blockchain) // android-library - implementation(deps.tangem.card.core) + implementation(tangemDeps.blockchain) // android-library + implementation(tangemDeps.card.core) // endregion } \ No newline at end of file diff --git a/domain/wallets/models/build.gradle.kts b/domain/wallets/models/build.gradle.kts index 9c259ee6b6..03afdb3da9 100644 --- a/domain/wallets/models/build.gradle.kts +++ b/domain/wallets/models/build.gradle.kts @@ -7,7 +7,7 @@ plugins { dependencies { // region Tangem libraries - implementation(deps.tangem.card.core) + implementation(tangemDeps.card.core) // endregion // region Domain modules diff --git a/features/details/impl/build.gradle.kts b/features/details/impl/build.gradle.kts index b3981ae397..2ffdab4b0e 100644 --- a/features/details/impl/build.gradle.kts +++ b/features/details/impl/build.gradle.kts @@ -45,9 +45,9 @@ dependencies { /* SDK */ // TODO: For TangemError model, should be removed after card domain scanning refactoring - implementation(deps.tangem.card.core) + implementation(tangemDeps.card.core) // For image resolving - implementation(deps.tangem.blockchain) + implementation(tangemDeps.blockchain) /* AndroidX */ implementation(deps.androidx.activity.compose) diff --git a/features/onboarding-v2/impl/build.gradle.kts b/features/onboarding-v2/impl/build.gradle.kts index 3f1c7150fc..636d71237b 100644 --- a/features/onboarding-v2/impl/build.gradle.kts +++ b/features/onboarding-v2/impl/build.gradle.kts @@ -45,8 +45,8 @@ dependencies { /** Tangem libraries */ implementation(projects.libs.tangemSdkApi) - implementation(deps.tangem.card.core) - implementation(deps.tangem.card.android) { + implementation(tangemDeps.card.core) + implementation(tangemDeps.card.android) { exclude(module = "joda-time") } diff --git a/features/onboarding/build.gradle.kts b/features/onboarding/build.gradle.kts index fb353a3220..6d048e8c4d 100644 --- a/features/onboarding/build.gradle.kts +++ b/features/onboarding/build.gradle.kts @@ -25,8 +25,8 @@ dependencies { implementation(project(":data:common")) /** Tangem libraries */ - implementation(deps.tangem.card.core) - implementation(deps.tangem.card.android) { + implementation(tangemDeps.card.core) + implementation(tangemDeps.card.android) { exclude(module = "joda-time") } @@ -50,7 +50,7 @@ dependencies { implementation(deps.compose.coil) implementation(deps.compose.shimmer) - implementation(deps.tangem.card.core) + implementation(tangemDeps.card.core) /** Other libraries */ implementation(deps.compose.shimmer) diff --git a/features/qr-scanning/impl/build.gradle.kts b/features/qr-scanning/impl/build.gradle.kts index 87bb1cc68e..f8bb506a61 100644 --- a/features/qr-scanning/impl/build.gradle.kts +++ b/features/qr-scanning/impl/build.gradle.kts @@ -60,5 +60,5 @@ dependencies { /** Other dependencies */ implementation(deps.arrow.core) implementation(deps.timber) - implementation(deps.tangem.card.core) + implementation(tangemDeps.card.core) } \ No newline at end of file diff --git a/features/referral/data/build.gradle.kts b/features/referral/data/build.gradle.kts index 954bac9c2e..bbe186db0f 100644 --- a/features/referral/data/build.gradle.kts +++ b/features/referral/data/build.gradle.kts @@ -38,5 +38,5 @@ dependencies { kapt(deps.hilt.kapt) /** Tangem deps */ - implementation(deps.tangem.blockchain) + implementation(tangemDeps.blockchain) } \ No newline at end of file diff --git a/features/referral/domain/build.gradle.kts b/features/referral/domain/build.gradle.kts index 4206513db7..a77d439bbb 100644 --- a/features/referral/domain/build.gradle.kts +++ b/features/referral/domain/build.gradle.kts @@ -32,7 +32,7 @@ dependencies { implementation(deps.arrow.core) implementation(deps.jodatime) implementation(deps.timber) - implementation(deps.tangem.card.core) + implementation(tangemDeps.card.core) /** DI */ implementation(deps.hilt.android) diff --git a/features/send/impl/build.gradle.kts b/features/send/impl/build.gradle.kts index 2126c0ac09..7df0d26ab3 100644 --- a/features/send/impl/build.gradle.kts +++ b/features/send/impl/build.gradle.kts @@ -39,8 +39,8 @@ dependencies { implementation(deps.compose.constraintLayout) /** Tangem SDKs */ - implementation(deps.tangem.card.core) - implementation(deps.tangem.blockchain) + implementation(tangemDeps.card.core) + implementation(tangemDeps.blockchain) /** Core modules */ implementation(projects.core.configToggles) diff --git a/features/staking/impl/build.gradle.kts b/features/staking/impl/build.gradle.kts index be3dbdd1e2..bbfa41e6e2 100644 --- a/features/staking/impl/build.gradle.kts +++ b/features/staking/impl/build.gradle.kts @@ -36,8 +36,8 @@ dependencies { implementation(deps.compose.constraintLayout) /** Tangem SDKs */ - implementation(deps.tangem.card.core) - implementation(deps.tangem.blockchain) + implementation(tangemDeps.card.core) + implementation(tangemDeps.blockchain) /** Core modules */ implementation(projects.core.configToggles) diff --git a/features/swap/data/build.gradle.kts b/features/swap/data/build.gradle.kts index 805cd27a59..f9af5bb02d 100644 --- a/features/swap/data/build.gradle.kts +++ b/features/swap/data/build.gradle.kts @@ -44,7 +44,7 @@ dependencies { implementation(projects.data.common) /** Tangem SDKs */ - implementation(deps.tangem.blockchain) + implementation(tangemDeps.blockchain) /** Others */ implementation(deps.timber) diff --git a/features/swap/domain/build.gradle.kts b/features/swap/domain/build.gradle.kts index ed5fe567e7..46a1c51668 100644 --- a/features/swap/domain/build.gradle.kts +++ b/features/swap/domain/build.gradle.kts @@ -51,8 +51,8 @@ dependencies { implementation(deps.kotlin.coroutines) implementation(deps.arrow.core) implementation(deps.timber) - implementation(deps.tangem.blockchain) - implementation(deps.tangem.card.core) + implementation(tangemDeps.blockchain) + implementation(tangemDeps.card.core) implementation(deps.moshi) kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) } \ No newline at end of file diff --git a/features/tester/impl/build.gradle.kts b/features/tester/impl/build.gradle.kts index 5c994aba93..5f26b9b233 100644 --- a/features/tester/impl/build.gradle.kts +++ b/features/tester/impl/build.gradle.kts @@ -50,7 +50,7 @@ dependencies { implementation(projects.features.tester.api) /* SDK */ - implementation(deps.tangem.blockchain) + implementation(tangemDeps.blockchain) /** Other modules */ implementation(projects.common.routing) diff --git a/features/tokendetails/impl/build.gradle.kts b/features/tokendetails/impl/build.gradle.kts index 4a38dc8f9b..1457affebd 100644 --- a/features/tokendetails/impl/build.gradle.kts +++ b/features/tokendetails/impl/build.gradle.kts @@ -35,8 +35,8 @@ dependencies { implementation(deps.jodatime) implementation(deps.kotlin.immutable.collections) implementation(deps.reKotlin) - implementation(deps.tangem.blockchain) - implementation(deps.tangem.card.core) + implementation(tangemDeps.blockchain) + implementation(tangemDeps.card.core) implementation(deps.timber) implementation(deps.lifecycle.compose) implementation(deps.kotlin.serialization) diff --git a/features/wallet/impl/build.gradle.kts b/features/wallet/impl/build.gradle.kts index 3d27a12451..99809111b3 100644 --- a/features/wallet/impl/build.gradle.kts +++ b/features/wallet/impl/build.gradle.kts @@ -39,8 +39,8 @@ dependencies { implementation(deps.jodatime) implementation(deps.kotlin.immutable.collections) implementation(deps.reKotlin) - implementation(deps.tangem.card.core) - implementation(deps.tangem.blockchain) + implementation(tangemDeps.card.core) + implementation(tangemDeps.blockchain) implementation(deps.timber) implementation(deps.firebase.perf) { exclude(group = "com.google.firebase", module = "protolite-well-known-types") diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 535afc2fe4..060b0ba823 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -88,15 +88,6 @@ markdown = "0.7.2" markdownComposeView = "0.5.4" # endregion Other libraries -# region Tangem -tangemBlockchainSdk = "develop-952" -#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "develop-434" -#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ -tangemVico = "2.0.0-alpha.25-tangem-developments8" -#tangemVico = "0.0.1" # Keep it! - used for local builds ^ -# endregion Tangem - # region Tools detektComposeRules = "1.3.0" detekt = "1.22.0" @@ -188,16 +179,6 @@ firebase-messaging = { module = "com.google.firebase:firebase-messaging-ktx" } firebase-perf = { module = "com.google.firebase:firebase-perf" } # endregion Firebase -# region Tangem -tangem-blockchain = { module = "com.tangem:blockchain", version.ref = "tangemBlockchainSdk" } -tangem-card-android = { module = "com.tangem.tangem-sdk-kotlin:android", version.ref = "tangemCardSdk" } -tangem-card-core = { module = "com.tangem.tangem-sdk-kotlin:core", version.ref = "tangemCardSdk" } - -tangem-vico-compose = { group = "com.tangem.vico", name = "compose", version.ref = "tangemVico" } -tangem-vico-compose-m3 = { group = "com.tangem.vico", name = "compose-m3", version.ref = "tangemVico" } -tangem-vico-core = { group = "com.tangem.vico", name = "core", version.ref = "tangemVico" } -# endregion Tangem - # region Detekt detekt-compose = { module = "ru.kode:detekt-rules-compose", version.ref = "detektComposeRules" } detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" } diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml new file mode 100644 index 0000000000..f9edc59dd5 --- /dev/null +++ b/gradle/tangem_dependencies.toml @@ -0,0 +1,18 @@ +[versions] +tangemBlockchainSdk = "develop-952" +#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds +tangemCardSdk = "develop-434" +#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ +tangemVico = "2.0.0-alpha.25-tangem-developments8" +#tangemVico = "0.0.1" # Keep it! - used for local builds ^ + + + +[libraries] +blockchain = { module = "com.tangem:blockchain", version.ref = "tangemBlockchainSdk" } +card-android = { module = "com.tangem.tangem-sdk-kotlin:android", version.ref = "tangemCardSdk" } +card-core = { module = "com.tangem.tangem-sdk-kotlin:core", version.ref = "tangemCardSdk" } + +vico-compose = { group = "com.tangem.vico", name = "compose", version.ref = "tangemVico" } +vico-compose-m3 = { group = "com.tangem.vico", name = "compose-m3", version.ref = "tangemVico" } +vico-core = { group = "com.tangem.vico", name = "core", version.ref = "tangemVico" } \ No newline at end of file diff --git a/libs/blockchain-sdk/build.gradle.kts b/libs/blockchain-sdk/build.gradle.kts index 12234d749f..31e9b0408e 100644 --- a/libs/blockchain-sdk/build.gradle.kts +++ b/libs/blockchain-sdk/build.gradle.kts @@ -45,8 +45,8 @@ dependencies { // endregion // region Tangem libraries - implementation(deps.tangem.blockchain) { exclude(module = "joda-time") } - implementation(deps.tangem.card.core) + implementation(tangemDeps.blockchain) { exclude(module = "joda-time") } + implementation(tangemDeps.card.core) // endregion testImplementation(deps.test.coroutine) diff --git a/libs/crypto/build.gradle.kts b/libs/crypto/build.gradle.kts index 1e443985c3..0278a0501c 100644 --- a/libs/crypto/build.gradle.kts +++ b/libs/crypto/build.gradle.kts @@ -16,7 +16,7 @@ dependencies { implementation(deps.kotlin.coroutines) /** SDK */ - implementation(deps.tangem.blockchain) + implementation(tangemDeps.blockchain) /** Core */ implementation(projects.core.utils) diff --git a/libs/tangem-sdk-api/build.gradle.kts b/libs/tangem-sdk-api/build.gradle.kts index 514702adfa..577365a357 100644 --- a/libs/tangem-sdk-api/build.gradle.kts +++ b/libs/tangem-sdk-api/build.gradle.kts @@ -22,8 +22,8 @@ dependencies { implementation(projects.core.res) /** Tangem libraries */ - implementation(deps.tangem.card.core) - implementation(deps.tangem.card.android) { + implementation(tangemDeps.card.core) + implementation(tangemDeps.card.android) { exclude(module = "joda-time") } diff --git a/plugins/configuration/settings.gradle.kts b/plugins/configuration/settings.gradle.kts index 0ed5a2e04b..13c8987dd9 100644 --- a/plugins/configuration/settings.gradle.kts +++ b/plugins/configuration/settings.gradle.kts @@ -3,5 +3,8 @@ dependencyResolutionManagement { create("deps") { from(files("../../gradle/dependencies.toml")) } + create("tangemDeps") { + from(files("../../gradle/tangem_dependencies.toml")) + } } } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 7d45b0e97e..1ad6153ba0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -113,7 +113,11 @@ dependencyResolutionManagement { create("deps") { from(files("gradle/dependencies.toml")) } + create("tangemDeps") { + from(files("gradle/tangem_dependencies.toml")) + } } + } enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") From 5899f9ea8d6118246d6058582a9444152df86fe0 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 19 Feb 2025 12:25:53 +0300 Subject: [PATCH 04/54] Updated on 2026-08-14 --- .../main/java/com/tangem/tap/MainActivity.kt | 4 - .../tangem/tap/routing/utils/ChildFactory.kt | 25 ++- core/deep-links/build.gradle.kts | 2 + .../tangem/core/deeplink/DeepLinksRegistry.kt | 19 --- .../deeplink/impl/DefaultDeepLinksRegistry.kt | 16 -- .../utils/AppComponentContextExtensions.kt | 21 +++ .../utils/DeepLinksLifecycleObserver.kt | 20 --- features/tokendetails/api/build.gradle.kts | 9 +- .../tokendetails/TokenDetailsComponent.kt | 16 ++ .../navigation/TokenDetailsRouter.kt | 8 - .../DefaultTokenDetailsComponent.kt | 78 +++++++++ .../tokendetails/di/TokenDetailsModule.kt | 38 +++++ .../di/TokenDetailsRouterModule.kt | 27 ---- .../presentation/TokenDetailsFragment.kt | 105 ------------ .../router/DefaultTokenDetailsRouter.kt | 9 +- .../router/InnerTokenDetailsRouter.kt | 3 +- .../TokenDetailsClickIntents.kt | 2 +- .../TokenDetailsModel.kt} | 150 ++++++++---------- .../TokenDetailsActionButtonsConverter.kt | 2 +- .../TokenDetailsLoadedBalanceConverter.kt | 2 +- .../TokenDetailsNotificationConverter.kt | 2 +- ...nDetailsOnrampTransactionStateConverter.kt | 2 +- .../TokenDetailsSkeletonStateConverter.kt | 2 +- .../state/factory/TokenDetailsStateFactory.kt | 2 +- ...enDetailsSwapTransactionsStateConverter.kt | 2 +- .../factory/express/ExchangeStatusFactory.kt | 2 +- .../factory/express/ExpressStatusFactory.kt | 2 +- .../factory/express/OnrampStatusFactory.kt | 2 +- .../TokenDetailsLoadedTxHistoryConverter.kt | 2 +- .../TokenDetailsLoadingTxHistoryConverter.kt | 2 +- .../TokenDetailsTxHistoryItemFlowConverter.kt | 2 +- ...tailsTxHistoryTransactionStateConverter.kt | 2 +- 32 files changed, 265 insertions(+), 315 deletions(-) create mode 100644 core/deep-links/src/main/kotlin/com/tangem/core/deeplink/utils/AppComponentContextExtensions.kt delete mode 100644 core/deep-links/src/main/kotlin/com/tangem/core/deeplink/utils/DeepLinksLifecycleObserver.kt create mode 100644 features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/TokenDetailsComponent.kt delete mode 100644 features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/navigation/TokenDetailsRouter.kt create mode 100644 features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/DefaultTokenDetailsComponent.kt create mode 100644 features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/di/TokenDetailsModule.kt delete mode 100644 features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/di/TokenDetailsRouterModule.kt delete mode 100644 features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/TokenDetailsFragment.kt rename features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/{viewmodels => model}/TokenDetailsClickIntents.kt (99%) rename features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/{viewmodels/TokenDetailsViewModel.kt => model/TokenDetailsModel.kt} (91%) diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index c96a550db8..72b9f67d82 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -64,7 +64,6 @@ import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnaly 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.tokendetails.navigation.TokenDetailsRouter import com.tangem.features.wallet.navigation.WalletRouter import com.tangem.google.GoogleServicesHelper import com.tangem.operations.backup.BackupService @@ -140,9 +139,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac @Inject lateinit var walletRouter: WalletRouter - @Inject - lateinit var tokenDetailsRouter: TokenDetailsRouter - @Inject lateinit var walletConnectInteractor: WalletConnectInteractor diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index d8483ca2db..09e825ea06 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -18,7 +18,7 @@ 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.tokendetails.TokenDetailsComponent 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 @@ -62,7 +62,7 @@ internal class ChildFactory @Inject constructor( private val stakingComponentFactory: StakingComponent.Factory, private val swapComponentFactory: SwapComponent.Factory, private val homeComponentFactory: HomeComponent.Factory, - private val tokenDetailsRouter: TokenDetailsRouter, + private val tokenDetailsComponentFactory: TokenDetailsComponent.Factory, private val walletRouter: WalletRouter, private val qrScanningRouter: QrScanningRouter, private val testerRouter: TesterRouter, @@ -213,6 +213,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), @@ -263,7 +273,6 @@ internal class ChildFactory @Inject constructor( is AppRoute.AppSettings, is AppRoute.CardSettings, is AppRoute.DetailsSecurity, - is AppRoute.OnboardingNote, is AppRoute.OnboardingOther, is AppRoute.OnboardingTwins, @@ -273,7 +282,6 @@ internal class ChildFactory @Inject constructor( is AppRoute.ResetToFactory, is AppRoute.Wallet, is AppRoute.WalletConnectSessions, - is AppRoute.CurrencyDetails, is AppRoute.PushNotification, -> error("Unsupported route: $route") } @@ -395,7 +403,14 @@ internal class ChildFactory @Inject constructor( route.asFragmentChild(Provider { WalletConnectFragment() }) } 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() }) diff --git a/core/deep-links/build.gradle.kts b/core/deep-links/build.gradle.kts index 9d43ab04df..c086d8f8d6 100644 --- a/core/deep-links/build.gradle.kts +++ b/core/deep-links/build.gradle.kts @@ -10,6 +10,8 @@ android { } dependencies { + /* Core */ + implementation(projects.core.decompose) /* Libs - AndroidX */ implementation(deps.lifecycle.runtime.ktx) diff --git a/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/DeepLinksRegistry.kt b/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/DeepLinksRegistry.kt index 105ddbc940..fc56ae10a0 100644 --- a/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/DeepLinksRegistry.kt +++ b/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/DeepLinksRegistry.kt @@ -1,8 +1,6 @@ package com.tangem.core.deeplink import android.content.Intent -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.ViewModel // TODO: Add tests /** @@ -21,17 +19,11 @@ interface DeepLinksRegistry { /** * Registers the given [deepLink]. - * - * @see registerWithLifecycle - * @see registerWithViewModel */ fun register(deepLink: DeepLink) /** * Registers the given [deepLinks]. - * - * @see registerWithLifecycle - * @see registerWithViewModel */ fun register(deepLinks: Collection) @@ -50,17 +42,6 @@ interface DeepLinksRegistry { * */ fun unregisterByIds(ids: Collection) - /** - * Registers the [deepLinks] when the [owner] is resumed and ensures that they are unregistered when the [owner] is - * stopped. - */ - fun registerWithLifecycle(owner: LifecycleOwner, deepLinks: Collection) - - /** - * Registers the [deepLinks] and ensures that they are unregistered when the [ViewModel] is closed. - */ - fun registerWithViewModel(viewModel: ViewModel, deepLinks: Collection) - /** * Triggers run last launched [Intent] with deeplink handlers that can handle delayed deeplink * after handle [Intent] clear that and second time no intent will be handled diff --git a/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/impl/DefaultDeepLinksRegistry.kt b/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/impl/DefaultDeepLinksRegistry.kt index e51f6b8b37..63f6f60d78 100644 --- a/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/impl/DefaultDeepLinksRegistry.kt +++ b/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/impl/DefaultDeepLinksRegistry.kt @@ -3,11 +3,8 @@ package com.tangem.core.deeplink.impl import android.content.Intent import android.net.Uri import androidx.core.net.toUri -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.ViewModel import com.tangem.core.deeplink.DeepLink import com.tangem.core.deeplink.DeepLinksRegistry -import com.tangem.core.deeplink.utils.DeepLinksLifecycleObserver import timber.log.Timber internal class DefaultDeepLinksRegistry : DeepLinksRegistry { @@ -103,19 +100,6 @@ internal class DefaultDeepLinksRegistry : DeepLinksRegistry { ) } - override fun registerWithLifecycle(owner: LifecycleOwner, deepLinks: Collection) { - val observer = DeepLinksLifecycleObserver(deepLinksRegistry = this, deepLinks) - owner.lifecycle.addObserver(observer) - } - - override fun registerWithViewModel(viewModel: ViewModel, deepLinks: Collection) { - viewModel.addCloseable { - unregister(deepLinks) - } - - register(deepLinks) - } - override fun triggerDelayedDeeplink() { if (lastIntent != null) { val intent = lastIntent diff --git a/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/utils/AppComponentContextExtensions.kt b/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/utils/AppComponentContextExtensions.kt new file mode 100644 index 0000000000..594b8305ca --- /dev/null +++ b/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/utils/AppComponentContextExtensions.kt @@ -0,0 +1,21 @@ +package com.tangem.core.deeplink.utils + +import com.arkivanov.essenty.lifecycle.subscribe +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.deeplink.DeepLink +import com.tangem.core.deeplink.DeepLinksRegistry + +fun AppComponentContext.registerDeepLinks(registry: DeepLinksRegistry, vararg deepLinks: DeepLink) { + registerDeepLinks(registry, deepLinks.toList()) +} + +fun AppComponentContext.registerDeepLinks(registry: DeepLinksRegistry, deepLinks: Collection) { + lifecycle.subscribe( + onCreate = { + registry.register(deepLinks) + }, + onDestroy = { + registry.unregister(deepLinks) + }, + ) +} \ No newline at end of file diff --git a/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/utils/DeepLinksLifecycleObserver.kt b/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/utils/DeepLinksLifecycleObserver.kt deleted file mode 100644 index ae1580e17e..0000000000 --- a/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/utils/DeepLinksLifecycleObserver.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.tangem.core.deeplink.utils - -import androidx.lifecycle.DefaultLifecycleObserver -import androidx.lifecycle.LifecycleOwner -import com.tangem.core.deeplink.DeepLink -import com.tangem.core.deeplink.DeepLinksRegistry - -internal class DeepLinksLifecycleObserver( - private val deepLinksRegistry: DeepLinksRegistry, - private val deepLinks: Collection, -) : DefaultLifecycleObserver { - - override fun onResume(owner: LifecycleOwner) { - deepLinksRegistry.register(deepLinks) - } - - override fun onPause(owner: LifecycleOwner) { - deepLinksRegistry.unregister(deepLinks) - } -} \ No newline at end of file diff --git a/features/tokendetails/api/build.gradle.kts b/features/tokendetails/api/build.gradle.kts index 26d2527cd2..dc22e4ffbb 100644 --- a/features/tokendetails/api/build.gradle.kts +++ b/features/tokendetails/api/build.gradle.kts @@ -10,8 +10,11 @@ android { } dependencies { - implementation(projects.domain.tokens.models) + /** Core */ + implementation(projects.core.decompose) + implementation(projects.core.ui) - /** AndroidX */ - implementation(deps.androidx.fragment.ktx) + /** Domain models */ + implementation(projects.domain.tokens.models) + implementation(projects.domain.wallets.models) } \ No newline at end of file diff --git a/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/TokenDetailsComponent.kt b/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/TokenDetailsComponent.kt new file mode 100644 index 0000000000..a057fcb984 --- /dev/null +++ b/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/TokenDetailsComponent.kt @@ -0,0 +1,16 @@ +package com.tangem.features.tokendetails + +import com.tangem.core.decompose.factory.ComponentFactory +import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWalletId + +interface TokenDetailsComponent : ComposableContentComponent { + + data class Params( + val userWalletId: UserWalletId, + val currency: CryptoCurrency, + ) + + interface Factory : ComponentFactory +} \ No newline at end of file diff --git a/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/navigation/TokenDetailsRouter.kt b/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/navigation/TokenDetailsRouter.kt deleted file mode 100644 index a361d75438..0000000000 --- a/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/navigation/TokenDetailsRouter.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.features.tokendetails.navigation - -import androidx.fragment.app.Fragment - -interface TokenDetailsRouter { - - fun getEntryFragment(): Fragment -} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/DefaultTokenDetailsComponent.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/DefaultTokenDetailsComponent.kt new file mode 100644 index 0000000000..5d4274694f --- /dev/null +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/DefaultTokenDetailsComponent.kt @@ -0,0 +1,78 @@ +package com.tangem.feature.tokendetails + +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.subscribe +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.decompose.context.child +import com.tangem.core.decompose.model.getOrCreateModel +import com.tangem.core.deeplink.DeepLinksRegistry +import com.tangem.core.deeplink.global.BuyCurrencyDeepLink +import com.tangem.core.deeplink.utils.registerDeepLinks +import com.tangem.core.ui.components.NavigationBar3ButtonsScrim +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsModel +import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreen +import com.tangem.features.markets.token.block.TokenMarketBlockComponent +import com.tangem.features.tokendetails.TokenDetailsComponent +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +internal class DefaultTokenDetailsComponent @AssistedInject constructor( + @Assisted appComponentContext: AppComponentContext, + @Assisted params: TokenDetailsComponent.Params, + tokenMarketBlockComponentFactory: TokenMarketBlockComponent.Factory, + deepLinksRegistry: DeepLinksRegistry, +) : TokenDetailsComponent, AppComponentContext by appComponentContext { + + private val model: TokenDetailsModel = getOrCreateModel(params) + + init { + lifecycle.subscribe( + onPause = model::onPause, + onResume = model::onResume, + ) + + registerDeepLinks( + registry = deepLinksRegistry, + BuyCurrencyDeepLink( + onReceive = model::onBuyCurrencyDeepLink, + ), + ) + } + + private val tokenMarketBlockComponent = params.currency.toTokenMarketParam()?.let { tokenMarketParams -> + tokenMarketBlockComponentFactory.create( + appComponentContext = child("tokenMarketBlockComponent"), + params = tokenMarketParams, + ) + } + + @Composable + override fun Content(modifier: Modifier) { + val state by model.uiState.collectAsStateWithLifecycle() + + NavigationBar3ButtonsScrim() + TokenDetailsScreen( + state = state, + tokenMarketBlockComponent = tokenMarketBlockComponent, + ) + } + + private fun CryptoCurrency.toTokenMarketParam(): TokenMarketBlockComponent.Params? { + id.rawCurrencyId ?: return null // token price is not available + + return TokenMarketBlockComponent.Params(cryptoCurrency = this) + } + + @AssistedFactory + interface Factory : TokenDetailsComponent.Factory { + override fun create( + context: AppComponentContext, + params: TokenDetailsComponent.Params, + ): DefaultTokenDetailsComponent + } +} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/di/TokenDetailsModule.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/di/TokenDetailsModule.kt new file mode 100644 index 0000000000..a7ad3dd026 --- /dev/null +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/di/TokenDetailsModule.kt @@ -0,0 +1,38 @@ +package com.tangem.feature.tokendetails.di + +import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.DecomposeComponent +import com.tangem.core.decompose.model.Model +import com.tangem.feature.tokendetails.DefaultTokenDetailsComponent +import com.tangem.feature.tokendetails.presentation.router.DefaultTokenDetailsRouter +import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRouter +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsModel +import com.tangem.features.tokendetails.TokenDetailsComponent +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 TokenDetailsModule { + + @Binds + fun bindComponentFactory(factory: DefaultTokenDetailsComponent.Factory): TokenDetailsComponent.Factory + + @Binds + @IntoMap + @ClassKey(TokenDetailsModel::class) + fun bindModel(model: TokenDetailsModel): Model +} + +@Module +@InstallIn(DecomposeComponent::class) +internal interface StakingComponentModule { + + @Binds + @ComponentScoped + fun bindRouter(impl: DefaultTokenDetailsRouter): InnerTokenDetailsRouter +} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/di/TokenDetailsRouterModule.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/di/TokenDetailsRouterModule.kt deleted file mode 100644 index 94147e5592..0000000000 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/di/TokenDetailsRouterModule.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.tangem.feature.tokendetails.di - -import com.tangem.common.routing.AppRouter -import com.tangem.core.navigation.share.ShareManager -import com.tangem.core.navigation.url.UrlOpener -import com.tangem.feature.tokendetails.presentation.router.DefaultTokenDetailsRouter -import com.tangem.features.tokendetails.navigation.TokenDetailsRouter -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.components.ActivityComponent -import dagger.hilt.android.scopes.ActivityScoped - -@Module -@InstallIn(ActivityComponent::class) -internal object TokenDetailsRouterModule { - - @Provides - @ActivityScoped - fun provideTokenDetailsRouter( - appRouter: AppRouter, - urlOpener: UrlOpener, - shareManager: ShareManager, - ): TokenDetailsRouter { - return DefaultTokenDetailsRouter(appRouter, urlOpener, shareManager) - } -} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/TokenDetailsFragment.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/TokenDetailsFragment.kt deleted file mode 100644 index 2c787270d1..0000000000 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/TokenDetailsFragment.kt +++ /dev/null @@ -1,105 +0,0 @@ -package com.tangem.feature.tokendetails.presentation - -import android.os.Bundle -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.fragment.app.viewModels -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.arkivanov.decompose.defaultComponentContext -import com.tangem.common.routing.AppRoute -import com.tangem.common.routing.AppRouter -import com.tangem.common.routing.bundle.unbundle -import com.tangem.common.routing.utils.asRouter -import com.tangem.core.decompose.context.DefaultAppComponentContext -import com.tangem.core.decompose.di.DecomposeComponent -import com.tangem.core.decompose.di.GlobalUiMessageSender -import com.tangem.core.decompose.ui.UiMessageSender -import com.tangem.core.ui.UiDependencies -import com.tangem.core.ui.components.NavigationBar3ButtonsScrim -import com.tangem.core.ui.screen.ComposeFragment -import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRouter -import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreen -import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsViewModel -import com.tangem.features.markets.token.block.TokenMarketBlockComponent -import com.tangem.features.tokendetails.navigation.TokenDetailsRouter -import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject - -@AndroidEntryPoint -internal class TokenDetailsFragment : ComposeFragment() { - - @Inject - override lateinit var uiDependencies: UiDependencies - - @Inject - @GlobalUiMessageSender - internal lateinit var messageSender: UiMessageSender - - @Inject - internal lateinit var tokenDetailsRouter: TokenDetailsRouter - - @Inject - internal lateinit var coroutineDispatcherProvider: CoroutineDispatcherProvider - - @Inject - internal lateinit var componentBuilder: DecomposeComponent.Builder - - @Inject - internal lateinit var tokenMarketBlockComponentFactory: TokenMarketBlockComponent.Factory - - @Inject - internal lateinit var appRouter: AppRouter - - private val viewModel by viewModels() - - private var tokenMarketBlockComponent: TokenMarketBlockComponent? = null - - private val internalTokenDetailsRouter: InnerTokenDetailsRouter - get() = requireNotNull(tokenDetailsRouter as? InnerTokenDetailsRouter) { - "internalTokenDetailsRouter should be instance of InnerTokenDetailsRouter" - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - viewModel.router = internalTokenDetailsRouter - lifecycle.addObserver(viewModel) - - val cryptoCurrency: CryptoCurrency = arguments - ?.getBundle(AppRoute.CurrencyDetails.CRYPTO_CURRENCY_KEY) - ?.unbundle(CryptoCurrency.serializer()) - ?: error("Token Details screen can't be opened without `CryptoCurrency`") - - val param = cryptoCurrency.toParam() ?: return - - val appContext = DefaultAppComponentContext( - componentContext = defaultComponentContext(requireActivity().onBackPressedDispatcher), - messageSender = messageSender, - dispatchers = coroutineDispatcherProvider, - hiltComponentBuilder = componentBuilder, - replaceRouter = appRouter.asRouter(), - ) - - tokenMarketBlockComponent = tokenMarketBlockComponentFactory.create( - appComponentContext = appContext, - params = param, - ) - } - - private fun CryptoCurrency.toParam(): TokenMarketBlockComponent.Params? { - id.rawCurrencyId ?: return null // token price is not available - - return TokenMarketBlockComponent.Params(cryptoCurrency = this) - } - - @Composable - override fun ScreenContent(modifier: Modifier) { - NavigationBar3ButtonsScrim() - TokenDetailsScreen( - state = viewModel.uiState.collectAsStateWithLifecycle().value, - tokenMarketBlockComponent = tokenMarketBlockComponent, - ) - } -} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/DefaultTokenDetailsRouter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/DefaultTokenDetailsRouter.kt index d8a3eb4733..4ffdf4c587 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/DefaultTokenDetailsRouter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/DefaultTokenDetailsRouter.kt @@ -1,23 +1,22 @@ package com.tangem.feature.tokendetails.presentation.router -import androidx.fragment.app.Fragment import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRouter +import com.tangem.core.decompose.di.ComponentScoped import com.tangem.core.navigation.share.ShareManager import com.tangem.core.navigation.url.UrlOpener import com.tangem.domain.staking.model.stakekit.Yield import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.feature.tokendetails.presentation.TokenDetailsFragment +import javax.inject.Inject -internal class DefaultTokenDetailsRouter( +@ComponentScoped +internal class DefaultTokenDetailsRouter @Inject constructor( private val router: AppRouter, private val urlOpener: UrlOpener, private val shareManager: ShareManager, ) : InnerTokenDetailsRouter { - override fun getEntryFragment(): Fragment = TokenDetailsFragment() - override fun popBackStack() { router.pop() } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/InnerTokenDetailsRouter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/InnerTokenDetailsRouter.kt index e4a143ccd1..156a7c60c1 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/InnerTokenDetailsRouter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/InnerTokenDetailsRouter.kt @@ -3,9 +3,8 @@ package com.tangem.feature.tokendetails.presentation.router import com.tangem.domain.staking.model.stakekit.Yield import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.features.tokendetails.navigation.TokenDetailsRouter -internal interface InnerTokenDetailsRouter : TokenDetailsRouter { +internal interface InnerTokenDetailsRouter { /** Pop back stack */ fun popBackStack() diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsClickIntents.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsClickIntents.kt similarity index 99% rename from features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsClickIntents.kt rename to features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsClickIntents.kt index 8806affc45..c716c21445 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsClickIntents.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsClickIntents.kt @@ -1,4 +1,4 @@ -package com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels +package com.tangem.feature.tokendetails.presentation.tokendetails.model import com.tangem.core.ui.components.bottomsheets.tokenreceive.AddressModel import com.tangem.core.ui.extensions.TextReference diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt similarity index 91% rename from features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt rename to features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt index 744218305e..2f6219c24e 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt @@ -1,21 +1,20 @@ -package com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels +package com.tangem.feature.tokendetails.presentation.tokendetails.model -import android.os.Bundle -import androidx.lifecycle.* +import androidx.compose.runtime.Stable import androidx.paging.cachedIn import arrow.core.getOrElse import com.tangem.blockchain.common.address.AddressType import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRouter -import com.tangem.common.routing.bundle.unbundle import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.decompose.di.ComponentScoped import com.tangem.core.decompose.di.GlobalUiMessageSender +import com.tangem.core.decompose.model.Model +import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.ui.UiMessageSender -import com.tangem.core.deeplink.DeepLinksRegistry -import com.tangem.core.deeplink.global.BuyCurrencyDeepLink import com.tangem.core.navigation.share.ShareManager import com.tangem.core.ui.clipboard.ClipboardManager import com.tangem.core.ui.components.bottomsheets.tokenreceive.AddressModel @@ -36,6 +35,7 @@ import com.tangem.domain.card.NetworkHasDerivationUseCase import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.onramp.model.OnrampSource +import com.tangem.domain.promo.ShouldShowSwapPromoTokenUseCase import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.staking.GetStakingAvailabilityUseCase import com.tangem.domain.staking.GetStakingEntryInfoUseCase @@ -73,12 +73,11 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenBala import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsStateFactory import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.express.ExpressStatusFactory -import com.tangem.domain.promo.ShouldShowSwapPromoTokenUseCase import com.tangem.features.onramp.OnrampFeatureToggles +import com.tangem.features.tokendetails.TokenDetailsComponent import com.tangem.features.tokendetails.impl.R import com.tangem.utils.Provider import com.tangem.utils.coroutines.* -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.async @@ -89,9 +88,10 @@ import timber.log.Timber import javax.inject.Inject @Suppress("LongParameterList", "LargeClass", "TooManyFunctions") -@HiltViewModel -internal class TokenDetailsViewModel @Inject constructor( - private val dispatchers: CoroutineDispatcherProvider, +@Stable +@ComponentScoped +internal class TokenDetailsModel @Inject constructor( + override val dispatchers: CoroutineDispatcherProvider, private val getCurrencyStatusUpdatesUseCase: GetCurrencyStatusUpdatesUseCase, private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase, @@ -122,26 +122,19 @@ internal class TokenDetailsViewModel @Inject constructor( private val onrampFeatureToggles: OnrampFeatureToggles, private val shareManager: ShareManager, @GlobalUiMessageSender private val uiMessageSender: UiMessageSender, + paramsContainer: ParamsContainer, expressStatusFactory: ExpressStatusFactory.Factory, getUserWalletUseCase: GetUserWalletUseCase, getStakingIntegrationIdUseCase: GetStakingIntegrationIdUseCase, - deepLinksRegistry: DeepLinksRegistry, - savedStateHandle: SavedStateHandle, private val appRouter: AppRouter, -) : ViewModel(), DefaultLifecycleObserver, TokenDetailsClickIntents { + private val router: InnerTokenDetailsRouter, +) : Model(), TokenDetailsClickIntents { - private val userWalletId: UserWalletId = savedStateHandle.get(AppRoute.CurrencyDetails.USER_WALLET_ID_KEY) - ?.unbundle(UserWalletId.serializer()) - ?: error("This screen can't be opened without `UserWalletId`") + private val params = paramsContainer.require() + private val userWalletId: UserWalletId = params.userWalletId + private val cryptoCurrency: CryptoCurrency = params.currency - private val cryptoCurrency: CryptoCurrency = - savedStateHandle.get(AppRoute.CurrencyDetails.CRYPTO_CURRENCY_KEY) - ?.unbundle(CryptoCurrency.serializer()) - ?: error("This screen can't be opened without `CryptoCurrency`") - - private val userWallet: UserWallet - - lateinit var router: InnerTokenDetailsRouter + private val userWallet: UserWallet = getUserWalletUseCase(userWalletId).getOrNull() ?: error("UserWallet not found") private val marketPriceJobHolder = JobHolder() private val refreshStateJobHolder = JobHolder() @@ -195,18 +188,16 @@ internal class TokenDetailsViewModel @Inject constructor( val uiState: StateFlow = internalUiState init { - deepLinksRegistry.registerWithViewModel( - viewModel = this, - deepLinks = listOf( - BuyCurrencyDeepLink( - onReceive = ::onBuyCurrencyDeepLink, - ), - ), + analyticsEventsHandler.send( + event = TokenScreenAnalyticsEvent.DetailsScreenOpened(token = cryptoCurrency.symbol), ) - userWallet = getUserWalletUseCase(userWalletId).getOrNull() ?: error("UserWallet not found") + updateTopBarMenu() + initButtons() + updateContent() + handleBalanceHiding() } - private fun onBuyCurrencyDeepLink(externalTxId: String) { + fun onBuyCurrencyDeepLink(externalTxId: String) { if (onrampFeatureToggles.isFeatureEnabled) { router.openOnrampSuccess(externalTxId) } else { @@ -215,36 +206,24 @@ internal class TokenDetailsViewModel @Inject constructor( } } - override fun onCreate(owner: LifecycleOwner) { - analyticsEventsHandler.send( - event = TokenScreenAnalyticsEvent.DetailsScreenOpened(token = cryptoCurrency.symbol), - ) - updateTopBarMenu() - initButtons() - updateContent() - handleBalanceHiding(owner) - } - - override fun onPause(owner: LifecycleOwner) { + fun onPause() { expressTxStatusTaskScheduler.cancelTask() expressTxJobHolder.cancel() - super.onPause(owner) } - override fun onResume(owner: LifecycleOwner) { + fun onResume() { subscribeOnExpressTransactionsUpdates() - super.onResume(owner) } - override fun onCleared() { + override fun onDestroy() { expressTxStatusTaskScheduler.cancelTask() expressTxJobHolder.cancel() - super.onCleared() + super.onDestroy() } private fun initButtons() { // we need also init buttons before start all loading to avoid buttons blocking - viewModelScope.launch { + modelScope.launch { val currentCryptoCurrencyStatus = getCryptoCurrencySyncUseCase.invoke( userWalletId = userWalletId, cryptoCurrencyId = cryptoCurrency.id, @@ -266,15 +245,14 @@ internal class TokenDetailsViewModel @Inject constructor( updateStakingInfo() } - private fun handleBalanceHiding(owner: LifecycleOwner) { + private fun handleBalanceHiding() { getBalanceHidingSettingsUseCase() - .flowWithLifecycle(owner.lifecycle) .onEach { internalUiState.value = stateFactory.getStateWithUpdatedHidden( isBalanceHidden = it.isBalanceHidden, ) } - .launchIn(viewModelScope) + .launchIn(modelScope) } private suspend fun updateButtons(currencyStatus: CryptoCurrencyStatus) { @@ -288,11 +266,11 @@ internal class TokenDetailsViewModel @Inject constructor( internalUiState.value = stateFactory.getManageButtonsState(actions = it.states) } .flowOn(dispatchers.main) - .launchIn(viewModelScope) + .launchIn(modelScope) } private fun updateWarnings(cryptoCurrencyStatus: CryptoCurrencyStatus) { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { getCurrencyWarningsUseCase.invoke( userWalletId = userWalletId, currencyStatus = cryptoCurrencyStatus, @@ -305,13 +283,13 @@ internal class TokenDetailsViewModel @Inject constructor( notificationsAnalyticsSender.send(internalUiState.value, updatedState.notifications) internalUiState.value = updatedState } - .launchIn(viewModelScope) + .launchIn(modelScope) .saveIn(warningsJobHolder) } } private fun subscribeOnCurrencyStatusUpdates() { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { getCurrencyStatusUpdatesUseCase( userWalletId = userWalletId, currencyId = cryptoCurrency.id, @@ -328,13 +306,13 @@ internal class TokenDetailsViewModel @Inject constructor( currencyStatusAnalyticsSender.send(maybeCurrencyStatus) } .flowOn(dispatchers.main) - .launchIn(viewModelScope) + .launchIn(modelScope) .saveIn(marketPriceJobHolder) } } private fun subscribeOnExpressTransactionsUpdates() { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { expressTxStatusTaskScheduler.cancelTask() expressStatusFactory .getExpressStatuses() @@ -345,7 +323,7 @@ internal class TokenDetailsViewModel @Inject constructor( ::updateNetworkToSwapBalance, ) expressTxStatusTaskScheduler.scheduleTask( - viewModelScope, + modelScope, PeriodicTask( isDelayFirst = false, delay = EXPRESS_STATUS_UPDATE_DELAY, @@ -365,13 +343,13 @@ internal class TokenDetailsViewModel @Inject constructor( ) } .flowOn(dispatchers.main) - .launchIn(viewModelScope) + .launchIn(modelScope) .saveIn(expressTxJobHolder) } } private fun updateNetworkToSwapBalance(toCryptoCurrency: CryptoCurrency) { - viewModelScope.launch { + modelScope.launch { updateDelayedCurrencyStatusUseCase( userWalletId = userWalletId, network = toCryptoCurrency.network, @@ -385,7 +363,7 @@ internal class TokenDetailsViewModel @Inject constructor( * @param showItemsLoading - show loading items placeholder. */ private fun updateTxHistory(refresh: Boolean, showItemsLoading: Boolean) { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { val txHistoryItemsCountEither = txHistoryItemsCountUseCase( userWalletId = userWalletId, currency = cryptoCurrency, @@ -404,7 +382,7 @@ internal class TokenDetailsViewModel @Inject constructor( userWalletId = userWalletId, currency = cryptoCurrency, refresh = refresh, - ).map { it.cachedIn(viewModelScope) } + ).map { it.cachedIn(modelScope) } internalUiState.value = stateFactory.getLoadedTxHistoryState(maybeTxHistory) } @@ -412,7 +390,7 @@ internal class TokenDetailsViewModel @Inject constructor( } private fun updateStakingInfo() { - viewModelScope.launch { + modelScope.launch { val availability = getStakingAvailabilityUseCase( userWalletId = userWalletId, cryptoCurrency = cryptoCurrency, @@ -432,7 +410,7 @@ internal class TokenDetailsViewModel @Inject constructor( } private fun updateTopBarMenu() { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { val hasDerivations = networkHasDerivationUseCase(userWallet.scanResponse, cryptoCurrency.network).getOrElse { false } @@ -452,7 +430,7 @@ internal class TokenDetailsViewModel @Inject constructor( maybeAppCurrency.getOrElse { AppCurrency.Default } } .stateIn( - scope = viewModelScope, + scope = modelScope, started = SharingStarted.Eagerly, initialValue = AppCurrency.Default, ) @@ -476,7 +454,7 @@ internal class TokenDetailsViewModel @Inject constructor( val status = cryptoCurrencyStatus ?: return if (onrampFeatureToggles.isFeatureEnabled) { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { reduxStateHolder.dispatch( TradeCryptoAction.Buy( userWallet = userWallet, @@ -488,7 +466,7 @@ internal class TokenDetailsViewModel @Inject constructor( } } else { showErrorIfDemoModeOrElse { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { reduxStateHolder.dispatch( TradeCryptoAction.Buy( userWallet = userWallet, @@ -554,7 +532,7 @@ internal class TokenDetailsViewModel @Inject constructor( return } - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { analyticsEventsHandler.send(TokenScreenAnalyticsEvent.ButtonReceive(cryptoCurrency.symbol)) analyticsEventsHandler.send(TokenReceiveAnalyticsEvent.ReceiveScreenOpened(cryptoCurrency.symbol)) @@ -587,7 +565,7 @@ internal class TokenDetailsViewModel @Inject constructor( } override fun onGenerateExtendedKey() { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { val extendedKey = getExtendedPublicKeyForCurrencyUseCase( userWalletId, cryptoCurrency.network, @@ -655,7 +633,7 @@ internal class TokenDetailsViewModel @Inject constructor( override fun onHideClick() { analyticsEventsHandler.send(TokenScreenAnalyticsEvent.ButtonRemoveToken(cryptoCurrency.symbol)) - viewModelScope.launch { + modelScope.launch { val hasLinkedTokens = removeCurrencyUseCase.hasLinkedTokens(userWalletId, cryptoCurrency) internalUiState.value = if (hasLinkedTokens) { stateFactory.getStateWithLinkedTokensDialog(cryptoCurrency) @@ -666,7 +644,7 @@ internal class TokenDetailsViewModel @Inject constructor( } override fun onHideConfirmed() { - viewModelScope.launch { + modelScope.launch { removeCurrencyUseCase.invoke(userWalletId, cryptoCurrency) .onLeft { Timber.e(it) } .onRight { router.popBackStack() } @@ -681,7 +659,7 @@ internal class TokenDetailsViewModel @Inject constructor( private fun openExplorer() { val currencyStatus = cryptoCurrencyStatus ?: return - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { when (val addresses = currencyStatus.value.networkAddress) { is NetworkAddress.Selectable -> { internalUiState.value = stateFactory.getStateWithChooseAddressBottomSheet(cryptoCurrency, addresses) @@ -713,7 +691,7 @@ internal class TokenDetailsViewModel @Inject constructor( } override fun onAddressTypeSelected(addressModel: AddressModel) { - viewModelScope.launch { + modelScope.launch { router.openUrl( url = getExploreUrlUseCase( userWalletId = userWalletId, @@ -738,7 +716,7 @@ internal class TokenDetailsViewModel @Inject constructor( override fun onRefreshSwipe(isRefreshing: Boolean) { internalUiState.value = stateFactory.getRefreshingState() - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { listOf( async { fetchCurrencyStatusUseCase( @@ -762,7 +740,7 @@ internal class TokenDetailsViewModel @Inject constructor( override fun onDismissBottomSheet() { when (val bsContent = internalUiState.value.bottomSheetConfig?.content) { is ExpressStatusBottomSheetConfig -> { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { expressStatusFactory.removeTransactionOnBottomSheetClosed(bsContent.value) } } @@ -792,7 +770,7 @@ internal class TokenDetailsViewModel @Inject constructor( } override fun onSwapPromoDismiss() { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { shouldShowSwapPromoTokenUseCase.neverToShow() analyticsEventsHandler.send( TokenSwapPromoAnalyticsEvent.PromotionBannerClicked( @@ -805,7 +783,7 @@ internal class TokenDetailsViewModel @Inject constructor( } override fun onSwapPromoClick() { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { shouldShowSwapPromoTokenUseCase.neverToShow() analyticsEventsHandler.send( TokenSwapPromoAnalyticsEvent.PromotionBannerClicked( @@ -836,7 +814,7 @@ internal class TokenDetailsViewModel @Inject constructor( blockchain = cryptoCurrency.network.name, ), ) - viewModelScope.launch { + modelScope.launch { retryIncompleteTransactionUseCase( userWalletId = userWalletId, currency = cryptoCurrency, @@ -877,13 +855,13 @@ internal class TokenDetailsViewModel @Inject constructor( blockchain = cryptoCurrency.network.name, ), ) - viewModelScope.launch { + modelScope.launch { internalUiState.value = stateFactory.getStateWithDismissIncompleteTransactionConfirmDialog() } } override fun onConfirmDismissIncompleteTransactionClick() { - viewModelScope.launch { + modelScope.launch { dismissIncompleteTransactionUseCase( userWalletId = userWalletId, currency = cryptoCurrency, @@ -908,7 +886,7 @@ internal class TokenDetailsViewModel @Inject constructor( blockchain = cryptoCurrency.network.name, ), ) - viewModelScope.launch(dispatchers.io) { + modelScope.launch(dispatchers.io) { associateAssetUseCase( userWalletId = userWalletId, currency = cryptoCurrency, @@ -947,7 +925,7 @@ internal class TokenDetailsViewModel @Inject constructor( override fun onDisposeExpressStatus() { val bottomSheetState = internalUiState.value.bottomSheetConfig?.content if (bottomSheetState is ExpressStatusBottomSheetConfig) { - viewModelScope.launch { + modelScope.launch { expressStatusFactory.removeTransactionOnBottomSheetClosed( expressState = bottomSheetState.value, isForceDispose = true, @@ -979,7 +957,7 @@ internal class TokenDetailsViewModel @Inject constructor( } private fun openStaking() { - viewModelScope.launch { + modelScope.launch { val yield = getYieldUseCase.invoke( cryptoCurrencyId = cryptoCurrency.id, symbol = cryptoCurrency.symbol, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsActionButtonsConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsActionButtonsConverter.kt index c68c1e3be2..50052f3557 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsActionButtonsConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsActionButtonsConverter.kt @@ -4,7 +4,7 @@ import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason import com.tangem.domain.tokens.model.TokenActionsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsActionButton -import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.utils.Provider import com.tangem.utils.converter.Converter import kotlinx.collections.immutable.ImmutableList diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt index 91ac3d6a00..75bb0ebc77 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt @@ -22,7 +22,7 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.* import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsTxHistoryTransactionStateConverter import com.tangem.feature.tokendetails.presentation.tokendetails.state.utils.getBalance -import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.features.tokendetails.impl.R import com.tangem.lib.crypto.BlockchainUtils.isBSC import com.tangem.lib.crypto.BlockchainUtils.isSolana diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt index 1c0e9869ad..f8d51e82c0 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt @@ -13,7 +13,7 @@ import com.tangem.domain.tokens.model.warnings.KaspaWarnings import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification.* -import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.features.tokendetails.impl.R import com.tangem.utils.converter.Converter import com.tangem.utils.extensions.removeBy diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsOnrampTransactionStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsOnrampTransactionStateConverter.kt index ec6b983685..c585e6e3cd 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsOnrampTransactionStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsOnrampTransactionStateConverter.kt @@ -26,7 +26,7 @@ import com.tangem.domain.tokens.model.analytics.TokenOnrampAnalyticsEvent import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateIconUM import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateInfoUM import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM -import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.features.tokendetails.impl.R import com.tangem.utils.Provider import com.tangem.utils.converter.Converter diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt index 44798192e1..d4f23daa2d 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt @@ -16,7 +16,7 @@ import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.feature.tokendetails.presentation.tokendetails.state.* import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsActionButton -import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.features.tokendetails.impl.R import com.tangem.lib.crypto.BlockchainUtils.isBitcoin import com.tangem.utils.converter.Converter diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt index e88c1cc061..a76e681373 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt @@ -33,7 +33,7 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.component import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadedTxHistoryConverter import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadingTxHistoryConverter import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadingTxHistoryConverter.TokenDetailsLoadingTxHistoryModel -import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.features.tokendetails.impl.R import com.tangem.utils.Provider import kotlinx.collections.immutable.toImmutableList diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt index e8e7415770..d13c0cab28 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt @@ -27,7 +27,7 @@ import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionModel import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotifications import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeStatusState import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM -import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.features.tokendetails.impl.R import com.tangem.utils.Provider import com.tangem.utils.converter.Converter diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt index 3bf62b35de..8596a83abd 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt @@ -18,7 +18,7 @@ import com.tangem.feature.swap.domain.models.domain.* import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsSwapTransactionsStateConverter -import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.utils.Provider import dagger.assisted.Assisted import dagger.assisted.AssistedFactory diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt index 5f1c18949f..289cfffede 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt @@ -13,7 +13,7 @@ import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.swap.domain.models.domain.ExchangeStatus import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM -import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.utils.Provider import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.assisted.Assisted diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/OnrampStatusFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/OnrampStatusFactory.kt index 79328454af..e25e788d52 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/OnrampStatusFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/OnrampStatusFactory.kt @@ -17,7 +17,7 @@ import com.tangem.domain.tokens.model.analytics.TokenOnrampAnalyticsEvent import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsOnrampTransactionStateConverter -import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.utils.Provider import dagger.assisted.Assisted import dagger.assisted.AssistedFactory diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsLoadedTxHistoryConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsLoadedTxHistoryConverter.kt index efcc958a22..cb5e434ccf 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsLoadedTxHistoryConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsLoadedTxHistoryConverter.kt @@ -6,7 +6,7 @@ import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.domain.txhistory.models.TxHistoryItem import com.tangem.domain.txhistory.models.TxHistoryListError import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState -import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.utils.Provider import com.tangem.utils.converter.Converter import kotlinx.coroutines.flow.Flow diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsLoadingTxHistoryConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsLoadingTxHistoryConverter.kt index e7c0cd2e1b..479a510db6 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsLoadingTxHistoryConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsLoadingTxHistoryConverter.kt @@ -7,7 +7,7 @@ import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.domain.txhistory.models.TxHistoryStateError import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadingTxHistoryConverter.TokenDetailsLoadingTxHistoryModel -import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.utils.Provider import com.tangem.utils.converter.Converter import kotlinx.collections.immutable.toImmutableList diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryItemFlowConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryItemFlowConverter.kt index 6a8bc163c7..2dc64a9aef 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryItemFlowConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryItemFlowConverter.kt @@ -7,7 +7,7 @@ import com.tangem.core.ui.components.transactions.state.TxHistoryState.TxHistory import com.tangem.core.ui.utils.toDateFormatWithTodayYesterday import com.tangem.domain.txhistory.models.TxHistoryItem import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState -import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.utils.Provider import com.tangem.utils.converter.Converter import kotlinx.coroutines.CoroutineScope diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryTransactionStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryTransactionStateConverter.kt index 360126d91d..8bc7cf05cd 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryTransactionStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryTransactionStateConverter.kt @@ -12,7 +12,7 @@ import com.tangem.core.ui.format.bigdecimal.format import com.tangem.core.ui.utils.toTimeFormat import com.tangem.domain.txhistory.models.TxHistoryItem import com.tangem.domain.txhistory.models.TxHistoryItem.* -import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.features.tokendetails.impl.R import com.tangem.utils.StringsSigns.MINUS import com.tangem.utils.StringsSigns.PLUS From 0658cf67cbd976b5236eb1ccb0aa95a4f0975110 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 19 Feb 2025 15:55:27 +0500 Subject: [PATCH 05/54] Updated on 2026-08-14 --- .../presentation/common/WalletPreviewData.kt | 10 +-- .../common/preview/WalletScreenPreviewData.kt | 6 +- .../implementors/MultiWalletContentLoader.kt | 8 ++ .../MultiWalletContentLoaderFactory.kt | 3 + .../implementors/SingleWalletContentLoader.kt | 7 ++ .../SingleWalletContentLoaderFactory.kt | 3 + .../SingleWalletWithTokenContentLoader.kt | 9 +++ ...ngleWalletWithTokenContentLoaderFactory.kt | 3 + .../wallet/state/model/WalletCardState.kt | 45 +++++------ .../wallet/state/model/WalletDropDownItems.kt | 10 +++ .../InitializeWalletsTransformer.kt | 3 +- .../SetBalancesAndLimitsTransformer.kt | 6 +- .../SetTokenListErrorTransformer.kt | 3 +- .../SetWalletCardDropDownItemsTransformer.kt | 78 +++++++++++++++++++ .../MultiWalletCardStateConverter.kt | 9 +-- .../SingleWalletCardStateConverter.kt | 9 +-- .../state/utils/WalletLoadingStateFactory.kt | 3 +- .../WalletDropDownItemsSubscriber.kt | 30 +++++++ .../wallet/ui/components/common/WalletCard.kt | 53 +++++-------- .../wallet/viewmodels/WalletViewModel.kt | 12 +-- 20 files changed, 213 insertions(+), 97 deletions(-) create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletDropDownItems.kt create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWalletCardDropDownItemsTransformer.kt create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/WalletDropDownItemsSubscriber.kt diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt index f77bbed840..7fd53126fb 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt @@ -13,6 +13,7 @@ import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensListState import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensState import com.tangem.feature.wallet.presentation.wallet.state.model.* +import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toPersistentList import java.util.UUID @@ -32,8 +33,7 @@ internal object WalletPreviewData { content = TextReference.Str("3 cards • Seed phrase3 cards • Seed phrasephrasephrasephrase"), ), imageResId = R.drawable.ill_wallet2_cards3_120_106, - onRenameClick = { _ -> }, - onDeleteClick = {}, + dropDownItems = persistentListOf(), cardCount = 1, isZeroBalance = false, isBalanceFlickering = false, @@ -45,8 +45,7 @@ internal object WalletPreviewData { id = UserWalletId("321"), title = "Wallet 1", imageResId = R.drawable.ill_wallet2_cards3_120_106, - onRenameClick = { _ -> }, - onDeleteClick = {}, + dropDownItems = persistentListOf(), ) } @@ -55,8 +54,7 @@ internal object WalletPreviewData { id = UserWalletId("24"), title = "Wallet 1", imageResId = R.drawable.ill_wallet2_cards3_120_106, - onRenameClick = { _ -> }, - onDeleteClick = {}, + dropDownItems = persistentListOf(), ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt index 6bb90675a5..da8b495a9a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt @@ -87,8 +87,7 @@ internal object WalletScreenPreviewData { content = TextReference.Str("Locked"), ), imageResId = R.drawable.ill_note_btc_120_106, - onRenameClick = { _ -> }, - onDeleteClick = {}, + dropDownItems = persistentListOf(), ) } private val miltiUnreachableCard by lazy { @@ -102,8 +101,7 @@ internal object WalletScreenPreviewData { imageResId = R.drawable.ill_wallet2_cards3_120_106, cardCount = 3, balance = DASH_SIGN, - onRenameClick = { _ -> }, - onDeleteClick = {}, + dropDownItems = persistentListOf(), isZeroBalance = false, isBalanceFlickering = false, ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoader.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoader.kt index b5c157f8b4..a80ea9429f 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoader.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoader.kt @@ -6,6 +6,7 @@ import com.tangem.domain.promo.GetStoryContentUseCase import com.tangem.domain.tokens.ApplyTokenListSortingUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsSingleEventSender @@ -13,6 +14,7 @@ import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarnin import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController +import com.tangem.feature.wallet.presentation.wallet.subscribers.* import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletActionButtonsSubscriber import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletTokenListSubscriber import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletWarningsSubscriber @@ -34,6 +36,7 @@ internal class MultiWalletContentLoader( private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase, private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory, private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase, + private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase, private val getStoryContentUseCase: GetStoryContentUseCase, private val swapFeatureToggles: SwapFeatureToggles, private val deepLinksRegistry: DeepLinksRegistry, @@ -68,6 +71,11 @@ internal class MultiWalletContentLoader( getStoryContentUseCase = getStoryContentUseCase, ).let(::add) } + WalletDropDownItemsSubscriber( + stateHolder = stateHolder, + shouldSaveUserWalletsUseCase = shouldSaveUserWalletsUseCase, + clickIntents = clickIntents, + ).let(::add) } } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoaderFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoaderFactory.kt index 0196a960d0..03ffae14b8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoaderFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoaderFactory.kt @@ -6,6 +6,7 @@ import com.tangem.domain.promo.GetStoryContentUseCase import com.tangem.domain.tokens.ApplyTokenListSortingUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsSingleEventSender @@ -31,6 +32,7 @@ internal class MultiWalletContentLoaderFactory @Inject constructor( private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender, private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender, private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase, + private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase, private val getStoryContentUseCase: GetStoryContentUseCase, private val swapFeatureToggles: SwapFeatureToggles, private val deepLinksRegistry: DeepLinksRegistry, @@ -51,6 +53,7 @@ internal class MultiWalletContentLoaderFactory @Inject constructor( applyTokenListSortingUseCase = applyTokenListSortingUseCase, runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase, getStoryContentUseCase = getStoryContentUseCase, + shouldSaveUserWalletsUseCase = shouldSaveUserWalletsUseCase, swapFeatureToggles = swapFeatureToggles, deepLinksRegistry = deepLinksRegistry, ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoader.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoader.kt index 0d96fb7855..5ebe780476 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoader.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoader.kt @@ -10,6 +10,7 @@ import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.domain.GetSingleWalletWarningsFactory import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController @@ -31,6 +32,7 @@ internal class SingleWalletContentLoader( private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, private val getOnrampTransactionsUseCase: GetOnrampTransactionsUseCase, private val onrampRemoveTransactionUseCase: OnrampRemoveTransactionUseCase, + private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase, private val analyticsEventHandler: AnalyticsEventHandler, private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender, ) : WalletContentLoader(id = userWallet.walletId) { @@ -59,6 +61,11 @@ internal class SingleWalletContentLoader( getSingleWalletWarningsFactory = getSingleWalletWarningsFactory, walletWarningsAnalyticsSender = walletWarningsAnalyticsSender, ), + WalletDropDownItemsSubscriber( + stateHolder = stateHolder, + shouldSaveUserWalletsUseCase = shouldSaveUserWalletsUseCase, + clickIntents = clickIntents, + ), SingleWalletExpressStatusesSubscriber( userWallet = userWallet, stateHolder = stateHolder, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoaderFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoaderFactory.kt index aa40c79e7f..d6a6f49dae 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoaderFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoaderFactory.kt @@ -10,6 +10,7 @@ import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.domain.GetSingleWalletWarningsFactory import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController @@ -30,6 +31,7 @@ internal class SingleWalletContentLoaderFactory @Inject constructor( private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, private val getOnrampTransactionsUseCase: GetOnrampTransactionsUseCase, private val onrampRemoveTransactionUseCase: OnrampRemoveTransactionUseCase, + private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase, private val analyticsEventHandler: AnalyticsEventHandler, private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender, ) { @@ -51,6 +53,7 @@ internal class SingleWalletContentLoaderFactory @Inject constructor( walletWarningsAnalyticsSender = walletWarningsAnalyticsSender, getOnrampTransactionsUseCase = getOnrampTransactionsUseCase, onrampRemoveTransactionUseCase = onrampRemoveTransactionUseCase, + shouldSaveUserWalletsUseCase = shouldSaveUserWalletsUseCase, ) } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoader.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoader.kt index e87a5d2d10..666c0eaacc 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoader.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoader.kt @@ -5,6 +5,7 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.promo.GetStoryContentUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsSingleEventSender @@ -12,9 +13,11 @@ import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarnin import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController +import com.tangem.feature.wallet.presentation.wallet.subscribers.* import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletActionButtonsSubscriber import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletWarningsSubscriber import com.tangem.feature.wallet.presentation.wallet.subscribers.SingleWalletWithTokenListSubscriber +import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletDropDownItemsSubscriber import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import com.tangem.features.swap.SwapFeatureToggles @@ -32,6 +35,7 @@ internal class SingleWalletWithTokenContentLoader( private val tokenListStore: MultiWalletTokenListStore, private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase, + private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase, private val getStoryContentUseCase: GetStoryContentUseCase, private val swapFeatureToggles: SwapFeatureToggles, private val deepLinksRegistry: DeepLinksRegistry, @@ -65,6 +69,11 @@ internal class SingleWalletWithTokenContentLoader( getStoryContentUseCase = getStoryContentUseCase, ).let(::add) } + WalletDropDownItemsSubscriber( + stateHolder = stateHolder, + shouldSaveUserWalletsUseCase = shouldSaveUserWalletsUseCase, + clickIntents = clickIntents, + ).let(::add) } } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoaderFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoaderFactory.kt index 002f3fc487..78cd9fa1ca 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoaderFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoaderFactory.kt @@ -5,6 +5,7 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.promo.GetStoryContentUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsSingleEventSender @@ -28,6 +29,7 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor( private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender, private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender, private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase, + private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase, private val getStoryContentUseCase: GetStoryContentUseCase, private val swapFeatureToggles: SwapFeatureToggles, private val deepLinksRegistry: DeepLinksRegistry, @@ -47,6 +49,7 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor( walletWarningsSingleEventSender = walletWarningsSingleEventSender, runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase, getStoryContentUseCase = getStoryContentUseCase, + shouldSaveUserWalletsUseCase = shouldSaveUserWalletsUseCase, swapFeatureToggles = swapFeatureToggles, deepLinksRegistry = deepLinksRegistry, ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletCardState.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletCardState.kt index c03ee58d88..2be0662c6c 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletCardState.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletCardState.kt @@ -5,6 +5,7 @@ import androidx.compose.runtime.Immutable import com.tangem.core.ui.extensions.TextReference import com.tangem.domain.wallets.models.UserWalletId import com.tangem.utils.StringsSigns.DASH_SIGN +import kotlinx.collections.immutable.ImmutableList /** Wallet card state */ @Immutable @@ -23,11 +24,8 @@ internal sealed interface WalletCardState { @get:DrawableRes val imageResId: Int? - /** Lambda be invoked when Rename button is clicked */ - val onRenameClick: (UserWalletId) -> Unit - - /** Lambda be invoked when Delete button is clicked */ - val onDeleteClick: (UserWalletId) -> Unit + /** Wallet drop down items */ + val dropDownItems: ImmutableList /** * Wallet card content state @@ -35,8 +33,7 @@ internal sealed interface WalletCardState { * @property id wallet id * @property title wallet name * @property imageResId wallet image resource id - * @property onRenameClick lambda be invoked when Rename button is clicked - * @property onDeleteClick lambda be invoked when Delete button is clicked + * @property dropDownItems wallet dropdown items * @property additionalInfo wallet additional info * @property cardCount number of cards in the wallet * @property balance wallet balance @@ -46,8 +43,7 @@ internal sealed interface WalletCardState { override val title: String, override val additionalInfo: WalletAdditionalInfo, override val imageResId: Int?, - override val onRenameClick: (UserWalletId) -> Unit, - override val onDeleteClick: (UserWalletId) -> Unit, + override val dropDownItems: ImmutableList, val isBalanceFlickering: Boolean, val cardCount: Int?, val balance: String, @@ -61,16 +57,14 @@ internal sealed interface WalletCardState { * @property title wallet name * @property additionalInfo wallet additional info * @property imageResId wallet image resource id - * @property onRenameClick lambda be invoked when Rename button is clicked - * @property onDeleteClick lambda be invoked when Delete button is clicked + * @property dropDownItems wallet dropdown items */ data class LockedContent( override val id: UserWalletId, override val title: String, override val additionalInfo: WalletAdditionalInfo, override val imageResId: Int?, - override val onRenameClick: (UserWalletId) -> Unit, - override val onDeleteClick: (UserWalletId) -> Unit, + override val dropDownItems: ImmutableList, ) : WalletCardState /** @@ -79,16 +73,14 @@ internal sealed interface WalletCardState { * @property id wallet id * @property title wallet name * @property imageResId wallet image resource id - * @property onRenameClick lambda be invoked when Rename button is clicked - * @property onDeleteClick lambda be invoked when Delete button is clicked + * @property dropDownItems wallet dropdown items */ data class Error( override val id: UserWalletId, override val title: String, override val additionalInfo: WalletAdditionalInfo? = defaultAdditionalInfo, override val imageResId: Int?, - override val onRenameClick: (UserWalletId) -> Unit, - override val onDeleteClick: (UserWalletId) -> Unit, + override val dropDownItems: ImmutableList, ) : WalletCardState { private companion object { @@ -103,24 +95,25 @@ internal sealed interface WalletCardState { * @property id wallet id * @property title wallet name * @property imageResId wallet image resource id - * @property onRenameClick lambda be invoked when Rename button is clicked - * @property onDeleteClick lambda be invoked when Delete button is clicked + * @property dropDownItems wallet dropdown items */ data class Loading( override val id: UserWalletId, override val title: String, override val additionalInfo: WalletAdditionalInfo? = null, override val imageResId: Int?, - override val onRenameClick: (UserWalletId) -> Unit, - override val onDeleteClick: (UserWalletId) -> Unit, + override val dropDownItems: ImmutableList, ) : WalletCardState - fun copySealed(title: String = this.title): WalletCardState { + fun copySealed( + title: String = this.title, + dropDownItems: ImmutableList = this.dropDownItems, + ): WalletCardState { return when (this) { - is Content -> copy(title = title) - is Error -> copy(title = title) - is Loading -> copy(title = title) - is LockedContent -> copy(title = title) + is Content -> copy(title = title, dropDownItems = dropDownItems) + is Error -> copy(title = title, dropDownItems = dropDownItems) + is Loading -> copy(title = title, dropDownItems = dropDownItems) + is LockedContent -> copy(title = title, dropDownItems = dropDownItems) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletDropDownItems.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletDropDownItems.kt new file mode 100644 index 0000000000..6e9166db40 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletDropDownItems.kt @@ -0,0 +1,10 @@ +package com.tangem.feature.wallet.presentation.wallet.state.model + +import androidx.compose.ui.graphics.vector.ImageVector +import com.tangem.core.ui.extensions.TextReference + +internal data class WalletDropDownItems( + val text: TextReference, + val icon: ImageVector, + val onClick: () -> Unit, +) \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/InitializeWalletsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/InitializeWalletsTransformer.kt index bfa6f1caa6..63b2d6c2a6 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/InitializeWalletsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/InitializeWalletsTransformer.kt @@ -91,8 +91,7 @@ internal class InitializeWalletsTransformer( title = name, additionalInfo = WalletAdditionalInfoFactory.resolve(wallet = this), imageResId = walletImageResolver.resolve(userWallet = this), - onRenameClick = clickIntents::onRenameBeforeConfirmationClick, - onDeleteClick = clickIntents::onDeleteBeforeConfirmationClick, + dropDownItems = persistentListOf(), ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetBalancesAndLimitsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetBalancesAndLimitsTransformer.kt index 97bbb348fb..a4d821f725 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetBalancesAndLimitsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetBalancesAndLimitsTransformer.kt @@ -58,8 +58,7 @@ internal class SetBalancesAndLimitsTransformer( id = id, title = title, imageResId = imageResId, - onRenameClick = onRenameClick, - onDeleteClick = onDeleteClick, + dropDownItems = dropDownItems, ) } } @@ -71,8 +70,7 @@ internal class SetBalancesAndLimitsTransformer( title = title, additionalInfo = createAdditionalInfo(visaCurrency), imageResId = imageResId, - onRenameClick = onRenameClick, - onDeleteClick = onDeleteClick, + dropDownItems = dropDownItems, balance = visaCurrency.balances.available.format { crypto(visaCurrency.symbol, visaCurrency.decimals) }, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListErrorTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListErrorTransformer.kt index 3705598bcd..a3522cddca 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListErrorTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListErrorTransformer.kt @@ -60,8 +60,7 @@ internal class SetTokenListErrorTransformer( title = title, additionalInfo = WalletAdditionalInfoFactory.resolve(wallet = selectedWallet), imageResId = imageResId, - onRenameClick = onRenameClick, - onDeleteClick = onDeleteClick, + dropDownItems = dropDownItems, balance = BigDecimalFormatter.formatFiatAmount( fiatAmount = BigDecimal.ZERO, fiatCurrencyCode = appCurrency.code, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWalletCardDropDownItemsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWalletCardDropDownItemsTransformer.kt new file mode 100644 index 0000000000..f538e29f90 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWalletCardDropDownItemsTransformer.kt @@ -0,0 +1,78 @@ +package com.tangem.feature.wallet.presentation.wallet.state.transformers + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Delete +import androidx.compose.material.icons.outlined.Edit +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.feature.wallet.impl.R +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDropDownItems +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState +import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletCardClickIntents +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList + +internal class SetWalletCardDropDownItemsTransformer( + private val dropdownEnabled: Boolean, + private val clickIntents: WalletCardClickIntents, +) : WalletScreenStateTransformer { + override fun transform(prevState: WalletScreenState): WalletScreenState { + return prevState.copy(wallets = prevState.wallets.map(::transformWalletState).toImmutableList()) + } + + private fun transformWalletState(prevState: WalletState): WalletState { + return when (prevState) { + is WalletState.MultiCurrency.Content -> prevState.copy( + walletCardState = prevState.walletCardState.copySealed( + dropDownItems = constructDropDownItems(prevState.walletCardState.id), + ), + ) + is WalletState.SingleCurrency.Content -> prevState.copy( + walletCardState = prevState.walletCardState.copySealed( + dropDownItems = constructDropDownItems(prevState.walletCardState.id), + ), + ) + is WalletState.Visa.Content -> prevState.copy( + walletCardState = prevState.walletCardState.copySealed( + dropDownItems = constructDropDownItems(prevState.walletCardState.id), + ), + ) + is WalletState.MultiCurrency.Locked -> prevState.copy( + walletCardState = prevState.walletCardState.copySealed( + dropDownItems = constructDropDownItems(prevState.walletCardState.id), + ), + ) + is WalletState.SingleCurrency.Locked -> prevState.copy( + walletCardState = prevState.walletCardState.copySealed( + dropDownItems = constructDropDownItems(prevState.walletCardState.id), + ), + ) + is WalletState.Visa.Locked -> prevState.copy( + walletCardState = prevState.walletCardState.copySealed( + dropDownItems = constructDropDownItems(prevState.walletCardState.id), + ), + ) + } + } + + private fun constructDropDownItems(userWalletId: UserWalletId): ImmutableList { + return if (dropdownEnabled) { + persistentListOf( + WalletDropDownItems( + text = resourceReference(id = R.string.common_rename), + icon = Icons.Outlined.Edit, + onClick = { clickIntents.onRenameBeforeConfirmationClick(userWalletId) }, + ), + WalletDropDownItems( + text = resourceReference(id = R.string.common_delete), + icon = Icons.Outlined.Delete, + onClick = { clickIntents.onDeleteBeforeConfirmationClick(userWalletId) }, + ), + ) + } else { + persistentListOf() + } + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCardStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCardStateConverter.kt index 2fdbb17338..65a68880bb 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCardStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCardStateConverter.kt @@ -30,8 +30,7 @@ internal class MultiWalletCardStateConverter( title = title, additionalInfo = additionalInfo, imageResId = imageResId, - onRenameClick = onRenameClick, - onDeleteClick = onDeleteClick, + dropDownItems = dropDownItems, ) } @@ -41,8 +40,7 @@ internal class MultiWalletCardStateConverter( title = title, additionalInfo = additionalInfo, imageResId = imageResId, - onDeleteClick = onDeleteClick, - onRenameClick = onRenameClick, + dropDownItems = dropDownItems, ) } @@ -52,8 +50,7 @@ internal class MultiWalletCardStateConverter( title = title, additionalInfo = WalletAdditionalInfoFactory.resolve(wallet = selectedWallet), imageResId = imageResId, - onRenameClick = onRenameClick, - onDeleteClick = onDeleteClick, + dropDownItems = dropDownItems, balance = BigDecimalFormatter.formatFiatAmount( fiatAmount = fiatBalance.amount, fiatCurrencyCode = appCurrency.code, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/SingleWalletCardStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/SingleWalletCardStateConverter.kt index 83dd7c2422..f763c222f8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/SingleWalletCardStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/SingleWalletCardStateConverter.kt @@ -36,8 +36,7 @@ internal class SingleWalletCardStateConverter( id = id, title = title, imageResId = imageResId, - onRenameClick = onRenameClick, - onDeleteClick = onDeleteClick, + dropDownItems = dropDownItems, ) } @@ -46,8 +45,7 @@ internal class SingleWalletCardStateConverter( id = id, title = title, imageResId = imageResId, - onRenameClick = onRenameClick, - onDeleteClick = onDeleteClick, + dropDownItems = dropDownItems, ) } @@ -60,8 +58,7 @@ internal class SingleWalletCardStateConverter( currencyAmount = status.amount, ), imageResId = imageResId, - onRenameClick = onRenameClick, - onDeleteClick = onDeleteClick, + dropDownItems = dropDownItems, balance = formatFiatAmount(status = status, appCurrency = appCurrency), cardCount = selectedWallet.getCardsCount(), isZeroBalance = status.fiatAmount?.isZero(), diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/WalletLoadingStateFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/WalletLoadingStateFactory.kt index 601894c802..2ea461b088 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/WalletLoadingStateFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/WalletLoadingStateFactory.kt @@ -90,8 +90,7 @@ internal class WalletLoadingStateFactory( title = name, additionalInfo = if (isMultiCurrency) WalletAdditionalInfoFactory.resolve(wallet = this) else null, imageResId = walletImageResolver.resolve(userWallet = this), - onRenameClick = clickIntents::onRenameBeforeConfirmationClick, - onDeleteClick = clickIntents::onDeleteBeforeConfirmationClick, + dropDownItems = persistentListOf(), ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/WalletDropDownItemsSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/WalletDropDownItemsSubscriber.kt new file mode 100644 index 0000000000..b58c62f9a1 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/WalletDropDownItemsSubscriber.kt @@ -0,0 +1,30 @@ +package com.tangem.feature.wallet.presentation.wallet.subscribers + +import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase +import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController +import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetWalletCardDropDownItemsTransformer +import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.* + +internal class WalletDropDownItemsSubscriber( + private val stateHolder: WalletStateController, + private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase, + private val clickIntents: WalletClickIntents, +) : WalletSubscriber() { + override fun create(coroutineScope: CoroutineScope): Flow<*> { + return flow { + shouldSaveUserWalletsUseCase.invoke() + .distinctUntilChanged() + .onEach { + stateHolder.update( + SetWalletCardDropDownItemsTransformer( + dropdownEnabled = it, + clickIntents = clickIntents, + ), + ) + } + .launchIn(coroutineScope) + } + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletCard.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletCard.kt index 2539a970d6..dd24826ded 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletCard.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletCard.kt @@ -2,7 +2,6 @@ package com.tangem.feature.wallet.presentation.wallet.ui.components.common import android.content.res.Configuration import androidx.annotation.DrawableRes -import androidx.annotation.StringRes import androidx.compose.animation.* import androidx.compose.animation.core.tween import androidx.compose.foundation.Image @@ -14,9 +13,6 @@ import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.PressInteraction import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.Delete -import androidx.compose.material.icons.outlined.Edit import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable @@ -48,13 +44,14 @@ import com.tangem.core.ui.components.flicker import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.orMaskWithStars import com.tangem.core.ui.extensions.resolveReference -import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemDimens import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.presentation.common.WalletPreviewData import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDropDownItems +import com.tangem.feature.wallet.presentation.wallet.ui.components.fastForEach +import kotlinx.collections.immutable.ImmutableList private const val HALF_OF_ITEM_WIDTH = 0.5 @@ -71,8 +68,7 @@ private const val HALF_OF_ITEM_WIDTH = 0.5 internal fun WalletCard(state: WalletCardState, isBalanceHidden: Boolean, modifier: Modifier = Modifier) { @Suppress("DestructuringDeclarationWithTooManyEntries") CardContainer( - onDeleteClick = { state.onDeleteClick(state.id) }, - onRenameClick = { state.onRenameClick(state.id) }, + dropDownItems = state.dropDownItems, isLockedState = state is WalletCardState.LockedContent, modifier = modifier, ) { itemSize -> @@ -148,8 +144,7 @@ internal fun WalletCard(state: WalletCardState, isBalanceHidden: Boolean, modifi @Composable private fun CardContainer( - onDeleteClick: () -> Unit, - onRenameClick: () -> Unit, + dropDownItems: ImmutableList, isLockedState: Boolean, modifier: Modifier = Modifier, content: @Composable (ConstraintLayoutScope.(IntSize) -> Unit), @@ -167,7 +162,7 @@ private fun CardContainer( .defaultMinSize(minHeight = TangemTheme.dimens.size108) .onSizeChanged { itemSize = it } .then( - if (isLockedState) { + if (isLockedState || dropDownItems.isEmpty()) { Modifier } else { Modifier @@ -210,8 +205,7 @@ private fun CardContainer( pressOffset = pressOffset, itemHeight = itemHeight, onDismissRequest = { isMenuVisible = false }, - onShowRenameWalletDialogClick = onRenameClick, - onDeleteClick = onDeleteClick, + dropDownItems = dropDownItems, ) } @@ -222,8 +216,7 @@ private fun ManageWalletContextMenu( pressOffset: DpOffset, itemHeight: Dp, onDismissRequest: () -> Unit, - onShowRenameWalletDialogClick: () -> Unit, - onDeleteClick: () -> Unit, + dropDownItems: ImmutableList, ) { DropdownMenu( expanded = isMenuVisible, @@ -231,29 +224,23 @@ private fun ManageWalletContextMenu( modifier = Modifier.background(color = TangemTheme.colors.background.secondary), offset = pressOffset.copy(y = pressOffset.y - itemHeight), ) { - MenuItem( - textResId = R.string.common_rename, - imageVector = Icons.Outlined.Edit, - onClick = { - onDismissRequest() - onShowRenameWalletDialogClick() - }, - ) - MenuItem( - textResId = R.string.common_delete, - imageVector = Icons.Outlined.Delete, - onClick = { - onDismissRequest() - onDeleteClick() - }, - ) + dropDownItems.fastForEach { item -> + MenuItem( + text = item.text, + imageVector = item.icon, + onClick = { + onDismissRequest() + item.onClick() + }, + ) + } } } @Composable -private fun MenuItem(@StringRes textResId: Int, imageVector: ImageVector, onClick: () -> Unit) { +private fun MenuItem(text: TextReference, imageVector: ImageVector, onClick: () -> Unit) { DropdownMenuItem( - text = { Text(text = stringResourceSafe(id = textResId), style = TangemTheme.typography.subtitle2) }, + text = { Text(text = text.resolveReference(), style = TangemTheme.typography.subtitle2) }, modifier = Modifier.background(color = TangemTheme.colors.background.secondary), trailingIcon = { Icon(imageVector = imageVector, contentDescription = null) }, onClick = onClick, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index cff354e8fa..1ddf2fdb9b 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -299,12 +299,6 @@ internal class WalletViewModel @Inject constructor( } private suspend fun initializeWallets(action: WalletsUpdateActionResolver.Action.InitializeWallets) { - walletScreenContentLoader.load( - userWallet = action.selectedWallet, - clickIntents = clickIntents, - coroutineScope = viewModelScope, - ) - stateHolder.update( transformer = InitializeWalletsTransformer( selectedWalletIndex = action.selectedWalletIndex, @@ -315,6 +309,12 @@ internal class WalletViewModel @Inject constructor( ), ) + walletScreenContentLoader.load( + userWallet = action.selectedWallet, + clickIntents = clickIntents, + coroutineScope = viewModelScope, + ) + if (action.wallets.size > 1 && isWalletsScrollPreviewEnabled()) { withContext(dispatchers.io) { delay(timeMillis = 1_800) } From 84570a8406cef0f2101f1fdd00d29e02d23c5cb8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 19 Feb 2025 18:06:50 +0300 Subject: [PATCH 06/54] Updated on 2026-08-14 --- app/build.gradle.kts | 7 +- .../data/visa/utils/VisaCurrencyFactory.kt | 1 - .../tangem/domain/visa/model/VisaCurrency.kt | 1 - .../BalancesAndLimitsBottomSheetConfig.kt | 1 - .../BalancesAndLimitsBottomSheetConverter.kt | 1 - .../visa/BalancesAndLimitsBottomSheet.kt | 5 - gradle/dependencies.toml | 2 +- libs/visa/build.gradle.kts | 6 + .../main/java/com/tangem/lib/visa/ERC20.java | 183 +- .../lib/visa/TangemBridgeProcessor.java | 1807 +++++++------ .../tangem/lib/visa/TangemPaymentAccount.java | 2392 ++++++++++------- .../visa/TangemPaymentAccountRegistry.java | 506 ++-- .../visa/DefaultVisaContractInfoProvider.kt | 43 +- .../tangem/lib/visa/model/VisaContractInfo.kt | 1 - settings.gradle.kts | 11 + 15 files changed, 2860 insertions(+), 2107 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f3177619a4..8fa9c93920 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,9 +22,14 @@ android { jniLibs { useLegacyPackaging = true } - resources.excludes.add("META-INF/DEPENDENCIES") resources.excludes.add("META-INF/LICENSE.md") resources.excludes.add("META-INF/NOTICE.md") + resources.excludes.add("META-INF/DISCLAIMER") + resources.excludes.add("META-INF/DEPENDENCIES") + resources.excludes.add("META-INF/FastDoubleParser-NOTICE") + resources.excludes.add("META-INF/FastDoubleParser-LICENSE") + resources.excludes.add("META-INF/io.netty.versions.properties") + resources.excludes.add("META-INF/INDEX.LIST") } androidResources { generateLocaleConfig = true diff --git a/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaCurrencyFactory.kt b/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaCurrencyFactory.kt index 6398dcec84..989a2d504c 100644 --- a/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaCurrencyFactory.kt +++ b/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaCurrencyFactory.kt @@ -32,7 +32,6 @@ internal class VisaCurrencyFactory { available = balances.available.forPayment, blocked = balances.blocked, debt = balances.debt, - pendingRefund = balances.pendingRefund, ) }, limits = VisaCurrency.Limits( diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/visa/model/VisaCurrency.kt b/domain/visa/src/main/kotlin/com/tangem/domain/visa/model/VisaCurrency.kt index 1e6a0c55a1..b21df662c3 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/visa/model/VisaCurrency.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/visa/model/VisaCurrency.kt @@ -20,7 +20,6 @@ data class VisaCurrency( val available: BigDecimal, val blocked: BigDecimal, val debt: BigDecimal, - val pendingRefund: BigDecimal, ) data class Limits( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/BalancesAndLimitsBottomSheetConfig.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/BalancesAndLimitsBottomSheetConfig.kt index 1dd961ab14..cedb03bee2 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/BalancesAndLimitsBottomSheetConfig.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/BalancesAndLimitsBottomSheetConfig.kt @@ -12,7 +12,6 @@ internal data class BalancesAndLimitsBottomSheetConfig( val availableBalance: String, val blockedBalance: String, val debit: String, - val pending: String, val amlVerified: String, val onInfoClick: () -> Unit, ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/BalancesAndLimitsBottomSheetConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/BalancesAndLimitsBottomSheetConverter.kt index dc965b29e2..ffb4722637 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/BalancesAndLimitsBottomSheetConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/BalancesAndLimitsBottomSheetConverter.kt @@ -27,7 +27,6 @@ internal class BalancesAndLimitsBottomSheetConverter( availableBalance = value.balances.available.let(::formatAmount), blockedBalance = value.balances.blocked.let(::formatAmount), debit = value.balances.debt.let(::formatAmount), - pending = value.balances.pendingRefund.let(::formatAmount), amlVerified = value.balances.verified.let(::formatAmount), onInfoClick = this::showBalanceInfo, ), diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/BalancesAndLimitsBottomSheet.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/BalancesAndLimitsBottomSheet.kt index 97dd93b282..d9296dab81 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/BalancesAndLimitsBottomSheet.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/BalancesAndLimitsBottomSheet.kt @@ -78,10 +78,6 @@ private fun BalancesBlock(balances: BalancesAndLimitsBottomSheetConfig.Balance, title = stringReference("Debit"), value = balances.debit, ) - BlockItem( - title = stringReference("Pending refund"), - value = balances.pending, - ) }, description = { InfoButton(onClick = balances.onInfoClick) @@ -180,7 +176,6 @@ private class BalancesAndLimitsBottomSheetParameterProvider : availableBalance = "392.45 USDT", blockedBalance = "36.00 USDT", debit = "00.00 USDT", - pending = "20.99 USDT", amlVerified = "356.45 USDT", onInfoClick = {}, ), diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 060b0ba823..7f200fada5 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -80,7 +80,7 @@ mlKit-barcodeScanning = "17.2.0" androidXCamera = "1.3.0" listenableFuture = "1.0" swipeRefreshLayout = "1.1.0" -web3j = "4.10.1" +web3j = "4.12.3-SNAPSHOT" leakcanary = "2.13" decompose = "2.2.2" room = "2.6.1" diff --git a/libs/visa/build.gradle.kts b/libs/visa/build.gradle.kts index eb6f922306..d73b1485ff 100644 --- a/libs/visa/build.gradle.kts +++ b/libs/visa/build.gradle.kts @@ -9,6 +9,12 @@ plugins { android { namespace = "com.tangem.libs.visa" + + packaging { + resources { + excludes += "/META-INF/*" + } + } } dependencies { diff --git a/libs/visa/src/main/java/com/tangem/lib/visa/ERC20.java b/libs/visa/src/main/java/com/tangem/lib/visa/ERC20.java index fb6048f082..5ea4655792 100644 --- a/libs/visa/src/main/java/com/tangem/lib/visa/ERC20.java +++ b/libs/visa/src/main/java/com/tangem/lib/visa/ERC20.java @@ -1,8 +1,18 @@ package com.tangem.lib.visa; +import io.reactivex.Flowable; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import org.web3j.abi.EventEncoder; import org.web3j.abi.TypeReference; -import org.web3j.abi.datatypes.*; +import org.web3j.abi.datatypes.Address; +import org.web3j.abi.datatypes.Event; +import org.web3j.abi.datatypes.Function; +import org.web3j.abi.datatypes.Type; +import org.web3j.abi.datatypes.Utf8String; import org.web3j.abi.datatypes.generated.Uint256; import org.web3j.abi.datatypes.generated.Uint8; import org.web3j.crypto.Credentials; @@ -17,25 +27,17 @@ import org.web3j.tx.Contract; import org.web3j.tx.TransactionManager; import org.web3j.tx.gas.ContractGasProvider; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import io.reactivex.Flowable; - /** *

Auto generated code. *

Do not modify! *

Please use the web3j command line tools, - * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the - * codegen module to update. + * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the + * codegen module to update. * - *

Generated with web3j version 1.5.2. + *

Generated with web3j version 1.6.1. */ @SuppressWarnings("rawtypes") -class ERC20 extends Contract { +public class ERC20 extends Contract { public static final String BINARY = "Bin file was not provided"; public static final String FUNC_ALLOWANCE = "allowance"; @@ -57,39 +59,40 @@ class ERC20 extends Contract { public static final String FUNC_TRANSFERFROM = "transferFrom"; public static final Event APPROVAL_EVENT = new Event("Approval", - Arrays.asList(new TypeReference

(true) { - }, new TypeReference
(true) { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference
(true) {}, new TypeReference
(true) {}, new TypeReference() {})); + ; public static final Event TRANSFER_EVENT = new Event("Transfer", - Arrays.asList(new TypeReference
(true) { - }, new TypeReference
(true) { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference
(true) {}, new TypeReference
(true) {}, new TypeReference() {})); + ; @Deprecated - protected ERC20(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + protected ERC20(String contractAddress, Web3j web3j, Credentials credentials, + BigInteger gasPrice, BigInteger gasLimit) { super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit); } - protected ERC20(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { + protected ERC20(String contractAddress, Web3j web3j, Credentials credentials, + ContractGasProvider contractGasProvider) { super(BINARY, contractAddress, web3j, credentials, contractGasProvider); } @Deprecated - protected ERC20(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + protected ERC20(String contractAddress, Web3j web3j, TransactionManager transactionManager, + BigInteger gasPrice, BigInteger gasLimit) { super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit); } - protected ERC20(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + protected ERC20(String contractAddress, Web3j web3j, TransactionManager transactionManager, + ContractGasProvider contractGasProvider) { super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider); } - public static List getApprovalEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(APPROVAL_EVENT, transactionReceipt); + public static List getApprovalEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(APPROVAL_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { ApprovalEventResponse typedResponse = new ApprovalEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.owner = (String) eventValues.getIndexedValues().get(0).getValue(); @@ -101,7 +104,7 @@ class ERC20 extends Contract { } public static ApprovalEventResponse getApprovalEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(APPROVAL_EVENT, log); + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(APPROVAL_EVENT, log); ApprovalEventResponse typedResponse = new ApprovalEventResponse(); typedResponse.log = log; typedResponse.owner = (String) eventValues.getIndexedValues().get(0).getValue(); @@ -110,20 +113,22 @@ class ERC20 extends Contract { return typedResponse; } - @Deprecated - public static ERC20 load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { - return new ERC20(contractAddress, web3j, credentials, gasPrice, gasLimit); + public Flowable approvalEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getApprovalEventFromLog(log)); } - @Deprecated - public static ERC20 load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { - return new ERC20(contractAddress, web3j, transactionManager, gasPrice, gasLimit); + public Flowable approvalEventFlowable(DefaultBlockParameter startBlock, + DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(APPROVAL_EVENT)); + return approvalEventFlowable(filter); } - public static List getTransferEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(TRANSFER_EVENT, transactionReceipt); + public static List getTransferEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(TRANSFER_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { TransferEventResponse typedResponse = new TransferEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.from = (String) eventValues.getIndexedValues().get(0).getValue(); @@ -135,7 +140,7 @@ class ERC20 extends Contract { } public static TransferEventResponse getTransferEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(TRANSFER_EVENT, log); + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(TRANSFER_EVENT, log); TransferEventResponse typedResponse = new TransferEventResponse(); typedResponse.log = log; typedResponse.from = (String) eventValues.getIndexedValues().get(0).getValue(); @@ -148,107 +153,107 @@ class ERC20 extends Contract { return web3j.ethLogFlowable(filter).map(log -> getTransferEventFromLog(log)); } - public Flowable transferEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public Flowable transferEventFlowable(DefaultBlockParameter startBlock, + DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); filter.addSingleTopic(EventEncoder.encode(TRANSFER_EVENT)); return transferEventFlowable(filter); } - public static ERC20 load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { - return new ERC20(contractAddress, web3j, credentials, contractGasProvider); - } - - public static ERC20 load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { - return new ERC20(contractAddress, web3j, transactionManager, contractGasProvider); - } - - public Flowable approvalEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getApprovalEventFromLog(log)); - } - - public Flowable approvalEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(APPROVAL_EVENT)); - return approvalEventFlowable(filter); - } - public RemoteFunctionCall allowance(String owner, String spender) { final Function function = new Function(FUNC_ALLOWANCE, - Arrays.asList(new Address(160, owner), - new Address(160, spender)), - List.of(new TypeReference() { - })); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, owner), + new org.web3j.abi.datatypes.Address(160, spender)), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public RemoteFunctionCall approve(String spender, BigInteger value) { final Function function = new Function( FUNC_APPROVE, - Arrays.asList(new Address(160, spender), - new Uint256(value)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, spender), + new org.web3j.abi.datatypes.generated.Uint256(value)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall balanceOf(String account) { final Function function = new Function(FUNC_BALANCEOF, - List.of(new Address(160, account)), - List.of(new TypeReference() { - })); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, account)), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public RemoteFunctionCall decimals() { final Function function = new Function(FUNC_DECIMALS, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public RemoteFunctionCall name() { final Function function = new Function(FUNC_NAME, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, String.class); } public RemoteFunctionCall symbol() { final Function function = new Function(FUNC_SYMBOL, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, String.class); } public RemoteFunctionCall totalSupply() { final Function function = new Function(FUNC_TOTALSUPPLY, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public RemoteFunctionCall transfer(String to, BigInteger value) { final Function function = new Function( FUNC_TRANSFER, - Arrays.asList(new Address(160, to), - new Uint256(value)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, to), + new org.web3j.abi.datatypes.generated.Uint256(value)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall transferFrom(String from, String to, BigInteger value) { + public RemoteFunctionCall transferFrom(String from, String to, + BigInteger value) { final Function function = new Function( FUNC_TRANSFERFROM, - Arrays.asList(new Address(160, from), - new Address(160, to), - new Uint256(value)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, from), + new org.web3j.abi.datatypes.Address(160, to), + new org.web3j.abi.datatypes.generated.Uint256(value)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } + @Deprecated + public static ERC20 load(String contractAddress, Web3j web3j, Credentials credentials, + BigInteger gasPrice, BigInteger gasLimit) { + return new ERC20(contractAddress, web3j, credentials, gasPrice, gasLimit); + } + + @Deprecated + public static ERC20 load(String contractAddress, Web3j web3j, + TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + return new ERC20(contractAddress, web3j, transactionManager, gasPrice, gasLimit); + } + + public static ERC20 load(String contractAddress, Web3j web3j, Credentials credentials, + ContractGasProvider contractGasProvider) { + return new ERC20(contractAddress, web3j, credentials, contractGasProvider); + } + + public static ERC20 load(String contractAddress, Web3j web3j, + TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + return new ERC20(contractAddress, web3j, transactionManager, contractGasProvider); + } + public static class ApprovalEventResponse extends BaseEventResponse { public String owner; @@ -264,4 +269,4 @@ class ERC20 extends Contract { public BigInteger value; } -} +} \ No newline at end of file diff --git a/libs/visa/src/main/java/com/tangem/lib/visa/TangemBridgeProcessor.java b/libs/visa/src/main/java/com/tangem/lib/visa/TangemBridgeProcessor.java index b612de84bc..3352f39d85 100644 --- a/libs/visa/src/main/java/com/tangem/lib/visa/TangemBridgeProcessor.java +++ b/libs/visa/src/main/java/com/tangem/lib/visa/TangemBridgeProcessor.java @@ -1,11 +1,23 @@ package com.tangem.lib.visa; +import io.reactivex.Flowable; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import org.web3j.abi.EventEncoder; import org.web3j.abi.FunctionEncoder; import org.web3j.abi.TypeReference; -import org.web3j.abi.datatypes.*; +import org.web3j.abi.datatypes.Address; +import org.web3j.abi.datatypes.Bool; +import org.web3j.abi.datatypes.Event; +import org.web3j.abi.datatypes.Function; +import org.web3j.abi.datatypes.StaticStruct; +import org.web3j.abi.datatypes.Type; +import org.web3j.abi.datatypes.generated.Bytes16; import org.web3j.abi.datatypes.generated.Bytes32; -import org.web3j.abi.datatypes.generated.Bytes4; +import org.web3j.abi.datatypes.generated.Uint16; import org.web3j.abi.datatypes.generated.Uint256; import org.web3j.crypto.Credentials; import org.web3j.protocol.Web3j; @@ -20,40 +32,36 @@ import org.web3j.tx.Contract; import org.web3j.tx.TransactionManager; import org.web3j.tx.gas.ContractGasProvider; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import io.reactivex.Flowable; - /** *

Auto generated code. *

Do not modify! *

Please use the web3j command line tools, - * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the - * codegen module to update. + * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the + * codegen module to update. * - *

Generated with web3j version 1.5.2. + *

Generated with web3j version 1.6.1. */ @SuppressWarnings("rawtypes") -class TangemBridgeProcessor extends Contract { - public static final String BINARY = "608060405262278d006008553480156200001857600080fd5b506040516200272f3803806200272f8339810160408190526200003b9162000214565b60028054600580546001600160a01b03199081166001600160a01b038a8116919091179092556006805482168984161790556001600160a81b03199092166101008783160217909255600380549091169184169190911790556009819055620000a6600033620000b2565b5050505050506200027b565b600080620000c18484620000ef565b90508015620000e6576000848152600160205260409020620000e490846200019d565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000194576000838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556200014b3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001620000e9565b506000620000e9565b6000620000e6836001600160a01b03841660008181526001830160205260408120546200019457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620000e9565b80516001600160a01b03811681146200020f57600080fd5b919050565b600080600080600060a086880312156200022d57600080fd5b6200023886620001f7565b94506200024860208701620001f7565b93506200025860408701620001f7565b92506200026860608701620001f7565b9150608086015190509295509295909350565b6124a4806200028b6000396000f3fe608060405234801561001057600080fd5b506004361061028a5760003560e01c806383af133d1161015c578063c904ea39116100ce578063da90f3a011610087578063da90f3a0146105f1578063e24fd1f114610604578063e452f20d14610617578063e63ab1e91461062a578063e96ede8e14610651578063fe2208aa1461066457600080fd5b8063c904ea3914610589578063ca15c8731461059c578063cb37f3b2146105af578063d47ae89c146105c2578063d547741f146105cb578063d6d32b2a146105de57600080fd5b80639353ce4c116101205780639353ce4c146104f357806396bc563d1461051a578063978975591461052f578063a217fddf14610556578063b77c6d351461055e578063be4d18511461057657600080fd5b806383af133d146104a95780638456cb59146104bc5780639010d07c146104c457806391792d5b146104d757806391d14854146104e057600080fd5b80633f4ba83a11610200578063601c6065116101b9578063601c60651461042357806365ebf99a1461043657806370e4306e1461044957806373d3467c146104705780637f2fadb0146104835780638072a0221461049657600080fd5b80633f4ba83a146103ae5780634413e098146103b65780634b9bb0b4146103c95780634e6d8a73146103f057806356737951146104035780635c975abb1461041857600080fd5b80632f2ff15d116102525780632f2ff15d1461030e5780633013ce291461032157806336568abe1461034c57806337de81061461035f5780633d409a86146103725780633e1dbe1f1461038757600080fd5b806301ffc9a71461028f5780630f1071be146102b757806311dce771146102ce578063248a9ca3146102e35780632cc3264114610306575b600080fd5b6102a261029d366004611f47565b610677565b60405190151581526020015b60405180910390f35b6102c060085481565b6040519081526020016102ae565b6102e16102dc366004611f86565b6106a2565b005b6102c06102f1366004611fa3565b60009081526020819052604090206001015490565b6102e1610710565b6102e161031c366004611fbc565b61078a565b600354610334906001600160a01b031681565b6040516001600160a01b0390911681526020016102ae565b6102e161035a366004611fbc565b6107b5565b6102e161036d366004611fa3565b6107ed565b6102c060008051602061242683398151915281565b6102c07f80578ee961742bd59ed4d7f52c856d4014970acf79709a07f09c8c279d66cbb481565b6102e161084c565b6102e16103c4366004611fec565b610881565b6102c07fc62d23620f0c241b20cdec293f57ff9c0cc09ac7c55352efe3363184cd93032281565b6102e16103fe366004612018565b61094d565b6102c06000805160206123b183398151915281565b60025460ff166102a2565b6102e1610431366004612018565b610a57565b6102e1610444366004611f86565b610c7f565b6102c07f6ac2c8b5322a929d300af17766189693ff6db6939ffe690430ad4720baf47d1c81565b6102e161047e36600461205b565b610ce5565b6102e1610491366004611fec565b610e02565b6102e16104a4366004611fa3565b610ee5565b6102e16104b7366004611fec565b610f70565b6102e161102f565b6103346104d23660046120df565b611061565b6102c060075481565b6102a26104ee366004611fbc565b611080565b6102c07f79af5a85184b45263c1b3721b9c8eb1becd98e55ade5a61da0fed18b90b8325681565b6102c060008051602061230183398151915281565b6102c07f581be84b4822abe392a3bcac0d4d656e4cd57faf2e321a32108215cdd4a8365681565b6102c0600081565b6002546103349061010090046001600160a01b031681565b600654610334906001600160a01b031681565b6102e1610597366004612101565b6110a9565b6102c06105aa366004611fa3565b6111aa565b600554610334906001600160a01b031681565b6102c060095481565b6102e16105d9366004611fbc565b6111c1565b6102e16105ec366004611fa3565b6111e6565b6102e16105ff366004611fec565b611270565b6102e161061236600461214b565b6114ed565b610334610625366004611f86565b61162e565b6102c07f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b6102e161065f366004612018565b61168d565b6102e1610672366004612018565b611782565b60006001600160e01b03198216635a05180f60e01b148061069c575061069c8261185c565b92915050565b6000805160206123018339815191526106ba81611891565b600680546001600160a01b0319166001600160a01b0384169081179091556040519081527f68c7b435e0ad7bfb2140fab0735300efbda206f62906049e0b35763cef67cc5e906020015b60405180910390a15050565b600a54339061071e8261189b565b6000811160405180606001604052806029815260200161244660299139906107625760405162461bcd60e51b8152600401610759919061219d565b60405180910390fd5b506000600a55600654600354610786916001600160a01b0391821691168484611946565b5050565b6000828152602081905260409020600101546107a581611891565b6107af83836119a0565b50505050565b6001600160a01b03811633146107de5760405163334bd91960e11b815260040160405180910390fd5b6107e882826119d5565b505050565b7f80578ee961742bd59ed4d7f52c856d4014970acf79709a07f09c8c279d66cbb461081781611891565b60078290556040518281527fb5aa183eb20407e22587bcd13d5c82a85835a4bd60e2a13d7c7efee3c2e9ed4890602001610704565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a61087681611891565b61087e611a02565b50565b7f581be84b4822abe392a3bcac0d4d656e4cd57faf2e321a32108215cdd4a836566108ab81611891565b60405163b9603bdf60e01b8152600481018390526001600160a01b0384169063b9603bdf90602401600060405180830381600087803b1580156108ed57600080fd5b505af1158015610901573d6000803e3d6000fd5b50505050826001600160a01b03167fc8818db5b3e4e986e2f21e002090b1513e17c05a7a326c3737af624bf6ef78c48360405161094091815260200190565b60405180910390a2505050565b610955611a54565b7f6ac2c8b5322a929d300af17766189693ff6db6939ffe690430ad4720baf47d1c61097f81611891565b600061098a8561162e565b905060006007548461099c91906121e6565b604051630381b4dd60e01b815260048101879052602481018290529091506001600160a01b03831690630381b4dd90604401600060405180830381600087803b1580156109e857600080fd5b505af11580156109fc573d6000803e3d6000fd5b5050505084866001600160a01b03167fa77a4ae2cfa0139350d70cd52434d01ae72e9ec897ae89be03580f1ff00dd3d086600754604051610a47929190918252602082015260400190565b60405180910390a3505050505050565b610a5f611a54565b6000805160206123b1833981519152610a7781611891565b60408051808201909152601b81527f353130307c436f6d6d6f6e3a20616d6f756e74206973207a65726f0000000000602082015282610ac95760405162461bcd60e51b8152600401610759919061219d565b506000610ad58561162e565b6003546006546040516370a0823160e01b81526001600160a01b0391821660048201529293506000929116906370a0823190602401602060405180830381865afa158015610b27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4b91906121f9565b9050838110156040518060400160405280601f81526020017f353130317c436f6d6d6f6e3a20696e73756666696369656e742066756e64730081525090610ba55760405162461bcd60e51b8152600401610759919061219d565b50600a84905560405163f89db45760e01b8152600481018690526001600160a01b0383169063f89db45790602401600060405180830381600087803b158015610bed57600080fd5b505af1158015610c01573d6000803e3d6000fd5b50505050600a546000146040518060600160405280602e81526020016123d1602e913990610c425760405162461bcd60e51b8152600401610759919061219d565b5084866001600160a01b03167fa5411d116afcb8415f0019792cccf595f94852ba82886dacbf756d9c3ce85f3f86604051610a4791815260200190565b600080516020612301833981519152610c9781611891565b600580546001600160a01b0319166001600160a01b0384169081179091556040519081527fccbdeb71dc680b2f0fd85f93e7ef0f70eda32a12b918c9715be07bb646360e5990602001610704565b610ced611a54565b600080516020612426833981519152610d0581611891565b6000610d108861162e565b9050600060075487610d2291906121e6565b6040516334284dfb60e01b8152600481018a9052602481018290526001600160801b03198816604482015261ffff8716606482015285151560848201529091506001600160a01b038316906334284dfb9060a401600060405180830381600087803b158015610d9057600080fd5b505af1158015610da4573d6000803e3d6000fd5b5050505087896001600160a01b03167f92c1dbadbb7b791052341ce7c185ca37861e432438355dc3e1642b7c1287609a89600754604051610def929190918252602082015260400190565b60405180910390a3505050505050505050565b610e0a611a54565b7f79af5a85184b45263c1b3721b9c8eb1becd98e55ade5a61da0fed18b90b83256610e3481611891565b6000610e3f8461162e565b604051636df6c7d560e11b8152600481018590529091506001600160a01b0382169063dbed8faa90602401600060405180830381600087803b158015610e8457600080fd5b505af1158015610e98573d6000803e3d6000fd5b50505050836001600160a01b03167f466723bb873015d5baf515fce6b0c8df2cb154adfd8badb6bc77a620a6ef676184604051610ed791815260200190565b60405180910390a250505050565b600080516020612301833981519152610efd81611891565b6283d60082106040518060600160405280602a81526020016122d7602a913990610f3a5760405162461bcd60e51b8152600401610759919061219d565b5060088290556040518281527fdc10143650bb79cd7a92cdf792545dcc2c3b0a719bebb3d83a8a21bb8fbfc3d690602001610704565b7f581be84b4822abe392a3bcac0d4d656e4cd57faf2e321a32108215cdd4a83656610f9a81611891565b6040516306b2a38360e41b8152600481018390526001600160a01b03841690636b2a383090602401600060405180830381600087803b158015610fdc57600080fd5b505af1158015610ff0573d6000803e3d6000fd5b50505050826001600160a01b03167fcc1685e553848099cad0e11271e780371c44b5ed92a54552fbedf9f1b6b9f2478360405161094091815260200190565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a61105981611891565b61087e611a7a565b60008281526001602052604081206110799083611ab7565b9392505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6110b1611a54565b6000805160206124268339815191526110c981611891565b60006110d48661162e565b90506000600754856110e691906121e6565b6040516320199e7960e21b8152600481018890526024810182905285151560448201529091506001600160a01b0383169063806679e490606401600060405180830381600087803b15801561113a57600080fd5b505af115801561114e573d6000803e3d6000fd5b5050505085876001600160a01b03167f92c1dbadbb7b791052341ce7c185ca37861e432438355dc3e1642b7c1287609a87600754604051611199929190918252602082015260400190565b60405180910390a350505050505050565b600081815260016020526040812061069c90611ac3565b6000828152602081905260409020600101546111dc81611891565b6107af83836119d5565b6000805160206123018339815191526111fe81611891565b610e1082106040518060600160405280602781526020016123ff602791399061123a5760405162461bcd60e51b8152600401610759919061219d565b5060098290556040518281527f7f63f876249f25f7856e620802edd09af38a83c9c6040fcdb37179154030831190602001610704565b611278611a54565b6000805160206123b183398151915261129081611891565b600061129b8461162e565b604051631902cad960e31b8152600481018590529091506000906001600160a01b0383169063c81656c890602401602060405180830381865afa1580156112e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130a91906121f9565b6003546006546040516370a0823160e01b81526001600160a01b0391821660048201529293506000929116906370a0823190602401602060405180830381865afa15801561135c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138091906121f9565b90506000821160405180606001604052806027815260200161238a60279139906113bd5760405162461bcd60e51b8152600401610759919061219d565b5060408051808201909152601f81527f353130317c436f6d6d6f6e3a20696e73756666696369656e742066756e6473006020820152828210156114135760405162461bcd60e51b8152600401610759919061219d565b50600a82905560405163e3dbffd560e01b8152600481018690526001600160a01b0384169063e3dbffd590602401600060405180830381600087803b15801561145b57600080fd5b505af115801561146f573d6000803e3d6000fd5b50505050600a546000146040518060600160405280602e81526020016123d1602e9139906114b05760405162461bcd60e51b8152600401610759919061219d565b5084866001600160a01b03167fdfab01fc691e8b69fca482c65142d1bcfeafeb9eb6e9fd5220867d7196d9476e84604051610a4791815260200190565b7fc62d23620f0c241b20cdec293f57ff9c0cc09ac7c55352efe3363184cd93032261151781611891565b6115208261189b565b306001600160a01b0316826001600160a01b031663ce1b1d436040518163ffffffff1660e01b8152600401602060405180830381865afa158015611568573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158c9190612212565b6001600160a01b03161460405180606001604052806032815260200161235860329139906115cd5760405162461bcd60e51b8152600401610759919061219d565b506001600160a01b0383811660008181526004602090815260409182902080546001600160a01b0319169487169485179055905192835290917f0c1464e8c817204497a2076f3b466fe64093e83033c83303b0cb44001cd9b6b59101610940565b6001600160a01b03808216600090815260046020908152604080832054815160608101909252602f80835293941692831515926122a890830139906116865760405162461bcd60e51b8152600401610759919061219d565b5092915050565b611695611a54565b6000805160206124268339815191526116ad81611891565b60006116b88561162e565b9050600083156116ca576007546116cd565b60005b905060006116db82866121e6565b60405163e4d7ddb960e01b815260048101889052602481018290529091506001600160a01b0384169063e4d7ddb990604401600060405180830381600087803b15801561172757600080fd5b505af115801561173b573d6000803e3d6000fd5b505060408051888152602081018690528993506001600160a01b038b1692507f8ba3ad1bd4ff5c3d75861d56df66b7942244d700f4d4cb67df693bac78e805a29101611199565b61178a611a54565b6000805160206123b18339815191526117a281611891565b60006117ad8561162e565b60405163456575e560e01b815260048101869052602481018590529091506001600160a01b0382169063456575e590604401600060405180830381600087803b1580156117f957600080fd5b505af115801561180d573d6000803e3d6000fd5b5050505083856001600160a01b03167f6f60b80b8dcecc3741c03485554a9a35ced96ebba66405fd324caf12a16261da8560405161184d91815260200190565b60405180910390a35050505050565b60006001600160e01b03198216637965db0b60e01b148061069c57506301ffc9a760e01b6001600160e01b031983161461069c565b61087e8133611acd565b6002546040516385bb392360e01b81526001600160a01b038381166004830152610100909204909116906385bb392390602401602060405180830381865afa1580156118eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190f919061222f565b60405180606001604052806037815260200161232160379139906107865760405162461bcd60e51b8152600401610759919061219d565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526107af908590611b06565b6000806119ad8484611b69565b905080156110795760008481526001602052604090206119cd9084611bfb565b509392505050565b6000806119e28484611c10565b905080156110795760008481526001602052604090206119cd9084611c7b565b611a0a611c90565b6002805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60025460ff1615611a785760405163d93c066560e01b815260040160405180910390fd5b565b611a82611a54565b6002805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611a373390565b60006110798383611cb3565b600061069c825490565b611ad78282611080565b6107865760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610759565b6000611b1b6001600160a01b03841683611cdd565b90508051600014158015611b40575080806020019051810190611b3e919061222f565b155b156107e857604051635274afe760e01b81526001600160a01b0384166004820152602401610759565b6000611b758383611080565b611bf3576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055611bab3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600161069c565b50600061069c565b6000611079836001600160a01b038416611ceb565b6000611c1c8383611080565b15611bf3576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a450600161069c565b6000611079836001600160a01b038416611d32565b60025460ff16611a7857604051638dfc202b60e01b815260040160405180910390fd5b6000826000018281548110611cca57611cca61224c565b9060005260206000200154905092915050565b606061107983836000611e25565b6000818152600183016020526040812054611bf35750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561069c565b60008181526001830160205260408120548015611e1b576000611d56600183612262565b8554909150600090611d6a90600190612262565b9050808214611dcf576000866000018281548110611d8a57611d8a61224c565b9060005260206000200154905080876000018481548110611dad57611dad61224c565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611de057611de0612275565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061069c565b600091505061069c565b606081471015611e4a5760405163cd78605960e01b8152306004820152602401610759565b600080856001600160a01b03168486604051611e66919061228b565b60006040518083038185875af1925050503d8060008114611ea3576040519150601f19603f3d011682016040523d82523d6000602084013e611ea8565b606091505b5091509150611eb8868383611ec2565b9695505050505050565b606082611ed757611ed282611f1e565b611079565b8151158015611eee57506001600160a01b0384163b155b15611f1757604051639996b31560e01b81526001600160a01b0385166004820152602401610759565b5080611079565b805115611f2e5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b600060208284031215611f5957600080fd5b81356001600160e01b03198116811461107957600080fd5b6001600160a01b038116811461087e57600080fd5b600060208284031215611f9857600080fd5b813561107981611f71565b600060208284031215611fb557600080fd5b5035919050565b60008060408385031215611fcf57600080fd5b823591506020830135611fe181611f71565b809150509250929050565b60008060408385031215611fff57600080fd5b823561200a81611f71565b946020939093013593505050565b60008060006060848603121561202d57600080fd5b833561203881611f71565b95602085013595506040909401359392505050565b801515811461087e57600080fd5b60008060008060008060c0878903121561207457600080fd5b863561207f81611f71565b9550602087013594506040870135935060608701356001600160801b0319811681146120aa57600080fd5b9250608087013561ffff811681146120c157600080fd5b915060a08701356120d18161204d565b809150509295509295509295565b600080604083850312156120f257600080fd5b50508035926020909101359150565b6000806000806080858703121561211757600080fd5b843561212281611f71565b9350602085013592506040850135915060608501356121408161204d565b939692955090935050565b6000806040838503121561215e57600080fd5b823561216981611f71565b91506020830135611fe181611f71565b60005b8381101561219457818101518382015260200161217c565b50506000910152565b60208152600082518060208401526121bc816040850160208701612179565b601f01601f19169190910160400192915050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561069c5761069c6121d0565b60006020828403121561220b57600080fd5b5051919050565b60006020828403121561222457600080fd5b815161107981611f71565b60006020828403121561224157600080fd5b81516110798161204d565b634e487b7160e01b600052603260045260246000fd5b8181038181111561069c5761069c6121d0565b634e487b7160e01b600052603160045260246000fd5b6000825161229d818460208701612179565b919091019291505056fe353230327c50726f636573736f723a206e6f207061796d656e74206163636f756e7420666f72207468652063617264353231307c50726f636573736f723a20736574746c656d656e7420706572696f6420746f6f206c6f6e67fa658e47c75a6eb0e27156b2f72e1b295c98b53e8a1d238d7ca6ea6345b34880353230307c50726f636573736f723a207061796d656e74206163636f756e74206e6f74206465706c6f79656420627920666163746f7279353230317c50726f636573736f723a207061796d656e74206163636f756e742070726f636573736f72206d69736d61746368353235307c50726f636573736f723a20726566756e64207265636f7264206e6f7420666f756e64d77cc12a543481a2b3ef8fd055979569715a10db9879cd9e664395eca3a54dff353235327c50726f636573736f723a20726566756e6420746f2070726f63657373207761736e2774207265736574353231317c50726f636573736f723a2073656375726974792064656c617920746f6f206c6f6e67a567244cad934c87b7f7e15b15dd0e75f95a76afd1916f8eab4a391410d6f278353235317c50726f636573736f723a20726566756e6420746f2070726f63657373206973207a65726fa2646970667358221220098c0e97a9ad9d3bb5cd4459c44925a6fb83295823a48d337beb3c254c7b728b64736f6c63430008160033"; +public class TangemBridgeProcessor extends Contract { + public static final String BINARY = "608060405234620000345762000022620000186200012e565b939290926200022c565b604051612dc86200057b8239612dc890f35b600080fd5b634e487b7160e01b600052604160045260246000fd5b90601f01601f191681019081106001600160401b038211176200007157604052565b62000039565b906200008e6200008660405190565b92836200004f565b565b6001600160a01b031690565b90565b6001600160a01b0381165b036200003457565b905051906200008e826200009f565b80620000aa565b905051906200008e82620000c1565b919060a0838203126200003457620000f08184620000b2565b92620001008260208301620000b2565b926200009c620001148460408501620000b2565b936080620001268260608701620000b2565b9401620000c8565b620001516200334380380380620001458162000077565b928339810190620000d7565b9091929394565b906001600160a01b03905b9181191691161790565b6200009c9062000090906001600160a01b031682565b6200009c906200016d565b6200009c9062000183565b90620001ad6200009c620001b5926200018e565b825462000158565b9055565b90610100600160a81b039060081b62000163565b90620001e16200009c620001b5926200018e565b8254620001b9565b906000199062000163565b6200009c6200009c6200009c9290565b90620002186200009c620001b592620001f4565b8254620001e9565b6200009c6000620001f4565b92620002676200026d6200027d946200026762000275956200025f620002859a9962000257620002c3565b600462000199565b600562000199565b6200018e565b6002620001cd565b600362000199565b600662000204565b6200029b6200029362000220565b3390620002e1565b50565b9060ff9062000163565b90620002bb6200009c620001b592151590565b82546200029e565b6200008e60006002620002a8565b905b600052602052604060002090565b620002ed828262000324565b9182620002f957505090565b6200030e6200009c62000314936001620002d1565b620003d2565b5090565b90620002d3906200018e565b6200033862000334838362000419565b1590565b15620003b8576200036460016200035e846000620003578682620002d1565b0162000318565b620002a8565b620003836200037c62000375339390565b936200018e565b916200018e565b917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d620003af60405190565b600090a4600190565b5050600090565b6200009c9081906001600160a01b031681565b906200040c6200040862000402620003fc60006200009c96620003f3600090565b50019462000183565b620003bf565b620001f4565b9190565b620004e4565b5460ff1690565b6200009c916000620003576200043a9362000432600090565b5082620002d1565b62000412565b634e487b7160e01b600052603260045260246000fd5b80548210156200047b5762000472600191600052602060002090565b91020190600090565b62000440565b9160001960089290920291821b911b62000163565b9190620004a86200009c620001b59390565b90835462000481565b9081549168010000000000000000831015620000715782620004dd9160016200008e9501815562000456565b9062000496565b620004f462000334838362000542565b15620003b8576200052991620005239060016200051b84620005178482620004b1565b5490565b9301620002d1565b62000204565b600190565b6200009c9081565b6200009c90546200052e565b620005659160016200055f9262000557600090565b5001620002d1565b62000536565b62000575620004086000620001f4565b14159056fe6080604052600436101561001257600080fd5b60003560e01c806301ffc9a71461030257806311dce771146102fd578063248a9ca3146102f857806328e14f24146102f35780632cc32641146102ee5780632e44b939146102e95780632f2ff15d146102e45780633013ce29146102df57806336568abe146102da5780633c1a5012146102d55780633d409a86146102d05780633f4ba83a146102cb57806341d2ac20146102c65780634413e098146102c157806356737951146102bc5780635c975abb146102b757806365ebf99a146102b257806368b40573146102ad5780636a7554c0146102a857806370e4306e146102a35780637123925e1461029e57806383af133d146102995780638456cb59146102945780639010d07c1461028f57806391d148541461028a5780639353ce4c1461028557806396bc563d14610280578063978975591461027b57806399fef6bb146102765780639e4da86214610271578063a217fddf1461026c578063a9eb7b5a14610267578063aca821f714610262578063b77c6d351461025d578063be4d185114610258578063c0e678f814610253578063c8de6d171461024e578063ca15c87314610249578063cb37f3b214610244578063d47ae89c1461023f578063d547741f1461023a578063d595130814610235578063d6d32b2a14610230578063e0a86ef71461022b578063e63ab1e914610226578063eb465bca146102215763f0cb94980361031a57610d95565b610d76565b610cce565b610caf565b610c04565b610be8565b610bcf565b610bb4565b610b77565b610b50565b610b37565b610b1b565b610a9f565b610a78565b610a50565b610a37565b610a1c565b6109c4565b6109a9565b610970565b610949565b610910565b6108f4565b6108be565b61088a565b610871565b610838565b6107ff565b6107e6565b6107ca565b61077d565b61075e565b610725565b61070c565b6106d7565b61068f565b610668565b610650565b610637565b610610565b61058d565b610548565b61046a565b610431565b6103fa565b6103b6565b610349565b6001600160e01b031981165b0361031a57565b600080fd5b9050359061032c82610307565b565b9060208282031261031a576103429161031f565b90565b9052565b3461031a5761037661036461035f36600461032e565b610dce565b60405191829182901515815260200190565b0390f35b6001600160a01b031690565b6001600160a01b038116610313565b9050359061032c82610386565b9060208282031261031a5761034291610395565b3461031a576103ce6103c93660046103a2565b610e81565b604051005b80610313565b9050359061032c826103d3565b9060208282031261031a57610342916103d9565b3461031a576103766104156104103660046103e6565b610eab565b6040515b9182918290815260200190565b600091031261031a57565b3461031a57610441366004610426565b6103767f350e76a198c654a14c1f5ccac917c5f939f08970b53375e57483f9623a24399c610415565b3461031a5761047a366004610426565b6103ce611072565b908160e091031261031a5790565b909182601f8301121561031a5781359167ffffffffffffffff831161031a57602001926001830284011161031a57565b6101808183031261031a576104d58282610395565b926104e38360208401610395565b926104f18160408501610482565b926105008261012083016103d9565b9261014082013567ffffffffffffffff811161031a5783610522918401610490565b92909361016082013567ffffffffffffffff811161031a576105449201610490565b9091565b3461031a576103ce61055b3660046104c0565b969590959491949392936113fd565b919060408382031261031a5761034290602061058682866103d9565b9401610395565b3461031a576103ce6105a036600461056a565b9061142b565b610342916008021c6001600160a01b031690565b9061034291546105a6565b610342600060036105ba565b6103429061037a906001600160a01b031682565b610342906105d1565b610342906105e5565b610345906105ee565b60208101929161032c91906105f7565b3461031a57610620366004610426565b61037661062b6105c5565b60405191829182610600565b3461031a576103ce61064a36600461056a565b90611435565b3461031a576103ce6106633660046103a2565b611530565b3461031a57610678366004610426565b610376600080516020612d73833981519152610415565b3461031a5761069f366004610426565b6103ce61156d565b909160608284031261031a576103426106c08484610395565b9360406106d08260208701610395565b94016103d9565b3461031a576103ce6106ea3660046106a7565b916116eb565b919060408382031261031a576103429060206106d08286610395565b3461031a576103ce61071f3660046106f0565b906117a3565b3461031a57610735366004610426565b6103767fd77cc12a543481a2b3ef8fd055979569715a10db9879cd9e664395eca3a54dff610415565b3461031a5761076e366004610426565b61037661036460025460ff1690565b3461031a576103ce6107903660046103a2565b6117f8565b60808183031261031a576107a98282610395565b926103426107ba8460208501610395565b9360606106d082604087016103d9565b3461031a576103ce6107dd366004610795565b92919091611a60565b3461031a576103ce6107f93660046106f0565b90611b0f565b3461031a5761080f366004610426565b6103767f6ac2c8b5322a929d300af17766189693ff6db6939ffe690430ad4720baf47d1c610415565b3461031a57610848366004610426565b6103767fca900a2e3cfbbbb78b9095304e53ddb6de902bbef4638bd3c79fe9cf3a441202610415565b3461031a576103ce6108843660046106f0565b90611bbc565b3461031a5761089a366004610426565b6103ce611bfa565b919060408382031261031a576103429060206106d082866103d9565b3461031a576103766108da6108d43660046108a2565b90611c02565b604051918291826001600160a01b03909116815260200190565b3461031a5761037661036461090a36600461056a565b90611c2c565b3461031a57610920366004610426565b6103767f79af5a85184b45263c1b3721b9c8eb1becd98e55ade5a61da0fed18b90b83256610415565b3461031a57610959366004610426565b610376600080516020612d53833981519152610415565b3461031a57610980366004610426565b6103767f581be84b4822abe392a3bcac0d4d656e4cd57faf2e321a32108215cdd4a83656610415565b3461031a576103766103646109bf3660046103a2565b611c55565b3461031a576109d4366004610426565b6103767f863747851594ece3a3681369cf3710069c605efc30fccffb517283afa5efce91610415565b6103426103426103429290565b61034260006109fd565b610342610a0a565b3461031a57610a2c366004610426565b610376610415610a14565b3461031a576103ce610a4a3660046106a7565b91611d3b565b3461031a576103ce610a63366004610795565b92919091611e22565b610342600160026105ba565b3461031a57610a88366004610426565b61037661062b610a6c565b610342600060056105ba565b3461031a57610aaf366004610426565b6103766108da610a93565b801515610313565b9050359061032c82610aba565b919060a08382031261031a57610ae58184610395565b92610af38260208301610395565b92610342610b0484604085016103d9565b936080610b1482606087016103d9565b9401610ac2565b3461031a576103ce610b2e366004610acf565b93929092611f2f565b3461031a576103ce610b4a3660046106a7565b91611ff3565b3461031a57610376610415610b663660046103e6565b611ffe565b610342600060046105ba565b3461031a57610b87366004610426565b6103766108da610b6b565b610342916008021c81565b906103429154610b92565b61034260006006610b9d565b3461031a57610bc4366004610426565b610376610415610ba8565b3461031a576103ce610be236600461056a565b90612030565b3461031a576103ce610bfb366004610795565b929190916120fc565b3461031a576103ce610c173660046103e6565b6121ce565b6001600160801b03198116610313565b9050359061032c82610c1c565b61ffff8116610313565b9050359061032c82610c39565b60e08183031261031a57610c648282610395565b92610c728360208401610395565b92610c8081604085016103d9565b92610c8e82606083016103d9565b92610342610c9f8460808501610c2c565b9360c0610b148260a08701610c43565b3461031a576103ce610cc2366004610c50565b959490949391936122b4565b3461031a57610cde366004610426565b6103767f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610415565b9060c08282031261031a57610d1c8183610395565b92610d2a8260208501610395565b92610d3883604083016103d9565b92610d4681606084016103d9565b92608083013567ffffffffffffffff811161031a5782610d6d60a094610342938701610490565b94909501610ac2565b3461031a576103ce610d89366004610d07565b95949094939193612397565b3461031a57610da5366004610426565b6103767f7245419aa9f77e6e9f023dc59852153b8258661dd13b3e1a61fe9e8a5977aa74610415565b635a05180f60e01b6001600160e01b0319821614908115610ded575090565b61034291506123a6565b61032c90610e17600080516020612d538339815191526123e0565b6123e0565b610e4c565b906001600160a01b03905b9181191691161790565b90610e41610342610e48926105ee565b8254610e1c565b9055565b610e7c7f68c7b435e0ad7bfb2140fab0735300efbda206f62906049e0b35763cef67cc5e916108da816005610e31565b0390a1565b61032c90610df7565b905b600052602052604060002090565b6103429081565b6103429054610e9a565b6001610ec461034292610ebc600090565b506000610e8a565b01610ea1565b634e487b7160e01b600052604160045260246000fd5b90601f01601f1916810190811067ffffffffffffffff821117610f0257604052565b610eca565b9061032c610f1460405190565b9283610ee0565b67ffffffffffffffff8111610f0257602090601f01601f19160190565b0190565b90610f4e610f4983610f1b565b610f07565b918252565b610f5d6029610f3c565b7f353235317c50726f636573736f723a20726566756e6420746f2070726f63657360208201526873206973207a65726f60b81b604082015290565b610342610f53565b610342610f98565b60005b838110610fbb5750506000910152565b8181015183820152602001610fab565b610fec610ff5602093610f3893610fe0815190565b80835293849260200190565b95869101610fa8565b601f01601f191690565b602080825261034292910190610fcb565b156110185750565b61103a9061102560405190565b62461bcd60e51b815291829160048301610fff565b0390fd5b9060001990610e27565b90611058610342610e48926109fd565b825461103e565b6103429061037a565b610342905461105f565b61032c336110806007610ea1565b9061108a81612475565b6110a761109760006109fd565b83116110a1610fa0565b90611010565b6110bb6110b460006109fd565b6007611048565b6110c56003611068565b6110cf6005611068565b90612537565b9061032c979695949392916110e8612581565b61032c979695949392919061111c7f863747851594ece3a3681369cf3710069c605efc30fccffb517283afa5efce916123e0565b61130e565b6103429060081c61037a565b6103429054611121565b9050519061032c82610386565b9060208282031261031a5761034291611137565b50610342906020810190610ac2565b50610342906020810190610c2c565b50610342906020810190610c43565b9060206111b661032c936111ad61119f6000830183611167565b6001600160801b0319168552565b82810190611176565b61ffff16910152565b506103429060208101906103d9565b90606061122361032c936111ec6111e860008301836111bf565b8552565b6112036111fc60208301836111bf565b6020860152565b61121a61121360408301836111bf565b6040860152565b828101906111bf565b910152565b90606061125e61032c936112486112426000830183611158565b15158552565b611259602082016020860190611185565b820190565b9101906111ce565b90826000939282370152565b9190610ff58161128981610f389560209181520190565b8095611266565b9694906112f3946112dd89956112d36103429c9a966112c36112e59660006101808c019b01906001600160a01b03169052565b6001600160a01b031660208d0152565b60408b0190611228565b610120890152565b868303610140880152611272565b92610160818503910152611272565b6040513d6000823e3d90fd5b9485611354839960209795969960009461133061132b600261112d565b6105ee565b9761133a60405190565b9c8d9a8b998a98632e44b93960e01b8a5260048a01611290565b03925af19081156113f8577f49f84c15b9f052fd24e68e7760c0bc11d05c5a058721d4dfc2c5c02866f84cd6926000926113c3575b50611393906105ee565b926113be6113a060405190565b928392836001600160a01b0391821681529116602082015260400190565b0390a2565b6113939192506113ea9060203d6020116113f1575b6113e28183610ee0565b810190611144565b9190611389565b503d6113d8565b611302565b9061032c979695949392916110d5565b9061032c9161141e610e1282610eab565b906114289161259f565b50565b9061032c9161140d565b9061143f3361037a565b6001600160a01b0382160361145757611428916125ce565b60405163334bd91960e11b8152600490fd5b61032c906114967fca900a2e3cfbbbb78b9095304e53ddb6de902bbef4638bd3c79fe9cf3a4412026123e0565b6114a261132b826105ee565b90813b1561031a5760006114b560405190565b6337a1d41560e01b8152928390600490829084905af19182156113f8576114e192611512575b506105ee565b7feb17a79f3df37ac5b011bba24abb3d48db9d0dd39110551346f1c30bfa0fe70161150b60405190565b80806113be565b61152a9060006115228183610ee0565b810190610426565b386114db565b61032c90611469565b6115627f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a6123e0565b61032c61032c61265f565b61032c611539565b9061032c9291611583612581565b61032c9291906115b27f79af5a85184b45263c1b3721b9c8eb1becd98e55ade5a61da0fed18b90b832566123e0565b6115f9565b9050519061032c826103d3565b9060208282031261031a57610342916115b7565b6001600160a01b03909116815260408101929161032c9160200152565b0152565b602061163360009461160d61132b856105ee565b9061161760405190565b968793849283919063f93184c160e01b835289600484016115d8565b03925af19283156113f85760009361168c575b5061168761167d6116777f8c7f40acbbdddd09014432da06798dda241de8adb409a62f3611f9a0d63d6b5b936105ee565b936105ee565b9361041960405190565b0390a3565b7f8c7f40acbbdddd09014432da06798dda241de8adb409a62f3611f9a0d63d6b5b91935061167d6116776116da6116879360203d6020116116e4575b6116d28183610ee0565b8101906115c4565b9593505050611646565b503d6116c8565b9061032c9291611575565b61032c91906117247f581be84b4822abe392a3bcac0d4d656e4cd57faf2e321a32108215cdd4a836566123e0565b61173061132b826105ee565b803b1561031a57600061174260405190565b63b9603bdf60e01b815260048101859052918290602490829084905af180156113f8577fc8818db5b3e4e986e2f21e002090b1513e17c05a7a326c3737af624bf6ef78c4926113be926117999261151257506105ee565b9261041960405190565b9061032c916116f6565b61032c906117c8600080516020612d538339815191526123e0565b610e7c7fccbdeb71dc680b2f0fd85f93e7ef0f70eda32a12b918c9715be07bb646360e59916108da816004610e31565b61032c906117ad565b9061032c939291611810612581565b61032c939291906118407fd77cc12a543481a2b3ef8fd055979569715a10db9879cd9e664395eca3a54dff6123e0565b6118e2565b61184f601f610f3c565b7f353130317c436f6d6d6f6e3a20696e73756666696369656e742066756e647300602082015290565b610342611845565b610342611878565b611892602e610f3c565b7f353235327c50726f636573736f723a20726566756e6420746f2070726f63657360208201526d1cc81dd85cdb89dd081c995cd95d60921b604082015290565b610342611888565b6103426118d2565b6118eb846126aa565b61193860206118fd61132b6003611068565b6119076005611068565b9061191160405190565b938492839182916370a0823160e01b5b83526001600160a01b031660048301526024820190565b03915afa80156113f85761196491600091611a41575b50859061195a565b9190565b10156110a1611880565b61196f846007611048565b61197b61132b826105ee565b90813b1561031a57600061198e60405190565b92839063bc77d49560e01b82528183816119ac8a8a600484016115d8565b03925af19081156113f857611a16611a10611a1c927f6de2d5fa0b9cac9e48f300a350314e447648d158a5067a56513a46396f1b638a95611a2695611a2b575b5061132b6119fa6007610ea1565b611a0761195660006109fd565b146110a16118da565b946105ee565b946109fd565b9461041960405190565b0390a4565b611a3b9060006115228183610ee0565b386119ec565b611a5a915060203d6020116116e4576116d28183610ee0565b3861194e565b9061032c939291611801565b61032c9190611a9a7f7245419aa9f77e6e9f023dc59852153b8258661dd13b3e1a61fe9e8a5977aa746123e0565b611aa661132b826105ee565b803b1561031a576000611ab860405190565b6377627c0960e11b815260048101859052918290602490829084905af180156113f8577faeb30c8dda75512b9946228f4034031bd3f99d91f2c4ed3806be677f3429cd80926113be926117999261151257506105ee565b9061032c91611a6c565b61032c9190611b477f581be84b4822abe392a3bcac0d4d656e4cd57faf2e321a32108215cdd4a836566123e0565b611b5361132b826105ee565b803b1561031a576000611b6560405190565b6306b2a38360e41b815260048101859052918290602490829084905af180156113f8577fcc1685e553848099cad0e11271e780371c44b5ed92a54552fbedf9f1b6b9f247926113be926117999261151257506105ee565b9061032c91611b19565b611bef7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a6123e0565b61032c61032c612705565b61032c611bc6565b90611c1d61034261034293611c15600090565b506001610e8a565b612723565b90610e8c906105ee565b610342916000611c48611c4e93611c41600090565b5082610e8a565b01611c22565b5460ff1690565b610342907f350e76a198c654a14c1f5ccac917c5f939f08970b53375e57483f9623a24399c611c2c565b9061032c9291611c8d612581565b61032c929190611cbc7f6ac2c8b5322a929d300af17766189693ff6db6939ffe690430ad4720baf47d1c6123e0565b611cc861132b826105ee565b90813b1561031a576000611cdb60405190565b928390633e0fc2ff60e01b8252818381611cf98a8a600484016115d8565b03925af19182156113f8576116776116879261167d927f7ea7d3b21868f19f237e4e91d95cc953f5a73d5b2c1862712635f3ef384887fd9561151257506105ee565b9061032c9291611c7f565b9061032c939291611d55612581565b61032c93929190611d73600080516020612d738339815191526123e0565b611d9f565b6001600160a01b03909116815260608101939261032c9290916040916115f5906020830152565b611dab61132b826105ee565b90813b1561031a576000611dbe60405190565b9283906374b76f4760e11b8252818381611ddd8b8b8b60048501611d78565b03925af19081156113f857611a16611a10611a1c927f0ee23c67813e7ee061931ccc27dd2be79deb9f90738c9649947a27243cd6d81f95611a269561151257506105ee565b9061032c939291611d46565b9061032c94939291611e3e612581565b61032c9493929190611e5d600080516020612d738339815191526123e0565b611ea2565b611e9a61032c94611e93606094989795611e8c608086019a60008701906001600160a01b03169052565b6020850152565b6040830152565b019015159052565b9390919293611eb361132b826105ee565b803b1561031a57611eea600093918492611ecc60405190565b95869384928391906303ad5cef60e31b83528c8c8c60048601611e62565b03925af19081156113f857611a16611a10611a1c927f3cd37480027e3583365f7acfb552d017416b316c9bec58d3c722169ebcfbed8d95611a269561151257506105ee565b9061032c94939291611e2e565b9061032c9291611f4a612581565b61032c929190611f797f79af5a85184b45263c1b3721b9c8eb1becd98e55ade5a61da0fed18b90b832566123e0565b611f8561132b826105ee565b90813b1561031a576000611f9860405190565b636df6c7d560e11b815260048101869052928390602490829084905af19182156113f8576116776116879261167d927f4ec4ca1f307e20478f96cb1c545fe5430572a8db4931456f3828b649f641b1ef9561151257506105ee565b9061032c9291611f3c565b61201061034261034292611c15600090565b612757565b9061032c91612026610e1282610eab565b90611428916125ce565b9061032c91612015565b9061032c939291612049612581565b61032c939291906120797f6ac2c8b5322a929d300af17766189693ff6db6939ffe690430ad4720baf47d1c6123e0565b61208561132b826105ee565b90813b1561031a57600061209860405190565b928390634e6d8a7360e01b82528183816120b78b8b8b60048501611d78565b03925af19081156113f857611a16611a10611a1c927f1dd3b030dd7573079a398f70654588c91f23b82a2434fc5351cef1cbeda903e195611a269561151257506105ee565b9061032c93929161203a565b61032c90612123600080516020612d538339815191526123e0565b612186565b610342610e106109fd565b61213d6027610f3c565b7f353231317c50726f636573736f723a2073656375726974792064656c617920746020820152666f6f206c6f6e6760c81b604082015290565b610342612133565b610342612176565b610e7c7f7f63f876249f25f7856e620802edd09af38a83c9c6040fcdb371791540308311916121c36121b9610342612128565b82106110a161217e565b610415816006611048565b61032c90612108565b9061032c9695949392916121e9612581565b61032c9695949392919061220a600080516020612d738339815191526123e0565b61226c565b9194612261611e9a9298979561225060a09661224961032c9a61224260c08a019e60008b01906001600160a01b03169052565b6020890152565b6040870152565b6001600160801b0319166060850152565b61ffff166080830152565b9194959093929561227f61132b846105ee565b803b1561031a5786600087611eea82968c9661229a60405190565b9a8b9889978896636fb7e9c160e01b88526004880161220f565b9061032c9695949392916121d7565b9061032c9695949392916122d5612581565b61032c969594939291906122f6600080516020612d738339815191526123e0565b61234f565b9695939461032c956123396080956123326123469661232b8d97600060a08a019901906001600160a01b03169052565b60208d0152565b60408b0152565b88830360608a0152611272565b94019015159052565b9194959093929561236261132b846105ee565b803b1561031a5786600087611eea82968c9661237d60405190565b9a8b98899788966311de011760e31b8852600488016122fb565b9061032c9695949392916122c3565b637965db0b60e01b6001600160e01b03198216149081156123c5575090565b61034291506001600160e01b0319166301ffc9a760e01b1490565b61032c90339061276d565b9050519061032c82610aba565b9060208282031261031a57610342916123eb565b6124166037610f3c565b7f353230307c50726f636573736f723a207061796d656e74206163636f756e742060208201527f6e6f74206465706c6f79656420627920666163746f7279000000000000000000604082015290565b61034261240c565b610342612465565b602061249f9161248861132b600261112d565b604051938492839182916385bb392360e01b611921565b03915afa80156113f85761032c916000916124be575b506110a161246d565b6124e0915060203d6020116124e6575b6124d88183610ee0565b8101906123f8565b386124b5565b503d6124ce565b6125066125006103429263ffffffff1690565b60e01b90565b6001600160e01b03191690565b6001600160a01b0391821681529116602082015260608101929161032c9160400152565b9061257c9061256d61032c956004956125536323b872dd6124ed565b9361255d60405190565b9788956020870190815201612513565b60208201810382520383610ee0565b6127a9565b60025460ff1661258d57565b60405163d93c066560e01b8152600490fd5b6125a98282612831565b91826125b457505090565b6125c56103426125ca936001610e8a565b6128be565b5090565b6125d882826128f0565b91826125e357505090565b6125f46103426125ca936001610e8a565b61294c565b61260161296c565b61032c612629565b9060ff90610e27565b90612622610342610e4892151590565b8254612609565b61263560006002612612565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa610e7c336108da565b61032c6125f9565b612671601b610f3c565b7f353130307c436f6d6d6f6e3a20616d6f756e74206973207a65726f0000000000602082015290565b610342612667565b61034261269a565b61032c906126bb61195660006109fd565b116110a16126a2565b6126cc612581565b61032c6126db60016002612612565b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610e7c336108da565b61032c6126c4565b610342906109fd565b61037a6103426103429290565b61274d6127486103429361274360006127529561273e600090565b500190565b6129d1565b61270d565b612716565b6105e5565b61276860006103429261273e600090565b6129f0565b9061277f61277b8284611c2c565b1590565b612787575050565b61103a61279360405190565b63e2517d3f60e01b8152928392600484016115d8565b6127b56127bc916105ee565b9182612a04565b80516127cb61195660006109fd565b1415908161280d575b506127dc5750565b61103a906127e960405190565b635274afe760e01b8152918291600483016001600160a01b03909116815260200190565b61282b915080602061282061277b935190565b8183010191016123f8565b386127d4565b61283e61277b8383611c2c565b156128a55761285d6001612858846000611c488682610e8a565b612612565b61287161286b611677339390565b916105ee565b917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d61289c60405190565b600090a4600190565b5050600090565b6103429081906001600160a01b031681565b906128eb6119566128e66128e16000610342966128d9600090565b5001946105e5565b6128ac565b6109fd565b612a71565b6128fa8282611c2c565b156128a55761291360006128588482611c488682610e8a565b61292161286b611677339390565b917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b61289c60405190565b906129676119566128e66128e16000610342966128d9600090565b612b3f565b61297b61277b60025460ff1690565b61298157565b604051638dfc202b60e01b8152600490fd5b634e487b7160e01b600052603260045260246000fd5b80548210156129cc576129c3600191600052602060002090565b91020190600090565b612993565b6103429160006129ea926129e3600090565b50016129a9565b90610b9d565b6000610342916129fe600090565b50015490565b61034291612a1260006109fd565b91612c23565b9160001960089290920291821b911b610e27565b9190612a3b610342610e489390565b908354612a18565b9081549168010000000000000000831015610f025782612a6b91600161032c950181556129a9565b90612a2c565b612a7e61277b8383612c88565b156128a557612aab91612aa6906001612a9f84612a9b8482612a43565b5490565b9301610e8a565b611048565b600190565b634e487b7160e01b600052601160045260246000fd5b91908203918211612ad357565b612ab0565b634e487b7160e01b600052603160045260246000fd5b61032c91600091612a2c565b80548015612b1d576000190190612b1a612b1483836129a9565b90612aee565b55565b612ad8565b9190612a3b610342610e48936109fd565b61032c91600091612b22565b90612b55612b508260018501610e8a565b610ea1565b612b5f60006109fd565b8114612bfc57612bc461034292600092612bb995612bbe6001978893612b8d612b87866109fd565b82612ac6565b88850191612bab612b9c845490565b612ba5896109fd565b90612ac6565b808303612bc9575b50505090565b612afa565b01610e8a565b612b33565b612a6b612bec612bf494612be36129ea612aa695896129a9565b928391886129a9565b888801610e8a565b388080612bb3565b505050600090565b3d15612c1e57612c133d610f3c565b903d6000602084013e565b606090565b91612c2d306105ee565b81813110612c57575060008281926020610342969551920190855af1612c51612c04565b91612cb3565b61103a90612c6460405190565b63cd78605960e01b8152918291600483016001600160a01b03909116815260200190565b612ca1916001612b5092612c9a600090565b5001610e8a565b612cae61195660006109fd565b141590565b90612cbe5750612d23565b8151612ccd61195660006109fd565b1480612d0d575b612cdc575090565b61103a90612ce960405190565b639996b31560e01b8152918291600483016001600160a01b03909116815260200190565b50803b612d1d61195660006109fd565b14612cd4565b8051612d3261195660006109fd565b1115612d4057805190602001fd5b604051630a12f52160e11b8152600490fdfefa658e47c75a6eb0e27156b2f72e1b295c98b53e8a1d238d7ca6ea6345b34880a567244cad934c87b7f7e15b15dd0e75f95a76afd1916f8eab4a391410d6f278a26469706673582212202e2530549c24438ec28dea3d0ac5bc4a94ae7752c7cb46a83d147d6cd4df5ffd64736f6c63430008160033"; + + private static String librariesLinkedBinary; public static final String FUNC_AUTHORIZATION_PROCESSOR_ROLE = "AUTHORIZATION_PROCESSOR_ROLE"; public static final String FUNC_BALANCE_VERIFIER_ROLE = "BALANCE_VERIFIER_ROLE"; + public static final String FUNC_CARD_CONFIRMER_ROLE = "CARD_CONFIRMER_ROLE"; + public static final String FUNC_DEBT_PROCESSOR_ROLE = "DEBT_PROCESSOR_ROLE"; public static final String FUNC_DEFAULT_ADMIN_ROLE = "DEFAULT_ADMIN_ROLE"; - public static final String FUNC_FIXED_FEE_SETTER_ROLE = "FIXED_FEE_SETTER_ROLE"; - public static final String FUNC_PAUSER_ROLE = "PAUSER_ROLE"; - public static final String FUNC_PAYMENT_ACCOUNT_SETTER_ROLE = "PAYMENT_ACCOUNT_SETTER_ROLE"; + public static final String FUNC_PAYMENT_ACCOUNT_DEPLOYER_ROLE = "PAYMENT_ACCOUNT_DEPLOYER_ROLE"; + + public static final String FUNC_PAYMENT_ACCOUNT_PROPERTY_SETTER_ROLE = "PAYMENT_ACCOUNT_PROPERTY_SETTER_ROLE"; public static final String FUNC_PROPERTY_SETTER_ROLE = "PROPERTY_SETTER_ROLE"; @@ -61,9 +69,9 @@ class TangemBridgeProcessor extends Contract { public static final String FUNC_SETTLEMENT_PROCESSOR_ROLE = "SETTLEMENT_PROCESSOR_ROLE"; - public static final String FUNC_FIXEDFEE = "fixedFee"; + public static final String FUNC_WITHDRAWAL_PROCESSOR_ROLE = "WITHDRAWAL_PROCESSOR_ROLE"; - public static final String FUNC_GETPAYMENTACCOUNT = "getPaymentAccount"; + public static final String FUNC_DEPLOYPAYMENTACCOUNT = "deployPaymentAccount"; public static final String FUNC_GETROLEADMIN = "getRoleAdmin"; @@ -77,6 +85,8 @@ class TangemBridgeProcessor extends Contract { public static final String FUNC_INCREASEVERIFIEDBALANCEFOR = "increaseVerifiedBalanceFor"; + public static final String FUNC_ISCARDCONFIRMER = "isCardConfirmer"; + public static final String FUNC_PAUSE = "pause"; public static final String FUNC_PAUSED = "paused"; @@ -87,13 +97,13 @@ class TangemBridgeProcessor extends Contract { public static final String FUNC_PAYMENTTOKEN = "paymentToken"; - public static final String FUNC_PROCESSAUTHORIZATION = "processAuthorization"; - public static final String FUNC_PROCESSAUTHORIZATIONCHANGE = "processAuthorizationChange"; - public static final String FUNC_PROCESSAUTHORIZATIONNOOTP = "processAuthorizationNoOtp"; + public static final String FUNC_PROCESSDEBT = "processDebt"; - public static final String FUNC_PROCESSPENDINGREFUND = "processPendingRefund"; + public static final String FUNC_PROCESSNOCONFIRMATIONAUTHORIZATION = "processNoConfirmationAuthorization"; + + public static final String FUNC_PROCESSOTPAUTHORIZATION = "processOtpAuthorization"; public static final String FUNC_PROCESSREFUND = "processRefund"; @@ -101,19 +111,21 @@ class TangemBridgeProcessor extends Contract { public static final String FUNC_PROCESSSETTLEMENT = "processSettlement"; + public static final String FUNC_PROCESSSIGNATUREAUTHORIZATION = "processSignatureAuthorization"; + + public static final String FUNC_PROCESSUNSETTLEDTRANSACTION = "processUnsettledTransaction"; + + public static final String FUNC_PROCESSWITHDRAWAL = "processWithdrawal"; + public static final String FUNC_REFUNDACCOUNT = "refundAccount"; public static final String FUNC_RENOUNCEROLE = "renounceRole"; public static final String FUNC_REVOKEROLE = "revokeRole"; - public static final String FUNC_SAVEPENDINGREFUND = "savePendingRefund"; - public static final String FUNC_SECURITYDELAY = "securityDelay"; - public static final String FUNC_SETFIXEDFEE = "setFixedFee"; - - public static final String FUNC_SETPAYMENTACCOUNT = "setPaymentAccount"; + public static final String FUNC_SETAUTHLIMITMARGINFOR = "setAuthLimitMarginFor"; public static final String FUNC_SETPAYMENTRECEIVER = "setPaymentReceiver"; @@ -121,214 +133,312 @@ class TangemBridgeProcessor extends Contract { public static final String FUNC_SETSECURITYDELAY = "setSecurityDelay"; - public static final String FUNC_SETSETTLEMENTPERIOD = "setSettlementPeriod"; - public static final String FUNC_SETVERIFIEDBALANCEFOR = "setVerifiedBalanceFor"; - public static final String FUNC_SETTLEMENTPERIOD = "settlementPeriod"; - public static final String FUNC_SUPPORTSINTERFACE = "supportsInterface"; public static final String FUNC_UNPAUSE = "unpause"; public static final String FUNC_WRITEOFFDEBT = "writeOffDebt"; + public static final Event AUTHLIMITMARGINSETFOR_EVENT = new Event("AuthLimitMarginSetFor", + Arrays.>asList(new TypeReference

(true) {}, new TypeReference() {})); + ; + public static final Event AUTHORIZATIONCHANGEPROCESSED_EVENT = new Event("AuthorizationChangeProcessed", - Arrays.asList(new TypeReference
(true) { - }, new TypeReference(true) { - }, new TypeReference() { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference
(true) {}, new TypeReference
(true) {}, new TypeReference(true) {}, new TypeReference() {})); + ; public static final Event AUTHORIZATIONPROCESSED_EVENT = new Event("AuthorizationProcessed", - Arrays.asList(new TypeReference
(true) { - }, new TypeReference(true) { - }, new TypeReference() { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference
(true) {}, new TypeReference
(true) {}, new TypeReference(true) {}, new TypeReference() {})); + ; + + public static final Event DEBTPROCESSED_EVENT = new Event("DebtProcessed", + Arrays.>asList(new TypeReference
(true) {}, new TypeReference
(true) {}, new TypeReference() {})); + ; public static final Event DEBTWRITEOFFPROCESSED_EVENT = new Event("DebtWriteOffProcessed", - Arrays.asList(new TypeReference
(true) { - }, new TypeReference() { - })); - - public static final Event FIXEDFEESET_EVENT = new Event("FixedFeeSet", - List.of(new TypeReference() { - })); + Arrays.>asList(new TypeReference
(true) {}, new TypeReference
(true) {}, new TypeReference() {})); + ; public static final Event PAUSED_EVENT = new Event("Paused", - List.of(new TypeReference
() { - })); + Arrays.>asList(new TypeReference
() {})); + ; - public static final Event PAYMENTACCOUNTSET_EVENT = new Event("PaymentAccountSet", - Arrays.asList(new TypeReference
(true) { - }, new TypeReference
() { - })); + public static final Event PAYMENTACCOUNTDEPLOYED_EVENT = new Event("PaymentAccountDeployed", + Arrays.>asList(new TypeReference
(true) {}, new TypeReference
() {}, new TypeReference
() {})); + ; public static final Event PAYMENTRECEIVERSET_EVENT = new Event("PaymentReceiverSet", - List.of(new TypeReference
() { - })); - - public static final Event PENDINGREFUNDPROCESSED_EVENT = new Event("PendingRefundProcessed", - Arrays.asList(new TypeReference
(true) { - }, new TypeReference(true) { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference
() {})); + ; public static final Event REFUNDACCOUNTSET_EVENT = new Event("RefundAccountSet", - List.of(new TypeReference
() { - })); + Arrays.>asList(new TypeReference
() {})); + ; public static final Event REFUNDPROCESSED_EVENT = new Event("RefundProcessed", - Arrays.asList(new TypeReference
(true) { - }, new TypeReference(true) { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference
(true) {}, new TypeReference
(true) {}, new TypeReference(true) {}, new TypeReference() {})); + ; public static final Event ROLEADMINCHANGED_EVENT = new Event("RoleAdminChanged", - Arrays.asList(new TypeReference(true) { - }, new TypeReference(true) { - }, new TypeReference(true) { - })); + Arrays.>asList(new TypeReference(true) {}, new TypeReference(true) {}, new TypeReference(true) {})); + ; public static final Event ROLEGRANTED_EVENT = new Event("RoleGranted", - Arrays.asList(new TypeReference(true) { - }, new TypeReference
(true) { - }, new TypeReference
(true) { - })); + Arrays.>asList(new TypeReference(true) {}, new TypeReference
(true) {}, new TypeReference
(true) {})); + ; public static final Event ROLEREVOKED_EVENT = new Event("RoleRevoked", - Arrays.asList(new TypeReference(true) { - }, new TypeReference
(true) { - }, new TypeReference
(true) { - })); - - public static final Event SAVEREFUNDPROCESSED_EVENT = new Event("SaveRefundProcessed", - Arrays.asList(new TypeReference
(true) { - }, new TypeReference(true) { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference(true) {}, new TypeReference
(true) {}, new TypeReference
(true) {})); + ; public static final Event SECURITYDELAYSET_EVENT = new Event("SecurityDelaySet", - List.of(new TypeReference() { - })); + Arrays.>asList(new TypeReference() {})); + ; public static final Event SETTLEMENTPERIODSET_EVENT = new Event("SettlementPeriodSet", - List.of(new TypeReference() { - })); + Arrays.>asList(new TypeReference() {})); + ; public static final Event SETTLEMENTPROCESSED_EVENT = new Event("SettlementProcessed", - Arrays.asList(new TypeReference
(true) { - }, new TypeReference(true) { - }, new TypeReference() { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference
(true) {}, new TypeReference
(true) {}, new TypeReference(true) {}, new TypeReference() {})); + ; public static final Event UNPAUSED_EVENT = new Event("Unpaused", - List.of(new TypeReference
() { - })); + Arrays.>asList(new TypeReference
() {})); + ; + + public static final Event UNSETTLEDTRANSACTIONPROCESSED_EVENT = new Event("UnsettledTransactionProcessed", + Arrays.>asList(new TypeReference
(true) {}, new TypeReference
(true) {}, new TypeReference() {})); + ; public static final Event VERIFIEDBALANCEINCREASEDFOR_EVENT = new Event("VerifiedBalanceIncreasedFor", - Arrays.asList(new TypeReference
(true) { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference
(true) {}, new TypeReference() {})); + ; public static final Event VERIFIEDBALANCESETFOR_EVENT = new Event("VerifiedBalanceSetFor", - Arrays.asList(new TypeReference
(true) { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference
(true) {}, new TypeReference() {})); + ; + + public static final Event WITHDRAWALPROCESSED_EVENT = new Event("WithdrawalProcessed", + Arrays.>asList(new TypeReference
(true) {})); + ; @Deprecated - protected TangemBridgeProcessor(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + protected TangemBridgeProcessor(String contractAddress, Web3j web3j, Credentials credentials, + BigInteger gasPrice, BigInteger gasLimit) { super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit); } - protected TangemBridgeProcessor(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { + protected TangemBridgeProcessor(String contractAddress, Web3j web3j, Credentials credentials, + ContractGasProvider contractGasProvider) { super(BINARY, contractAddress, web3j, credentials, contractGasProvider); } @Deprecated - protected TangemBridgeProcessor(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + protected TangemBridgeProcessor(String contractAddress, Web3j web3j, + TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit); } - protected TangemBridgeProcessor(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + protected TangemBridgeProcessor(String contractAddress, Web3j web3j, + TransactionManager transactionManager, ContractGasProvider contractGasProvider) { super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider); } - public static List getAuthorizationChangeProcessedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(AUTHORIZATIONCHANGEPROCESSED_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - AuthorizationChangeProcessedEventResponse typedResponse = new AuthorizationChangeProcessedEventResponse(); + public static List getAuthLimitMarginSetForEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(AUTHLIMITMARGINSETFOR_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + AuthLimitMarginSetForEventResponse typedResponse = new AuthLimitMarginSetForEventResponse(); typedResponse.log = eventValues.getLog(); - typedResponse.card = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(1).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.fee = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.authLimitMargin = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); responses.add(typedResponse); } return responses; } - public static AuthorizationChangeProcessedEventResponse getAuthorizationChangeProcessedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(AUTHORIZATIONCHANGEPROCESSED_EVENT, log); - AuthorizationChangeProcessedEventResponse typedResponse = new AuthorizationChangeProcessedEventResponse(); + public static AuthLimitMarginSetForEventResponse getAuthLimitMarginSetForEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(AUTHLIMITMARGINSETFOR_EVENT, log); + AuthLimitMarginSetForEventResponse typedResponse = new AuthLimitMarginSetForEventResponse(); typedResponse.log = log; - typedResponse.card = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(1).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.fee = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.authLimitMargin = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); return typedResponse; } - public static AuthorizationProcessedEventResponse getAuthorizationProcessedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(AUTHORIZATIONPROCESSED_EVENT, log); + public Flowable authLimitMarginSetForEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getAuthLimitMarginSetForEventFromLog(log)); + } + + public Flowable authLimitMarginSetForEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(AUTHLIMITMARGINSETFOR_EVENT)); + return authLimitMarginSetForEventFlowable(filter); + } + + public static List getAuthorizationChangeProcessedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(AUTHORIZATIONCHANGEPROCESSED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + AuthorizationChangeProcessedEventResponse typedResponse = new AuthorizationChangeProcessedEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(2).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public static AuthorizationChangeProcessedEventResponse getAuthorizationChangeProcessedEventFromLog( + Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(AUTHORIZATIONCHANGEPROCESSED_EVENT, log); + AuthorizationChangeProcessedEventResponse typedResponse = new AuthorizationChangeProcessedEventResponse(); + typedResponse.log = log; + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(2).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; + } + + public Flowable authorizationChangeProcessedEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getAuthorizationChangeProcessedEventFromLog(log)); + } + + public Flowable authorizationChangeProcessedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(AUTHORIZATIONCHANGEPROCESSED_EVENT)); + return authorizationChangeProcessedEventFlowable(filter); + } + + public static List getAuthorizationProcessedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(AUTHORIZATIONPROCESSED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + AuthorizationProcessedEventResponse typedResponse = new AuthorizationProcessedEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(2).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public static AuthorizationProcessedEventResponse getAuthorizationProcessedEventFromLog( + Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(AUTHORIZATIONPROCESSED_EVENT, log); AuthorizationProcessedEventResponse typedResponse = new AuthorizationProcessedEventResponse(); typedResponse.log = log; - typedResponse.card = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(2).getValue(); typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.fee = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); return typedResponse; } + public Flowable authorizationProcessedEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getAuthorizationProcessedEventFromLog(log)); + } + + public Flowable authorizationProcessedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(AUTHORIZATIONPROCESSED_EVENT)); + return authorizationProcessedEventFlowable(filter); + } + + public static List getDebtProcessedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(DEBTPROCESSED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + DebtProcessedEventResponse typedResponse = new DebtProcessedEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public static DebtProcessedEventResponse getDebtProcessedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(DEBTPROCESSED_EVENT, log); + DebtProcessedEventResponse typedResponse = new DebtProcessedEventResponse(); + typedResponse.log = log; + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; + } + + public Flowable debtProcessedEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getDebtProcessedEventFromLog(log)); + } + + public Flowable debtProcessedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(DEBTPROCESSED_EVENT)); + return debtProcessedEventFlowable(filter); + } + + public static List getDebtWriteOffProcessedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(DEBTWRITEOFFPROCESSED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + DebtWriteOffProcessedEventResponse typedResponse = new DebtWriteOffProcessedEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + public static DebtWriteOffProcessedEventResponse getDebtWriteOffProcessedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(DEBTWRITEOFFPROCESSED_EVENT, log); + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(DEBTWRITEOFFPROCESSED_EVENT, log); DebtWriteOffProcessedEventResponse typedResponse = new DebtWriteOffProcessedEventResponse(); typedResponse.log = log; - typedResponse.card = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); return typedResponse; } - public static List getAuthorizationProcessedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(AUTHORIZATIONPROCESSED_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - AuthorizationProcessedEventResponse typedResponse = new AuthorizationProcessedEventResponse(); - typedResponse.log = eventValues.getLog(); - typedResponse.card = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(1).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.fee = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); - responses.add(typedResponse); - } - return responses; + public Flowable debtWriteOffProcessedEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getDebtWriteOffProcessedEventFromLog(log)); } - public static FixedFeeSetEventResponse getFixedFeeSetEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(FIXEDFEESET_EVENT, log); - FixedFeeSetEventResponse typedResponse = new FixedFeeSetEventResponse(); - typedResponse.log = log; - typedResponse.fixedFee = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; + public Flowable debtWriteOffProcessedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(DEBTWRITEOFFPROCESSED_EVENT)); + return debtWriteOffProcessedEventFlowable(filter); } public static List getPausedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(PAUSED_EVENT, transactionReceipt); + List valueList = staticExtractEventParametersWithLog(PAUSED_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { PausedEventResponse typedResponse = new PausedEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.account = (String) eventValues.getNonIndexedValues().get(0).getValue(); @@ -338,177 +448,67 @@ class TangemBridgeProcessor extends Contract { } public static PausedEventResponse getPausedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(PAUSED_EVENT, log); + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(PAUSED_EVENT, log); PausedEventResponse typedResponse = new PausedEventResponse(); typedResponse.log = log; typedResponse.account = (String) eventValues.getNonIndexedValues().get(0).getValue(); return typedResponse; } - public static List getDebtWriteOffProcessedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(DEBTWRITEOFFPROCESSED_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - DebtWriteOffProcessedEventResponse typedResponse = new DebtWriteOffProcessedEventResponse(); + public Flowable pausedEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getPausedEventFromLog(log)); + } + + public Flowable pausedEventFlowable(DefaultBlockParameter startBlock, + DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(PAUSED_EVENT)); + return pausedEventFlowable(filter); + } + + public static List getPaymentAccountDeployedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(PAYMENTACCOUNTDEPLOYED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + PaymentAccountDeployedEventResponse typedResponse = new PaymentAccountDeployedEventResponse(); typedResponse.log = eventValues.getLog(); - typedResponse.card = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.owner = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.cardAddress = (String) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.paymentAccount = (String) eventValues.getNonIndexedValues().get(1).getValue(); responses.add(typedResponse); } return responses; } - public static PaymentAccountSetEventResponse getPaymentAccountSetEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(PAYMENTACCOUNTSET_EVENT, log); - PaymentAccountSetEventResponse typedResponse = new PaymentAccountSetEventResponse(); + public static PaymentAccountDeployedEventResponse getPaymentAccountDeployedEventFromLog( + Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(PAYMENTACCOUNTDEPLOYED_EVENT, log); + PaymentAccountDeployedEventResponse typedResponse = new PaymentAccountDeployedEventResponse(); typedResponse.log = log; - typedResponse.card = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.paymentAccount = (String) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.owner = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.cardAddress = (String) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.paymentAccount = (String) eventValues.getNonIndexedValues().get(1).getValue(); return typedResponse; } - public static PaymentReceiverSetEventResponse getPaymentReceiverSetEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(PAYMENTRECEIVERSET_EVENT, log); - PaymentReceiverSetEventResponse typedResponse = new PaymentReceiverSetEventResponse(); - typedResponse.log = log; - typedResponse.paymentReceiver = (String) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; + public Flowable paymentAccountDeployedEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getPaymentAccountDeployedEventFromLog(log)); } - public static RefundAccountSetEventResponse getRefundAccountSetEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(REFUNDACCOUNTSET_EVENT, log); - RefundAccountSetEventResponse typedResponse = new RefundAccountSetEventResponse(); - typedResponse.log = log; - typedResponse.refundAccount = (String) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; + public Flowable paymentAccountDeployedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(PAYMENTACCOUNTDEPLOYED_EVENT)); + return paymentAccountDeployedEventFlowable(filter); } - public static List getFixedFeeSetEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(FIXEDFEESET_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - FixedFeeSetEventResponse typedResponse = new FixedFeeSetEventResponse(); - typedResponse.log = eventValues.getLog(); - typedResponse.fixedFee = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - responses.add(typedResponse); - } - return responses; - } - - public static RefundProcessedEventResponse getRefundProcessedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(REFUNDPROCESSED_EVENT, log); - RefundProcessedEventResponse typedResponse = new RefundProcessedEventResponse(); - typedResponse.log = log; - typedResponse.card = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(1).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; - } - - public static RoleAdminChangedEventResponse getRoleAdminChangedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(ROLEADMINCHANGED_EVENT, log); - RoleAdminChangedEventResponse typedResponse = new RoleAdminChangedEventResponse(); - typedResponse.log = log; - typedResponse.role = (byte[]) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.previousAdminRole = (byte[]) eventValues.getIndexedValues().get(1).getValue(); - typedResponse.newAdminRole = (byte[]) eventValues.getIndexedValues().get(2).getValue(); - return typedResponse; - } - - public static RoleGrantedEventResponse getRoleGrantedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(ROLEGRANTED_EVENT, log); - RoleGrantedEventResponse typedResponse = new RoleGrantedEventResponse(); - typedResponse.log = log; - typedResponse.role = (byte[]) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.account = (String) eventValues.getIndexedValues().get(1).getValue(); - typedResponse.sender = (String) eventValues.getIndexedValues().get(2).getValue(); - return typedResponse; - } - - public static RoleRevokedEventResponse getRoleRevokedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(ROLEREVOKED_EVENT, log); - RoleRevokedEventResponse typedResponse = new RoleRevokedEventResponse(); - typedResponse.log = log; - typedResponse.role = (byte[]) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.account = (String) eventValues.getIndexedValues().get(1).getValue(); - typedResponse.sender = (String) eventValues.getIndexedValues().get(2).getValue(); - return typedResponse; - } - - public static SaveRefundProcessedEventResponse getSaveRefundProcessedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(SAVEREFUNDPROCESSED_EVENT, log); - SaveRefundProcessedEventResponse typedResponse = new SaveRefundProcessedEventResponse(); - typedResponse.log = log; - typedResponse.card = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(1).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; - } - - public static SecurityDelaySetEventResponse getSecurityDelaySetEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(SECURITYDELAYSET_EVENT, log); - SecurityDelaySetEventResponse typedResponse = new SecurityDelaySetEventResponse(); - typedResponse.log = log; - typedResponse.securityDelay = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; - } - - public static SettlementPeriodSetEventResponse getSettlementPeriodSetEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(SETTLEMENTPERIODSET_EVENT, log); - SettlementPeriodSetEventResponse typedResponse = new SettlementPeriodSetEventResponse(); - typedResponse.log = log; - typedResponse.settlementPeriod = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; - } - - public static List getPaymentAccountSetEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(PAYMENTACCOUNTSET_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - PaymentAccountSetEventResponse typedResponse = new PaymentAccountSetEventResponse(); - typedResponse.log = eventValues.getLog(); - typedResponse.card = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.paymentAccount = (String) eventValues.getNonIndexedValues().get(0).getValue(); - responses.add(typedResponse); - } - return responses; - } - - public static SettlementProcessedEventResponse getSettlementProcessedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(SETTLEMENTPROCESSED_EVENT, log); - SettlementProcessedEventResponse typedResponse = new SettlementProcessedEventResponse(); - typedResponse.log = log; - typedResponse.card = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(1).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.fee = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); - return typedResponse; - } - - public static List getUnpausedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(UNPAUSED_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - UnpausedEventResponse typedResponse = new UnpausedEventResponse(); - typedResponse.log = eventValues.getLog(); - typedResponse.account = (String) eventValues.getNonIndexedValues().get(0).getValue(); - responses.add(typedResponse); - } - return responses; - } - - public static UnpausedEventResponse getUnpausedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(UNPAUSED_EVENT, log); - UnpausedEventResponse typedResponse = new UnpausedEventResponse(); - typedResponse.log = log; - typedResponse.account = (String) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; - } - - public static List getPaymentReceiverSetEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(PAYMENTRECEIVERSET_EVENT, transactionReceipt); + public static List getPaymentReceiverSetEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(PAYMENTRECEIVERSET_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { PaymentReceiverSetEventResponse typedResponse = new PaymentReceiverSetEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.paymentReceiver = (String) eventValues.getNonIndexedValues().get(0).getValue(); @@ -517,61 +517,31 @@ class TangemBridgeProcessor extends Contract { return responses; } - public static VerifiedBalanceIncreasedForEventResponse getVerifiedBalanceIncreasedForEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(VERIFIEDBALANCEINCREASEDFOR_EVENT, log); - VerifiedBalanceIncreasedForEventResponse typedResponse = new VerifiedBalanceIncreasedForEventResponse(); + public static PaymentReceiverSetEventResponse getPaymentReceiverSetEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(PAYMENTRECEIVERSET_EVENT, log); + PaymentReceiverSetEventResponse typedResponse = new PaymentReceiverSetEventResponse(); typedResponse.log = log; - typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.increase = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.paymentReceiver = (String) eventValues.getNonIndexedValues().get(0).getValue(); return typedResponse; } - @Deprecated - public static TangemBridgeProcessor load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { - return new TangemBridgeProcessor(contractAddress, web3j, credentials, gasPrice, gasLimit); + public Flowable paymentReceiverSetEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getPaymentReceiverSetEventFromLog(log)); } - @Deprecated - public static TangemBridgeProcessor load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { - return new TangemBridgeProcessor(contractAddress, web3j, transactionManager, gasPrice, gasLimit); + public Flowable paymentReceiverSetEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(PAYMENTRECEIVERSET_EVENT)); + return paymentReceiverSetEventFlowable(filter); } - public static List getPendingRefundProcessedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(PENDINGREFUNDPROCESSED_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - PendingRefundProcessedEventResponse typedResponse = new PendingRefundProcessedEventResponse(); - typedResponse.log = eventValues.getLog(); - typedResponse.card = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(1).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - responses.add(typedResponse); - } - return responses; - } - - public static PendingRefundProcessedEventResponse getPendingRefundProcessedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(PENDINGREFUNDPROCESSED_EVENT, log); - PendingRefundProcessedEventResponse typedResponse = new PendingRefundProcessedEventResponse(); - typedResponse.log = log; - typedResponse.card = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(1).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; - } - - public static TangemBridgeProcessor load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { - return new TangemBridgeProcessor(contractAddress, web3j, credentials, contractGasProvider); - } - - public static TangemBridgeProcessor load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { - return new TangemBridgeProcessor(contractAddress, web3j, transactionManager, contractGasProvider); - } - - public static List getRefundAccountSetEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(REFUNDACCOUNTSET_EVENT, transactionReceipt); + public static List getRefundAccountSetEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(REFUNDACCOUNTSET_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { RefundAccountSetEventResponse typedResponse = new RefundAccountSetEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.refundAccount = (String) eventValues.getNonIndexedValues().get(0).getValue(); @@ -580,72 +550,68 @@ class TangemBridgeProcessor extends Contract { return responses; } - public static RemoteCall deploy(Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider, String paymentReceiver_, String refundAccount_, String paymentAccountFactory_, String paymentToken_, BigInteger securityDelay_) { - String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new Address(160, paymentReceiver_), - new Address(160, refundAccount_), - new Address(160, paymentAccountFactory_), - new Address(160, paymentToken_), - new Uint256(securityDelay_))); - return deployRemoteCall(TangemBridgeProcessor.class, web3j, credentials, contractGasProvider, BINARY, encodedConstructor); + public static RefundAccountSetEventResponse getRefundAccountSetEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(REFUNDACCOUNTSET_EVENT, log); + RefundAccountSetEventResponse typedResponse = new RefundAccountSetEventResponse(); + typedResponse.log = log; + typedResponse.refundAccount = (String) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; } - public static RemoteCall deploy(Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider, String paymentReceiver_, String refundAccount_, String paymentAccountFactory_, String paymentToken_, BigInteger securityDelay_) { - String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new Address(160, paymentReceiver_), - new Address(160, refundAccount_), - new Address(160, paymentAccountFactory_), - new Address(160, paymentToken_), - new Uint256(securityDelay_))); - return deployRemoteCall(TangemBridgeProcessor.class, web3j, transactionManager, contractGasProvider, BINARY, encodedConstructor); + public Flowable refundAccountSetEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getRefundAccountSetEventFromLog(log)); } - @Deprecated - public static RemoteCall deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit, String paymentReceiver_, String refundAccount_, String paymentAccountFactory_, String paymentToken_, BigInteger securityDelay_) { - String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new Address(160, paymentReceiver_), - new Address(160, refundAccount_), - new Address(160, paymentAccountFactory_), - new Address(160, paymentToken_), - new Uint256(securityDelay_))); - return deployRemoteCall(TangemBridgeProcessor.class, web3j, credentials, gasPrice, gasLimit, BINARY, encodedConstructor); + public Flowable refundAccountSetEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(REFUNDACCOUNTSET_EVENT)); + return refundAccountSetEventFlowable(filter); } - public static List getRefundProcessedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(REFUNDPROCESSED_EVENT, transactionReceipt); + public static List getRefundProcessedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(REFUNDPROCESSED_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { RefundProcessedEventResponse typedResponse = new RefundProcessedEventResponse(); typedResponse.log = eventValues.getLog(); - typedResponse.card = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(2).getValue(); typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); responses.add(typedResponse); } return responses; } - @Deprecated - public static RemoteCall deploy(Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit, String paymentReceiver_, String refundAccount_, String paymentAccountFactory_, String paymentToken_, BigInteger securityDelay_) { - String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new Address(160, paymentReceiver_), - new Address(160, refundAccount_), - new Address(160, paymentAccountFactory_), - new Address(160, paymentToken_), - new Uint256(securityDelay_))); - return deployRemoteCall(TangemBridgeProcessor.class, web3j, transactionManager, gasPrice, gasLimit, BINARY, encodedConstructor); + public static RefundProcessedEventResponse getRefundProcessedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(REFUNDPROCESSED_EVENT, log); + RefundProcessedEventResponse typedResponse = new RefundProcessedEventResponse(); + typedResponse.log = log; + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(2).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; } - public Flowable authorizationChangeProcessedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getAuthorizationChangeProcessedEventFromLog(log)); + public Flowable refundProcessedEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getRefundProcessedEventFromLog(log)); } - public Flowable authorizationChangeProcessedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public Flowable refundProcessedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(AUTHORIZATIONCHANGEPROCESSED_EVENT)); - return authorizationChangeProcessedEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(REFUNDPROCESSED_EVENT)); + return refundProcessedEventFlowable(filter); } - public static List getRoleAdminChangedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(ROLEADMINCHANGED_EVENT, transactionReceipt); + public static List getRoleAdminChangedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(ROLEADMINCHANGED_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { RoleAdminChangedEventResponse typedResponse = new RoleAdminChangedEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.role = (byte[]) eventValues.getIndexedValues().get(0).getValue(); @@ -656,24 +622,32 @@ class TangemBridgeProcessor extends Contract { return responses; } - public Flowable authorizationProcessedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getAuthorizationProcessedEventFromLog(log)); + public static RoleAdminChangedEventResponse getRoleAdminChangedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(ROLEADMINCHANGED_EVENT, log); + RoleAdminChangedEventResponse typedResponse = new RoleAdminChangedEventResponse(); + typedResponse.log = log; + typedResponse.role = (byte[]) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.previousAdminRole = (byte[]) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.newAdminRole = (byte[]) eventValues.getIndexedValues().get(2).getValue(); + return typedResponse; } - public Flowable authorizationProcessedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public Flowable roleAdminChangedEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getRoleAdminChangedEventFromLog(log)); + } + + public Flowable roleAdminChangedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(AUTHORIZATIONPROCESSED_EVENT)); - return authorizationProcessedEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(ROLEADMINCHANGED_EVENT)); + return roleAdminChangedEventFlowable(filter); } - public Flowable debtWriteOffProcessedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getDebtWriteOffProcessedEventFromLog(log)); - } - - public static List getRoleGrantedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(ROLEGRANTED_EVENT, transactionReceipt); + public static List getRoleGrantedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(ROLEGRANTED_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { RoleGrantedEventResponse typedResponse = new RoleGrantedEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.role = (byte[]) eventValues.getIndexedValues().get(0).getValue(); @@ -684,26 +658,32 @@ class TangemBridgeProcessor extends Contract { return responses; } - public Flowable debtWriteOffProcessedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public static RoleGrantedEventResponse getRoleGrantedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(ROLEGRANTED_EVENT, log); + RoleGrantedEventResponse typedResponse = new RoleGrantedEventResponse(); + typedResponse.log = log; + typedResponse.role = (byte[]) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.account = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.sender = (String) eventValues.getIndexedValues().get(2).getValue(); + return typedResponse; + } + + public Flowable roleGrantedEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getRoleGrantedEventFromLog(log)); + } + + public Flowable roleGrantedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(DEBTWRITEOFFPROCESSED_EVENT)); - return debtWriteOffProcessedEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(ROLEGRANTED_EVENT)); + return roleGrantedEventFlowable(filter); } - public Flowable fixedFeeSetEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getFixedFeeSetEventFromLog(log)); - } - - public Flowable fixedFeeSetEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(FIXEDFEESET_EVENT)); - return fixedFeeSetEventFlowable(filter); - } - - public static List getRoleRevokedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(ROLEREVOKED_EVENT, transactionReceipt); + public static List getRoleRevokedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(ROLEREVOKED_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { RoleRevokedEventResponse typedResponse = new RoleRevokedEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.role = (byte[]) eventValues.getIndexedValues().get(0).getValue(); @@ -714,54 +694,32 @@ class TangemBridgeProcessor extends Contract { return responses; } - public Flowable pausedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getPausedEventFromLog(log)); + public static RoleRevokedEventResponse getRoleRevokedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(ROLEREVOKED_EVENT, log); + RoleRevokedEventResponse typedResponse = new RoleRevokedEventResponse(); + typedResponse.log = log; + typedResponse.role = (byte[]) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.account = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.sender = (String) eventValues.getIndexedValues().get(2).getValue(); + return typedResponse; } - public Flowable pausedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public Flowable roleRevokedEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getRoleRevokedEventFromLog(log)); + } + + public Flowable roleRevokedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(PAUSED_EVENT)); - return pausedEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(ROLEREVOKED_EVENT)); + return roleRevokedEventFlowable(filter); } - public Flowable paymentAccountSetEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getPaymentAccountSetEventFromLog(log)); - } - - public static List getSaveRefundProcessedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(SAVEREFUNDPROCESSED_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - SaveRefundProcessedEventResponse typedResponse = new SaveRefundProcessedEventResponse(); - typedResponse.log = eventValues.getLog(); - typedResponse.card = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(1).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - responses.add(typedResponse); - } - return responses; - } - - public Flowable paymentAccountSetEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(PAYMENTACCOUNTSET_EVENT)); - return paymentAccountSetEventFlowable(filter); - } - - public Flowable paymentReceiverSetEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getPaymentReceiverSetEventFromLog(log)); - } - - public Flowable paymentReceiverSetEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(PAYMENTRECEIVERSET_EVENT)); - return paymentReceiverSetEventFlowable(filter); - } - - public static List getSecurityDelaySetEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(SECURITYDELAYSET_EVENT, transactionReceipt); + public static List getSecurityDelaySetEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(SECURITYDELAYSET_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { SecurityDelaySetEventResponse typedResponse = new SecurityDelaySetEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.securityDelay = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); @@ -770,24 +728,30 @@ class TangemBridgeProcessor extends Contract { return responses; } - public Flowable pendingRefundProcessedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getPendingRefundProcessedEventFromLog(log)); + public static SecurityDelaySetEventResponse getSecurityDelaySetEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(SECURITYDELAYSET_EVENT, log); + SecurityDelaySetEventResponse typedResponse = new SecurityDelaySetEventResponse(); + typedResponse.log = log; + typedResponse.securityDelay = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; } - public Flowable pendingRefundProcessedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public Flowable securityDelaySetEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getSecurityDelaySetEventFromLog(log)); + } + + public Flowable securityDelaySetEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(PENDINGREFUNDPROCESSED_EVENT)); - return pendingRefundProcessedEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(SECURITYDELAYSET_EVENT)); + return securityDelaySetEventFlowable(filter); } - public Flowable refundAccountSetEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getRefundAccountSetEventFromLog(log)); - } - - public static List getSettlementPeriodSetEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(SETTLEMENTPERIODSET_EVENT, transactionReceipt); + public static List getSettlementPeriodSetEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(SETTLEMENTPERIODSET_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { SettlementPeriodSetEventResponse typedResponse = new SettlementPeriodSetEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.settlementPeriod = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); @@ -796,75 +760,140 @@ class TangemBridgeProcessor extends Contract { return responses; } - public Flowable refundAccountSetEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public static SettlementPeriodSetEventResponse getSettlementPeriodSetEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(SETTLEMENTPERIODSET_EVENT, log); + SettlementPeriodSetEventResponse typedResponse = new SettlementPeriodSetEventResponse(); + typedResponse.log = log; + typedResponse.settlementPeriod = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; + } + + public Flowable settlementPeriodSetEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getSettlementPeriodSetEventFromLog(log)); + } + + public Flowable settlementPeriodSetEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(REFUNDACCOUNTSET_EVENT)); - return refundAccountSetEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(SETTLEMENTPERIODSET_EVENT)); + return settlementPeriodSetEventFlowable(filter); } - public Flowable refundProcessedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getRefundProcessedEventFromLog(log)); - } - - public Flowable refundProcessedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(REFUNDPROCESSED_EVENT)); - return refundProcessedEventFlowable(filter); - } - - public static List getSettlementProcessedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(SETTLEMENTPROCESSED_EVENT, transactionReceipt); + public static List getSettlementProcessedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(SETTLEMENTPROCESSED_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { SettlementProcessedEventResponse typedResponse = new SettlementProcessedEventResponse(); typedResponse.log = eventValues.getLog(); - typedResponse.card = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(2).getValue(); typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.fee = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); responses.add(typedResponse); } return responses; } - public Flowable roleAdminChangedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getRoleAdminChangedEventFromLog(log)); + public static SettlementProcessedEventResponse getSettlementProcessedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(SETTLEMENTPROCESSED_EVENT, log); + SettlementProcessedEventResponse typedResponse = new SettlementProcessedEventResponse(); + typedResponse.log = log; + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(2).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; } - public Flowable roleAdminChangedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public Flowable settlementProcessedEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getSettlementProcessedEventFromLog(log)); + } + + public Flowable settlementProcessedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(ROLEADMINCHANGED_EVENT)); - return roleAdminChangedEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(SETTLEMENTPROCESSED_EVENT)); + return settlementProcessedEventFlowable(filter); } - public Flowable roleGrantedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getRoleGrantedEventFromLog(log)); + public static List getUnpausedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(UNPAUSED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + UnpausedEventResponse typedResponse = new UnpausedEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.account = (String) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; } - public Flowable roleGrantedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public static UnpausedEventResponse getUnpausedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(UNPAUSED_EVENT, log); + UnpausedEventResponse typedResponse = new UnpausedEventResponse(); + typedResponse.log = log; + typedResponse.account = (String) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; + } + + public Flowable unpausedEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getUnpausedEventFromLog(log)); + } + + public Flowable unpausedEventFlowable(DefaultBlockParameter startBlock, + DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(ROLEGRANTED_EVENT)); - return roleGrantedEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(UNPAUSED_EVENT)); + return unpausedEventFlowable(filter); } - public Flowable roleRevokedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getRoleRevokedEventFromLog(log)); + public static List getUnsettledTransactionProcessedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(UNSETTLEDTRANSACTIONPROCESSED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + UnsettledTransactionProcessedEventResponse typedResponse = new UnsettledTransactionProcessedEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.transactionId = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; } - public Flowable roleRevokedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public static UnsettledTransactionProcessedEventResponse getUnsettledTransactionProcessedEventFromLog( + Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(UNSETTLEDTRANSACTIONPROCESSED_EVENT, log); + UnsettledTransactionProcessedEventResponse typedResponse = new UnsettledTransactionProcessedEventResponse(); + typedResponse.log = log; + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.transactionId = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; + } + + public Flowable unsettledTransactionProcessedEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getUnsettledTransactionProcessedEventFromLog(log)); + } + + public Flowable unsettledTransactionProcessedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(ROLEREVOKED_EVENT)); - return roleRevokedEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(UNSETTLEDTRANSACTIONPROCESSED_EVENT)); + return unsettledTransactionProcessedEventFlowable(filter); } - public Flowable saveRefundProcessedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getSaveRefundProcessedEventFromLog(log)); - } - - public static List getVerifiedBalanceIncreasedForEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(VERIFIEDBALANCEINCREASEDFOR_EVENT, transactionReceipt); + public static List getVerifiedBalanceIncreasedForEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(VERIFIEDBALANCEINCREASEDFOR_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { VerifiedBalanceIncreasedForEventResponse typedResponse = new VerifiedBalanceIncreasedForEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); @@ -874,26 +903,33 @@ class TangemBridgeProcessor extends Contract { return responses; } - public Flowable saveRefundProcessedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public static VerifiedBalanceIncreasedForEventResponse getVerifiedBalanceIncreasedForEventFromLog( + Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(VERIFIEDBALANCEINCREASEDFOR_EVENT, log); + VerifiedBalanceIncreasedForEventResponse typedResponse = new VerifiedBalanceIncreasedForEventResponse(); + typedResponse.log = log; + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.increase = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; + } + + public Flowable verifiedBalanceIncreasedForEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getVerifiedBalanceIncreasedForEventFromLog(log)); + } + + public Flowable verifiedBalanceIncreasedForEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(SAVEREFUNDPROCESSED_EVENT)); - return saveRefundProcessedEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(VERIFIEDBALANCEINCREASEDFOR_EVENT)); + return verifiedBalanceIncreasedForEventFlowable(filter); } - public Flowable securityDelaySetEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getSecurityDelaySetEventFromLog(log)); - } - - public Flowable securityDelaySetEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(SECURITYDELAYSET_EVENT)); - return securityDelaySetEventFlowable(filter); - } - - public static List getVerifiedBalanceSetForEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(VERIFIEDBALANCESETFOR_EVENT, transactionReceipt); + public static List getVerifiedBalanceSetForEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(VERIFIEDBALANCESETFOR_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { VerifiedBalanceSetForEventResponse typedResponse = new VerifiedBalanceSetForEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); @@ -904,7 +940,7 @@ class TangemBridgeProcessor extends Contract { } public static VerifiedBalanceSetForEventResponse getVerifiedBalanceSetForEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(VERIFIEDBALANCESETFOR_EVENT, log); + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(VERIFIEDBALANCESETFOR_EVENT, log); VerifiedBalanceSetForEventResponse typedResponse = new VerifiedBalanceSetForEventResponse(); typedResponse.log = log; typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); @@ -912,486 +948,671 @@ class TangemBridgeProcessor extends Contract { return typedResponse; } - public Flowable verifiedBalanceSetForEventFlowable(EthFilter filter) { + public Flowable verifiedBalanceSetForEventFlowable( + EthFilter filter) { return web3j.ethLogFlowable(filter).map(log -> getVerifiedBalanceSetForEventFromLog(log)); } - public Flowable verifiedBalanceSetForEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public Flowable verifiedBalanceSetForEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); filter.addSingleTopic(EventEncoder.encode(VERIFIEDBALANCESETFOR_EVENT)); return verifiedBalanceSetForEventFlowable(filter); } - public Flowable settlementPeriodSetEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getSettlementPeriodSetEventFromLog(log)); + public static List getWithdrawalProcessedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(WITHDRAWALPROCESSED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + WithdrawalProcessedEventResponse typedResponse = new WithdrawalProcessedEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; } - public Flowable settlementPeriodSetEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public static WithdrawalProcessedEventResponse getWithdrawalProcessedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(WITHDRAWALPROCESSED_EVENT, log); + WithdrawalProcessedEventResponse typedResponse = new WithdrawalProcessedEventResponse(); + typedResponse.log = log; + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + return typedResponse; + } + + public Flowable withdrawalProcessedEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getWithdrawalProcessedEventFromLog(log)); + } + + public Flowable withdrawalProcessedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(SETTLEMENTPERIODSET_EVENT)); - return settlementPeriodSetEventFlowable(filter); - } - - public Flowable settlementProcessedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getSettlementProcessedEventFromLog(log)); - } - - public Flowable settlementProcessedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(SETTLEMENTPROCESSED_EVENT)); - return settlementProcessedEventFlowable(filter); - } - - public Flowable unpausedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getUnpausedEventFromLog(log)); - } - - public Flowable unpausedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(UNPAUSED_EVENT)); - return unpausedEventFlowable(filter); - } - - public Flowable verifiedBalanceIncreasedForEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getVerifiedBalanceIncreasedForEventFromLog(log)); - } - - public Flowable verifiedBalanceIncreasedForEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(VERIFIEDBALANCEINCREASEDFOR_EVENT)); - return verifiedBalanceIncreasedForEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(WITHDRAWALPROCESSED_EVENT)); + return withdrawalProcessedEventFlowable(filter); } public RemoteFunctionCall AUTHORIZATION_PROCESSOR_ROLE() { final Function function = new Function(FUNC_AUTHORIZATION_PROCESSOR_ROLE, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, byte[].class); } public RemoteFunctionCall BALANCE_VERIFIER_ROLE() { final Function function = new Function(FUNC_BALANCE_VERIFIER_ROLE, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + return executeRemoteCallSingleValueReturn(function, byte[].class); + } + + public RemoteFunctionCall CARD_CONFIRMER_ROLE() { + final Function function = new Function(FUNC_CARD_CONFIRMER_ROLE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, byte[].class); } public RemoteFunctionCall DEBT_PROCESSOR_ROLE() { final Function function = new Function(FUNC_DEBT_PROCESSOR_ROLE, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, byte[].class); } public RemoteFunctionCall DEFAULT_ADMIN_ROLE() { final Function function = new Function(FUNC_DEFAULT_ADMIN_ROLE, - List.of(), - List.of(new TypeReference() { - })); - return executeRemoteCallSingleValueReturn(function, byte[].class); - } - - public RemoteFunctionCall FIXED_FEE_SETTER_ROLE() { - final Function function = new Function(FUNC_FIXED_FEE_SETTER_ROLE, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, byte[].class); } public RemoteFunctionCall PAUSER_ROLE() { final Function function = new Function(FUNC_PAUSER_ROLE, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, byte[].class); } - public RemoteFunctionCall PAYMENT_ACCOUNT_SETTER_ROLE() { - final Function function = new Function(FUNC_PAYMENT_ACCOUNT_SETTER_ROLE, - List.of(), - List.of(new TypeReference() { - })); + public RemoteFunctionCall PAYMENT_ACCOUNT_DEPLOYER_ROLE() { + final Function function = new Function(FUNC_PAYMENT_ACCOUNT_DEPLOYER_ROLE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + return executeRemoteCallSingleValueReturn(function, byte[].class); + } + + public RemoteFunctionCall PAYMENT_ACCOUNT_PROPERTY_SETTER_ROLE() { + final Function function = new Function(FUNC_PAYMENT_ACCOUNT_PROPERTY_SETTER_ROLE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, byte[].class); } public RemoteFunctionCall PROPERTY_SETTER_ROLE() { final Function function = new Function(FUNC_PROPERTY_SETTER_ROLE, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, byte[].class); } public RemoteFunctionCall REFUND_PROCESSOR_ROLE() { final Function function = new Function(FUNC_REFUND_PROCESSOR_ROLE, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, byte[].class); } public RemoteFunctionCall SETTLEMENT_PROCESSOR_ROLE() { final Function function = new Function(FUNC_SETTLEMENT_PROCESSOR_ROLE, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, byte[].class); } - public RemoteFunctionCall fixedFee() { - final Function function = new Function(FUNC_FIXEDFEE, - List.of(), - List.of(new TypeReference() { - })); - return executeRemoteCallSingleValueReturn(function, BigInteger.class); + public RemoteFunctionCall WITHDRAWAL_PROCESSOR_ROLE() { + final Function function = new Function(FUNC_WITHDRAWAL_PROCESSOR_ROLE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + return executeRemoteCallSingleValueReturn(function, byte[].class); } - public RemoteFunctionCall getPaymentAccount(String card) { - final Function function = new Function(FUNC_GETPAYMENTACCOUNT, - List.of(new Address(160, card)), - List.of(new TypeReference
() { - })); - return executeRemoteCallSingleValueReturn(function, String.class); + public RemoteFunctionCall deployPaymentAccount(String owner, + String cardAddress, CardParams cardParams, BigInteger authLimitMargin_, + byte[] ownerDeployAcceptanceSignature, byte[] cardDeployAcceptanceSignature) { + final Function function = new Function( + FUNC_DEPLOYPAYMENTACCOUNT, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, owner), + new org.web3j.abi.datatypes.Address(160, cardAddress), + cardParams, + new org.web3j.abi.datatypes.generated.Uint256(authLimitMargin_), + new org.web3j.abi.datatypes.DynamicBytes(ownerDeployAcceptanceSignature), + new org.web3j.abi.datatypes.DynamicBytes(cardDeployAcceptanceSignature)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); } public RemoteFunctionCall getRoleAdmin(byte[] role) { final Function function = new Function(FUNC_GETROLEADMIN, - List.of(new Bytes32(role)), - List.of(new TypeReference() { - })); + Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(role)), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, byte[].class); } public RemoteFunctionCall getRoleMember(byte[] role, BigInteger index) { final Function function = new Function(FUNC_GETROLEMEMBER, - Arrays.asList(new Bytes32(role), - new Uint256(index)), - List.of(new TypeReference
() { - })); + Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(role), + new org.web3j.abi.datatypes.generated.Uint256(index)), + Arrays.>asList(new TypeReference
() {})); return executeRemoteCallSingleValueReturn(function, String.class); } public RemoteFunctionCall getRoleMemberCount(byte[] role) { final Function function = new Function(FUNC_GETROLEMEMBERCOUNT, - List.of(new Bytes32(role)), - List.of(new TypeReference() { - })); + Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(role)), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public RemoteFunctionCall grantRole(byte[] role, String account) { final Function function = new Function( FUNC_GRANTROLE, - Arrays.asList(new Bytes32(role), - new Address(160, account)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(role), + new org.web3j.abi.datatypes.Address(160, account)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall hasRole(byte[] role, String account) { final Function function = new Function(FUNC_HASROLE, - Arrays.asList(new Bytes32(role), - new Address(160, account)), - List.of(new TypeReference() { - })); + Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(role), + new org.web3j.abi.datatypes.Address(160, account)), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, Boolean.class); } - public RemoteFunctionCall increaseVerifiedBalanceFor(String paymentAccount, BigInteger increase) { + public RemoteFunctionCall increaseVerifiedBalanceFor(String paymentAccount, + BigInteger increase) { final Function function = new Function( FUNC_INCREASEVERIFIEDBALANCEFOR, - Arrays.asList(new Address(160, paymentAccount), - new Uint256(increase)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentAccount), + new org.web3j.abi.datatypes.generated.Uint256(increase)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } + public RemoteFunctionCall isCardConfirmer(String account) { + final Function function = new Function(FUNC_ISCARDCONFIRMER, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, account)), + Arrays.>asList(new TypeReference() {})); + return executeRemoteCallSingleValueReturn(function, Boolean.class); + } + public RemoteFunctionCall pause() { final Function function = new Function( FUNC_PAUSE, - List.of(), - Collections.emptyList()); + Arrays.asList(), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall paused() { final Function function = new Function(FUNC_PAUSED, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, Boolean.class); } public RemoteFunctionCall paymentAccountFactory() { final Function function = new Function(FUNC_PAYMENTACCOUNTFACTORY, - List.of(), - List.of(new TypeReference
() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); return executeRemoteCallSingleValueReturn(function, String.class); } public RemoteFunctionCall paymentReceiver() { final Function function = new Function(FUNC_PAYMENTRECEIVER, - List.of(), - List.of(new TypeReference
() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); return executeRemoteCallSingleValueReturn(function, String.class); } public RemoteFunctionCall paymentToken() { final Function function = new Function(FUNC_PAYMENTTOKEN, - List.of(), - List.of(new TypeReference
() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); return executeRemoteCallSingleValueReturn(function, String.class); } - public RemoteFunctionCall processAuthorization(String card, BigInteger transactionId, BigInteger amount, byte[] otp, BigInteger otpCounter, Boolean forced) { - final Function function = new Function( - FUNC_PROCESSAUTHORIZATION, - Arrays.asList(new Address(160, card), - new Uint256(transactionId), - new Uint256(amount), - new org.web3j.abi.datatypes.generated.Bytes16(otp), - new org.web3j.abi.datatypes.generated.Uint16(otpCounter), - new Bool(forced)), - Collections.emptyList()); - return executeRemoteCallTransaction(function); - } - - public RemoteFunctionCall processAuthorizationChange(String card, BigInteger transactionId, BigInteger amount) { + public RemoteFunctionCall processAuthorizationChange(String paymentAccount, + String card, BigInteger transactionId, BigInteger amount) { final Function function = new Function( FUNC_PROCESSAUTHORIZATIONCHANGE, - Arrays.asList(new Address(160, card), - new Uint256(transactionId), - new Uint256(amount)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentAccount), + new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(transactionId), + new org.web3j.abi.datatypes.generated.Uint256(amount)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall processAuthorizationNoOtp(String card, BigInteger transactionId, BigInteger amount, Boolean forced) { + public RemoteFunctionCall processDebt(String paymentAccount, String card, + BigInteger amount) { final Function function = new Function( - FUNC_PROCESSAUTHORIZATIONNOOTP, - Arrays.asList(new Address(160, card), - new Uint256(transactionId), - new Uint256(amount), - new Bool(forced)), - Collections.emptyList()); + FUNC_PROCESSDEBT, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentAccount), + new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(amount)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall processPendingRefund(String card, BigInteger transactionId) { + public RemoteFunctionCall processNoConfirmationAuthorization( + String paymentAccount, String card, BigInteger transactionId, BigInteger amount, + Boolean forced) { final Function function = new Function( - FUNC_PROCESSPENDINGREFUND, - Arrays.asList(new Address(160, card), - new Uint256(transactionId)), - Collections.emptyList()); + FUNC_PROCESSNOCONFIRMATIONAUTHORIZATION, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentAccount), + new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(transactionId), + new org.web3j.abi.datatypes.generated.Uint256(amount), + new org.web3j.abi.datatypes.Bool(forced)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall processRefund(String card, BigInteger transactionId, BigInteger refundAmount) { + public RemoteFunctionCall processOtpAuthorization(String paymentAccount, + String card, BigInteger transactionId, BigInteger amount, byte[] otp, + BigInteger otpCounter, Boolean forced) { + final Function function = new Function( + FUNC_PROCESSOTPAUTHORIZATION, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentAccount), + new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(transactionId), + new org.web3j.abi.datatypes.generated.Uint256(amount), + new org.web3j.abi.datatypes.generated.Bytes16(otp), + new org.web3j.abi.datatypes.generated.Uint16(otpCounter), + new org.web3j.abi.datatypes.Bool(forced)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + public RemoteFunctionCall processRefund(String paymentAccount, String card, + BigInteger transactionId, BigInteger refundAmount) { final Function function = new Function( FUNC_PROCESSREFUND, - Arrays.asList(new Address(160, card), - new Uint256(transactionId), - new Uint256(refundAmount)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentAccount), + new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(transactionId), + new org.web3j.abi.datatypes.generated.Uint256(refundAmount)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall processRefundCallback() { final Function function = new Function( FUNC_PROCESSREFUNDCALLBACK, - List.of(), - Collections.emptyList()); + Arrays.asList(), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall processSettlement(String card, BigInteger transactionId, BigInteger amount) { + public RemoteFunctionCall processSettlement(String paymentAccount, + String card, BigInteger transactionId, BigInteger amount) { final Function function = new Function( FUNC_PROCESSSETTLEMENT, - Arrays.asList(new Address(160, card), - new Uint256(transactionId), - new Uint256(amount)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentAccount), + new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(transactionId), + new org.web3j.abi.datatypes.generated.Uint256(amount)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + public RemoteFunctionCall processSignatureAuthorization( + String paymentAccount, String card, BigInteger transactionId, BigInteger amount, + byte[] signature, Boolean forced) { + final Function function = new Function( + FUNC_PROCESSSIGNATUREAUTHORIZATION, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentAccount), + new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(transactionId), + new org.web3j.abi.datatypes.generated.Uint256(amount), + new org.web3j.abi.datatypes.DynamicBytes(signature), + new org.web3j.abi.datatypes.Bool(forced)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + public RemoteFunctionCall processUnsettledTransaction(String paymentAccount, + String card, BigInteger transactionId) { + final Function function = new Function( + FUNC_PROCESSUNSETTLEDTRANSACTION, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentAccount), + new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(transactionId)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + public RemoteFunctionCall processWithdrawal(String paymentAccount) { + final Function function = new Function( + FUNC_PROCESSWITHDRAWAL, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentAccount)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall refundAccount() { final Function function = new Function(FUNC_REFUNDACCOUNT, - List.of(), - List.of(new TypeReference
() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); return executeRemoteCallSingleValueReturn(function, String.class); } - public RemoteFunctionCall renounceRole(byte[] role, String callerConfirmation) { + public RemoteFunctionCall renounceRole(byte[] role, + String callerConfirmation) { final Function function = new Function( FUNC_RENOUNCEROLE, - Arrays.asList(new Bytes32(role), - new Address(160, callerConfirmation)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(role), + new org.web3j.abi.datatypes.Address(160, callerConfirmation)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall revokeRole(byte[] role, String account) { final Function function = new Function( FUNC_REVOKEROLE, - Arrays.asList(new Bytes32(role), - new Address(160, account)), - Collections.emptyList()); - return executeRemoteCallTransaction(function); - } - - public RemoteFunctionCall savePendingRefund(String card, BigInteger transactionId, BigInteger amount) { - final Function function = new Function( - FUNC_SAVEPENDINGREFUND, - Arrays.asList(new Address(160, card), - new Uint256(transactionId), - new Uint256(amount)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(role), + new org.web3j.abi.datatypes.Address(160, account)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall securityDelay() { final Function function = new Function(FUNC_SECURITYDELAY, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } - public RemoteFunctionCall setFixedFee(BigInteger fixedFee_) { + public RemoteFunctionCall setAuthLimitMarginFor(String paymentAccount, + BigInteger authLimitMargin) { final Function function = new Function( - FUNC_SETFIXEDFEE, - List.of(new Uint256(fixedFee_)), - Collections.emptyList()); - return executeRemoteCallTransaction(function); - } - - public RemoteFunctionCall setPaymentAccount(String card, String paymentAccount) { - final Function function = new Function( - FUNC_SETPAYMENTACCOUNT, - Arrays.asList(new Address(160, card), - new Address(160, paymentAccount)), - Collections.emptyList()); + FUNC_SETAUTHLIMITMARGINFOR, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentAccount), + new org.web3j.abi.datatypes.generated.Uint256(authLimitMargin)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall setPaymentReceiver(String paymentReceiver_) { final Function function = new Function( FUNC_SETPAYMENTRECEIVER, - List.of(new Address(160, paymentReceiver_)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentReceiver_)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall setRefundAccount(String refundAccount_) { final Function function = new Function( FUNC_SETREFUNDACCOUNT, - List.of(new Address(160, refundAccount_)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, refundAccount_)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall setSecurityDelay(BigInteger securityDelay_) { final Function function = new Function( FUNC_SETSECURITYDELAY, - List.of(new Uint256(securityDelay_)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.generated.Uint256(securityDelay_)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall setSettlementPeriod(BigInteger settlementPeriod_) { - final Function function = new Function( - FUNC_SETSETTLEMENTPERIOD, - List.of(new Uint256(settlementPeriod_)), - Collections.emptyList()); - return executeRemoteCallTransaction(function); - } - - public RemoteFunctionCall setVerifiedBalanceFor(String paymentAccount, BigInteger verifiedBalance) { + public RemoteFunctionCall setVerifiedBalanceFor(String paymentAccount, + BigInteger verifiedBalance) { final Function function = new Function( FUNC_SETVERIFIEDBALANCEFOR, - Arrays.asList(new Address(160, paymentAccount), - new Uint256(verifiedBalance)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentAccount), + new org.web3j.abi.datatypes.generated.Uint256(verifiedBalance)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall settlementPeriod() { - final Function function = new Function(FUNC_SETTLEMENTPERIOD, - List.of(), - List.of(new TypeReference() { - })); - return executeRemoteCallSingleValueReturn(function, BigInteger.class); - } - public RemoteFunctionCall supportsInterface(byte[] interfaceId) { final Function function = new Function(FUNC_SUPPORTSINTERFACE, - List.of(new Bytes4(interfaceId)), - List.of(new TypeReference() { - })); + Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes4(interfaceId)), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, Boolean.class); } public RemoteFunctionCall unpause() { final Function function = new Function( FUNC_UNPAUSE, - List.of(), - Collections.emptyList()); + Arrays.asList(), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall writeOffDebt(String card, BigInteger amount) { + public RemoteFunctionCall writeOffDebt(String paymentAccount, String card, + BigInteger amount) { final Function function = new Function( FUNC_WRITEOFFDEBT, - Arrays.asList(new Address(160, card), - new Uint256(amount)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentAccount), + new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(amount)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } + @Deprecated + public static TangemBridgeProcessor load(String contractAddress, Web3j web3j, + Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + return new TangemBridgeProcessor(contractAddress, web3j, credentials, gasPrice, gasLimit); + } + + @Deprecated + public static TangemBridgeProcessor load(String contractAddress, Web3j web3j, + TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + return new TangemBridgeProcessor(contractAddress, web3j, transactionManager, gasPrice, gasLimit); + } + + public static TangemBridgeProcessor load(String contractAddress, Web3j web3j, + Credentials credentials, ContractGasProvider contractGasProvider) { + return new TangemBridgeProcessor(contractAddress, web3j, credentials, contractGasProvider); + } + + public static TangemBridgeProcessor load(String contractAddress, Web3j web3j, + TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + return new TangemBridgeProcessor(contractAddress, web3j, transactionManager, contractGasProvider); + } + + public static RemoteCall deploy(Web3j web3j, Credentials credentials, + ContractGasProvider contractGasProvider, String paymentReceiver_, String refundAccount_, + String paymentAccountFactory_, String paymentToken_, BigInteger securityDelay_) { + String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentReceiver_), + new org.web3j.abi.datatypes.Address(160, refundAccount_), + new org.web3j.abi.datatypes.Address(160, paymentAccountFactory_), + new org.web3j.abi.datatypes.Address(160, paymentToken_), + new org.web3j.abi.datatypes.generated.Uint256(securityDelay_))); + return deployRemoteCall(TangemBridgeProcessor.class, web3j, credentials, contractGasProvider, getDeploymentBinary(), encodedConstructor); + } + + public static RemoteCall deploy(Web3j web3j, + TransactionManager transactionManager, ContractGasProvider contractGasProvider, + String paymentReceiver_, String refundAccount_, String paymentAccountFactory_, + String paymentToken_, BigInteger securityDelay_) { + String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentReceiver_), + new org.web3j.abi.datatypes.Address(160, refundAccount_), + new org.web3j.abi.datatypes.Address(160, paymentAccountFactory_), + new org.web3j.abi.datatypes.Address(160, paymentToken_), + new org.web3j.abi.datatypes.generated.Uint256(securityDelay_))); + return deployRemoteCall(TangemBridgeProcessor.class, web3j, transactionManager, contractGasProvider, getDeploymentBinary(), encodedConstructor); + } + + @Deprecated + public static RemoteCall deploy(Web3j web3j, Credentials credentials, + BigInteger gasPrice, BigInteger gasLimit, String paymentReceiver_, + String refundAccount_, String paymentAccountFactory_, String paymentToken_, + BigInteger securityDelay_) { + String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentReceiver_), + new org.web3j.abi.datatypes.Address(160, refundAccount_), + new org.web3j.abi.datatypes.Address(160, paymentAccountFactory_), + new org.web3j.abi.datatypes.Address(160, paymentToken_), + new org.web3j.abi.datatypes.generated.Uint256(securityDelay_))); + return deployRemoteCall(TangemBridgeProcessor.class, web3j, credentials, gasPrice, gasLimit, getDeploymentBinary(), encodedConstructor); + } + + @Deprecated + public static RemoteCall deploy(Web3j web3j, + TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit, + String paymentReceiver_, String refundAccount_, String paymentAccountFactory_, + String paymentToken_, BigInteger securityDelay_) { + String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.Address(160, paymentReceiver_), + new org.web3j.abi.datatypes.Address(160, refundAccount_), + new org.web3j.abi.datatypes.Address(160, paymentAccountFactory_), + new org.web3j.abi.datatypes.Address(160, paymentToken_), + new org.web3j.abi.datatypes.generated.Uint256(securityDelay_))); + return deployRemoteCall(TangemBridgeProcessor.class, web3j, transactionManager, gasPrice, gasLimit, getDeploymentBinary(), encodedConstructor); + } + + public static void linkLibraries(List references) { + librariesLinkedBinary = linkBinaryWithReferences(BINARY, references); + } + + private static String getDeploymentBinary() { + if (librariesLinkedBinary != null) { + return librariesLinkedBinary; + } else { + return BINARY; + } + } + + public static class OtpState extends StaticStruct { + public byte[] otp; + + public BigInteger counter; + + public OtpState(byte[] otp, BigInteger counter) { + super(new org.web3j.abi.datatypes.generated.Bytes16(otp), + new org.web3j.abi.datatypes.generated.Uint16(counter)); + this.otp = otp; + this.counter = counter; + } + + public OtpState(Bytes16 otp, Uint16 counter) { + super(otp, counter); + this.otp = otp.getValue(); + this.counter = counter.getValue(); + } + } + + public static class LimitsParams extends StaticStruct { + public BigInteger singleTransactionLimit; + + public BigInteger spendLimit; + + public BigInteger noConfirmationSpendLimit; + + public BigInteger spendLimitsPeriod; + + public LimitsParams(BigInteger singleTransactionLimit, BigInteger spendLimit, + BigInteger noConfirmationSpendLimit, BigInteger spendLimitsPeriod) { + super(new org.web3j.abi.datatypes.generated.Uint256(singleTransactionLimit), + new org.web3j.abi.datatypes.generated.Uint256(spendLimit), + new org.web3j.abi.datatypes.generated.Uint256(noConfirmationSpendLimit), + new org.web3j.abi.datatypes.generated.Uint256(spendLimitsPeriod)); + this.singleTransactionLimit = singleTransactionLimit; + this.spendLimit = spendLimit; + this.noConfirmationSpendLimit = noConfirmationSpendLimit; + this.spendLimitsPeriod = spendLimitsPeriod; + } + + public LimitsParams(Uint256 singleTransactionLimit, Uint256 spendLimit, + Uint256 noConfirmationSpendLimit, Uint256 spendLimitsPeriod) { + super(singleTransactionLimit, spendLimit, noConfirmationSpendLimit, spendLimitsPeriod); + this.singleTransactionLimit = singleTransactionLimit.getValue(); + this.spendLimit = spendLimit.getValue(); + this.noConfirmationSpendLimit = noConfirmationSpendLimit.getValue(); + this.spendLimitsPeriod = spendLimitsPeriod.getValue(); + } + } + + public static class CardParams extends StaticStruct { + public Boolean isOwner; + + public OtpState otpState; + + public LimitsParams limitsParams; + + public CardParams(Boolean isOwner, OtpState otpState, LimitsParams limitsParams) { + super(new org.web3j.abi.datatypes.Bool(isOwner), + otpState, + limitsParams); + this.isOwner = isOwner; + this.otpState = otpState; + this.limitsParams = limitsParams; + } + + public CardParams(Bool isOwner, OtpState otpState, LimitsParams limitsParams) { + super(isOwner, otpState, limitsParams); + this.isOwner = isOwner.getValue(); + this.otpState = otpState; + this.limitsParams = limitsParams; + } + } + + public static class AuthLimitMarginSetForEventResponse extends BaseEventResponse { + public String paymentAccount; + + public BigInteger authLimitMargin; + } + public static class AuthorizationChangeProcessedEventResponse extends BaseEventResponse { + public String paymentAccount; + public String card; public BigInteger transactionId; public BigInteger amount; - - public BigInteger fee; } public static class AuthorizationProcessedEventResponse extends BaseEventResponse { + public String paymentAccount; + public String card; public BigInteger transactionId; public BigInteger amount; - - public BigInteger fee; } - public static class DebtWriteOffProcessedEventResponse extends BaseEventResponse { + public static class DebtProcessedEventResponse extends BaseEventResponse { + public String paymentAccount; + public String card; public BigInteger amount; } - public static class FixedFeeSetEventResponse extends BaseEventResponse { - public BigInteger fixedFee; + public static class DebtWriteOffProcessedEventResponse extends BaseEventResponse { + public String paymentAccount; + + public String card; + + public BigInteger amount; } public static class PausedEventResponse extends BaseEventResponse { public String account; } - public static class PaymentAccountSetEventResponse extends BaseEventResponse { - public String card; + public static class PaymentAccountDeployedEventResponse extends BaseEventResponse { + public String owner; + + public String cardAddress; public String paymentAccount; } @@ -1400,19 +1621,13 @@ class TangemBridgeProcessor extends Contract { public String paymentReceiver; } - public static class PendingRefundProcessedEventResponse extends BaseEventResponse { - public String card; - - public BigInteger transactionId; - - public BigInteger amount; - } - public static class RefundAccountSetEventResponse extends BaseEventResponse { public String refundAccount; } public static class RefundProcessedEventResponse extends BaseEventResponse { + public String paymentAccount; + public String card; public BigInteger transactionId; @@ -1444,14 +1659,6 @@ class TangemBridgeProcessor extends Contract { public String sender; } - public static class SaveRefundProcessedEventResponse extends BaseEventResponse { - public String card; - - public BigInteger transactionId; - - public BigInteger amount; - } - public static class SecurityDelaySetEventResponse extends BaseEventResponse { public BigInteger securityDelay; } @@ -1461,19 +1668,27 @@ class TangemBridgeProcessor extends Contract { } public static class SettlementProcessedEventResponse extends BaseEventResponse { + public String paymentAccount; + public String card; public BigInteger transactionId; public BigInteger amount; - - public BigInteger fee; } public static class UnpausedEventResponse extends BaseEventResponse { public String account; } + public static class UnsettledTransactionProcessedEventResponse extends BaseEventResponse { + public String paymentAccount; + + public String card; + + public BigInteger transactionId; + } + public static class VerifiedBalanceIncreasedForEventResponse extends BaseEventResponse { public String paymentAccount; @@ -1485,4 +1700,8 @@ class TangemBridgeProcessor extends Contract { public BigInteger verifiedBalance; } -} + + public static class WithdrawalProcessedEventResponse extends BaseEventResponse { + public String paymentAccount; + } +} \ No newline at end of file diff --git a/libs/visa/src/main/java/com/tangem/lib/visa/TangemPaymentAccount.java b/libs/visa/src/main/java/com/tangem/lib/visa/TangemPaymentAccount.java index 834d85f3c2..df19c6cee9 100644 --- a/libs/visa/src/main/java/com/tangem/lib/visa/TangemPaymentAccount.java +++ b/libs/visa/src/main/java/com/tangem/lib/visa/TangemPaymentAccount.java @@ -1,10 +1,30 @@ package com.tangem.lib.visa; +import io.reactivex.Flowable; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; import org.web3j.abi.EventEncoder; import org.web3j.abi.FunctionEncoder; import org.web3j.abi.TypeReference; -import org.web3j.abi.datatypes.*; -import org.web3j.abi.datatypes.generated.*; +import org.web3j.abi.datatypes.Address; +import org.web3j.abi.datatypes.Bool; +import org.web3j.abi.datatypes.DynamicArray; +import org.web3j.abi.datatypes.DynamicBytes; +import org.web3j.abi.datatypes.Event; +import org.web3j.abi.datatypes.Function; +import org.web3j.abi.datatypes.StaticStruct; +import org.web3j.abi.datatypes.Type; +import org.web3j.abi.datatypes.Utf8String; +import org.web3j.abi.datatypes.generated.Bytes1; +import org.web3j.abi.datatypes.generated.Bytes16; +import org.web3j.abi.datatypes.generated.Bytes32; +import org.web3j.abi.datatypes.generated.Uint16; +import org.web3j.abi.datatypes.generated.Uint256; +import org.web3j.abi.datatypes.generated.Uint64; import org.web3j.crypto.Credentials; import org.web3j.protocol.Web3j; import org.web3j.protocol.core.DefaultBlockParameter; @@ -14,36 +34,36 @@ import org.web3j.protocol.core.methods.request.EthFilter; import org.web3j.protocol.core.methods.response.BaseEventResponse; import org.web3j.protocol.core.methods.response.Log; import org.web3j.protocol.core.methods.response.TransactionReceipt; -import org.web3j.tuples.generated.Tuple3; +import org.web3j.tuples.generated.Tuple4; +import org.web3j.tuples.generated.Tuple5; import org.web3j.tuples.generated.Tuple7; import org.web3j.tx.Contract; import org.web3j.tx.TransactionManager; import org.web3j.tx.gas.ContractGasProvider; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.Callable; - -import io.reactivex.Flowable; - /** *

Auto generated code. *

Do not modify! *

Please use the web3j command line tools, - * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the - * codegen module to update. + * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the + * codegen module to update. * - *

Generated with web3j version 1.5.2. + *

Generated with web3j version 1.6.1. */ @SuppressWarnings("rawtypes") -class TangemPaymentAccount extends Contract { - public static final String BINARY = "60c06040523060a0523480156200001557600080fd5b5060405162005aa938038062005aa983398101604081905262000038916200010a565b6001600160a01b0381166080526200004f62000056565b506200013c565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff1615620000a75760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b0390811614620001075780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b6000602082840312156200011d57600080fd5b81516001600160a01b03811681146200013557600080fd5b9392505050565b60805160a05161592b6200017e600039600081816132fe0152818161332701526135880152600081816104d301528181610578015261290d015261592b6000f3fe6080604052600436106102c85760003560e01c806386489ba911610175578063c470d703116100dc578063df7727b411610095578063e3dbffd51161006f578063e3dbffd514610a40578063e4d7ddb914610a60578063e6e268f414610a80578063f89db45714610a9557600080fd5b8063df7727b4146102f5578063e1a8eafd146109b2578063e37b8154146109d257600080fd5b8063c470d703146108da578063c81656c81461090e578063ce1b1d431461093b578063d47ae89c1461095b578063dbed8faa14610970578063dcab7e501461099057600080fd5b8063a789457d1161012e578063a789457d1461077b578063ad3cb1cc14610827578063b4d02d0d14610865578063b9603bdf14610885578063be69191d146108a5578063c45a0155146108ba57600080fd5b806386489ba9146106c657806386f15d09146106e65780638bbe11af146106fb5780638c3b2a9b1461071b5780638da5cb5b1461073b578063a075b7c71461075b57600080fd5b80633c1a5012116102345780636b2a3830116101ed5780637da0a877116101c75780637da0a87714610569578063806679e41461059c57806384b0196e146105bc578063860aefcf146105e457600080fd5b80636b2a3830146105135780636b4943a7146105335780637b1039991461054957600080fd5b80633c1a501214610439578063456575e51461045957806346236eb9146104795780634f1ef2861461048e57806352d1902d146104a1578063572b6c05146104b657600080fd5b806322611280116102865780632261128014610377578063229865d11461038c5780633013ce29146103ac578063309433ba146103e457806334284dfb1461040457806335ba9af81461042457600080fd5b806274f356146102cd57806301e948ff146102f55780630381b4dd1461030a5780630f1071be1461032c57806319cdeb6f146103415780631f852f4b14610357575b600080fd5b3480156102d957600080fd5b506102e2610ab5565b6040519081526020015b60405180910390f35b34801561030157600080fd5b506102e2610acf565b34801561031657600080fd5b5061032a610325366004614b0d565b610ae0565b005b34801561033857600080fd5b506102e2610dde565b34801561034d57600080fd5b506102e260065481565b34801561036357600080fd5b5061032a610372366004614b8d565b610e63565b34801561038357600080fd5b5061032a610fa7565b34801561039857600080fd5b5061032a6103a7366004614be2565b611034565b3480156103b857600080fd5b506000546103cc906001600160a01b031681565b6040516001600160a01b0390911681526020016102ec565b3480156103f057600080fd5b5061032a6103ff366004614c2a565b6110cb565b34801561041057600080fd5b5061032a61041f366004614cb0565b611337565b34801561043057600080fd5b506102e26113fd565b34801561044557600080fd5b5061032a610454366004614d0b565b611490565b34801561046557600080fd5b5061032a610474366004614b0d565b61151c565b34801561048557600080fd5b50601c546102e2565b61032a61049c366004614d3e565b6115bc565b3480156104ad57600080fd5b506102e26115db565b3480156104c257600080fd5b506105036104d1366004614d0b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b60405190151581526020016102ec565b34801561051f57600080fd5b5061032a61052e366004614be2565b6115f8565b34801561053f57600080fd5b506102e260075481565b34801561055557600080fd5b506002546103cc906001600160a01b031681565b34801561057557600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006103cc565b3480156105a857600080fd5b5061032a6105b7366004614e02565b611749565b3480156105c857600080fd5b506105d16117ed565b6040516102ec9796959493929190614e8b565b3480156105f057600080fd5b506040805160a08082018352600d54825282518084018452600e548152600f546020828101919091528084019190915283518085018552601054815260115481830152838501528351808201855260125481526060808501919091526013546080808601919091528551938401865260145484528551808701875260155481526016548185015284840152855180870187526017548152601854818501528487015285519283019095526019548252820152601a5492810192909252601b546106b7929083565b6040516102ec93929190614f6c565b3480156106d257600080fd5b5061032a6106e1366004614f97565b611899565b3480156106f257600080fd5b50610503611a66565b34801561070757600080fd5b5061032a610716366004614be2565b611a90565b34801561072757600080fd5b5061032a610736366004614ff0565b611ba9565b34801561074757600080fd5b506004546103cc906001600160a01b031681565b34801561076757600080fd5b5061032a610776366004615023565b611cf8565b34801561078757600080fd5b506040805180820182526008546001600160a01b039081168252825180840184526009546001600160801b0319608082811b8216845261ffff600160801b9384900481166020868101919091528088019590955287518089018952600a5490961686528751808901909852600b549182901b9092168752919091041684820152810192909252600c54610818929083565b6040516102ec93929190615086565b34801561083357600080fd5b50610858604051806040016040528060058152602001640352e302e360dc1b81525081565b6040516102ec91906150af565b34801561087157600080fd5b5061032a610880366004614be2565b611de0565b34801561089157600080fd5b5061032a6108a0366004614be2565b611ee3565b3480156108b157600080fd5b5061050361201c565b3480156108c657600080fd5b506001546103cc906001600160a01b031681565b3480156108e657600080fd5b507f3fc394ec90f88dd7e18c46ffeef55f1b6719a2027f4ae9fbc4ab118271891200546102e2565b34801561091a57600080fd5b506102e2610929366004614be2565b6000908152601d602052604090205490565b34801561094757600080fd5b506003546103cc906001600160a01b031681565b34801561096757600080fd5b506102e2612044565b34801561097c57600080fd5b5061032a61098b366004614be2565b6120c8565b34801561099c57600080fd5b506000805160206154fc833981519152546102e2565b3480156109be57600080fd5b5061032a6109cd366004614d0b565b612127565b3480156109de57600080fd5b50610a1b6109ed366004614be2565b600560205260009081526040902080546001909101546001600160801b03811690600160801b900460ff1683565b604080519384526001600160801b0390921660208401521515908201526060016102ec565b348015610a4c57600080fd5b5061032a610a5b366004614be2565b6122c6565b348015610a6c57600080fd5b5061032a610a7b366004614b0d565b6124ac565b348015610a8c57600080fd5b506102e261265c565b348015610aa157600080fd5b5061032a610ab0366004614be2565b612673565b6000806000805160206154dc8339815191525b5492915050565b6000610adb600061284d565b905090565b6003546001600160a01b0316610af4612909565b6001600160a01b0316146040518060600160405280603381526020016153166033913990610b3e5760405162461bcd60e51b8152600401610b3591906150af565b60405180910390fd5b50610b488161295b565b60008281526005602052604081205490818311610b7b575081808203828214610b7557610b75858261299b565b50610bff565b50806000610b89600d6129e0565b8054909150600081851015610bbf57610bae858303610ba98560006129ff565b612a6b565b9050610bbc81610ba9610acf565b90505b8015610be7576000610bd382878903612a6b565b948501949050610be584826000612a83565b505b838603868514610bfa57610bfa81612aaa565b505050505b8160075410156040518060600160405280602981526020016158226029913990610c3c5760405162461bcd60e51b8152600401610b3591906150af565b50600780548390039055600084815260056020908152604080832092835560019290920180546001600160881b0319169055600354825163659bf9d960e11b81529251610cdf936001600160a01b039092169263cb37f3b292600480820193918290030181865afa158015610cb5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd991906150c2565b82612b0b565b604080518481526020810183905285917fa06caae8c696e5deb33f685024044b74125cb932e11521aef47de748321657c4910160405180910390a26000546040516370a0823160e01b81523060048201527f273f30c859762d267fd40559825ed2fa0f467908c92843dfd0184b9d577dc082916001600160a01b0316906370a0823190602401602060405180830381865afa158015610d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da691906150df565b600754610db1610ab5565b601c546040805194855260208501939093529183015260608201526080015b60405180910390a150505050565b6000610adb600360009054906101000a90046001600160a01b03166001600160a01b0316630f1071be6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5a91906150df565b6283d600612a6b565b6004546001600160a01b0316610e77612909565b6001600160a01b03161480610eae5750610e916008612c1b565b546001600160a01b0316610ea3612909565b6001600160a01b0316145b6040518060600160405280602f815260200161589e602f913990610ee55760405162461bcd60e51b8152600401610b3591906150af565b50610ef1838383612c36565b600480546001600160a01b038581166001600160a01b0319831681178455600254604051635cd2673760e01b815293831694840185905260248401919091521690635cd2673790604401600060405180830381600087803b158015610f5557600080fd5b505af1158015610f69573d6000803e3d6000fd5b50506040516001600160a01b03871681527f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe292506020019050610dd0565b6004546001600160a01b0316610fbb612909565b6001600160a01b03161480610ff25750610fd56008612c1b565b546001600160a01b0316610fe7612909565b6001600160a01b0316145b6040518060600160405280602f815260200161589e602f9139906110295760405162461bcd60e51b8152600401610b3591906150af565b50611032612d2a565b565b6004546001600160a01b0316611048612909565b6001600160a01b0316148061107f57506110626008612c1b565b546001600160a01b0316611074612909565b6001600160a01b0316145b6040518060600160405280602f815260200161589e602f9139906110b65760405162461bcd60e51b8152600401610b3591906150af565b506110c8816110c3612044565b612d7b565b50565b6004546001600160a01b03166110df612909565b6001600160a01b0316148061111657506110f96008612c1b565b546001600160a01b031661110b612909565b6001600160a01b0316145b6040518060600160405280602f815260200161589e602f91399061114d5760405162461bcd60e51b8152600401610b3591906150af565b50611159858383612c36565b600c541561122857600a546040805180820182526001600160a01b03888116825282518084019093526001600160801b03198816835261ffff87166020848101919091528201929092529116906111bb906111b2612044565b60089190612e79565b600254604051630747fc3760e41b81526001600160a01b03838116600483015288811660248301529091169063747fc37090604401600060405180830381600087803b15801561120a57600080fd5b505af115801561121e573d6000803e3d6000fd5b50505050506112db565b61127b6040518060400160405280876001600160a01b031681526020016040518060400160405280886001600160801b03191681526020018761ffff16815250815250600861302090919063ffffffff16565b60025460405163346b888d60e11b81526001600160a01b038781166004830152909116906368d7111a90602401600060405180830381600087803b1580156112c257600080fd5b505af11580156112d6573d6000803e3d6000fd5b505050505b604080516001600160a01b03871681526001600160801b03198616602082015261ffff85168183015290517fae81d31085749debb22edb9a09f263e50cf6047cfc57ec741c07ce62b1121b9a9181900360600190a15050505050565b6003546001600160a01b031661134b612909565b6001600160a01b031614604051806060016040528060338152602001615316603391399061138c5760405162461bcd60e51b8152600401610b3591906150af565b50600161139a8484846130c1565b6113a68686848461311d565b604080518681526001600160801b03198616602082015261ffff851681830152905187917faab1db26b8ce0ed14d67fd3d8eab92617f4caf4134148122ad6f2a4e20068df7919081900360600190a2505050505050565b600080546040516370a0823160e01b815230600482015282916001600160a01b0316906370a0823190602401602060405180830381865afa158015611446573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061146a91906150df565b905060075481101561147d57600061148a565b60075461148a908261510e565b91505090565b6004546001600160a01b03166114a4612909565b6001600160a01b031614806114db57506114be6008612c1b565b546001600160a01b03166114d0612909565b6001600160a01b0316145b6040518060600160405280602f815260200161589e602f9139906115125760405162461bcd60e51b8152600401610b3591906150af565b506110c881613186565b6003546001600160a01b0316611530612909565b6001600160a01b03161460405180606001604052806033815260200161531660339139906115715760405162461bcd60e51b8152600401610b3591906150af565b5061157e601c8383613274565b817fea92e836c1b642a333bb58b44d5f13c5a066c5b0f35b8d6da5032af605c9e031826040516115b091815260200190565b60405180910390a25050565b6115c46132f3565b6115cd82613398565b6115d782826134c0565b5050565b60006115e561357d565b506000805160206155cf83398151915290565b6003546001600160a01b031661160c612909565b6001600160a01b031614604051806060016040528060338152602001615316603391399061164d5760405162461bcd60e51b8152600401610b3591906150af565b5060008160065461165e9190615121565b6000546040516370a0823160e01b81523060048201529192506001600160a01b0316906370a0823190602401602060405180830381865afa1580156116a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116cb91906150df565b8111156040518060600160405280603781526020016153c760379139906117055760405162461bcd60e51b8152600401610b3591906150af565b50600681905560408051838152602081018390527fd6004694c2f543b69302481de26731f63c1d41062795b5366d8ca20fd3e3d6d391015b60405180910390a15050565b6003546001600160a01b031661175d612909565b6001600160a01b031614604051806060016040528060338152602001615316603391399061179e5760405162461bcd60e51b8152600401610b3591906150af565b5060006117ad8484848461311d565b837f5e1266400272ee17509f7d7edb190c0fa83572f90677ee6a3bbfac22bf1f679d846040516117df91815260200190565b60405180910390a250505050565b60006060808280808381600080516020615541833981519152805490915015801561181a57506001810154155b61185e5760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b6044820152606401610b35565b6118666135c6565b61186e613689565b60408051600080825260208201909252600f60f81b9c939b5091995046985030975095509350915050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156118df5750825b905060008267ffffffffffffffff1660011480156118fc5750303b155b90508115801561190a575080155b156119285760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561195257845460ff60401b1916600160401b1785555b61195a6136c8565b6119626136c8565b6119b16040518060400160405280601481526020017315185b99d95b54185e5b595b9d1058d8dbdd5b9d60621b815250604051806040016040528060018152602001603160f81b8152506136d0565b6119b96136c8565b6119c1612909565b600180546001600160a01b03199081166001600160a01b03938416179091556004805482168e841617905560028054909116918c16919091179055611a13611a0b8a8a8a8a6136e2565b600d90613780565b8315611a5957845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050505050565b6000805160206154fc8339815191525460009060008051602061549c83398151915290151561148a565b6000818152600560205260409020600181015490546001600160801b0390911690611ab9610dde565b611ac39083615121565b42116040518060600160405280602b8152602001615349602b913990611afc5760405162461bcd60e51b8152600401610b3591906150af565b508060075410156040518060600160405280602981526020016158226029913990611b3a5760405162461bcd60e51b8152600401610b3591906150af565b5060078054829003905560008381526005602052604080822091825560019190910180546001600160881b03191690555183907f056bed1bad5d90aa1df671c8d28b1bbb82ff67fd545f804e63cd261140b11f7b90611b9c9084815260200190565b60405180910390a2505050565b6004546001600160a01b0316611bbd612909565b6001600160a01b03161480611bf45750611bd76008612c1b565b546001600160a01b0316611be9612909565b6001600160a01b0316145b6040518060600160405280602f815260200161589e602f913990611c2b5760405162461bcd60e51b8152600401610b3591906150af565b50600c5415156040518060600160405280603181526020016157c66031913990611c685760405162461bcd60e51b8152600401610b3591906150af565b50604080518082018252600a546001600160a01b0316815281518083019092526001600160801b03198416825261ffff8316602083810191909152810191909152611cb5906111b2612044565b604080516001600160801b03198416815261ffff831660208201527fc50d2cc66f62a75104edeabfbcedb2a37ebd1cb8ce0b873ec3afa504e8bb1480910161173d565b6004546001600160a01b0316611d0c612909565b6001600160a01b03161480611d435750611d266008612c1b565b546001600160a01b0316611d38612909565b6001600160a01b0316145b6040518060600160405280602f815260200161589e602f913990611d7a5760405162461bcd60e51b8152600401610b3591906150af565b50611d9b611d8a858585856136e2565b611d92612044565b600d919061380c565b6040805185815260208101859052908101839052606081018290527ffc3ccf3ca5a38fad8786ed39386de19cb574b06205422992c583e4753aa6268f90608001610dd0565b6004546001600160a01b0316611df4612909565b6001600160a01b03161480611e2b5750611e0e6008612c1b565b546001600160a01b0316611e20612909565b6001600160a01b0316145b6040518060600160405280602f815260200161589e602f913990611e625760405162461bcd60e51b8152600401610b3591906150af565b506110c881600360009054906101000a90046001600160a01b03166001600160a01b031663cb37f3b26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611eba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ede91906150c2565b6138fa565b6003546001600160a01b0316611ef7612909565b6001600160a01b0316146040518060600160405280603381526020016153166033913990611f385760405162461bcd60e51b8152600401610b3591906150af565b506000546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015611f81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa591906150df565b8111156040518060600160405280603781526020016153c76037913990611fdf5760405162461bcd60e51b8152600401610b3591906150af565b5060068190556040518181527f321b800465e47508430424e6c089344256e17f9a5b0b43c751dffbdfd3930263906020015b60405180910390a150565b600060008051602061549c83398151915261148a6000805160206154fc833981519152613a4c565b6000610adb600360009054906101000a90046001600160a01b03166001600160a01b031663d47ae89c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561209c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c091906150df565b610e10612a6b565b6003546001600160a01b03166120dc612909565b6001600160a01b031614604051806060016040528060338152602001615316603391399061211d5760405162461bcd60e51b8152600401610b3591906150af565b506110c881613ab4565b6004546001600160a01b031661213b612909565b6001600160a01b0316148061217257506121556008612c1b565b546001600160a01b0316612167612909565b6001600160a01b0316145b6040518060600160405280602f815260200161589e602f9139906121a95760405162461bcd60e51b8152600401610b3591906150af565b50600354604080516060810190915260238082526001600160a01b0390921615916153fe6020830139906121f05760405162461bcd60e51b8152600401610b3591906150af565b50600380546001600160a01b0319166001600160a01b03831690811790915560408051633013ce2960e01b81529051633013ce29916004808201926020929091908290030181865afa15801561224a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061226e91906150c2565b600080546001600160a01b0319166001600160a01b0392831690811790915560408051928416835260208301919091527fb84a8bf26086331c9421c7ce6650da3b0ef748bd335c3f00ada56f481e4321939101612011565b6003546001600160a01b03166122da612909565b6001600160a01b031614604051806060016040528060338152602001615316603391399061231b5760405162461bcd60e51b8152600401610b3591906150af565b50600080546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015612365573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061238991906150df565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316632cc326416040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156123db57600080fd5b505af11580156123ef573d6000803e3d6000fd5b5050600080546040516370a0823160e01b81523060048201529193508492506001600160a01b0316906370a0823190602401602060405180830381865afa15801561243e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061246291906150df565b61246c919061510e565b905061247a601c8483613b81565b827f2c6a6ee02f179bb5f13a4b7fdc9ccd1dd37e524b48ff0957a931348cc9ad75c082604051611b9c91815260200190565b6003546001600160a01b03166124c0612909565b6001600160a01b03161460405180606001604052806033815260200161531660339139906125015760405162461bcd60e51b8152600401610b3591906150af565b506000600560008481526020019081526020016000206000015490506000811160405180606001604052806023815260200161547960239139906125585760405162461bcd60e51b8152600401610b3591906150af565b508082106040518060600160405280603b81526020016156d7603b9139906125935760405162461bcd60e51b8152600401610b3591906150af565b508181036125a1848261299b565b80600754101560405180606001604052806029815260200161582260299139906125de5760405162461bcd60e51b8152600401610b3591906150af565b50600780548290039055600083900361261857600084815260056020526040812090815560010180546001600160881b031916905561262a565b60008481526005602052604090208390555b837f8274e5392b3ab6bba68ee0567f4ede55e361239b8d0122fa5d3b5dc36497b91d846040516117df91815260200190565b60008060008051602061549c833981519152610ac8565b6003546001600160a01b0316612687612909565b6001600160a01b03161460405180606001604052806033815260200161531660339139906126c85760405162461bcd60e51b8152600401610b3591906150af565b50600080546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015612712573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061273691906150df565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316632cc326416040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561278857600080fd5b505af115801561279c573d6000803e3d6000fd5b5050600080546040516370a0823160e01b81523060048201529193508492506001600160a01b0316906370a0823190602401602060405180830381865afa1580156127eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061280f91906150df565b612819919061510e565b9050827f2c6a6ee02f179bb5f13a4b7fdc9ccd1dd37e524b48ff0957a931348cc9ad75c082604051611b9c91815260200190565b600080546040516370a0823160e01b815230600482015282916128c8916001600160a01b03909116906370a0823190602401602060405180830381865afa15801561289c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c091906150df565b600654612a6b565b600754909150836128e8576128db61265c565b6128e59082615121565b90505b808210156128f7576000612901565b612901818361510e565b949350505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633148015612944575060143610155b15612956575060131936013560601c90565b503390565b60408051808201909152601b81526000805160206154218339815191526020820152816115d75760405162461bcd60e51b8152600401610b3591906150af565b6000828152600560205260409020600101546001600160801b03811690600160801b900460ff166129da8383836129d2600d6129e0565b929190613c6c565b50505050565b60004282600e015411156129f457816129f9565b816007015b92915050565b6000612a0d83600501613a4c565b15612a3e578115612a23575060018201546129f9565b60018301546003840154612a379190612a6b565b90506129f9565b8115612a5057612a3783600101613c9a565b612a37612a5f84600101613c9a565b610ba985600301613c9a565b6000818310612a7a5781612a7c565b825b9392505050565b612a8c83613cbc565b612a968383613cee565b80612aa557612aa58383613cfb565b505050565b6000805160206154dc833981519152805482908290600090612acd908490615121565b909155505080546040805184815260208101929092527ff3a2c404b3362c4238317c3dad1020c2e9e984ba8df38a4a1ff18d57e92a242a910161173d565b600080546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015612b54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b7891906150df565b905080600654146040518060600160405280603381526020016157656033913990612bb65760405162461bcd60e51b8152600401610b3591906150af565b5060408051808201909152601f81526000805160206154bc833981519152602082015282821015612bfa5760405162461bcd60e51b8152600401610b3591906150af565b50600680548390039055600054612aa5906001600160a01b03168484613d08565b60004282600401541115612c2f57816129f9565b5060020190565b60408051602081019091527f3fc394ec90f88dd7e18c46ffeef55f1b6719a2027f4ae9fbc4ab1182718912008054825290600090612c7c90612c7790613d5a565b613db2565b90506000612cc08286868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613ddf92505050565b9050856001600160a01b0316816001600160a01b0316146040518060600160405280602b81526020016157f7602b913990612d0e5760405162461bcd60e51b8152600401610b3591906150af565b508254836000612d1d83615134565b9190505550505050505050565b600060008051602061549c8339815191528181556000805160206154fc83398151915282905560405190917f8892a543ee6d561b73cc067b2cde5a76c251a4e0b978d92390f1301db5d125ab91a150565b60408051808201909152601b8152600080516020615421833981519152602082015282612dbb5760405162461bcd60e51b8152600401610b3591906150af565b50612dc46113fd565b8211156040518060400160405280601f81526020016000805160206154bc83398151915281525090612e095760405162461bcd60e51b8152600401610b3591906150af565b5060008051602061549c833981519152828155612e346000805160206154fc83398151915283613e09565b60018101546040805185815260208101929092527ffa4870dc2e2f95d11863e7e765a98e12fe92c3d1d2a703b4cf983f9c4b1052e691015b60405180910390a1505050565b602082015151600384015460801b6001600160801b03199081169116141580612ebc575060208083015101516003840154600160801b900461ffff908116911614155b80612ed95750815160028401546001600160a01b03908116911614155b60405180606001604052806027815260200161568e6027913990612f105760405162461bcd60e51b8152600401610b3591906150af565b506004830154421015612f895781516002840180546001600160a01b039092166001600160a01b03199092169190911790556020808301518051600386018054929093015161ffff16600160801b026001600160901b031990921660809190911c17179055612f7f8142615121565b6004840155505050565b60028301805484546001600160a01b03199081166001600160a01b0380841691909117875560038701805460018901805461ffff600160801b808504821681026001600160901b03199384166001600160801b03871617179093558a51909516959096169490941790955560208088015180519101519092169092029290931660809390931c92909217179055612f7f8142615121565b60048201541515156040518060600160405280602f81526020016152e7602f91399061305f5760405162461bcd60e51b8152600401610b3591906150af565b5080516002830180546001600160a01b039092166001600160a01b03199092169190911790556020908101518051600384018054929093015161ffff16600160801b026001600160901b031990921660809190911c1717905542600490910155565b600c54421015806130cf5750805b60405180606001604052806035815260200161565960359139906131065760405162461bcd60e51b8152600401610b3591906150af565b50612aa583836131166008612c1b565b9190613e6c565b600560008581526020019081526020016000206000015460001460405180606001604052806029815260200161573c602991399061316e5760405162461bcd60e51b8152600401610b3591906150af565b5061317a838383613e87565b6129da84848484613ec8565b60008051602061549c833981519152805461319f6113fd565b8111156040518060400160405280601f81526020016000805160206154bc833981519152815250906131e45760405162461bcd60e51b8152600401610b3591906150af565b506131ed61201c565b60405180606001604052806038815260200161544160389139906132245760405162461bcd60e51b8152600401610b3591906150af565b50600080835560018301556132398382614067565b826001600160a01b03167fa578b4c05763eb039caef37b2d7b949c22914c3838384c9c73cefb78c4a8ed0a82604051611b9c91815260200190565b826001016000838152602001908152602001600020546000146040518060600160405280602a8152602001615374602a9139906132c45760405162461bcd60e51b8152600401610b3591906150af565b50600082815260018401602052604081208290558354829185916132e9908490615121565b9091555050505050565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061337a57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661336e6000805160206155cf833981519152546001600160a01b031690565b6001600160a01b031614155b156110325760405163703e46dd60e11b815260040160405180910390fd5b6004546001600160a01b03166133ac612909565b6001600160a01b031614806133e357506133c66008612c1b565b546001600160a01b03166133d8612909565b6001600160a01b0316145b6040518060600160405280602f815260200161589e602f91399061341a5760405162461bcd60e51b8152600401610b3591906150af565b506001546040516316da1fb760e11b81526001600160a01b03838116600483015290911690632db43f6e90602401602060405180830381865afa158015613465573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613489919061514d565b6040518060600160405280602981526020016158cd60299139906115d75760405162461bcd60e51b8152600401610b3591906150af565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561351a575060408051601f3d908101601f19168201909252613517918101906150df565b60015b61354257604051634c9c8ce360e01b81526001600160a01b0383166004820152602401610b35565b6000805160206155cf833981519152811461357357604051632a87526960e21b815260048101829052602401610b35565b612aa583836140a0565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146110325760405163703e46dd60e11b815260040160405180910390fd5b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1028054606091600080516020615541833981519152916136059061516a565b80601f01602080910402602001604051908101604052809291908181526020018280546136319061516a565b801561367e5780601f106136535761010080835404028352916020019161367e565b820191906000526020600020905b81548152906001019060200180831161366157829003601f168201915b505050505091505090565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1038054606091600080516020615541833981519152916136059061516a565b6110326140f6565b6136d86140f6565b6115d7828261413f565b6136ea614a94565b600082116040518060600160405280602e815260200161584b602e9139906137255760405162461bcd60e51b8152600401610b3591906150af565b50506040805160a0810182529485528051808201825293845260006020858101829052808701959095528151808301835293845283850152848101929092528151928301909152600182526060830191909152608082015290565b600e8201541515156040518060600160405280602f81526020016152e7602f9139906137bf5760405162461bcd60e51b8152600401610b3591906150af565b508051600783015560208082015180516008850155810151600984015560408201518051600a8501550151600b830155606081015151600c83015560800151600d82015542600e90910155565b600e830154421015613870578151600784015560208083015180516008860155810151600985015560408301518051600a8601550151600b840155606082015151600c8401556080820151600d8401556138668142615121565b600e840155505050565b600783018054845560088401805460018601556009850180546002870155600a860180546003880155600b870180546004890155600c8801805460058a0155600d8901805460068b01558851909655602080890151805190965594850151909355604087015180519092559201519091556060840151519055608083015190556138668142615121565b6000805160206154dc8339815191526000613913610acf565b825460408051808201909152601b8152600080516020615421833981519152602082015291925090856139595760405162461bcd60e51b8152600401610b3591906150af565b5060408051808201909152601d81527f353430327c446562743a206e6f2066756e647320617661696c61626c650000006020820152826139ac5760405162461bcd60e51b8152600401610b3591906150af565b508085111560405180606001604052806025815260200161556160259139906139e85760405162461bcd60e51b8152600401610b3591906150af565b5060006139f58387612a6b565b845481900385559050613a088582614151565b83546040805183815260208101929092527f75aec94f6ad949cfd9728eb818639f1b0b882089b480409ab73245c06469eef4910160405180910390a1505050505050565b6000613a588254151590565b6040518060400160405280601d81526020017f353534317c54696d6572733a2074696d6572206e6f742061637469766500000081525090613aac5760405162461bcd60e51b8152600401610b3591906150af565b505054421190565b6000805160206154dc833981519152805460408051808201909152601b8152600080516020615421833981519152602082015283613b055760405162461bcd60e51b8152600401610b3591906150af565b50808311156040518060600160405280602581526020016155616025913990613b415760405162461bcd60e51b8152600401610b3591906150af565b5081548390038083556040805185815260208101929092527fb940258db5193d85cafbc591d0c29fad88d804ff8b9ab71c8f9545af2bb2c07c9101612e6c565b60008360010160008481526020019081526020016000205490506000811160405180606001604052806025815260200161551c6025913990613bd65760405162461bcd60e51b8152600401610b3591906150af565b508082146040518060600160405280602581526020016158796025913990613c115760405162461bcd60e51b8152600401610b3591906150af565b5083600001548111156040518060600160405280602a8152602001615712602a913990613c515760405162461bcd60e51b8152600401610b3591906150af565b50835403835550600090815260019091016020526040812055565b613c76848361415b565b156129da57613c886001850184614199565b806129da576129da6003850184614199565b805460018201546000919080821015613cb4576000612901565b900392915050565b613cc881600501613a4c565b156110c857600060028201556000600482015560068101546110c8906005830190613e09565b6115d760018301826141e8565b6115d760038301826141e8565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612aa5908490614205565b60006040518060600160405280602281526020016156b56022913980516020918201208351604051613d959301918252602082015260400190565b604051602081830303815290604052805190602001209050919050565b60006129f9613dbf614268565b8360405161190160f01b8152600281019290925260228201526042902090565b600080600080613def8686614272565b925092509250613dff82826142bf565b5090949350505050565b60408051808201909152601781527f353534307c54696d6572733a207a65726f2064656c6179000000000000000000602082015281613e5b5760405162461bcd60e51b8152600401610b3591906150af565b50613e668142615121565b90915550565b8254612aa59060018501906001600160a01b03168484614378565b601b5442101580613e955750815b15613eb057612aa58382613ea9600d6129e0565b9190614500565b613ebc600d8483614500565b612aa560148483614500565b613ed18361295b565b60008215613f3c576000613ee5600161284d565b9050848110613ef657849150613f36565b809150857f83067e3478aa8b638f7e34eeecb23875cc3671e615445e892cc22dcd4c8b8df3828703604051613f2d91815260200190565b60405180910390a25b50613f8e565b613f44610acf565b8411156040518060400160405280601f81526020016000805160206154bc83398151915281525090613f895760405162461bcd60e51b8152600401610b3591906150af565b508390505b60408051808201909152601f81527f353331337c4163636f756e743a206e6f2066756e647320746f20626c6f636b00602082015281613fe05760405162461bcd60e51b8152600401610b3591906150af565b50604080516060810182528281526001600160801b03428116602080840191825286151584860190815260008b815260059092529481209351845590516001909301805494511515600160801b026001600160881b03199095169390921692909217929092179091556007805483929061405b908490615121565b90915550505050505050565b806006541015614078576000614086565b80600654614086919061510e565b6006556000546115d7906001600160a01b03168383613d08565b6140a982614562565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a28051156140ee57612aa582826145c7565b6115d761463d565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661103257604051631afcd79f60e31b815260040160405180910390fd5b6141476140f6565b6115d7828261465c565b6115d78282612b0b565b60006005830161416a81613a4c565b156141795760009150506129f9565b6006840154815460009161418c9161510e565b84101592506129f9915050565b80826001015410156040518060600160405280602e8152602001615798602e9139906141d85760405162461bcd60e51b8152600401610b3591906150af565b5060019091018054919091039055565b808260010160008282546141fc9190615121565b90915550505050565b600061421a6001600160a01b038416836146bd565b9050805160001415801561423f57508080602001905181019061423d919061514d565b155b15612aa557604051635274afe760e01b81526001600160a01b0384166004820152602401610b35565b6000610adb6146cb565b600080600083516041036142ac5760208401516040850151606086015160001a61429e8882858561473f565b9550955095505050506142b8565b50508151600091506002905b9250925092565b60008260038111156142d3576142d36151a4565b036142dc575050565b60018260038111156142f0576142f06151a4565b0361430e5760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115614322576143226151a4565b036143435760405163fce698f760e01b815260048101829052602401610b35565b6003826003811115614357576143576151a4565b036115d7576040516335e2f38360e21b815260048101829052602401610b35565b83546040805160608101909152602980825261ffff600160801b90930483169284168311919061539e6020830139906143c45760405162461bcd60e51b8152600401610b3591906150af565b5082825b8261ffff168161ffff161015614482576040516bffffffffffffffffffffffff19606088901b1660208201526001600160f01b031960f083901b1660348201526001600160801b03198316603682015260029060460160408051601f1981840301815290829052614438916151ba565b602060405180830381855afa158015614455573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061447891906150df565b91506001016143c8565b5085546040805160608101909152602180825260809290921b6001600160801b031990811690841614916155ae6020830139906144d25760405162461bcd60e51b8152600401610b3591906150af565b5050845461ffff909216600160801b026001600160901b031990921660809390931c92909217179092555050565b82600001548211156040518060600160405280603b815260200161561e603b91399061453f5760405162461bcd60e51b8152600401610b3591906150af565b5061454983613cbc565b614553838361480e565b80612aa557612aa5838361485d565b806001600160a01b03163b60000361459857604051634c9c8ce360e01b81526001600160a01b0382166004820152602401610b35565b6000805160206155cf83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b0316846040516145e491906151ba565b600060405180830381855af49150503d806000811461461f576040519150601f19603f3d011682016040523d82523d6000602084013e614624565b606091505b50915091506146348583836148af565b95945050505050565b34156110325760405163b398979f60e01b815260040160405180910390fd5b6146646140f6565b6000805160206155418339815191527fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10261469e8482615226565b50600381016146ad8382615226565b5060008082556001909101555050565b6060612a7c8383600061490b565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6146f66149a8565b6146fe614a12565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561477a5750600091506003905082614804565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156147ce573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166147fa57506000925060019150829050614804565b9250600091508190505b9450945094915050565b61481b6001830182614a56565b60405180606001604052806028815260200161558660289139906148525760405162461bcd60e51b8152600401610b3591906150af565b506115d78282613cee565b61486a6003830182614a56565b6040518060600160405280602f81526020016155ef602f9139906148a15760405162461bcd60e51b8152600401610b3591906150af565b506115d760038301826141e8565b6060826148c4576148bf82614a6b565b612a7c565b81511580156148db57506001600160a01b0384163b155b1561490457604051639996b31560e01b81526001600160a01b0385166004820152602401610b35565b5092915050565b6060814710156149305760405163cd78605960e01b8152306004820152602401610b35565b600080856001600160a01b0316848660405161494c91906151ba565b60006040518083038185875af1925050503d8060008114614989576040519150601f19603f3d011682016040523d82523d6000602084013e61498e565b606091505b509150915061499e8683836148af565b9695505050505050565b6000600080516020615541833981519152816149c26135c6565b8051909150156149da57805160209091012092915050565b815480156149e9579392505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470935050505090565b600060008051602061554183398151915281614a2c613689565b805190915015614a4457805160209091012092915050565b600182015480156149e9579392505050565b6000614a6183613c9a565b9091111592915050565b805115614a7b5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6040518060a0016040528060008152602001614ac3604051806040016040528060008152602001600081525090565b8152602001614ae5604051806040016040528060008152602001600081525090565b8152602001614b006040518060200160405280600081525090565b8152602001600081525090565b60008060408385031215614b2057600080fd5b50508035926020909101359150565b6001600160a01b03811681146110c857600080fd5b60008083601f840112614b5657600080fd5b50813567ffffffffffffffff811115614b6e57600080fd5b602083019150836020828501011115614b8657600080fd5b9250929050565b600080600060408486031215614ba257600080fd5b8335614bad81614b2f565b9250602084013567ffffffffffffffff811115614bc957600080fd5b614bd586828701614b44565b9497909650939450505050565b600060208284031215614bf457600080fd5b5035919050565b80356001600160801b031981168114614c1357600080fd5b919050565b803561ffff81168114614c1357600080fd5b600080600080600060808688031215614c4257600080fd5b8535614c4d81614b2f565b9450614c5b60208701614bfb565b9350614c6960408701614c18565b9250606086013567ffffffffffffffff811115614c8557600080fd5b614c9188828901614b44565b969995985093965092949392505050565b80151581146110c857600080fd5b600080600080600060a08688031215614cc857600080fd5b8535945060208601359350614cdf60408701614bfb565b9250614ced60608701614c18565b91506080860135614cfd81614ca2565b809150509295509295909350565b600060208284031215614d1d57600080fd5b8135612a7c81614b2f565b634e487b7160e01b600052604160045260246000fd5b60008060408385031215614d5157600080fd5b8235614d5c81614b2f565b9150602083013567ffffffffffffffff80821115614d7957600080fd5b818501915085601f830112614d8d57600080fd5b813581811115614d9f57614d9f614d28565b604051601f8201601f19908116603f01168101908382118183101715614dc757614dc7614d28565b81604052828152886020848701011115614de057600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b600080600060608486031215614e1757600080fd5b83359250602084013591506040840135614e3081614ca2565b809150509250925092565b60005b83811015614e56578181015183820152602001614e3e565b50506000910152565b60008151808452614e77816020860160208601614e3b565b601f01601f19169290920160200192915050565b60ff60f81b881681526000602060e06020840152614eac60e084018a614e5f565b8381036040850152614ebe818a614e5f565b606085018990526001600160a01b038816608086015260a0850187905284810360c08601528551808252602080880193509091019060005b81811015614f1257835183529284019291840191600101614ef6565b50909c9b505050505050505050505050565b8051825260208082015180518285015290810151604084015250604081015180516060840152602081015160808401525060608101515160a08301526080015160c090910152565b6101e08101614f7b8286614f24565b614f8860e0830185614f24565b826101c0830152949350505050565b60008060008060008060c08789031215614fb057600080fd5b8635614fbb81614b2f565b95506020870135614fcb81614b2f565b95989597505050506040840135936060810135936080820135935060a0909101359150565b6000806040838503121561500357600080fd5b61500c83614bfb565b915061501a60208401614c18565b90509250929050565b6000806000806080858703121561503957600080fd5b5050823594602084013594506040840135936060013592509050565b80516001600160a01b0316825260209081015180516001600160801b03191682840152015161ffff16604090910152565b60e081016150948286615055565b6150a16060830185615055565b8260c0830152949350505050565b602081526000612a7c6020830184614e5f565b6000602082840312156150d457600080fd5b8151612a7c81614b2f565b6000602082840312156150f157600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b818103818111156129f9576129f96150f8565b808201808211156129f9576129f96150f8565b600060018201615146576151466150f8565b5060010190565b60006020828403121561515f57600080fd5b8151612a7c81614ca2565b600181811c9082168061517e57607f821691505b60208210810361519e57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052602160045260246000fd5b600082516151cc818460208701614e3b565b9190910192915050565b601f821115612aa5576000816000526020600020601f850160051c810160208610156151ff5750805b601f850160051c820191505b8181101561521e5782815560010161520b565b505050505050565b815167ffffffffffffffff81111561524057615240614d28565b6152548161524e845461516a565b846151d6565b602080601f83116001811461528957600084156152715750858301515b600019600386901b1c1916600185901b17855561521e565b600085815260208120601f198616915b828110156152b857888601518255948401946001909101908401615299565b50858210156152d65787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe353530307c44656c6179656453657474696e67733a2076616c756520616c726561647920696e697469616c697a6564353330327c4163636f756e743a206f6e6c792070726f636573736f722063616e2063616c6c20746869732066756e6374696f6e353334307c4163636f756e743a20736574746c656d656e7420706572696f64206973206e6f74206f766572353432307c526566756e64733a20726566756e64207265636f726420616c726561647920657869737473353531307c4f6e6554696d6550617373776f72643a20696e76616c6964204f545020636f756e746572353335307c4163636f756e743a20726573756c74696e672076657269666965642062616c616e636520657863656564732061637475616c353335317c4163636f756e743a2070726f636573736f7220616c726561647920736574353130307c436f6d6d6f6e3a20616d6f756e74206973207a65726f0000000000353431307c44656c617965645769746864726177616c733a207769746864726177616c2074696d656c6f636b206e6f742065787072696564353332307c4163636f756e743a207472616e73616374696f6e206e6f7420666f756e6476d8021c4b979e99674b80f4e0cc10154af0e5f32df05eb51b29a464e2435500353130317c436f6d6d6f6e3a20696e73756666696369656e742066756e6473003486e95df892f06bd37fd38c44e2fee4c4efb6660a66e6eb20ed6d8a167eae0076d8021c4b979e99674b80f4e0cc10154af0e5f32df05eb51b29a464e2435501353432317c526566756e64733a20726566756e64207265636f7264206e6f7420666f756e64a16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100353430337c446562743a20616d6f756e7420697320686967686572207468616e2064656274353532317c4163636f756e744c696d6974733a207370656e64206c696d6974206578636565646564353531317c4f6e6554696d6550617373776f72643a20696e76616c6964204f5450360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc353532337c4163636f756e744c696d6974733a206e6f206f7470207370656e64206c696d6974206578636565646564353532307c4163636f756e744c696d6974733a20616d6f756e7420657863656564732073696e676c65207472616e73616374696f6e206c696d6974353331327c4163636f756e743a2063617264206f72204f5450207374617465206368616e676520697320696e2070726f6772657373353530317c44656c6179656453657474696e67733a2076616c756520616c7265616479207365744f776e657273686970416363657074616e63652875696e74323536206e6f6e636529353332317c4163636f756e743a206e657720616d6f756e7420697320657175616c206f7220686967686572207468616e20617574686f72697a6564353432337c526566756e64733a2070656e64696e6720616d6f756e74206578636565647320746f74616c353331307c4163636f756e743a207472616e73616374696f6e20494420616c72656164792075736564353333307c4163636f756e743a2076657269666965642062616c616e6365206e6f7420657175616c20746f2062616c616e6365353533317c5370656e644c696d6974733a20696e73756666696369656e74207370656e7420746f2063616e63656c353335327c4163636f756e743a20636172642077697468206f7470207374617465206e6f7420696e697469616c697a6564353535307c4f776e657273686970416363657074616e63653a20696e76616c6964207369676e6174757265353330347c4163636f756e743a20696e73756666696369656e7420626c6f636b656420616d6f756e74353532347c4163636f756e744c696d6974733a207370656e64206c696d697420706572696f64206973207a65726f353432327c526566756e64733a20696e76616c696420616d6f756e74207265636569766564353330317c4163636f756e743a206f6e6c79206f776e65722063616e2063616c6c20746869732066756e6374696f6e353337307c4163636f756e743a20756e617574686f72697a656420696d706c656d656e746174696f6ea26469706673582212201bf402f34a1057d0d739b2911423245677cc744b072d4af8e7f665bc51781a7f64736f6c63430008160033"; +public class TangemPaymentAccount extends Contract { + public static final String BINARY = "60c06040523462000050576200001e62000018620000f3565b62000116565b604051616e73620002b28239608051818181610fea0152612efb015260a0518181816149490152614b830152616e7390f35b600080fd5b634e487b7160e01b600052604160045260246000fd5b90601f01601f191681019081106001600160401b038211176200008d57604052565b62000055565b90620000aa620000a260405190565b92836200006b565b565b6001600160a01b031690565b90565b6001600160a01b038116036200005057565b90505190620000aa82620000bb565b906020828203126200005057620000b891620000cd565b620000b862007125803803806200010a8162000093565b928339810190620000dc565b620001219062000157565b620000aa620001fa565b620000b890620000ac906001600160a01b031682565b620000b8906200012b565b620000b89062000141565b60805262000168620000aa80808080565b62000173306200014c565b60a052565b620000b89060401c60ff1690565b620000b8905462000178565b620000b8905b6001600160401b031690565b620000b8905462000192565b620000b89062000198906001600160401b031682565b90620001da620000b8620001f692620001b0565b82546001600160401b0319166001600160401b03919091161790565b9055565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00620002268162000186565b6200029f576200023681620001a4565b6001600160401b03919082908116036200024e575050565b81620002807fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2936200029a93620001c6565b604051918291826001600160401b03909116815260200190565b0390a1565b60405163f92ee8a960e01b8152600490fdfe6080604052600436101561001257600080fd5b60003560e01c806274f3561461037c57806301e948ff1461029657806312a168311461037757806316fc32971461037257806319cdeb6f1461036d5780631d6ae778146103685780631f852f4b14610363578063226112801461035e578063246f8b96146103595780632ea63823146103545780633013ce291461034f57806334d6ee4a1461034a578063357a03331461034557806335ba9af81461034057806337a1d4151461033b5780633e0fc2ff1461033657806340345137146103315780634e6d8a731461032c5780634f1ef2861461032757806352d1902d14610322578063563b9b0f1461031d578063572b6c05146103185780636b2a3830146103135780636b4943a71461030e5780636fb7e9c11461030957806370908f21146103045780637917cf6f146102ff5780637b103999146102fa5780637da0a877146102f557806384b0196e146102f057806386f15d09146102eb5780638da5cb5b146102e65780638ef008b8146102e1578063997584a4146102dc5780639cadd226146102d7578063aa37ff1b146102d2578063ad3cb1cc146102cd578063b9603bdf146102c8578063bc77d495146102c3578063be69191d146102be578063c45a0155146102b9578063c470d703146102b4578063c9a557fa146102af578063ce1b1d43146102aa578063d47ae89c146102a5578063dbed8faa146102a0578063dcab7e501461029b578063df7727b414610296578063e2b7202514610291578063e37b81541461028c578063e6e268f414610287578063e96ede8e14610282578063eec4f8121461027d578063f2bcd022146102785763f93184c10361038c57611620565b611605565b6115ed565b6115d4565b6115b9565b611588565b611496565b6103c7565b61147b565b611463565b611448565b61142d565b611406565b6113eb565b6113d0565b6113a9565b611390565b611378565b611351565b6112e3565b6112c4565b611247565b61120c565b611191565b61116a565b611136565b610fd5565b610fba565b610f93565b610f56565b610bb9565b610b17565b610af3565b610ac6565b610a93565b610a11565b6109fd565b61093d565b6108f5565b610879565b610861565b610846565b61082d565b6107e3565b610748565b6106c6565b6105e1565b6105c9565b6105b0565b61052c565b6104c0565b610486565b610441565b610397565b600091031261038c57565b600080fd5b9052565b565b3461038c576103a7366004610381565b6103c36103b261163c565b6040515b9182918290815260200190565b0390f35b3461038c576103d7366004610381565b6103c36103b2611655565b6001600160a01b031690565b90565b6001600160a01b0381165b0361038c57565b90503590610395826103f1565b9081604091031261038c5790565b919060608382031261038c576103ee90602061043a8286610403565b9401610410565b3461038c5761045a61045436600461041e565b90611869565b604051005b806103fc565b905035906103958261045f565b9060208282031261038c576103ee91610465565b3461038c5761045a610499366004610472565b611938565b6103ee916008021c81565b906103ee915461049e565b6103ee600060076104a9565b3461038c576104d0366004610381565b6103c36103b26104b4565b8015156103fc565b90503590610395826104db565b60808183031261038c576105048282610403565b926103ee6105158460208501610465565b9360606105258260408701610465565b94016104e3565b3461038c5761045a61053f3660046104f0565b92919091611a30565b909182601f8301121561038c578135916001600160401b03831161038c57602001926001830284011161038c57565b91909160408184031261038c5761058e8382610403565b9260208201356001600160401b03811161038c576105ac9201610548565b9091565b3461038c5761045a6105c3366004610577565b91611c61565b3461038c576105d9366004610381565b61045a611c82565b3461038c576105f1366004610381565b61045a611cda565b634e487b7160e01b600052604160045260246000fd5b90601f01601f191681019081106001600160401b0382111761063057604052565b6105f9565b9061039561064260405190565b928361060f565b919060808382031261038c5761069c9060606106656080610635565b946106708382610465565b865261067f8360208301610465565b60208701526106918360408301610465565b604087015201610465565b6060830152565b919060a08382031261038c576103ee9060206106bf8286610403565b9401610649565b3461038c5761045a6106d93660046106a3565b90611d9b565b6103ee916008021c6001600160a01b031690565b906103ee91546106df565b6103ee6000806106f3565b6103ee906103e2906001600160a01b031682565b6103ee90610709565b6103ee9061071d565b61039190610726565b602081019291610395919061072f565b3461038c57610758366004610381565b6103c36107636106fe565b60405191829182610738565b0190565b9061079361078c610782845190565b8084529260200190565b9260200190565b9060005b8181106107a45750505090565b9091926107ca6107c360019286516001600160a01b0316815260200190565b9460200190565b929101610797565b60208082526103ee92910190610773565b3461038c576107f3366004610381565b6103c36107fe611da5565b604051918291826107d2565b919060408382031261038c576103ee9060206108268286610403565b9401610465565b3461038c5761045a61084036600461080a565b90611dd1565b3461038c57610856366004610381565b6103c36103b2611e24565b3461038c57610871366004610381565b61045a611fd5565b3461038c5761045a61088c36600461080a565b906122fe565b908160e091031261038c5790565b90916101808284031261038c576108b78383610403565b926108c58160208501610403565b926108d38260408301610403565b926103ee6108e48460608501610403565b936101606108268260808701610892565b3461038c5761045a6109083660046108a0565b9493909392919261286e565b909160608284031261038c576103ee61092d8484610403565b9360406108268260208701610465565b3461038c5761045a610950366004610914565b91612c73565b6001600160401b03811161063057602090601f01601f19160190565b90826000939282370152565b9092919261099361098e82610956565b610635565b938185528183011161038c57610395916020850190610972565b9080601f8301121561038c578160206103ee9335910161097e565b91909160408184031261038c576109df8382610403565b9260208201356001600160401b03811161038c576103ee92016109ad565b61045a610a0b3660046109c8565b90612c9e565b3461038c57610a21366004610381565b6103c36103b2612ceb565b91906101408382031261038c57610a438184610403565b92610a518260208301610892565b926101008201356001600160401b03811161038c5783610a72918401610548565b9290936101208201356001600160401b03811161038c576105ac9201610548565b3461038c5761045a610aa6366004610a2c565b94939093929192612ee5565b9060208282031261038c576103ee91610403565b3461038c576103c3610ae1610adc366004610ab2565b612ef3565b60405191829182901515815260200190565b3461038c5761045a610b06366004610472565b613063565b6103ee600060086104a9565b3461038c57610b27366004610381565b6103c36103b2610b0b565b6001600160801b031981166103fc565b9050359061039582610b32565b61ffff81166103fc565b9050359061039582610b4f565b909160c08284031261038c57610b7c8383610403565b92610b8a8160208501610465565b92610b988260408301610465565b926103ee610ba98460608501610b42565b9360a06105258260808701610b59565b3461038c5761045a610bcc366004610b66565b94939093929192613103565b90610be290610726565b600052602052604060002090565b6103ee905b60ff1690565b6103ee9054610bf0565b6103ee9060081c610bf5565b6103ee9054610c05565b6103ee9060101c5b6001600160401b031690565b6103ee9054610c1b565b6103ee9060801c5b61ffff1690565b6103ee9054610c39565b6103ee6040610635565b90610395610c946000610c6d610c52565b94610c8e610c7e8383015460801b90565b6001600160801b03191687840152565b01610c48565b61ffff166020840152565b6103ee9081565b6103ee9054610c9f565b6103ee6060610635565b90610395610cf86002610ccb610cb0565b94610cdc610cd882610c5c565b8752565b610cf2610ceb60018301610c5c565b6020880152565b01610ca6565b6040840152565b90610395610d1d6001610d10610c52565b94610cf2610cd882610ca6565b6020840152565b6103ee6020610635565b90610395610d466000610d3f610d24565b9401610ca6565b8352565b6103ee60a0610635565b90610395610dad6006610d65610d4a565b94610d72610cd882610ca6565b610d81610ceb60018301610cff565b610d97610d9060038301610cff565b6040880152565b610cf2610da660058301610d2e565b6060880152565b6080840152565b90610395610cf8600e610dc5610cb0565b94610dd2610cd882610d54565b610cf2610ceb60078301610d54565b610dec906005610bd8565b610df581610bfb565b91610dff82610c11565b91610e0981610c2f565b916103ee6004610e1b60018501610cba565b9301610db4565b805180516001600160801b031916835260209081015161ffff16908301526103959190608090604090610e7460208201518386019080516001600160801b031916825260209081015161ffff16910152565b0151910152565b8051825261039591906020908190610e74565b516103959152565b80518252610395919060c090608090610eb760208201516020860190610e7b565b610ec960408201516060860190610e7b565b610e74606082015160a0860190610e8e565b906101c0604061039593610ef760008201516000860190610e96565b610e74602082015160e0860190610e96565b90151581526102e08101959461039594909361010093610f4f9291610f4591610f359015156020870152565b6001600160401b03166040850152565b6060830190610e22565b0190610edb565b3461038c576103c3610f71610f6c366004610ab2565b610de1565b91610f7e95939560405190565b95869586610f09565b6103ee600060096104a9565b3461038c57610fa3366004610381565b6103c36103b2610f87565b6103ee600060026106f3565b3461038c57610fca366004610381565b6103c3610763610fae565b3461038c57610fe5366004610381565b6103c37f00000000000000000000000000000000000000000000000000000000000000005b6040515b918291826001600160a01b03909116815260200190565b60005b8381106110385750506000910152565b8181015183820152602001611028565b61106961107260209361076f9361105d815190565b80835293849260200190565b95869101611025565b601f01601f191690565b9061108b61078c610782845190565b9060005b81811061109c5750505090565b9091926110b26107c36001928651815260200190565b92910161108f565b9395919461111261110a611129956110fc611122956103ee9c9a6110ef60e08c019260008d01906001600160f81b0319169052565b8a820360208c0152611048565b9088820360408a0152611048565b976060870152565b6001600160a01b03166080850152565b60a0830152565b60c081840391015261107c565b3461038c57611146366004610381565b6103c36111516131a1565b9361116197959793919360405190565b978897886110ba565b3461038c5761117a366004610381565b6103c3610ae161323f565b6103ee600060046106f3565b3461038c576111a1366004610381565b6103c361100a611185565b9160a08383031261038c576111c18284610403565b926111cf8360208301610465565b926111dd8160408401610465565b9260608301356001600160401b03811161038c57826112036080946103ee938701610548565b949095016104e3565b3461038c5761045a61121f3660046111ac565b9493909392919261330a565b919060408382031261038c576103ee9060206105258286610403565b3461038c5761045a61125a36600461122b565b906134ab565b919060808382031261038c576112768184610403565b9261128482602083016104e3565b9260408201356001600160401b03811161038c57836112a4918401610548565b92909360608201356001600160401b03811161038c576105ac9201610548565b3461038c5761045a6112d7366004611260565b949390939291926135ea565b3461038c5761045a6112f6366004610ab2565b6136c8565b9061130861098e83610956565b918252565b61131760056112fb565b640352e302e360dc1b602082015290565b6103ee61130d565b6103ee611328565b6103ee611330565b60208082526103ee92910190611048565b3461038c57611361366004610381565b6103c361136c611338565b60405191829182611340565b3461038c5761045a61138b366004610472565b613745565b3461038c5761045a6113a336600461080a565b906138cf565b3461038c576113b9366004610381565b6103c3610ae16138d9565b6103ee600060016106f3565b3461038c576113e0366004610381565b6103c36107636113c4565b3461038c576113fb366004610381565b6103c36103b2613902565b3461038c57611416366004610381565b6103c36103b261392d565b6103ee600060036106f3565b3461038c5761143d366004610381565b6103c3610763611421565b3461038c57611458366004610381565b6103c36103b2613963565b3461038c5761045a611476366004610472565b6139e1565b3461038c5761148b366004610381565b6103c36103b26139ea565b3461038c576114a6366004610381565b6103c36103b2613a13565b6103ee6103ee6103ee9290565b90610be2906114b1565b6103ee906103e2565b6103ee90546114c8565b6103ee9060a01c610c23565b6103ee90546114db565b6103ee9060e01c610bf5565b6103ee90546114f1565b6115129060066114be565b9061151c82610ca6565b91611529600182016114d1565b916103ee600161153a8185016114e7565b93016114fd565b61158061039594611570606094989795611560608086019a6000870152565b6001600160a01b03166020850152565b6001600160401b03166040830152565b019015159052565b3461038c576103c36115a361159e366004610472565b611507565b906115b094929460405190565b94859485611541565b3461038c576115c9366004610381565b6103c36103b2613a3e565b3461038c5761045a6115e7366004610914565b91613c48565b3461038c5761045a611600366004610472565b613c92565b3461038c57611615366004610381565b6103c361100a613c9b565b3461038c576103c36103b261163636600461080a565b90613d3b565b6103ee6000600080516020616dfe833981519152610cf2565b6103ee6000613d47565b611669602f6112fb565b7f353330317c4163636f756e743a206f6e6c79206f776e65722063616e2063616c60208201526e36103a3434b990333ab731ba34b7b760891b604082015290565b6103ee61165f565b6103ee6116aa565b156116c25750565b6116e4906116cf60405190565b62461bcd60e51b815291829160048301611340565b0390fd5b90610395916117276116f8613de3565b6117056103e260046114d1565b6001600160a01b0382161490811561172c575b506117216116b2565b906116ba565b611803565b61174491506103ee61173f916005610bd8565b613e1c565b38611718565b919060408382031261038c576117799060206117666040610635565b946117718382610b42565b865201610b59565b6020830152565b6103ee90369061174a565b506103ee906020810190610b42565b506103ee906020810190610b59565b9060206117da610395936117d16117c3600083018361178b565b6001600160801b0319168552565b8281019061179a565b61ffff16910152565b6001600160a01b03909116815260608101929161039591602001906117a9565b907fec402263d6c2da14e65d81be89696eecf02dad51b4edf01a00f7f001fdae65839161184f6118376103ee836005610bd8565b61183f613963565b9061184985611780565b90613e88565b61186461185b60405190565b928392836117e3565b0390a1565b90610395916116e8565b610395906118826116f8613de3565b6118b4565b90505190610395826103f1565b9060208282031261038c576103ee91611887565b6040513d6000823e3d90fd5b6118c66118c160036114d1565b610726565b9060206118d260405190565b63659bf9d960e11b815292839060049082905afa908115611933576118ff92600092611902575b50613f43565b50565b61192591925060203d60201161192c575b61191d818361060f565b810190611894565b90386118f9565b503d611913565b6118a8565b61039590611873565b61194b60336112fb565b7f353330327c4163636f756e743a206f6e6c792070726f636573736f722063616e6020820152721031b0b636103a3434b990333ab731ba34b7b760691b604082015290565b6103ee611941565b6103ee611990565b906103959392916119db6119b2613de3565b6119d26119c56103e26118c160036114d1565b916001600160a01b031690565b14611721611998565b9192611a21611a1b7f6f9b3fed74d79ecbab600aa9408ec793100801e0e811317a78db1cd7f56c589893611a166000611a2b9589848a614050565b6114b1565b93610726565b936103b660405190565b0390a3565b906103959392916119a0565b906103959291611a4d6116f8613de3565b611ac2565b6103e26103ee6103ee9290565b6103ee90611a52565b906001600160a01b03905b9181191691161790565b90611a8d6103ee611a9492610726565b8254611a68565b9055565b6001600160a01b039091168152604081019291610395916020905b01906001600160a01b03169052565b91611ad691611ad084614135565b836141c4565b611ae060046114d1565b600090611aef6103e283611a5f565b6001600160a01b03821603611bb75750611b0a826004611a7d565b611b176118c160026114d1565b91823b1561038c5781611b2960405190565b630d00929760e01b81526001600160a01b0383166004820152938490602490829084905af1918215611933577f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe29361186493611b8a575b505060405161100e565b81611ba992903d10611bb0575b611ba1818361060f565b810190610381565b3880611b80565b503d611b97565b91611bc3816004611a7d565b611bd06118c160026114d1565b803b1561038c57818391611c079583611be860405190565b809881958294611bfc63f00d4b5d60e01b90565b845260048401611a98565b03925af1918215611933577f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe29361186493611c44575b505061100a565b81611c5a92903d10611bb057611ba1818361060f565b3880611c3d565b906103959291611a3c565b611c776116f8613de3565b610395610395614254565b610395611c6c565b611c956116f8613de3565b6103957f58619076adf5bb0943d100ef88d52d7c3fd691b19d3a9071b555b651fbf418da611864611cc660046114d1565b61100a611cd36000611a5f565b6004611a7d565b610395611c8a565b9061039591611cf26116f8613de3565b611d43565b8051825261039591906060908190611d1460208201516020860152565b610e7460408201516040860152565b6001600160a01b03909116815260a0810192916103959160200190611cf7565b907f92daafee7b0d3ce63f680acb8054b3dc8e73ffb341502efa1b45a15b1687752991611d86611d776103ee836005610bd8565b83611d80613963565b916142de565b611864611d9260405190565b92839283611d23565b9061039591611ce2565b6103ee600a614307565b9061039591611dbf6116f8613de3565b61039591611dcb613963565b91614360565b9061039591611daf565b905051906103958261045f565b9060208282031261038c576103ee91611ddb565b634e487b7160e01b600052601160045260246000fd5b91908203918211611e1f57565b611dfc565b611e706020611e366118c160006114d1565b611e3f30610726565b90611e4960405190565b938492839182916370a0823160e01b5b83526001600160a01b031660048301526024820190565b03915afa90811561193357600091611eb6575b50611e916103ee6008610ca6565b8110611eab576103ee90611ea56008610ca6565b90611e12565b506103ee60006114b1565b611ed8915060203d602011611ede575b611ed0818361060f565b810190611de8565b38611e83565b503d611ec6565b611eef603c6112fb565b7f353330337c4163636f756e743a206f6e6c792070726f636573736f72206f722060208201527f6f776e65722063616e2063616c6c20746869732066756e6374696f6e00000000604082015290565b6103ee611ee5565b6103ee611f3e565b611f8c611f59613de3565b611f696103e26118c160036114d1565b6001600160a01b03821614908115611fad575b8115611f94575b50611721611f46565b610395611fcd565b611fa791506103ee61173f916005610bd8565b38611f83565b9050611fbc6103e260046114d1565b6001600160a01b0382161490611f7c565b61039561445f565b610395611f4e565b9061039591611fed6119b2613de3565b6121f4565b81810292918115918404141715611e1f57565b6103ee6127106114b1565b634e487b7160e01b600052601260045260246000fd5b90612030565b9190565b90811561203b570490565b612010565b61204a60236112fb565b7f353334317c4163636f756e743a207472616e73616374696f6e206e6f7420666f6020820152621d5b9960ea1b604082015290565b6103ee612040565b6103ee61207f565b612099603e6112fb565b7f353338327c4163636f756e743a207472616e73616374696f6e2077617320617560208201527f74686f72697a65642077697468206120646966666572656e7420636172640000604082015290565b6103ee61208f565b6103ee6120e8565b61210260296112fb565b7f353330347c4163636f756e743a20696e73756666696369656e7420626c6f636b602082015268195908185b5bdd5b9d60ba1b604082015290565b6103ee6120f8565b6103ee61213d565b9060001990611a73565b906121676103ee611a94926114b1565b825461214d565b91908201809211611e1f57565b9160001960089290920291821b911b611a73565b91906121a06103ee611a94936114b1565b90835461217b565b6103959160009161218f565b6000906001906121c483826121a8565b0155565b634e487b7160e01b600052600060045260246000fd5b906000036121ef57610395906121b4565b6121c8565b7fec2d267131598e18b6231352c72c82d77f6236d7da371ad09865737055a23180611a2b611a21611a1b6001956122e96122e26122356103ee8460066114be565b6122a661228b61224483610ca6565b9b8c9361228561226e61226061225a6009610ca6565b88611ff2565b612268612005565b90612026565b9561227c61202c60006114b1565b11611721612087565b016114d1565b61229d6001600160a01b038c166119c5565b146117216120f0565b6122c06122b36008610ca6565b8b905b1015611721612145565b6122dc6122d58b6122d16008610ca6565b0390565b6008612157565b8961216e565b87836144e9565b611a1660006122f98360066114be565b6121de565b9061039591611fdd565b6103ee9060401c610bf5565b6103ee9054612308565b6103ee90610c23565b6103ee905461231e565b610c236103ee6103ee9290565b906001600160401b0390611a73565b610c236103ee6103ee926001600160401b031690565b906123736103ee611a949261234d565b825461233e565b9068ff00000000000000009060401b611a73565b9061239e6103ee611a9492151590565b825461237a565b61039190612331565b60208101929161039591906123a5565b9093949291926123eb7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0090565b9586936124076124016123fd87612314565b1590565b95612327565b9560009761241489612331565b6001600160401b038916148061250c575b6001986124416124348b612331565b916001600160401b031690565b1490816124e8575b155b90816124df575b506124cd5761247b95876124728b6124698c612331565b9d019c8d612363565b6124be576126b7565b61248457505050565b6124b2611864927fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29461238e565b604051918291826123ae565b6124c8898c61238e565b6126b7565b60405163f92ee8a960e01b8152600490fd5b15905038612452565b905061244b6124f630610726565b3b61250361202c8d6114b1565b14919050612449565b5086612425565b61251d60146112fb565b7315185b99d95b54185e5b595b9d1058d8dbdd5b9d60621b602082015290565b6103ee612513565b61254f60016112fb565b603160f81b602082015290565b6103ee612545565b919060e08382031261038c576125a490606061257f81610635565b9461258a83826104e3565b8652612599836020830161174a565b602087015201610649565b6040830152565b6103ee903690612564565b6103fc816114c8565b90505190610395826125b6565b9060208282031261038c576103ee916125bf565b506103ee9060208101906104e3565b506103ee906020810190610465565b9060606126536103959361261c61261860008301836125ef565b8552565b61263361262c60208301836125ef565b6020860152565b61264a61264360408301836125ef565b6040860152565b828101906125ef565b910152565b90606061268e6103959361267861267260008301836125e0565b15158552565b6126896020820160208601906117a9565b820190565b9101906125fe565b6001600160a01b039091168152610100810192916103959160200190612658565b90612752612759936118c161274b611cd3946126d287614135565b6126db81614135565b6126e484614135565b6126ed89614135565b6126f5614547565b6126fd614547565b61271661270861253d565b61271061255c565b90614566565b61271e614547565b612726614547565b61272e614547565b612736614547565b6118c16127446118c1613de3565b6001611a7d565b6003611a7d565b6002611a7d565b61277961276a6103ee836005610bd8565b612773846125ab565b9061460c565b61278481600a614696565b506127926118c160036114d1565b92602061279e60405190565b633013ce2960e01b815294859060049082905afa908115611933576127f26127f9927f778238c396424814c7113c41823459473262293bc693b847480fcbc85a6d94bd9660009161283f575b506000611a7d565b6009612157565b7f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe261282761100a60046114d1565b0390a161186461283660405190565b92839283612696565b612861915060203d602011612867575b612859818361060f565b8101906125cc565b386127ea565b503d61284f565b9061039595949392916123be565b90610395929161288d6119b2613de3565b612907565b61289c60206112fb565b7f353338307c4163636f756e743a2063617264206973206e6f7420616374697665602082015290565b6103ee612892565b6103ee6128c5565b9081526040810192916103959160200152565b0152565b9081526060810193926103959290916040916128e890611779565b9190916129186103ee8460066114be565b9161292281614706565b61296f6001840193612933856114d1565b9060009586926129486119c56103e286611a5f565b03612c505750610cf26129676129626103ee886005610bd8565b614720565b6117216128cd565b926129866122606129806009610ca6565b86611ff2565b93600094818411612b2b576129dd916129ad6122d5928698506129a887840390565b61216e565b6129b6856114b1565b8111612b1a575b505b6129d36129cc6008610ca6565b82906122b6565b6122d16008610ca6565b6129ec816122f98760066114be565b6129f96118c160036114d1565b916020612a0560405190565b63659bf9d960e11b815293849060049082905afa938415611933577fabb0c23c76702883b6d5427581380669e510735331d9dc6a0eb99a1312dd5d5a86612a68611a1b612a869a611a1660209b611e369b6118c19b600091612afc575b506148a6565b93612a7e612a7560405190565b928392836128d5565b0390a36114d1565b03915afa8015611933577fc638d270f17f849b0216682c6cf6ee6fd9af6cac195b4647eb3b4857bbc10dc791600091612add575b50612ac56008610ca6565b90611864612ad161163c565b604051938493846128ec565b612af6915060203d602011611ede57611ed0818361060f565b38612aba565b612b1491508e3d60201161192c5761191d818361060f565b38612a62565b612b2590878a6144e9565b386129bd565b948195612b46612b41600461076f896005610bd8565b614741565b90612b52858301610ca6565b848491612b5c8190565b8210612c28575b5050612b6e866114b1565b8111612baf575b5050506129dd916122d59150612b8a87860390565b612b93856114b1565b8111612ba0575b506129bf565b612ba9906147fd565b38612b9a565b6129dd9492985090612bce6122d59492612bc8858a0390565b906147c7565b868482019a83831015612bf9575050612bea90612bf192611e12565b888b6144e9565b918193612b75565b9091838111612c0c575b50505050612bf1565b612c1f93612c1991611e12565b906147d4565b38858180612c03565b612c499250612c41919003612bc88461076f8a88614759565b612bc8611655565b8438612b63565b612c5c612c6e916114d1565b61229d6001600160a01b0388166119c5565b610cf2565b90610395929161287c565b9061039591612c8b61493e565b9061039591612c9981614a86565b614a8f565b9061039591612c7e565b6103ee90612cb4614b6d565b612ce2565b6103ee7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6114b1565b506103ee612cb9565b6103ee6000612ca8565b906103959594939291612d096116f8613de3565b612d89565b356103ee816104db565b90505190610395826104db565b9060208282031261038c576103ee91612d18565b612d4360246112fb565b7f353335337c4163636f756e743a20696e76616c6964206361726420636f6e667260208201526334b6b2b960e11b604082015290565b6103ee612d39565b6103ee612d79565b94612db79194612da8612ddb95602095612da28a614135565b896141c4565b612db186612d0e565b87614baf565b612dc46118c160036114d1565b604051938492839182916399fef6bb60e01b611e59565b03915afa801561193357612dfa91600091612eb6575b50611721612d81565b612e14612e0b6103ee846005610bd8565b612773836125ab565b612e1f82600a614696565b50612e2d6118c160026114d1565b91823b1561038c576000612e4060405190565b631ee284a960e11b81526001600160a01b0383166004820152938490602490829084905af1928315611933577f778238c396424814c7113c41823459473262293bc693b847480fcbc85a6d94bd93612ea0575b5061186461283660405190565b612eb0906000611ba1818361060f565b38612e93565b612ed8915060203d602011612ede575b612ed0818361060f565b810190612d25565b38612df1565b503d612ec6565b906103959594939291612cf5565b612f1f6119c57f00000000000000000000000000000000000000000000000000000000000000006103e2565b1490565b61039590612f326119b2613de3565b612fa0565b612f4160376112fb565b7f353335307c4163636f756e743a20726573756c74696e6720766572696669656460208201527f2062616c616e636520657863656564732061637475616c000000000000000000604082015290565b6103ee612f37565b6103ee612f90565b612fe990612fb2816129a86007610ca6565b906020612fc26118c160006114d1565b612fcb30610726565b90612fd560405190565b958692839182916370a0823160e01b611e59565b03915afa801561193357613027613033917fd6004694c2f543b69302481de26731f63c1d41062795b5366d8ca20fd3e3d6d39560009161304a575090565b835b1115611721612f98565b61303e826007612157565b611864612a7560405190565b6103ee915060203d602011611ede57611ed0818361060f565b61039590612f23565b9061039595949392916130806119b2613de3565b93946130cf6130c9859493611a166001856130c1611a2b978d7f30ac254a4e36e31e8baa2471788b94b8879347196809fce466f5c214c7d71e639c8e614c91565b87848c614050565b95610726565b956130d960405190565b938493849081526001600160801b031991909116602082015261ffff909116604082015260600190565b90610395959493929161306c565b1561311857565b60405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b6044820152606490fd5b6001600160401b0381116106305760208091020190565b9061130861098e83613155565b369037565b9061039561319461318e8461316c565b93613155565b601f190160208401613179565b600080516020616e1e8339815191526131da6131bc82610ca6565b916000926131cc61202c856114b1565b14908161321f575b50613111565b6131e2614dd3565b916131eb614dee565b916131f530610726565b9061321061320b613205836114b1565b926114b1565b61317e565b600f60f81b9594934693929190565b61322c9150600101610ca6565b61323861202c846114b1565b14386131d4565b6103ee7f76d8021c4b979e99674b80f4e0cc10154af0e5f32df05eb51b29a464e2435502614e07565b90610395959493929161327c6119b2613de3565b6132b7565b9190611072816132988161076f9560209181520190565b8095610972565b9081526040602082018190526103ee93910191613281565b93946132f76130c97f8b7b934d191c6093eafb9a1fc61ef68d088dc5a0438697fe2ceac68b79574a52959493611a166001611a2b956130c18c8a8d614e89565b9561330160405190565b9384938461329f565b906103959594939291613268565b90610395916133286116f8613de3565b613406565b6103ee6103ee6103ee926001600160401b031690565b61334d60266112fb565b7f353338317c4163636f756e743a20636172642064697361626c6520696e2070726020820152656f677265737360d01b604082015290565b6103ee613343565b6103ee613385565b61339f60216112fb565b7f353335347c4163636f756e743a2069734f776e657220616c72656164792073656020820152601d60fa1b604082015290565b6103ee613395565b6103ee6133d2565b9061ff009060081b611a73565b906133ff6103ee611a9492151590565b82546133e2565b6118649061100a7f6a5e3421b4ba058a580be88d10e1c5940843a54923898f281b2fdf1ae733aef893600061343f6103ee856005610bd8565b61344b61296782614720565b0161347e61345882610c2f565b61347561346f6103ee613469613963565b4261216e565b9161332d565b1161172161338d565b6134a66134976000613491876005610bd8565b01610c11565b151583151514156117216133da565b6133ef565b9061039591613318565b9061039595949392916134c96116f8613de3565b6134ed565b6001600160a01b03909116815260408101929161039591602090611580565b94612db7919461350361350a95602095896141c4565b8587614baf565b03915afa80156119335761352891600091612eb65750611721612d81565b61353f8161353a6103ee856005610bd8565b614f34565b61354a82600a614696565b506135586118c160026114d1565b91823b1561038c57600061356b60405190565b631ee284a960e11b81526001600160a01b0383166004820152938490602490829084905af1928315611933577f1526aa7b69cd2d8a922030e75d5e009a330a1e46b715fd6f0e438df811d8ce8b936135d4575b506118646135cb60405190565b928392836134ce565b6135e4906000611ba1818361060f565b386135be565b9061039595949392916134b5565b610395906136076116f8613de3565b6136266136186103ee836005610bd8565b613620613963565b90614fba565b61363181600a615005565b5061363f6118c160026114d1565b90813b1561038c57600061365260405190565b634149177b60e01b81526001600160a01b0383166004820152928390602490829084905af1908115611933577f6a5e3421b4ba058a580be88d10e1c5940843a54923898f281b2fdf1ae733aef892611864926136b2575b5060405161100e565b6136c2906000611ba1818361060f565b386136a9565b610395906135f8565b610395906136e06119b2613de3565b6136f26020611e366118c160006114d1565b03915afa9182156119335761373a6137347f321b800465e47508430424e6c089344256e17f9a5b0b43c751dffbdfd3930263946118649460009161304a575090565b82613029565b6103b2816007612157565b610395906136d1565b906103959161375e6119b2613de3565b61376b6118c160006114d1565b6370a0823161377930610726565b90602061378560405190565b80946137918460e01b90565b82526001600160a01b038516600483015260249082905afa928315611933576000936138ae575b506137c66118c160036114d1565b91823b1561038c5760006137d960405190565b632cc3264160e01b8152938490600490829084905af19182156119335761382a93602093613898575b50611e596138136118c160006114d1565b9161381d60405190565b9586948593849360e01b90565b03915afa91821561193357611a1b613873611a21927faef62a4e4bd58df7ff5d05f9b40355fadfa67884312a36b7f64c53fd699d4f5695611a2b95600091613879575b50611e12565b956114b1565b613892915060203d602011611ede57611ed0818361060f565b3861386d565b6138a8906000611ba1818361060f565b38613802565b6138c891935060203d602011611ede57611ed0818361060f565b91386137b8565b906103959161374e565b6103ee7f76d8021c4b979e99674b80f4e0cc10154af0e5f32df05eb51b29a464e2435502615068565b6103ee60007f3fc394ec90f88dd7e18c46ffeef55f1b6719a2027f4ae9fbc4ab118271891200610cf2565b6103ee60007f5066de352c02692985a663f298a4534cb506e7947f703135018b6c3e10f82e00610cf2565b6103ee610e106114b1565b6139706118c160036114d1565b602061397b60405190565b63351eba2760e21b815291829060049082905afa8015611933576103ee916000916139aa575b50612bc8613958565b6139c3915060203d602011611ede57611ed0818361060f565b386139a1565b610395906139d86119b2613de3565b61039590615093565b610395906139c9565b6103ee7f76d8021c4b979e99674b80f4e0cc10154af0e5f32df05eb51b29a464e2435502610ca6565b6103ee60007fa715e0242b72e6c41603cf400167fb9f6392ccc61630d77addc87403bc041800610cf2565b6103ee6001600080516020616dde833981519152610cf2565b906103959291613a686119b2613de3565b613b25565b613a7760236112fb565b7f353332307c4163636f756e743a207472616e73616374696f6e206e6f7420666f6020820152621d5b9960ea1b604082015290565b6103ee613a6d565b6103ee613aac565b613ac6603b6112fb565b7f353332317c4163636f756e743a206e657720616d6f756e74206973206571756160208201527f6c206f7220686967686572207468616e20617574686f72697a65640000000000604082015290565b6103ee613abc565b6103ee613b15565b90611a2b611a21611a1b7f69cb00da9d035cbf84d93e5abc808a960d34e0da15bbddbda1e24f1b38bab89993613b5f6103ee8260066114be565b613c1c6122d56129bf8a613b7285610ca6565b613b89613b7f60006114b1565b8211611721613ab4565b613bac8c61229d6119c5613b9f60018b016114d1565b926001600160a01b031690565b613bba818310611721613b1d565b6122d1613c15613bd3613bcd6009610ca6565b84611ff2565b611ea5613c0e613c07613bee613be7612005565b8095612026565b93613c02613bfc6009610ca6565b8a611ff2565b612026565b928661216e565b918661216e565b8d896144e9565b87613c2760006114b1565b8103613c3f575050611a1660006122f98360066114be565b611a1691612157565b906103959291613a57565b61039590613c626119b2613de3565b6118647f7c8919e8b0586f5fc7dfabcfce8ecf5465b6ac9f6aaa0bcba610c55e30dad8c3916103b2816009612157565b61039590613c53565b6103ee6000600080516020616dde833981519152612285565b906103ee9291613cc56119b2613de3565b92919250613cec613ce1612b41600461076f6000956005610bd8565b93612bc88386614759565b90613cfa6118c160036114d1565b6020613d0560405190565b63659bf9d960e11b815291829060049082905afa80156119335761039593613d34926000926119025750613f43565b80946147d4565b6103ee91906000613cb4565b613d596020611e366118c160006114d1565b03915afa801561193357613d7a91600091613dc4575b50612bc86007610ca6565b90613d856008610ca6565b90819015613dab575b50808210613d9f576103ee91611e12565b50506103ee60006114b1565b613dbe9150613db8613a3e565b9061216e565b38613d8e565b613ddd915060203d602011611ede57611ed0818361060f565b38613d6f565b613dec33612ef3565b80613e06575b15613e0257601436033560601c90565b3390565b5036613e1561202c60146114b1565b1015613df2565b613e2581610c11565b9081613e2f575090565b6103ee9150614720565b613e4360236112fb565b7f353536317c43617264733a2063617264206973206e6f7420696e697469616c696020820152621e995960ea1b604082015290565b6103ee613e39565b6103ee613e78565b90613eaa6001610395949361076f613ea260008301610bfb565b611721613e80565b615241565b613eb9601d6112fb565b7f353430327c446562743a206e6f2066756e647320617661696c61626c65000000602082015290565b6103ee613eaf565b6103ee613ee2565b613efc60256112fb565b7f353430337c446562743a20616d6f756e7420697320686967686572207468616e602082015264081919589d60da1b604082015290565b6103ee613ef2565b6103ee613f33565b91907f75aec94f6ad949cfd9728eb818639f1b0b882089b480409ab73245c06469eef490613fee613fc5600080516020616dfe83398151915295613f85611655565b613fc0613fb4613f948a610ca6565b613f9d85614706565b6103ee613faa60006114b1565b8511611721613eea565b835b1115611721613f3b565b6147c7565b948592613fe9908490613fe4613fde836122d187610ca6565b85612157565b615305565b610ca6565b90611864612a7560405190565b61400560296112fb565b7f353331307c4163636f756e743a207472616e73616374696f6e20494420616c726020820152681958591e481d5cd95960ba1b604082015290565b6103ee613ffb565b6103ee614040565b906103959493929161406183614706565b61408a6140746000610cf28560066114be565b61408161202c60006114b1565b14611721614048565b61409e6129676129626103ee846005610bd8565b83156140d4575b6140cf85856140c96140c36122606140bd6009610ca6565b89611ff2565b8761216e565b8461530f565b615477565b6140ed61345860006140e7846005610bd8565b01610c2f565b6140a5565b6140fc601c6112fb565b7f353130327c436f6d6d6f6e3a2061646472657373206973207a65726f00000000602082015290565b6103ee6140f2565b6103ee614125565b610395906141496119c56103e26000611a5f565b141561172161412d565b6103ee91369161097e565b614168602b6112fb565b7f353535307c4f776e657273686970416363657074616e63653a20696e76616c6960208201526a64207369676e617475726560a81b604082015290565b6103ee61415e565b6103ee6141a5565b6000198114611e1f5760010190565b61423d906142346119c5613b9f610395969561422e60006142027f3fc394ec90f88dd7e18c46ffeef55f1b6719a2027f4ae9fbc4ab11827189120090565b01976142286142236142138b610ca6565b61421e611308610d24565b6155ff565b615646565b92614153565b9061566f565b146117216141ad565b61424e61424982610ca6565b6141b5565b90612157565b600080516020616dde8339815191527fc04d7db2ae23be2ba46893b43d7c4af2fc045905461f3df891e1d6c4d0683ef66142d96142cf614293846114d1565b6118c16142ca6002600188019761076f6142ac8a610ca6565b996142c06142ba6000611a5f565b84611a7d565b61424e60006114b1565b615685565b926103b660405190565b0390a2565b906143016142fb6004610395959461076f613ea260008301610bfb565b91615768565b906159b6565b60609061431890615a83565b930190565b905090565b614327601f6112fb565b7f353130317c436f6d6d6f6e3a20696e73756666696369656e742066756e647300602082015290565b6103ee61431d565b6103ee614350565b6143e96143e360007f31f69201fab7912e3ec9850e3ab705964bf46d9d4276bdcbb6d05e965e5f5401949561439487614706565b6143ae6143a26103ee611e24565b885b1115611721614358565b610cf26002600080516020616dde8339815191526143ce88868301611a7d565b6143db8a60018301612157565b019182615adb565b91610726565b926142d9612a7560405190565b61440060386112fb565b7f353431307c44656c617965645769746864726177616c733a207769746864726160208201527f77616c2074696d656c6f636b206e6f7420657870726965640000000000000000604082015290565b6103ee6143f6565b6103ee61444f565b600080516020616dde8339815191527fa578b4c05763eb039caef37b2d7b949c22914c3838384c9c73cefb78c4a8ed0a6142d96142cf61449e846114d1565b6144df6142ca6002600188019761076f6144b78a610ca6565b996144cc6144c66103ee611e24565b8c6143a4565b6142c06144d76138d9565b611721614457565b6118c18582615afa565b6144fd600461076f61039595946005610bd8565b9161453a614534600161452e6145266145218361451b8960066114be565b016114e7565b61332d565b9560066114be565b016114fd565b93614741565b615b37565b610395615b72565b61039561453f565b906103959161455c615b72565b9061039591615d4c565b906103959161454f565b61457a60246112fb565b7f353536307c43617264733a206361726420616c726561647920696e697469616c6020820152631a5e995960e21b604082015290565b6103ee614570565b6103ee6145b0565b9060ff90611a73565b906145d96103ee611a9492151590565b82546145c0565b9069ffffffffffffffff00009060101b611a73565b906146056103ee611a949261234d565b82546145e0565b9061467e60406146766004610395956146646001600160401b03600083016146416146396123fd83610bfb565b6117216145b8565b61464c6001826145c9565b61465f6146598a51151590565b826133ef565b6145f5565b61076f60018201602088015190615db3565b920151615768565b90615de4565b6103ee9081906001600160a01b031681565b906146be61202c611a166146b960006103ee966146b1600090565b50019461071d565b614684565b615e8e565b6146cd601b6112fb565b7f353130307c436f6d6d6f6e3a20616d6f756e74206973207a65726f0000000000602082015290565b6103ee6146c3565b6103ee6146f6565b6103959061471761202c60006114b1565b116117216146fe565b61472981610bfb565b9081614733575090565b6103ee91506123fd90615ed4565b61474d600e8201610ca6565b42106103ee5760070190565b9061476660058301615068565b1561479b571561477c576103ee90600101610ca6565b6103ee90612bc86000600361479360018501610ca6565b930101610ca6565b156147b1576103ee90600101615ef7565b615ef7565b6103ee90612bc86147ac60036143136001850183565b9080821015614318575090565b916147ec906147e284615f18565b6123fd8385615f5a565b6147f4575050565b61039591615f6c565b7ff3a2c404b3362c4238317c3dad1020c2e9e984ba8df38a4a1ff18d57e92a242a90613fee600080516020616dfe833981519152613fe9614841846129a884610ca6565b82612157565b61485160336112fb565b7f353333307c4163636f756e743a2076657269666965642062616c616e6365206e6020820152726f7420657175616c20746f2062616c616e636560681b604082015290565b6103ee614847565b6103ee614896565b906148ba916020612fc26118c160006114d1565b03915afa92831561193357610395936148f89160009161491f575b506148ed6148e36007610ca6565b821461172161489e565b831115611721614358565b614910614909836122d16007610ca6565b6007612157565b61491a60006114d1565b615fbc565b614938915060203d602011611ede57611ed0818361060f565b386148d5565b61494730610726565b7f00000000000000000000000000000000000000000000000000000000000000009061497b6001600160a01b0383166119c5565b1490811561499d575b5061498b57565b60405163703e46dd60e11b8152600490fd5b90506149ad6119c5613b9f616004565b141538614984565b610395906149c46116f8613de3565b614a1e565b6149d360296112fb565b7f353337307c4163636f756e743a20756e617574686f72697a656420696d706c6560208201526836b2b73a30ba34b7b760b91b604082015290565b6103ee6149c9565b6103ee614a0e565b6020614a4891614a316118c160016114d1565b604051938492839182916316da1fb760e11b611e59565b03915afa80156119335761039591600091614a67575b50611721614a16565b614a80915060203d602011612ede57612ed0818361060f565b38614a5e565b610395906149b5565b90614a9c6118c183610726565b906020614aa860405190565b6352d1902d60e01b815292839060049082905afa60009281614b4c575b50614b065750506001614ad55750565b6116e490614ae260405190565b634c9c8ce360e01b8152918291600483016001600160a01b03909116815260200190565b909291614b146103ee612cb9565b8403614b2557610395929350616014565b6116e484614b3260405190565b632a87526960e21b81529182916004830190815260200190565b614b6691935060203d602011611ede57611ed0818361060f565b9138614ac5565b614b7630610726565b614ba86001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166119c5565b0361498b57565b9261422e9192614c33614c266142236103ee97614bca600090565b507f5066de352c02692985a663f298a4534cb506e7947f703135018b6c3e10f82e0097614c21906125a4614bfd8b610ca6565b91614c18614c09610cb0565b6001600160a01b039096168652565b15156020850152565b61610e565b9461424e61424982610ca6565b614153565b614c42602d6112fb565b7f353331327c4163636f756e743a204f5450207374617465206368616e6765206960208201526c7320696e2070726f677265737360981b604082015290565b6103ee614c38565b6103ee614c81565b614cce61039594614cc9614cab600161076f866005610bd8565b91614cb86123fd84616151565b908115614cd3575b50611721614c89565b616164565b6162a9565b905038614cc0565b634e487b7160e01b600052602260045260246000fd5b9060016002830492168015614d11575b6020831014614d0c57565b614cdb565b91607f1691614d01565b80546000939291614d38614d2e83614cf1565b8085529360200190565b9160018116908115614d8a5750600114614d5157505050565b614d649192939450600052602060002090565b916000925b818410614d765750500190565b805484840152602090930192600101614d69565b92949550505060ff1916825215156020020190565b906103ee91614d1b565b90610395614dc392614dba60405190565b93848092614d9f565b038361060f565b6103ee90614da9565b6103ee6002600080516020616e1e8339815191525b01614dca565b6103ee6003600080516020616e1e833981519152614de8565b6000614e1c91614e15600090565b5001610ca6565b614e2961202c60006114b1565b141590565b614e38602f6112fb565b7f353535317c5472616e73616374696f6e436f6e6669726d6174696f6e3a20696e60208201526e76616c6964207369676e617475726560881b604082015290565b6103ee614e2e565b6103ee614e79565b61423d90614ee86119c5613b9f610395969561422e6000614ec77fa715e0242b72e6c41603cf400167fb9f6392ccc61630d77addc87403bc04180090565b0197614228614223614ed88b610ca6565b614ee3611308610d24565b6163ce565b14611721614e81565b614efb60206112fb565b7f353536327c43617264733a2063617264206973206e6f742064697361626c6564602082015290565b6103ee614ef1565b6103ee614f24565b6103959190614f59614f5182614f4c613ea282610bfb565b615ed4565b611721614f2c565b6134a66001600160401b03826145f5565b614f7460246112fb565b7f353536327c43617264733a206361726420697320616c72656164792064697361602082015263189b195960e21b604082015290565b6103ee614f6a565b6103ee614faa565b60008091614fff61039594614ff9614ff485850192613469614fdb85610c2f565b614feb6001600160401b03612434565b14611721614fb2565b612331565b906145f5565b016133ef565b9061502061202c611a166146b960006103ee966146b1600090565b616435565b61502f601d6112fb565b7f353534317c54696d6572733a2074696d6572206e6f7420616374697665000000602082015290565b6103ee615025565b6103ee615058565b6103ee600061508e92615079600090565b50610cf261508682614e07565b611721615060565b421190565b7fb940258db5193d85cafbc591d0c29fad88d804ff8b9ab71c8f9545af2bb2c07c90613fee600080516020616dfe8339815191526150e56150df6150d683610ca6565b6103ee86614706565b84613fb6565b613fe9614841846122d184610ca6565b6150ff60276112fb565b7f353530317c44656c6179656453657474696e67733a2076616c756520616c726560208201526618591e481cd95d60ca1b604082015290565b6103ee6150f5565b6103ee615138565b906fffffffffffffffffffffffffffffffff90611a73565b6001600160801b03191690565b9061518b615185611a94926001600160801b03191690565b60801c90565b8254615148565b9061ffff60801b9060801b611a73565b610c416103ee6103ee9261ffff1690565b906151c36103ee611a94926151a2565b8254615192565b908082036151d6575050565b61039591906151f8906151f36151ed825460801b90565b8461516d565b610c48565b906151b3565b90610395916151ca565b610395916151f89060209061522e61522882516001600160801b03191690565b8561516d565b015161ffff1690565b9061039591615208565b906001820161528e81615255815460801b90565b61527b61526d61516087516001600160801b03191690565b916001600160801b03191690565b14159081156152d6575b50611721615140565b61529783616151565b156152b657610395936134696002936152af93615237565b9101612157565b61039593613469600293836152d16152af95600089016151fe565b615237565b6152e09150610c48565b6152fd6152f5610c41602087015161ffff1690565b9161ffff1690565b141538615285565b90610395916148a6565b600461076f615322929594956005610bd8565b9261532f6123fd856164f5565b908115615362575b501561534e5761534961039593614741565b61656c565b610395926153499060079061076f85858386565b905038615337565b615374601f6112fb565b7f353331337c4163636f756e743a206e6f2066756e647320746f20626c6f636b00602082015290565b6103ee61536a565b6103ee61539d565b6103ee6080610635565b9067ffffffffffffffff60a01b9060a01b611a73565b906153dd6103ee611a949261234d565b82546153b7565b9060ff60e01b9060e01b611a73565b906154036103ee611a9492151590565b82546153e4565b906154676060600161039594615424614841600087015190565b019261544361543d60208301516001600160a01b031690565b85611a7d565b61546061545a60408301516001600160401b031690565b856153cd565b0151151590565b906153f3565b906103959161540a565b61039594916122d594615488600090565b5015615575576154986001613d47565b84811061552257506155139061550c615518945b6154c36154b960006114b1565b88116117216153a5565b6155036154cf42612331565b6154f36154da6153ad565b976154e38b8a52565b6001600160a01b03166020890152565b6001600160401b03166040870152565b15156060850152565b60066114be565b61546d565b6129a86008610ca6565b9061550c615518946155378461551395980390565b615540846114b1565b7f398a399795162d7b100f484c496bd46d45b5d80499256c51a0a1c0322b32986361556d611a2189610726565b0390a36154ac565b6155139061550c615518949561559561558f6103ee611655565b826143a4565b956154ac565b6155a560226112fb565b7f4f776e657273686970416363657074616e63652875696e74323536206e6f6e63602082015261652960f01b604082015290565b6103ee61559b565b6155e96155d9565b6155fb6155f4825190565b9160200190565b2090565b6155e961563a9161560e600090565b50615622600061561c6155e1565b92015190565b9061562c60405190565b9384926020840192836128d5565b9081038252038261060f565b6103ee906156526165af565b6042916040519161190160f01b8352600283015260228201522090565b6103ee9161567c916165b7565b90929192616652565b6103959060006152af816114b1565b61569c610c52565b906000825260006020830152565b6103ee615694565b6156ba610d24565b9060008252565b6103ee6156b2565b6156d1610d4a565b906000825260208080808086016156e66156aa565b8152016156f16156aa565b8152016156fc6156c1565b8152016000905250565b6103ee6156c9565b615718602e6112fb565b7f353532347c4163636f756e744c696d6974733a207370656e64206c696d69742060208201526d706572696f64206973207a65726f60901b604082015290565b6103ee61570e565b6103ee615758565b615770615706565b506103ee6060820191615854615784845190565b936157a060009561579761202c886114b1565b11611721615760565b61584d6157ad8685015190565b936158466157bc602083015190565b6157ce6157c7610c52565b918a830152565b61580a6157f060406157df8c6114b1565b956157eb876020870152565b015190565b936158036157fc610c52565b958c870152565b6020850152565b61583f615830615818610d24565b9661582c61582660016114b1565b8d8a0152565b5190565b97615839610d4a565b9a8b0152565b6020890152565b6040870152565b6060850152565b6080830152565b818103615866575050565b60016152af8184610cf261587f60006103959801610ca6565b86612157565b906103959161585b565b81810361589a575050565b60006152af816103959401610ca6565b906103959161588f565b8181036158bf575050565b60066152af81846158d861587f60006103959801610ca6565b6158e86001820160018701615885565b6158f86003820160038701615885565b610cf260058201600587016158aa565b90610395916158b4565b60016152af6020610395946157eb61587f600083015190565b9061039591615912565b60006152af8161039594015190565b9061039591615935565b60066152af60806103959461596761587f600083015190565b61597e615975602083015190565b6001870161592b565b61599561598c604083015190565b6003870161592b565b6157eb6159a3606083015190565b60058701615944565b906103959161594e565b906159c0826164f5565b156159db576152af61039593613469600e93600786016159ac565b6152af61039593613469600e93600786016159f98160008901615908565b6159ac565b90615a19615a0d610782845490565b92600052602060002090565b9060005b818110615a2a5750505090565b909192615a4e615a47600192615a3f87610ca6565b815260200190565b9460010190565b929101615a1d565b906103ee916159fe565b90610395614dc392615a7160405190565b93848092615a56565b6103ee90615a60565b60006103ee91615a91606090565b5001615a7a565b615aa260176112fb565b7f353534307c54696d6572733a207a65726f2064656c6179000000000000000000602082015290565b6103ee615a98565b6103ee615acb565b60006152af61039593613469615af0846114b1565b8211611721615ad3565b9061039591615b096007610ca6565b8211615b255761491061490983615b206007610ca6565b611e12565b614910615b3260006114b1565b614909565b929091615b44908461671b565b615b4d57505050565b615b5e906123fd83600186016167b0565b615b66575050565b610395916003016167b0565b615b7d6123fd6167dc565b615b8357565b604051631afcd79f60e31b8152600490fd5b9061039591615ba2615b72565b615cfd565b818110615bb2575050565b80615bc060006001936121a8565b01615ba7565b9190601f8111615bd557505050565b615be761039593600052602060002090565b906020601f840181900483019310615c09575b6020601f909101040190615ba7565b9091508190615bfa565b90615c1c815190565b906001600160401b03821161063057615c3f82615c398554614cf1565b85615bc6565b602090601f8311600114615c7a57611a94929160009183615c6f575b5050600019600883021c1916906002021790565b015190503880615c5b565b601f19831691615c8f85600052602060002090565b9260005b818110615ccd57509160029391856001969410615cb4575b50505002019055565b01516000196008601f8516021c19169055388080615cab565b91936020600181928787015181550195019201615c93565b9061039591615c13565b906121676103ee611a949290565b615d2f61039592615d26615d1c600080516020616e1e83398151915290565b9360028501615ce5565b60038301615ce5565b6001615d3b60006114b1565b91615d468382615cef565b01615cef565b9061039591615b95565b615d6060316112fb565b7f353530307c44656c6179656453657474696e67733a2073657474696e6720616c6020820152701c9958591e481a5b9a5d1a585b1a5e9959607a1b604082015290565b6103ee615d56565b6103ee615da3565b615dda61039592615dd1615dc96123fd85616805565b611721615dab565b60018301615237565b6002429101612157565b615e0361039592615dfa615dc96123fd85616813565b600783016159ac565b600e429101612157565b634e487b7160e01b600052603260045260246000fd5b8054821015615e4657615e3d600191600052602060002090565b91020190600090565b615e0d565b91906121a06103ee611a949390565b90815491680100000000000000008310156106305782615e8291600161039595018155615e23565b90615e4b565b90610be2565b615e9b6123fd8383616821565b15615ecd57615ec891615ec3906001615ebc84615eb88482615e5a565b5490565b9301615e88565b612157565b600190565b5050600090565b6000615ee991615ee2600090565b5001610c2f565b615ef24261346f565b111590565b615f0c6001615f0583610ca6565b9201610ca6565b808210613d9f57900390565b60058101615f2581615068565b615f2d575050565b615f54600683615f48615f436001610395970190565b61683a565b610cf26003820161683a565b90615adb565b610395919060010161684a565b61684a565b610395919060030161684a565b615f92615f8c6103ee9263ffffffff1690565b60e01b90565b6001600160e01b03191690565b6001600160a01b0390911681526040810192916103959160200152565b615fff600492615ff061039595615fd663a9059cbb615f79565b92615fe060405190565b9687946020860190815201615f9f565b6020820181038252038361060f565b61685f565b6103ee60006122856103ee612cb9565b9061601e826168e7565b61602782610726565b7fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b61605160405190565b600090a2805161606461202c60006114b1565b1115616073576118ff91616955565b5050610395616912565b61608760406112fb565b7f43617264436f6e6669726d6174696f6e2861646472657373206361726441646460208201527f726573732c626f6f6c2069734f776e65722c75696e74323536206e6f6e636529604082015290565b6103ee61607d565b6155e96160d6565b6128e861039594616105606094989795611560608086019a6000870152565b15156040830152565b6155e96161196160de565b82516001600160a01b03169061563a616140604061613a6020880151151590565b96015190565b6040519586946020860194856160e6565b600261615f91614e15600090565b421090565b61617060028201610ca6565b42106103ee5760010190565b61618660296112fb565b7f353531307c4f6e6554696d6550617373776f72643a20696e76616c6964204f54602082015268281031b7bab73a32b960b91b604082015290565b6103ee61617c565b6103ee6161c1565b60016103ee910161ffff1690565b610391906001600160a01b031660601b90565b6103919061ffff1660f01b90565b6010939261622160148361621960029561076f976161df565b0180926161f2565b0180926001600160801b0319169052565b61076f61624a92602092616244815190565b94859290565b93849101611025565b6103ee91616232565b61626660216112fb565b7f353531317c4f6e6554696d6550617373776f72643a20696e76616c6964204f546020820152600560fc1b604082015290565b6103ee61625c565b6103ee616299565b9391929091906162b885610c48565b946162cf61ffff871661ffff8416106117216161c9565b8482955b61ffff88165b61ffff8816101561634457600061631660209261630a8a8a61563a6162fd60405190565b9485938985019384616200565b60405191829182616253565b039060025afa15611933576162d961633c61633661516060005160001b90565b976161d1565b9690506162d3565b6163719192949750610395965061637793955061636861526d615160875460801b90565b146117216162a1565b8261516d565b6151b3565b61638660266112fb565b7f5472616e73616374696f6e436f6e6669726d6174696f6e2875696e74323536206020820152656e6f6e63652960d01b604082015290565b6103ee61637c565b6155e96163be565b6155e961563a916163dd600090565b50615622600061561c6163c6565b634e487b7160e01b600052603160045260246000fd5b61039591600091615e4b565b8054801561643057600019019061642d6164278383615e23565b90616401565b55565b6163eb565b90616446613fe98260018501615e88565b61645060006114b1565b81146164ed576164af6103ee926000926164a4956164a9600197889361647e616478866114b1565b82611e12565b8885019161649661648d845490565b611ea5896114b1565b8083036164b4575b50505090565b61640d565b01615e88565b6121a8565b615e826164dd6164e5946164d46164ce615ec39589615e23565b906104a9565b92839188615e23565b888801615e88565b38808061649e565b505050600090565b600e61615f91614e15600090565b61650d603b6112fb565b7f353532307c4163636f756e744c696d6974733a20616d6f756e7420657863656560208201527f64732073696e676c65207472616e73616374696f6e206c696d69740000000000604082015290565b6103ee616503565b6103ee61655c565b9161659e9061658b6165806103ee86610ca6565b841115611721616564565b61659484615f18565b6123fd83856169d0565b6165a6575050565b61039591616a4d565b6103ee616a9c565b906000916165c3825190565b6165d061202c60416114b1565b036165fa576165f392506020820151906060604084015193015160001a90616b19565b9192909190565b509050616612611a1661660d6000611a5f565b925190565b909160029190565b634e487b7160e01b600052602160045260246000fd5b6004111561663a57565b61661a565b9061039582616630565b6103ee906114b1565b61665c600061663f565b6166658261663f565b0361666e575050565b616678600161663f565b6166818261663f565b036166985760405163f645eedf60e01b8152600490fd5b6166a2600261663f565b6166ab8261663f565b036166d9576116e46166bc83616649565b60405163fce698f760e01b81529182916004830190815260200190565b6166ec6166e6600361663f565b9161663f565b146166f45750565b6116e49061670160405190565b6335e2f38360e21b81529182916004830190815260200190565b600581019061672982615068565b1561673657505050600090565b6103ee61202c91611ea56006615f0560006167519701610ca6565b101590565b616760602e6112fb565b7f353533317c5370656e644c696d6974733a20696e73756666696369656e74207360208201526d1c195b9d081d1bc818d85b98d95b60921b604082015290565b6103ee616756565b6103ee6167a0565b9061424e60016103959301916167d36167c884610ca6565b8211156117216167a8565b6122d183610ca6565b6103ee7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00612314565b6002614e1c91614e15600090565b600e614e1c91614e15600090565b614e1c916001613fe992616833600090565b5001615e88565b6103959060016152af60006114b1565b9061424e60016103959301916129a883610ca6565b61686b61687291610726565b9182616be0565b805161688161202c60006114b1565b141590816168c3575b506168925750565b6116e49061689f60405190565b635274afe760e01b8152918291600483016001600160a01b03909116815260200190565b6168e191508060206168d66123fd935190565b818301019101612d25565b3861688a565b803b6168f661202c60006114b1565b14614ad55761039590600061690c6103ee612cb9565b01611a7d565b61691c60006114b1565b341161692457565b60405163b398979f60e01b8152600490fd5b3d15616950576169453d6112fb565b903d6000602084013e565b606090565b6000806103ee93616964606090565b50602081519101845af4616976616936565b91616bf4565b61698660286112fb565b7f353532317c4163636f756e744c696d6974733a207370656e64206c696d697420602082015267195e18d95959195960c21b604082015290565b6103ee61697c565b6103ee6169c0565b61039591906169ed6169e58360018401616c64565b6117216169c8565b615f5a565b6169fc602f6112fb565b7f353532337c4163636f756e744c696d6974733a206e6f206f7470207370656e6460208201526e081b1a5b5a5d08195e18d959591959608a1b604082015290565b6103ee6169f2565b6103ee616a3d565b6103959190600301615f67616a628383616c64565b611721616a45565b909594926103959461069c611ab392616a95608096616a8e60a088019c6000890152565b6020870152565b6040850152565b7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6155e9616ac8616c7c565b616ad0616d00565b9061563a616add30610726565b6040519586946020860194469286616a6a565b6128e8610395946125a4606094989795616b0f608086019a6000870152565b60ff166020850152565b9091616b2484616649565b616b5061202c7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a06114b1565b11616bcc5790616b7260209460009493616b6960405190565b94859485616af0565b838052039060015afa1561193357600051600091616b8f83611a5f565b6001600160a01b0381166001600160a01b03841614616bb85750616bb2836114b1565b91929190565b915091616bc4906114b1565b909160019190565b505050616bd96000611a5f565b9160039190565b6103ee91616bee60006114b1565b91616d4f565b90616bff5750616dae565b8151616c0e61202c60006114b1565b1480616c4e575b616c1d575090565b6116e490616c2a60405190565b639996b31560e01b8152918291600483016001600160a01b03909116815260200190565b50803b616c5e61202c60006114b1565b14616c15565b61202c6103ee615ef292616c76600090565b50615ef7565b600080516020616e1e833981519152616c966103ee614dd3565b90616c9f825190565b616cac61202c60006114b1565b1115616cbe57506155fb6155f4825190565b616cc89150610ca6565b616cd260006114b1565b8114616cdb5790565b507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47090565b600080516020616e1e833981519152616d1a6103ee614dee565b90616d23825190565b616d3061202c60006114b1565b1115616d4257506155fb6155f4825190565b616cc89150600101610ca6565b91616d5930610726565b81813110616d7d5750600082819260206103ee969551920190855af1616976616936565b6116e490616d8a60405190565b63cd78605960e01b8152918291600483016001600160a01b03909116815260200190565b8051616dbd61202c60006114b1565b1115616dcb57805190602001fd5b604051630a12f52160e11b8152600490fdfe76d8021c4b979e99674b80f4e0cc10154af0e5f32df05eb51b29a464e24355003486e95df892f06bd37fd38c44e2fee4c4efb6660a66e6eb20ed6d8a167eae00a16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100a2646970667358221220299c9946e80716a606163fc8482c2e4aa42277a57c723d628ffa5e98c614887064736f6c63430008160033"; + + private static String librariesLinkedBinary; public static final String FUNC_UPGRADE_INTERFACE_VERSION = "UPGRADE_INTERFACE_VERSION"; + public static final String FUNC_ACTIVECARDADDRESSES = "activeCardAddresses"; + + public static final String FUNC_ADDCARD = "addCard"; + + public static final String FUNC_AUTHLIMITMARGIN = "authLimitMargin"; + public static final String FUNC_AUTHORIZEDTRANSACTIONS = "authorizedTransactions"; public static final String FUNC_AVAILABLEFORDEBTPAYMENT = "availableForDebtPayment"; @@ -56,12 +76,18 @@ class TangemPaymentAccount extends Contract { public static final String FUNC_CANCELWITHDRAWAL = "cancelWithdrawal"; - public static final String FUNC_CARDWITHOTP = "cardWithOtp"; + public static final String FUNC_CARDCONFIRMATIONNONCE = "cardConfirmationNonce"; + + public static final String FUNC_CARDS = "cards"; public static final String FUNC_DEBTAMOUNT = "debtAmount"; + public static final String FUNC_DISABLECARD = "disableCard"; + public static final String FUNC_EIP712DOMAIN = "eip712Domain"; + public static final String FUNC_ENABLECARD = "enableCard"; + public static final String FUNC_FACTORY = "factory"; public static final String FUNC_INCREASEVERIFIEDBALANCE = "increaseVerifiedBalance"; @@ -76,32 +102,30 @@ class TangemPaymentAccount extends Contract { public static final String FUNC_ISWITHDRAWALREADY = "isWithdrawalReady"; - public static final String FUNC_LIMITS = "limits"; - public static final String FUNC_OWNER = "owner"; public static final String FUNC_OWNERSHIPACCEPTANCENONCE = "ownershipAcceptanceNonce"; + public static final String FUNC_PAYDEBT = "payDebt"; + public static final String FUNC_PAYMENTTOKEN = "paymentToken"; - public static final String FUNC_PENDINGREFUNDAMOUNT = "pendingRefundAmount"; - - public static final String FUNC_PENDINGREFUNDTOTAL = "pendingRefundTotal"; - - public static final String FUNC_PROCESSAUTHORIZATION = "processAuthorization"; - public static final String FUNC_PROCESSAUTHORIZATIONCHANGE = "processAuthorizationChange"; - public static final String FUNC_PROCESSAUTHORIZATIONNOOTP = "processAuthorizationNoOtp"; - public static final String FUNC_PROCESSDEBT = "processDebt"; - public static final String FUNC_PROCESSPENDINGREFUNDPAYMENT = "processPendingRefundPayment"; + public static final String FUNC_PROCESSNOCONFIRMATIONAUTHORIZATION = "processNoConfirmationAuthorization"; + + public static final String FUNC_PROCESSOTPAUTHORIZATION = "processOtpAuthorization"; public static final String FUNC_PROCESSREFUNDPAYMENT = "processRefundPayment"; public static final String FUNC_PROCESSSETTLEMENT = "processSettlement"; + public static final String FUNC_PROCESSSIGNATUREAUTHORIZATION = "processSignatureAuthorization"; + + public static final String FUNC_PROCESSUNSETTLEDTRANSACTION = "processUnsettledTransaction"; + public static final String FUNC_PROCESSWITHDRAWAL = "processWithdrawal"; public static final String FUNC_PROCESSOR = "processor"; @@ -110,11 +134,13 @@ class TangemPaymentAccount extends Contract { public static final String FUNC_REGISTRY = "registry"; - public static final String FUNC_SAVEPENDINGREFUND = "savePendingRefund"; + public static final String FUNC_REMOVEOWNER = "removeOwner"; public static final String FUNC_SECURITYDELAY = "securityDelay"; - public static final String FUNC_SETCARD = "setCard"; + public static final String FUNC_SETAUTHLIMITMARGIN = "setAuthLimitMargin"; + + public static final String FUNC_SETCARDISOWNER = "setCardIsOwner"; public static final String FUNC_SETLIMITS = "setLimits"; @@ -122,20 +148,18 @@ class TangemPaymentAccount extends Contract { public static final String FUNC_SETOWNER = "setOwner"; - public static final String FUNC_SETPROCESSOR = "setProcessor"; - public static final String FUNC_SETVERIFIEDBALANCE = "setVerifiedBalance"; - public static final String FUNC_SETTLEMENTPERIOD = "settlementPeriod"; + public static final String FUNC_TRANSACTIONCONFIRMATIONNONCE = "transactionConfirmationNonce"; public static final String FUNC_TRUSTEDFORWARDER = "trustedForwarder"; - public static final String FUNC_UNBLOCKUNSETTLEDTRANSACTION = "unblockUnsettledTransaction"; - public static final String FUNC_UPGRADETOANDCALL = "upgradeToAndCall"; public static final String FUNC_VERIFIEDBALANCE = "verifiedBalance"; + public static final String FUNC_WITHDRAWALADDRESS = "withdrawalAddress"; + public static final String FUNC_WITHDRAWALAMOUNT = "withdrawalAmount"; public static final String FUNC_WITHDRAWALREADYTIMESTAMP = "withdrawalReadyTimestamp"; @@ -143,240 +167,319 @@ class TangemPaymentAccount extends Contract { public static final String FUNC_WRITEOFFDEBT = "writeOffDebt"; public static final Event ACCOUNTSTATEAFTERSETTLEMENT_EVENT = new Event("AccountStateAfterSettlement", - Arrays.asList(new TypeReference() { - }, new TypeReference() { - }, new TypeReference() { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference() {}, new TypeReference() {}, new TypeReference() {})); + ; - public static final Event CARDSET_EVENT = new Event("CardSet", - Arrays.asList(new TypeReference

() { - }, new TypeReference() { - }, new TypeReference() { - })); + public static final Event AUTHLIMITMARGINSET_EVENT = new Event("AuthLimitMarginSet", + Arrays.>asList(new TypeReference() {})); + ; + + public static final Event CARDADDED_EVENT = new Event("CardAdded", + Arrays.>asList(new TypeReference
() {}, new TypeReference() {})); + ; + + public static final Event CARDDISABLED_EVENT = new Event("CardDisabled", + Arrays.>asList(new TypeReference
() {})); + ; + + public static final Event CARDENABLED_EVENT = new Event("CardEnabled", + Arrays.>asList(new TypeReference
() {}, new TypeReference() {})); + ; public static final Event DEBTINCREASED_EVENT = new Event("DebtIncreased", - Arrays.asList(new TypeReference() { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference() {}, new TypeReference() {})); + ; public static final Event DEBTPAID_EVENT = new Event("DebtPaid", - Arrays.asList(new TypeReference() { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference() {}, new TypeReference() {})); + ; public static final Event DEBTWRITTENOFF_EVENT = new Event("DebtWrittenOff", - Arrays.asList(new TypeReference() { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference() {}, new TypeReference() {})); + ; public static final Event EIP712DOMAINCHANGED_EVENT = new Event("EIP712DomainChanged", - List.of()); + Arrays.>asList()); + ; public static final Event INITIALIZED_EVENT = new Event("Initialized", - List.of(new TypeReference() { - })); + Arrays.>asList(new TypeReference() {})); + ; public static final Event INSUFFICIENTFUNDSONFORCEDAUTH_EVENT = new Event("InsufficientFundsOnForcedAuth", - Arrays.asList(new TypeReference(true) { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference(true) {}, new TypeReference
(true) {}, new TypeReference() {})); + ; public static final Event LIMITSSET_EVENT = new Event("LimitsSet", - Arrays.asList(new TypeReference() { - }, new TypeReference() { - }, new TypeReference() { - }, new TypeReference() { - })); - - public static final Event NOOTPTRANSACTIONAUTHORIZED_EVENT = new Event("NoOtpTransactionAuthorized", - Arrays.asList(new TypeReference(true) { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference
() {}, new TypeReference() {})); + ; public static final Event OTPSTATESET_EVENT = new Event("OtpStateSet", - Arrays.asList(new TypeReference() { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference
() {}, new TypeReference() {})); + ; + + public static final Event OWNERREMOVED_EVENT = new Event("OwnerRemoved", + Arrays.>asList(new TypeReference
() {})); + ; public static final Event OWNERSET_EVENT = new Event("OwnerSet", - List.of(new TypeReference
() { - })); - - public static final Event PENDINGREFUNDSAVED_EVENT = new Event("PendingRefundSaved", - Arrays.asList(new TypeReference(true) { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference
() {})); + ; public static final Event PROCESSORSET_EVENT = new Event("ProcessorSet", - Arrays.asList(new TypeReference
() { - }, new TypeReference
() { - })); + Arrays.>asList(new TypeReference
() {}, new TypeReference
() {})); + ; public static final Event REFUNDPAID_EVENT = new Event("RefundPaid", - Arrays.asList(new TypeReference(true) { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference(true) {}, new TypeReference
(true) {}, new TypeReference() {})); + ; public static final Event TRANSACTIONAMOUNTCHANGED_EVENT = new Event("TransactionAmountChanged", - Arrays.asList(new TypeReference(true) { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference(true) {}, new TypeReference
(true) {}, new TypeReference() {})); + ; - public static final Event TRANSACTIONAUTHORIZED_EVENT = new Event("TransactionAuthorized", - Arrays.asList(new TypeReference(true) { - }, new TypeReference() { - }, new TypeReference() { - }, new TypeReference() { - })); + public static final Event TRANSACTIONAUTHORIZEDNOCONFIRMATION_EVENT = new Event("TransactionAuthorizedNoConfirmation", + Arrays.>asList(new TypeReference(true) {}, new TypeReference
(true) {}, new TypeReference() {})); + ; + + public static final Event TRANSACTIONAUTHORIZEDWITHOTP_EVENT = new Event("TransactionAuthorizedWithOtp", + Arrays.>asList(new TypeReference(true) {}, new TypeReference
(true) {}, new TypeReference() {}, new TypeReference() {}, new TypeReference() {})); + ; + + public static final Event TRANSACTIONAUTHORIZEDWITHSIGNATURE_EVENT = new Event("TransactionAuthorizedWithSignature", + Arrays.>asList(new TypeReference(true) {}, new TypeReference
(true) {}, new TypeReference() {}, new TypeReference() {})); + ; public static final Event TRANSACTIONSETTLED_EVENT = new Event("TransactionSettled", - Arrays.asList(new TypeReference(true) { - }, new TypeReference() { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference(true) {}, new TypeReference
(true) {}, new TypeReference() {}, new TypeReference() {})); + ; public static final Event UNSETTLEDTRANSACTIONUNBLOCKED_EVENT = new Event("UnsettledTransactionUnblocked", - Arrays.asList(new TypeReference(true) { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference(true) {}, new TypeReference
(true) {}, new TypeReference() {})); + ; public static final Event UPGRADED_EVENT = new Event("Upgraded", - List.of(new TypeReference
(true) { - })); + Arrays.>asList(new TypeReference
(true) {})); + ; public static final Event VERIFIEDBALANCEINCREASED_EVENT = new Event("VerifiedBalanceIncreased", - Arrays.asList(new TypeReference() { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference() {}, new TypeReference() {})); + ; public static final Event VERIFIEDBALANCESET_EVENT = new Event("VerifiedBalanceSet", - List.of(new TypeReference() { - })); + Arrays.>asList(new TypeReference() {})); + ; public static final Event WITHDRAWALCANCELED_EVENT = new Event("WithdrawalCanceled", - List.of()); + Arrays.>asList(new TypeReference
(true) {}, new TypeReference() {})); + ; public static final Event WITHDRAWALCOMPLETE_EVENT = new Event("WithdrawalComplete", - Arrays.asList(new TypeReference
(true) { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference
(true) {}, new TypeReference() {})); + ; public static final Event WITHDRAWALINITIATED_EVENT = new Event("WithdrawalInitiated", - Arrays.asList(new TypeReference() { - }, new TypeReference() { - })); + Arrays.>asList(new TypeReference
(true) {}, new TypeReference() {}, new TypeReference() {})); + ; @Deprecated - protected TangemPaymentAccount(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + protected TangemPaymentAccount(String contractAddress, Web3j web3j, Credentials credentials, + BigInteger gasPrice, BigInteger gasLimit) { super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit); } - protected TangemPaymentAccount(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { + protected TangemPaymentAccount(String contractAddress, Web3j web3j, Credentials credentials, + ContractGasProvider contractGasProvider) { super(BINARY, contractAddress, web3j, credentials, contractGasProvider); } @Deprecated - protected TangemPaymentAccount(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + protected TangemPaymentAccount(String contractAddress, Web3j web3j, + TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit); } - protected TangemPaymentAccount(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + protected TangemPaymentAccount(String contractAddress, Web3j web3j, + TransactionManager transactionManager, ContractGasProvider contractGasProvider) { super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider); } - public static List getAccountStateAfterSettlementEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(ACCOUNTSTATEAFTERSETTLEMENT_EVENT, transactionReceipt); + public static List getAccountStateAfterSettlementEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(ACCOUNTSTATEAFTERSETTLEMENT_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { AccountStateAfterSettlementEventResponse typedResponse = new AccountStateAfterSettlementEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.balance = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); typedResponse.blockedAmount = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); typedResponse.debtTotal = (BigInteger) eventValues.getNonIndexedValues().get(2).getValue(); - typedResponse.pendingRefundTotal = (BigInteger) eventValues.getNonIndexedValues().get(3).getValue(); responses.add(typedResponse); } return responses; } - public static AccountStateAfterSettlementEventResponse getAccountStateAfterSettlementEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(ACCOUNTSTATEAFTERSETTLEMENT_EVENT, log); + public static AccountStateAfterSettlementEventResponse getAccountStateAfterSettlementEventFromLog( + Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(ACCOUNTSTATEAFTERSETTLEMENT_EVENT, log); AccountStateAfterSettlementEventResponse typedResponse = new AccountStateAfterSettlementEventResponse(); typedResponse.log = log; typedResponse.balance = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); typedResponse.blockedAmount = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); typedResponse.debtTotal = (BigInteger) eventValues.getNonIndexedValues().get(2).getValue(); - typedResponse.pendingRefundTotal = (BigInteger) eventValues.getNonIndexedValues().get(3).getValue(); return typedResponse; } - public static CardSetEventResponse getCardSetEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(CARDSET_EVENT, log); - CardSetEventResponse typedResponse = new CardSetEventResponse(); + public Flowable accountStateAfterSettlementEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getAccountStateAfterSettlementEventFromLog(log)); + } + + public Flowable accountStateAfterSettlementEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(ACCOUNTSTATEAFTERSETTLEMENT_EVENT)); + return accountStateAfterSettlementEventFlowable(filter); + } + + public static List getAuthLimitMarginSetEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(AUTHLIMITMARGINSET_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + AuthLimitMarginSetEventResponse typedResponse = new AuthLimitMarginSetEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.authLimitMargin = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public static AuthLimitMarginSetEventResponse getAuthLimitMarginSetEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(AUTHLIMITMARGINSET_EVENT, log); + AuthLimitMarginSetEventResponse typedResponse = new AuthLimitMarginSetEventResponse(); typedResponse.log = log; - typedResponse.card = (String) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.otpRoot = (byte[]) eventValues.getNonIndexedValues().get(1).getValue(); - typedResponse.otpCounter = (BigInteger) eventValues.getNonIndexedValues().get(2).getValue(); + typedResponse.authLimitMargin = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); return typedResponse; } - public static DebtIncreasedEventResponse getDebtIncreasedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(DEBTINCREASED_EVENT, log); - DebtIncreasedEventResponse typedResponse = new DebtIncreasedEventResponse(); + public Flowable authLimitMarginSetEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getAuthLimitMarginSetEventFromLog(log)); + } + + public Flowable authLimitMarginSetEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(AUTHLIMITMARGINSET_EVENT)); + return authLimitMarginSetEventFlowable(filter); + } + + public static List getCardAddedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(CARDADDED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + CardAddedEventResponse typedResponse = new CardAddedEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.cardAddress = (String) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.cardData = (CardParams) eventValues.getNonIndexedValues().get(1); + responses.add(typedResponse); + } + return responses; + } + + public static CardAddedEventResponse getCardAddedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(CARDADDED_EVENT, log); + CardAddedEventResponse typedResponse = new CardAddedEventResponse(); typedResponse.log = log; - typedResponse.increase = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.debtAmount = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); + typedResponse.cardAddress = (String) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.cardData = (CardParams) eventValues.getNonIndexedValues().get(1); return typedResponse; } - public static List getCardSetEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(CARDSET_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - CardSetEventResponse typedResponse = new CardSetEventResponse(); + public Flowable cardAddedEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getCardAddedEventFromLog(log)); + } + + public Flowable cardAddedEventFlowable(DefaultBlockParameter startBlock, + DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(CARDADDED_EVENT)); + return cardAddedEventFlowable(filter); + } + + public static List getCardDisabledEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(CARDDISABLED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + CardDisabledEventResponse typedResponse = new CardDisabledEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.card = (String) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.otpRoot = (byte[]) eventValues.getNonIndexedValues().get(1).getValue(); - typedResponse.otpCounter = (BigInteger) eventValues.getNonIndexedValues().get(2).getValue(); responses.add(typedResponse); } return responses; } - public static DebtPaidEventResponse getDebtPaidEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(DEBTPAID_EVENT, log); - DebtPaidEventResponse typedResponse = new DebtPaidEventResponse(); + public static CardDisabledEventResponse getCardDisabledEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(CARDDISABLED_EVENT, log); + CardDisabledEventResponse typedResponse = new CardDisabledEventResponse(); typedResponse.log = log; - typedResponse.paid = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.debtLeft = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); + typedResponse.card = (String) eventValues.getNonIndexedValues().get(0).getValue(); return typedResponse; } - public static DebtWrittenOffEventResponse getDebtWrittenOffEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(DEBTWRITTENOFF_EVENT, log); - DebtWrittenOffEventResponse typedResponse = new DebtWrittenOffEventResponse(); - typedResponse.log = log; - typedResponse.writtenOff = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.debtLeft = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); - return typedResponse; + public Flowable cardDisabledEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getCardDisabledEventFromLog(log)); } - public static List getEIP712DomainChangedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(EIP712DOMAINCHANGED_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - EIP712DomainChangedEventResponse typedResponse = new EIP712DomainChangedEventResponse(); + public Flowable cardDisabledEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(CARDDISABLED_EVENT)); + return cardDisabledEventFlowable(filter); + } + + public static List getCardEnabledEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(CARDENABLED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + CardEnabledEventResponse typedResponse = new CardEnabledEventResponse(); typedResponse.log = eventValues.getLog(); + typedResponse.card = (String) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.isOwner = (Boolean) eventValues.getNonIndexedValues().get(1).getValue(); responses.add(typedResponse); } return responses; } - public static List getDebtIncreasedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(DEBTINCREASED_EVENT, transactionReceipt); + public static CardEnabledEventResponse getCardEnabledEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(CARDENABLED_EVENT, log); + CardEnabledEventResponse typedResponse = new CardEnabledEventResponse(); + typedResponse.log = log; + typedResponse.card = (String) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.isOwner = (Boolean) eventValues.getNonIndexedValues().get(1).getValue(); + return typedResponse; + } + + public Flowable cardEnabledEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getCardEnabledEventFromLog(log)); + } + + public Flowable cardEnabledEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(CARDENABLED_EVENT)); + return cardEnabledEventFlowable(filter); + } + + public static List getDebtIncreasedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(DEBTINCREASED_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { DebtIncreasedEventResponse typedResponse = new DebtIncreasedEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.increase = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); @@ -386,34 +489,31 @@ class TangemPaymentAccount extends Contract { return responses; } - public static EIP712DomainChangedEventResponse getEIP712DomainChangedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(EIP712DOMAINCHANGED_EVENT, log); - EIP712DomainChangedEventResponse typedResponse = new EIP712DomainChangedEventResponse(); + public static DebtIncreasedEventResponse getDebtIncreasedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(DEBTINCREASED_EVENT, log); + DebtIncreasedEventResponse typedResponse = new DebtIncreasedEventResponse(); typedResponse.log = log; + typedResponse.increase = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.debtAmount = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); return typedResponse; } - public static InitializedEventResponse getInitializedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(INITIALIZED_EVENT, log); - InitializedEventResponse typedResponse = new InitializedEventResponse(); - typedResponse.log = log; - typedResponse.version = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; + public Flowable debtIncreasedEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getDebtIncreasedEventFromLog(log)); } - public static InsufficientFundsOnForcedAuthEventResponse getInsufficientFundsOnForcedAuthEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(INSUFFICIENTFUNDSONFORCEDAUTH_EVENT, log); - InsufficientFundsOnForcedAuthEventResponse typedResponse = new InsufficientFundsOnForcedAuthEventResponse(); - typedResponse.log = log; - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.insufficientAmount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; + public Flowable debtIncreasedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(DEBTINCREASED_EVENT)); + return debtIncreasedEventFlowable(filter); } - public static List getDebtPaidEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(DEBTPAID_EVENT, transactionReceipt); + public static List getDebtPaidEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(DEBTPAID_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { DebtPaidEventResponse typedResponse = new DebtPaidEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.paid = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); @@ -423,39 +523,31 @@ class TangemPaymentAccount extends Contract { return responses; } - public static LimitsSetEventResponse getLimitsSetEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(LIMITSSET_EVENT, log); - LimitsSetEventResponse typedResponse = new LimitsSetEventResponse(); + public static DebtPaidEventResponse getDebtPaidEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(DEBTPAID_EVENT, log); + DebtPaidEventResponse typedResponse = new DebtPaidEventResponse(); typedResponse.log = log; - typedResponse.singleTransactionLimit = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.spendLimit = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); - typedResponse.noOtpSpendLimit = (BigInteger) eventValues.getNonIndexedValues().get(2).getValue(); - typedResponse.spendLimitsPeriod = (BigInteger) eventValues.getNonIndexedValues().get(3).getValue(); + typedResponse.paid = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.debtLeft = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); return typedResponse; } - public static NoOtpTransactionAuthorizedEventResponse getNoOtpTransactionAuthorizedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(NOOTPTRANSACTIONAUTHORIZED_EVENT, log); - NoOtpTransactionAuthorizedEventResponse typedResponse = new NoOtpTransactionAuthorizedEventResponse(); - typedResponse.log = log; - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; + public Flowable debtPaidEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getDebtPaidEventFromLog(log)); } - public static OtpStateSetEventResponse getOtpStateSetEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(OTPSTATESET_EVENT, log); - OtpStateSetEventResponse typedResponse = new OtpStateSetEventResponse(); - typedResponse.log = log; - typedResponse.otpRoot = (byte[]) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.otpCounter = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); - return typedResponse; + public Flowable debtPaidEventFlowable(DefaultBlockParameter startBlock, + DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(DEBTPAID_EVENT)); + return debtPaidEventFlowable(filter); } - public static List getDebtWrittenOffEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(DEBTWRITTENOFF_EVENT, transactionReceipt); + public static List getDebtWrittenOffEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(DEBTWRITTENOFF_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { DebtWrittenOffEventResponse typedResponse = new DebtWrittenOffEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.writtenOff = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); @@ -465,10 +557,232 @@ class TangemPaymentAccount extends Contract { return responses; } - public static List getOwnerSetEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(OWNERSET_EVENT, transactionReceipt); + public static DebtWrittenOffEventResponse getDebtWrittenOffEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(DEBTWRITTENOFF_EVENT, log); + DebtWrittenOffEventResponse typedResponse = new DebtWrittenOffEventResponse(); + typedResponse.log = log; + typedResponse.writtenOff = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.debtLeft = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); + return typedResponse; + } + + public Flowable debtWrittenOffEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getDebtWrittenOffEventFromLog(log)); + } + + public Flowable debtWrittenOffEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(DEBTWRITTENOFF_EVENT)); + return debtWrittenOffEventFlowable(filter); + } + + public static List getEIP712DomainChangedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(EIP712DOMAINCHANGED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + EIP712DomainChangedEventResponse typedResponse = new EIP712DomainChangedEventResponse(); + typedResponse.log = eventValues.getLog(); + responses.add(typedResponse); + } + return responses; + } + + public static EIP712DomainChangedEventResponse getEIP712DomainChangedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(EIP712DOMAINCHANGED_EVENT, log); + EIP712DomainChangedEventResponse typedResponse = new EIP712DomainChangedEventResponse(); + typedResponse.log = log; + return typedResponse; + } + + public Flowable eIP712DomainChangedEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getEIP712DomainChangedEventFromLog(log)); + } + + public Flowable eIP712DomainChangedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(EIP712DOMAINCHANGED_EVENT)); + return eIP712DomainChangedEventFlowable(filter); + } + + public static List getInitializedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(INITIALIZED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + InitializedEventResponse typedResponse = new InitializedEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.version = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public static InitializedEventResponse getInitializedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(INITIALIZED_EVENT, log); + InitializedEventResponse typedResponse = new InitializedEventResponse(); + typedResponse.log = log; + typedResponse.version = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; + } + + public Flowable initializedEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getInitializedEventFromLog(log)); + } + + public Flowable initializedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(INITIALIZED_EVENT)); + return initializedEventFlowable(filter); + } + + public static List getInsufficientFundsOnForcedAuthEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(INSUFFICIENTFUNDSONFORCEDAUTH_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + InsufficientFundsOnForcedAuthEventResponse typedResponse = new InsufficientFundsOnForcedAuthEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.insufficientAmount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public static InsufficientFundsOnForcedAuthEventResponse getInsufficientFundsOnForcedAuthEventFromLog( + Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(INSUFFICIENTFUNDSONFORCEDAUTH_EVENT, log); + InsufficientFundsOnForcedAuthEventResponse typedResponse = new InsufficientFundsOnForcedAuthEventResponse(); + typedResponse.log = log; + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.insufficientAmount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; + } + + public Flowable insufficientFundsOnForcedAuthEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getInsufficientFundsOnForcedAuthEventFromLog(log)); + } + + public Flowable insufficientFundsOnForcedAuthEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(INSUFFICIENTFUNDSONFORCEDAUTH_EVENT)); + return insufficientFundsOnForcedAuthEventFlowable(filter); + } + + public static List getLimitsSetEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(LIMITSSET_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + LimitsSetEventResponse typedResponse = new LimitsSetEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.card = (String) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.limitsParams = (LimitsParams) eventValues.getNonIndexedValues().get(1); + responses.add(typedResponse); + } + return responses; + } + + public static LimitsSetEventResponse getLimitsSetEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(LIMITSSET_EVENT, log); + LimitsSetEventResponse typedResponse = new LimitsSetEventResponse(); + typedResponse.log = log; + typedResponse.card = (String) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.limitsParams = (LimitsParams) eventValues.getNonIndexedValues().get(1); + return typedResponse; + } + + public Flowable limitsSetEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getLimitsSetEventFromLog(log)); + } + + public Flowable limitsSetEventFlowable(DefaultBlockParameter startBlock, + DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(LIMITSSET_EVENT)); + return limitsSetEventFlowable(filter); + } + + public static List getOtpStateSetEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(OTPSTATESET_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + OtpStateSetEventResponse typedResponse = new OtpStateSetEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.card = (String) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.otpState = (OtpState) eventValues.getNonIndexedValues().get(1); + responses.add(typedResponse); + } + return responses; + } + + public static OtpStateSetEventResponse getOtpStateSetEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(OTPSTATESET_EVENT, log); + OtpStateSetEventResponse typedResponse = new OtpStateSetEventResponse(); + typedResponse.log = log; + typedResponse.card = (String) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.otpState = (OtpState) eventValues.getNonIndexedValues().get(1); + return typedResponse; + } + + public Flowable otpStateSetEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getOtpStateSetEventFromLog(log)); + } + + public Flowable otpStateSetEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(OTPSTATESET_EVENT)); + return otpStateSetEventFlowable(filter); + } + + public static List getOwnerRemovedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(OWNERREMOVED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + OwnerRemovedEventResponse typedResponse = new OwnerRemovedEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.previousOwner = (String) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public static OwnerRemovedEventResponse getOwnerRemovedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(OWNERREMOVED_EVENT, log); + OwnerRemovedEventResponse typedResponse = new OwnerRemovedEventResponse(); + typedResponse.log = log; + typedResponse.previousOwner = (String) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; + } + + public Flowable ownerRemovedEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getOwnerRemovedEventFromLog(log)); + } + + public Flowable ownerRemovedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(OWNERREMOVED_EVENT)); + return ownerRemovedEventFlowable(filter); + } + + public static List getOwnerSetEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(OWNERSET_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { OwnerSetEventResponse typedResponse = new OwnerSetEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.owner = (String) eventValues.getNonIndexedValues().get(0).getValue(); @@ -478,277 +792,29 @@ class TangemPaymentAccount extends Contract { } public static OwnerSetEventResponse getOwnerSetEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(OWNERSET_EVENT, log); + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(OWNERSET_EVENT, log); OwnerSetEventResponse typedResponse = new OwnerSetEventResponse(); typedResponse.log = log; typedResponse.owner = (String) eventValues.getNonIndexedValues().get(0).getValue(); return typedResponse; } - public static PendingRefundSavedEventResponse getPendingRefundSavedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(PENDINGREFUNDSAVED_EVENT, log); - PendingRefundSavedEventResponse typedResponse = new PendingRefundSavedEventResponse(); - typedResponse.log = log; - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; + public Flowable ownerSetEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getOwnerSetEventFromLog(log)); } - public static ProcessorSetEventResponse getProcessorSetEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(PROCESSORSET_EVENT, log); - ProcessorSetEventResponse typedResponse = new ProcessorSetEventResponse(); - typedResponse.log = log; - typedResponse.processor = (String) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.paymentToken = (String) eventValues.getNonIndexedValues().get(1).getValue(); - return typedResponse; - } - - public static RefundPaidEventResponse getRefundPaidEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(REFUNDPAID_EVENT, log); - RefundPaidEventResponse typedResponse = new RefundPaidEventResponse(); - typedResponse.log = log; - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; - } - - public static TransactionAmountChangedEventResponse getTransactionAmountChangedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(TRANSACTIONAMOUNTCHANGED_EVENT, log); - TransactionAmountChangedEventResponse typedResponse = new TransactionAmountChangedEventResponse(); - typedResponse.log = log; - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.newAmount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; - } - - public static TransactionAuthorizedEventResponse getTransactionAuthorizedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(TRANSACTIONAUTHORIZED_EVENT, log); - TransactionAuthorizedEventResponse typedResponse = new TransactionAuthorizedEventResponse(); - typedResponse.log = log; - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.otp = (byte[]) eventValues.getNonIndexedValues().get(1).getValue(); - typedResponse.otpCounter = (BigInteger) eventValues.getNonIndexedValues().get(2).getValue(); - return typedResponse; - } - - public static List getInitializedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(INITIALIZED_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - InitializedEventResponse typedResponse = new InitializedEventResponse(); - typedResponse.log = eventValues.getLog(); - typedResponse.version = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - responses.add(typedResponse); - } - return responses; - } - - public static TransactionSettledEventResponse getTransactionSettledEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(TRANSACTIONSETTLED_EVENT, log); - TransactionSettledEventResponse typedResponse = new TransactionSettledEventResponse(); - typedResponse.log = log; - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.settlementAmount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.paymentAmount = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); - return typedResponse; - } - - public static UnsettledTransactionUnblockedEventResponse getUnsettledTransactionUnblockedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(UNSETTLEDTRANSACTIONUNBLOCKED_EVENT, log); - UnsettledTransactionUnblockedEventResponse typedResponse = new UnsettledTransactionUnblockedEventResponse(); - typedResponse.log = log; - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; - } - - public static UpgradedEventResponse getUpgradedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(UPGRADED_EVENT, log); - UpgradedEventResponse typedResponse = new UpgradedEventResponse(); - typedResponse.log = log; - typedResponse.implementation = (String) eventValues.getIndexedValues().get(0).getValue(); - return typedResponse; - } - - public static List getInsufficientFundsOnForcedAuthEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(INSUFFICIENTFUNDSONFORCEDAUTH_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - InsufficientFundsOnForcedAuthEventResponse typedResponse = new InsufficientFundsOnForcedAuthEventResponse(); - typedResponse.log = eventValues.getLog(); - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.insufficientAmount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - responses.add(typedResponse); - } - return responses; - } - - public static VerifiedBalanceIncreasedEventResponse getVerifiedBalanceIncreasedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(VERIFIEDBALANCEINCREASED_EVENT, log); - VerifiedBalanceIncreasedEventResponse typedResponse = new VerifiedBalanceIncreasedEventResponse(); - typedResponse.log = log; - typedResponse.increase = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.verifiedBalance = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); - return typedResponse; - } - - public static VerifiedBalanceSetEventResponse getVerifiedBalanceSetEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(VERIFIEDBALANCESET_EVENT, log); - VerifiedBalanceSetEventResponse typedResponse = new VerifiedBalanceSetEventResponse(); - typedResponse.log = log; - typedResponse.verifiedBalance = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; - } - - public static WithdrawalCanceledEventResponse getWithdrawalCanceledEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(WITHDRAWALCANCELED_EVENT, log); - WithdrawalCanceledEventResponse typedResponse = new WithdrawalCanceledEventResponse(); - typedResponse.log = log; - return typedResponse; - } - - public static List getLimitsSetEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(LIMITSSET_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - LimitsSetEventResponse typedResponse = new LimitsSetEventResponse(); - typedResponse.log = eventValues.getLog(); - typedResponse.singleTransactionLimit = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.spendLimit = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); - typedResponse.noOtpSpendLimit = (BigInteger) eventValues.getNonIndexedValues().get(2).getValue(); - typedResponse.spendLimitsPeriod = (BigInteger) eventValues.getNonIndexedValues().get(3).getValue(); - responses.add(typedResponse); - } - return responses; - } - - public static WithdrawalCompleteEventResponse getWithdrawalCompleteEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(WITHDRAWALCOMPLETE_EVENT, log); - WithdrawalCompleteEventResponse typedResponse = new WithdrawalCompleteEventResponse(); - typedResponse.log = log; - typedResponse.to = (String) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - return typedResponse; - } - - @Deprecated - public static TangemPaymentAccount load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { - return new TangemPaymentAccount(contractAddress, web3j, credentials, gasPrice, gasLimit); - } - - @Deprecated - public static TangemPaymentAccount load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { - return new TangemPaymentAccount(contractAddress, web3j, transactionManager, gasPrice, gasLimit); - } - - public static List getNoOtpTransactionAuthorizedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(NOOTPTRANSACTIONAUTHORIZED_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - NoOtpTransactionAuthorizedEventResponse typedResponse = new NoOtpTransactionAuthorizedEventResponse(); - typedResponse.log = eventValues.getLog(); - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - responses.add(typedResponse); - } - return responses; - } - - public static TangemPaymentAccount load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { - return new TangemPaymentAccount(contractAddress, web3j, credentials, contractGasProvider); - } - - public static TangemPaymentAccount load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { - return new TangemPaymentAccount(contractAddress, web3j, transactionManager, contractGasProvider); - } - - public static RemoteCall deploy(Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider, String trustedForwarder) { - String encodedConstructor = FunctionEncoder.encodeConstructor(List.of(new Address(160, trustedForwarder))); - return deployRemoteCall(TangemPaymentAccount.class, web3j, credentials, contractGasProvider, BINARY, encodedConstructor); - } - - public static List getOtpStateSetEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(OTPSTATESET_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - OtpStateSetEventResponse typedResponse = new OtpStateSetEventResponse(); - typedResponse.log = eventValues.getLog(); - typedResponse.otpRoot = (byte[]) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.otpCounter = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); - responses.add(typedResponse); - } - return responses; - } - - public static RemoteCall deploy(Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider, String trustedForwarder) { - String encodedConstructor = FunctionEncoder.encodeConstructor(List.of(new Address(160, trustedForwarder))); - return deployRemoteCall(TangemPaymentAccount.class, web3j, transactionManager, contractGasProvider, BINARY, encodedConstructor); - } - - @Deprecated - public static RemoteCall deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit, String trustedForwarder) { - String encodedConstructor = FunctionEncoder.encodeConstructor(List.of(new Address(160, trustedForwarder))); - return deployRemoteCall(TangemPaymentAccount.class, web3j, credentials, gasPrice, gasLimit, BINARY, encodedConstructor); - } - - @Deprecated - public static RemoteCall deploy(Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit, String trustedForwarder) { - String encodedConstructor = FunctionEncoder.encodeConstructor(List.of(new Address(160, trustedForwarder))); - return deployRemoteCall(TangemPaymentAccount.class, web3j, transactionManager, gasPrice, gasLimit, BINARY, encodedConstructor); - } - - public Flowable accountStateAfterSettlementEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getAccountStateAfterSettlementEventFromLog(log)); - } - - public Flowable accountStateAfterSettlementEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public Flowable ownerSetEventFlowable(DefaultBlockParameter startBlock, + DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(ACCOUNTSTATEAFTERSETTLEMENT_EVENT)); - return accountStateAfterSettlementEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(OWNERSET_EVENT)); + return ownerSetEventFlowable(filter); } - public Flowable cardSetEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getCardSetEventFromLog(log)); - } - - public Flowable cardSetEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(CARDSET_EVENT)); - return cardSetEventFlowable(filter); - } - - public static List getPendingRefundSavedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(PENDINGREFUNDSAVED_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - PendingRefundSavedEventResponse typedResponse = new PendingRefundSavedEventResponse(); - typedResponse.log = eventValues.getLog(); - typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); - typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); - responses.add(typedResponse); - } - return responses; - } - - public Flowable debtIncreasedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getDebtIncreasedEventFromLog(log)); - } - - public Flowable debtIncreasedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(DEBTINCREASED_EVENT)); - return debtIncreasedEventFlowable(filter); - } - - public Flowable debtPaidEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getDebtPaidEventFromLog(log)); - } - - public static List getProcessorSetEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(PROCESSORSET_EVENT, transactionReceipt); + public static List getProcessorSetEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(PROCESSORSET_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { ProcessorSetEventResponse typedResponse = new ProcessorSetEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.processor = (String) eventValues.getNonIndexedValues().get(0).getValue(); @@ -758,85 +824,147 @@ class TangemPaymentAccount extends Contract { return responses; } - public Flowable debtPaidEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public static ProcessorSetEventResponse getProcessorSetEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(PROCESSORSET_EVENT, log); + ProcessorSetEventResponse typedResponse = new ProcessorSetEventResponse(); + typedResponse.log = log; + typedResponse.processor = (String) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.paymentToken = (String) eventValues.getNonIndexedValues().get(1).getValue(); + return typedResponse; + } + + public Flowable processorSetEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getProcessorSetEventFromLog(log)); + } + + public Flowable processorSetEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(DEBTPAID_EVENT)); - return debtPaidEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(PROCESSORSET_EVENT)); + return processorSetEventFlowable(filter); } - public Flowable debtWrittenOffEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getDebtWrittenOffEventFromLog(log)); - } - - public Flowable debtWrittenOffEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(DEBTWRITTENOFF_EVENT)); - return debtWrittenOffEventFlowable(filter); - } - - public static List getRefundPaidEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(REFUNDPAID_EVENT, transactionReceipt); + public static List getRefundPaidEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(REFUNDPAID_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { RefundPaidEventResponse typedResponse = new RefundPaidEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); responses.add(typedResponse); } return responses; } - public Flowable eIP712DomainChangedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getEIP712DomainChangedEventFromLog(log)); + public static RefundPaidEventResponse getRefundPaidEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(REFUNDPAID_EVENT, log); + RefundPaidEventResponse typedResponse = new RefundPaidEventResponse(); + typedResponse.log = log; + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; } - public Flowable eIP712DomainChangedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public Flowable refundPaidEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getRefundPaidEventFromLog(log)); + } + + public Flowable refundPaidEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(EIP712DOMAINCHANGED_EVENT)); - return eIP712DomainChangedEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(REFUNDPAID_EVENT)); + return refundPaidEventFlowable(filter); } - public Flowable initializedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getInitializedEventFromLog(log)); - } - - public static List getTransactionAmountChangedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(TRANSACTIONAMOUNTCHANGED_EVENT, transactionReceipt); + public static List getTransactionAmountChangedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(TRANSACTIONAMOUNTCHANGED_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { TransactionAmountChangedEventResponse typedResponse = new TransactionAmountChangedEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); typedResponse.newAmount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); responses.add(typedResponse); } return responses; } - public Flowable initializedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public static TransactionAmountChangedEventResponse getTransactionAmountChangedEventFromLog( + Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(TRANSACTIONAMOUNTCHANGED_EVENT, log); + TransactionAmountChangedEventResponse typedResponse = new TransactionAmountChangedEventResponse(); + typedResponse.log = log; + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.newAmount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; + } + + public Flowable transactionAmountChangedEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getTransactionAmountChangedEventFromLog(log)); + } + + public Flowable transactionAmountChangedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(INITIALIZED_EVENT)); - return initializedEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(TRANSACTIONAMOUNTCHANGED_EVENT)); + return transactionAmountChangedEventFlowable(filter); } - public Flowable insufficientFundsOnForcedAuthEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getInsufficientFundsOnForcedAuthEventFromLog(log)); - } - - public Flowable insufficientFundsOnForcedAuthEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(INSUFFICIENTFUNDSONFORCEDAUTH_EVENT)); - return insufficientFundsOnForcedAuthEventFlowable(filter); - } - - public static List getTransactionAuthorizedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(TRANSACTIONAUTHORIZED_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - TransactionAuthorizedEventResponse typedResponse = new TransactionAuthorizedEventResponse(); + public static List getTransactionAuthorizedNoConfirmationEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(TRANSACTIONAUTHORIZEDNOCONFIRMATION_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + TransactionAuthorizedNoConfirmationEventResponse typedResponse = new TransactionAuthorizedNoConfirmationEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public static TransactionAuthorizedNoConfirmationEventResponse getTransactionAuthorizedNoConfirmationEventFromLog( + Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(TRANSACTIONAUTHORIZEDNOCONFIRMATION_EVENT, log); + TransactionAuthorizedNoConfirmationEventResponse typedResponse = new TransactionAuthorizedNoConfirmationEventResponse(); + typedResponse.log = log; + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; + } + + public Flowable transactionAuthorizedNoConfirmationEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getTransactionAuthorizedNoConfirmationEventFromLog(log)); + } + + public Flowable transactionAuthorizedNoConfirmationEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(TRANSACTIONAUTHORIZEDNOCONFIRMATION_EVENT)); + return transactionAuthorizedNoConfirmationEventFlowable(filter); + } + + public static List getTransactionAuthorizedWithOtpEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(TRANSACTIONAUTHORIZEDWITHOTP_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + TransactionAuthorizedWithOtpEventResponse typedResponse = new TransactionAuthorizedWithOtpEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); typedResponse.otp = (byte[]) eventValues.getNonIndexedValues().get(1).getValue(); typedResponse.otpCounter = (BigInteger) eventValues.getNonIndexedValues().get(2).getValue(); @@ -845,27 +973,80 @@ class TangemPaymentAccount extends Contract { return responses; } - public Flowable limitsSetEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getLimitsSetEventFromLog(log)); + public static TransactionAuthorizedWithOtpEventResponse getTransactionAuthorizedWithOtpEventFromLog( + Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(TRANSACTIONAUTHORIZEDWITHOTP_EVENT, log); + TransactionAuthorizedWithOtpEventResponse typedResponse = new TransactionAuthorizedWithOtpEventResponse(); + typedResponse.log = log; + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.otp = (byte[]) eventValues.getNonIndexedValues().get(1).getValue(); + typedResponse.otpCounter = (BigInteger) eventValues.getNonIndexedValues().get(2).getValue(); + return typedResponse; } - public Flowable limitsSetEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public Flowable transactionAuthorizedWithOtpEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getTransactionAuthorizedWithOtpEventFromLog(log)); + } + + public Flowable transactionAuthorizedWithOtpEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(LIMITSSET_EVENT)); - return limitsSetEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(TRANSACTIONAUTHORIZEDWITHOTP_EVENT)); + return transactionAuthorizedWithOtpEventFlowable(filter); } - public Flowable noOtpTransactionAuthorizedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getNoOtpTransactionAuthorizedEventFromLog(log)); + public static List getTransactionAuthorizedWithSignatureEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(TRANSACTIONAUTHORIZEDWITHSIGNATURE_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + TransactionAuthorizedWithSignatureEventResponse typedResponse = new TransactionAuthorizedWithSignatureEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.signature = (byte[]) eventValues.getNonIndexedValues().get(1).getValue(); + responses.add(typedResponse); + } + return responses; } - public static List getTransactionSettledEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(TRANSACTIONSETTLED_EVENT, transactionReceipt); + public static TransactionAuthorizedWithSignatureEventResponse getTransactionAuthorizedWithSignatureEventFromLog( + Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(TRANSACTIONAUTHORIZEDWITHSIGNATURE_EVENT, log); + TransactionAuthorizedWithSignatureEventResponse typedResponse = new TransactionAuthorizedWithSignatureEventResponse(); + typedResponse.log = log; + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.signature = (byte[]) eventValues.getNonIndexedValues().get(1).getValue(); + return typedResponse; + } + + public Flowable transactionAuthorizedWithSignatureEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getTransactionAuthorizedWithSignatureEventFromLog(log)); + } + + public Flowable transactionAuthorizedWithSignatureEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(TRANSACTIONAUTHORIZEDWITHSIGNATURE_EVENT)); + return transactionAuthorizedWithSignatureEventFlowable(filter); + } + + public static List getTransactionSettledEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(TRANSACTIONSETTLED_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { TransactionSettledEventResponse typedResponse = new TransactionSettledEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); typedResponse.settlementAmount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); typedResponse.paymentAmount = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); responses.add(typedResponse); @@ -873,53 +1054,72 @@ class TangemPaymentAccount extends Contract { return responses; } - public Flowable noOtpTransactionAuthorizedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public static TransactionSettledEventResponse getTransactionSettledEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(TRANSACTIONSETTLED_EVENT, log); + TransactionSettledEventResponse typedResponse = new TransactionSettledEventResponse(); + typedResponse.log = log; + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.settlementAmount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.paymentAmount = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); + return typedResponse; + } + + public Flowable transactionSettledEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getTransactionSettledEventFromLog(log)); + } + + public Flowable transactionSettledEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(NOOTPTRANSACTIONAUTHORIZED_EVENT)); - return noOtpTransactionAuthorizedEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(TRANSACTIONSETTLED_EVENT)); + return transactionSettledEventFlowable(filter); } - public Flowable otpStateSetEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getOtpStateSetEventFromLog(log)); - } - - public Flowable otpStateSetEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(OTPSTATESET_EVENT)); - return otpStateSetEventFlowable(filter); - } - - public static List getUnsettledTransactionUnblockedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(UNSETTLEDTRANSACTIONUNBLOCKED_EVENT, transactionReceipt); + public static List getUnsettledTransactionUnblockedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(UNSETTLEDTRANSACTIONUNBLOCKED_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { UnsettledTransactionUnblockedEventResponse typedResponse = new UnsettledTransactionUnblockedEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); responses.add(typedResponse); } return responses; } - public Flowable ownerSetEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getOwnerSetEventFromLog(log)); + public static UnsettledTransactionUnblockedEventResponse getUnsettledTransactionUnblockedEventFromLog( + Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(UNSETTLEDTRANSACTIONUNBLOCKED_EVENT, log); + UnsettledTransactionUnblockedEventResponse typedResponse = new UnsettledTransactionUnblockedEventResponse(); + typedResponse.log = log; + typedResponse.transactionId = (BigInteger) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; } - public Flowable ownerSetEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public Flowable unsettledTransactionUnblockedEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getUnsettledTransactionUnblockedEventFromLog(log)); + } + + public Flowable unsettledTransactionUnblockedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(OWNERSET_EVENT)); - return ownerSetEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(UNSETTLEDTRANSACTIONUNBLOCKED_EVENT)); + return unsettledTransactionUnblockedEventFlowable(filter); } - public Flowable pendingRefundSavedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getPendingRefundSavedEventFromLog(log)); - } - - public static List getUpgradedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(UPGRADED_EVENT, transactionReceipt); + public static List getUpgradedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(UPGRADED_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { UpgradedEventResponse typedResponse = new UpgradedEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.implementation = (String) eventValues.getIndexedValues().get(0).getValue(); @@ -928,26 +1128,30 @@ class TangemPaymentAccount extends Contract { return responses; } - public Flowable pendingRefundSavedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public static UpgradedEventResponse getUpgradedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(UPGRADED_EVENT, log); + UpgradedEventResponse typedResponse = new UpgradedEventResponse(); + typedResponse.log = log; + typedResponse.implementation = (String) eventValues.getIndexedValues().get(0).getValue(); + return typedResponse; + } + + public Flowable upgradedEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getUpgradedEventFromLog(log)); + } + + public Flowable upgradedEventFlowable(DefaultBlockParameter startBlock, + DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(PENDINGREFUNDSAVED_EVENT)); - return pendingRefundSavedEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(UPGRADED_EVENT)); + return upgradedEventFlowable(filter); } - public Flowable processorSetEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getProcessorSetEventFromLog(log)); - } - - public Flowable processorSetEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(PROCESSORSET_EVENT)); - return processorSetEventFlowable(filter); - } - - public static List getVerifiedBalanceIncreasedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(VERIFIEDBALANCEINCREASED_EVENT, transactionReceipt); + public static List getVerifiedBalanceIncreasedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(VERIFIEDBALANCEINCREASED_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { VerifiedBalanceIncreasedEventResponse typedResponse = new VerifiedBalanceIncreasedEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.increase = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); @@ -957,24 +1161,33 @@ class TangemPaymentAccount extends Contract { return responses; } - public Flowable refundPaidEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getRefundPaidEventFromLog(log)); + public static VerifiedBalanceIncreasedEventResponse getVerifiedBalanceIncreasedEventFromLog( + Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(VERIFIEDBALANCEINCREASED_EVENT, log); + VerifiedBalanceIncreasedEventResponse typedResponse = new VerifiedBalanceIncreasedEventResponse(); + typedResponse.log = log; + typedResponse.increase = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.verifiedBalance = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); + return typedResponse; } - public Flowable refundPaidEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public Flowable verifiedBalanceIncreasedEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getVerifiedBalanceIncreasedEventFromLog(log)); + } + + public Flowable verifiedBalanceIncreasedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(REFUNDPAID_EVENT)); - return refundPaidEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(VERIFIEDBALANCEINCREASED_EVENT)); + return verifiedBalanceIncreasedEventFlowable(filter); } - public Flowable transactionAmountChangedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getTransactionAmountChangedEventFromLog(log)); - } - - public static List getVerifiedBalanceSetEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(VERIFIEDBALANCESET_EVENT, transactionReceipt); + public static List getVerifiedBalanceSetEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(VERIFIEDBALANCESET_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { VerifiedBalanceSetEventResponse typedResponse = new VerifiedBalanceSetEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.verifiedBalance = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); @@ -983,51 +1196,66 @@ class TangemPaymentAccount extends Contract { return responses; } - public Flowable transactionAmountChangedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public static VerifiedBalanceSetEventResponse getVerifiedBalanceSetEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(VERIFIEDBALANCESET_EVENT, log); + VerifiedBalanceSetEventResponse typedResponse = new VerifiedBalanceSetEventResponse(); + typedResponse.log = log; + typedResponse.verifiedBalance = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; + } + + public Flowable verifiedBalanceSetEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getVerifiedBalanceSetEventFromLog(log)); + } + + public Flowable verifiedBalanceSetEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(TRANSACTIONAMOUNTCHANGED_EVENT)); - return transactionAmountChangedEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(VERIFIEDBALANCESET_EVENT)); + return verifiedBalanceSetEventFlowable(filter); } - public Flowable transactionAuthorizedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getTransactionAuthorizedEventFromLog(log)); - } - - public Flowable transactionAuthorizedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(TRANSACTIONAUTHORIZED_EVENT)); - return transactionAuthorizedEventFlowable(filter); - } - - public static List getWithdrawalCanceledEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(WITHDRAWALCANCELED_EVENT, transactionReceipt); + public static List getWithdrawalCanceledEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(WITHDRAWALCANCELED_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { WithdrawalCanceledEventResponse typedResponse = new WithdrawalCanceledEventResponse(); typedResponse.log = eventValues.getLog(); + typedResponse.to = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); responses.add(typedResponse); } return responses; } - public Flowable transactionSettledEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getTransactionSettledEventFromLog(log)); + public static WithdrawalCanceledEventResponse getWithdrawalCanceledEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(WITHDRAWALCANCELED_EVENT, log); + WithdrawalCanceledEventResponse typedResponse = new WithdrawalCanceledEventResponse(); + typedResponse.log = log; + typedResponse.to = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; } - public Flowable transactionSettledEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public Flowable withdrawalCanceledEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getWithdrawalCanceledEventFromLog(log)); + } + + public Flowable withdrawalCanceledEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(TRANSACTIONSETTLED_EVENT)); - return transactionSettledEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(WITHDRAWALCANCELED_EVENT)); + return withdrawalCanceledEventFlowable(filter); } - public Flowable unsettledTransactionUnblockedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getUnsettledTransactionUnblockedEventFromLog(log)); - } - - public static List getWithdrawalCompleteEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(WITHDRAWALCOMPLETE_EVENT, transactionReceipt); + public static List getWithdrawalCompleteEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(WITHDRAWALCOMPLETE_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { WithdrawalCompleteEventResponse typedResponse = new WithdrawalCompleteEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.to = (String) eventValues.getIndexedValues().get(0).getValue(); @@ -1037,28 +1265,35 @@ class TangemPaymentAccount extends Contract { return responses; } - public Flowable unsettledTransactionUnblockedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public static WithdrawalCompleteEventResponse getWithdrawalCompleteEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(WITHDRAWALCOMPLETE_EVENT, log); + WithdrawalCompleteEventResponse typedResponse = new WithdrawalCompleteEventResponse(); + typedResponse.log = log; + typedResponse.to = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; + } + + public Flowable withdrawalCompleteEventFlowable( + EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getWithdrawalCompleteEventFromLog(log)); + } + + public Flowable withdrawalCompleteEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(UNSETTLEDTRANSACTIONUNBLOCKED_EVENT)); - return unsettledTransactionUnblockedEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(WITHDRAWALCOMPLETE_EVENT)); + return withdrawalCompleteEventFlowable(filter); } - public Flowable upgradedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getUpgradedEventFromLog(log)); - } - - public Flowable upgradedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(UPGRADED_EVENT)); - return upgradedEventFlowable(filter); - } - - public static List getWithdrawalInitiatedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(WITHDRAWALINITIATED_EVENT, transactionReceipt); + public static List getWithdrawalInitiatedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(WITHDRAWALINITIATED_EVENT, transactionReceipt); ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { + for (Contract.EventValuesWithLog eventValues : valueList) { WithdrawalInitiatedEventResponse typedResponse = new WithdrawalInitiatedEventResponse(); typedResponse.log = eventValues.getLog(); + typedResponse.to = (String) eventValues.getIndexedValues().get(0).getValue(); typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); typedResponse.readyToWithdrawTimestamp = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); responses.add(typedResponse); @@ -1067,175 +1302,176 @@ class TangemPaymentAccount extends Contract { } public static WithdrawalInitiatedEventResponse getWithdrawalInitiatedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(WITHDRAWALINITIATED_EVENT, log); + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(WITHDRAWALINITIATED_EVENT, log); WithdrawalInitiatedEventResponse typedResponse = new WithdrawalInitiatedEventResponse(); typedResponse.log = log; + typedResponse.to = (String) eventValues.getIndexedValues().get(0).getValue(); typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); typedResponse.readyToWithdrawTimestamp = (BigInteger) eventValues.getNonIndexedValues().get(1).getValue(); return typedResponse; } - public Flowable withdrawalInitiatedEventFlowable(EthFilter filter) { + public Flowable withdrawalInitiatedEventFlowable( + EthFilter filter) { return web3j.ethLogFlowable(filter).map(log -> getWithdrawalInitiatedEventFromLog(log)); } - public Flowable withdrawalInitiatedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public Flowable withdrawalInitiatedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); filter.addSingleTopic(EventEncoder.encode(WITHDRAWALINITIATED_EVENT)); return withdrawalInitiatedEventFlowable(filter); } - public Flowable verifiedBalanceIncreasedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getVerifiedBalanceIncreasedEventFromLog(log)); - } - - public Flowable verifiedBalanceIncreasedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(VERIFIEDBALANCEINCREASED_EVENT)); - return verifiedBalanceIncreasedEventFlowable(filter); - } - - public Flowable verifiedBalanceSetEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getVerifiedBalanceSetEventFromLog(log)); - } - - public Flowable verifiedBalanceSetEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(VERIFIEDBALANCESET_EVENT)); - return verifiedBalanceSetEventFlowable(filter); - } - - public Flowable withdrawalCanceledEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getWithdrawalCanceledEventFromLog(log)); - } - - public Flowable withdrawalCanceledEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(WITHDRAWALCANCELED_EVENT)); - return withdrawalCanceledEventFlowable(filter); - } - - public Flowable withdrawalCompleteEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getWithdrawalCompleteEventFromLog(log)); - } - - public Flowable withdrawalCompleteEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(WITHDRAWALCOMPLETE_EVENT)); - return withdrawalCompleteEventFlowable(filter); - } - public RemoteFunctionCall UPGRADE_INTERFACE_VERSION() { final Function function = new Function(FUNC_UPGRADE_INTERFACE_VERSION, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, String.class); } - public RemoteFunctionCall> authorizedTransactions(BigInteger param0) { - final Function function = new Function(FUNC_AUTHORIZEDTRANSACTIONS, - List.of(new Uint256(param0)), - Arrays.asList(new TypeReference() { - }, new TypeReference() { - }, new TypeReference() { - })); - return new RemoteFunctionCall>(function, - new Callable>() { + public RemoteFunctionCall activeCardAddresses() { + final Function function = new Function(FUNC_ACTIVECARDADDRESSES, + Arrays.asList(), + Arrays.>asList(new TypeReference>() {})); + return new RemoteFunctionCall(function, + new Callable() { @Override - public Tuple3 call() throws Exception { + @SuppressWarnings("unchecked") + public List call() throws Exception { + List result = (List) executeCallSingleValueReturn(function, List.class); + return convertToNative(result); + } + }); + } + + public RemoteFunctionCall addCard(String cardAddress, CardParams cardParams, + byte[] ownershipAcceptanceSignature, byte[] cardConfirmationSignature) { + final Function function = new Function( + FUNC_ADDCARD, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, cardAddress), + cardParams, + new org.web3j.abi.datatypes.DynamicBytes(ownershipAcceptanceSignature), + new org.web3j.abi.datatypes.DynamicBytes(cardConfirmationSignature)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + public RemoteFunctionCall authLimitMargin() { + final Function function = new Function(FUNC_AUTHLIMITMARGIN, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + return executeRemoteCallSingleValueReturn(function, BigInteger.class); + } + + public RemoteFunctionCall> authorizedTransactions( + BigInteger param0) { + final Function function = new Function(FUNC_AUTHORIZEDTRANSACTIONS, + Arrays.asList(new org.web3j.abi.datatypes.generated.Uint256(param0)), + Arrays.>asList(new TypeReference() {}, new TypeReference
() {}, new TypeReference() {}, new TypeReference() {})); + return new RemoteFunctionCall>(function, + new Callable>() { + @Override + public Tuple4 call() throws Exception { List results = executeCallMultipleValueReturn(function); - return new Tuple3( + return new Tuple4( (BigInteger) results.get(0).getValue(), - (BigInteger) results.get(1).getValue(), - (Boolean) results.get(2).getValue()); + (String) results.get(1).getValue(), + (BigInteger) results.get(2).getValue(), + (Boolean) results.get(3).getValue()); } }); } public RemoteFunctionCall availableForDebtPayment() { final Function function = new Function(FUNC_AVAILABLEFORDEBTPAYMENT, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public RemoteFunctionCall availableForPayment() { final Function function = new Function(FUNC_AVAILABLEFORPAYMENT, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public RemoteFunctionCall availableForWithdrawal() { final Function function = new Function(FUNC_AVAILABLEFORWITHDRAWAL, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public RemoteFunctionCall blockedAmount() { final Function function = new Function(FUNC_BLOCKEDAMOUNT, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public RemoteFunctionCall cancelWithdrawal() { final Function function = new Function( FUNC_CANCELWITHDRAWAL, - List.of(), - Collections.emptyList()); + Arrays.asList(), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall> cardWithOtp() { - final Function function = new Function(FUNC_CARDWITHOTP, - List.of(), - Arrays.asList(new TypeReference() { - }, new TypeReference() { - }, new TypeReference() { - })); - return new RemoteFunctionCall>(function, - new Callable>() { + public RemoteFunctionCall cardConfirmationNonce() { + final Function function = new Function(FUNC_CARDCONFIRMATIONNONCE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + return executeRemoteCallSingleValueReturn(function, BigInteger.class); + } + + public RemoteFunctionCall> cards( + String param0) { + final Function function = new Function(FUNC_CARDS, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, param0)), + Arrays.>asList(new TypeReference() {}, new TypeReference() {}, new TypeReference() {}, new TypeReference() {}, new TypeReference() {})); + return new RemoteFunctionCall>(function, + new Callable>() { @Override - public Tuple3 call() throws Exception { + public Tuple5 call( + ) throws Exception { List results = executeCallMultipleValueReturn(function); - return new Tuple3( - (CardWithOtp) results.get(0), - (CardWithOtp) results.get(1), - (BigInteger) results.get(2).getValue()); + return new Tuple5( + (Boolean) results.get(0).getValue(), + (Boolean) results.get(1).getValue(), + (BigInteger) results.get(2).getValue(), + (OtpStateSetting) results.get(3), + (LimitsSetting) results.get(4)); } }); } public RemoteFunctionCall debtAmount() { final Function function = new Function(FUNC_DEBTAMOUNT, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } - public RemoteFunctionCall>> eip712Domain() { + public RemoteFunctionCall disableCard(String card) { + final Function function = new Function( + FUNC_DISABLECARD, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, card)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + public RemoteFunctionCall>> eip712Domain( + ) { final Function function = new Function(FUNC_EIP712DOMAIN, - List.of(), - Arrays.asList(new TypeReference() { - }, new TypeReference() { - }, new TypeReference() { - }, new TypeReference() { - }, new TypeReference
() { - }, new TypeReference() { - }, new TypeReference>() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {}, new TypeReference() {}, new TypeReference() {}, new TypeReference() {}, new TypeReference
() {}, new TypeReference() {}, new TypeReference>() {})); return new RemoteFunctionCall>>(function, new Callable>>() { @Override - public Tuple7> call() throws Exception { + public Tuple7> call( + ) throws Exception { List results = executeCallMultipleValueReturn(function); return new Tuple7>( (byte[]) results.get(0).getValue(), @@ -1249,369 +1485,427 @@ class TangemPaymentAccount extends Contract { }); } + public RemoteFunctionCall enableCard(String card, Boolean isOwner, + byte[] ownershipAcceptanceSignature, byte[] cardConfirmationSignature) { + final Function function = new Function( + FUNC_ENABLECARD, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.Bool(isOwner), + new org.web3j.abi.datatypes.DynamicBytes(ownershipAcceptanceSignature), + new org.web3j.abi.datatypes.DynamicBytes(cardConfirmationSignature)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + public RemoteFunctionCall factory() { final Function function = new Function(FUNC_FACTORY, - List.of(), - List.of(new TypeReference
() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); return executeRemoteCallSingleValueReturn(function, String.class); } public RemoteFunctionCall increaseVerifiedBalance(BigInteger increase) { final Function function = new Function( FUNC_INCREASEVERIFIEDBALANCE, - List.of(new Uint256(increase)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.generated.Uint256(increase)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall initWithdrawal(BigInteger amount) { + public RemoteFunctionCall initWithdrawal(String to, BigInteger amount) { final Function function = new Function( FUNC_INITWITHDRAWAL, - List.of(new Uint256(amount)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, to), + new org.web3j.abi.datatypes.generated.Uint256(amount)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall initialize(String owner_, String registry_, BigInteger singleTransactionLimit, BigInteger spendLimit, BigInteger noOtpSpendLimit, BigInteger spendLimitsPeriod) { + public RemoteFunctionCall initialize(String owner_, String processor_, + String registry_, String cardAddress, CardParams cardParams, + BigInteger authLimitMargin_) { final Function function = new Function( FUNC_INITIALIZE, - Arrays.asList(new Address(160, owner_), - new Address(160, registry_), - new Uint256(singleTransactionLimit), - new Uint256(spendLimit), - new Uint256(noOtpSpendLimit), - new Uint256(spendLimitsPeriod)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, owner_), + new org.web3j.abi.datatypes.Address(160, processor_), + new org.web3j.abi.datatypes.Address(160, registry_), + new org.web3j.abi.datatypes.Address(160, cardAddress), + cardParams, + new org.web3j.abi.datatypes.generated.Uint256(authLimitMargin_)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall isTrustedForwarder(String forwarder) { final Function function = new Function(FUNC_ISTRUSTEDFORWARDER, - List.of(new Address(160, forwarder)), - List.of(new TypeReference() { - })); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, forwarder)), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, Boolean.class); } public RemoteFunctionCall isWithdrawalInProgress() { final Function function = new Function(FUNC_ISWITHDRAWALINPROGRESS, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, Boolean.class); } public RemoteFunctionCall isWithdrawalReady() { final Function function = new Function(FUNC_ISWITHDRAWALREADY, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, Boolean.class); } - public RemoteFunctionCall> limits() { - final Function function = new Function(FUNC_LIMITS, - List.of(), - Arrays.asList(new TypeReference() { - }, new TypeReference() { - }, new TypeReference() { - })); - return new RemoteFunctionCall>(function, - new Callable>() { - @Override - public Tuple3 call() throws Exception { - List results = executeCallMultipleValueReturn(function); - return new Tuple3( - (Limits) results.get(0), - (Limits) results.get(1), - (BigInteger) results.get(2).getValue()); - } - }); - } - public RemoteFunctionCall owner() { final Function function = new Function(FUNC_OWNER, - List.of(), - List.of(new TypeReference
() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); return executeRemoteCallSingleValueReturn(function, String.class); } public RemoteFunctionCall ownershipAcceptanceNonce() { final Function function = new Function(FUNC_OWNERSHIPACCEPTANCENONCE, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } + public RemoteFunctionCall payDebt(BigInteger amount) { + final Function function = new Function( + FUNC_PAYDEBT, + Arrays.asList(new org.web3j.abi.datatypes.generated.Uint256(amount)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + public RemoteFunctionCall paymentToken() { final Function function = new Function(FUNC_PAYMENTTOKEN, - List.of(), - List.of(new TypeReference
() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); return executeRemoteCallSingleValueReturn(function, String.class); } - public RemoteFunctionCall pendingRefundAmount(BigInteger transactionId) { - final Function function = new Function(FUNC_PENDINGREFUNDAMOUNT, - List.of(new Uint256(transactionId)), - List.of(new TypeReference() { - })); - return executeRemoteCallSingleValueReturn(function, BigInteger.class); - } - - public RemoteFunctionCall pendingRefundTotal() { - final Function function = new Function(FUNC_PENDINGREFUNDTOTAL, - List.of(), - List.of(new TypeReference() { - })); - return executeRemoteCallSingleValueReturn(function, BigInteger.class); - } - - public RemoteFunctionCall processAuthorization(BigInteger transactionId, BigInteger amount, byte[] otp, BigInteger otpCounter, Boolean forced) { - final Function function = new Function( - FUNC_PROCESSAUTHORIZATION, - Arrays.asList(new Uint256(transactionId), - new Uint256(amount), - new Bytes16(otp), - new Uint16(otpCounter), - new Bool(forced)), - Collections.emptyList()); - return executeRemoteCallTransaction(function); - } - - public RemoteFunctionCall processAuthorizationChange(BigInteger transactionId, BigInteger newAmount) { + public RemoteFunctionCall processAuthorizationChange(String card, + BigInteger transactionId, BigInteger newAmount) { final Function function = new Function( FUNC_PROCESSAUTHORIZATIONCHANGE, - Arrays.asList(new Uint256(transactionId), - new Uint256(newAmount)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(transactionId), + new org.web3j.abi.datatypes.generated.Uint256(newAmount)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall processAuthorizationNoOtp(BigInteger transactionId, BigInteger amount, Boolean forced) { - final Function function = new Function( - FUNC_PROCESSAUTHORIZATIONNOOTP, - Arrays.asList(new Uint256(transactionId), - new Uint256(amount), - new Bool(forced)), - Collections.emptyList()); - return executeRemoteCallTransaction(function); - } - - public RemoteFunctionCall processDebt(BigInteger amount) { + public RemoteFunctionCall processDebt(String card, BigInteger amount) { final Function function = new Function( FUNC_PROCESSDEBT, - List.of(new Uint256(amount)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(amount)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall processPendingRefundPayment(BigInteger transactionId) { + public RemoteFunctionCall processNoConfirmationAuthorization(String card, + BigInteger transactionId, BigInteger amount, Boolean forced) { final Function function = new Function( - FUNC_PROCESSPENDINGREFUNDPAYMENT, - List.of(new Uint256(transactionId)), - Collections.emptyList()); + FUNC_PROCESSNOCONFIRMATIONAUTHORIZATION, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(transactionId), + new org.web3j.abi.datatypes.generated.Uint256(amount), + new org.web3j.abi.datatypes.Bool(forced)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall processRefundPayment(BigInteger transactionId) { + public RemoteFunctionCall processOtpAuthorization(String card, + BigInteger transactionId, BigInteger amount, byte[] otp, BigInteger otpCounter, + Boolean forced) { + final Function function = new Function( + FUNC_PROCESSOTPAUTHORIZATION, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(transactionId), + new org.web3j.abi.datatypes.generated.Uint256(amount), + new org.web3j.abi.datatypes.generated.Bytes16(otp), + new org.web3j.abi.datatypes.generated.Uint16(otpCounter), + new org.web3j.abi.datatypes.Bool(forced)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + public RemoteFunctionCall processRefundPayment(String card, + BigInteger transactionId) { final Function function = new Function( FUNC_PROCESSREFUNDPAYMENT, - List.of(new Uint256(transactionId)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(transactionId)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall processSettlement(BigInteger transactionId, BigInteger amount) { + public RemoteFunctionCall processSettlement(String card, + BigInteger transactionId, BigInteger amount) { final Function function = new Function( FUNC_PROCESSSETTLEMENT, - Arrays.asList(new Uint256(transactionId), - new Uint256(amount)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(transactionId), + new org.web3j.abi.datatypes.generated.Uint256(amount)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall processWithdrawal(String to) { + public RemoteFunctionCall processSignatureAuthorization(String card, + BigInteger transactionId, BigInteger amount, byte[] transactionConfirmationSignature, + Boolean forced) { + final Function function = new Function( + FUNC_PROCESSSIGNATUREAUTHORIZATION, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(transactionId), + new org.web3j.abi.datatypes.generated.Uint256(amount), + new org.web3j.abi.datatypes.DynamicBytes(transactionConfirmationSignature), + new org.web3j.abi.datatypes.Bool(forced)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + public RemoteFunctionCall processUnsettledTransaction(String card, + BigInteger transactionId) { + final Function function = new Function( + FUNC_PROCESSUNSETTLEDTRANSACTION, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.generated.Uint256(transactionId)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + public RemoteFunctionCall processWithdrawal() { final Function function = new Function( FUNC_PROCESSWITHDRAWAL, - List.of(new Address(160, to)), - Collections.emptyList()); + Arrays.asList(), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall processor() { final Function function = new Function(FUNC_PROCESSOR, - List.of(), - List.of(new TypeReference
() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); return executeRemoteCallSingleValueReturn(function, String.class); } public RemoteFunctionCall proxiableUUID() { final Function function = new Function(FUNC_PROXIABLEUUID, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, byte[].class); } public RemoteFunctionCall registry() { final Function function = new Function(FUNC_REGISTRY, - List.of(), - List.of(new TypeReference
() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); return executeRemoteCallSingleValueReturn(function, String.class); } - public RemoteFunctionCall savePendingRefund(BigInteger transactionId, BigInteger amount) { + public RemoteFunctionCall removeOwner() { final Function function = new Function( - FUNC_SAVEPENDINGREFUND, - Arrays.asList(new Uint256(transactionId), - new Uint256(amount)), - Collections.emptyList()); + FUNC_REMOVEOWNER, + Arrays.asList(), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall securityDelay() { final Function function = new Function(FUNC_SECURITYDELAY, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } - public RemoteFunctionCall setCard(String card, byte[] otpRoot, BigInteger otpCounter, byte[] ownershipAcceptanceSignature) { + public RemoteFunctionCall setAuthLimitMargin(BigInteger authLimitMargin_) { final Function function = new Function( - FUNC_SETCARD, - Arrays.asList(new Address(160, card), - new Bytes16(otpRoot), - new Uint16(otpCounter), - new org.web3j.abi.datatypes.DynamicBytes(ownershipAcceptanceSignature)), - Collections.emptyList()); + FUNC_SETAUTHLIMITMARGIN, + Arrays.asList(new org.web3j.abi.datatypes.generated.Uint256(authLimitMargin_)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall setLimits(BigInteger singleTransactionLimit, BigInteger spendLimit, BigInteger noOtpSpendLimit, BigInteger spendLimitsPeriod) { + public RemoteFunctionCall setCardIsOwner(String card, Boolean isOwner) { + final Function function = new Function( + FUNC_SETCARDISOWNER, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.Bool(isOwner)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + public RemoteFunctionCall setLimits(String card, + LimitsParams limitsParams) { final Function function = new Function( FUNC_SETLIMITS, - Arrays.asList(new Uint256(singleTransactionLimit), - new Uint256(spendLimit), - new Uint256(noOtpSpendLimit), - new Uint256(spendLimitsPeriod)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, card), + limitsParams), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall setOtpState(byte[] otp, BigInteger counter) { + public RemoteFunctionCall setOtpState(String card, OtpState otpState) { final Function function = new Function( FUNC_SETOTPSTATE, - Arrays.asList(new Bytes16(otp), - new Uint16(counter)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, card), + otpState), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall setOwner(String owner_, byte[] ownershipAcceptanceSignature) { + public RemoteFunctionCall setOwner(String owner_, + byte[] ownershipAcceptanceSignature) { final Function function = new Function( FUNC_SETOWNER, - Arrays.asList(new Address(160, owner_), + Arrays.asList(new org.web3j.abi.datatypes.Address(160, owner_), new org.web3j.abi.datatypes.DynamicBytes(ownershipAcceptanceSignature)), - Collections.emptyList()); - return executeRemoteCallTransaction(function); - } - - public RemoteFunctionCall setProcessor(String processor_) { - final Function function = new Function( - FUNC_SETPROCESSOR, - List.of(new Address(160, processor_)), - Collections.emptyList()); + Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall setVerifiedBalance(BigInteger verifiedBalance_) { final Function function = new Function( FUNC_SETVERIFIEDBALANCE, - List.of(new Uint256(verifiedBalance_)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.generated.Uint256(verifiedBalance_)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall settlementPeriod() { - final Function function = new Function(FUNC_SETTLEMENTPERIOD, - List.of(), - List.of(new TypeReference() { - })); + public RemoteFunctionCall transactionConfirmationNonce() { + final Function function = new Function(FUNC_TRANSACTIONCONFIRMATIONNONCE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public RemoteFunctionCall trustedForwarder() { final Function function = new Function(FUNC_TRUSTEDFORWARDER, - List.of(), - List.of(new TypeReference
() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); return executeRemoteCallSingleValueReturn(function, String.class); } - public RemoteFunctionCall unblockUnsettledTransaction(BigInteger transactionId) { - final Function function = new Function( - FUNC_UNBLOCKUNSETTLEDTRANSACTION, - List.of(new Uint256(transactionId)), - Collections.emptyList()); - return executeRemoteCallTransaction(function); - } - - public RemoteFunctionCall upgradeToAndCall(String newImplementation, byte[] data, BigInteger weiValue) { + public RemoteFunctionCall upgradeToAndCall(String newImplementation, + byte[] data, BigInteger weiValue) { final Function function = new Function( FUNC_UPGRADETOANDCALL, - Arrays.asList(new Address(160, newImplementation), + Arrays.asList(new org.web3j.abi.datatypes.Address(160, newImplementation), new org.web3j.abi.datatypes.DynamicBytes(data)), - Collections.emptyList()); + Collections.>emptyList()); return executeRemoteCallTransaction(function, weiValue); } public RemoteFunctionCall verifiedBalance() { final Function function = new Function(FUNC_VERIFIEDBALANCE, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } + public RemoteFunctionCall withdrawalAddress() { + final Function function = new Function(FUNC_WITHDRAWALADDRESS, + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); + return executeRemoteCallSingleValueReturn(function, String.class); + } + public RemoteFunctionCall withdrawalAmount() { final Function function = new Function(FUNC_WITHDRAWALAMOUNT, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public RemoteFunctionCall withdrawalReadyTimestamp() { final Function function = new Function(FUNC_WITHDRAWALREADYTIMESTAMP, - List.of(), - List.of(new TypeReference() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, BigInteger.class); } public RemoteFunctionCall writeOffDebt(BigInteger amount) { final Function function = new Function( FUNC_WRITEOFFDEBT, - List.of(new Uint256(amount)), - Collections.emptyList()); + Arrays.asList(new org.web3j.abi.datatypes.generated.Uint256(amount)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } + @Deprecated + public static TangemPaymentAccount load(String contractAddress, Web3j web3j, + Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + return new TangemPaymentAccount(contractAddress, web3j, credentials, gasPrice, gasLimit); + } + + @Deprecated + public static TangemPaymentAccount load(String contractAddress, Web3j web3j, + TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + return new TangemPaymentAccount(contractAddress, web3j, transactionManager, gasPrice, gasLimit); + } + + public static TangemPaymentAccount load(String contractAddress, Web3j web3j, + Credentials credentials, ContractGasProvider contractGasProvider) { + return new TangemPaymentAccount(contractAddress, web3j, credentials, contractGasProvider); + } + + public static TangemPaymentAccount load(String contractAddress, Web3j web3j, + TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + return new TangemPaymentAccount(contractAddress, web3j, transactionManager, contractGasProvider); + } + + public static RemoteCall deploy(Web3j web3j, Credentials credentials, + ContractGasProvider contractGasProvider, String trustedForwarder) { + String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.Address(160, trustedForwarder))); + return deployRemoteCall(TangemPaymentAccount.class, web3j, credentials, contractGasProvider, getDeploymentBinary(), encodedConstructor); + } + + public static RemoteCall deploy(Web3j web3j, + TransactionManager transactionManager, ContractGasProvider contractGasProvider, + String trustedForwarder) { + String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.Address(160, trustedForwarder))); + return deployRemoteCall(TangemPaymentAccount.class, web3j, transactionManager, contractGasProvider, getDeploymentBinary(), encodedConstructor); + } + + @Deprecated + public static RemoteCall deploy(Web3j web3j, Credentials credentials, + BigInteger gasPrice, BigInteger gasLimit, String trustedForwarder) { + String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.Address(160, trustedForwarder))); + return deployRemoteCall(TangemPaymentAccount.class, web3j, credentials, gasPrice, gasLimit, getDeploymentBinary(), encodedConstructor); + } + + @Deprecated + public static RemoteCall deploy(Web3j web3j, + TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit, + String trustedForwarder) { + String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.Address(160, trustedForwarder))); + return deployRemoteCall(TangemPaymentAccount.class, web3j, transactionManager, gasPrice, gasLimit, getDeploymentBinary(), encodedConstructor); + } + + public static void linkLibraries(List references) { + librariesLinkedBinary = linkBinaryWithReferences(BINARY, references); + } + + private static String getDeploymentBinary() { + if (librariesLinkedBinary != null) { + return librariesLinkedBinary; + } else { + return BINARY; + } + } + public static class OtpState extends StaticStruct { public byte[] otp; public BigInteger counter; public OtpState(byte[] otp, BigInteger counter) { - super(new Bytes16(otp), - new Uint16(counter)); + super(new org.web3j.abi.datatypes.generated.Bytes16(otp), + new org.web3j.abi.datatypes.generated.Uint16(counter)); this.otp = otp; this.counter = counter; } @@ -1623,22 +1917,53 @@ class TangemPaymentAccount extends Contract { } } - public static class Limit extends StaticStruct { - public BigInteger _00_limit; + public static class LimitsParams extends StaticStruct { + public BigInteger singleTransactionLimit; - public BigInteger _01_spent; + public BigInteger spendLimit; + + public BigInteger noConfirmationSpendLimit; + + public BigInteger spendLimitsPeriod; + + public LimitsParams(BigInteger singleTransactionLimit, BigInteger spendLimit, + BigInteger noConfirmationSpendLimit, BigInteger spendLimitsPeriod) { + super(new org.web3j.abi.datatypes.generated.Uint256(singleTransactionLimit), + new org.web3j.abi.datatypes.generated.Uint256(spendLimit), + new org.web3j.abi.datatypes.generated.Uint256(noConfirmationSpendLimit), + new org.web3j.abi.datatypes.generated.Uint256(spendLimitsPeriod)); + this.singleTransactionLimit = singleTransactionLimit; + this.spendLimit = spendLimit; + this.noConfirmationSpendLimit = noConfirmationSpendLimit; + this.spendLimitsPeriod = spendLimitsPeriod; + } + + public LimitsParams(Uint256 singleTransactionLimit, Uint256 spendLimit, + Uint256 noConfirmationSpendLimit, Uint256 spendLimitsPeriod) { + super(singleTransactionLimit, spendLimit, noConfirmationSpendLimit, spendLimitsPeriod); + this.singleTransactionLimit = singleTransactionLimit.getValue(); + this.spendLimit = spendLimit.getValue(); + this.noConfirmationSpendLimit = noConfirmationSpendLimit.getValue(); + this.spendLimitsPeriod = spendLimitsPeriod.getValue(); + } + } + + public static class Limit extends StaticStruct { + public BigInteger limit; + + public BigInteger spent; public Limit(BigInteger limit, BigInteger spent) { - super(new Uint256(limit), - new Uint256(spent)); - this._00_limit = limit; - this._01_spent = spent; + super(new org.web3j.abi.datatypes.generated.Uint256(limit), + new org.web3j.abi.datatypes.generated.Uint256(spent)); + this.limit = limit; + this.spent = spent; } public Limit(Uint256 limit, Uint256 spent) { super(limit, spent); - this._00_limit = limit.getValue(); - this._01_spent = spent.getValue(); + this.limit = limit.getValue(); + this.spent = spent.getValue(); } } @@ -1646,7 +1971,7 @@ class TangemPaymentAccount extends Contract { public BigInteger expireTimestamp; public Timer(BigInteger expireTimestamp) { - super(new Uint256(expireTimestamp)); + super(new org.web3j.abi.datatypes.generated.Uint256(expireTimestamp)); this.expireTimestamp = expireTimestamp; } @@ -1656,56 +1981,112 @@ class TangemPaymentAccount extends Contract { } } - public static class CardWithOtp extends StaticStruct { - public String card; + public static class CardParams extends StaticStruct { + public Boolean isOwner; public OtpState otpState; - public CardWithOtp(String card, OtpState otpState) { - super(new Address(160, card), - otpState); - this.card = card; + public LimitsParams limitsParams; + + public CardParams(Boolean isOwner, OtpState otpState, LimitsParams limitsParams) { + super(new org.web3j.abi.datatypes.Bool(isOwner), + otpState, + limitsParams); + this.isOwner = isOwner; this.otpState = otpState; + this.limitsParams = limitsParams; } - public CardWithOtp(Address card, OtpState otpState) { - super(card, otpState); - this.card = card.getValue(); + public CardParams(Bool isOwner, OtpState otpState, LimitsParams limitsParams) { + super(isOwner, otpState, limitsParams); + this.isOwner = isOwner.getValue(); this.otpState = otpState; + this.limitsParams = limitsParams; + } + } + + public static class OtpStateSetting extends StaticStruct { + public OtpState oldValue; + + public OtpState newValue; + + public BigInteger changeTimestamp; + + public OtpStateSetting(OtpState oldValue, OtpState newValue, BigInteger changeTimestamp) { + super(oldValue, + newValue, + new org.web3j.abi.datatypes.generated.Uint256(changeTimestamp)); + this.oldValue = oldValue; + this.newValue = newValue; + this.changeTimestamp = changeTimestamp; + } + + public OtpStateSetting(OtpState oldValue, OtpState newValue, Uint256 changeTimestamp) { + super(oldValue, newValue, changeTimestamp); + this.oldValue = oldValue; + this.newValue = newValue; + this.changeTimestamp = changeTimestamp.getValue(); } } public static class Limits extends StaticStruct { - public BigInteger _00_singleTransactionLimit; + public BigInteger singleTransactionLimit; - public Limit _01_spendLimit; + public Limit spendLimit; - public Limit _02_noOtpSpendLimit; + public Limit noConfirmationSpendLimit; - public Timer _03_spendLimitsTimer; + public Timer spendLimitsTimer; - public BigInteger _04_spendLimitsPeriod; + public BigInteger spendLimitsPeriod; - public Limits(BigInteger singleTransactionLimit, Limit spendLimit, Limit noOtpSpendLimit, Timer spendLimitsTimer, BigInteger spendLimitsPeriod) { - super(new Uint256(singleTransactionLimit), + public Limits(BigInteger singleTransactionLimit, Limit spendLimit, + Limit noConfirmationSpendLimit, Timer spendLimitsTimer, + BigInteger spendLimitsPeriod) { + super(new org.web3j.abi.datatypes.generated.Uint256(singleTransactionLimit), spendLimit, - noOtpSpendLimit, - spendLimitsTimer, - new Uint256(spendLimitsPeriod)); - this._00_singleTransactionLimit = singleTransactionLimit; - this._01_spendLimit = spendLimit; - this._02_noOtpSpendLimit = noOtpSpendLimit; - this._03_spendLimitsTimer = spendLimitsTimer; - this._04_spendLimitsPeriod = spendLimitsPeriod; + noConfirmationSpendLimit, + spendLimitsTimer, + new org.web3j.abi.datatypes.generated.Uint256(spendLimitsPeriod)); + this.singleTransactionLimit = singleTransactionLimit; + this.spendLimit = spendLimit; + this.noConfirmationSpendLimit = noConfirmationSpendLimit; + this.spendLimitsTimer = spendLimitsTimer; + this.spendLimitsPeriod = spendLimitsPeriod; } - public Limits(Uint256 singleTransactionLimit, Limit spendLimit, Limit noOtpSpendLimit, Timer spendLimitsTimer, Uint256 spendLimitsPeriod) { - super(singleTransactionLimit, spendLimit, noOtpSpendLimit, spendLimitsTimer, spendLimitsPeriod); - this._00_singleTransactionLimit = singleTransactionLimit.getValue(); - this._01_spendLimit = spendLimit; - this._02_noOtpSpendLimit = noOtpSpendLimit; - this._03_spendLimitsTimer = spendLimitsTimer; - this._04_spendLimitsPeriod = spendLimitsPeriod.getValue(); + public Limits(Uint256 singleTransactionLimit, Limit spendLimit, + Limit noConfirmationSpendLimit, Timer spendLimitsTimer, Uint256 spendLimitsPeriod) { + super(singleTransactionLimit, spendLimit, noConfirmationSpendLimit, spendLimitsTimer, spendLimitsPeriod); + this.singleTransactionLimit = singleTransactionLimit.getValue(); + this.spendLimit = spendLimit; + this.noConfirmationSpendLimit = noConfirmationSpendLimit; + this.spendLimitsTimer = spendLimitsTimer; + this.spendLimitsPeriod = spendLimitsPeriod.getValue(); + } + } + + public static class LimitsSetting extends StaticStruct { + public Limits oldValue; + + public Limits newValue; + + public BigInteger changeTimestamp; + + public LimitsSetting(Limits oldValue, Limits newValue, BigInteger changeTimestamp) { + super(oldValue, + newValue, + new org.web3j.abi.datatypes.generated.Uint256(changeTimestamp)); + this.oldValue = oldValue; + this.newValue = newValue; + this.changeTimestamp = changeTimestamp; + } + + public LimitsSetting(Limits oldValue, Limits newValue, Uint256 changeTimestamp) { + super(oldValue, newValue, changeTimestamp); + this.oldValue = oldValue; + this.newValue = newValue; + this.changeTimestamp = changeTimestamp.getValue(); } } @@ -1715,16 +2096,26 @@ class TangemPaymentAccount extends Contract { public BigInteger blockedAmount; public BigInteger debtTotal; - - public BigInteger pendingRefundTotal; } - public static class CardSetEventResponse extends BaseEventResponse { + public static class AuthLimitMarginSetEventResponse extends BaseEventResponse { + public BigInteger authLimitMargin; + } + + public static class CardAddedEventResponse extends BaseEventResponse { + public String cardAddress; + + public CardParams cardData; + } + + public static class CardDisabledEventResponse extends BaseEventResponse { + public String card; + } + + public static class CardEnabledEventResponse extends BaseEventResponse { public String card; - public byte[] otpRoot; - - public BigInteger otpCounter; + public Boolean isOwner; } public static class DebtIncreasedEventResponse extends BaseEventResponse { @@ -1755,41 +2146,31 @@ class TangemPaymentAccount extends Contract { public static class InsufficientFundsOnForcedAuthEventResponse extends BaseEventResponse { public BigInteger transactionId; + public String card; + public BigInteger insufficientAmount; } public static class LimitsSetEventResponse extends BaseEventResponse { - public BigInteger singleTransactionLimit; + public String card; - public BigInteger spendLimit; - - public BigInteger noOtpSpendLimit; - - public BigInteger spendLimitsPeriod; - } - - public static class NoOtpTransactionAuthorizedEventResponse extends BaseEventResponse { - public BigInteger transactionId; - - public BigInteger amount; + public LimitsParams limitsParams; } public static class OtpStateSetEventResponse extends BaseEventResponse { - public byte[] otpRoot; + public String card; - public BigInteger otpCounter; + public OtpState otpState; + } + + public static class OwnerRemovedEventResponse extends BaseEventResponse { + public String previousOwner; } public static class OwnerSetEventResponse extends BaseEventResponse { public String owner; } - public static class PendingRefundSavedEventResponse extends BaseEventResponse { - public BigInteger transactionId; - - public BigInteger amount; - } - public static class ProcessorSetEventResponse extends BaseEventResponse { public String processor; @@ -1799,18 +2180,32 @@ class TangemPaymentAccount extends Contract { public static class RefundPaidEventResponse extends BaseEventResponse { public BigInteger transactionId; + public String card; + public BigInteger amount; } public static class TransactionAmountChangedEventResponse extends BaseEventResponse { public BigInteger transactionId; + public String card; + public BigInteger newAmount; } - public static class TransactionAuthorizedEventResponse extends BaseEventResponse { + public static class TransactionAuthorizedNoConfirmationEventResponse extends BaseEventResponse { public BigInteger transactionId; + public String card; + + public BigInteger amount; + } + + public static class TransactionAuthorizedWithOtpEventResponse extends BaseEventResponse { + public BigInteger transactionId; + + public String card; + public BigInteger amount; public byte[] otp; @@ -1818,9 +2213,21 @@ class TangemPaymentAccount extends Contract { public BigInteger otpCounter; } + public static class TransactionAuthorizedWithSignatureEventResponse extends BaseEventResponse { + public BigInteger transactionId; + + public String card; + + public BigInteger amount; + + public byte[] signature; + } + public static class TransactionSettledEventResponse extends BaseEventResponse { public BigInteger transactionId; + public String card; + public BigInteger settlementAmount; public BigInteger paymentAmount; @@ -1829,6 +2236,8 @@ class TangemPaymentAccount extends Contract { public static class UnsettledTransactionUnblockedEventResponse extends BaseEventResponse { public BigInteger transactionId; + public String card; + public BigInteger amount; } @@ -1847,6 +2256,9 @@ class TangemPaymentAccount extends Contract { } public static class WithdrawalCanceledEventResponse extends BaseEventResponse { + public String to; + + public BigInteger amount; } public static class WithdrawalCompleteEventResponse extends BaseEventResponse { @@ -1856,8 +2268,10 @@ class TangemPaymentAccount extends Contract { } public static class WithdrawalInitiatedEventResponse extends BaseEventResponse { + public String to; + public BigInteger amount; public BigInteger readyToWithdrawTimestamp; } -} +} \ No newline at end of file diff --git a/libs/visa/src/main/java/com/tangem/lib/visa/TangemPaymentAccountRegistry.java b/libs/visa/src/main/java/com/tangem/lib/visa/TangemPaymentAccountRegistry.java index bcf93417f6..a5107bee89 100644 --- a/libs/visa/src/main/java/com/tangem/lib/visa/TangemPaymentAccountRegistry.java +++ b/libs/visa/src/main/java/com/tangem/lib/visa/TangemPaymentAccountRegistry.java @@ -1,9 +1,20 @@ package com.tangem.lib.visa; +import io.reactivex.Flowable; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; import org.web3j.abi.EventEncoder; import org.web3j.abi.FunctionEncoder; import org.web3j.abi.TypeReference; -import org.web3j.abi.datatypes.*; +import org.web3j.abi.datatypes.Address; +import org.web3j.abi.datatypes.DynamicArray; +import org.web3j.abi.datatypes.Event; +import org.web3j.abi.datatypes.Function; +import org.web3j.abi.datatypes.Type; import org.web3j.crypto.Credentials; import org.web3j.protocol.Web3j; import org.web3j.protocol.core.DefaultBlockParameter; @@ -17,111 +28,89 @@ import org.web3j.tx.Contract; import org.web3j.tx.TransactionManager; import org.web3j.tx.gas.ContractGasProvider; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.Callable; - -import io.reactivex.Flowable; - /** *

Auto generated code. *

Do not modify! *

Please use the web3j command line tools, * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the - * codegen module to update. + * codegen module to update. * - *

Generated with web3j version 1.5.2. + *

Generated with web3j version 1.6.1. */ @SuppressWarnings("rawtypes") -class TangemPaymentAccountRegistry extends Contract { - public static final String BINARY = "608060405234801561001057600080fd5b50604051610c47380380610c4783398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b610bb4806100936000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c806368d7111a1161005b57806368d7111a146100f0578063747fc3701461010357806379da564f14610116578063c45a01551461013657600080fd5b80630cef7172146100825780633509c7c5146100c85780635cd26737146100dd575b600080fd5b6100ab6100903660046108fd565b6002602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100db6100d6366004610918565b610149565b005b6100db6100eb366004610918565b610201565b6100db6100fe3660046108fd565b6103b0565b6100db610111366004610918565b610506565b6101296101243660046108fd565b6106db565b6040516100bf919061094b565b6000546100ab906001600160a01b031681565b600054604080516080810190915260428082526001600160a01b03909216331491610a576020830139906101995760405162461bcd60e51b81526004016101909190610998565b60405180910390fd5b506001600160a01b03811660009081526001602052604090206101bc9083610705565b50806001600160a01b0316826001600160a01b03167f65b303fd420aefd0541d9300bb10190bb8e3320a0e7c2ce4dec6b6bfb953027f60405160405180910390a35050565b6000546040516385bb392360e01b81523360048201526001600160a01b03909116906385bb392390602401602060405180830381865afa158015610249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061026d91906109e7565b6040518060600160405280603a8152602001610b45603a9139906102a45760405162461bcd60e51b81526004016101909190610998565b506001600160a01b038216600090815260016020526040902033906102c99082610721565b6040518060600160405280603b8152602001610ad0603b9139906103005760405162461bcd60e51b81526004016101909190610998565b506001600160a01b03821660009081526001602052604090206103239082610705565b6040518060600160405280603b8152602001610ad0603b91399061035a5760405162461bcd60e51b81526004016101909190610998565b50604080516001600160a01b03808416825280861660208301528416918101919091527ffba993cae385d1da628b11b1b150a27262bca00bb2674980516b45ad7d331eaa906060015b60405180910390a1505050565b6000546040516385bb392360e01b81523360048201526001600160a01b03909116906385bb392390602401602060405180830381865afa1580156103f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041c91906109e7565b6040518060600160405280603a8152602001610b45603a9139906104535760405162461bcd60e51b81526004016101909190610998565b506001600160a01b0381811660009081526002602090815260409182902054825160608101909352603a8084529316159290610b0b90830139906104aa5760405162461bcd60e51b81526004016101909190610998565b506001600160a01b03811660008181526002602052604080822080546001600160a01b03191633908117909155905190929183917f02e4debb2ab36299bfcc998345f66f73428adbbda9ef5efef399d75a67a4b78a9190a35050565b6000546040516385bb392360e01b81523360048201526001600160a01b03909116906385bb392390602401602060405180830381865afa15801561054e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061057291906109e7565b6040518060600160405280603a8152602001610b45603a9139906105a95760405162461bcd60e51b81526004016101909190610998565b506001600160a01b0382811660009081526002602090815260409182902054825160608101909352603780845233949190911684149291610a9990830139906106055760405162461bcd60e51b81526004016101909190610998565b506001600160a01b0382811660009081526002602090815260409182902054825160608101909352603a8084529316159290610b0b908301399061065c5760405162461bcd60e51b81526004016101909190610998565b506001600160a01b03838116600081815260026020908152604080832080546001600160a01b03199081169091558786168085529382902080549091169587169586179055805194855290840192909252908201527f362e9cf018894fbf5dfe9c5cbfb25c3e3ac8c4d5beed564352f1af2e2712dfc8906060016103a3565b6001600160a01b03811660009081526001602052604090206060906106ff90610736565b92915050565b600061071a836001600160a01b038416610743565b9392505050565b600061071a836001600160a01b038416610792565b6060600061071a83610885565b600081815260018301602052604081205461078a575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556106ff565b5060006106ff565b6000818152600183016020526040812054801561087b5760006107b6600183610a09565b85549091506000906107ca90600190610a09565b905080821461082f5760008660000182815481106107ea576107ea610a2a565b906000526020600020015490508087600001848154811061080d5761080d610a2a565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061084057610840610a40565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506106ff565b60009150506106ff565b6060816000018054806020026020016040519081016040528092919081815260200182805480156108d557602002820191906000526020600020905b8154815260200190600101908083116108c1575b50505050509050919050565b80356001600160a01b03811681146108f857600080fd5b919050565b60006020828403121561090f57600080fd5b61071a826108e1565b6000806040838503121561092b57600080fd5b610934836108e1565b9150610942602084016108e1565b90509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561098c5783516001600160a01b031683529284019291840191600101610967565b50909695505050505050565b60006020808352835180602085015260005b818110156109c6578581018301518582016040015282016109aa565b506000604082860101526040601f19601f8301168501019250505092915050565b6000602082840312156109f957600080fd5b8151801515811461071a57600080fd5b818103818111156106ff57634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fdfe353630307c52656769737472793a206f6e6c79207061796d656e74206163636f756e7420666163746f72792063616e2063616c6c20746869732066756e6374696f6e353630347c52656769737472793a2070726576696f757320636172642773207061796d656e74206163636f756e74206d69736d61746368353630327c52656769737472793a207061796d656e74206163636f756e74206265696e672072656d6f766564206e6f7420696e2074686520736574353630347c52656769737472793a207061796d656e74206163636f756e7420697320616c72656164792073657420666f72207468652063617264353630317c52656769737472793a206f6e6c79207061796d656e74206163636f756e742063616e2063616c6c20746869732066756e6374696f6ea26469706673582212203c97923f6f14a45f904087dcdced3b09f33cd32821438cd9cbf0add5824acaf064736f6c63430008160033"; +public class TangemPaymentAccountRegistry extends Contract { + public static final String BINARY = "60806040523462000030576200001e62000018620000d3565b62000156565b6040516110ab6200016e82396110ab90f35b600080fd5b634e487b7160e01b600052604160045260246000fd5b90601f01601f191681019081106001600160401b038211176200006d57604052565b62000035565b906200008a6200008260405190565b92836200004b565b565b6001600160a01b031690565b90565b6001600160a01b038116036200003057565b905051906200008a826200009b565b9060208282031262000030576200009891620000ad565b620000986200121980380380620000ea8162000073565b928339810190620000bc565b62000098906200008c906001600160a01b031682565b6200009890620000f6565b62000098906200010c565b906200013662000098620001529262000117565b82546001600160a01b0319166001600160a01b03919091161790565b9055565b620001656200008a9162000117565b60006200012256fe6080604052600436101561001257600080fd5b60003560e01c80630cef7172146100b25780630d009297146100ad578063173825d9146100a85780633dc50952146100a35780634149177b1461009e57806379da564f14610099578063a727bc9014610094578063c45a01551461008f578063f00d4b5d1461008a5763f72a1107036100d857610353565b61033a565b610313565b6102cb565b610281565b6101f5565b6101dd565b6101c5565b6101a8565b61016f565b6001600160a01b031690565b90565b6001600160a01b0381165b036100d857565b600080fd5b905035906100ea826100c6565b565b906020828203126100d8576100c3916100dd565b6100c3906100b7906001600160a01b031682565b6100c390610100565b6100c390610114565b906101309061011d565b600052602052604060002090565b6100c3916008021c6100b7565b906100c3915461013e565b60006101666100c3926002610126565b61014b565b9052565b346100d8576101a461018a6101853660046100ec565b610156565b604051918291826001600160a01b03909116815260200190565b0390f35b346100d8576101c06101bb3660046100ec565b6105da565b604051005b346100d8576101c06101d83660046100ec565b610709565b346100d8576101c06101f03660046100ec565b61076f565b346100d8576101c06102083660046100ec565b6108f0565b0190565b9061023161022a610220845190565b8084529260200190565b9260200190565b9060005b8181106102425750505090565b90919261026861026160019286516001600160a01b0316815260200190565b9460200190565b929101610235565b60208082526100c392910190610211565b346100d8576101a461029c6102973660046100ec565b6108f9565b60405191829182610270565b91906040838203126100d8576100c39060206102c482866100dd565b94016100dd565b346100d8576101c06102de3660046102a8565b906109b8565b60009103126100d857565b6100c360008061014b565b61016b9061011d565b6020810192916100ea91906102fa565b346100d8576103233660046102e4565b6101a461032e6102ef565b60405191829182610303565b346100d8576101c061034d3660046102a8565b90610b01565b346100d8576101c06103663660046102a8565b90610b2d565b6100c3906100b7565b6100c3905461036c565b634e487b7160e01b600052604160045260246000fd5b90601f01601f1916810190811067ffffffffffffffff8211176103b757604052565b61037f565b8015156100d1565b905051906100ea826103bc565b906020828203126100d8576100c3916103c4565b6040513d6000823e3d90fd5b906100ea6103fe60405190565b9283610395565b67ffffffffffffffff81116103b757602090601f01601f19160190565b9061043461042f83610405565b6103f1565b918252565b610443603a610422565b7f353630317c52656769737472793a206f6e6c79207061796d656e74206163636f60208201527f756e742063616e2063616c6c20746869732066756e6374696f6e000000000000604082015290565b6100c3610439565b6100c3610492565b60005b8381106104b55750506000910152565b81810151838201526020016104a5565b6104e66104ef60209361020d936104da815190565b80835293849260200190565b958691016104a2565b601f01601f191690565b60208082526100c3929101906104c5565b156105125750565b6105349061051f60405190565b62461bcd60e51b8152918291600483016104f9565b0390fd5b61054a6105456000610375565b61011d565b90602061055660405190565b6385bb392360e01b815233600482015292839060249082905afa9182156105ca576100ea926105969160009161059b575b5061059061049a565b9061050a565b6105cf565b6105bd915060203d6020116105c3575b6105b58183610395565b8101906103d1565b38610587565b503d6105ab565b6103e5565b6100ea903390610b37565b6100ea90610538565b6105f06105456000610375565b9060206105fc60405190565b6385bb392360e01b815233600482015292839060249082905afa9182156105ca576100ea926106359160009161059b575061059061049a565b6106a3565b610644603b610422565b7f353630327c52656769737472793a207061796d656e74206163636f756e74206260208201527f65696e672072656d6f766564206e6f7420696e20746865207365740000000000604082015290565b6100c361063a565b6100c3610693565b6106c66106be6106b76100c3846001610126565b3390610ba3565b61059061069b565b6106d86106d23361011d565b9161011d565b907fe594d081b4382713733fe631966432c9cea5199afb2db5c3c1931f9f9300367961070360405190565b600090a3565b6100ea906105e3565b61071f6105456000610375565b90602061072b60405190565b6385bb392360e01b815233600482015292839060249082905afa9182156105ca576100ea926107649160009161059b575061059061049a565b6100ea903390610c7e565b6100ea90610712565b6107856105456000610375565b90602061079160405190565b6385bb392360e01b815233600482015292839060249082905afa9182156105ca576100ea926107ca9160009161059b575061059061049a565b610873565b6107d96030610422565b7f353630357c52656769737472793a2063617264206265696e672072656d6f766560208201526f19081b9bdd081a5b881d1a19481cd95d60821b604082015290565b6100c36107cf565b6100c361081b565b916001600160a01b0360089290920291821b911b5b9181191691161790565b919061085b6100c36108639361011d565b90835461082b565b9055565b6100ea9160009161084a565b6108a4610889610884836002610126565b610375565b61089b335b916001600160a01b031690565b14610590610823565b6108b960006108b4836002610126565b610867565b6108c56106d23361011d565b907f5f8ec0a3d11bc25dab3cc6b87b3add8f1797a221531def932c4d242f561abf2561070360405190565b6100ea90610778565b6109136100c36100c39261090b606090565b506001610126565b610cef565b6109226042610422565b7f353630307c52656769737472793a206f6e6c79207061796d656e74206163636f60208201527f756e7420666163746f72792063616e2063616c6c20746869732066756e63746960408201526137b760f11b606082015290565b6100c3610918565b6100c361097c565b906100ea916109ae6109a46100b76105456000610375565b3314610590610984565b906100ea91610c7e565b906100ea9161098c565b906109d06105456000610375565b9160206109dc60405190565b6385bb392360e01b815233600482015293849060249082905afa9283156105ca576100ea93610a159160009161059b575061059061049a565b610a83565b610a246040610422565b7f353630337c52656769737472793a207061796d656e74206163636f756e74206260208201527f65696e6720616464656420697320616c726561647920696e2074686520736574604082015290565b6100c3610a1a565b6100c3610a73565b90610a986106be6106b76100c3856001610126565b610abb610ab3610aac6100c3846001610126565b3390610d00565b610590610a7b565b610ad06106d2610aca3361011d565b9361011d565b917f381c0d11398486654573703c51ee8210ce9461764d133f9f0e53b6a539705331610afb60405190565b600090a4565b906100ea916109c2565b906100ea91610b236109a46100b76105456000610375565b906100ea91610b37565b906100ea91610b0b565b906106d2610b5991610545610ab382610b546100c3886001610126565b610d00565b907fa5e1f8b4009110f5525798d04ae2125421a12d0590aa52c13682ff1bd3c492ca61070360405190565b6100c39081906001600160a01b031681565b6100c36100c36100c39290565b90610bd4610bd0610bcb610bc660006100c396610bbe600090565b500194610114565b610b84565b610b96565b9190565b610e66565b6100b76100c36100c39290565b6100c390610bd9565b610bf9603a610422565b7f353630347c52656769737472793a207061796d656e74206163636f756e74206960208201527f7320616c72656164792073657420666f72207468652063617264000000000000604082015290565b6100c3610bef565b6100c3610c48565b906001600160a01b0390610840565b90610c776100c36108639261011d565b8254610c58565b906106d2610cc491610cb0610c97610884866002610126565b610ca761088e6100b76000610be6565b14610590610c50565b61054581610cbf866002610126565b610c67565b907fc063fc300750e8c5649c6b3779f6c4b05e7b38b170ee5c4a4b222ede9a28808361070360405190565b606090610cfb90610fc8565b905090565b90610d1b610bd0610bcb610bc660006100c396610bbe600090565b611005565b90610130565b6100c39081565b6100c39054610d26565b634e487b7160e01b600052601160045260246000fd5b91908203918211610d5a57565b610d37565b634e487b7160e01b600052603260045260246000fd5b8054821015610d9857610d8f600191600052602060002090565b91020190600090565b610d5f565b6100c3916008021c81565b906100c39154610d9d565b9160001960089290920291821b911b610840565b9190610dd66100c36108639390565b908354610db3565b9060001990610840565b90610df86100c361086392610b96565b8254610dde565b634e487b7160e01b600052603160045260246000fd5b6100ea91600091610dc7565b80548015610e44576000190190610e41610e3b8383610d75565b90610e15565b55565b610dff565b9190610dd66100c361086393610b96565b6100ea91600091610e49565b90610e7c610e778260018501610d20565b610d2d565b610e866000610b96565b8114610f3457610eeb6100c392600092610ee095610ee56001978893610eb4610eae86610b96565b82610d4d565b88850191610ed2610ec3845490565b610ecc89610b96565b90610d4d565b808303610ef0575b50505090565b610e21565b01610d20565b610e5a565b610f19610f1f610f2c94610f10610f0a610f279589610d75565b90610da8565b92839188610d75565b90610dc7565b888801610d20565b610de8565b388080610eda565b505050600090565b90610f57610f4b610220845490565b92600052602060002090565b9060005b818110610f685750505090565b909192610f8c610f85600192610f7d87610d2d565b815260200190565b9460010190565b929101610f5b565b906100c391610f3c565b906100ea610fb892610faf60405190565b93848092610f94565b0383610395565b6100c390610f9e565b60006100c391610fd6606090565b5001610fbf565b90815491680100000000000000008310156103b75782610f199160016100ea95018155610d75565b611016611012838361104a565b1590565b156110435761103e91610f27906001611037846110338482610fdd565b5490565b9301610d20565b600190565b5050600090565b611063916001610e779261105c600090565b5001610d20565b611070610bd06000610b96565b14159056fea26469706673582212205e9abf37b9af5365c966f2cb4bdb949d15aac5e8ec856dbc6a6c8fc7e9de783764736f6c63430008160033"; - public static final String FUNC_CHANGEPAYMENTACCOUNTCARD = "changePaymentAccountCard"; + private static String librariesLinkedBinary; - public static final String FUNC_CHANGEPAYMENTACCOUNTOWNER = "changePaymentAccountOwner"; + public static final String FUNC_ADDCARD = "addCard"; + + public static final String FUNC_ADDCARDONDEPLOY = "addCardOnDeploy"; + + public static final String FUNC_CHANGEOWNER = "changeOwner"; public static final String FUNC_FACTORY = "factory"; - public static final String FUNC_INITPAYMENTACCOUNTCARD = "initPaymentAccountCard"; + public static final String FUNC_INITOWNER = "initOwner"; - public static final String FUNC_INITPAYMENTACCOUNTOWNER = "initPaymentAccountOwner"; + public static final String FUNC_INITOWNERONDEPLOY = "initOwnerOnDeploy"; public static final String FUNC_PAYMENTACCOUNTBYCARD = "paymentAccountByCard"; public static final String FUNC_PAYMENTACCOUNTSBYOWNER = "paymentAccountsByOwner"; - public static final Event PAYMENTACCOUNTCARDCHANGED_EVENT = new Event("PaymentAccountCardChanged", - Arrays.asList(new TypeReference

() { - }, new TypeReference
() { - }, new TypeReference
() { - })); + public static final String FUNC_REMOVECARD = "removeCard"; - public static final Event PAYMENTACCOUNTCARDREGISTERED_EVENT = new Event("PaymentAccountCardRegistered", - Arrays.asList(new TypeReference
(true) { - }, new TypeReference
(true) { - })); + public static final String FUNC_REMOVEOWNER = "removeOwner"; - public static final Event PAYMENTACCOUNTOWNERCHANGED_EVENT = new Event("PaymentAccountOwnerChanged", - Arrays.asList(new TypeReference
() { - }, new TypeReference
() { - }, new TypeReference
() { - })); + public static final Event CARDREGISTERED_EVENT = new Event("CardRegistered", + Arrays.>asList(new TypeReference
(true) {}, new TypeReference
(true) {})); + ; - public static final Event PAYMENTACCOUNTOWNERREGISTERED_EVENT = new Event("PaymentAccountOwnerRegistered", - Arrays.asList(new TypeReference
(true) { - }, new TypeReference
(true) { - })); + public static final Event CARDREMOVED_EVENT = new Event("CardRemoved", + Arrays.>asList(new TypeReference
(true) {}, new TypeReference
(true) {})); + ; + + public static final Event OWNERCHANGED_EVENT = new Event("OwnerChanged", + Arrays.>asList(new TypeReference
(true) {}, new TypeReference
(true) {}, new TypeReference
(true) {})); + ; + + public static final Event OWNERREGISTERED_EVENT = new Event("OwnerRegistered", + Arrays.>asList(new TypeReference
(true) {}, new TypeReference
(true) {})); + ; + + public static final Event OWNERREMOVED_EVENT = new Event("OwnerRemoved", + Arrays.>asList(new TypeReference
(true) {}, new TypeReference
(true) {})); + ; @Deprecated - protected TangemPaymentAccountRegistry(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + protected TangemPaymentAccountRegistry(String contractAddress, Web3j web3j, + Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit); } - protected TangemPaymentAccountRegistry(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { + protected TangemPaymentAccountRegistry(String contractAddress, Web3j web3j, + Credentials credentials, ContractGasProvider contractGasProvider) { super(BINARY, contractAddress, web3j, credentials, contractGasProvider); } @Deprecated - protected TangemPaymentAccountRegistry(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + protected TangemPaymentAccountRegistry(String contractAddress, Web3j web3j, + TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit); } - protected TangemPaymentAccountRegistry(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + protected TangemPaymentAccountRegistry(String contractAddress, Web3j web3j, + TransactionManager transactionManager, ContractGasProvider contractGasProvider) { super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider); } - public static List getPaymentAccountCardChangedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(PAYMENTACCOUNTCARDCHANGED_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - PaymentAccountCardChangedEventResponse typedResponse = new PaymentAccountCardChangedEventResponse(); - typedResponse.log = eventValues.getLog(); - typedResponse.paymentAccount = (String) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.previousCard = (String) eventValues.getNonIndexedValues().get(1).getValue(); - typedResponse.newCard = (String) eventValues.getNonIndexedValues().get(2).getValue(); - responses.add(typedResponse); - } - return responses; - } - - public static PaymentAccountCardChangedEventResponse getPaymentAccountCardChangedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(PAYMENTACCOUNTCARDCHANGED_EVENT, log); - PaymentAccountCardChangedEventResponse typedResponse = new PaymentAccountCardChangedEventResponse(); - typedResponse.log = log; - typedResponse.paymentAccount = (String) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.previousCard = (String) eventValues.getNonIndexedValues().get(1).getValue(); - typedResponse.newCard = (String) eventValues.getNonIndexedValues().get(2).getValue(); - return typedResponse; - } - - public static List getPaymentAccountCardRegisteredEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(PAYMENTACCOUNTCARDREGISTERED_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - PaymentAccountCardRegisteredEventResponse typedResponse = new PaymentAccountCardRegisteredEventResponse(); + public static List getCardRegisteredEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(CARDREGISTERED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + CardRegisteredEventResponse typedResponse = new CardRegisteredEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); @@ -130,44 +119,102 @@ class TangemPaymentAccountRegistry extends Contract { return responses; } - public static PaymentAccountCardRegisteredEventResponse getPaymentAccountCardRegisteredEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(PAYMENTACCOUNTCARDREGISTERED_EVENT, log); - PaymentAccountCardRegisteredEventResponse typedResponse = new PaymentAccountCardRegisteredEventResponse(); + public static CardRegisteredEventResponse getCardRegisteredEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(CARDREGISTERED_EVENT, log); + CardRegisteredEventResponse typedResponse = new CardRegisteredEventResponse(); typedResponse.log = log; typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); return typedResponse; } - public static List getPaymentAccountOwnerChangedEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(PAYMENTACCOUNTOWNERCHANGED_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - PaymentAccountOwnerChangedEventResponse typedResponse = new PaymentAccountOwnerChangedEventResponse(); + public Flowable cardRegisteredEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getCardRegisteredEventFromLog(log)); + } + + public Flowable cardRegisteredEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(CARDREGISTERED_EVENT)); + return cardRegisteredEventFlowable(filter); + } + + public static List getCardRemovedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(CARDREMOVED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + CardRemovedEventResponse typedResponse = new CardRemovedEventResponse(); typedResponse.log = eventValues.getLog(); - typedResponse.paymentAccount = (String) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.previousOwner = (String) eventValues.getNonIndexedValues().get(1).getValue(); - typedResponse.newOwner = (String) eventValues.getNonIndexedValues().get(2).getValue(); + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); responses.add(typedResponse); } return responses; } - public static PaymentAccountOwnerChangedEventResponse getPaymentAccountOwnerChangedEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(PAYMENTACCOUNTOWNERCHANGED_EVENT, log); - PaymentAccountOwnerChangedEventResponse typedResponse = new PaymentAccountOwnerChangedEventResponse(); + public static CardRemovedEventResponse getCardRemovedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(CARDREMOVED_EVENT, log); + CardRemovedEventResponse typedResponse = new CardRemovedEventResponse(); typedResponse.log = log; - typedResponse.paymentAccount = (String) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.previousOwner = (String) eventValues.getNonIndexedValues().get(1).getValue(); - typedResponse.newOwner = (String) eventValues.getNonIndexedValues().get(2).getValue(); + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.card = (String) eventValues.getIndexedValues().get(1).getValue(); return typedResponse; } - public static List getPaymentAccountOwnerRegisteredEvents(TransactionReceipt transactionReceipt) { - List valueList = staticExtractEventParametersWithLog(PAYMENTACCOUNTOWNERREGISTERED_EVENT, transactionReceipt); - ArrayList responses = new ArrayList(valueList.size()); - for (EventValuesWithLog eventValues : valueList) { - PaymentAccountOwnerRegisteredEventResponse typedResponse = new PaymentAccountOwnerRegisteredEventResponse(); + public Flowable cardRemovedEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getCardRemovedEventFromLog(log)); + } + + public Flowable cardRemovedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(CARDREMOVED_EVENT)); + return cardRemovedEventFlowable(filter); + } + + public static List getOwnerChangedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(OWNERCHANGED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + OwnerChangedEventResponse typedResponse = new OwnerChangedEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.previousOwner = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.newOwner = (String) eventValues.getIndexedValues().get(2).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public static OwnerChangedEventResponse getOwnerChangedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(OWNERCHANGED_EVENT, log); + OwnerChangedEventResponse typedResponse = new OwnerChangedEventResponse(); + typedResponse.log = log; + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.previousOwner = (String) eventValues.getIndexedValues().get(1).getValue(); + typedResponse.newOwner = (String) eventValues.getIndexedValues().get(2).getValue(); + return typedResponse; + } + + public Flowable ownerChangedEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getOwnerChangedEventFromLog(log)); + } + + public Flowable ownerChangedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(OWNERCHANGED_EVENT)); + return ownerChangedEventFlowable(filter); + } + + public static List getOwnerRegisteredEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(OWNERREGISTERED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + OwnerRegisteredEventResponse typedResponse = new OwnerRegisteredEventResponse(); typedResponse.log = eventValues.getLog(); typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); typedResponse.owner = (String) eventValues.getIndexedValues().get(1).getValue(); @@ -176,151 +223,124 @@ class TangemPaymentAccountRegistry extends Contract { return responses; } - public static PaymentAccountOwnerRegisteredEventResponse getPaymentAccountOwnerRegisteredEventFromLog(Log log) { - EventValuesWithLog eventValues = staticExtractEventParametersWithLog(PAYMENTACCOUNTOWNERREGISTERED_EVENT, log); - PaymentAccountOwnerRegisteredEventResponse typedResponse = new PaymentAccountOwnerRegisteredEventResponse(); + public static OwnerRegisteredEventResponse getOwnerRegisteredEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(OWNERREGISTERED_EVENT, log); + OwnerRegisteredEventResponse typedResponse = new OwnerRegisteredEventResponse(); typedResponse.log = log; typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); typedResponse.owner = (String) eventValues.getIndexedValues().get(1).getValue(); return typedResponse; } - @Deprecated - public static TangemPaymentAccountRegistry load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { - return new TangemPaymentAccountRegistry(contractAddress, web3j, credentials, gasPrice, gasLimit); + public Flowable ownerRegisteredEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getOwnerRegisteredEventFromLog(log)); } - @Deprecated - public static TangemPaymentAccountRegistry load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { - return new TangemPaymentAccountRegistry(contractAddress, web3j, transactionManager, gasPrice, gasLimit); - } - - public static TangemPaymentAccountRegistry load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { - return new TangemPaymentAccountRegistry(contractAddress, web3j, credentials, contractGasProvider); - } - - public static TangemPaymentAccountRegistry load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { - return new TangemPaymentAccountRegistry(contractAddress, web3j, transactionManager, contractGasProvider); - } - - public static RemoteCall deploy(Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider, String factory_) { - String encodedConstructor = FunctionEncoder.encodeConstructor(List.of(new Address(160, factory_))); - return deployRemoteCall(TangemPaymentAccountRegistry.class, web3j, credentials, contractGasProvider, BINARY, encodedConstructor); - } - - public static RemoteCall deploy(Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider, String factory_) { - String encodedConstructor = FunctionEncoder.encodeConstructor(List.of(new Address(160, factory_))); - return deployRemoteCall(TangemPaymentAccountRegistry.class, web3j, transactionManager, contractGasProvider, BINARY, encodedConstructor); - } - - @Deprecated - public static RemoteCall deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit, String factory_) { - String encodedConstructor = FunctionEncoder.encodeConstructor(List.of(new Address(160, factory_))); - return deployRemoteCall(TangemPaymentAccountRegistry.class, web3j, credentials, gasPrice, gasLimit, BINARY, encodedConstructor); - } - - @Deprecated - public static RemoteCall deploy(Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit, String factory_) { - String encodedConstructor = FunctionEncoder.encodeConstructor(List.of(new Address(160, factory_))); - return deployRemoteCall(TangemPaymentAccountRegistry.class, web3j, transactionManager, gasPrice, gasLimit, BINARY, encodedConstructor); - } - - public Flowable paymentAccountCardChangedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getPaymentAccountCardChangedEventFromLog(log)); - } - - public Flowable paymentAccountCardChangedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public Flowable ownerRegisteredEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(PAYMENTACCOUNTCARDCHANGED_EVENT)); - return paymentAccountCardChangedEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(OWNERREGISTERED_EVENT)); + return ownerRegisteredEventFlowable(filter); } - public Flowable paymentAccountCardRegisteredEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getPaymentAccountCardRegisteredEventFromLog(log)); + public static List getOwnerRemovedEvents( + TransactionReceipt transactionReceipt) { + List valueList = staticExtractEventParametersWithLog(OWNERREMOVED_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + OwnerRemovedEventResponse typedResponse = new OwnerRemovedEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.owner = (String) eventValues.getIndexedValues().get(1).getValue(); + responses.add(typedResponse); + } + return responses; } - public Flowable paymentAccountCardRegisteredEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + public static OwnerRemovedEventResponse getOwnerRemovedEventFromLog(Log log) { + Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(OWNERREMOVED_EVENT, log); + OwnerRemovedEventResponse typedResponse = new OwnerRemovedEventResponse(); + typedResponse.log = log; + typedResponse.paymentAccount = (String) eventValues.getIndexedValues().get(0).getValue(); + typedResponse.owner = (String) eventValues.getIndexedValues().get(1).getValue(); + return typedResponse; + } + + public Flowable ownerRemovedEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(log -> getOwnerRemovedEventFromLog(log)); + } + + public Flowable ownerRemovedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(PAYMENTACCOUNTCARDREGISTERED_EVENT)); - return paymentAccountCardRegisteredEventFlowable(filter); + filter.addSingleTopic(EventEncoder.encode(OWNERREMOVED_EVENT)); + return ownerRemovedEventFlowable(filter); } - public Flowable paymentAccountOwnerChangedEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getPaymentAccountOwnerChangedEventFromLog(log)); - } - - public Flowable paymentAccountOwnerChangedEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(PAYMENTACCOUNTOWNERCHANGED_EVENT)); - return paymentAccountOwnerChangedEventFlowable(filter); - } - - public Flowable paymentAccountOwnerRegisteredEventFlowable(EthFilter filter) { - return web3j.ethLogFlowable(filter).map(log -> getPaymentAccountOwnerRegisteredEventFromLog(log)); - } - - public Flowable paymentAccountOwnerRegisteredEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { - EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); - filter.addSingleTopic(EventEncoder.encode(PAYMENTACCOUNTOWNERREGISTERED_EVENT)); - return paymentAccountOwnerRegisteredEventFlowable(filter); - } - - public RemoteFunctionCall changePaymentAccountCard(String previousCard, String newCard) { + public RemoteFunctionCall addCard(String card) { final Function function = new Function( - FUNC_CHANGEPAYMENTACCOUNTCARD, - Arrays.asList(new Address(160, previousCard), - new Address(160, newCard)), - Collections.emptyList()); + FUNC_ADDCARD, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, card)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall changePaymentAccountOwner(String previousOwner, String newOwner) { + public RemoteFunctionCall addCardOnDeploy(String card, + String paymentAccount) { final Function function = new Function( - FUNC_CHANGEPAYMENTACCOUNTOWNER, - Arrays.asList(new Address(160, previousOwner), - new Address(160, newOwner)), - Collections.emptyList()); + FUNC_ADDCARDONDEPLOY, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, card), + new org.web3j.abi.datatypes.Address(160, paymentAccount)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + public RemoteFunctionCall changeOwner(String previousOwner, + String newOwner) { + final Function function = new Function( + FUNC_CHANGEOWNER, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, previousOwner), + new org.web3j.abi.datatypes.Address(160, newOwner)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall factory() { final Function function = new Function(FUNC_FACTORY, - List.of(), - List.of(new TypeReference
() { - })); + Arrays.asList(), + Arrays.>asList(new TypeReference
() {})); return executeRemoteCallSingleValueReturn(function, String.class); } - public RemoteFunctionCall initPaymentAccountCard(String card) { + public RemoteFunctionCall initOwner(String owner) { final Function function = new Function( - FUNC_INITPAYMENTACCOUNTCARD, - List.of(new Address(160, card)), - Collections.emptyList()); + FUNC_INITOWNER, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, owner)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall initPaymentAccountOwner(String paymentAccount, String owner) { + public RemoteFunctionCall initOwnerOnDeploy(String owner, + String paymentAccount) { final Function function = new Function( - FUNC_INITPAYMENTACCOUNTOWNER, - Arrays.asList(new Address(160, paymentAccount), - new Address(160, owner)), - Collections.emptyList()); + FUNC_INITOWNERONDEPLOY, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, owner), + new org.web3j.abi.datatypes.Address(160, paymentAccount)), + Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall paymentAccountByCard(String param0) { final Function function = new Function(FUNC_PAYMENTACCOUNTBYCARD, - List.of(new Address(160, param0)), - List.of(new TypeReference
() { - })); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, param0)), + Arrays.>asList(new TypeReference
() {})); return executeRemoteCallSingleValueReturn(function, String.class); } public RemoteFunctionCall paymentAccountsByOwner(String owner) { final Function function = new Function(FUNC_PAYMENTACCOUNTSBYOWNER, - List.of(new Address(160, owner)), - List.of(new TypeReference>() { - })); + Arrays.asList(new org.web3j.abi.datatypes.Address(160, owner)), + Arrays.>asList(new TypeReference>() {})); return new RemoteFunctionCall(function, new Callable() { @Override @@ -332,21 +352,97 @@ class TangemPaymentAccountRegistry extends Contract { }); } - public static class PaymentAccountCardChangedEventResponse extends BaseEventResponse { - public String paymentAccount; - - public String previousCard; - - public String newCard; + public RemoteFunctionCall removeCard(String card) { + final Function function = new Function( + FUNC_REMOVECARD, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, card)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); } - public static class PaymentAccountCardRegisteredEventResponse extends BaseEventResponse { + public RemoteFunctionCall removeOwner(String owner) { + final Function function = new Function( + FUNC_REMOVEOWNER, + Arrays.asList(new org.web3j.abi.datatypes.Address(160, owner)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + @Deprecated + public static TangemPaymentAccountRegistry load(String contractAddress, Web3j web3j, + Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + return new TangemPaymentAccountRegistry(contractAddress, web3j, credentials, gasPrice, gasLimit); + } + + @Deprecated + public static TangemPaymentAccountRegistry load(String contractAddress, Web3j web3j, + TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + return new TangemPaymentAccountRegistry(contractAddress, web3j, transactionManager, gasPrice, gasLimit); + } + + public static TangemPaymentAccountRegistry load(String contractAddress, Web3j web3j, + Credentials credentials, ContractGasProvider contractGasProvider) { + return new TangemPaymentAccountRegistry(contractAddress, web3j, credentials, contractGasProvider); + } + + public static TangemPaymentAccountRegistry load(String contractAddress, Web3j web3j, + TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + return new TangemPaymentAccountRegistry(contractAddress, web3j, transactionManager, contractGasProvider); + } + + public static RemoteCall deploy(Web3j web3j, + Credentials credentials, ContractGasProvider contractGasProvider, String factory_) { + String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.Address(160, factory_))); + return deployRemoteCall(TangemPaymentAccountRegistry.class, web3j, credentials, contractGasProvider, getDeploymentBinary(), encodedConstructor); + } + + public static RemoteCall deploy(Web3j web3j, + TransactionManager transactionManager, ContractGasProvider contractGasProvider, + String factory_) { + String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.Address(160, factory_))); + return deployRemoteCall(TangemPaymentAccountRegistry.class, web3j, transactionManager, contractGasProvider, getDeploymentBinary(), encodedConstructor); + } + + @Deprecated + public static RemoteCall deploy(Web3j web3j, + Credentials credentials, BigInteger gasPrice, BigInteger gasLimit, String factory_) { + String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.Address(160, factory_))); + return deployRemoteCall(TangemPaymentAccountRegistry.class, web3j, credentials, gasPrice, gasLimit, getDeploymentBinary(), encodedConstructor); + } + + @Deprecated + public static RemoteCall deploy(Web3j web3j, + TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit, + String factory_) { + String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.Address(160, factory_))); + return deployRemoteCall(TangemPaymentAccountRegistry.class, web3j, transactionManager, gasPrice, gasLimit, getDeploymentBinary(), encodedConstructor); + } + + public static void linkLibraries(List references) { + librariesLinkedBinary = linkBinaryWithReferences(BINARY, references); + } + + private static String getDeploymentBinary() { + if (librariesLinkedBinary != null) { + return librariesLinkedBinary; + } else { + return BINARY; + } + } + + public static class CardRegisteredEventResponse extends BaseEventResponse { public String paymentAccount; public String card; } - public static class PaymentAccountOwnerChangedEventResponse extends BaseEventResponse { + public static class CardRemovedEventResponse extends BaseEventResponse { + public String paymentAccount; + + public String card; + } + + public static class OwnerChangedEventResponse extends BaseEventResponse { public String paymentAccount; public String previousOwner; @@ -354,9 +450,15 @@ class TangemPaymentAccountRegistry extends Contract { public String newOwner; } - public static class PaymentAccountOwnerRegisteredEventResponse extends BaseEventResponse { + public static class OwnerRegisteredEventResponse extends BaseEventResponse { public String paymentAccount; public String owner; } -} + + public static class OwnerRemovedEventResponse extends BaseEventResponse { + public String paymentAccount; + + public String owner; + } +} \ No newline at end of file diff --git a/libs/visa/src/main/kotlin/com/tangem/lib/visa/DefaultVisaContractInfoProvider.kt b/libs/visa/src/main/kotlin/com/tangem/lib/visa/DefaultVisaContractInfoProvider.kt index 312f708435..2265f6258f 100644 --- a/libs/visa/src/main/kotlin/com/tangem/lib/visa/DefaultVisaContractInfoProvider.kt +++ b/libs/visa/src/main/kotlin/com/tangem/lib/visa/DefaultVisaContractInfoProvider.kt @@ -102,8 +102,7 @@ internal class DefaultVisaContractInfoProvider( { paymentAccount.availableForDebtPayment().send() }, { paymentAccount.blockedAmount().send() }, { paymentAccount.debtAmount().send() }, - { paymentAccount.pendingRefundTotal().send() }, - ) { total, verified, payment, withdrawal, debtPayment, blocked, debt, refund -> + ) { total, verified, payment, withdrawal, debtPayment, blocked, debt -> val decimals = paymentToken.decimals Balances( @@ -116,40 +115,42 @@ internal class DefaultVisaContractInfoProvider( ), blocked = blocked.toBigDecimal(decimals), debt = debt.toBigDecimal(decimals), - pendingRefund = refund.toBigDecimal(decimals), ) } } + @Suppress("UnusedPrivateMember") private fun fetchLimits( paymentAccount: TangemPaymentAccount, paymentToken: PaymentTokenInfo, ): Triple { - val ( - oldLimit, - newLimit, - changeDateSeconds, - ) = paymentAccount.limits().send() - - return Triple( - first = getLimits(oldLimit, paymentToken), - second = getLimits(newLimit, paymentToken), - third = changeDateSeconds.toInstant(), - ) + TODO() // TODO: [REDACTED_TASK_KEY] + // val ( + // oldLimit, + // newLimit, + // changeDateSeconds, + // ) = paymentAccount.cards("").send().component5() + // + // return Triple( + // first = getLimits(oldLimit, paymentToken), + // second = getLimits(newLimit, paymentToken), + // third = changeDateSeconds.toInstant(), + // ) } + @Suppress("UnusedPrivateMember") private fun getLimits(limit: TangemPaymentAccount.Limits, paymentToken: PaymentTokenInfo): Limits = Limits( - spendLimit = limit._01_spendLimit.toLimit(paymentToken.decimals), - noOtpLimit = limit._02_noOtpSpendLimit.toLimit(paymentToken.decimals), - singleTransactionLimit = limit._00_singleTransactionLimit.toBigDecimal(paymentToken.decimals), - expirationDate = limit._03_spendLimitsTimer.expireTimestamp.toInstant(), - spendPeriodSeconds = limit._04_spendLimitsPeriod, + spendLimit = limit.spendLimit.toLimit(paymentToken.decimals), + noOtpLimit = limit.noConfirmationSpendLimit.toLimit(paymentToken.decimals), + singleTransactionLimit = limit.singleTransactionLimit.toBigDecimal(paymentToken.decimals), + expirationDate = limit.spendLimitsTimer.expireTimestamp.toInstant(), + spendPeriodSeconds = limit.spendLimitsPeriod, ) private fun TangemPaymentAccount.Limit.toLimit(decimals: Int): Limits.Limit { return Limits.Limit( - limit = _00_limit.toBigDecimal(decimals), - spent = _01_spent.toBigDecimal(decimals), + limit = limit.toBigDecimal(decimals), + spent = spent.toBigDecimal(decimals), ) } diff --git a/libs/visa/src/main/kotlin/com/tangem/lib/visa/model/VisaContractInfo.kt b/libs/visa/src/main/kotlin/com/tangem/lib/visa/model/VisaContractInfo.kt index e2e6f98d58..e50c6e3c89 100644 --- a/libs/visa/src/main/kotlin/com/tangem/lib/visa/model/VisaContractInfo.kt +++ b/libs/visa/src/main/kotlin/com/tangem/lib/visa/model/VisaContractInfo.kt @@ -25,7 +25,6 @@ data class VisaContractInfo( val available: Available, val blocked: BigDecimal, val debt: BigDecimal, - val pendingRefund: BigDecimal, ) { data class Available( diff --git a/settings.gradle.kts b/settings.gradle.kts index 1ad6153ba0..b89a9482f9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -106,6 +106,17 @@ dependencyResolutionManagement { includeGroupAndSubgroups("com.tangem.ic4j") } } + maven { + // setting any repository from tangem project allows maven search all packages in the project + url = uri("https://maven.pkg.github.com/tangem/web3j") + credentials { + username = properties.getProperty("gpr.user") ?: System.getenv("GITHUB_ACTOR") + password = properties.getProperty("gpr.key") ?: System.getenv("GITHUB_TOKEN") + } + content { + includeGroupAndSubgroups("org.web3j") + } + } maven("https://jitpack.io") } From 06e132ba04fa9e73c3fd18e7c8bbbb7ff1449d5b Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 18 Feb 2025 20:10:42 +0300 Subject: [PATCH 07/54] Updated on 2026-08-14 --- .../DefaultWalletConnectComponent.kt | 71 +++++++++++++++++++ .../ui/walletconnect/WalletConnectFragment.kt | 68 ------------------ ...nectViewModel.kt => WalletConnectModel.kt} | 19 ++--- .../api/WalletConnectComponent.kt | 8 +++ .../di/WalletConnectFeatureModule.kt | 25 +++++++ .../tangem/tap/routing/utils/ChildFactory.kt | 17 ++++- 6 files changed, 129 insertions(+), 79 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/DefaultWalletConnectComponent.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectFragment.kt rename app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/{WalletConnectViewModel.kt => WalletConnectModel.kt} (82%) create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/api/WalletConnectComponent.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/di/WalletConnectFeatureModule.kt diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/DefaultWalletConnectComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/DefaultWalletConnectComponent.kt new file mode 100644 index 0000000000..5fadd6a1e8 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/DefaultWalletConnectComponent.kt @@ -0,0 +1,71 @@ +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 { + + private val model: WalletConnectModel = getOrCreateModel() + + private var screenState: MutableState? = null + + init { + lifecycle.subscribe( + onCreate = { + Analytics.send(WalletConnect.ScreenOpened()) + screenState = mutableStateOf(model.updateState(store.state.walletConnectState)) + }, + 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) { + val state = screenState?.value ?: return + WalletConnectScreen( + modifier = modifier, + state = state, + onBackClick = { + store.dispatchNavigationAction(AppRouter::pop) + }, + ) + } + + @AssistedFactory + interface Factory : WalletConnectComponent.Factory { + override fun create(context: AppComponentContext, params: Unit): DefaultWalletConnectComponent + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectFragment.kt deleted file mode 100644 index d720c10ec7..0000000000 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectFragment.kt +++ /dev/null @@ -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 { - - @Inject - override lateinit var uiDependencies: UiDependencies - - private val viewModel: WalletConnectViewModel by viewModels() - - private var screenState: MutableState? = 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) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectModel.kt similarity index 82% rename from app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectViewModel.kt rename to app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectModel.kt index 2ee11076ee..6372c2f648 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectModel.kt @@ -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.ComponentScoped +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 +@ComponentScoped +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)) } } } diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/api/WalletConnectComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/api/WalletConnectComponent.kt new file mode 100644 index 0000000000..4e1f4ab3fb --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/api/WalletConnectComponent.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/di/WalletConnectFeatureModule.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/di/WalletConnectFeatureModule.kt new file mode 100644 index 0000000000..20a85d18be --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/di/WalletConnectFeatureModule.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index 09e825ea06..970abaae15 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -26,7 +26,7 @@ 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.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 @@ -63,6 +63,7 @@ internal class ChildFactory @Inject constructor( private val swapComponentFactory: SwapComponent.Factory, private val homeComponentFactory: HomeComponent.Factory, private val tokenDetailsComponentFactory: TokenDetailsComponent.Factory, + private val walletConnectComponentFactory: WalletConnectComponent.Factory, private val walletRouter: WalletRouter, private val qrScanningRouter: QrScanningRouter, private val testerRouter: TesterRouter, @@ -267,6 +268,13 @@ internal class ChildFactory @Inject constructor( componentFactory = homeComponentFactory, ) } + is AppRoute.WalletConnectSessions -> { + createComponentChild( + contextProvider = contextProvider(route, contextFactory), + params = Unit, + componentFactory = walletConnectComponentFactory, + ) + } is AppRoute.AccessCodeRecovery, is AppRoute.AppCurrencySelector, is AppRoute.SaveWallet, @@ -281,7 +289,6 @@ internal class ChildFactory @Inject constructor( is AppRoute.ReferralProgram, is AppRoute.ResetToFactory, is AppRoute.Wallet, - is AppRoute.WalletConnectSessions, is AppRoute.PushNotification, -> error("Unsupported route: $route") } @@ -400,7 +407,11 @@ internal class ChildFactory @Inject constructor( route.asFragmentChild(Provider { walletRouter.getEntryFragment() }) } is AppRoute.WalletConnectSessions -> { - route.asFragmentChild(Provider { WalletConnectFragment() }) + route.asComponentChild( + contextProvider = contextProvider(route, contextFactory), + params = Unit, + componentFactory = walletConnectComponentFactory, + ) } is AppRoute.CurrencyDetails -> { route.asComponentChild( From cf38933188e49ee43f996aeed99bec1239249375 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 18 Feb 2025 20:13:14 +0300 Subject: [PATCH 08/54] Updated on 2026-08-14 --- .../ui/walletconnect/DefaultWalletConnectComponent.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/DefaultWalletConnectComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/DefaultWalletConnectComponent.kt index 5fadd6a1e8..02357ff195 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/DefaultWalletConnectComponent.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/DefaultWalletConnectComponent.kt @@ -27,13 +27,13 @@ internal class DefaultWalletConnectComponent @AssistedInject constructor( private val model: WalletConnectModel = getOrCreateModel() - private var screenState: MutableState? = null + private var screenState: MutableState = + mutableStateOf(model.updateState(store.state.walletConnectState)) init { lifecycle.subscribe( onCreate = { Analytics.send(WalletConnect.ScreenOpened()) - screenState = mutableStateOf(model.updateState(store.state.walletConnectState)) }, onStart = { store.subscribe(this) { state -> @@ -54,10 +54,9 @@ internal class DefaultWalletConnectComponent @AssistedInject constructor( @Composable override fun Content(modifier: Modifier) { - val state = screenState?.value ?: return WalletConnectScreen( modifier = modifier, - state = state, + state = screenState.value, onBackClick = { store.dispatchNavigationAction(AppRouter::pop) }, From 886dc6ee322ae893aa4e4ee067d0c721026f0d2a Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 19 Feb 2025 19:51:21 +0700 Subject: [PATCH 09/54] Updated on 2026-08-14 --- app/src/main/assets/tangem-app-config | 2 +- gradle/tangem_dependencies.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index 89dac3cd1e..a3549d3e15 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit 89dac3cd1e171d5801596ad151aa3af3fbc6c140 +Subproject commit a3549d3e156d3e1929649605798bf0239b4a29a0 diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index f9edc59dd5..967701e091 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -1,5 +1,5 @@ [versions] -tangemBlockchainSdk = "develop-952" +tangemBlockchainSdk = "develop-957" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "develop-434" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ From 4697ca6584e7b7090ff7be0c2a447cfa3ef9b687 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 20 Feb 2025 13:32:25 +0300 Subject: [PATCH 10/54] Updated on 2026-08-14 --- .../main/java/com/tangem/tap/MainActivity.kt | 4 - .../tangem/tap/routing/utils/ChildFactory.kt | 24 ++- .../com/tangem/common/routing/AppRoute.kt | 38 +---- .../com/tangem/core/decompose/model/Model.kt | 2 + features/qr-scanning/api/build.gradle.kts | 6 + .../feature/qrscanning/QrScanningComponent.kt | 15 ++ .../feature/qrscanning/QrScanningRouter.kt | 8 - features/qr-scanning/impl/build.gradle.kts | 1 + .../qrscanning/DefaultQrScanningComponent.kt | 142 ++++++++++++++++ .../feature/qrscanning/QrScanningFragment.kt | 158 ------------------ .../qrscanning/di/QrScanningFeatureModule.kt | 25 +++ .../qrscanning/di/QrScanningRouterModule.kt | 21 --- .../model/QrScanningClickIntents.kt | 16 ++ .../qrscanning/model/QrScanningModel.kt | 91 ++++++++++ .../navigation/DefaultQrScanningRouter.kt | 16 -- .../navigation/QrScanningInnerRouter.kt | 8 - .../InitializeQrScanningStateTransformer.kt | 2 +- .../ShowCameraDeniedBottomSheetTransformer.kt | 2 +- .../viewmodel/BaseQrScanningClickIntents.kt | 23 --- .../viewmodel/QrScanningClickIntents.kt | 67 -------- .../viewmodel/QrScanningViewModel.kt | 66 -------- 21 files changed, 323 insertions(+), 412 deletions(-) create mode 100644 features/qr-scanning/api/src/main/java/com/tangem/feature/qrscanning/QrScanningComponent.kt delete mode 100644 features/qr-scanning/api/src/main/java/com/tangem/feature/qrscanning/QrScanningRouter.kt create mode 100644 features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/DefaultQrScanningComponent.kt delete mode 100644 features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/QrScanningFragment.kt create mode 100644 features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/di/QrScanningFeatureModule.kt delete mode 100644 features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/di/QrScanningRouterModule.kt create mode 100644 features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/model/QrScanningClickIntents.kt create mode 100644 features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/model/QrScanningModel.kt delete mode 100644 features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/navigation/DefaultQrScanningRouter.kt delete mode 100644 features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/navigation/QrScanningInnerRouter.kt delete mode 100644 features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/viewmodel/BaseQrScanningClickIntents.kt delete mode 100644 features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/viewmodel/QrScanningClickIntents.kt delete mode 100644 features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/viewmodel/QrScanningViewModel.kt diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 72b9f67d82..9b8c16a128 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -59,7 +59,6 @@ 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 @@ -142,9 +141,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac @Inject lateinit var walletConnectInteractor: WalletConnectInteractor - @Inject - lateinit var qrScanningRouter: QrScanningRouter - @Inject lateinit var deepLinksRegistry: DeepLinksRegistry diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index 970abaae15..2342a80e63 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -2,7 +2,7 @@ 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.qrscanning.QrScanningComponent import com.tangem.feature.referral.ReferralFragment import com.tangem.feature.stories.api.StoriesComponent import com.tangem.feature.walletsettings.component.WalletSettingsComponent @@ -64,8 +64,8 @@ internal class ChildFactory @Inject constructor( private val homeComponentFactory: HomeComponent.Factory, private val tokenDetailsComponentFactory: TokenDetailsComponent.Factory, private val walletConnectComponentFactory: WalletConnectComponent.Factory, + private val qrScanningComponentFactory: QrScanningComponent.Factory, private val walletRouter: WalletRouter, - private val qrScanningRouter: QrScanningRouter, private val testerRouter: TesterRouter, private val pushNotificationRouter: PushNotificationsRouter, private val routingFeatureToggles: RoutingFeatureToggles, @@ -275,6 +275,16 @@ internal class ChildFactory @Inject constructor( componentFactory = walletConnectComponentFactory, ) } + is AppRoute.QrScanning -> { + createComponentChild( + contextProvider = contextProvider(route, contextFactory), + params = QrScanningComponent.Params( + source = route.source, + networkName = route.networkName, + ), + componentFactory = qrScanningComponentFactory, + ) + } is AppRoute.AccessCodeRecovery, is AppRoute.AppCurrencySelector, is AppRoute.SaveWallet, @@ -285,7 +295,6 @@ internal class ChildFactory @Inject constructor( is AppRoute.OnboardingOther, is AppRoute.OnboardingTwins, is AppRoute.OnboardingWallet, - is AppRoute.QrScanning, is AppRoute.ReferralProgram, is AppRoute.ResetToFactory, is AppRoute.Wallet, @@ -383,7 +392,14 @@ 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() }) diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt index f2c6c70148..62df97b518 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt @@ -93,20 +93,7 @@ sealed class AppRoute(val path: String) : Route { "&$amount" + "&$tag" + "&$destinationAddress", - ), - RouteBundleParams { - - override fun getBundle(): Bundle = bundle(serializer()) - - companion object { - const val USER_WALLET_ID_KEY = "userWalletId" - const val CRYPTO_CURRENCY_KEY = "currency" - const val TRANSACTION_ID_KEY = "transactionId" - const val AMOUNT_KEY = "amount" - const val TAG_KEY = "tag" - const val DESTINATION_ADDRESS_KEY = "destinationAddress" - } - } + ) @Serializable data class Details( @@ -196,15 +183,7 @@ sealed class AppRoute(val path: String) : Route { data class QrScanning( val source: SourceType, val networkName: String? = null, - ) : AppRoute(path = "/$source/qr_scanning${if (networkName != null) "/$networkName" else ""}"), RouteBundleParams { - - override fun getBundle(): Bundle = bundle(serializer()) - - companion object { - const val SOURCE_KEY = "source" - const val NETWORK_KEY = "networkName" - } - } + ) : AppRoute(path = "/$source/qr_scanning${if (networkName != null) "/$networkName" else ""}") @Serializable data class ReferralProgram( @@ -230,18 +209,7 @@ sealed class AppRoute(val path: String) : Route { "/${currencyTo?.id?.value}" + "/${userWalletId.stringValue}" + "/$isInitialReverseOrder", - ), - RouteBundleParams { - - override fun getBundle(): Bundle = bundle(serializer()) - - companion object { - const val CURRENCY_FROM_KEY = "currencyFrom" - const val CURRENCY_TO_KEY = "currencyTo" - const val USER_WALLET_ID_KEY = "userWalletId" - const val IS_INITIAL_REVERSE_ORDER = "isInitialReverseOrder" - } - } + ) @Serializable data object TesterMenu : AppRoute(path = "/tester_menu") diff --git a/core/decompose/src/main/kotlin/com/tangem/core/decompose/model/Model.kt b/core/decompose/src/main/kotlin/com/tangem/core/decompose/model/Model.kt index b1337c72f9..79ce712b57 100644 --- a/core/decompose/src/main/kotlin/com/tangem/core/decompose/model/Model.kt +++ b/core/decompose/src/main/kotlin/com/tangem/core/decompose/model/Model.kt @@ -6,6 +6,7 @@ import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.* import kotlinx.coroutines.flow.* +import javax.annotation.OverridingMethodsMustInvokeSuper /** * Abstract class for a component's model. @@ -29,6 +30,7 @@ abstract class Model : InstanceKeeper.Instance { CoroutineScope(context = dispatchers.mainImmediate + SupervisorJob()) } + @OverridingMethodsMustInvokeSuper override fun onDestroy() { runCatching { modelScope.cancel() } } diff --git a/features/qr-scanning/api/build.gradle.kts b/features/qr-scanning/api/build.gradle.kts index d88f0c6f03..5508ff8910 100644 --- a/features/qr-scanning/api/build.gradle.kts +++ b/features/qr-scanning/api/build.gradle.kts @@ -9,6 +9,12 @@ android { } dependencies { + /** Domain models */ + implementation(projects.domain.qrScanning.models) + + /** Core */ + implementation(projects.core.decompose) + implementation(projects.core.ui) /** AndroidX */ implementation(deps.androidx.fragment.ktx) diff --git a/features/qr-scanning/api/src/main/java/com/tangem/feature/qrscanning/QrScanningComponent.kt b/features/qr-scanning/api/src/main/java/com/tangem/feature/qrscanning/QrScanningComponent.kt new file mode 100644 index 0000000000..4789912572 --- /dev/null +++ b/features/qr-scanning/api/src/main/java/com/tangem/feature/qrscanning/QrScanningComponent.kt @@ -0,0 +1,15 @@ +package com.tangem.feature.qrscanning + +import com.tangem.core.decompose.factory.ComponentFactory +import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.domain.qrscanning.models.SourceType + +interface QrScanningComponent : ComposableContentComponent { + + data class Params( + val source: SourceType, + val networkName: String? = null, + ) + + interface Factory : ComponentFactory +} \ No newline at end of file diff --git a/features/qr-scanning/api/src/main/java/com/tangem/feature/qrscanning/QrScanningRouter.kt b/features/qr-scanning/api/src/main/java/com/tangem/feature/qrscanning/QrScanningRouter.kt deleted file mode 100644 index 049e039209..0000000000 --- a/features/qr-scanning/api/src/main/java/com/tangem/feature/qrscanning/QrScanningRouter.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.feature.qrscanning - -import androidx.fragment.app.Fragment - -interface QrScanningRouter { - - fun getEntryFragment(): Fragment -} \ No newline at end of file diff --git a/features/qr-scanning/impl/build.gradle.kts b/features/qr-scanning/impl/build.gradle.kts index f8bb506a61..5e1a8a4c8f 100644 --- a/features/qr-scanning/impl/build.gradle.kts +++ b/features/qr-scanning/impl/build.gradle.kts @@ -14,6 +14,7 @@ dependencies { /** Core */ implementation(projects.core.ui) + implementation(projects.core.decompose) implementation(projects.core.utils) implementation(projects.core.navigation) implementation(projects.common.routing) diff --git a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/DefaultQrScanningComponent.kt b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/DefaultQrScanningComponent.kt new file mode 100644 index 0000000000..2e00a6910d --- /dev/null +++ b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/DefaultQrScanningComponent.kt @@ -0,0 +1,142 @@ +package com.tangem.feature.qrscanning + +import android.Manifest +import android.content.pm.PackageManager +import android.net.Uri +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.core.content.ContextCompat +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.compose.LifecycleEventEffect +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.arkivanov.essenty.lifecycle.doOnDestroy +import com.google.mlkit.vision.common.InputImage +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.decompose.model.getOrCreateModel +import com.tangem.core.ui.components.SystemBarsIconsDisposable +import com.tangem.feature.qrscanning.inner.MLKitBarcodeAnalyzer +import com.tangem.feature.qrscanning.model.QrScanningModel +import com.tangem.feature.qrscanning.presentation.QrScanningContent +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.delay +import timber.log.Timber +import java.io.IOException +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors + +class DefaultQrScanningComponent @AssistedInject constructor( + @Assisted appComponentContext: AppComponentContext, + @Assisted params: QrScanningComponent.Params, +) : QrScanningComponent, AppComponentContext by appComponentContext { + + private val model: QrScanningModel = getOrCreateModel(params) + + private val cameraExecutor: ExecutorService = Executors.newSingleThreadExecutor() + // Camera requires its own analyzer instance due to flow of frames needed to be analyzed. + // Each new frame can cancel previous analysis e.i. image from the gallery can be skipped. + private val cameraAnalyzer: MLKitBarcodeAnalyzer by lazy(LazyThreadSafetyMode.NONE) { + MLKitBarcodeAnalyzer(model::onQrScanned) + } + private val analyzer: MLKitBarcodeAnalyzer by lazy(LazyThreadSafetyMode.NONE) { + MLKitBarcodeAnalyzer(model::onQrScanned) + } + + init { + lifecycle.doOnDestroy { cameraExecutor.shutdown() } + } + + @Composable + override fun Content(modifier: Modifier) { + val context = LocalContext.current + + val cameraPermissionLauncher = + rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> + if (isGranted.not()) { + model.onCameraDeniedState() + } + } + + val galleryLauncher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { + val selectedImage = it ?: Uri.EMPTY + if (selectedImage != Uri.EMPTY) { + val mimeType = context.contentResolver.getType(selectedImage) + if (mimeType.isImageMimeType()) { + try { + val image = InputImage.fromFilePath(context, selectedImage) + analyzer.analyze(image) + } catch (e: IOException) { + Timber.e(e, "Unable to get image $selectedImage from gallery") + } + } + } + } + + LaunchedEffect(Unit) { + model.launchGallery.collect { + galleryLauncher.launch(GALLERY_IMAGE_FILTER) + delay(timeMillis = 2000) + } + } + + LifecycleEventEffect( + event = Lifecycle.Event.ON_CREATE, + ) { + if ( + ContextCompat.checkSelfPermission( + context, + Manifest.permission.CAMERA, + ) == PackageManager.PERMISSION_DENIED + ) { + cameraPermissionLauncher.launch(Manifest.permission.CAMERA) + } + } + + LifecycleEventEffect( + event = Lifecycle.Event.ON_RESUME, + ) { + if (ContextCompat.checkSelfPermission( + context, + Manifest.permission.CAMERA, + ) == PackageManager.PERMISSION_GRANTED + ) { + model.onDismissBottomSheetState() + } + } + + ScreenContent(modifier) + } + + @Suppress("UnusedPrivateMember") + @Composable + private fun ScreenContent(modifier: Modifier = Modifier) { + SystemBarsIconsDisposable(darkIcons = false) + + QrScanningContent( + executor = { cameraExecutor }, + analyzer = { cameraAnalyzer }, + uiState = model.uiState.collectAsStateWithLifecycle().value, + ) + } + + private fun String?.isImageMimeType() = this?.startsWith(prefix = "$IMAGE_MIME_TYPE/") == true + + @AssistedFactory + interface Factory : QrScanningComponent.Factory { + override fun create( + context: AppComponentContext, + params: QrScanningComponent.Params, + ): DefaultQrScanningComponent + } + + companion object { + + private const val IMAGE_MIME_TYPE = "image" + private const val GALLERY_IMAGE_FILTER = "$IMAGE_MIME_TYPE/*" + } +} \ No newline at end of file diff --git a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/QrScanningFragment.kt b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/QrScanningFragment.kt deleted file mode 100644 index 787c7bdfe9..0000000000 --- a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/QrScanningFragment.kt +++ /dev/null @@ -1,158 +0,0 @@ -package com.tangem.feature.qrscanning - -import android.Manifest -import android.content.pm.PackageManager -import android.net.Uri -import android.os.Bundle -import android.view.View -import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.core.content.ContextCompat -import androidx.fragment.app.viewModels -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle -import com.google.mlkit.vision.common.InputImage -import com.tangem.core.ui.UiDependencies -import com.tangem.core.ui.components.SystemBarsIconsDisposable -import com.tangem.core.ui.screen.ComposeFragment -import com.tangem.feature.qrscanning.inner.MLKitBarcodeAnalyzer -import com.tangem.feature.qrscanning.navigation.QrScanningInnerRouter -import com.tangem.feature.qrscanning.presentation.QrScanningContent -import com.tangem.feature.qrscanning.viewmodel.QrScanningViewModel -import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import timber.log.Timber -import java.io.IOException -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors -import javax.inject.Inject -import kotlin.properties.Delegates - -@AndroidEntryPoint -internal class QrScanningFragment : ComposeFragment() { - - @Inject - override lateinit var uiDependencies: UiDependencies - - @Inject - lateinit var router: QrScanningRouter - - private val innerRouter: QrScanningInnerRouter - get() = requireNotNull(router as? QrScanningInnerRouter) { - "innerRouter should be instance of QrScanningInnerRouter" - } - - private val viewModel by viewModels() - - private var cameraExecutor: ExecutorService by Delegates.notNull() - // Camera requires its own analyzer instance due to flow of frames needed to be analyzed. - // Each new frame can cancel previous analysis e.i. image from the gallery can be skipped. - private val cameraAnalyzer: MLKitBarcodeAnalyzer by lazy(LazyThreadSafetyMode.NONE) { - MLKitBarcodeAnalyzer(viewModel::onQrScanned) - } - private val analyzer: MLKitBarcodeAnalyzer by lazy(LazyThreadSafetyMode.NONE) { - MLKitBarcodeAnalyzer(viewModel::onQrScanned) - } - - private val cameraPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { - if (!it) viewModel.onCameraDeniedState() - } - private val galleryLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { - val selectedImage = it ?: Uri.EMPTY - if (selectedImage != Uri.EMPTY) { - val mimeType = requireContext().contentResolver.getType(selectedImage) - if (mimeType.isImageMimeType()) { - try { - val image = InputImage.fromFilePath(requireContext(), selectedImage) - analyzer.analyze(image) - } catch (e: IOException) { - Timber.e(e, "Unable to get image $selectedImage from gallery") - } - } - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - viewModel.setRouter(innerRouter) - cameraExecutor = Executors.newSingleThreadExecutor() - requestCameraPermission() - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - viewLifecycleOwner.lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.launchGalleryEvent - .collect { - galleryLauncher.launch(GALLERY_IMAGE_FILTER) - delay(timeMillis = 2000) - } - } - } - } - - override fun onResume() { - super.onResume() - checkPermissionGranted() - } - - override fun onDestroy() { - super.onDestroy() - cameraPermissionLauncher.unregister() - cameraExecutor.shutdown() - } - - @Composable - override fun ScreenContent(modifier: Modifier) { - SystemBarsIconsDisposable(darkIcons = false) - - QrScanningContent( - executor = { cameraExecutor }, - analyzer = { cameraAnalyzer }, - uiState = viewModel.uiState.collectAsStateWithLifecycle().value, - ) - } - - /** - * Method for requesting permission if there isn't one. - */ - private fun requestCameraPermission() { - if ( - ContextCompat.checkSelfPermission( - requireContext(), - Manifest.permission.CAMERA, - ) == PackageManager.PERMISSION_DENIED - ) { - cameraPermissionLauncher.launch(Manifest.permission.CAMERA) - } - } - - /** - * Method for checking if permission was granted after user opened Settings screen. - * If permission was granted dismiss bottom sheet. - */ - private fun checkPermissionGranted() { - if (ContextCompat.checkSelfPermission( - requireContext(), - Manifest.permission.CAMERA, - ) == PackageManager.PERMISSION_GRANTED - ) { - viewModel.onDismissBottomSheetState() - } - } - - private fun String?.isImageMimeType() = this?.startsWith(prefix = "$IMAGE_MIME_TYPE/") == true - - companion object { - - private const val IMAGE_MIME_TYPE = "image" - private const val GALLERY_IMAGE_FILTER = "$IMAGE_MIME_TYPE/*" - - fun create() = QrScanningFragment() - } -} \ No newline at end of file diff --git a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/di/QrScanningFeatureModule.kt b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/di/QrScanningFeatureModule.kt new file mode 100644 index 0000000000..b623deb575 --- /dev/null +++ b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/di/QrScanningFeatureModule.kt @@ -0,0 +1,25 @@ +package com.tangem.feature.qrscanning.di + +import com.tangem.core.decompose.model.Model +import com.tangem.feature.qrscanning.DefaultQrScanningComponent +import com.tangem.feature.qrscanning.QrScanningComponent +import com.tangem.feature.qrscanning.model.QrScanningModel +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 QrScanningFeatureModule { + + @Binds + fun bindComponentFactory(impl: DefaultQrScanningComponent.Factory): QrScanningComponent.Factory + + @Binds + @IntoMap + @ClassKey(QrScanningModel::class) + fun bindModel(model: QrScanningModel): Model +} \ No newline at end of file diff --git a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/di/QrScanningRouterModule.kt b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/di/QrScanningRouterModule.kt deleted file mode 100644 index b22a6c713f..0000000000 --- a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/di/QrScanningRouterModule.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.feature.qrscanning.di - -import com.tangem.common.routing.AppRouter -import com.tangem.feature.qrscanning.QrScanningRouter -import com.tangem.feature.qrscanning.navigation.DefaultQrScanningRouter -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.components.ActivityComponent -import dagger.hilt.android.scopes.ActivityScoped - -@Module -@InstallIn(ActivityComponent::class) -internal object QrScanningRouterModule { - - @Provides - @ActivityScoped - fun provideQrScanRouter(appRouter: AppRouter): QrScanningRouter { - return DefaultQrScanningRouter(appRouter) - } -} \ No newline at end of file diff --git a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/model/QrScanningClickIntents.kt b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/model/QrScanningClickIntents.kt new file mode 100644 index 0000000000..b0702b0d62 --- /dev/null +++ b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/model/QrScanningClickIntents.kt @@ -0,0 +1,16 @@ +package com.tangem.feature.qrscanning.model + +import kotlinx.coroutines.flow.SharedFlow + +internal interface QrScanningClickIntents { + + val launchGallery: SharedFlow + + fun onBackClick() + + fun onQrScanned(qrCode: String) + + fun onGalleryClicked() + + fun onSettingsClick() +} \ No newline at end of file diff --git a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/model/QrScanningModel.kt b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/model/QrScanningModel.kt new file mode 100644 index 0000000000..1ba92657ba --- /dev/null +++ b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/model/QrScanningModel.kt @@ -0,0 +1,91 @@ +package com.tangem.feature.qrscanning.model + +import androidx.compose.runtime.Stable +import com.tangem.common.routing.AppRouter +import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.model.Model +import com.tangem.core.decompose.model.ParamsContainer +import com.tangem.core.navigation.settings.SettingsManager +import com.tangem.data.card.sdk.CardSdkProvider +import com.tangem.domain.qrscanning.usecases.EmitQrScannedEventUseCase +import com.tangem.feature.qrscanning.QrScanningComponent +import com.tangem.feature.qrscanning.presentation.QrScanningState +import com.tangem.feature.qrscanning.presentation.QrScanningStateController +import com.tangem.feature.qrscanning.presentation.transformers.DismissBottomSheetTransformer +import com.tangem.feature.qrscanning.presentation.transformers.InitializeQrScanningStateTransformer +import com.tangem.feature.qrscanning.presentation.transformers.ShowCameraDeniedBottomSheetTransformer +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@Suppress("LongParameterList") +@Stable +@ComponentScoped +internal class QrScanningModel @Inject constructor( + override val dispatchers: CoroutineDispatcherProvider, + paramsContainer: ParamsContainer, + private val stateHolder: QrScanningStateController, + private val cardSdkProvider: CardSdkProvider, + private val emitQrScannedEventUseCase: EmitQrScannedEventUseCase, + private val settingsManager: SettingsManager, + private val appRouter: AppRouter, +) : Model(), QrScanningClickIntents { + + private val params = paramsContainer.require() + val uiState: StateFlow = stateHolder.uiState + private var isScanned = false + + override val launchGallery = MutableSharedFlow( + extraBufferCapacity = 1, + onBufferOverflow = BufferOverflow.DROP_LATEST, + ) + + init { + // samsung for some reason disables reader mode, and then it works unstable + // to prevent this disable ir manually before scan QR + cardSdkProvider.sdk.forceDisableReaderMode() + stateHolder.update(InitializeQrScanningStateTransformer(this, params.source, params.networkName)) + } + + fun onCameraDeniedState() { + stateHolder.update(ShowCameraDeniedBottomSheetTransformer(this)) + } + + fun onDismissBottomSheetState() { + stateHolder.update(DismissBottomSheetTransformer()) + } + + override fun onBackClick() = appRouter.pop() + + override fun onQrScanned(qrCode: String) { + if (qrCode.isNotBlank()) { + modelScope.launch(dispatchers.mainImmediate) { + emitQrScannedEventUseCase.invoke(params.source, qrCode) + } + if (!isScanned) { + appRouter.pop() + isScanned = true + } + } + } + + override fun onGalleryClicked() { + launchGallery.tryEmit(Unit) + if (stateHolder.value.bottomSheetConfig != null) { + stateHolder.update(DismissBottomSheetTransformer()) + } + } + + override fun onSettingsClick() { + settingsManager.openAppSettings() + } + + override fun onDestroy() { + super.onDestroy() + // don't forget enable reader mode after scan complete + cardSdkProvider.sdk.forceEnableReaderMode() + } +} \ No newline at end of file diff --git a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/navigation/DefaultQrScanningRouter.kt b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/navigation/DefaultQrScanningRouter.kt deleted file mode 100644 index 3813274b68..0000000000 --- a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/navigation/DefaultQrScanningRouter.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.tangem.feature.qrscanning.navigation - -import androidx.fragment.app.Fragment -import com.tangem.common.routing.AppRouter - -import com.tangem.feature.qrscanning.QrScanningFragment - -class DefaultQrScanningRouter( - private val router: AppRouter, -) : QrScanningInnerRouter { - override fun getEntryFragment(): Fragment = QrScanningFragment.create() - - override fun popBackStack() { - router.pop() - } -} \ No newline at end of file diff --git a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/navigation/QrScanningInnerRouter.kt b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/navigation/QrScanningInnerRouter.kt deleted file mode 100644 index cdfb4cf247..0000000000 --- a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/navigation/QrScanningInnerRouter.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.feature.qrscanning.navigation - -import com.tangem.feature.qrscanning.QrScanningRouter - -interface QrScanningInnerRouter : QrScanningRouter { - - fun popBackStack() -} \ No newline at end of file diff --git a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/presentation/transformers/InitializeQrScanningStateTransformer.kt b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/presentation/transformers/InitializeQrScanningStateTransformer.kt index 2f38d3e545..7c6d08b333 100644 --- a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/presentation/transformers/InitializeQrScanningStateTransformer.kt +++ b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/presentation/transformers/InitializeQrScanningStateTransformer.kt @@ -5,7 +5,7 @@ import com.tangem.core.ui.extensions.wrappedList import com.tangem.domain.qrscanning.models.SourceType import com.tangem.feature.qrscanning.impl.R import com.tangem.feature.qrscanning.presentation.QrScanningState -import com.tangem.feature.qrscanning.viewmodel.QrScanningClickIntents +import com.tangem.feature.qrscanning.model.QrScanningClickIntents internal class InitializeQrScanningStateTransformer( private val clickIntents: QrScanningClickIntents, diff --git a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/presentation/transformers/ShowCameraDeniedBottomSheetTransformer.kt b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/presentation/transformers/ShowCameraDeniedBottomSheetTransformer.kt index 5dedeffebc..dfd650019f 100644 --- a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/presentation/transformers/ShowCameraDeniedBottomSheetTransformer.kt +++ b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/presentation/transformers/ShowCameraDeniedBottomSheetTransformer.kt @@ -3,7 +3,7 @@ package com.tangem.feature.qrscanning.presentation.transformers import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.feature.qrscanning.presentation.CameraDeniedBottomSheetConfig import com.tangem.feature.qrscanning.presentation.QrScanningState -import com.tangem.feature.qrscanning.viewmodel.QrScanningClickIntents +import com.tangem.feature.qrscanning.model.QrScanningClickIntents internal class ShowCameraDeniedBottomSheetTransformer( private val clickIntents: QrScanningClickIntents, diff --git a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/viewmodel/BaseQrScanningClickIntents.kt b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/viewmodel/BaseQrScanningClickIntents.kt deleted file mode 100644 index 2ff968422a..0000000000 --- a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/viewmodel/BaseQrScanningClickIntents.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.tangem.feature.qrscanning.viewmodel - -import com.tangem.domain.qrscanning.models.SourceType -import com.tangem.feature.qrscanning.navigation.QrScanningInnerRouter -import kotlinx.coroutines.CoroutineScope -import kotlin.properties.Delegates - -internal open class BaseQrScanningClickIntents { - - protected val router: QrScanningInnerRouter get() = _router - protected val viewModelScope: CoroutineScope get() = _viewModelScope - protected val source: SourceType get() = _source - - private var _router: QrScanningInnerRouter by Delegates.notNull() - private var _viewModelScope: CoroutineScope by Delegates.notNull() - private var _source: SourceType by Delegates.notNull() - - open fun initialize(router: QrScanningInnerRouter, source: SourceType, coroutineScope: CoroutineScope) { - _router = router - _viewModelScope = coroutineScope - _source = source - } -} \ No newline at end of file diff --git a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/viewmodel/QrScanningClickIntents.kt b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/viewmodel/QrScanningClickIntents.kt deleted file mode 100644 index adfaf8bcff..0000000000 --- a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/viewmodel/QrScanningClickIntents.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.tangem.feature.qrscanning.viewmodel - -import com.tangem.core.navigation.settings.SettingsManager -import com.tangem.domain.qrscanning.usecases.EmitQrScannedEventUseCase -import com.tangem.feature.qrscanning.presentation.QrScanningStateController -import com.tangem.feature.qrscanning.presentation.transformers.DismissBottomSheetTransformer -import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import dagger.hilt.android.scopes.ViewModelScoped -import kotlinx.coroutines.channels.BufferOverflow -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.launch -import javax.inject.Inject - -internal interface QrScanningClickIntents { - - val launchGallery: SharedFlow - - fun onBackClick() - - fun onQrScanned(qrCode: String) - - fun onGalleryClicked() - - fun onSettingsClick() -} - -@ViewModelScoped -internal class QrScanningClickIntentsImplementor @Inject constructor( - private val stateHolder: QrScanningStateController, - private val emitQrScannedEventUseCase: EmitQrScannedEventUseCase, - private val settingsManager: SettingsManager, - private val dispatcher: CoroutineDispatcherProvider, -) : BaseQrScanningClickIntents(), QrScanningClickIntents { - - private var isScanned = false - - override val launchGallery = MutableSharedFlow( - extraBufferCapacity = 1, - onBufferOverflow = BufferOverflow.DROP_LATEST, - ) - - override fun onBackClick() = router.popBackStack() - - override fun onQrScanned(qrCode: String) { - if (qrCode.isNotBlank()) { - viewModelScope.launch(dispatcher.mainImmediate) { - emitQrScannedEventUseCase.invoke(source, qrCode) - } - if (!isScanned) { - router.popBackStack() - isScanned = true - } - } - } - - override fun onGalleryClicked() { - launchGallery.tryEmit(Unit) - if (stateHolder.value.bottomSheetConfig != null) { - stateHolder.update(DismissBottomSheetTransformer()) - } - } - - override fun onSettingsClick() { - settingsManager.openAppSettings() - } -} \ No newline at end of file diff --git a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/viewmodel/QrScanningViewModel.kt b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/viewmodel/QrScanningViewModel.kt deleted file mode 100644 index ceff5566d6..0000000000 --- a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/viewmodel/QrScanningViewModel.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.tangem.feature.qrscanning.viewmodel - -import androidx.lifecycle.SavedStateHandle -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.tangem.common.routing.AppRoute -import com.tangem.data.card.sdk.CardSdkProvider -import com.tangem.domain.qrscanning.models.SourceType -import com.tangem.feature.qrscanning.navigation.QrScanningInnerRouter -import com.tangem.feature.qrscanning.presentation.QrScanningState -import com.tangem.feature.qrscanning.presentation.QrScanningStateController -import com.tangem.feature.qrscanning.presentation.transformers.DismissBottomSheetTransformer -import com.tangem.feature.qrscanning.presentation.transformers.InitializeQrScanningStateTransformer -import com.tangem.feature.qrscanning.presentation.transformers.ShowCameraDeniedBottomSheetTransformer -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.StateFlow -import javax.inject.Inject - -@HiltViewModel -internal class QrScanningViewModel @Inject constructor( - private val stateHolder: QrScanningStateController, - private val clickIntents: QrScanningClickIntentsImplementor, - private val cardSdkProvider: CardSdkProvider, - savedStateHandle: SavedStateHandle, -) : ViewModel() { - - private val source: SourceType = savedStateHandle.get(AppRoute.QrScanning.SOURCE_KEY) - ?.let { SourceType.entries[it] } - ?: error("Source is mandatory") - private val network: String? = savedStateHandle[AppRoute.QrScanning.NETWORK_KEY] - - val uiState: StateFlow = stateHolder.uiState - val launchGalleryEvent: SharedFlow = clickIntents.launchGallery - - init { - // samsung for some reason disables reader mode, and then it works unstable - // to prevent this disable ir manually before scan QR - cardSdkProvider.sdk.forceDisableReaderMode() - } - - fun setRouter(router: QrScanningInnerRouter) { - clickIntents.initialize( - router = router, - source = source, - coroutineScope = viewModelScope, - ) - stateHolder.update(InitializeQrScanningStateTransformer(clickIntents, source, network)) - } - - fun onQrScanned(qrCode: String) = clickIntents.onQrScanned(qrCode) - - fun onCameraDeniedState() { - stateHolder.update(ShowCameraDeniedBottomSheetTransformer(clickIntents)) - } - - fun onDismissBottomSheetState() { - stateHolder.update(DismissBottomSheetTransformer()) - } - - override fun onCleared() { - super.onCleared() - // don't forget enable reader mode after scan complete - cardSdkProvider.sdk.forceEnableReaderMode() - } -} \ No newline at end of file From 68e752b57041f288df58ea5863def63968a55c4f Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 20 Feb 2025 11:03:22 +0000 Subject: [PATCH 11/54] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index d49f7f2f1d..967701e091 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -1,7 +1,7 @@ [versions] -tangemBlockchainSdk = "release-app_5.21-955" +tangemBlockchainSdk = "develop-957" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "release-app_5.21-435" +tangemCardSdk = "develop-434" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "2.0.0-alpha.25-tangem-developments8" #tangemVico = "0.0.1" # Keep it! - used for local builds ^ From 111dea42be5f1abcca5f6b5356f5e9c9e02ad64b Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 20 Feb 2025 14:50:16 +0400 Subject: [PATCH 12/54] Updated on 2026-08-14 --- .../network/DefaultNetworksStatusesStore.kt | 37 +++++++++++++++---- .../local/network/NetworksStatusesStore.kt | 2 + .../local/quote/DefaultQuotesStore.kt | 29 ++++++++++----- .../datasource/local/quote/QuotesStore.kt | 2 + .../local/token/DefaultStakingBalanceStore.kt | 32 +++++++++++----- .../local/token/StakingBalanceStore.kt | 2 + .../data/staking/DefaultStakingRepository.kt | 4 ++ .../repository/DefaultNetworksRepository.kt | 13 +------ .../repository/DefaultQuotesRepository.kt | 4 ++ .../domain/tokens/model/NetworkStatus.kt | 15 +++++--- .../operations/CurrencyStatusOperations.kt | 1 - 11 files changed, 97 insertions(+), 44 deletions(-) diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/network/DefaultNetworksStatusesStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/network/DefaultNetworksStatusesStore.kt index f3e3d06f65..8a2e170bb9 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/network/DefaultNetworksStatusesStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/network/DefaultNetworksStatusesStore.kt @@ -72,14 +72,26 @@ internal class DefaultNetworksStatusesStore( override suspend fun storeAll(key: UserWalletId, values: Set) { coroutineScope { - val updatedValues = getSyncOrNull(key).orEmpty() - .addOrReplace(items = values) { prev, new -> prev.network == new.network } - - launch { runtimeDataStore.store(key = provideStringKey(key), value = updatedValues) } - launch { storeNetworkStatusInPersistence(userWalletId = key, statuses = updatedValues) } + launch { storeInRuntimeStore(key = key, statuses = values) } + launch { storeInPersistenceStore(userWalletId = key, statuses = values) } } } + override suspend fun refresh(key: UserWalletId, networks: Set) { + val currentStatuses = getSyncOrNull(key).orEmpty() + + storeInRuntimeStore( + key = key, + statuses = networks.mapNotNullTo(hashSetOf()) { network -> + val status = currentStatuses.firstOrNull { it.network.id == network.id } ?: return@mapNotNullTo null + + status.copy( + value = status.value.copySealed(source = StatusSource.CACHE), + ) + }, + ) + } + /** * Merge [cachedStatuses] with [runtimeStatuses] * The resulting set contains statuses from both sets. @@ -108,7 +120,6 @@ internal class DefaultNetworksStatusesStore( val updatedCachedStatus = when (val status = cached.value) { is NetworkStatus.NoAccount -> status.copy(source = StatusSource.ONLY_CACHE) is NetworkStatus.Verified -> status.copy(source = StatusSource.ONLY_CACHE) - is NetworkStatus.Refreshing, is NetworkStatus.Unreachable, is NetworkStatus.MissedDerivation, -> null @@ -121,13 +132,23 @@ internal class DefaultNetworksStatusesStore( } } - private suspend fun storeNetworkStatusInPersistence(userWalletId: UserWalletId, statuses: Set) { + private suspend fun storeInRuntimeStore(key: UserWalletId, statuses: Set) { + val updatedValues = getSyncOrNull(key).orEmpty() + .addOrReplace(items = statuses) { prev, new -> prev.network == new.network } + + runtimeDataStore.store(key = provideStringKey(key), value = updatedValues) + } + + private suspend fun storeInPersistenceStore(userWalletId: UserWalletId, statuses: Set) { // Converter will return null if the network status is not supported val newStatuses = NetworkStatusDataModelConverter.convertSet(input = statuses).filterNotNull().toSet() persistenceDataStore.updateData { storedStatuses -> storedStatuses.toMutableMap().apply { - this[userWalletId.stringValue] = newStatuses + val updatedValues = this[userWalletId.stringValue].orEmpty() + .addOrReplace(newStatuses) { prev, new -> prev.networkId == new.networkId } + + this[userWalletId.stringValue] = updatedValues } } } diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/network/NetworksStatusesStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/network/NetworksStatusesStore.kt index 81838f97aa..a1d92c60cc 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/network/NetworksStatusesStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/network/NetworksStatusesStore.kt @@ -16,4 +16,6 @@ interface NetworksStatusesStore { suspend fun store(key: UserWalletId, value: NetworkStatus) suspend fun storeAll(key: UserWalletId, values: Set) + + suspend fun refresh(key: UserWalletId, networks: Set) } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/quote/DefaultQuotesStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/quote/DefaultQuotesStore.kt index d7e5299c72..8cc69f2fda 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/quote/DefaultQuotesStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/quote/DefaultQuotesStore.kt @@ -52,17 +52,30 @@ internal class DefaultQuotesStore( override suspend fun store(response: QuotesResponse) { coroutineScope { - launch { storeInRuntimeStore(response = response) } + launch { + storeInRuntimeStore( + values = QuoteConverter(isCached = false).convertSet(input = response.quotes.entries), + ) + } launch { storeInPersistenceStore(response = response) } } } override suspend fun storeEmptyQuotes(currenciesIds: Set) { - runtimeStore.update(default = emptySet()) { saved -> - val new = currenciesIds.map { Quote.Empty(it) } + storeInRuntimeStore(values = currenciesIds.map(Quote::Empty).toSet()) + } - (saved + new).distinctBy { it.rawCurrencyId }.toSet() - } + override suspend fun refresh(currenciesIds: Set) { + val currentStatuses = getSync(currenciesIds) + + storeInRuntimeStore( + values = currentStatuses.mapTo(hashSetOf()) { quote -> + when (quote) { + is Quote.Empty -> quote + is Quote.Value -> quote.copy(source = StatusSource.CACHE) + } + }, + ) } private suspend fun getCachedQuotes(currenciesIds: Set): Set { @@ -95,11 +108,9 @@ internal class DefaultQuotesStore( ?: Quote.Empty(currencyId) } - private suspend fun storeInRuntimeStore(response: QuotesResponse) { - val new = QuoteConverter(isCached = false).convertSet(input = response.quotes.entries) - + private suspend fun storeInRuntimeStore(values: Set) { runtimeStore.update(default = emptySet()) { saved -> - (saved + new).distinctBy { it.rawCurrencyId }.toSet() + (saved + values).distinctBy { it.rawCurrencyId }.toSet() } } diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/quote/QuotesStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/quote/QuotesStore.kt index 4d632c3558..69b76b154b 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/quote/QuotesStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/quote/QuotesStore.kt @@ -19,4 +19,6 @@ interface QuotesStore { /** Store [Quote.Empty] for [currenciesIds] */ suspend fun storeEmptyQuotes(currenciesIds: Set) + + suspend fun refresh(currenciesIds: Set) } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/token/DefaultStakingBalanceStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/token/DefaultStakingBalanceStore.kt index 50de014b59..aaadb1d435 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/token/DefaultStakingBalanceStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/token/DefaultStakingBalanceStore.kt @@ -72,15 +72,26 @@ internal class DefaultStakingBalanceStore( override suspend fun store(userWalletId: UserWalletId, items: Set) { coroutineScope { launch { - storeInRuntimeStore( - userWalletId = userWalletId, - items = YieldBalanceConverter(isCached = false).convertSet(input = items), - ) + updateRuntimeStore(userWalletId = userWalletId) { + YieldBalanceConverter(isCached = false).convertSet(input = items) + } } launch { storeInPersistenceStore(userWalletId = userWalletId, items = items) } } } + override suspend fun refresh(userWalletId: UserWalletId) { + updateRuntimeStore(userWalletId = userWalletId) { saved -> + saved.mapTo(hashSetOf()) { + when (it) { + is YieldBalance.Data -> it.copy(source = StatusSource.CACHE) + is YieldBalance.Empty -> it.copy(source = StatusSource.CACHE) + is YieldBalance.Error -> it + } + } + } + } + override suspend fun store( userWalletId: UserWalletId, integrationId: String, @@ -107,13 +118,16 @@ internal class DefaultStakingBalanceStore( ?.addOrReplace(newBalance) { it.integrationId == integrationId && it.address == address } ?: setOf(newBalance) - storeInRuntimeStore(userWalletId = userWalletId, items = balances) + updateRuntimeStore(userWalletId = userWalletId) { balances } } - private suspend fun storeInRuntimeStore(userWalletId: UserWalletId, items: Set) { - runtimeStore.update(default = emptyMap()) { - it.toMutableMap().apply { - this[userWalletId] = items + private suspend fun updateRuntimeStore( + userWalletId: UserWalletId, + function: (Set) -> Set, + ) { + runtimeStore.update(default = emptyMap()) { saved -> + saved.toMutableMap().apply { + this[userWalletId] = function(this[userWalletId].orEmpty()) } } } diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/token/StakingBalanceStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/token/StakingBalanceStore.kt index 0638d1ac9f..c09987f7f4 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/token/StakingBalanceStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/token/StakingBalanceStore.kt @@ -26,4 +26,6 @@ interface StakingBalanceStore { /** Store [item] by [userWalletId], [integrationId] and [address] */ suspend fun store(userWalletId: UserWalletId, integrationId: String, address: String, item: YieldBalanceWrapperDTO) + + suspend fun refresh(userWalletId: UserWalletId) } \ No newline at end of file diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt index 4e4c6e7833..620bad0ce9 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt @@ -402,6 +402,10 @@ internal class DefaultStakingRepository( cryptoCurrencies: List, refresh: Boolean, ) = withContext(dispatchers.io) { + if (refresh) { + stakingBalanceStore.refresh(userWalletId = userWalletId) + } + cacheRegistry.invokeOnExpire( key = getYieldBalancesKey(userWalletId), skipCache = refresh, diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultNetworksRepository.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultNetworksRepository.kt index 0760786a7d..85fce53032 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultNetworksRepository.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultNetworksRepository.kt @@ -50,6 +50,7 @@ internal class DefaultNetworksRepository( networks: Set, ): Flow> { return networksStatusesStore.get(userWalletId, networks) + .distinctUntilChanged() .flowOn(dispatchers.io) } @@ -120,17 +121,7 @@ internal class DefaultNetworksRepository( refresh: Boolean, ) = coroutineScope { if (refresh) { - val statusesToRefresh = networksStatusesStore.getSyncOrNull(userWalletId)?.mapNotNull { - if (it.network in networks) { - it.copy(value = NetworkStatus.Refreshing) - } else { - null - } - } - - if (statusesToRefresh != null) { - networksStatusesStore.storeAll(key = userWalletId, values = statusesToRefresh.toSet()) - } + networksStatusesStore.refresh(key = userWalletId, networks = networks) } val currencies = getCurrencies(userWalletId, networks) diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultQuotesRepository.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultQuotesRepository.kt index 8c7ce6b8bf..0874594282 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultQuotesRepository.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultQuotesRepository.kt @@ -100,6 +100,10 @@ internal class DefaultQuotesRepository( // it changes after filterExpiredCurrenciesIds // calls with different coroutines and lead to fetchQuotes mutex.withLock { + if (refresh) { + quotesStore.refresh(currenciesIds) + } + val expiredCurrenciesIds = filterExpiredCurrenciesIds( currenciesIds = currenciesIds, refresh = refresh || quotesFetchedForAppCurrency != appCurrencyId, diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/NetworkStatus.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/NetworkStatus.kt index 1f9bd66e11..6bacb5067b 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/NetworkStatus.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/NetworkStatus.kt @@ -23,13 +23,16 @@ data class NetworkStatus( sealed class Value { abstract val source: StatusSource - } - /** - * Represents the state where the network is refreshing. - */ - data object Refreshing : Value() { - override val source: StatusSource = StatusSource.ACTUAL + fun copySealed(source: StatusSource): Value { + return when (this) { + is NoAccount -> copy(source = source) + is Verified -> copy(source = source) + is Unreachable, + is MissedDerivation, + -> this + } + } } /** diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt index 7e2dc0db71..d160103afe 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt @@ -30,7 +30,6 @@ internal class CurrencyStatusOperations( private fun createStatus(): CryptoCurrencyStatus.Value { return when (val status = networkStatus?.value) { null, - is NetworkStatus.Refreshing, -> CryptoCurrencyStatus.Loading is NetworkStatus.MissedDerivation -> createMissedDerivationStatus() is NetworkStatus.Unreachable -> createUnreachableStatus(status) From 1e5e55009c53314061495e37645c1f84bb6e63a6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 19 Feb 2025 18:03:27 +0700 Subject: [PATCH 13/54] Updated on 2026-08-14 --- app/src/main/assets/tangem-app-config | 2 +- .../mercuryo/MercuryoBlockchainMapping.kt | 2 ++ .../moonpay/MoonpayBlockchainMapping.kt | 2 ++ .../configs/excluded_blockchains_config.json | 8 +++++++ .../core/ui/extensions/BlockchainIcons.kt | 9 +++++++ core/ui/src/main/res/drawable/ic_vanar_22.xml | 9 +++++++ .../ui/src/main/res/drawable/ic_zklink_22.xml | 14 +++++++++++ .../ui/src/main/res/drawable/img_vanar_22.xml | 19 +++++++++++++++ .../src/main/res/drawable/img_zklink_22.xml | 24 +++++++++++++++++++ .../data/common/currency/NetworkOperations.kt | 2 ++ .../common/configs/Wallet2CardConfig.kt | 4 ++++ .../common/configs/Wallet2CardConfigTest.kt | 4 ++++ .../feature/swap/domain/SwapInteractorImpl.kt | 2 ++ gradle/tangem_dependencies.toml | 2 +- .../tangem/blockchainsdk/utils/Blockchain.kt | 10 ++++++++ 15 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 core/ui/src/main/res/drawable/ic_vanar_22.xml create mode 100644 core/ui/src/main/res/drawable/ic_zklink_22.xml create mode 100644 core/ui/src/main/res/drawable/img_vanar_22.xml create mode 100644 core/ui/src/main/res/drawable/img_zklink_22.xml diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index a3549d3e15..af8b453fd2 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit a3549d3e156d3e1929649605798bf0239b4a29a0 +Subproject commit af8b453fd25b29d949c05302ec282511dc2614b8 diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoBlockchainMapping.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoBlockchainMapping.kt index 8a647aeee9..3c20cb9f8e 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoBlockchainMapping.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoBlockchainMapping.kt @@ -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 } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonpayBlockchainMapping.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonpayBlockchainMapping.kt index aa3442e13d..a0f0c7f157 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonpayBlockchainMapping.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonpayBlockchainMapping.kt @@ -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 } \ No newline at end of file diff --git a/core/config-toggles/src/main/assets/configs/excluded_blockchains_config.json b/core/config-toggles/src/main/assets/configs/excluded_blockchains_config.json index f3fc207299..11acf26497 100644 --- a/core/config-toggles/src/main/assets/configs/excluded_blockchains_config.json +++ b/core/config-toggles/src/main/assets/configs/excluded_blockchains_config.json @@ -26,5 +26,13 @@ { "name": "alephium", "version": "5.21.0" + }, + { + "name": "scroll", + "version": "undefined" + }, + { + "name": "zklink", + "version": "undefined" } ] \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt b/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt index f3a42975bc..44c9a4dd6d 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt @@ -90,6 +90,9 @@ fun getActiveIconRes(blockchainId: String): Int { "bitrock", "bitrock/test" -> R.drawable.img_bitrock_22 "sonic", "sonic/test" -> R.drawable.img_sonic_22 "apechain", "apechain/test" -> R.drawable.img_apecoin_22 + "scroll", "scroll/test" -> R.drawable.ic_alert_24 // FIXME: add icon during full integration + "zklink", "zklink/test" -> R.drawable.img_zklink_22 + "vanar-chain", "vanar-chain/test" -> R.drawable.img_vanar_22 else -> R.drawable.ic_alert_24 } } @@ -178,6 +181,9 @@ fun getActiveIconResByCoinId(coinId: String): Int { "bitrock", "bitrock/test" -> R.drawable.img_bitrock_22 "sonic", "sonic/test" -> R.drawable.img_sonic_22 "apechain", "apechain/test" -> R.drawable.img_apecoin_22 + "scroll", "scroll/test" -> R.drawable.ic_alert_24 // FIXME: add icon during full integration + "zklink", "zklink/test" -> R.drawable.img_zklink_22 + "vanar-chain", "vanar-chain/test" -> R.drawable.img_vanar_22 else -> R.drawable.ic_alert_24 } } @@ -269,6 +275,9 @@ fun getGreyedOutIconRes(blockchainId: String): Int { "bitrock", "bitrock/test" -> R.drawable.ic_bitrock_22 "sonic", "sonic/test" -> R.drawable.ic_sonic_22 "apechain", "apechain/test" -> R.drawable.ic_apecoin_22 + "scroll", "scroll/test" -> R.drawable.ic_alert_24 // FIXME: add icon during full integration + "zklink", "zklink/test" -> R.drawable.ic_zklink_22 + "vanar-chain", "vanar-chain/test" -> R.drawable.ic_vanar_22 else -> R.drawable.ic_alert_24 } } \ No newline at end of file diff --git a/core/ui/src/main/res/drawable/ic_vanar_22.xml b/core/ui/src/main/res/drawable/ic_vanar_22.xml new file mode 100644 index 0000000000..3ddb0cea23 --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_vanar_22.xml @@ -0,0 +1,9 @@ + + + diff --git a/core/ui/src/main/res/drawable/ic_zklink_22.xml b/core/ui/src/main/res/drawable/ic_zklink_22.xml new file mode 100644 index 0000000000..70fb36416d --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_zklink_22.xml @@ -0,0 +1,14 @@ + + + + diff --git a/core/ui/src/main/res/drawable/img_vanar_22.xml b/core/ui/src/main/res/drawable/img_vanar_22.xml new file mode 100644 index 0000000000..7fc4405bcb --- /dev/null +++ b/core/ui/src/main/res/drawable/img_vanar_22.xml @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/core/ui/src/main/res/drawable/img_zklink_22.xml b/core/ui/src/main/res/drawable/img_zklink_22.xml new file mode 100644 index 0000000000..91405830fc --- /dev/null +++ b/core/ui/src/main/res/drawable/img_zklink_22.xml @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/data/common/src/main/kotlin/com/tangem/data/common/currency/NetworkOperations.kt b/data/common/src/main/kotlin/com/tangem/data/common/currency/NetworkOperations.kt index 31d90fac3f..a0fde030cc 100644 --- a/data/common/src/main/kotlin/com/tangem/data/common/currency/NetworkOperations.kt +++ b/data/common/src/main/kotlin/com/tangem/data/common/currency/NetworkOperations.kt @@ -299,6 +299,8 @@ private fun Blockchain.getSupportedTransactionExtras(): Network.TransactionExtra Blockchain.Bitrock, Blockchain.BitrockTestnet, Blockchain.Sonic, Blockchain.SonicTestnet, Blockchain.ApeChain, Blockchain.ApeChainTestnet, + Blockchain.Scroll, Blockchain.ScrollTestnet, + Blockchain.ZkLinkNova, Blockchain.ZkLinkNovaTestnet, -> Network.TransactionExtrasType.NONE // endregion } diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/configs/Wallet2CardConfig.kt b/domain/legacy/src/main/java/com/tangem/domain/common/configs/Wallet2CardConfig.kt index 79355cd5c6..aa0a5e23e6 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/common/configs/Wallet2CardConfig.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/common/configs/Wallet2CardConfig.kt @@ -201,6 +201,10 @@ data object Wallet2CardConfig : CardConfig { Blockchain.KaspaTestnet -> EllipticCurve.Secp256k1 Blockchain.Alephium -> EllipticCurve.Secp256k1 Blockchain.AlephiumTestnet -> EllipticCurve.Secp256k1 + Blockchain.Scroll -> EllipticCurve.Secp256k1 + Blockchain.ScrollTestnet -> EllipticCurve.Secp256k1 + Blockchain.ZkLinkNova -> EllipticCurve.Secp256k1 + Blockchain.ZkLinkNovaTestnet -> EllipticCurve.Secp256k1 } } } \ No newline at end of file diff --git a/domain/legacy/src/test/java/com/tangem/domain/common/configs/Wallet2CardConfigTest.kt b/domain/legacy/src/test/java/com/tangem/domain/common/configs/Wallet2CardConfigTest.kt index 3faea63878..d80b9be554 100644 --- a/domain/legacy/src/test/java/com/tangem/domain/common/configs/Wallet2CardConfigTest.kt +++ b/domain/legacy/src/test/java/com/tangem/domain/common/configs/Wallet2CardConfigTest.kt @@ -158,6 +158,10 @@ class Wallet2CardConfigTest { Blockchain.KaspaTestnet to EllipticCurve.Secp256k1, Blockchain.Alephium to EllipticCurve.Secp256k1, Blockchain.AlephiumTestnet to EllipticCurve.Secp256k1, + Blockchain.Scroll to EllipticCurve.Secp256k1, + Blockchain.ScrollTestnet to EllipticCurve.Secp256k1, + Blockchain.ZkLinkNova to EllipticCurve.Secp256k1, + Blockchain.ZkLinkNovaTestnet to EllipticCurve.Secp256k1, ) @Test diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index 7cc9ebc2f2..a36223d839 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -989,6 +989,8 @@ internal class SwapInteractorImpl @AssistedInject constructor( Bitrock, BitrockTestnet, Sonic, SonicTestnet, ApeChain, ApeChainTestnet, + Scroll, ScrollTestnet, + ZkLinkNova, ZkLinkNovaTestnet, -> Fee.Common(feeAmount) // endregion } diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 967701e091..b58666bdd9 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -1,5 +1,5 @@ [versions] -tangemBlockchainSdk = "develop-957" +tangemBlockchainSdk = "develop-959" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "develop-434" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ diff --git a/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/utils/Blockchain.kt b/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/utils/Blockchain.kt index 866170f4c5..dc2f9b8a81 100644 --- a/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/utils/Blockchain.kt +++ b/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/utils/Blockchain.kt @@ -159,6 +159,10 @@ fun Blockchain.Companion.fromNetworkId(networkId: String): Blockchain? { "apechain" -> Blockchain.ApeChain "apechain/test" -> Blockchain.ApeChainTestnet "kaspa/test" -> Blockchain.KaspaTestnet + "scroll" -> Blockchain.Scroll + "scroll/test" -> Blockchain.ScrollTestnet + "zklink" -> Blockchain.ZkLinkNova + "zklink/test" -> Blockchain.ZkLinkNovaTestnet else -> null } } @@ -315,6 +319,10 @@ fun Blockchain.toNetworkId(): String { Blockchain.SonicTestnet -> "sonic/test" Blockchain.ApeChain -> "apechain" Blockchain.ApeChainTestnet -> "apechain/test" + Blockchain.Scroll -> "scroll" + Blockchain.ScrollTestnet -> "scroll/test" + Blockchain.ZkLinkNova -> "zklink" + Blockchain.ZkLinkNovaTestnet -> "zklink/test" } } @@ -415,6 +423,8 @@ fun Blockchain.toCoinId(): String { Blockchain.Bitrock, Blockchain.BitrockTestnet -> "bitrock" Blockchain.Sonic, Blockchain.SonicTestnet -> "sonic-3" Blockchain.ApeChain, Blockchain.ApeChainTestnet -> "apecoin" + Blockchain.Scroll, Blockchain.ScrollTestnet -> "scroll" + Blockchain.ZkLinkNova, Blockchain.ZkLinkNovaTestnet -> "zklink" } } From 08a78738cb2d6821064a56e0179a45ccf2335f7a Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 21 Feb 2025 12:07:39 +0300 Subject: [PATCH 14/54] Updated on 2026-08-14 --- .../impl/child/seedphrase/ui/MultiWalletSeedPhraseWords.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseWords.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseWords.kt index f5ac73fd97..1099d8bcc1 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseWords.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseWords.kt @@ -84,8 +84,8 @@ private fun SegmentSeedBlock(state: MultiWalletSeedPhraseUM.GenerateSeedPhrase, Text( text = pluralStringResourceSafe( id = R.plurals.onboarding_seed_generate_words_count, - count = state.option.length, - state.option.length, + count = it.length, + it.length, ), modifier = Modifier .padding(vertical = TangemTheme.dimens.spacing10) From 3477c8f5911b94b7114d03a2d29f8295a4ed7d35 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 21 Feb 2025 12:07:59 +0300 Subject: [PATCH 15/54] Updated on 2026-08-14 --- .../ui/cardsettings/CardSettingsFragment.kt | 27 ------------ .../DefaultCardSettingsComponent.kt | 36 ++++++++++++++++ .../cardsettings/api/CardSettingsComponent.kt | 14 +++++++ .../AccessCodeRecoveryFragment.kt | 33 --------------- .../DefaultAccessCodeRecoveryComponent.kt | 40 ++++++++++++++++++ .../api/AccessCodeRecoveryComponent.kt | 9 ++++ .../di/AccessCodeRecoveryFeatureModule.kt | 25 +++++++++++ .../AccessCodeRecoveryModel.kt} | 20 +++++---- .../di/CardSettingsFeatureModule.kt | 25 +++++++++++ .../CardSettingsModel.kt} | 42 ++++++++++--------- .../tangem/tap/routing/utils/ChildFactory.kt | 34 ++++++++++++--- .../com/tangem/common/routing/AppRoute.kt | 9 +--- .../visa/model/VisaActivationOrderInfo.kt | 2 + 13 files changed, 215 insertions(+), 101 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsFragment.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/DefaultCardSettingsComponent.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/api/CardSettingsComponent.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/AccessCodeRecoveryFragment.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/DefaultAccessCodeRecoveryComponent.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/api/AccessCodeRecoveryComponent.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/di/AccessCodeRecoveryFeatureModule.kt rename app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/{AccessCodeRecoveryViewModel.kt => model/AccessCodeRecoveryModel.kt} (84%) create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/di/CardSettingsFeatureModule.kt rename app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/{CardSettingsViewModel.kt => model/CardSettingsModel.kt} (89%) diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsFragment.kt deleted file mode 100644 index 328815f377..0000000000 --- a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsFragment.kt +++ /dev/null @@ -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) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/DefaultCardSettingsComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/DefaultCardSettingsComponent.kt new file mode 100644 index 0000000000..bb92d1a9a1 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/DefaultCardSettingsComponent.kt @@ -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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/api/CardSettingsComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/api/CardSettingsComponent.kt new file mode 100644 index 0000000000..608362caa8 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/api/CardSettingsComponent.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/AccessCodeRecoveryFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/AccessCodeRecoveryFragment.kt deleted file mode 100644 index bcfe7cd28d..0000000000 --- a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/AccessCodeRecoveryFragment.kt +++ /dev/null @@ -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) }, - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/DefaultAccessCodeRecoveryComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/DefaultAccessCodeRecoveryComponent.kt new file mode 100644 index 0000000000..fd75548292 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/DefaultAccessCodeRecoveryComponent.kt @@ -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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/api/AccessCodeRecoveryComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/api/AccessCodeRecoveryComponent.kt new file mode 100644 index 0000000000..5cd2e1449c --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/api/AccessCodeRecoveryComponent.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/di/AccessCodeRecoveryFeatureModule.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/di/AccessCodeRecoveryFeatureModule.kt new file mode 100644 index 0000000000..a4c86d70a7 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/di/AccessCodeRecoveryFeatureModule.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/AccessCodeRecoveryViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/model/AccessCodeRecoveryModel.kt similarity index 84% rename from app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/AccessCodeRecoveryViewModel.kt rename to app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/model/AccessCodeRecoveryModel.kt index 1652506ca9..b3c2fb4878 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/AccessCodeRecoveryViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/model/AccessCodeRecoveryModel.kt @@ -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.ComponentScoped +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 +@ComponentScoped +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 diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/di/CardSettingsFeatureModule.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/di/CardSettingsFeatureModule.kt new file mode 100644 index 0000000000..78f5ba6486 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/di/CardSettingsFeatureModule.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt similarity index 89% rename from app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsViewModel.kt rename to app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt index 68d354a90c..11964f58c4 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt @@ -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.ComponentScoped +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 +@ComponentScoped +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() private var previousBiometricsRequestPolicy: Boolean = false - private val userWalletId = savedStateHandle.get(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 = 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)) { diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index 2342a80e63..5818faad8e 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -22,8 +22,8 @@ import com.tangem.features.tokendetails.TokenDetailsComponent 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.cardsettings.api.CardSettingsComponent +import com.tangem.tap.features.details.ui.cardsettings.coderecovery.api.AccessCodeRecoveryComponent 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.api.WalletConnectComponent @@ -65,6 +65,8 @@ internal class ChildFactory @Inject constructor( 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 walletRouter: WalletRouter, private val testerRouter: TesterRouter, private val pushNotificationRouter: PushNotificationsRouter, @@ -285,11 +287,23 @@ internal class ChildFactory @Inject constructor( componentFactory = qrScanningComponentFactory, ) } - is AppRoute.AccessCodeRecovery, + 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, is AppRoute.SaveWallet, is AppRoute.AppSettings, - is AppRoute.CardSettings, is AppRoute.DetailsSecurity, is AppRoute.OnboardingNote, is AppRoute.OnboardingOther, @@ -314,7 +328,11 @@ 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() }) @@ -340,7 +358,11 @@ internal class ChildFactory @Inject constructor( route.asFragmentChild(Provider { AppSettingsFragment() }) } 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( diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt index 62df97b518..2d3246daa6 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt @@ -111,14 +111,7 @@ sealed class AppRoute(val path: String) : Route { @Serializable data class CardSettings( val userWalletId: UserWalletId, - ) : AppRoute(path = "/card_settings/${userWalletId.stringValue}"), RouteBundleParams { - - override fun getBundle(): Bundle = bundle(serializer()) - - companion object { - const val USER_WALLET_ID_KEY = "userWalletId" - } - } + ) : AppRoute(path = "/card_settings/${userWalletId.stringValue}") @Serializable data object AppSettings : AppRoute(path = "/app_settings") diff --git a/domain/visa/models/src/main/kotlin/com/tangem/domain/visa/model/VisaActivationOrderInfo.kt b/domain/visa/models/src/main/kotlin/com/tangem/domain/visa/model/VisaActivationOrderInfo.kt index b8320e7678..78bbd9692b 100644 --- a/domain/visa/models/src/main/kotlin/com/tangem/domain/visa/model/VisaActivationOrderInfo.kt +++ b/domain/visa/models/src/main/kotlin/com/tangem/domain/visa/model/VisaActivationOrderInfo.kt @@ -1,9 +1,11 @@ package com.tangem.domain.visa.model import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass import kotlinx.serialization.Serializable @Serializable +@JsonClass(generateAdapter = true) data class VisaActivationOrderInfo( @Json(name = "orderId") val orderId: String, @Json(name = "customer_id") val customerId: String, From 2c65f0cfb0375d0c2e26ad134f84d948f807ec2d Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 21 Feb 2025 12:16:36 +0300 Subject: [PATCH 16/54] Updated on 2026-08-14 --- .../main/java/com/tangem/tap/MainActivity.kt | 5 ++++ data/balance-hiding/build.gradle.kts | 1 + .../DefaultBalanceHidingRepository.kt | 5 +++- .../DefaultDeviceFlipDetector.kt | 26 +++++++++++++++++-- .../balancehiding/di/BalanceHidingModule.kt | 19 +++++--------- 5 files changed, 40 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 9b8c16a128..20410b9a00 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -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 @@ -205,6 +206,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 @@ -271,6 +275,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac } lifecycle.addObserver(WindowObscurationObserver) + lifecycle.addObserver(defaultDeviceFlipDetector) } private fun installEventMessageEffect() { diff --git a/data/balance-hiding/build.gradle.kts b/data/balance-hiding/build.gradle.kts index 84db19b2d7..3d3caf3397 100644 --- a/data/balance-hiding/build.gradle.kts +++ b/data/balance-hiding/build.gradle.kts @@ -12,6 +12,7 @@ android { dependencies { implementation(deps.androidx.datastore) + implementation(deps.androidx.appCompat) /** DI */ implementation(deps.hilt.android) diff --git a/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/DefaultBalanceHidingRepository.kt b/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/DefaultBalanceHidingRepository.kt index f2fdcd320e..b0200df3ff 100644 --- a/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/DefaultBalanceHidingRepository.kt +++ b/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/DefaultBalanceHidingRepository.kt @@ -8,8 +8,11 @@ import com.tangem.datasource.local.preferences.utils.storeObject import com.tangem.domain.balancehiding.BalanceHidingSettings import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository import kotlinx.coroutines.flow.Flow +import javax.inject.Inject +import javax.inject.Singleton -internal class DefaultBalanceHidingRepository( +@Singleton +internal class DefaultBalanceHidingRepository @Inject constructor( private val appPreferencesStore: AppPreferencesStore, ) : BalanceHidingRepository { diff --git a/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/DefaultDeviceFlipDetector.kt b/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/DefaultDeviceFlipDetector.kt index 30b2e97726..9a4c8de638 100644 --- a/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/DefaultDeviceFlipDetector.kt +++ b/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/DefaultDeviceFlipDetector.kt @@ -3,18 +3,40 @@ package com.tangem.data.balancehiding import android.content.Context import android.hardware.Sensor import android.hardware.SensorManager +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner import com.tangem.domain.balancehiding.DeviceFlipDetector +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow +import java.util.concurrent.atomic.AtomicBoolean +import javax.inject.Inject +import javax.inject.Singleton -internal class DefaultDeviceFlipDetector(context: Context) : DeviceFlipDetector { +@Singleton +class DefaultDeviceFlipDetector @Inject constructor( + @ApplicationContext context: Context, +) : DeviceFlipDetector, DefaultLifecycleObserver { private val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager private var gravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) + private var isResumedState = AtomicBoolean(false) + + override fun onPause(owner: LifecycleOwner) { + isResumedState.set(false) + } + + override fun onResume(owner: LifecycleOwner) { + isResumedState.set(true) + } override fun getDeviceFlipFlow(): Flow = callbackFlow { - val listener = FlipListener { trySend(Unit) } + val listener = FlipListener { + if (isResumedState.get()) { + trySend(Unit) + } + } gravitySensor?.let { sensorManager.registerListener(listener, it, SensorManager.SENSOR_DELAY_NORMAL) diff --git a/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/di/BalanceHidingModule.kt b/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/di/BalanceHidingModule.kt index f83fac4932..0f213c83f8 100644 --- a/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/di/BalanceHidingModule.kt +++ b/data/balance-hiding/src/main/java/com/tangem/data/balancehiding/di/BalanceHidingModule.kt @@ -1,31 +1,24 @@ package com.tangem.data.balancehiding.di -import android.content.Context import com.tangem.data.balancehiding.DefaultBalanceHidingRepository import com.tangem.data.balancehiding.DefaultDeviceFlipDetector -import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.domain.balancehiding.DeviceFlipDetector import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository +import dagger.Binds import dagger.Module -import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) -internal object BalanceHidingModule { +internal interface BalanceHidingModule { - @Provides + @Binds @Singleton - fun provideBalanceHidingRepository(appPreferencesStore: AppPreferencesStore): BalanceHidingRepository { - return DefaultBalanceHidingRepository(appPreferencesStore = appPreferencesStore) - } + fun provideBalanceHidingRepository(impl: DefaultBalanceHidingRepository): BalanceHidingRepository - @Provides + @Binds @Singleton - fun provideFlipDetector(@ApplicationContext context: Context): DeviceFlipDetector { - return DefaultDeviceFlipDetector(context = context) - } + fun provideFlipDetector(impl: DefaultDeviceFlipDetector): DeviceFlipDetector } \ No newline at end of file From 6afeba5f96c50c66537cc642a7cb9da3fd739e4d Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 21 Feb 2025 11:26:05 +0000 Subject: [PATCH 17/54] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 2b6ab573a0..b58666bdd9 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -1,7 +1,7 @@ [versions] -tangemBlockchainSdk = "release-app_5.21-958" +tangemBlockchainSdk = "develop-959" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "release-app_5.21-435" +tangemCardSdk = "develop-434" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "2.0.0-alpha.25-tangem-developments8" #tangemVico = "0.0.1" # Keep it! - used for local builds ^ From c5d78b20407b744d8224b092f1eaff8018b03463 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 24 Feb 2025 00:58:45 +0500 Subject: [PATCH 18/54] Updated on 2026-08-14 --- .../configs/feature_toggles_config.json | 4 ++ .../local/preferences/PreferencesKeys.kt | 2 + .../data/wallets/DefaultWalletsRepository.kt | 20 ++++++ .../wallets/repository/WalletsRepository.kt | 6 ++ features/nft/api/.gitignore | 1 + features/nft/api/build.gradle.kts | 22 +++++++ .../tangem/features/nft/NFTFeatureToggles.kt | 5 ++ features/nft/impl/.gitignore | 1 + features/nft/impl/build.gradle.kts | 66 +++++++++++++++++++ .../features/nft/DefaultNFTFeatureToggles.kt | 10 +++ .../tangem/features/nft/NFTFeatureModule.kt | 19 ++++++ 11 files changed, 156 insertions(+) create mode 100644 features/nft/api/.gitignore create mode 100644 features/nft/api/build.gradle.kts create mode 100644 features/nft/api/src/main/kotlin/com/tangem/features/nft/NFTFeatureToggles.kt create mode 100644 features/nft/impl/.gitignore create mode 100644 features/nft/impl/build.gradle.kts create mode 100644 features/nft/impl/src/main/kotlin/com/tangem/features/nft/DefaultNFTFeatureToggles.kt create mode 100644 features/nft/impl/src/main/kotlin/com/tangem/features/nft/NFTFeatureModule.kt diff --git a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json index ba2bb626ea..92d4653d08 100644 --- a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json @@ -46,5 +46,9 @@ { "name": "BALANCES_CACHING_ENABLED", "version": "5.21.0" + }, + { + "name": "NFT_ENABLED", + "version": "undefined" } ] diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt index 434d4c4a92..52d244da2b 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt @@ -121,6 +121,8 @@ object PreferencesKeys { val SEED_FIRST_NOTIFICATION_SHOW_TIME by lazy { longPreferencesKey("seedFirstNotificationTime") } + val WALLETS_WITH_NFT_ENABLED_KEY by lazy { stringSetPreferencesKey(name = "walletsWithNftEnabled") } + fun getShouldShowStoriesKey(storyId: String) = booleanPreferencesKey("shouldShowStories_$storyId") // region Permission diff --git a/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletsRepository.kt b/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletsRepository.kt index 0d0c0f38ee..e8a5b95b08 100644 --- a/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletsRepository.kt +++ b/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletsRepository.kt @@ -202,4 +202,24 @@ internal class DefaultWalletsRepository( } } } + + override fun nftEnabledStatus(userWalletId: UserWalletId): Flow { + return appPreferencesStore + .get(key = PreferencesKeys.WALLETS_WITH_NFT_ENABLED_KEY, default = emptySet()) + .map { it.contains(userWalletId.stringValue) } + } + + override suspend fun enableNFT(userWalletId: UserWalletId) { + appPreferencesStore.editData { + val added = it[PreferencesKeys.WALLETS_WITH_NFT_ENABLED_KEY].orEmpty() + it[PreferencesKeys.WALLETS_WITH_NFT_ENABLED_KEY] = added + userWalletId.stringValue + } + } + + override suspend fun disableNFT(userWalletId: UserWalletId) { + appPreferencesStore.editData { + val added = it[PreferencesKeys.WALLETS_WITH_NFT_ENABLED_KEY].orEmpty() + it[PreferencesKeys.WALLETS_WITH_NFT_ENABLED_KEY] = added - userWalletId.stringValue + } + } } \ No newline at end of file diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletsRepository.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletsRepository.kt index f226543d60..b1e526ce5c 100644 --- a/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletsRepository.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletsRepository.kt @@ -29,4 +29,10 @@ interface WalletsRepository { suspend fun acceptSeedPhraseSecondNotification(userWalletId: UserWalletId) suspend fun markWallet2WasCreated(userWalletId: UserWalletId) + + fun nftEnabledStatus(userWalletId: UserWalletId): Flow + + suspend fun enableNFT(userWalletId: UserWalletId) + + suspend fun disableNFT(userWalletId: UserWalletId) } \ No newline at end of file diff --git a/features/nft/api/.gitignore b/features/nft/api/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/features/nft/api/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/features/nft/api/build.gradle.kts b/features/nft/api/build.gradle.kts new file mode 100644 index 0000000000..f94a0582c0 --- /dev/null +++ b/features/nft/api/build.gradle.kts @@ -0,0 +1,22 @@ +plugins { + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) + id("configuration") +} + +android { + namespace = "com.tangem.features.nft.api" +} + +dependencies { + + /* Project - Domain */ + implementation(projects.domain.models) + + /* Project - Core */ + implementation(projects.core.decompose) + implementation(projects.core.ui) + + /* Compose */ + implementation(deps.compose.runtime) +} \ No newline at end of file diff --git a/features/nft/api/src/main/kotlin/com/tangem/features/nft/NFTFeatureToggles.kt b/features/nft/api/src/main/kotlin/com/tangem/features/nft/NFTFeatureToggles.kt new file mode 100644 index 0000000000..a3b0ad1cb5 --- /dev/null +++ b/features/nft/api/src/main/kotlin/com/tangem/features/nft/NFTFeatureToggles.kt @@ -0,0 +1,5 @@ +package com.tangem.features.nft + +interface NFTFeatureToggles { + val isNFTEnabled: Boolean +} \ No newline at end of file diff --git a/features/nft/impl/.gitignore b/features/nft/impl/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/features/nft/impl/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/features/nft/impl/build.gradle.kts b/features/nft/impl/build.gradle.kts new file mode 100644 index 0000000000..0de9bbcd2d --- /dev/null +++ b/features/nft/impl/build.gradle.kts @@ -0,0 +1,66 @@ +plugins { + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) + alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.kotlin.serialization) + alias(deps.plugins.hilt.android) + id("configuration") +} + +android { + namespace = "com.tangem.features.nft.impl" +} + +dependencies { + /** Api */ + implementation(projects.features.nft.api) + + /** Core modules */ + implementation(projects.core.configToggles) + implementation(projects.core.analytics) + implementation(projects.core.analytics.models) + implementation(projects.core.utils) + implementation(projects.core.ui) + implementation(projects.core.res) + implementation(projects.core.decompose) + implementation(projects.core.navigation) + implementation(projects.core.datasource) + + /** Common */ + implementation(projects.common.ui) + implementation(projects.common.routing) + + /** Tangem libraries */ + implementation(projects.libs.tangemSdkApi) + implementation(deps.tangem.card.core) + implementation(deps.tangem.card.android) { + exclude(module = "joda-time") + } + + /** AndroidX libraries */ + implementation(deps.androidx.core.ktx) + implementation(deps.lifecycle.runtime.ktx) + + /** Compose libraries */ + implementation(deps.compose.material) // to use buttons and text field in MultiWalletSeedPhraseImport.kt + implementation(deps.compose.material3) + implementation(deps.compose.animation) + implementation(deps.compose.foundation) + implementation(deps.compose.ui) + implementation(deps.compose.ui.tooling) + implementation(deps.compose.coil) + implementation(deps.lottie.compose) + implementation(deps.decompose.ext.compose) + implementation(deps.androidx.activity.compose) + implementation(deps.androidx.datastore) + + /** Other libraries */ + implementation(deps.kotlin.immutable.collections) + implementation(deps.kotlin.serialization) + implementation(deps.timber) + implementation(deps.firebase.crashlytics) + + /** DI */ + implementation(deps.hilt.android) + kapt(deps.hilt.kapt) +} \ No newline at end of file diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/DefaultNFTFeatureToggles.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/DefaultNFTFeatureToggles.kt new file mode 100644 index 0000000000..7697217e52 --- /dev/null +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/DefaultNFTFeatureToggles.kt @@ -0,0 +1,10 @@ +package com.tangem.features.nft + +import com.tangem.core.configtoggle.feature.FeatureTogglesManager + +internal class DefaultNFTFeatureToggles( + private val featureTogglesManager: FeatureTogglesManager, +) : NFTFeatureToggles { + override val isNFTEnabled: Boolean + get() = featureTogglesManager.isFeatureEnabled(name = "NFT_ENABLED") +} \ No newline at end of file diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/NFTFeatureModule.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/NFTFeatureModule.kt new file mode 100644 index 0000000000..b456b29b0b --- /dev/null +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/NFTFeatureModule.kt @@ -0,0 +1,19 @@ +package com.tangem.features.nft + +import com.tangem.core.configtoggle.feature.FeatureTogglesManager +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal object NFTFeatureModule { + + @Provides + @Singleton + fun provideFeatureToggles(featureTogglesManager: FeatureTogglesManager): NFTFeatureToggles { + return DefaultNFTFeatureToggles(featureTogglesManager) + } +} \ No newline at end of file From 6ad6215eb00c200d7aafaccf7b8e261a6616c9c7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 24 Feb 2025 09:31:32 +0200 Subject: [PATCH 19/54] Updated on 2026-08-14 --- .../auth/DefaultExpressAuthProvider.kt | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/network/auth/DefaultExpressAuthProvider.kt b/app/src/main/java/com/tangem/tap/network/auth/DefaultExpressAuthProvider.kt index 7331b9f95c..452b90127d 100644 --- a/app/src/main/java/com/tangem/tap/network/auth/DefaultExpressAuthProvider.kt +++ b/app/src/main/java/com/tangem/tap/network/auth/DefaultExpressAuthProvider.kt @@ -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" } } \ No newline at end of file From 6d56af68f5d08d08679ffa7cfba0f076224ed2a8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Sat, 22 Feb 2025 14:27:25 +0300 Subject: [PATCH 20/54] Updated on 2026-08-14 --- .../com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt index d0f4cc5985..abf3ce3f3c 100644 --- a/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt @@ -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)), ) } From 3d9e937ee90ac1a8a2a532185e677d1f88e76bf6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 17 Feb 2025 21:44:49 +0300 Subject: [PATCH 21/54] Updated on 2026-08-14 --- .../network/auth/DefaultVisaAuthProvider.kt | 19 --- .../tangem/tap/network/auth/di/AuthModule.kt | 13 -- .../api/common/visa/TangemVisaAuthProvider.kt | 6 - .../datasource/api/visa/TangemVisaApi.kt | 19 ++- .../datasource/api/visa/TangemVisaAuthApi.kt | 3 +- .../visa/models/response/VisaCustomerInfo.kt | 15 +++ .../models/response}/VisaTxHistoryResponse.kt | 2 +- .../data/visa/di/ImplementedVisaDataModule.kt | 25 ---- .../visa/DefaultVisaActivationRepository.kt | 6 + .../tangem/data/visa/DefaultVisaRepository.kt | 123 ++++++------------ .../data/visa/MockVisaActivationRepository.kt | 4 + ...isaRepository.kt => MockVisaRepository.kt} | 3 +- .../com/tangem/data/visa/config/VisaConfig.kt | 2 + .../tangem/data/visa/config/VisaLibLoader.kt | 32 +---- .../data/visa/di/ImplementedVisaRepository.kt | 6 - .../di/ImplementedVisaRepositoryModule.kt | 16 --- .../com/tangem/data/visa/di/VisaDataModule.kt | 27 ++-- .../tangem/data/visa/utils/CurrencyUtils.kt | 0 .../data/visa/utils/VisaApiRequestMaker.kt | 107 +++++++++++++++ .../tangem/data/visa/utils/VisaConstants.kt | 10 +- .../data/visa/utils/VisaCurrencyFactory.kt | 0 .../data/visa/utils/VisaTxDetailsFactory.kt | 2 +- .../visa/utils/VisaTxHistoryItemFactory.kt | 2 +- .../visa/utils/VisaTxHistoryPagingSource.kt | 6 +- .../domain/visa/SetVisaPinCodeUseCase.kt | 5 +- .../repository/VisaActivationRepository.kt | 2 + .../visa/DefaultVisaContractInfoProvider.kt | 48 ++++--- .../lib/visa/VisaContractInfoProvider.kt | 9 +- .../kotlin/com/tangem/lib/visa/api/VisaApi.kt | 18 --- .../com/tangem/lib/visa/api/VisaApiBuilder.kt | 72 ---------- 30 files changed, 258 insertions(+), 344 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/network/auth/DefaultVisaAuthProvider.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/common/visa/TangemVisaAuthProvider.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/visa/models/response/VisaCustomerInfo.kt rename {libs/visa/src/main/kotlin/com/tangem/lib/visa/model => core/datasource/src/main/java/com/tangem/datasource/api/visa/models/response}/VisaTxHistoryResponse.kt (98%) delete mode 100644 data/visa/src/debug/kotlin/com/tangem/data/visa/di/ImplementedVisaDataModule.kt rename data/visa/src/{debug => main}/kotlin/com/tangem/data/visa/DefaultVisaRepository.kt (65%) rename data/visa/src/main/kotlin/com/tangem/data/visa/{DummyVisaRepository.kt => MockVisaRepository.kt} (89%) rename data/visa/src/{debug => main}/kotlin/com/tangem/data/visa/config/VisaConfig.kt (92%) rename data/visa/src/{debug => main}/kotlin/com/tangem/data/visa/config/VisaLibLoader.kt (68%) delete mode 100644 data/visa/src/main/kotlin/com/tangem/data/visa/di/ImplementedVisaRepository.kt delete mode 100644 data/visa/src/main/kotlin/com/tangem/data/visa/di/ImplementedVisaRepositoryModule.kt rename data/visa/src/{debug => main}/kotlin/com/tangem/data/visa/utils/CurrencyUtils.kt (100%) create mode 100644 data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaApiRequestMaker.kt rename data/visa/src/{debug => main}/kotlin/com/tangem/data/visa/utils/VisaConstants.kt (86%) rename data/visa/src/{debug => main}/kotlin/com/tangem/data/visa/utils/VisaCurrencyFactory.kt (100%) rename data/visa/src/{debug => main}/kotlin/com/tangem/data/visa/utils/VisaTxDetailsFactory.kt (97%) rename data/visa/src/{debug => main}/kotlin/com/tangem/data/visa/utils/VisaTxHistoryItemFactory.kt (89%) rename data/visa/src/{debug => main}/kotlin/com/tangem/data/visa/utils/VisaTxHistoryPagingSource.kt (92%) delete mode 100644 libs/visa/src/main/kotlin/com/tangem/lib/visa/api/VisaApi.kt delete mode 100644 libs/visa/src/main/kotlin/com/tangem/lib/visa/api/VisaApiBuilder.kt diff --git a/app/src/main/java/com/tangem/tap/network/auth/DefaultVisaAuthProvider.kt b/app/src/main/java/com/tangem/tap/network/auth/DefaultVisaAuthProvider.kt deleted file mode 100644 index 0a793b0222..0000000000 --- a/app/src/main/java/com/tangem/tap/network/auth/DefaultVisaAuthProvider.kt +++ /dev/null @@ -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() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt b/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt index 829f08d9cc..c72a9c145c 100644 --- a/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt +++ b/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt @@ -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 } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/visa/TangemVisaAuthProvider.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/visa/TangemVisaAuthProvider.kt deleted file mode 100644 index 1f164d8411..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/visa/TangemVisaAuthProvider.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.tangem.datasource.api.common.visa - -interface TangemVisaAuthProvider { - - suspend fun getAuthHeader(cardId: String): String -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/visa/TangemVisaApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/visa/TangemVisaApi.kt index 802738fbd7..a0d08a74a1 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/visa/TangemVisaApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/visa/TangemVisaApi.kt @@ -5,9 +5,7 @@ import com.tangem.datasource.api.utils.ReadTimeout import com.tangem.datasource.api.visa.models.request.ActivationByCardWalletRequest import com.tangem.datasource.api.visa.models.request.ActivationByCustomerWalletRequest import com.tangem.datasource.api.visa.models.request.SetPinCodeRequest -import com.tangem.datasource.api.visa.models.response.CardActivationRemoteStateResponse -import com.tangem.datasource.api.visa.models.response.CardWalletDataToSignResponse -import com.tangem.datasource.api.visa.models.response.CustomerWalletDataToSignResponse +import com.tangem.datasource.api.visa.models.response.* import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.Header @@ -71,4 +69,19 @@ interface TangemVisaApi { @Header("Authorization") authHeader: String, @Body body: SetPinCodeRequest, ): ApiResponse + + @GET("customer/info") + suspend fun getCustomerInfo( + @Header("Authorization") authHeader: String, + @Query("card_id") cardId: String, + ): ApiResponse + + @GET("product_instance/transactions") + suspend fun getTxHistory( + @Header("Authorization") authHeader: String, + @Query("customer_id") customerId: String, + @Query("product_instance_id") productInstanceId: String, + @Query("limit") limit: Int, + @Query("offset") offset: Int, + ): ApiResponse } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/visa/TangemVisaAuthApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/visa/TangemVisaAuthApi.kt index 1e200c63bd..b2ed8d19be 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/visa/TangemVisaAuthApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/visa/TangemVisaAuthApi.kt @@ -1,5 +1,6 @@ package com.tangem.datasource.api.visa +import com.tangem.datasource.api.common.response.ApiResponse import com.tangem.datasource.api.visa.models.response.GenerateNonceResponse import com.tangem.datasource.api.visa.models.response.JWTResponse import retrofit2.http.Field @@ -27,5 +28,5 @@ interface TangemVisaAuthApi { ): JWTResponse @POST("auth/refresh_token") - suspend fun refreshAccessToken(@Field("refresh_token") refreshToken: String): JWTResponse + suspend fun refreshAccessToken(@Field("refresh_token") refreshToken: String): ApiResponse } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/visa/models/response/VisaCustomerInfo.kt b/core/datasource/src/main/java/com/tangem/datasource/api/visa/models/response/VisaCustomerInfo.kt new file mode 100644 index 0000000000..70d5f6ac94 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/visa/models/response/VisaCustomerInfo.kt @@ -0,0 +1,15 @@ +package com.tangem.datasource.api.visa.models.response + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class VisaCustomerInfo( + @Json(name = "payment_accounts") val paymentAccounts: List, +) { + data class PaymentAccount( + @Json(name = "id") val id: String, + @Json(name = "customer_wallet_address") val customerWalletAddress: String, + @Json(name = "payment_account_address") val paymentAccountAddress: String, + ) +} \ No newline at end of file diff --git a/libs/visa/src/main/kotlin/com/tangem/lib/visa/model/VisaTxHistoryResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/visa/models/response/VisaTxHistoryResponse.kt similarity index 98% rename from libs/visa/src/main/kotlin/com/tangem/lib/visa/model/VisaTxHistoryResponse.kt rename to core/datasource/src/main/java/com/tangem/datasource/api/visa/models/response/VisaTxHistoryResponse.kt index bf722ca7bf..7c4d7d0a22 100644 --- a/libs/visa/src/main/kotlin/com/tangem/lib/visa/model/VisaTxHistoryResponse.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/visa/models/response/VisaTxHistoryResponse.kt @@ -1,4 +1,4 @@ -package com.tangem.lib.visa.model +package com.tangem.datasource.api.visa.models.response import com.squareup.moshi.Json import com.squareup.moshi.JsonClass diff --git a/data/visa/src/debug/kotlin/com/tangem/data/visa/di/ImplementedVisaDataModule.kt b/data/visa/src/debug/kotlin/com/tangem/data/visa/di/ImplementedVisaDataModule.kt deleted file mode 100644 index efb081bdc6..0000000000 --- a/data/visa/src/debug/kotlin/com/tangem/data/visa/di/ImplementedVisaDataModule.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.tangem.data.visa.di - -import com.tangem.data.common.cache.CacheRegistry -import com.tangem.data.visa.DefaultVisaRepository -import com.tangem.data.visa.config.VisaLibLoader -import com.tangem.datasource.api.tangemTech.TangemTechApi -import com.tangem.datasource.local.userwallet.UserWalletsStore -import com.tangem.domain.visa.repository.VisaRepository -import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import dagger.Binds -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -internal interface ImplementedVisaDataModule { - - @Binds - @Singleton - @ImplementedVisaRepository - fun provideVisaRepository(impl: DefaultVisaRepository): VisaRepository -} \ No newline at end of file diff --git a/data/visa/src/main/kotlin/com/tangem/data/visa/DefaultVisaActivationRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/DefaultVisaActivationRepository.kt index 4bb73eee50..b4bb976ce9 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/visa/DefaultVisaActivationRepository.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/visa/DefaultVisaActivationRepository.kt @@ -1,5 +1,6 @@ package com.tangem.data.visa +import com.tangem.data.visa.config.VisaLibLoader import com.tangem.data.visa.converter.AccessCodeDataConverter import com.tangem.data.visa.converter.VisaActivationStatusConverter import com.tangem.datasource.api.common.response.ApiResponseError @@ -28,6 +29,7 @@ internal class DefaultVisaActivationRepository @AssistedInject constructor( private val visaAuthTokenStorage: VisaAuthTokenStorage, private val accessCodeDataConverter: AccessCodeDataConverter, private val visaAuthRepository: VisaAuthRepository, + private val visaLibLoader: VisaLibLoader, ) : VisaActivationRepository { override suspend fun getActivationRemoteState(): VisaActivationRemoteState = withContext(dispatcherProvider.io) { @@ -192,6 +194,10 @@ internal class DefaultVisaActivationRepository @AssistedInject constructor( } } + override suspend fun getPinCodeRsaEncryptionPublicKey(): String { + return visaLibLoader.getOrCreateConfig().rsaPublicKey + } + private suspend fun request(requestBlock: suspend () -> T): T { return runCatching { requestBlock() diff --git a/data/visa/src/debug/kotlin/com/tangem/data/visa/DefaultVisaRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/DefaultVisaRepository.kt similarity index 65% rename from data/visa/src/debug/kotlin/com/tangem/data/visa/DefaultVisaRepository.kt rename to data/visa/src/main/kotlin/com/tangem/data/visa/DefaultVisaRepository.kt index b7ce28f265..6a78abbf06 100644 --- a/data/visa/src/debug/kotlin/com/tangem/data/visa/DefaultVisaRepository.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/visa/DefaultVisaRepository.kt @@ -12,21 +12,18 @@ import com.tangem.common.extensions.toHexString import com.tangem.data.common.cache.CacheRegistry import com.tangem.data.visa.config.VisaLibLoader import com.tangem.data.visa.utils.* -import com.tangem.datasource.api.common.response.ApiResponseError import com.tangem.datasource.api.common.response.getOrThrow -import com.tangem.datasource.api.common.visa.TangemVisaAuthProvider import com.tangem.datasource.api.tangemTech.TangemTechApi +import com.tangem.datasource.api.visa.TangemVisaApi +import com.tangem.datasource.api.visa.models.response.VisaTxHistoryResponse import com.tangem.datasource.local.userwallet.UserWalletsStore import com.tangem.domain.common.util.cardTypesResolver -import com.tangem.domain.common.visa.VisaUtilities -import com.tangem.domain.visa.exception.RefreshTokenExpiredException -import com.tangem.domain.visa.model.* -import com.tangem.domain.visa.repository.VisaAuthRepository +import com.tangem.domain.visa.model.VisaCurrency +import com.tangem.domain.visa.model.VisaTxDetails +import com.tangem.domain.visa.model.VisaTxHistoryItem import com.tangem.domain.visa.repository.VisaRepository import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.lib.visa.api.VisaApi -import com.tangem.lib.visa.model.VisaTxHistoryResponse import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -35,8 +32,8 @@ import kotlinx.coroutines.withContext import java.math.BigDecimal import javax.inject.Inject import javax.inject.Singleton -import kotlin.jvm.Throws +@Suppress("LongParameterList") @Singleton internal class DefaultVisaRepository @Inject constructor( private val visaLibLoader: VisaLibLoader, @@ -44,8 +41,8 @@ internal class DefaultVisaRepository @Inject constructor( private val cacheRegistry: CacheRegistry, private val userWalletsStore: UserWalletsStore, private val dispatchers: CoroutineDispatcherProvider, - private val visaAuthProvider: TangemVisaAuthProvider, - private val visaAuthRepository: VisaAuthRepository, + private val visaApiRequestMaker: VisaApiRequestMaker, + private val visaApi: TangemVisaApi, ) : VisaRepository { private val currencyFactory by lazy(mode = LazyThreadSafetyMode.NONE) { @@ -65,27 +62,32 @@ internal class DefaultVisaRepository @Inject constructor( override suspend fun getVisaCurrency(userWalletId: UserWalletId, isRefresh: Boolean): VisaCurrency { val address = makeAddress(userWalletId) - fetchVisaCurrencyIfExpired(address, isRefresh) + fetchVisaCurrencyIfExpired(userWalletId, address, isRefresh) return requireNotNull(fetchedCurrencies.value[address]) { "Unable to find VISA currency for $address" } } - private suspend fun fetchVisaCurrencyIfExpired(address: String, isRefresh: Boolean) { + private suspend fun fetchVisaCurrencyIfExpired(userWalletId: UserWalletId, address: String, isRefresh: Boolean) { cacheRegistry.invokeOnExpire( key = getVisaCurrencyKey(address), skipCache = isRefresh, - block = { fetchVisaCurrency(address) }, + block = { fetchVisaCurrency(userWalletId, address) }, ) } - private suspend fun fetchVisaCurrency(address: String) { + private suspend fun fetchVisaCurrency(userWalletId: UserWalletId, address: String) { val contractInfoProvider = visaLibLoader.getOrCreateProvider() parZip( dispatchers.io, - { contractInfoProvider.getContractInfo(address) }, + { + contractInfoProvider.getContractInfo( + walletAddress = address, + paymentAccountAddress = getPaymentAccountAddress(userWalletId), + ) + }, { getFiatRate() }, { contractInfo, fiatRate -> fetchedCurrencies.update { value -> @@ -104,7 +106,7 @@ internal class DefaultVisaRepository @Inject constructor( ): Flow> { val userWallet = findVisaUserWallet(userWalletId) val cardPubKey = getCardPubKey(userWallet) - val api = visaLibLoader.getOrCreateApi() + val pager = Pager( config = PagingConfig( pageSize = pageSize, @@ -121,7 +123,7 @@ internal class DefaultVisaRepository @Inject constructor( cacheRegistry = cacheRegistry, fetchedItems = fetchedHistoryItems, dispatchers = dispatchers, - requestTxHistory = { offset, pageSize -> getTxHistory(api, userWalletId, offset, pageSize) }, + requestTxHistory = { offset, pageSize -> getTxHistory(userWalletId, offset, pageSize) }, ) }, ) @@ -145,22 +147,31 @@ internal class DefaultVisaRepository @Inject constructor( } } - private suspend fun getTxHistory( - api: VisaApi, - userWalletId: UserWalletId, - offset: Int, - pageSize: Int, - ): VisaTxHistoryResponse = withContext(dispatchers.io) { + private suspend fun getPaymentAccountAddress(userWalletId: UserWalletId): String? = runCatching { val userWallet = findVisaUserWallet(userWalletId) - val cardPubKey = getCardPubKey(userWallet) - request(userWalletId = userWalletId) { - api.getTxHistory( - authorizationHeader = visaAuthProvider.getAuthHeader(userWallet.cardId), - cardPublicKey = cardPubKey, + val customerInfo = visaApiRequestMaker.request(userWalletId) { authHeader, _ -> + visaApi.getCustomerInfo( + authHeader = authHeader, + cardId = userWallet.scanResponse.card.cardId, + ) + } + + // TODO select correct account when multiple accounts are available (will be implemented when backend is ready) + customerInfo.paymentAccounts.firstOrNull()?.paymentAccountAddress + }.getOrNull() + + private suspend fun getTxHistory(userWalletId: UserWalletId, offset: Int, pageSize: Int): VisaTxHistoryResponse { + return visaApiRequestMaker.request( + userWalletId = userWalletId, + ) { authHeader, accessCodeData -> + visaApi.getTxHistory( + authHeader = authHeader, + customerId = accessCodeData.customerId, + productInstanceId = accessCodeData.productInstanceId, limit = pageSize, offset = offset, - ).getOrThrow() + ) } } @@ -217,56 +228,4 @@ internal class DefaultVisaRepository @Inject constructor( private fun getVisaCurrencyKey(address: String): String { return "visa_currency_$address" } - - private suspend fun request( - userWalletId: UserWalletId, - requestBlock: suspend () -> T, - ): T { - return runCatching { - requestBlock() - }.getOrElse { responseError -> - if (responseError !is ApiResponseError.HttpException || - responseError.code != ApiResponseError.HttpException.Code.UNAUTHORIZED - ) { - throw responseError - } - - val authTokens = getAuthTokens(userWalletId) - val newTokens = runCatching { - visaAuthRepository.refreshAccessTokens(authTokens.refreshToken) - }.getOrElse { - if (it is ApiResponseError.HttpException && - it.code == ApiResponseError.HttpException.Code.UNAUTHORIZED - ) { - userWalletsStore.update(userWalletId) { userWallet -> - userWallet.copy( - scanResponse = userWallet.scanResponse.copy( - visaCardActivationStatus = VisaCardActivationStatus.RefreshTokenExpired - ) - ) - } - } - throw RefreshTokenExpiredException() - } - - userWalletsStore.update(userWalletId) { userWallet -> - userWallet.copy( - scanResponse = userWallet.scanResponse.copy( - visaCardActivationStatus = VisaCardActivationStatus.Activated( - visaAuthTokens = newTokens - ) - ) - ) - } - - requestBlock() - } - } - - @Throws - private suspend fun getAuthTokens(userWalletId: UserWalletId): VisaAuthTokens { - val userWallet = findVisaUserWallet(userWalletId) - val status = userWallet.scanResponse.visaCardActivationStatus ?: error("Visa card activation status not found") - return (status as? VisaCardActivationStatus.Activated)?.visaAuthTokens ?: error("Visa card is not activated") - } } \ No newline at end of file diff --git a/data/visa/src/main/kotlin/com/tangem/data/visa/MockVisaActivationRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/MockVisaActivationRepository.kt index 8ebb4ae1b4..ed49e8187b 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/visa/MockVisaActivationRepository.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/visa/MockVisaActivationRepository.kt @@ -45,6 +45,10 @@ class MockVisaActivationRepository @AssistedInject constructor( override suspend fun sendPinCode(pinCode: VisaEncryptedPinCode) {} + override suspend fun getPinCodeRsaEncryptionPublicKey(): String { + return CryptoUtils.generateRandomBytes(length = 32).toHexString() + } + @AssistedFactory interface Factory : VisaActivationRepository.Factory { override fun create(cardId: VisaCardId): MockVisaActivationRepository diff --git a/data/visa/src/main/kotlin/com/tangem/data/visa/DummyVisaRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/MockVisaRepository.kt similarity index 89% rename from data/visa/src/main/kotlin/com/tangem/data/visa/DummyVisaRepository.kt rename to data/visa/src/main/kotlin/com/tangem/data/visa/MockVisaRepository.kt index e965d71e93..87402d0554 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/visa/DummyVisaRepository.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/visa/MockVisaRepository.kt @@ -7,8 +7,9 @@ import com.tangem.domain.visa.model.VisaTxHistoryItem import com.tangem.domain.visa.repository.VisaRepository import com.tangem.domain.wallets.models.UserWalletId import kotlinx.coroutines.flow.Flow +import javax.inject.Inject -internal class DummyVisaRepository : VisaRepository { +internal class MockVisaRepository @Inject constructor() : VisaRepository { override suspend fun getVisaCurrency(userWalletId: UserWalletId, isRefresh: Boolean): VisaCurrency { TODO("Not implemented for this build type") diff --git a/data/visa/src/debug/kotlin/com/tangem/data/visa/config/VisaConfig.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/config/VisaConfig.kt similarity index 92% rename from data/visa/src/debug/kotlin/com/tangem/data/visa/config/VisaConfig.kt rename to data/visa/src/main/kotlin/com/tangem/data/visa/config/VisaConfig.kt index 187f4ca9e6..2dd3b5566c 100644 --- a/data/visa/src/debug/kotlin/com/tangem/data/visa/config/VisaConfig.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/visa/config/VisaConfig.kt @@ -11,6 +11,8 @@ internal data class VisaConfig( val mainnet: Addresses, @Json(name = "txHistoryAPIAdditionalHeaders") val header: Header, + @Json(name = "rsaPublicKey") + val rsaPublicKey: String, ) { @JsonClass(generateAdapter = true) diff --git a/data/visa/src/debug/kotlin/com/tangem/data/visa/config/VisaLibLoader.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/config/VisaLibLoader.kt similarity index 68% rename from data/visa/src/debug/kotlin/com/tangem/data/visa/config/VisaLibLoader.kt rename to data/visa/src/main/kotlin/com/tangem/data/visa/config/VisaLibLoader.kt index e5062cf662..471f56ea4e 100644 --- a/data/visa/src/debug/kotlin/com/tangem/data/visa/config/VisaLibLoader.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/visa/config/VisaLibLoader.kt @@ -1,13 +1,9 @@ package com.tangem.data.visa.config -import com.squareup.moshi.Moshi import com.tangem.data.visa.BuildConfig import com.tangem.data.visa.utils.VisaConstants import com.tangem.datasource.asset.loader.AssetLoader -import com.tangem.datasource.di.NetworkMoshi import com.tangem.lib.visa.VisaContractInfoProvider -import com.tangem.lib.visa.api.VisaApi -import com.tangem.lib.visa.api.VisaApiBuilder import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock @@ -15,21 +11,19 @@ import javax.inject.Inject internal class VisaLibLoader @Inject constructor( private val assetLoader: AssetLoader, - @NetworkMoshi private val moshi: Moshi, private val dispatchers: CoroutineDispatcherProvider, ) { - private val createMutex = Mutex() + private val createMutex2 = Mutex() private var config: VisaConfig? = null private var provider: VisaContractInfoProvider? = null - private var api: VisaApi? = null + + suspend fun getOrCreateConfig(): VisaConfig = config ?: getOrLoadConfig() suspend fun getOrCreateProvider(): VisaContractInfoProvider = provider ?: createProvider() - suspend fun getOrCreateApi(): VisaApi = api ?: createApi() - private suspend fun createProvider(): VisaContractInfoProvider = createMutex.withLock { val config = getOrLoadConfig() @@ -54,24 +48,7 @@ internal class VisaLibLoader @Inject constructor( } } - private suspend fun createApi(): VisaApi = createMutex.withLock { - val config = getOrLoadConfig() - - api = VisaApiBuilder( - useDevApi = VisaConstants.USE_TEST_ENV, - isNetworkLoggingEnabled = BuildConfig.LOG_ENABLED, - moshi = moshi, - headers = mapOf( - X_ASN_HEADER_NAME to config.header.xAsn, - ), - ).build() - - return requireNotNull(api) { - "Visa API is not created" - } - } - - private suspend fun getOrLoadConfig(): VisaConfig { + private suspend fun getOrLoadConfig(): VisaConfig = createMutex2.withLock { config = assetLoader.load(VISA_CONFIG_FILE_NAME) return requireNotNull(config) { @@ -81,6 +58,5 @@ internal class VisaLibLoader @Inject constructor( companion object { private const val VISA_CONFIG_FILE_NAME = "tangem-app-config/visa_config" - private const val X_ASN_HEADER_NAME = "x-asn" } } \ No newline at end of file diff --git a/data/visa/src/main/kotlin/com/tangem/data/visa/di/ImplementedVisaRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/di/ImplementedVisaRepository.kt deleted file mode 100644 index 074af6e72d..0000000000 --- a/data/visa/src/main/kotlin/com/tangem/data/visa/di/ImplementedVisaRepository.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.tangem.data.visa.di - -import javax.inject.Qualifier - -@Qualifier -internal annotation class ImplementedVisaRepository \ No newline at end of file diff --git a/data/visa/src/main/kotlin/com/tangem/data/visa/di/ImplementedVisaRepositoryModule.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/di/ImplementedVisaRepositoryModule.kt deleted file mode 100644 index 96de38914e..0000000000 --- a/data/visa/src/main/kotlin/com/tangem/data/visa/di/ImplementedVisaRepositoryModule.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.tangem.data.visa.di - -import com.tangem.domain.visa.repository.VisaRepository -import dagger.BindsOptionalOf -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent - -@Module -@InstallIn(SingletonComponent::class) -internal interface ImplementedVisaRepositoryModule { - - @BindsOptionalOf - @ImplementedVisaRepository - fun bindImplementedVisaRepository(): VisaRepository -} \ No newline at end of file diff --git a/data/visa/src/main/kotlin/com/tangem/data/visa/di/VisaDataModule.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/di/VisaDataModule.kt index 5cfa0296bb..e1cc459371 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/visa/di/VisaDataModule.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/visa/di/VisaDataModule.kt @@ -1,36 +1,20 @@ package com.tangem.data.visa.di import com.tangem.data.visa.DefaultVisaAuthRepository -import com.tangem.data.visa.DummyVisaRepository +import com.tangem.data.visa.MockVisaRepository import com.tangem.data.visa.MockVisaActivationRepository import com.tangem.domain.visa.repository.VisaActivationRepository import com.tangem.domain.visa.repository.VisaAuthRepository import com.tangem.domain.visa.repository.VisaRepository import dagger.Binds import dagger.Module -import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import java.util.Optional import javax.inject.Singleton -import kotlin.jvm.optionals.getOrNull @Module @InstallIn(SingletonComponent::class) -internal object VisaDataModule { - - @Provides - @Singleton - fun provideVisaRepository( - @ImplementedVisaRepository implementedVisaRepository: Optional, - ): VisaRepository { - return implementedVisaRepository.getOrNull() ?: DummyVisaRepository() - } -} - -@Module -@InstallIn(SingletonComponent::class) -internal interface VisaDataBindsModule { +internal interface VisaDataModule { @Binds @Singleton @@ -48,4 +32,11 @@ internal interface VisaDataBindsModule { fun bindVisaActivationRepositoryFactory( repository: MockVisaActivationRepository.Factory, ): VisaActivationRepository.Factory + + // @Binds + // fun bindVisaRepository(repository: DefaultVisaRepository): VisaRepository + + // Mocked + @Binds + fun bindVisaRepository(repository: MockVisaRepository): VisaRepository } \ No newline at end of file diff --git a/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/CurrencyUtils.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/utils/CurrencyUtils.kt similarity index 100% rename from data/visa/src/debug/kotlin/com/tangem/data/visa/utils/CurrencyUtils.kt rename to data/visa/src/main/kotlin/com/tangem/data/visa/utils/CurrencyUtils.kt diff --git a/data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaApiRequestMaker.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaApiRequestMaker.kt new file mode 100644 index 0000000000..d06d1fb0de --- /dev/null +++ b/data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaApiRequestMaker.kt @@ -0,0 +1,107 @@ +package com.tangem.data.visa.utils + +import com.tangem.data.visa.converter.AccessCodeDataConverter +import com.tangem.data.visa.model.AccessCodeData +import com.tangem.datasource.api.common.response.ApiResponse +import com.tangem.datasource.api.common.response.ApiResponseError +import com.tangem.datasource.api.common.response.getOrThrow +import com.tangem.datasource.api.visa.TangemVisaAuthApi +import com.tangem.datasource.local.userwallet.UserWalletsStore +import com.tangem.domain.common.util.cardTypesResolver +import com.tangem.domain.visa.exception.RefreshTokenExpiredException +import com.tangem.domain.visa.model.VisaAuthTokens +import com.tangem.domain.visa.model.VisaCardActivationStatus +import com.tangem.domain.visa.model.getAuthHeader +import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.withContext +import javax.inject.Inject +import kotlin.jvm.Throws + +typealias VisaAuthorizationHeader = String + +internal class VisaApiRequestMaker @Inject constructor( + private val userWalletsStore: UserWalletsStore, + private val visaAuthApi: TangemVisaAuthApi, + private val accessCodeDataConverter: AccessCodeDataConverter, + private val dispatcherProvider: CoroutineDispatcherProvider, +) { + suspend fun request( + userWalletId: UserWalletId, + requestBlock: suspend (header: VisaAuthorizationHeader, accessCodeData: AccessCodeData) -> ApiResponse, + ): T = withContext(dispatcherProvider.io) { + val authTokens = getAuthTokens(userWalletId) + val authHeader = authTokens.getAuthHeader() + val accessCodeData = accessCodeDataConverter.convert(authTokens) + + runCatching { + requestBlock(authHeader, accessCodeData).getOrThrow() + }.getOrElse { responseError -> + if (responseError !is ApiResponseError.HttpException || + responseError.code != ApiResponseError.HttpException.Code.UNAUTHORIZED + ) { + throw responseError + } + + val newTokens = runCatching { + refreshAccessTokens(authTokens.refreshToken) + }.getOrElse { + if (it is ApiResponseError.HttpException && + it.code == ApiResponseError.HttpException.Code.UNAUTHORIZED + ) { + userWalletsStore.update(userWalletId) { userWallet -> + userWallet.copy( + scanResponse = userWallet.scanResponse.copy( + visaCardActivationStatus = VisaCardActivationStatus.RefreshTokenExpired, + ), + ) + } + } + throw RefreshTokenExpiredException() + } + + userWalletsStore.update(userWalletId) { userWallet -> + userWallet.copy( + scanResponse = userWallet.scanResponse.copy( + visaCardActivationStatus = VisaCardActivationStatus.Activated( + visaAuthTokens = newTokens, + ), + ), + ) + } + + val newAuthHeader = newTokens.getAuthHeader() + val newAccessCodeData = accessCodeDataConverter.convert(newTokens) + + requestBlock(newAuthHeader, newAccessCodeData).getOrThrow() + } + } + + private suspend fun refreshAccessTokens(refreshToken: VisaAuthTokens.RefreshToken): VisaAuthTokens { + val result = visaAuthApi.refreshAccessToken(refreshToken.value).getOrThrow() + + return VisaAuthTokens( + accessToken = result.accessToken, + refreshToken = VisaAuthTokens.RefreshToken(result.refreshToken), + ) + } + + @Throws + private suspend fun getAuthTokens(userWalletId: UserWalletId): VisaAuthTokens { + val userWallet = findVisaUserWallet(userWalletId) + val status = userWallet.scanResponse.visaCardActivationStatus ?: error("Visa card activation status not found") + return (status as? VisaCardActivationStatus.Activated)?.visaAuthTokens ?: error("Visa card is not activated") + } + + private suspend fun findVisaUserWallet(userWalletId: UserWalletId): UserWallet { + val userWallet = requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) { + "No user wallet found: $userWalletId" + } + if (!userWallet.scanResponse.cardTypesResolver.isVisaWallet()) { + error("VISA wallet required: $userWalletId") + } + + return userWallet + } +} \ No newline at end of file diff --git a/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaConstants.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaConstants.kt similarity index 86% rename from data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaConstants.kt rename to data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaConstants.kt index 27cd336588..1a6f0a142a 100644 --- a/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaConstants.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaConstants.kt @@ -15,9 +15,9 @@ internal object VisaConstants { ) /* - * Must be `false` in production - * Don't forget to change CardTypesResolver.isVisaWallet - * */ + * Must be `false` in production + * Don't forget to change CardTypesResolver.isVisaWallet + * */ const val IS_DEMO_MODE_ENABLED = false const val USE_TEST_ENV = true @@ -40,5 +40,7 @@ internal fun getDemoAddress(): String { internal fun getDemoPublicKey(): String { return if (VisaConstants.USE_TEST_ENV) { VisaConstants.DEMO_TESTNET_PUBLIC_KEY - } else VisaConstants.DEMO_MAINNET_PUBLIC_KEY + } else { + VisaConstants.DEMO_MAINNET_PUBLIC_KEY + } } \ No newline at end of file diff --git a/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaCurrencyFactory.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaCurrencyFactory.kt similarity index 100% rename from data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaCurrencyFactory.kt rename to data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaCurrencyFactory.kt diff --git a/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaTxDetailsFactory.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaTxDetailsFactory.kt similarity index 97% rename from data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaTxDetailsFactory.kt rename to data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaTxDetailsFactory.kt index 5108e0387e..c69adf5664 100644 --- a/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaTxDetailsFactory.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaTxDetailsFactory.kt @@ -2,8 +2,8 @@ package com.tangem.data.visa.utils import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.externallinkprovider.TxExploreState +import com.tangem.datasource.api.visa.models.response.VisaTxHistoryResponse import com.tangem.domain.visa.model.VisaTxDetails -import com.tangem.lib.visa.model.VisaTxHistoryResponse internal class VisaTxDetailsFactory { diff --git a/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaTxHistoryItemFactory.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaTxHistoryItemFactory.kt similarity index 89% rename from data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaTxHistoryItemFactory.kt rename to data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaTxHistoryItemFactory.kt index 86d1439068..75a8c4eefe 100644 --- a/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaTxHistoryItemFactory.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaTxHistoryItemFactory.kt @@ -1,7 +1,7 @@ package com.tangem.data.visa.utils +import com.tangem.datasource.api.visa.models.response.VisaTxHistoryResponse import com.tangem.domain.visa.model.VisaTxHistoryItem -import com.tangem.lib.visa.model.VisaTxHistoryResponse internal class VisaTxHistoryItemFactory { diff --git a/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaTxHistoryPagingSource.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaTxHistoryPagingSource.kt similarity index 92% rename from data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaTxHistoryPagingSource.kt rename to data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaTxHistoryPagingSource.kt index e233435e55..4393d4f372 100644 --- a/data/visa/src/debug/kotlin/com/tangem/data/visa/utils/VisaTxHistoryPagingSource.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaTxHistoryPagingSource.kt @@ -3,13 +3,9 @@ package com.tangem.data.visa.utils import androidx.paging.PagingSource import androidx.paging.PagingState import com.tangem.data.common.cache.CacheRegistry -import com.tangem.datasource.api.common.response.ApiResponseError -import com.tangem.datasource.api.common.response.getOrThrow -import com.tangem.datasource.api.common.visa.TangemVisaAuthProvider +import com.tangem.datasource.api.visa.models.response.VisaTxHistoryResponse import com.tangem.domain.visa.model.VisaTxHistoryItem import com.tangem.domain.wallets.models.UserWallet -import com.tangem.lib.visa.api.VisaApi -import com.tangem.lib.visa.model.VisaTxHistoryResponse import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/visa/SetVisaPinCodeUseCase.kt b/domain/visa/src/main/kotlin/com/tangem/domain/visa/SetVisaPinCodeUseCase.kt index 7b05cf26b8..6fda7af7df 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/visa/SetVisaPinCodeUseCase.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/visa/SetVisaPinCodeUseCase.kt @@ -18,8 +18,6 @@ import javax.crypto.spec.SecretKeySpec private const val KEY_SIZE = 256 -private const val RSA_PUB_KEY = "TODO" // TODO add RSA public key [REDACTED_TASK_KEY] - class SetVisaPinCodeUseCase( private val visaActivationRepositoryFactory: VisaActivationRepository.Factory, ) { @@ -30,9 +28,10 @@ class SetVisaPinCodeUseCase( pinCode: String, ): Either = Either.catch { val visaActivationRepository = visaActivationRepositoryFactory.create(visaCardId) + val rsaPublicKey = visaActivationRepository.getPinCodeRsaEncryptionPublicKey() val sessionKey = generateSessionKey() - val sessionId = getSessionId(RSA_PUB_KEY, sessionKey) + val sessionId = getSessionId(rsaPublicKey, sessionKey) val secureRandom = SecureRandom() val iv = ByteArray(size = 16) diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/visa/repository/VisaActivationRepository.kt b/domain/visa/src/main/kotlin/com/tangem/domain/visa/repository/VisaActivationRepository.kt index 5f7959f423..f6d451fb7b 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/visa/repository/VisaActivationRepository.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/visa/repository/VisaActivationRepository.kt @@ -20,6 +20,8 @@ interface VisaActivationRepository { suspend fun sendPinCode(pinCode: VisaEncryptedPinCode) + suspend fun getPinCodeRsaEncryptionPublicKey(): String + interface Factory { fun create(cardId: VisaCardId): VisaActivationRepository } diff --git a/libs/visa/src/main/kotlin/com/tangem/lib/visa/DefaultVisaContractInfoProvider.kt b/libs/visa/src/main/kotlin/com/tangem/lib/visa/DefaultVisaContractInfoProvider.kt index 2265f6258f..395904554e 100644 --- a/libs/visa/src/main/kotlin/com/tangem/lib/visa/DefaultVisaContractInfoProvider.kt +++ b/libs/visa/src/main/kotlin/com/tangem/lib/visa/DefaultVisaContractInfoProvider.kt @@ -20,27 +20,38 @@ internal class DefaultVisaContractInfoProvider( private val dispatchers: CoroutineDispatcherProvider, ) : VisaContractInfoProvider { - override suspend fun getContractInfo(walletAddress: String): VisaContractInfo { + override suspend fun getContractInfo(walletAddress: String, paymentAccountAddress: String?): VisaContractInfo { return parZip( dispatchers.io, - { loadPaymentAccount(walletAddress) }, + { loadPaymentAccount(walletAddress = walletAddress, paymentAccountAddress = paymentAccountAddress) }, { loadPaymentTokenInfo() }, { paymentAccount, paymentToken -> - fetchBalancesAndLimits(paymentAccount, paymentToken) + fetchBalancesAndLimits( + paymentAccount = paymentAccount, + paymentToken = paymentToken, + walletAddress = walletAddress, + ) }, ) } - private fun loadPaymentAccount(walletAddress: String): TangemPaymentAccount { + private fun loadPaymentAccount(walletAddress: String, paymentAccountAddress: String?): TangemPaymentAccount { + return TangemPaymentAccount.load( + /* contractAddress = */ paymentAccountAddress ?: getPaymentAccountAddressFromRegistry(walletAddress), + /* web3j = */ web3j, + /* transactionManager = */ transactionManager, + /* contractGasProvider = */ gasProvider, + ) + } + + private fun getPaymentAccountAddressFromRegistry(walletAddress: String): String { val paymentAccountRegistry = TangemPaymentAccountRegistry.load( /* contractAddress = */ paymentAccountRegistryAddress, /* web3j = */ web3j, /* transactionManager = */ transactionManager, /* contractGasProvider = */ gasProvider, ) - val paymentAccountAddress = paymentAccountRegistry.paymentAccountByCard(walletAddress).send() - - return TangemPaymentAccount.load(paymentAccountAddress, web3j, transactionManager, gasProvider) + return paymentAccountRegistry.paymentAccountByCard(walletAddress).send() } private fun loadPaymentTokenInfo(): PaymentTokenInfo { @@ -63,11 +74,12 @@ internal class DefaultVisaContractInfoProvider( private suspend fun fetchBalancesAndLimits( paymentAccount: TangemPaymentAccount, paymentToken: PaymentTokenInfo, + walletAddress: String, ): VisaContractInfo = parZip( dispatchers.io, { fetchToken(paymentAccount) }, { fetchBalances(paymentAccount, paymentToken) }, - { fetchLimits(paymentAccount, paymentToken) }, + { fetchLimits(paymentAccount, paymentToken, walletAddress) }, { token, balances, (oldLimit, newLimit, changeDate) -> VisaContractInfo(token, balances, oldLimit, newLimit, changeDate) }, @@ -123,19 +135,15 @@ internal class DefaultVisaContractInfoProvider( private fun fetchLimits( paymentAccount: TangemPaymentAccount, paymentToken: PaymentTokenInfo, + walletAddress: String, ): Triple { - TODO() // TODO: [REDACTED_TASK_KEY] - // val ( - // oldLimit, - // newLimit, - // changeDateSeconds, - // ) = paymentAccount.cards("").send().component5() - // - // return Triple( - // first = getLimits(oldLimit, paymentToken), - // second = getLimits(newLimit, paymentToken), - // third = changeDateSeconds.toInstant(), - // ) + val limits = paymentAccount.cards(walletAddress).send().component5() + + return Triple( + first = getLimits(limits.oldValue, paymentToken), + second = getLimits(limits.newValue, paymentToken), + third = limits.changeTimestamp.toInstant(), + ) } @Suppress("UnusedPrivateMember") diff --git a/libs/visa/src/main/kotlin/com/tangem/lib/visa/VisaContractInfoProvider.kt b/libs/visa/src/main/kotlin/com/tangem/lib/visa/VisaContractInfoProvider.kt index 4696b698fb..4587bfabf1 100644 --- a/libs/visa/src/main/kotlin/com/tangem/lib/visa/VisaContractInfoProvider.kt +++ b/libs/visa/src/main/kotlin/com/tangem/lib/visa/VisaContractInfoProvider.kt @@ -21,7 +21,14 @@ import java.util.concurrent.TimeUnit interface VisaContractInfoProvider { - suspend fun getContractInfo(walletAddress: String): VisaContractInfo + /** + * Fetches Visa contract info for the given wallet address. + * + * @param walletAddress Wallet address to fetch contract info for. + * @param paymentAccountAddress Payment account address to fetch data from. If null, + * it will be fetched from the registry. + */ + suspend fun getContractInfo(walletAddress: String, paymentAccountAddress: String?): VisaContractInfo class Builder( private val useTestnetRpc: Boolean, diff --git a/libs/visa/src/main/kotlin/com/tangem/lib/visa/api/VisaApi.kt b/libs/visa/src/main/kotlin/com/tangem/lib/visa/api/VisaApi.kt deleted file mode 100644 index 106ced7a60..0000000000 --- a/libs/visa/src/main/kotlin/com/tangem/lib/visa/api/VisaApi.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.tangem.lib.visa.api - -import com.tangem.datasource.api.common.response.ApiResponse -import com.tangem.lib.visa.model.VisaTxHistoryResponse -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.Query - -interface VisaApi { - - @GET("transaction") - suspend fun getTxHistory( - @Header("Authorization") authorizationHeader: String, - @Query("card_public_key") cardPublicKey: String, - @Query("limit") limit: Int, - @Query("offset") offset: Int, - ): ApiResponse -} \ No newline at end of file diff --git a/libs/visa/src/main/kotlin/com/tangem/lib/visa/api/VisaApiBuilder.kt b/libs/visa/src/main/kotlin/com/tangem/lib/visa/api/VisaApiBuilder.kt deleted file mode 100644 index ef1a99dd5f..0000000000 --- a/libs/visa/src/main/kotlin/com/tangem/lib/visa/api/VisaApiBuilder.kt +++ /dev/null @@ -1,72 +0,0 @@ -package com.tangem.lib.visa.api - -import android.util.Log -import com.ihsanbal.logging.Level -import com.ihsanbal.logging.LoggingInterceptor -import com.squareup.moshi.Moshi -import com.tangem.datasource.api.common.response.ApiResponseCallAdapterFactory -import com.tangem.lib.visa.utils.Constants -import com.tangem.lib.visa.utils.Constants.NETWORK_LOGS_TAG -import okhttp3.Interceptor -import okhttp3.OkHttpClient -import retrofit2.Retrofit -import retrofit2.converter.moshi.MoshiConverterFactory -import java.util.concurrent.TimeUnit - -class VisaApiBuilder( - private val useDevApi: Boolean, - private val isNetworkLoggingEnabled: Boolean, - private val moshi: Moshi, - private val headers: Map, - private val networkTimeoutSeconds: Long = Constants.NETWORK_TIMEOUT_SECONDS, -) { - - fun build(): VisaApi { - val okHttpClient = createOkHttpClient() - val retrofit = createRetrofit(okHttpClient) - return retrofit.create(VisaApi::class.java) - } - - private fun createOkHttpClient(): OkHttpClient { - val builder = OkHttpClient.Builder().apply { - connectTimeout(networkTimeoutSeconds, TimeUnit.SECONDS) - readTimeout(networkTimeoutSeconds, TimeUnit.SECONDS) - writeTimeout(networkTimeoutSeconds, TimeUnit.SECONDS) - - if (isNetworkLoggingEnabled) { - addInterceptor(createNetworkLoggingInterceptor()) - } - - if (headers.isNotEmpty()) { - addInterceptor { chain -> - val request = chain.request().newBuilder().apply { - headers.forEach { (key, value) -> addHeader(key, value) } - }.build() - - chain.proceed(request) - } - } - } - - return builder.build() - } - - private fun createRetrofit(okHttpClient: OkHttpClient): Retrofit { - val baseUrl = if (useDevApi) Constants.VISA_API_DEV_URL else Constants.VISA_API_PROD_URL - - return Retrofit.Builder() - .addConverterFactory(MoshiConverterFactory.create(moshi)) - .addCallAdapterFactory(ApiResponseCallAdapterFactory.create()) - .baseUrl(baseUrl) - .client(okHttpClient) - .build() - } -} - -private fun createNetworkLoggingInterceptor(): Interceptor { - return LoggingInterceptor.Builder() - .setLevel(Level.BODY) - .log(Log.VERBOSE) - .tag(NETWORK_LOGS_TAG) - .build() -} \ No newline at end of file From b2d47a56a2e65c9be90f54bc7d7c4f90f214bd1f Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 21 Feb 2025 15:45:53 +0300 Subject: [PATCH 22/54] Updated on 2026-08-14 --- .../com/tangem/data/visa/config/VisaLibLoader.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/data/visa/src/main/kotlin/com/tangem/data/visa/config/VisaLibLoader.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/config/VisaLibLoader.kt index 471f56ea4e..f8935ef774 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/visa/config/VisaLibLoader.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/visa/config/VisaLibLoader.kt @@ -16,8 +16,10 @@ internal class VisaLibLoader @Inject constructor( private val createMutex = Mutex() private val createMutex2 = Mutex() + @Volatile private var config: VisaConfig? = null + @Volatile private var provider: VisaContractInfoProvider? = null suspend fun getOrCreateConfig(): VisaConfig = config ?: getOrLoadConfig() @@ -25,6 +27,8 @@ internal class VisaLibLoader @Inject constructor( suspend fun getOrCreateProvider(): VisaContractInfoProvider = provider ?: createProvider() private suspend fun createProvider(): VisaContractInfoProvider = createMutex.withLock { + if (provider != null) return@withLock requireNotNull(provider) + val config = getOrLoadConfig() provider = VisaContractInfoProvider.Builder( @@ -49,10 +53,12 @@ internal class VisaLibLoader @Inject constructor( } private suspend fun getOrLoadConfig(): VisaConfig = createMutex2.withLock { + if (config != null) return@withLock requireNotNull(config) + config = assetLoader.load(VISA_CONFIG_FILE_NAME) - return requireNotNull(config) { - "Visa config is not found" + return@withLock requireNotNull(config) { + "Visa config is not loaded" } } From dd60ff7542c3ee3c222375561c7e64fb1ee6046e Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 24 Feb 2025 14:50:44 +0300 Subject: [PATCH 23/54] Updated on 2026-08-14 --- .../features/details/redux/DetailsAction.kt | 4 +- .../details/redux/DetailsMiddleware.kt | 8 +-- .../AppCurrencySelectorFragment.kt | 31 ------------ .../DefaultAppCurrencySelectorComponent.kt | 38 ++++++++++++++ .../api/AppCurrencySelectorComponent.kt | 9 ++++ .../di/AppCurrencySelectorFeatureModule.kt | 25 ++++++++++ .../AppCurrencySelectorModel.kt} | 27 +++++----- .../ui/appsettings/AppSettingsFragment.kt | 42 ---------------- .../DefaultAppSettingsComponent.kt | 49 +++++++++++++++++++ .../AppSettingsItemsAnalyticsSender.kt | 4 +- .../appsettings/api/AppSettingsComponent.kt | 9 ++++ .../di/AppSettingsFeatureModule.kt | 25 ++++++++++ .../AppSettingsModel.kt} | 30 +++++++----- .../DefaultWalletConnectComponent.kt | 2 +- .../tangem/tap/routing/utils/ChildFactory.kt | 34 ++++++++++--- 15 files changed, 225 insertions(+), 112 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/AppCurrencySelectorFragment.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/DefaultAppCurrencySelectorComponent.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/api/AppCurrencySelectorComponent.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/di/AppCurrencySelectorFeatureModule.kt rename app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/{AppCurrencySelectorViewModel.kt => model/AppCurrencySelectorModel.kt} (77%) delete mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsFragment.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/appsettings/DefaultAppSettingsComponent.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/appsettings/api/AppSettingsComponent.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/appsettings/di/AppSettingsFeatureModule.kt rename app/src/main/java/com/tangem/tap/features/details/ui/appsettings/{AppSettingsViewModel.kt => model/AppSettingsModel.kt} (92%) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt index 53844799aa..6b648b7c0d 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt @@ -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() diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index 106bc50e1e..af4c05b261 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -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) } diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/AppCurrencySelectorFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/AppCurrencySelectorFragment.kt deleted file mode 100644 index e4170e8003..0000000000 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/AppCurrencySelectorFragment.kt +++ /dev/null @@ -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, - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/DefaultAppCurrencySelectorComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/DefaultAppCurrencySelectorComponent.kt new file mode 100644 index 0000000000..6f6ec872a4 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/DefaultAppCurrencySelectorComponent.kt @@ -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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/api/AppCurrencySelectorComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/api/AppCurrencySelectorComponent.kt new file mode 100644 index 0000000000..3b823712b2 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/api/AppCurrencySelectorComponent.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/di/AppCurrencySelectorFeatureModule.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/di/AppCurrencySelectorFeatureModule.kt new file mode 100644 index 0000000000..293c87d7a3 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/di/AppCurrencySelectorFeatureModule.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/AppCurrencySelectorViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/model/AppCurrencySelectorModel.kt similarity index 77% rename from app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/AppCurrencySelectorViewModel.kt rename to app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/model/AppCurrencySelectorModel.kt index 41d27d02a9..abddb2896e 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/AppCurrencySelectorViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/model/AppCurrencySelectorModel.kt @@ -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.ComponentScoped +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 +@ComponentScoped +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 = 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() diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsFragment.kt deleted file mode 100644 index 9036d7d1fd..0000000000 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsFragment.kt +++ /dev/null @@ -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().apply { - LocalLifecycleOwner.current.lifecycle.addObserver(observer = this) - } - val state by viewModel.uiState.collectAsStateWithLifecycle() - - AppSettingsScreen( - modifier = modifier, - state = state, - onBackClick = { - store.dispatchNavigationAction(AppRouter::pop) - }, - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/DefaultAppSettingsComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/DefaultAppSettingsComponent.kt new file mode 100644 index 0000000000..a92b632003 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/DefaultAppSettingsComponent.kt @@ -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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/analytics/AppSettingsItemsAnalyticsSender.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/analytics/AppSettingsItemsAnalyticsSender.kt index d61f054cb5..fc0137dca3 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/analytics/AppSettingsItemsAnalyticsSender.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/analytics/AppSettingsItemsAnalyticsSender.kt @@ -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.ComponentScoped 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 +@ComponentScoped internal class AppSettingsItemsAnalyticsSender @Inject constructor( private val analyticsHandler: AnalyticsEventHandler, ) { diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/api/AppSettingsComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/api/AppSettingsComponent.kt new file mode 100644 index 0000000000..62be87bc2c --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/api/AppSettingsComponent.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/di/AppSettingsFeatureModule.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/di/AppSettingsFeatureModule.kt new file mode 100644 index 0000000000..8991fbdc06 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/di/AppSettingsFeatureModule.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/model/AppSettingsModel.kt similarity index 92% rename from app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsViewModel.kt rename to app/src/main/java/com/tangem/tap/features/details/ui/appsettings/model/AppSettingsModel.kt index 55d16d7d80..953ad0933c 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/model/AppSettingsModel.kt @@ -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.ComponentScoped +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 +@ComponentScoped +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, - DefaultLifecycleObserver { +) : Model(), StoreSubscriber { 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(), diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/DefaultWalletConnectComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/DefaultWalletConnectComponent.kt index 02357ff195..73a0989519 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/DefaultWalletConnectComponent.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/DefaultWalletConnectComponent.kt @@ -49,7 +49,7 @@ internal class DefaultWalletConnectComponent @AssistedInject constructor( } override fun newState(state: WalletConnectState) { - screenState?.value = model.updateState(state) + screenState.value = model.updateState(state) } @Composable diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index 7274342341..229d4b63a2 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -20,8 +20,8 @@ import com.tangem.features.staking.api.StakingComponent import com.tangem.features.tester.api.TesterRouter import com.tangem.features.tokendetails.TokenDetailsComponent 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.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.ResetCardFragment @@ -67,6 +67,8 @@ internal class ChildFactory @Inject constructor( 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 walletRouter: WalletRouter, private val testerRouter: TesterRouter, private val pushNotificationRouter: PushNotificationsRouter, @@ -303,9 +305,21 @@ internal class ChildFactory @Inject constructor( componentFactory = cardSettingsComponentFactory, ) } - is AppRoute.AppCurrencySelector, + 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.SaveWallet, - is AppRoute.AppSettings, is AppRoute.DetailsSecurity, is AppRoute.OnboardingNote, is AppRoute.OnboardingOther, @@ -337,7 +351,11 @@ internal class ChildFactory @Inject constructor( ) } is AppRoute.AppCurrencySelector -> { - route.asFragmentChild(Provider { AppCurrencySelectorFragment() }) + route.asComponentChild( + contextProvider = contextProvider(route, contextFactory), + params = Unit, + componentFactory = appCurrencySelectorComponentFactory, + ) } is AppRoute.SaveWallet -> { route.asFragmentChild(Provider { SaveWalletBottomSheetFragment() }) @@ -357,7 +375,11 @@ internal class ChildFactory @Inject constructor( ) } is AppRoute.AppSettings -> { - route.asFragmentChild(Provider { AppSettingsFragment() }) + route.asComponentChild( + contextProvider = contextProvider(route, contextFactory), + params = Unit, + componentFactory = appSettingsComponentFactory, + ) } is AppRoute.CardSettings -> { route.asComponentChild( From 3503a14f3b1ee3733bf3fec2825864f71c439800 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 24 Feb 2025 17:28:05 +0300 Subject: [PATCH 24/54] Updated on 2026-08-14 --- .../domain/userWalletList/model/UserWalletInformation.kt | 3 +++ .../com/tangem/tap/domain/userWalletList/utils/Mapper.kt | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/model/UserWalletInformation.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/model/UserWalletInformation.kt index 2697b453b7..e7a9f1873f 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/model/UserWalletInformation.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/model/UserWalletInformation.kt @@ -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, + @Json(name = "visaCardActivationStatus") + val visaCardActivationStatus: VisaCardActivationStatus? = null, ) @JsonClass(generateAdapter = true) diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/Mapper.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/Mapper.kt index 7b869eb69f..4c73101416 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/Mapper.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/Mapper.kt @@ -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, ), ) \ No newline at end of file From 8212dffeb6b1f0e387499e47adee8c869022ab58 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 24 Feb 2025 21:30:53 +0300 Subject: [PATCH 25/54] Updated on 2026-08-14 --- .../ui/resetcard/DefaultResetCardComponent.kt | 40 ++++++++++++++++ .../details/ui/resetcard/ResetCardFragment.kt | 34 ------------- .../ui/resetcard/api/ResetCardComponent.kt | 17 +++++++ .../ui/resetcard/di/ResetCardFeatureModule.kt | 25 ++++++++++ .../ResetCardModel.kt} | 47 +++++++++--------- .../DefaultSecurityModeComponent.kt | 43 +++++++++++++++++ .../ui/securitymode/SecurityModeFragment.kt | 34 ------------- .../securitymode/api/SecurityModeComponent.kt | 14 ++++++ .../di/SecurityModeFeatureModule.kt | 25 ++++++++++ .../SecurityModeModel.kt} | 20 ++++---- .../tangem/tap/routing/utils/ChildFactory.kt | 48 ++++++++++++++++--- .../com/tangem/common/routing/AppRoute.kt | 18 +------ 12 files changed, 243 insertions(+), 122 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/resetcard/DefaultResetCardComponent.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardFragment.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/resetcard/api/ResetCardComponent.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/resetcard/di/ResetCardFeatureModule.kt rename app/src/main/java/com/tangem/tap/features/details/ui/resetcard/{ResetCardViewModel.kt => model/ResetCardModel.kt} (88%) create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/securitymode/DefaultSecurityModeComponent.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/securitymode/SecurityModeFragment.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/securitymode/api/SecurityModeComponent.kt create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/securitymode/di/SecurityModeFeatureModule.kt rename app/src/main/java/com/tangem/tap/features/details/ui/securitymode/{SecurityModeViewModel.kt => model/SecurityModeModel.kt} (87%) diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/DefaultResetCardComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/DefaultResetCardComponent.kt new file mode 100644 index 0000000000..16000cb7bb --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/DefaultResetCardComponent.kt @@ -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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardFragment.kt deleted file mode 100644 index 041a91ee08..0000000000 --- a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardFragment.kt +++ /dev/null @@ -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, - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/api/ResetCardComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/api/ResetCardComponent.kt new file mode 100644 index 0000000000..abbe76595b --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/api/ResetCardComponent.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/di/ResetCardFeatureModule.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/di/ResetCardFeatureModule.kt new file mode 100644 index 0000000000..cdda8d97d4 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/di/ResetCardFeatureModule.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/model/ResetCardModel.kt similarity index 88% rename from app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardViewModel.kt rename to app/src/main/java/com/tangem/tap/features/details/ui/resetcard/model/ResetCardModel.kt index ebcdf702a9..a4108e3ea0 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/model/ResetCardModel.kt @@ -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.ComponentScoped +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 +@ComponentScoped +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() // region Card-set specific data. All cards from single set have the same userWalletId and cardTypesResolver - private val currentUserWalletId = savedStateHandle.get(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(AppRoute.ResetToFactory.CARD_ID) - ?: error("CardId must be provided for ResetCardViewModel") + private val primaryCardId: String = params.cardId - private val isActiveBackupPrimaryCard = - savedStateHandle.get(AppRoute.ResetToFactory.IS_ACTIVE_BACKUP_STATUS) - ?: error("IsActiveBackupCard must be provided for ResetCardViewModel") + private val isActiveBackupPrimaryCard = params.isActiveBackupStatus - private val primaryBackupCardsCount = savedStateHandle.get(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, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/DefaultSecurityModeComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/DefaultSecurityModeComponent.kt new file mode 100644 index 0000000000..151b4c123d --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/DefaultSecurityModeComponent.kt @@ -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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/SecurityModeFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/SecurityModeFragment.kt deleted file mode 100644 index 1c5fe7f90b..0000000000 --- a/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/SecurityModeFragment.kt +++ /dev/null @@ -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) }, - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/api/SecurityModeComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/api/SecurityModeComponent.kt new file mode 100644 index 0000000000..a09d7ba6c9 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/api/SecurityModeComponent.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/di/SecurityModeFeatureModule.kt b/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/di/SecurityModeFeatureModule.kt new file mode 100644 index 0000000000..3fb8b00635 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/di/SecurityModeFeatureModule.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/SecurityModeViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/model/SecurityModeModel.kt similarity index 87% rename from app/src/main/java/com/tangem/tap/features/details/ui/securitymode/SecurityModeViewModel.kt rename to app/src/main/java/com/tangem/tap/features/details/ui/securitymode/model/SecurityModeModel.kt index a7f0b763b3..5fe21b868c 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/SecurityModeViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/model/SecurityModeModel.kt @@ -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.ComponentScoped +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 +@ComponentScoped +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) diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index 229d4b63a2..ff2cfe56d1 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -24,8 +24,8 @@ import com.tangem.tap.features.details.ui.appcurrency.api.AppCurrencySelectorCom 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.ResetCardFragment -import com.tangem.tap.features.details.ui.securitymode.SecurityModeFragment +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 @@ -69,6 +69,8 @@ internal class ChildFactory @Inject constructor( 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 walletRouter: WalletRouter, private val testerRouter: TesterRouter, private val pushNotificationRouter: PushNotificationsRouter, @@ -319,14 +321,33 @@ internal class ChildFactory @Inject constructor( 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.SaveWallet, - is AppRoute.DetailsSecurity, is AppRoute.OnboardingNote, is AppRoute.OnboardingOther, is AppRoute.OnboardingTwins, is AppRoute.OnboardingWallet, is AppRoute.ReferralProgram, - is AppRoute.ResetToFactory, is AppRoute.Wallet, is AppRoute.PushNotification, -> error("Unsupported route: $route") @@ -396,7 +417,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( @@ -451,7 +478,16 @@ internal class ChildFactory @Inject constructor( route.asFragmentChild(Provider { ReferralFragment() }) } 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( diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt index 4fec799a3c..dddee065b7 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt @@ -103,10 +103,7 @@ sealed class AppRoute(val path: String) : Route { @Serializable data class DetailsSecurity( val userWalletId: UserWalletId, - ) : AppRoute(path = "/details/security"), RouteBundleParams { - - override fun getBundle(): Bundle = bundle(serializer()) - } + ) : AppRoute(path = "/details/security") @Serializable data class CardSettings( @@ -136,18 +133,7 @@ sealed class AppRoute(val path: String) : Route { "/$cardId" + "/$isActiveBackupStatus" + "/$backupCardsCount", - ), - RouteBundleParams { - - override fun getBundle(): Bundle = bundle(serializer()) - - companion object { - const val USER_WALLET_ID = "userWalletId" - const val CARD_ID = "cardId" - const val IS_ACTIVE_BACKUP_STATUS = "isActiveBackupStatus" - const val BACKUP_CARDS_COUNT = "backupCardsCount" - } - } + ) @Serializable data object AccessCodeRecovery : AppRoute(path = "/access_code_recovery"), RouteBundleParams { From e88aaebe5d0aaa5a0e1871bb5db648b2771f8be4 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 25 Feb 2025 05:35:58 +0000 Subject: [PATCH 26/54] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 3be6bacbc0..b58666bdd9 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -1,7 +1,7 @@ [versions] -tangemBlockchainSdk = "release-app_5.21-963" +tangemBlockchainSdk = "develop-959" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "release-app_5.21-435" +tangemCardSdk = "develop-434" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "2.0.0-alpha.25-tangem-developments8" #tangemVico = "0.0.1" # Keep it! - used for local builds ^ From e8da66786f0c665c18908fefb247c490fb77a6f0 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 25 Feb 2025 09:53:16 +0300 Subject: [PATCH 27/54] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index b58666bdd9..422608e325 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -1,5 +1,5 @@ [versions] -tangemBlockchainSdk = "develop-959" +tangemBlockchainSdk = "develop-965" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "develop-434" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ From 4a6e57a049ca7cc88c9b83f83566200ff9e3d678 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 25 Feb 2025 10:02:39 +0300 Subject: [PATCH 28/54] Updated on 2026-08-14 --- app/build.gradle.kts | 2 +- .../tangem/tap/routing/utils/ChildFactory.kt | 17 ++++- .../di/CoroutineDispatcherProviderModule.kt | 2 +- features/referral/api/.gitignore | 1 + features/referral/api/build.gradle.kts | 20 ++++++ .../feature/referral/api/ReferralComponent.kt | 14 +++++ features/referral/domain/build.gradle.kts | 1 + .../domain/di/ReferralDomainModule.kt | 8 +-- .../{presentation => impl}/.gitignore | 0 .../{presentation => impl}/build.gradle.kts | 4 ++ .../referral/DefaultReferralComponent.kt | 30 +++++++++ .../referral/analytics/ReferralEvents.kt | 0 .../feature/referral/di/ComponentModule.kt | 25 ++++++++ .../feature/referral/model/ReferralModel.kt} | 62 ++++++++----------- .../referral/models/DemoModeException.kt | 0 .../referral/models/ReferralStateHolder.kt | 0 .../feature/referral/ui/AgreementText.kt | 0 .../referral/ui/NonParticipateBottomBlock.kt | 0 .../referral/ui/ParticipateBottomBlock.kt | 0 .../feature/referral/ui/ReferralScreen.kt | 0 .../feature/referral/ReferralFragment.kt | 37 ----------- .../feature/referral/router/ReferralRouter.kt | 12 ---- settings.gradle.kts | 3 +- 23 files changed, 143 insertions(+), 95 deletions(-) create mode 100644 features/referral/api/.gitignore create mode 100644 features/referral/api/build.gradle.kts create mode 100644 features/referral/api/src/main/kotlin/com/tangem/feature/referral/api/ReferralComponent.kt rename features/referral/{presentation => impl}/.gitignore (100%) rename features/referral/{presentation => impl}/build.gradle.kts (93%) create mode 100644 features/referral/impl/src/main/java/com/tangem/feature/referral/DefaultReferralComponent.kt rename features/referral/{presentation => impl}/src/main/java/com/tangem/feature/referral/analytics/ReferralEvents.kt (100%) create mode 100644 features/referral/impl/src/main/java/com/tangem/feature/referral/di/ComponentModule.kt rename features/referral/{presentation/src/main/java/com/tangem/feature/referral/viewmodels/ReferralViewModel.kt => impl/src/main/java/com/tangem/feature/referral/model/ReferralModel.kt} (78%) rename features/referral/{presentation => impl}/src/main/java/com/tangem/feature/referral/models/DemoModeException.kt (100%) rename features/referral/{presentation => impl}/src/main/java/com/tangem/feature/referral/models/ReferralStateHolder.kt (100%) rename features/referral/{presentation => impl}/src/main/java/com/tangem/feature/referral/ui/AgreementText.kt (100%) rename features/referral/{presentation => impl}/src/main/java/com/tangem/feature/referral/ui/NonParticipateBottomBlock.kt (100%) rename features/referral/{presentation => impl}/src/main/java/com/tangem/feature/referral/ui/ParticipateBottomBlock.kt (100%) rename features/referral/{presentation => impl}/src/main/java/com/tangem/feature/referral/ui/ReferralScreen.kt (100%) delete mode 100644 features/referral/presentation/src/main/java/com/tangem/feature/referral/ReferralFragment.kt delete mode 100644 features/referral/presentation/src/main/java/com/tangem/feature/referral/router/ReferralRouter.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8fa9c93920..c3a1e5b24a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -146,7 +146,7 @@ dependencies { /** Features */ implementation(projects.features.onboarding) - implementation(projects.features.referral.presentation) + implementation(projects.features.referral.impl) implementation(projects.features.referral.domain) implementation(projects.features.referral.data) implementation(projects.features.swap.api) diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index ff2cfe56d1..bcea27fccd 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -3,7 +3,7 @@ package com.tangem.tap.routing.utils import com.tangem.common.routing.AppRoute import com.tangem.core.decompose.context.AppComponentContext import com.tangem.feature.qrscanning.QrScanningComponent -import com.tangem.feature.referral.ReferralFragment +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 @@ -71,6 +71,7 @@ internal class ChildFactory @Inject constructor( private val appSettingsComponentFactory: AppSettingsComponent.Factory, private val securityModeComponentFactory: SecurityModeComponent.Factory, private val resetCardComponentFactory: ResetCardComponent.Factory, + private val referralComponentFactory: ReferralComponent.Factory, private val walletRouter: WalletRouter, private val testerRouter: TesterRouter, private val pushNotificationRouter: PushNotificationsRouter, @@ -342,12 +343,18 @@ internal class ChildFactory @Inject constructor( componentFactory = resetCardComponentFactory, ) } + is AppRoute.ReferralProgram -> { + createComponentChild( + contextProvider = contextProvider(route, contextFactory), + params = ReferralComponent.Params(route.userWalletId), + componentFactory = referralComponentFactory, + ) + } is AppRoute.SaveWallet, is AppRoute.OnboardingNote, is AppRoute.OnboardingOther, is AppRoute.OnboardingTwins, is AppRoute.OnboardingWallet, - is AppRoute.ReferralProgram, is AppRoute.Wallet, is AppRoute.PushNotification, -> error("Unsupported route: $route") @@ -475,7 +482,11 @@ internal class ChildFactory @Inject constructor( ) } is AppRoute.ReferralProgram -> { - route.asFragmentChild(Provider { ReferralFragment() }) + route.asComponentChild( + contextProvider = contextProvider(route, contextFactory), + params = ReferralComponent.Params(route.userWalletId), + componentFactory = referralComponentFactory, + ) } is AppRoute.ResetToFactory -> { route.asComponentChild( diff --git a/core/utils/src/main/java/com/tangem/utils/di/CoroutineDispatcherProviderModule.kt b/core/utils/src/main/java/com/tangem/utils/di/CoroutineDispatcherProviderModule.kt index 6dd1011462..cf0847f2f0 100644 --- a/core/utils/src/main/java/com/tangem/utils/di/CoroutineDispatcherProviderModule.kt +++ b/core/utils/src/main/java/com/tangem/utils/di/CoroutineDispatcherProviderModule.kt @@ -9,7 +9,7 @@ import dagger.hilt.components.SingletonComponent @Module @InstallIn(SingletonComponent::class) -interface CoroutineDispatcherProviderModule { +internal interface CoroutineDispatcherProviderModule { @Binds fun bindCoroutineDispatcherProvider( diff --git a/features/referral/api/.gitignore b/features/referral/api/.gitignore new file mode 100644 index 0000000000..796b96d1c4 --- /dev/null +++ b/features/referral/api/.gitignore @@ -0,0 +1 @@ +/build diff --git a/features/referral/api/build.gradle.kts b/features/referral/api/build.gradle.kts new file mode 100644 index 0000000000..22a3ba6fa3 --- /dev/null +++ b/features/referral/api/build.gradle.kts @@ -0,0 +1,20 @@ +plugins { + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) + alias(deps.plugins.kotlin.serialization) + id("kotlin-parcelize") + id("configuration") +} + +android { + namespace = "com.tangem.features.referral.api" +} + +dependencies { + /* Project - Core */ + implementation(projects.core.decompose) + implementation(projects.core.ui) + + /* Project - Domain */ + implementation(projects.domain.wallets.models) +} \ No newline at end of file diff --git a/features/referral/api/src/main/kotlin/com/tangem/feature/referral/api/ReferralComponent.kt b/features/referral/api/src/main/kotlin/com/tangem/feature/referral/api/ReferralComponent.kt new file mode 100644 index 0000000000..de0cda3a93 --- /dev/null +++ b/features/referral/api/src/main/kotlin/com/tangem/feature/referral/api/ReferralComponent.kt @@ -0,0 +1,14 @@ +package com.tangem.feature.referral.api + +import com.tangem.core.decompose.factory.ComponentFactory +import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.domain.wallets.models.UserWalletId + +interface ReferralComponent : ComposableContentComponent { + + data class Params( + val userWalletId: UserWalletId, + ) + + interface Factory : ComponentFactory +} \ No newline at end of file diff --git a/features/referral/domain/build.gradle.kts b/features/referral/domain/build.gradle.kts index a77d439bbb..0ca36ddd1a 100644 --- a/features/referral/domain/build.gradle.kts +++ b/features/referral/domain/build.gradle.kts @@ -13,6 +13,7 @@ dependencies { /** Libs */ implementation(projects.core.utils) + implementation(projects.core.decompose) /** Core modules */ implementation(projects.libs.crypto) diff --git a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/di/ReferralDomainModule.kt b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/di/ReferralDomainModule.kt index 172c41b27d..07ec550009 100644 --- a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/di/ReferralDomainModule.kt +++ b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/di/ReferralDomainModule.kt @@ -1,5 +1,7 @@ package com.tangem.feature.referral.domain.di +import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.DecomposeComponent import com.tangem.domain.card.DerivePublicKeysUseCase import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase import com.tangem.domain.wallets.usecase.GetUserWalletUseCase @@ -10,15 +12,13 @@ import com.tangem.lib.crypto.UserWalletManager import dagger.Module import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.components.ViewModelComponent -import dagger.hilt.android.scopes.ViewModelScoped @Module -@InstallIn(ViewModelComponent::class) +@InstallIn(DecomposeComponent::class) class ReferralDomainModule { @Provides - @ViewModelScoped + @ComponentScoped fun provideReferralInteractor( referralRepository: ReferralRepository, userWalletManager: UserWalletManager, diff --git a/features/referral/presentation/.gitignore b/features/referral/impl/.gitignore similarity index 100% rename from features/referral/presentation/.gitignore rename to features/referral/impl/.gitignore diff --git a/features/referral/presentation/build.gradle.kts b/features/referral/impl/build.gradle.kts similarity index 93% rename from features/referral/presentation/build.gradle.kts rename to features/referral/impl/build.gradle.kts index 6ee99e86cb..cf2272bee5 100644 --- a/features/referral/presentation/build.gradle.kts +++ b/features/referral/impl/build.gradle.kts @@ -11,6 +11,9 @@ android { } dependencies { + /** Api */ + api(projects.features.referral.api) + /** Core modules */ implementation(projects.core.analytics) implementation(projects.core.analytics.models) @@ -18,6 +21,7 @@ dependencies { implementation(projects.core.res) implementation(projects.core.utils) implementation(projects.core.ui) + implementation(projects.core.decompose) implementation(projects.libs.crypto) implementation(projects.common.routing) diff --git a/features/referral/impl/src/main/java/com/tangem/feature/referral/DefaultReferralComponent.kt b/features/referral/impl/src/main/java/com/tangem/feature/referral/DefaultReferralComponent.kt new file mode 100644 index 0000000000..f30cefaab8 --- /dev/null +++ b/features/referral/impl/src/main/java/com/tangem/feature/referral/DefaultReferralComponent.kt @@ -0,0 +1,30 @@ +package com.tangem.feature.referral + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.decompose.model.getOrCreateModel +import com.tangem.feature.referral.api.ReferralComponent +import com.tangem.feature.referral.model.ReferralModel +import com.tangem.feature.referral.ui.ReferralScreen +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +class DefaultReferralComponent @AssistedInject constructor( + @Assisted appComponentContext: AppComponentContext, + @Assisted params: ReferralComponent.Params, +) : ReferralComponent, AppComponentContext by appComponentContext { + + private val model: ReferralModel = getOrCreateModel(params) + + @Composable + override fun Content(modifier: Modifier) { + ReferralScreen(stateHolder = model.uiState) + } + + @AssistedFactory + interface Factory : ReferralComponent.Factory { + override fun create(context: AppComponentContext, params: ReferralComponent.Params): DefaultReferralComponent + } +} \ No newline at end of file diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/analytics/ReferralEvents.kt b/features/referral/impl/src/main/java/com/tangem/feature/referral/analytics/ReferralEvents.kt similarity index 100% rename from features/referral/presentation/src/main/java/com/tangem/feature/referral/analytics/ReferralEvents.kt rename to features/referral/impl/src/main/java/com/tangem/feature/referral/analytics/ReferralEvents.kt diff --git a/features/referral/impl/src/main/java/com/tangem/feature/referral/di/ComponentModule.kt b/features/referral/impl/src/main/java/com/tangem/feature/referral/di/ComponentModule.kt new file mode 100644 index 0000000000..54355a0a6c --- /dev/null +++ b/features/referral/impl/src/main/java/com/tangem/feature/referral/di/ComponentModule.kt @@ -0,0 +1,25 @@ +package com.tangem.feature.referral.di + +import com.tangem.core.decompose.model.Model +import com.tangem.feature.referral.DefaultReferralComponent +import com.tangem.feature.referral.api.ReferralComponent +import com.tangem.feature.referral.model.ReferralModel +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 ComponentModule { + + @Binds + fun provideReferralComponentFactory(impl: DefaultReferralComponent.Factory): ReferralComponent.Factory + + @Binds + @IntoMap + @ClassKey(ReferralModel::class) + fun bindModel(model: ReferralModel): Model +} \ No newline at end of file diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/viewmodels/ReferralViewModel.kt b/features/referral/impl/src/main/java/com/tangem/feature/referral/model/ReferralModel.kt similarity index 78% rename from features/referral/presentation/src/main/java/com/tangem/feature/referral/viewmodels/ReferralViewModel.kt rename to features/referral/impl/src/main/java/com/tangem/feature/referral/model/ReferralModel.kt index 57d35abc7d..621ddbe1aa 100644 --- a/features/referral/presentation/src/main/java/com/tangem/feature/referral/viewmodels/ReferralViewModel.kt +++ b/features/referral/impl/src/main/java/com/tangem/feature/referral/model/ReferralModel.kt @@ -1,21 +1,20 @@ -package com.tangem.feature.referral.viewmodels +package com.tangem.feature.referral.model -import android.os.Bundle +import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue -import androidx.lifecycle.SavedStateHandle -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.tangem.common.routing.AppRoute -import com.tangem.common.routing.bundle.unbundle +import com.tangem.common.routing.AppRouter import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.model.Model +import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.navigation.share.ShareManager import com.tangem.core.navigation.url.UrlOpener import com.tangem.domain.demo.IsDemoCardUseCase -import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.feature.referral.analytics.ReferralEvents +import com.tangem.feature.referral.api.ReferralComponent import com.tangem.feature.referral.domain.ReferralInteractor import com.tangem.feature.referral.domain.errors.ReferralError import com.tangem.feature.referral.domain.models.DiscountType @@ -25,29 +24,26 @@ import com.tangem.feature.referral.models.DemoModeException import com.tangem.feature.referral.models.ReferralStateHolder import com.tangem.feature.referral.models.ReferralStateHolder.ErrorSnackbar import com.tangem.feature.referral.models.ReferralStateHolder.ReferralInfoState -import com.tangem.feature.referral.router.ReferralRouter -import dagger.hilt.android.lifecycle.HiltViewModel +import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.launch import javax.inject.Inject -import kotlin.properties.Delegates @Suppress("LongParameterList") -@HiltViewModel -internal class ReferralViewModel @Inject constructor( +@Stable +@ComponentScoped +internal class ReferralModel @Inject constructor( + paramsContainer: ParamsContainer, + override val dispatchers: CoroutineDispatcherProvider, private val referralInteractor: ReferralInteractor, private val analyticsEventHandler: AnalyticsEventHandler, private val shareManager: ShareManager, private val urlOpener: UrlOpener, private val getUserWalletUseCase: GetUserWalletUseCase, private val isDemoCardUseCase: IsDemoCardUseCase, - savedStateHandle: SavedStateHandle, -) : ViewModel() { + private val appRouter: AppRouter, +) : Model() { - private val userWalletId = savedStateHandle.get(AppRoute.ReferralProgram.USER_WALLET_ID_KEY) - ?.unbundle(UserWalletId.serializer()) - ?: error("User wallet ID is required for Referral screen") - - private var referralRouter: ReferralRouter by Delegates.notNull() + private val params = paramsContainer.require() private var lastReferralData: ReferralData? = null @@ -55,20 +51,14 @@ internal class ReferralViewModel @Inject constructor( private set init { + analyticsEventHandler.send(ReferralEvents.ReferralScreenOpened) loadReferralData() } - fun setRouter(router: ReferralRouter) { - referralRouter = router - uiState = uiState.copy(headerState = ReferralStateHolder.HeaderState(onBackClicked = router::back)) - } - - fun onScreenOpened() { - analyticsEventHandler.send(ReferralEvents.ReferralScreenOpened) - } - private fun createInitiallyUiState() = ReferralStateHolder( - headerState = ReferralStateHolder.HeaderState(onBackClicked = { }), + headerState = ReferralStateHolder.HeaderState( + onBackClicked = appRouter::pop, + ), referralInfoState = ReferralInfoState.Loading, errorSnackbar = null, analytics = ReferralStateHolder.Analytics( @@ -80,9 +70,9 @@ internal class ReferralViewModel @Inject constructor( private fun loadReferralData() { uiState = uiState.copy(referralInfoState = ReferralInfoState.Loading) - viewModelScope.launch { + modelScope.launch { runCatching { - referralInteractor.getReferralStatus(userWalletId).apply { + referralInteractor.getReferralStatus(params.userWalletId).apply { lastReferralData = this } } @@ -92,15 +82,15 @@ internal class ReferralViewModel @Inject constructor( } private fun participate() { - val userWallet = getUserWalletUseCase(userWalletId).getOrNull() ?: error("User wallet not found") + val userWallet = getUserWalletUseCase(params.userWalletId).getOrNull() ?: error("User wallet not found") if (isDemoCardUseCase(cardId = userWallet.cardId)) { showErrorSnackbar(DemoModeException()) } else { analyticsEventHandler.send(ReferralEvents.ClickParticipate) uiState = uiState.copy(referralInfoState = ReferralInfoState.Loading) - viewModelScope.launch { - runCatching { referralInteractor.startReferral(userWalletId) } + modelScope.launch { + runCatching { referralInteractor.startReferral(params.userWalletId) } .onSuccess(::showContent) .onFailure { throwable -> if (throwable is ReferralError.UserCancelledException) { @@ -121,7 +111,7 @@ internal class ReferralViewModel @Inject constructor( private fun showErrorSnackbar(throwable: Throwable) { uiState = uiState.copy( - errorSnackbar = ErrorSnackbar(throwable = throwable, onOkClicked = referralRouter::back), + errorSnackbar = ErrorSnackbar(throwable = throwable, onOkClicked = appRouter::pop), ) } diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/models/DemoModeException.kt b/features/referral/impl/src/main/java/com/tangem/feature/referral/models/DemoModeException.kt similarity index 100% rename from features/referral/presentation/src/main/java/com/tangem/feature/referral/models/DemoModeException.kt rename to features/referral/impl/src/main/java/com/tangem/feature/referral/models/DemoModeException.kt diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/models/ReferralStateHolder.kt b/features/referral/impl/src/main/java/com/tangem/feature/referral/models/ReferralStateHolder.kt similarity index 100% rename from features/referral/presentation/src/main/java/com/tangem/feature/referral/models/ReferralStateHolder.kt rename to features/referral/impl/src/main/java/com/tangem/feature/referral/models/ReferralStateHolder.kt diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/AgreementText.kt b/features/referral/impl/src/main/java/com/tangem/feature/referral/ui/AgreementText.kt similarity index 100% rename from features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/AgreementText.kt rename to features/referral/impl/src/main/java/com/tangem/feature/referral/ui/AgreementText.kt diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/NonParticipateBottomBlock.kt b/features/referral/impl/src/main/java/com/tangem/feature/referral/ui/NonParticipateBottomBlock.kt similarity index 100% rename from features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/NonParticipateBottomBlock.kt rename to features/referral/impl/src/main/java/com/tangem/feature/referral/ui/NonParticipateBottomBlock.kt diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/ParticipateBottomBlock.kt b/features/referral/impl/src/main/java/com/tangem/feature/referral/ui/ParticipateBottomBlock.kt similarity index 100% rename from features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/ParticipateBottomBlock.kt rename to features/referral/impl/src/main/java/com/tangem/feature/referral/ui/ParticipateBottomBlock.kt diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/ReferralScreen.kt b/features/referral/impl/src/main/java/com/tangem/feature/referral/ui/ReferralScreen.kt similarity index 100% rename from features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/ReferralScreen.kt rename to features/referral/impl/src/main/java/com/tangem/feature/referral/ui/ReferralScreen.kt diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ReferralFragment.kt b/features/referral/presentation/src/main/java/com/tangem/feature/referral/ReferralFragment.kt deleted file mode 100644 index cec296cc80..0000000000 --- a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ReferralFragment.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.tangem.feature.referral - -import android.os.Bundle -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.fragment.app.viewModels -import com.tangem.common.routing.AppRouter -import com.tangem.core.ui.UiDependencies -import com.tangem.core.ui.screen.ComposeFragment -import com.tangem.feature.referral.router.ReferralRouter -import com.tangem.feature.referral.ui.ReferralScreen -import com.tangem.feature.referral.viewmodels.ReferralViewModel -import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject - -@AndroidEntryPoint -class ReferralFragment : ComposeFragment() { - - @Inject - override lateinit var uiDependencies: UiDependencies - - @Inject - internal lateinit var appRouter: AppRouter - - private val viewModel by viewModels() - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - viewModel.onScreenOpened() - viewModel.setRouter(ReferralRouter(appRouter)) - } - - @Composable - override fun ScreenContent(modifier: Modifier) { - ReferralScreen(stateHolder = viewModel.uiState) - } -} \ No newline at end of file diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/router/ReferralRouter.kt b/features/referral/presentation/src/main/java/com/tangem/feature/referral/router/ReferralRouter.kt deleted file mode 100644 index a8ac11e54b..0000000000 --- a/features/referral/presentation/src/main/java/com/tangem/feature/referral/router/ReferralRouter.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.tangem.feature.referral.router - -import com.tangem.common.routing.AppRouter - -internal class ReferralRouter( - private val appRouter: AppRouter, -) { - - fun back() { - appRouter.pop() - } -} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index b89a9482f9..ddb8968ba6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -171,9 +171,10 @@ include(":features:onboarding") include(":features:onboarding-v2:api") include(":features:onboarding-v2:impl") +include(":features:referral:api") include(":features:referral:data") include(":features:referral:domain") -include(":features:referral:presentation") +include(":features:referral:impl") include(":features:swap:api") include(":features:swap:data") From 5507c2249b5b3b37e208a96a1882f00dd04f2de3 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 25 Feb 2025 10:31:26 +0300 Subject: [PATCH 29/54] Updated on 2026-08-14 --- data/visa/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/visa/build.gradle.kts b/data/visa/build.gradle.kts index b2f273b514..a4adc23b0f 100644 --- a/data/visa/build.gradle.kts +++ b/data/visa/build.gradle.kts @@ -29,7 +29,7 @@ dependencies { implementation(projects.libs.blockchainSdk) /** Project - Libs */ - debugImplementation(projects.libs.visa) + implementation(projects.libs.visa) /** Libs - Other */ implementation(deps.kotlin.coroutines) From c70afd815e71c303cfaf8c9c8ba80ab012e5b81e Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 25 Feb 2025 13:21:07 +0300 Subject: [PATCH 30/54] Updated on 2026-08-14 --- .../main/java/com/tangem/tap/MainActivity.kt | 4 -- .../tap/proxy/redux/DaggerGraphState.kt | 2 - .../tangem/tap/routing/utils/ChildFactory.kt | 18 ++++++-- .../v2/multiwallet/impl/ui/WalletArtwork.kt | 9 +++- .../push-notifications/api/build.gradle.kts | 3 +- .../api/PushNotificationsComponent.kt | 9 ++++ .../api/navigation/PushNotificationsRouter.kt | 8 ---- .../push-notifications/impl/build.gradle.kts | 1 + .../impl/DefaultPushNotificationsComponent.kt | 42 +++++++++++++++++++ .../impl/PushNotificationsFragment.kt | 39 ----------------- .../impl/di/PushNotificationsModule.kt | 33 ++++++++------- .../PushNotificationsClickIntents.kt | 2 +- .../PushNotificationsModel.kt} | 35 +++++++++------- .../DefaultPushNotificationsRouter.kt | 18 -------- .../InnerPushNotificationsRouter.kt | 8 ---- 15 files changed, 112 insertions(+), 119 deletions(-) create mode 100644 features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsComponent.kt delete mode 100644 features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/navigation/PushNotificationsRouter.kt create mode 100644 features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/DefaultPushNotificationsComponent.kt delete mode 100644 features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/PushNotificationsFragment.kt rename features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/{presentation/viewmodel => model}/PushNotificationsClickIntents.kt (67%) rename features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/{presentation/viewmodel/PushNotificationViewModel.kt => model/PushNotificationsModel.kt} (69%) delete mode 100644 features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/navigation/DefaultPushNotificationsRouter.kt delete mode 100644 features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/navigation/InnerPushNotificationsRouter.kt diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 20410b9a00..3e81d97a82 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -62,7 +62,6 @@ import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase import com.tangem.domain.wallets.legacy.UserWalletsListManager 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.wallet.navigation.WalletRouter import com.tangem.google.GoogleServicesHelper @@ -176,9 +175,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac @Inject internal lateinit var routingComponentFactory: RoutingComponent.Factory - @Inject - lateinit var pushNotificationsRouter: PushNotificationsRouter - @Inject lateinit var cardRepository: CardRepository diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt index 3c36d9833b..08b6c9ba8a 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt @@ -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, diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index bcea27fccd..52cf5cc8ee 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -13,7 +13,7 @@ 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.pushnotifications.api.PushNotificationsComponent import com.tangem.features.send.api.SendComponent import com.tangem.features.swap.SwapComponent import com.tangem.features.staking.api.StakingComponent @@ -72,9 +72,9 @@ internal class ChildFactory @Inject constructor( private val securityModeComponentFactory: SecurityModeComponent.Factory, private val resetCardComponentFactory: ResetCardComponent.Factory, private val referralComponentFactory: ReferralComponent.Factory, + private val pushNotificationsComponentFactory: PushNotificationsComponent.Factory, private val walletRouter: WalletRouter, private val testerRouter: TesterRouter, - private val pushNotificationRouter: PushNotificationsRouter, private val routingFeatureToggles: RoutingFeatureToggles, ) { @@ -350,13 +350,19 @@ internal class ChildFactory @Inject constructor( componentFactory = referralComponentFactory, ) } + is AppRoute.PushNotification -> { + createComponentChild( + contextProvider = contextProvider(route, contextFactory), + params = Unit, + componentFactory = pushNotificationsComponentFactory, + ) + } is AppRoute.SaveWallet, is AppRoute.OnboardingNote, is AppRoute.OnboardingOther, is AppRoute.OnboardingTwins, is AppRoute.OnboardingWallet, is AppRoute.Wallet, - is AppRoute.PushNotification, -> error("Unsupported route: $route") } // endregion @@ -551,7 +557,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( diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/ui/WalletArtwork.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/ui/WalletArtwork.kt index 78d304117a..6ba4014a77 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/ui/WalletArtwork.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/ui/WalletArtwork.kt @@ -2,10 +2,12 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.ui +import android.content.res.Configuration import androidx.compose.animation.core.Transition import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.updateTransition import androidx.compose.foundation.Canvas +import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.material3.Button import androidx.compose.material3.Text @@ -106,7 +108,7 @@ fun WalletArtworks( } } - val circleColor = TangemTheme.colors.background.secondary + val circleColor = TangemTheme.colors.button.secondary Canvas( modifier = Modifier @@ -451,11 +453,14 @@ private fun WalletArtworksState.toTransitionSetState(maxWidthDp: Float, maxHeigh } @Preview(showBackground = true, widthDp = 360, heightDp = 640) +@Preview(showBackground = true, widthDp = 360, heightDp = 640, uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable private fun Preview() { TangemThemePreview { Box( - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .background(TangemTheme.colors.background.primary) + .fillMaxSize(), contentAlignment = Alignment.Center, ) { var state: WalletArtworksState by remember { mutableStateOf(WalletArtworksState.Folded) } diff --git a/features/push-notifications/api/build.gradle.kts b/features/push-notifications/api/build.gradle.kts index 8fd2b5a11b..3366d4511c 100644 --- a/features/push-notifications/api/build.gradle.kts +++ b/features/push-notifications/api/build.gradle.kts @@ -9,10 +9,11 @@ android { } dependencies { - /** AndroidX */ implementation(deps.androidx.fragment.ktx) /** Core */ + implementation(projects.core.decompose) + implementation(projects.core.ui) implementation(projects.core.analytics.models) } \ No newline at end of file diff --git a/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsComponent.kt b/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsComponent.kt new file mode 100644 index 0000000000..515492abe3 --- /dev/null +++ b/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/PushNotificationsComponent.kt @@ -0,0 +1,9 @@ +package com.tangem.features.pushnotifications.api + +import com.tangem.core.decompose.factory.ComponentFactory +import com.tangem.core.ui.decompose.ComposableContentComponent + +interface PushNotificationsComponent : ComposableContentComponent { + + interface Factory : ComponentFactory +} \ No newline at end of file diff --git a/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/navigation/PushNotificationsRouter.kt b/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/navigation/PushNotificationsRouter.kt deleted file mode 100644 index 6881437671..0000000000 --- a/features/push-notifications/api/src/main/java/com/tangem/features/pushnotifications/api/navigation/PushNotificationsRouter.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.features.pushnotifications.api.navigation - -import androidx.fragment.app.Fragment - -interface PushNotificationsRouter { - - fun entryFragment(): Fragment -} \ No newline at end of file diff --git a/features/push-notifications/impl/build.gradle.kts b/features/push-notifications/impl/build.gradle.kts index de3b57819b..184fccb455 100644 --- a/features/push-notifications/impl/build.gradle.kts +++ b/features/push-notifications/impl/build.gradle.kts @@ -26,6 +26,7 @@ dependencies { implementation(deps.kotlin.immutable.collections) /** Core modules */ + implementation(projects.core.decompose) implementation(projects.core.ui) implementation(projects.core.configToggles) implementation(projects.core.navigation) diff --git a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/DefaultPushNotificationsComponent.kt b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/DefaultPushNotificationsComponent.kt new file mode 100644 index 0000000000..d2ba519029 --- /dev/null +++ b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/DefaultPushNotificationsComponent.kt @@ -0,0 +1,42 @@ +package com.tangem.features.pushnotifications.impl + +import androidx.activity.compose.BackHandler +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.decompose.model.getOrCreateModel +import com.tangem.core.ui.components.NavigationBar3ButtonsScrim +import com.tangem.core.ui.utils.findActivity +import com.tangem.features.pushnotifications.api.PushNotificationsComponent +import com.tangem.features.pushnotifications.impl.model.PushNotificationsModel +import com.tangem.features.pushnotifications.impl.presentation.ui.PushNotificationsScreen +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +internal class DefaultPushNotificationsComponent @AssistedInject constructor( + @Assisted appComponentContext: AppComponentContext, + @Assisted params: Unit, +) : PushNotificationsComponent, AppComponentContext by appComponentContext { + + private val model: PushNotificationsModel = getOrCreateModel(params) + + @Composable + override fun Content(modifier: Modifier) { + val activity = LocalContext.current.findActivity() + BackHandler(onBack = { activity.finish() }) + NavigationBar3ButtonsScrim() + PushNotificationsScreen( + onRequest = model::onRequest, + onNeverRequest = model::onNeverRequest, + onAllowPermission = model::onAllowPermission, + onDenyPermission = model::onDenyPermission, + ) + } + + @AssistedFactory + interface Factory : PushNotificationsComponent.Factory { + override fun create(context: AppComponentContext, params: Unit): DefaultPushNotificationsComponent + } +} \ No newline at end of file diff --git a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/PushNotificationsFragment.kt b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/PushNotificationsFragment.kt deleted file mode 100644 index c7110e411f..0000000000 --- a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/PushNotificationsFragment.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.tangem.features.pushnotifications.impl - -import androidx.activity.compose.BackHandler -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.fragment.app.viewModels -import com.tangem.core.ui.UiDependencies -import com.tangem.core.ui.components.NavigationBar3ButtonsScrim -import com.tangem.core.ui.screen.ComposeFragment -import com.tangem.features.pushnotifications.impl.presentation.ui.PushNotificationsScreen -import com.tangem.features.pushnotifications.impl.presentation.viewmodel.PushNotificationViewModel -import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject - -@AndroidEntryPoint -internal class PushNotificationsFragment : ComposeFragment() { - - @Inject - override lateinit var uiDependencies: UiDependencies - - private val viewModel by viewModels() - - @Composable - override fun ScreenContent(modifier: Modifier) { - BackHandler(onBack = requireActivity()::finish) - NavigationBar3ButtonsScrim() - PushNotificationsScreen( - onRequest = viewModel::onRequest, - onNeverRequest = viewModel::onNeverRequest, - onAllowPermission = viewModel::onAllowPermission, - onDenyPermission = viewModel::onDenyPermission, - ) - } - - companion object { - /** Create push notifications fragment instance */ - fun create(): PushNotificationsFragment = PushNotificationsFragment() - } -} \ No newline at end of file diff --git a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/di/PushNotificationsModule.kt b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/di/PushNotificationsModule.kt index b568880483..edbd3dc188 100644 --- a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/di/PushNotificationsModule.kt +++ b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/di/PushNotificationsModule.kt @@ -1,24 +1,25 @@ package com.tangem.features.pushnotifications.impl.di -import com.tangem.common.routing.AppRouter -import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter -import com.tangem.features.pushnotifications.impl.navigation.DefaultPushNotificationsRouter +import com.tangem.core.decompose.model.Model +import com.tangem.features.pushnotifications.api.PushNotificationsComponent +import com.tangem.features.pushnotifications.impl.DefaultPushNotificationsComponent +import com.tangem.features.pushnotifications.impl.model.PushNotificationsModel +import dagger.Binds import dagger.Module -import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.components.ActivityComponent -import dagger.hilt.android.scopes.ActivityScoped +import dagger.hilt.components.SingletonComponent +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap -/** - * DI module provides implementation of [PushNotificationsRouter] - */ @Module -@InstallIn(ActivityComponent::class) -object PushNotificationsModule { +@InstallIn(SingletonComponent::class) +internal interface PushNotificationsModule { - @Provides - @ActivityScoped - fun provideDisclaimerRouter(appRouter: AppRouter): PushNotificationsRouter { - return DefaultPushNotificationsRouter(appRouter) - } + @Binds + fun bindComponentFactory(impl: DefaultPushNotificationsComponent.Factory): PushNotificationsComponent.Factory + + @Binds + @IntoMap + @ClassKey(PushNotificationsModel::class) + fun bindModel(model: PushNotificationsModel): Model } \ No newline at end of file diff --git a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/presentation/viewmodel/PushNotificationsClickIntents.kt b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsClickIntents.kt similarity index 67% rename from features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/presentation/viewmodel/PushNotificationsClickIntents.kt rename to features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsClickIntents.kt index 63100190b7..99b02a379c 100644 --- a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/presentation/viewmodel/PushNotificationsClickIntents.kt +++ b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsClickIntents.kt @@ -1,4 +1,4 @@ -package com.tangem.features.pushnotifications.impl.presentation.viewmodel +package com.tangem.features.pushnotifications.impl.model internal interface PushNotificationsClickIntents { fun onRequest() diff --git a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/presentation/viewmodel/PushNotificationViewModel.kt b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsModel.kt similarity index 69% rename from features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/presentation/viewmodel/PushNotificationViewModel.kt rename to features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsModel.kt index b760936b5b..4043db3350 100644 --- a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/presentation/viewmodel/PushNotificationViewModel.kt +++ b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsModel.kt @@ -1,26 +1,29 @@ -package com.tangem.features.pushnotifications.impl.presentation.viewmodel +package com.tangem.features.pushnotifications.impl.model -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope +import androidx.compose.runtime.Stable +import com.tangem.common.routing.AppRoute +import com.tangem.common.routing.AppRouter import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.model.Model import com.tangem.domain.settings.NeverRequestPermissionUseCase import com.tangem.domain.settings.NeverToInitiallyAskPermissionUseCase import com.tangem.features.pushnotifications.api.analytics.PushNotificationAnalyticEvents import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION -import com.tangem.features.pushnotifications.impl.navigation.DefaultPushNotificationsRouter -import dagger.hilt.android.lifecycle.HiltViewModel +import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.launch import javax.inject.Inject -@Suppress("LongParameterList") -@HiltViewModel -internal class PushNotificationViewModel @Inject constructor( +@Stable +@ComponentScoped +class PushNotificationsModel @Inject constructor( + override val dispatchers: CoroutineDispatcherProvider, private val neverRequestPermissionUseCase: NeverRequestPermissionUseCase, private val neverToInitiallyAskPermissionUseCase: NeverToInitiallyAskPermissionUseCase, - private val router: DefaultPushNotificationsRouter, + private val appRouter: AppRouter, private val analyticHandler: AnalyticsEventHandler, -) : ViewModel(), PushNotificationsClickIntents { +) : Model(), PushNotificationsClickIntents { override fun onRequest() { analyticHandler.send( @@ -32,10 +35,10 @@ internal class PushNotificationViewModel @Inject constructor( analyticHandler.send( PushNotificationAnalyticEvents.ButtonLater(AnalyticsParam.ScreensSources.Stories), ) - viewModelScope.launch { + modelScope.launch { neverRequestPermissionUseCase(PUSH_PERMISSION) neverToInitiallyAskPermissionUseCase(PUSH_PERMISSION) - router.openHome() + appRouter.push(AppRoute.Home) } } @@ -43,10 +46,10 @@ internal class PushNotificationViewModel @Inject constructor( analyticHandler.send( PushNotificationAnalyticEvents.PermissionStatus(isAllowed = true), ) - viewModelScope.launch { + modelScope.launch { neverRequestPermissionUseCase(PUSH_PERMISSION) neverToInitiallyAskPermissionUseCase(PUSH_PERMISSION) - router.openHome() + appRouter.push(AppRoute.Home) } } @@ -54,10 +57,10 @@ internal class PushNotificationViewModel @Inject constructor( analyticHandler.send( PushNotificationAnalyticEvents.PermissionStatus(isAllowed = false), ) - viewModelScope.launch { + modelScope.launch { neverRequestPermissionUseCase(PUSH_PERMISSION) neverToInitiallyAskPermissionUseCase(PUSH_PERMISSION) - router.openHome() + appRouter.push(AppRoute.Home) } } } \ No newline at end of file diff --git a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/navigation/DefaultPushNotificationsRouter.kt b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/navigation/DefaultPushNotificationsRouter.kt deleted file mode 100644 index b2536cfe47..0000000000 --- a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/navigation/DefaultPushNotificationsRouter.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.tangem.features.pushnotifications.impl.navigation - -import androidx.fragment.app.Fragment -import com.tangem.common.routing.AppRoute -import com.tangem.common.routing.AppRouter -import com.tangem.features.pushnotifications.impl.PushNotificationsFragment -import javax.inject.Inject - -internal class DefaultPushNotificationsRouter @Inject constructor( - private val appRouter: AppRouter, -) : InnerPushNotificationsRouter { - - override fun entryFragment(): Fragment = PushNotificationsFragment.create() - - override fun openHome() { - appRouter.push(AppRoute.Home) - } -} \ No newline at end of file diff --git a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/navigation/InnerPushNotificationsRouter.kt b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/navigation/InnerPushNotificationsRouter.kt deleted file mode 100644 index 20050eca1e..0000000000 --- a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/navigation/InnerPushNotificationsRouter.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.features.pushnotifications.impl.navigation - -import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter - -interface InnerPushNotificationsRouter : PushNotificationsRouter { - - fun openHome() -} \ No newline at end of file From 43975742d55b04f4da731f598d07a7fa58f1fa6d Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 24 Feb 2025 16:13:32 +0500 Subject: [PATCH 31/54] Updated on 2026-08-14 --- .../NavigationButtonsState.kt | 2 +- .../data/staking/DefaultStakingRepository.kt | 9 +++-- .../action/StakingActionCommonType.kt | 2 +- .../analytics/utils/StakingAnalyticSender.kt | 2 +- .../impl/presentation/model/StakingModel.kt | 4 +-- .../state/StakingStateController.kt | 2 +- .../presentation/state/StakingStateRouter.kt | 14 ++++---- .../helpers/StakingFeeTransactionLoader.kt | 2 +- .../state/helpers/StakingTransactionSender.kt | 2 +- .../transformers/SetAmountDataTransformer.kt | 2 +- .../SetButtonsStateTransformer.kt | 17 ++++++--- .../SetConfirmationStateEmptyTransformer.kt | 2 +- .../SetConfirmationStateInitTransformer.kt | 22 ++++++++---- .../SetConfirmationStateLoadingTransformer.kt | 16 +++++---- .../state/transformers/SetTitleTransformer.kt | 4 +-- .../AmountRequirementStateTransformer.kt | 36 +++++++++++++------ .../AddStakingNotificationsTransformer.kt | 4 +-- .../StakingInfoNotificationsFactory.kt | 2 +- .../ValidatorSelectChangeTransformer.kt | 2 +- 19 files changed, 93 insertions(+), 53 deletions(-) diff --git a/common/ui/src/main/java/com/tangem/common/ui/navigationButtons/NavigationButtonsState.kt b/common/ui/src/main/java/com/tangem/common/ui/navigationButtons/NavigationButtonsState.kt index c534f12308..e7788a87df 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/navigationButtons/NavigationButtonsState.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/navigationButtons/NavigationButtonsState.kt @@ -8,7 +8,7 @@ sealed class NavigationButtonsState { data object Empty : NavigationButtonsState() data class Data( - val primaryButton: NavigationButton, + val primaryButton: NavigationButton?, val prevButton: NavigationButton?, val extraButtons: ImmutableList, val txUrl: String? = null, diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt index 620bad0ce9..25634c3787 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt @@ -237,7 +237,7 @@ internal class DefaultStakingRepository( ): StakingAction { return withContext(dispatchers.io) { val response = when (params.actionCommonType) { - StakingActionCommonType.Enter -> stakeKitApi.createEnterAction( + is StakingActionCommonType.Enter -> stakeKitApi.createEnterAction( createActionRequestBody( userWalletId, network, @@ -267,7 +267,7 @@ internal class DefaultStakingRepository( ): StakingGasEstimate { return withContext(dispatchers.io) { val gasEstimateDTO = when (params.actionCommonType) { - StakingActionCommonType.Enter -> stakeKitApi.estimateGasOnEnter( + is StakingActionCommonType.Enter -> stakeKitApi.estimateGasOnEnter( createActionRequestBody( userWalletId, network, @@ -582,13 +582,14 @@ internal class DefaultStakingRepository( -> TransactionData.Compiled.Data.Bytes(unsignedTransaction.hexToBytes()) Blockchain.BSC, Blockchain.Ethereum, + Blockchain.TON, + Blockchain.Cardano, -> TransactionData.Compiled.Data.RawString(unsignedTransaction) Blockchain.Tron -> { val tronStakeKitTransaction = tronStakeKitTransactionAdapter.fromJson(unsignedTransaction) ?: error("Failed to parse Tron StakeKit transaction") TransactionData.Compiled.Data.RawString(tronStakeKitTransaction.rawDataHex) } - Blockchain.TON -> TransactionData.Compiled.Data.RawString(unsignedTransaction) else -> error("Unsupported blockchain") } } @@ -647,6 +648,7 @@ internal class DefaultStakingRepository( const val KAVA_INTEGRATION_ID = "kava-kava-native-staking" const val NEAR_INTEGRATION_ID = "near-near-native-staking" const val TEZOS_INTEGRATION_ID = "tezos-xtz-native-staking" + const val CARDANO_INTEGRATION_ID = "cardano-ada-native-staking" const val ETHEREUM_POLYGON_APPROVE_SPENDER = "0x5e3Ef299fDDf15eAa0432E6e66473ace8c13D908" @@ -669,6 +671,7 @@ internal class DefaultStakingRepository( // Blockchain.Kava.run { id + toCoinId() } to KAVA_INTEGRATION_ID, // Blockchain.Near.run { id + toCoinId() } to NEAR_INTEGRATION_ID, // Blockchain.Tezos.run { id + toCoinId() } to TEZOS_INTEGRATION_ID, + Blockchain.Cardano.run { id + toCoinId() } to CARDANO_INTEGRATION_ID, ) } } \ No newline at end of file diff --git a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/action/StakingActionCommonType.kt b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/action/StakingActionCommonType.kt index 120dfd0c18..605393dfb4 100644 --- a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/action/StakingActionCommonType.kt +++ b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/action/StakingActionCommonType.kt @@ -2,7 +2,7 @@ package com.tangem.domain.staking.model.stakekit.action sealed class StakingActionCommonType { - data object Enter : StakingActionCommonType() + data class Enter(val skipEnterAmount: Boolean) : StakingActionCommonType() data class Exit(val partiallyUnstakeDisabled: Boolean) : StakingActionCommonType() sealed class Pending : StakingActionCommonType() { data object Restake : Pending() diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/analytics/utils/StakingAnalyticSender.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/analytics/utils/StakingAnalyticSender.kt index fdc4685953..e5911ef720 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/analytics/utils/StakingAnalyticSender.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/analytics/utils/StakingAnalyticSender.kt @@ -113,7 +113,7 @@ internal class StakingAnalyticSender( val confirmationState = value.confirmationState as? StakingStates.ConfirmationState.Data return when (value.actionType) { - StakingActionCommonType.Enter -> StakingActionType.STAKE + is StakingActionCommonType.Enter -> StakingActionType.STAKE is StakingActionCommonType.Exit -> StakingActionType.UNSTAKE is StakingActionCommonType.Pending -> confirmationState?.pendingAction?.type ?: StakingActionType.UNKNOWN } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt index bb2c07e2c4..846032569e 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt @@ -397,7 +397,7 @@ internal class StakingModel @Inject constructor( StakingEvent.ShowAlert(StakingAlertUM.NoAvailableValidators), ) } else { - if (uiState.value.actionType == StakingActionCommonType.Enter) { + if (uiState.value.actionType is StakingActionCommonType.Enter) { stateController.updateAll( ValidatorSelectChangeTransformer( selectedValidator = null, @@ -712,7 +712,7 @@ internal class StakingModel @Inject constructor( ): BigDecimal? { // TODO split for different networks val subtractedBalanceAmount = when (actionType) { - StakingActionCommonType.Enter -> checkAndCalculateSubtractedAmount( + is StakingActionCommonType.Enter -> checkAndCalculateSubtractedAmount( isAmountSubtractAvailable = isAmountSubtractAvailable, cryptoCurrencyStatus = cryptoCurrencyStatus, amountValue = amount.orZero(), diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt index e66c38a778..328bf590dd 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt @@ -85,7 +85,7 @@ internal class StakingStateController @Inject constructor( isBalanceHidden = false, event = consumedEvent(), bottomSheetConfig = null, - actionType = StakingActionCommonType.Enter, + actionType = StakingActionCommonType.Enter(skipEnterAmount = false), buttonsState = NavigationButtonsState.Empty, balanceState = null, ) diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt index 60afd5cfef..622c27808f 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt @@ -23,11 +23,11 @@ internal class StakingStateRouter( fun onNextClick() { when (stateController.value.currentStep) { StakingStep.InitialInfo -> when (val actionType = stateController.value.actionType) { - StakingActionCommonType.Enter -> showAmount() - is StakingActionCommonType.Exit -> if (actionType.partiallyUnstakeDisabled) { - showConfirmation() - } else { - showAmount() + is StakingActionCommonType.Enter -> { + if (actionType.skipEnterAmount) showConfirmation() else showAmount() + } + is StakingActionCommonType.Exit -> { + if (actionType.partiallyUnstakeDisabled) showConfirmation() else showAmount() } StakingActionCommonType.Pending.Other, StakingActionCommonType.Pending.Rewards, @@ -53,7 +53,9 @@ internal class StakingStateRouter( -> showInitial() StakingStep.Confirmation -> { when (val actionType = uiState.actionType) { - StakingActionCommonType.Enter -> showAmount() + is StakingActionCommonType.Enter -> { + if (actionType.skipEnterAmount) showInitial() else showAmount() + } is StakingActionCommonType.Pending -> showInitial() is StakingActionCommonType.Exit -> { if (actionType.partiallyUnstakeDisabled) showInitial() else showAmount() diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingFeeTransactionLoader.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingFeeTransactionLoader.kt index 6ed1669b40..1688f31bdf 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingFeeTransactionLoader.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingFeeTransactionLoader.kt @@ -63,7 +63,7 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor( val validatorAddress = validatorState.chosenValidator.address - val isEnter = state.actionType == StakingActionCommonType.Enter + val isEnter = state.actionType is StakingActionCommonType.Enter val isApprovalNeeded = confirmationState.isApprovalNeeded val isAllowanceNotEnough = confirmationState.allowance < amount if (isEnter && isApprovalNeeded && isAllowanceNotEnough) { diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingTransactionSender.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingTransactionSender.kt index cc4b4686a5..2810a6d3c3 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingTransactionSender.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingTransactionSender.kt @@ -280,7 +280,7 @@ internal class StakingTransactionSender @AssistedInject constructor( private fun getAmount(amountState: AmountState.Data, fee: Fee, reduceAmountBy: BigDecimal?): BigDecimal { val amountValue = amountState.amountTextField.cryptoAmount.value ?: error("No amount value") val feeValue = fee.amount.value ?: error("No fee value") - val isEnterAction = stateController.value.actionType == StakingActionCommonType.Enter + val isEnterAction = stateController.value.actionType is StakingActionCommonType.Enter return checkAndCalculateSubtractedAmount( isAmountSubtractAvailable = isAmountSubtractAvailable && isEnterAction, diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetAmountDataTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetAmountDataTransformer.kt index d33a64975d..4103633ad5 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetAmountDataTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetAmountDataTransformer.kt @@ -32,7 +32,7 @@ internal class SetAmountDataTransformer( stringReference(userWalletProvider().name) } val cryptoBalanceValue = cryptoCurrencyStatusProvider().value - val (amount, fiatAmount) = if (prevState.actionType != StakingActionCommonType.Enter) { + val (amount, fiatAmount) = if (prevState.actionType !is StakingActionCommonType.Enter) { prevState.balanceState?.cryptoAmount to prevState.balanceState?.fiatAmount } else { cryptoBalanceValue.amount to cryptoBalanceValue.fiatAmount diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetButtonsStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetButtonsStateTransformer.kt index 61eb924114..6195aea430 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetButtonsStateTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetButtonsStateTransformer.kt @@ -10,6 +10,7 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType import com.tangem.features.staking.impl.presentation.state.* import com.tangem.features.staking.impl.presentation.state.utils.getPendingActionTitle +import com.tangem.lib.crypto.BlockchainUtils import com.tangem.utils.extensions.orZero import com.tangem.utils.transformer.Transformer import kotlinx.collections.immutable.ImmutableList @@ -37,7 +38,7 @@ internal class SetButtonsStateTransformer( return prevState.copy(buttonsState = buttonsState) } - private fun getPrimaryButton(prevState: StakingUiState): NavigationButton { + private fun getPrimaryButton(prevState: StakingUiState): NavigationButton? { val confirmState = prevState.confirmationState as? StakingStates.ConfirmationState.Data val innerConfirmState = confirmState?.innerState @@ -54,7 +55,7 @@ internal class SetButtonsStateTransformer( showProgress = isInProgress, isEnabled = prevState.isButtonEnabled(), onClick = { prevState.onPrimaryClick() }, - ) + ).takeIf { prevState.isPrimaryButtonVisible() } } private fun getPrevButton(prevState: StakingUiState): NavigationButton? { @@ -125,7 +126,7 @@ internal class SetButtonsStateTransformer( resourceReference(R.string.common_close) } else { when (actionType) { - StakingActionCommonType.Enter -> { + is StakingActionCommonType.Enter -> { val amount = amountState.amountTextField.cryptoAmount.value.orZero() if (confirmationState.isApprovalNeeded && confirmationState.allowance < amount) { resourceReference(R.string.give_permission_title) @@ -162,7 +163,7 @@ internal class SetButtonsStateTransformer( clickIntents.onNextClick() } else { val amount = amountState.amountTextField.cryptoAmount.value.orZero() - val isEnterAction = actionType == StakingActionCommonType.Enter + val isEnterAction = actionType is StakingActionCommonType.Enter if (isEnterAction && confirmationState.isApprovalNeeded && confirmationState.allowance < amount) { clickIntents.showApprovalBottomSheet() } else { @@ -185,6 +186,14 @@ internal class SetButtonsStateTransformer( -> true } + private fun StakingUiState.isPrimaryButtonVisible(): Boolean { + val initialState = initialInfoState as? StakingStates.InitialInfoState.Data + val hasNotStaking = initialState?.yieldBalance == InnerYieldBalanceState.Empty + val isCardano = BlockchainUtils.isCardano(cryptoCurrencyBlockchainId) + + return hasNotStaking || !(isCardano && currentStep == StakingStep.InitialInfo) + } + private fun StakingUiState.isButtonEnabled(): Boolean { return when (currentStep) { StakingStep.InitialInfo -> initialInfoState.isPrimaryButtonEnabled diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateEmptyTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateEmptyTransformer.kt index 4bf8d5ce5d..c1ab24e015 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateEmptyTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateEmptyTransformer.kt @@ -8,7 +8,7 @@ import com.tangem.utils.transformer.Transformer internal object SetConfirmationStateEmptyTransformer : Transformer { override fun transform(prevState: StakingUiState): StakingUiState { return prevState.copy( - actionType = StakingActionCommonType.Enter, + actionType = StakingActionCommonType.Enter(skipEnterAmount = false), validatorState = StakingStates.ValidatorState.Empty(), confirmationState = StakingStates.ConfirmationState.Empty(), balanceState = null, diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt index c55fb7a485..8a2f781acc 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt @@ -44,11 +44,17 @@ internal class SetConfirmationStateInitTransformer( override fun transform(prevState: StakingUiState): StakingUiState { val actionType = when { - isEnter -> StakingActionCommonType.Enter - isImplicitExit || isExplicitExit -> StakingActionCommonType.Exit(isPartialUnstakeDisabled(prevState)) + isEnter -> StakingActionCommonType.Enter( + skipEnterAmount = isAmountEnterSkipped(prevState), + ) + isImplicitExit || isExplicitExit -> StakingActionCommonType.Exit(isPartiallyUnstakeDisabled(prevState)) else -> when (pendingAction?.type) { - StakingActionType.STAKE -> StakingActionCommonType.Enter - StakingActionType.UNSTAKE -> StakingActionCommonType.Exit(isPartialUnstakeDisabled(prevState)) + StakingActionType.STAKE -> StakingActionCommonType.Enter( + skipEnterAmount = isAmountEnterSkipped(prevState), + ) + StakingActionType.UNSTAKE -> StakingActionCommonType.Exit( + partiallyUnstakeDisabled = isPartiallyUnstakeDisabled(prevState), + ) StakingActionType.CLAIM_REWARDS, StakingActionType.RESTAKE_REWARDS, -> StakingActionCommonType.Pending.Rewards @@ -71,7 +77,7 @@ internal class SetConfirmationStateInitTransformer( transactionDoneState = TransactionDoneState.Empty, isApprovalNeeded = stakingApproval is StakingApproval.Needed, allowance = stakingAllowance, - isAmountEditable = actionType == StakingActionCommonType.Enter || + isAmountEditable = actionType is StakingActionCommonType.Enter || actionType is StakingActionCommonType.Exit && !actionType.partiallyUnstakeDisabled, reduceAmountBy = null, @@ -81,7 +87,7 @@ internal class SetConfirmationStateInitTransformer( ) } - private fun isPartialUnstakeDisabled(state: StakingUiState): Boolean { + private fun isPartiallyUnstakeDisabled(state: StakingUiState): Boolean { val isSolana = BlockchainUtils.isSolana(state.cryptoCurrencyBlockchainId) val isValidatorPreferred = balanceState?.validator?.preferred == true if (isSolana && !isValidatorPreferred) { @@ -94,4 +100,8 @@ internal class SetConfirmationStateInitTransformer( val max = exitAmount.maximum ?: return false return !min.isPositive() && !max.isPositive() } + + private fun isAmountEnterSkipped(state: StakingUiState): Boolean { + return BlockchainUtils.isCardano(state.cryptoCurrencyBlockchainId) + } } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateLoadingTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateLoadingTransformer.kt index 723a0ffd7c..30fd4ad88e 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateLoadingTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateLoadingTransformer.kt @@ -4,7 +4,8 @@ import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList -import com.tangem.core.ui.utils.BigDecimalFormatter +import com.tangem.core.ui.format.bigdecimal.fiat +import com.tangem.core.ui.format.bigdecimal.format import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.staking.model.stakekit.Yield import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType @@ -35,14 +36,15 @@ internal class SetConfirmationStateLoadingTransformer( private fun getFooter(state: StakingUiState): TextReference { val amountState = state.amountState as? AmountState.Data - val isEnterAction = state.actionType == StakingActionCommonType.Enter + val isEnterAction = state.actionType is StakingActionCommonType.Enter val amountDecimal = amountState?.amountTextField?.fiatAmount?.value - val amountValue = BigDecimalFormatter.formatFiatAmount( - fiatAmount = amountDecimal, - fiatCurrencyCode = appCurrency.code, - fiatCurrencySymbol = appCurrency.symbol, - ) + val amountValue = amountDecimal.format { + fiat( + fiatCurrencyCode = appCurrency.code, + fiatCurrencySymbol = appCurrency.symbol, + ) + } val rewardSchedule = getRewardScheduleText( rewardSchedule = yield.metadata.rewardSchedule, networkId = cryptoCurrency.network.id.value, diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetTitleTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetTitleTransformer.kt index 46258e60a7..d16bb669e4 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetTitleTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetTitleTransformer.kt @@ -31,7 +31,7 @@ internal object SetTitleTransformer : Transformer { StakingStep.Confirmation -> { when (actionType) { - StakingActionCommonType.Enter -> resourceReference( + is StakingActionCommonType.Enter -> resourceReference( R.string.staking_title_stake, wrappedList(prevState.cryptoCurrencyName), ) @@ -53,7 +53,7 @@ internal object SetTitleTransformer : Transformer { } } - val subtitle = if (currentStep == StakingStep.Confirmation && actionType == StakingActionCommonType.Enter) { + val subtitle = if (currentStep == StakingStep.Confirmation && actionType is StakingActionCommonType.Enter) { stringReference(prevState.walletName) } else { null diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountRequirementStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountRequirementStateTransformer.kt index 655b39d571..10e96e7b32 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountRequirementStateTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountRequirementStateTransformer.kt @@ -16,6 +16,7 @@ import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.features.staking.impl.R import com.tangem.lib.crypto.BlockchainUtils.isTron +import com.tangem.utils.extensions.isPositive import com.tangem.utils.isNullOrZero import com.tangem.utils.transformer.Transformer import java.math.BigDecimal @@ -57,7 +58,7 @@ internal class AmountRequirementStateTransformer( amountState.amountTextField.isError -> amountState.amountTextField.error requirementError != null -> requirementError isIntegerOnlyError -> when (actionType) { - StakingActionCommonType.Enter -> resourceReference( + is StakingActionCommonType.Enter -> resourceReference( R.string.staking_amount_tron_integer_error, wrappedList(roundedDownCrypto), ) @@ -92,7 +93,7 @@ internal class AmountRequirementStateTransformer( if (isAlreadyErrorState || isAmountZero) return null return when (actionType) { - StakingActionCommonType.Enter -> { + is StakingActionCommonType.Enter -> { val enterRequirements = yield.args.enter.args[Yield.Args.ArgType.AMOUNT] enterRequirements?.getError(amountDecimal, R.string.staking_amount_requirement_error) } @@ -107,7 +108,7 @@ internal class AmountRequirementStateTransformer( private fun isIntegerOnlyError(amountState: AmountState.Data, actionType: StakingActionCommonType): Boolean { val cryptoAmountValue = amountState.amountTextField.cryptoAmount.value ?: return false - val isEnterOrExit = actionType == StakingActionCommonType.Enter || actionType is StakingActionCommonType.Exit + val isEnterOrExit = actionType is StakingActionCommonType.Enter || actionType is StakingActionCommonType.Exit val isTron = isTron(cryptoCurrencyStatus.currency.network.id.value) val isIntegerOnly = cryptoAmountValue.isZero() || cryptoAmountValue.remainder(BigDecimal.ONE).isZero() @@ -116,17 +117,30 @@ internal class AmountRequirementStateTransformer( } private fun AddressArgument.getError(amount: BigDecimal, @StringRes errorTextRes: Int): TextReference? { - val isExceedsRequirements = maximum?.compareTo(amount) == -1 || - minimum?.compareTo(amount) == 1 + val isExceedsMinRequirement = minimum?.compareTo(amount) == 1 + val isExceedsMaxRequirement = if (maximum?.isPositive() == true) { + maximum?.compareTo(amount) == -1 + } else { + cryptoCurrencyStatus.value.amount?.compareTo(amount) == 1 + } - return resourceReference( - errorTextRes, - wrappedList( + val errorText = when { + isExceedsMinRequirement -> { minimum.format { crypto(cryptoCurrencyStatus.currency) - }, - ), - ).takeIf { required && isExceedsRequirements } + } + } + isExceedsMaxRequirement -> { + maximum.format { + crypto(cryptoCurrencyStatus.currency) + } + } + else -> "" + } + return resourceReference( + errorTextRes, + wrappedList(errorText), + ).takeIf { required && (isExceedsMinRequirement || isExceedsMaxRequirement) } } data class Data( diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt index 6aeb94cc74..7e8f2c875d 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt @@ -65,7 +65,7 @@ internal class AddStakingNotificationsTransformer( val feeValue = feeState?.fee?.amount?.value.orZero() val reduceAmountBy = confirmationState.reduceAmountBy.orZero() - val isEnterAction = prevState.actionType == StakingActionCommonType.Enter + val isEnterAction = prevState.actionType is StakingActionCommonType.Enter val isFeeCoverage = checkFeeCoverage( amountValue = amountValue, feeValue = feeValue, @@ -236,7 +236,7 @@ internal class AddStakingNotificationsTransformer( val showNotification = sendingAmount + feeAmount > balance if (showNotification) { - val notification = if (actionType == StakingActionCommonType.Enter) { + val notification = if (actionType is StakingActionCommonType.Enter) { NotificationUM.Error.TotalExceedsBalance } else { with(cryptoCurrencyStatus.currency) { diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/StakingInfoNotificationsFactory.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/StakingInfoNotificationsFactory.kt index aed53b2408..a88e7ace69 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/StakingInfoNotificationsFactory.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/StakingInfoNotificationsFactory.kt @@ -44,7 +44,7 @@ internal class StakingInfoNotificationsFactory( addStakingLowBalanceNotification(prevState, actionAmount) when (prevState.actionType) { - StakingActionCommonType.Enter -> addEnterInfoNotifications(sendingAmount, feeValue) + is StakingActionCommonType.Enter -> addEnterInfoNotifications(sendingAmount, feeValue) is StakingActionCommonType.Exit -> addExitInfoNotifications() is StakingActionCommonType.Pending -> addPendingInfoNotifications(prevState) } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/validator/ValidatorSelectChangeTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/validator/ValidatorSelectChangeTransformer.kt index 0f79a3ab26..960c928ca8 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/validator/ValidatorSelectChangeTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/validator/ValidatorSelectChangeTransformer.kt @@ -18,7 +18,7 @@ internal class ValidatorSelectChangeTransformer( val confirmationState = prevState.confirmationState as? StakingStates.ConfirmationState.Data val isRestake = prevState.actionType == StakingActionCommonType.Pending.Restake - val isEnter = prevState.actionType == StakingActionCommonType.Enter + val isEnter = prevState.actionType is StakingActionCommonType.Enter val isFromInfoScreen = prevState.currentStep == StakingStep.InitialInfo val isVoteLocked = confirmationState?.pendingAction?.type == StakingActionType.VOTE_LOCKED From 52996292213d26c08a3732121b3f64cd1bc5496a Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 26 Feb 2025 11:46:02 +0300 Subject: [PATCH 32/54] Updated on 2026-08-14 --- core/res/src/main/res/values-ru/strings.xml | 4 ++++ core/res/src/main/res/values/strings.xml | 7 +++++- .../data/visa/utils/VisaApiRequestMaker.kt | 5 ++++ .../utils/WalletWarningsAnalyticsSender.kt | 1 + .../wallet/state/model/WalletNotification.kt | 13 +++++++++++ .../wallet/state/model/WalletState.kt | 23 +++++++++++++++++++ .../CloseBottomSheetTransformer.kt | 3 +++ .../OpenBottomSheetTransformer.kt | 3 +++ .../transformers/RenameWalletsTransformer.kt | 1 + .../SetBalancesAndLimitsTransformer.kt | 15 ++++++++++++ .../SetRefreshStateTransformer.kt | 1 + .../SetTxHistoryCountErrorTransformer.kt | 1 + .../SetTxHistoryCountTransformer.kt | 1 + .../SetTxHistoryItemsErrorTransformer.kt | 18 ++++++++++++++- .../SetTxHistoryItemsTransformer.kt | 1 + .../SetWalletCardDropDownItemsTransformer.kt | 5 ++++ .../transformers/SetWarningsTransformer.kt | 1 + .../transformers/UnlockWalletTransformer.kt | 3 ++- .../UpdateWalletCardsCountTransformer.kt | 1 + .../viewmodels/intents/WalletClickIntents.kt | 1 + .../intents/WalletWarningsClickIntents.kt | 6 +++++ 21 files changed, 111 insertions(+), 3 deletions(-) diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 04c5129fac..e7e9bccc89 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -694,6 +694,7 @@ Отсканируйте карту или кольцо, чтобы изменить ее настройки. Изменения затронут только ту карту или кольцо, которые вы отсканировали, и не повлияют на другие устройства, привязанные к вашему кошельку. Приготовьте свой Tangem! Уведомление безопасности + Да На вашем балансе недостаточно средств для продажи криптовалюты. Пожалуйста, пополните нужный актив, чтобы продолжить. Недостаточно средств Продажа криптовалюты в вашем регионе временно недоступна. Мы активно работаем над тем, чтобы добавить эту возможность. Следите за нашими новостями! @@ -897,6 +898,8 @@ Встречайте Tangem Обменивайте, покупайте NFT, получайте займы и делайте вклады в более чем 100 различных децентрализованных сервисах Поддержка Web 3.0 + Для отправки требуется входящая транзакция на сумму не менее %1$s + Недостаточно средств Комиссия сети за одобрение токена будет взиматься за подтверждение того, что именно вы разрешаете использовать ваш токен для обмена. Обменивайте больше токенов по лучшим курсам прямо в вашем кошельке. Новый провайдер обмена! @@ -1110,6 +1113,7 @@ Нравится Tangem? Вам необходимо провести ассоциацию токена для того, чтобы иметь возможность принимать его Необходима плата за аренду сети + Вы обращались в службу поддержки через приложение в течение 7 дней после создания кошелька? Если обращались или не уверены, нажмите «Да» и следуйте инструкциям. Спасибо! Всё в порядке! Дальнейшие действия не требуются. Вы будете перенаправлены на официальный сайт Tangem. Пожалуйста, прочитайте и выполните указанные там инструкции. Вы когда-либо обращались в службу поддержки Tangem напрямую из этого приложения? diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 15e6dcf94d..8efdb73f1b 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -886,6 +886,8 @@ Meet Tangem Exchange, buy NFT\'s, make loans and deposits in more than 100 different decentralized services Web 3.0 Compatible + An incoming transaction of at least %1$s is required to proceed + Insufficient funds The network will charge a token approval fee to verify that you are authorizing the use of your token for the swap. Exchange more tokens at better rates directly in your wallet. New Swap Provider Available! @@ -985,6 +987,9 @@ Rename wallet Unlock all Unlock all with %s + Unlock + Scan your card to unlock access + Needed unlock Blockchain is unreachable. Try later Scan card or ring This wallet has already been activated earlier.\nIf it was not done by you, please contact support.\nTangem never sells wallets along with pre-generated access codes. @@ -1099,7 +1104,7 @@ You must associate your token before receiving tokens Network rent fee required Action required - Did you contact support via the app or email within 7 days of creating a wallet? If you did or are unsure, follow and complete the instructions. + Did you contact support via the app within 7 days of creating your wallet? If yes, or if you\'re unsure, click \'Yes\' and follow the instructions. Thank you! All set! No further actions required. You will now be redirected to the official Tangem website. Please read and follow instructions there. Have you ever contacted the Tangem support team directly through this application? diff --git a/data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaApiRequestMaker.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaApiRequestMaker.kt index d06d1fb0de..538c665358 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaApiRequestMaker.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/visa/utils/VisaApiRequestMaker.kt @@ -91,6 +91,11 @@ internal class VisaApiRequestMaker @Inject constructor( private suspend fun getAuthTokens(userWalletId: UserWalletId): VisaAuthTokens { val userWallet = findVisaUserWallet(userWalletId) val status = userWallet.scanResponse.visaCardActivationStatus ?: error("Visa card activation status not found") + + if (status is VisaCardActivationStatus.RefreshTokenExpired) { + throw RefreshTokenExpiredException() + } + return (status as? VisaCardActivationStatus.Activated)?.visaAuthTokens ?: error("Visa card is not activated") } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt index cc8e0c9c5e..12a4cf918c 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt @@ -59,6 +59,7 @@ internal class WalletWarningsAnalyticsSender @Inject constructor( is WalletNotification.Warning.SomeNetworksUnreachable, is WalletNotification.Warning.NetworksUnreachable, is WalletNotification.UsedOutdatedData, + is WalletNotification.UnlockVisaAccess, -> null is WalletNotification.Critical.SeedPhraseNotification -> MainScreen.NoticeSeedPhraseSupport is WalletNotification.Critical.SeedPhraseSecondNotification -> MainScreen.NoticeSeedPhraseSupportSecond diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt index 6cb194fd18..203a35a3a8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt @@ -191,6 +191,19 @@ sealed class WalletNotification(val config: NotificationConfig) { ), ) + data class UnlockVisaAccess(val onUnlockClick: () -> Unit) : WalletNotification( + config = NotificationConfig( + title = resourceReference(id = R.string.visa_unlock_notification_title), + subtitle = resourceReference(id = R.string.visa_unlock_notification_subtitle), + iconResId = R.drawable.ic_locked_24, + buttonsState = NotificationConfig.ButtonsState.PrimaryButtonConfig( + text = resourceReference(id = R.string.visa_unlock_notification_button), + iconResId = R.drawable.ic_tangem_24, + onClick = onUnlockClick, + ), + ), + ) + data class RateApp( val onLikeClick: () -> Unit, val onDislikeClick: () -> Unit, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletState.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletState.kt index 885e370725..42b4839fc4 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletState.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletState.kt @@ -12,6 +12,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.holder.TxHistor import com.tangem.feature.wallet.presentation.wallet.state.model.holder.WalletStateHolder import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf internal const val NOT_INITIALIZED_WALLET_INDEX = -1 @@ -115,5 +116,27 @@ internal sealed interface WalletState : WalletStateHolder { override val balancesAndLimitBlockState: BalancesAndLimitsBlockState? = null } + + data class AccessTokenLocked( + override val walletCardState: WalletCardState, + override val buttons: PersistentList, + override val bottomSheetConfig: TangemBottomSheetConfig?, + val onExploreClick: () -> Unit, + val onUnlockVisaAccessNotificationClick: () -> Unit, + ) : Visa(), + TxHistoryStateHolder by LockedTxHistoryStateHolder(onExploreClick), + WalletStateHolder by LockedWalletStateHolder( + walletCardState = walletCardState, + buttons = buttons, + bottomSheetConfig = bottomSheetConfig, + onUnlockNotificationClick = {}, + ) { + + override val warnings: ImmutableList = persistentListOf( + WalletNotification.UnlockVisaAccess(onUnlockClick = onUnlockVisaAccessNotificationClick), + ) + + override val balancesAndLimitBlockState: BalancesAndLimitsBlockState? = null + } } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/CloseBottomSheetTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/CloseBottomSheetTransformer.kt index feeea1a264..8bfcd6adaf 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/CloseBottomSheetTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/CloseBottomSheetTransformer.kt @@ -25,6 +25,9 @@ internal class CloseBottomSheetTransformer(userWalletId: UserWalletId) : WalletS is WalletState.Visa.Locked -> prevState.copy( bottomSheetConfig = updateConfig(prevState), ) + is WalletState.Visa.AccessTokenLocked -> prevState.copy( + bottomSheetConfig = updateConfig(prevState), + ) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/OpenBottomSheetTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/OpenBottomSheetTransformer.kt index 46ffbf9066..1d3bcc9423 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/OpenBottomSheetTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/OpenBottomSheetTransformer.kt @@ -31,6 +31,9 @@ internal class OpenBottomSheetTransformer( is WalletState.Visa.Locked -> prevState.copy( bottomSheetConfig = updateConfig(), ) + is WalletState.Visa.AccessTokenLocked -> prevState.copy( + bottomSheetConfig = updateConfig(), + ) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/RenameWalletsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/RenameWalletsTransformer.kt index 9dd8ccb8f9..d9141b8c48 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/RenameWalletsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/RenameWalletsTransformer.kt @@ -44,6 +44,7 @@ internal class RenameWalletsTransformer( is WalletState.MultiCurrency.Locked, is WalletState.SingleCurrency.Locked, is WalletState.Visa.Locked, + is WalletState.Visa.AccessTokenLocked, -> { Timber.e("Impossible to rename wallet in locked state") prevState diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetBalancesAndLimitsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetBalancesAndLimitsTransformer.kt index cd0675560d..421848db63 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetBalancesAndLimitsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetBalancesAndLimitsTransformer.kt @@ -7,6 +7,7 @@ import com.tangem.core.ui.format.bigdecimal.crypto import com.tangem.core.ui.format.bigdecimal.fiat import com.tangem.core.ui.format.bigdecimal.format import com.tangem.domain.common.util.getCardsCount +import com.tangem.domain.visa.exception.RefreshTokenExpiredException import com.tangem.domain.visa.model.VisaCurrency import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.presentation.wallet.state.model.BalancesAndLimitsBlockState @@ -29,6 +30,10 @@ internal class SetBalancesAndLimitsTransformer( override fun transformTyped(prevState: WalletState.Visa.Content): WalletState { val visaCurrency = maybeVisaCurrency.getOrElse { + if (it is RefreshTokenExpiredException) { + return getRefreshTokenExpiredState(prevState) + } + return prevState.copy( walletCardState = getErrorWalletCardState(prevState.walletCardState), depositButtonState = prevState.depositButtonState.copy(isEnabled = false), @@ -100,4 +105,14 @@ internal class SetBalancesAndLimitsTransformer( return WalletAdditionalInfo(hideable = true, infoContent) } + + private fun getRefreshTokenExpiredState(prevState: WalletState.Visa.Content): WalletState { + return WalletState.Visa.AccessTokenLocked( + walletCardState = prevState.walletCardState, + buttons = prevState.buttons, + bottomSheetConfig = prevState.bottomSheetConfig, + onExploreClick = clickIntents::onExploreClick, + onUnlockVisaAccessNotificationClick = clickIntents::onUnlockVisaAccessClick, + ) + } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetRefreshStateTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetRefreshStateTransformer.kt index 9977790553..08c92c4139 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetRefreshStateTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetRefreshStateTransformer.kt @@ -35,6 +35,7 @@ internal class SetRefreshStateTransformer( is WalletState.MultiCurrency.Locked, is WalletState.SingleCurrency.Locked, is WalletState.Visa.Locked, + is WalletState.Visa.AccessTokenLocked, -> prevState } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryCountErrorTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryCountErrorTransformer.kt index 9d97991b83..7f7c2f2a2e 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryCountErrorTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryCountErrorTransformer.kt @@ -33,6 +33,7 @@ internal class SetTxHistoryCountErrorTransformer( is WalletState.Visa.Content -> prevState.copy(txHistoryState = createErrorState()) is WalletState.SingleCurrency.Locked, is WalletState.Visa.Locked, + is WalletState.Visa.AccessTokenLocked, -> { Timber.w("Impossible to load transactions history for locked wallet") prevState diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryCountTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryCountTransformer.kt index f61b4961fe..e1f2e9145d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryCountTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryCountTransformer.kt @@ -26,6 +26,7 @@ internal class SetTxHistoryCountTransformer( ) is WalletState.SingleCurrency.Locked, is WalletState.Visa.Locked, + is WalletState.Visa.AccessTokenLocked, -> { Timber.w("Impossible to load transactions history for locked wallet") prevState diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryItemsErrorTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryItemsErrorTransformer.kt index 5eda4b196e..3dad635156 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryItemsErrorTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryItemsErrorTransformer.kt @@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.domain.txhistory.models.TxHistoryListError +import com.tangem.domain.visa.exception.RefreshTokenExpiredException import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents @@ -16,9 +17,10 @@ internal class SetTxHistoryItemsErrorTransformer( override fun transform(prevState: WalletState): WalletState { return when (prevState) { is WalletState.SingleCurrency.Content -> prevState.copy(txHistoryState = createErrorState()) - is WalletState.Visa.Content -> prevState.copy(txHistoryState = createErrorState()) + is WalletState.Visa.Content -> transformVisaContent(prevState) is WalletState.SingleCurrency.Locked, is WalletState.Visa.Locked, + is WalletState.Visa.AccessTokenLocked, -> { Timber.w("Impossible to load transactions history for locked wallet") prevState @@ -30,6 +32,20 @@ internal class SetTxHistoryItemsErrorTransformer( } } + private fun transformVisaContent(prevState: WalletState.Visa.Content): WalletState { + return if (error.cause is RefreshTokenExpiredException) { + WalletState.Visa.AccessTokenLocked( + walletCardState = prevState.walletCardState, + buttons = prevState.buttons, + bottomSheetConfig = prevState.bottomSheetConfig, + onExploreClick = clickIntents::onExploreClick, + onUnlockVisaAccessNotificationClick = clickIntents::onUnlockVisaAccessClick, + ) + } else { + prevState.copy(txHistoryState = createErrorState()) + } + } + private fun createErrorState(): TxHistoryState.Error = when (error) { is TxHistoryListError.DataError -> { TxHistoryState.Error( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryItemsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryItemsTransformer.kt index 09c90b2841..712edaa421 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryItemsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryItemsTransformer.kt @@ -26,6 +26,7 @@ internal class SetTxHistoryItemsTransformer( ) is WalletState.SingleCurrency.Locked, is WalletState.Visa.Locked, + is WalletState.Visa.AccessTokenLocked, -> { Timber.w("Impossible to load transactions history for locked wallet") prevState diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWalletCardDropDownItemsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWalletCardDropDownItemsTransformer.kt index f538e29f90..f9ea74d599 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWalletCardDropDownItemsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWalletCardDropDownItemsTransformer.kt @@ -54,6 +54,11 @@ internal class SetWalletCardDropDownItemsTransformer( dropDownItems = constructDropDownItems(prevState.walletCardState.id), ), ) + is WalletState.Visa.AccessTokenLocked -> prevState.copy( + walletCardState = prevState.walletCardState.copySealed( + dropDownItems = constructDropDownItems(prevState.walletCardState.id), + ), + ) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWarningsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWarningsTransformer.kt index 7d7246a01e..f47eaa2356 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWarningsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWarningsTransformer.kt @@ -19,6 +19,7 @@ internal class SetWarningsTransformer( is WalletState.MultiCurrency.Locked, is WalletState.SingleCurrency.Locked, is WalletState.Visa.Locked, + is WalletState.Visa.AccessTokenLocked, -> { Timber.w("Impossible to update notifications for locked wallet") prevState diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/UnlockWalletTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/UnlockWalletTransformer.kt index 8d4c837f82..32165880b8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/UnlockWalletTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/UnlockWalletTransformer.kt @@ -50,8 +50,9 @@ internal class UnlockWalletTransformer( is WalletState.MultiCurrency.Content, is WalletState.SingleCurrency.Content, is WalletState.Visa.Content, + is WalletState.Visa.AccessTokenLocked, -> { - Timber.e("Impossible to unlock wallet with content state") + Timber.e("Impossible to unlock wallet with not locked state") prevState } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/UpdateWalletCardsCountTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/UpdateWalletCardsCountTransformer.kt index f350399697..55634425fa 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/UpdateWalletCardsCountTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/UpdateWalletCardsCountTransformer.kt @@ -27,6 +27,7 @@ internal class UpdateWalletCardsCountTransformer( is WalletState.MultiCurrency.Locked, is WalletState.SingleCurrency.Locked, is WalletState.Visa.Locked, + is WalletState.Visa.AccessTokenLocked, -> { Timber.e("Impossible to update wallet cards count for locked wallet") prevState diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletClickIntents.kt index 1c218be754..289e9a955d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletClickIntents.kt @@ -107,6 +107,7 @@ internal class WalletClickIntents @Inject constructor( is WalletState.MultiCurrency.Locked, is WalletState.SingleCurrency.Locked, is WalletState.Visa.Locked, + is WalletState.Visa.AccessTokenLocked, -> Unit } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt index 115c9535ab..6926361876 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt @@ -55,6 +55,8 @@ internal interface WalletWarningsClickIntents { fun onUnlockWalletClick() + fun onUnlockVisaAccessClick() + fun onScanToUnlockWalletClick() fun onLikeAppClick() @@ -176,6 +178,10 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( } } + override fun onUnlockVisaAccessClick() { + openScanCardDialog() + } + private fun handleUnlockWalletsError(error: UnlockWalletsError) { val event = when (error) { is UnlockWalletsError.DataError, From 2fb5b86505cfbed6664d1c7411f39da7ec93c7f0 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 26 Feb 2025 13:22:09 +0300 Subject: [PATCH 33/54] Updated on 2026-08-14 --- .../tangem/tap/di/RootAppComponentContextModule.kt | 4 ++-- .../ui/appcurrency/model/AppCurrencySelectorModel.kt | 4 ++-- .../analytics/AppSettingsItemsAnalyticsSender.kt | 4 ++-- .../details/ui/appsettings/model/AppSettingsModel.kt | 4 ++-- .../coderecovery/model/AccessCodeRecoveryModel.kt | 4 ++-- .../ui/cardsettings/model/CardSettingsModel.kt | 4 ++-- .../details/ui/resetcard/model/ResetCardModel.kt | 4 ++-- .../ui/securitymode/model/SecurityModeModel.kt | 4 ++-- .../details/ui/walletconnect/WalletConnectModel.kt | 4 ++-- .../java/com/tangem/tap/features/home/HomeModel.kt | 4 ++-- .../tangem/tap/features/welcome/di/ModelModule.kt | 4 ++-- .../decompose/context/DefaultAppComponentContext.kt | 4 ++-- .../com/tangem/core/decompose/di/ComponentScoped.kt | 9 --------- .../core/decompose/di/HiltComponentBuilderOwner.kt | 2 +- .../di/{DecomposeComponent.kt => ModelComponent.kt} | 8 ++++---- .../com/tangem/core/decompose/di/ModelScoped.kt | 12 ++++++++++++ .../tangem/core/decompose/model/ModelEntryPoint.kt | 4 ++-- .../tangem/core/decompose/model/ParamsContainer.kt | 2 +- .../com/tangem/features/details/di/ModelModule.kt | 4 ++-- .../tangem/features/details/model/DetailsModel.kt | 4 ++-- .../features/details/model/UserWalletListModel.kt | 4 ++-- .../tangem/features/details/utils/ItemsBuilder.kt | 4 ++-- .../tangem/features/details/utils/SocialsBuilder.kt | 4 ++-- .../tangem/features/details/utils/UserWalletSaver.kt | 4 ++-- .../features/details/utils/UserWalletsFetcher.kt | 4 ++-- .../features/disclaimer/impl/di/ModelModule.kt | 4 ++-- .../disclaimer/impl/model/DisclaimerModel.kt | 4 ++-- .../tangem/features/managetokens/di/ModelModule.kt | 4 ++-- .../managetokens/model/CustomTokenFormModel.kt | 4 ++-- .../managetokens/model/CustomTokenSelectorModel.kt | 4 ++-- .../features/managetokens/model/ManageTokensModel.kt | 4 ++-- .../model/OnboardingManageTokensModel.kt | 4 ++-- .../managetokens/utils/CustomCurrencyFormBuilder.kt | 4 ++-- .../managetokens/utils/CustomCurrencyValidator.kt | 4 ++-- .../utils/list/ManageTokensListManager.kt | 4 ++-- .../features/markets/details/impl/di/ModelModule.kt | 4 ++-- .../details/impl/model/MarketsTokenDetailsModel.kt | 4 ++-- .../markets/portfolio/impl/di/ModelModule.kt | 4 ++-- .../portfolio/impl/model/MarketsPortfolioModel.kt | 4 ++-- .../portfolio/impl/model/TokenActionsHandler.kt | 2 -- .../markets/token/block/impl/di/ModelModule.kt | 4 ++-- .../token/block/impl/model/TokenMarketBlockModel.kt | 4 ++-- .../markets/tokenlist/impl/di/ModelModule.kt | 4 ++-- .../markets/tokenlist/impl/model/MarketsListModel.kt | 4 ++-- .../onboarding/v2/entry/impl/di/ComponentModule.kt | 4 ++-- .../v2/entry/impl/model/OnboardingEntryModel.kt | 4 ++-- .../accesscode/model/MultiWalletAccessCodeModel.kt | 4 ++-- .../child/backup/model/MultiWalletBackupModel.kt | 4 ++-- .../chooseoption/model/Wallet1ChooseOptionModel.kt | 4 ++-- .../model/MultiWalletCreateWalletModel.kt | 4 ++-- .../child/finalize/model/MultiWalletFinalizeModel.kt | 4 ++-- .../scanprimary/model/Wallet1ScanPrimaryModel.kt | 4 ++-- .../seedphrase/model/MultiWalletSeedPhraseModel.kt | 4 ++-- .../v2/multiwallet/impl/di/ComponentModule.kt | 4 ++-- .../impl/model/OnboardingMultiWalletModel.kt | 4 ++-- .../model/OnboardingVisaAccessCodeModel.kt | 4 ++-- .../approve/model/OnboardingVisaApproveModel.kt | 4 ++-- .../model/OnboardingVisaChooseWalletModel.kt | 4 ++-- .../model/OnboardingVisaInProgressModel.kt | 4 ++-- .../model/OnboardingVisaOtherWalletModel.kt | 4 ++-- .../pincode/model/OnboardingVisaPinCodeModel.kt | 4 ++-- .../welcome/model/OnboardingVisaWelcomeModel.kt | 4 ++-- .../onboarding/v2/visa/impl/di/ComponentModule.kt | 4 ++-- .../v2/visa/impl/model/OnboardingVisaModel.kt | 4 ++-- .../di/OnrampConfirmResidencyModelModule.kt | 4 ++-- .../confirmresidency/model/ConfirmResidencyModel.kt | 4 ++-- .../onramp/hottokens/di/HotCryptoModelModule.kt | 4 ++-- .../onramp/hottokens/model/HotCryptoModel.kt | 4 ++-- .../portfolio/di/OnrampAddToPortfolioModelModule.kt | 4 ++-- .../portfolio/model/OnrampAddToPortfolioModel.kt | 4 ++-- .../onramp/main/di/OnrampMainComponentModelModule.kt | 4 ++-- .../onramp/providers/di/SelectProviderModelModule.kt | 4 ++-- .../onramp/providers/model/SelectProviderModel.kt | 4 ++-- .../onramp/redirect/di/OnrampRedirectModelModule.kt | 4 ++-- .../di/OnrampSelectCountryModelModule.kt | 4 ++-- .../selectcountry/model/OnrampSelectCountryModel.kt | 4 ++-- .../di/OnrampSelectCurrencyModelModule.kt | 4 ++-- .../model/OnrampSelectCurrencyModel.kt | 4 ++-- .../selecttoken/di/OnrampOperationModelModule.kt | 4 ++-- .../onramp/selecttoken/model/OnrampOperationModel.kt | 4 ++-- .../onramp/settings/di/OnrampSettingsModelModule.kt | 4 ++-- .../onramp/settings/model/OnrampSettingsModel.kt | 4 ++-- .../success/di/OnrampSuccessComponentModelModule.kt | 4 ++-- .../di/AvailableSwapPairsModelModule.kt | 4 ++-- .../onramp/swap/di/SwapSelectTokensModelModule.kt | 4 ++-- .../tokenlist/di/OnrampTokenListModelModule.kt | 4 ++-- .../impl/model/PushNotificationsModel.kt | 4 ++-- .../feature/qrscanning/model/QrScanningModel.kt | 4 ++-- .../referral/domain/di/ReferralDomainModule.kt | 8 ++++---- .../tangem/feature/referral/model/ReferralModel.kt | 4 ++-- .../com/tangem/features/send/impl/di/SendModule.kt | 8 ++++---- .../send/impl/navigation/DefaultSendRouter.kt | 4 ++-- .../send/impl/presentation/model/SendModel.kt | 4 ++-- .../tangem/features/staking/impl/di/StakingModule.kt | 8 ++++---- .../staking/impl/navigation/DefaultStakingRouter.kt | 4 ++-- .../staking/impl/presentation/model/StakingModel.kt | 4 ++-- .../feature/stories/impl/di/StoriesModelModule.kt | 4 ++-- .../com/tangem/feature/swap/di/SwapModelModule.kt | 4 ++-- .../java/com/tangem/feature/swap/model/SwapModel.kt | 4 ++-- .../feature/tokendetails/di/TokenDetailsModule.kt | 8 ++++---- .../presentation/router/DefaultTokenDetailsRouter.kt | 4 ++-- .../tokendetails/model/TokenDetailsModel.kt | 4 ++-- .../component/impl/model/RenameWalletModel.kt | 4 ++-- .../walletsettings/di/WalletSettingsModelModule.kt | 4 ++-- .../walletsettings/model/WalletSettingsModel.kt | 4 ++-- .../feature/walletsettings/utils/ItemsBuilder.kt | 4 ++-- .../feature/wallet/presentation/WalletFragment.kt | 4 ++-- 107 files changed, 228 insertions(+), 227 deletions(-) delete mode 100644 core/decompose/src/main/kotlin/com/tangem/core/decompose/di/ComponentScoped.kt rename core/decompose/src/main/kotlin/com/tangem/core/decompose/di/{DecomposeComponent.kt => ModelComponent.kt} (88%) create mode 100644 core/decompose/src/main/kotlin/com/tangem/core/decompose/di/ModelScoped.kt diff --git a/app/src/main/java/com/tangem/tap/di/RootAppComponentContextModule.kt b/app/src/main/java/com/tangem/tap/di/RootAppComponentContextModule.kt index b59094d579..0d535ff71d 100644 --- a/app/src/main/java/com/tangem/tap/di/RootAppComponentContextModule.kt +++ b/app/src/main/java/com/tangem/tap/di/RootAppComponentContextModule.kt @@ -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( diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/model/AppCurrencySelectorModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/model/AppCurrencySelectorModel.kt index abddb2896e..f48804c41c 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/model/AppCurrencySelectorModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appcurrency/model/AppCurrencySelectorModel.kt @@ -3,7 +3,7 @@ package com.tangem.tap.features.details.ui.appcurrency.model import androidx.compose.runtime.Stable import com.tangem.common.routing.AppRouter import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +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 @@ -19,7 +19,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Stable -@ComponentScoped +@ModelScoped internal class AppCurrencySelectorModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/analytics/AppSettingsItemsAnalyticsSender.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/analytics/AppSettingsItemsAnalyticsSender.kt index fc0137dca3..64a5832a8c 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/analytics/AppSettingsItemsAnalyticsSender.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/analytics/AppSettingsItemsAnalyticsSender.kt @@ -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.ComponentScoped +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 javax.inject.Inject -@ComponentScoped +@ModelScoped internal class AppSettingsItemsAnalyticsSender @Inject constructor( private val analyticsHandler: AnalyticsEventHandler, ) { diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/model/AppSettingsModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/model/AppSettingsModel.kt index 953ad0933c..ee93849f31 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/model/AppSettingsModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/model/AppSettingsModel.kt @@ -3,7 +3,7 @@ package com.tangem.tap.features.details.ui.appsettings.model import androidx.compose.runtime.Stable import com.tangem.common.routing.AppRoute import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +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 @@ -40,7 +40,7 @@ import javax.inject.Inject @Suppress("LongParameterList") @Stable -@ComponentScoped +@ModelScoped internal class AppSettingsModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val appCurrencyRepository: AppCurrencyRepository, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/model/AccessCodeRecoveryModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/model/AccessCodeRecoveryModel.kt index b3c2fb4878..2d90ffa871 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/model/AccessCodeRecoveryModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/coderecovery/model/AccessCodeRecoveryModel.kt @@ -4,7 +4,7 @@ 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.ComponentScoped +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 @@ -22,7 +22,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Stable -@ComponentScoped +@ModelScoped internal class AccessCodeRecoveryModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val tangemSdkManager: TangemSdkManager, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt index 11964f58c4..773aa32d80 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt @@ -7,7 +7,7 @@ import com.tangem.common.doOnSuccess import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRouter import com.tangem.core.analytics.Analytics -import com.tangem.core.decompose.di.ComponentScoped +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 @@ -45,7 +45,7 @@ import javax.inject.Inject @Suppress("LongParameterList") @Stable -@ComponentScoped +@ModelScoped internal class CardSettingsModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/model/ResetCardModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/model/ResetCardModel.kt index a4108e3ea0..f401bbfc09 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/model/ResetCardModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/model/ResetCardModel.kt @@ -5,7 +5,7 @@ import arrow.core.getOrElse import com.tangem.common.routing.AppRoute import com.tangem.common.routing.utils.popTo import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +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 @@ -37,7 +37,7 @@ import javax.inject.Inject @Suppress("LongParameterList") @Stable -@ComponentScoped +@ModelScoped internal class ResetCardModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, paramsContainer: ParamsContainer, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/model/SecurityModeModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/model/SecurityModeModel.kt index 5fe21b868c..39ae0e13fb 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/model/SecurityModeModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/model/SecurityModeModel.kt @@ -5,7 +5,7 @@ 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.ComponentScoped +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 @@ -25,7 +25,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Stable -@ComponentScoped +@ModelScoped internal class SecurityModeModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val tangemSdkManager: TangemSdkManager, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectModel.kt index 6372c2f648..39f27fb752 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectModel.kt @@ -2,7 +2,7 @@ package com.tangem.tap.features.details.ui.walletconnect import androidx.compose.runtime.Stable import arrow.core.getOrElse -import com.tangem.core.decompose.di.ComponentScoped +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 @@ -18,7 +18,7 @@ import timber.log.Timber import javax.inject.Inject @Stable -@ComponentScoped +@ModelScoped internal class WalletConnectModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val listenToQrScanningUseCase: ListenToQrScanningUseCase, diff --git a/app/src/main/java/com/tangem/tap/features/home/HomeModel.kt b/app/src/main/java/com/tangem/tap/features/home/HomeModel.kt index 91a72ef7ed..8511f53ab2 100644 --- a/app/src/main/java/com/tangem/tap/features/home/HomeModel.kt +++ b/app/src/main/java/com/tangem/tap/features/home/HomeModel.kt @@ -9,7 +9,7 @@ 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.ComponentScoped +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 @@ -40,7 +40,7 @@ import javax.inject.Inject @Suppress("LongParameterList") @Stable -@ComponentScoped +@ModelScoped internal class HomeModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val scanCardProcessor: ScanCardProcessor, diff --git a/app/src/main/java/com/tangem/tap/features/welcome/di/ModelModule.kt b/app/src/main/java/com/tangem/tap/features/welcome/di/ModelModule.kt index 1a90bd0bc5..92e347fe26 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/di/ModelModule.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/di/ModelModule.kt @@ -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 diff --git a/core/decompose/src/main/kotlin/com/tangem/core/decompose/context/DefaultAppComponentContext.kt b/core/decompose/src/main/kotlin/com/tangem/core/decompose/context/DefaultAppComponentContext.kt index d4453d3e6a..ea9afa04a5 100644 --- a/core/decompose/src/main/kotlin/com/tangem/core/decompose/context/DefaultAppComponentContext.kt +++ b/core/decompose/src/main/kotlin/com/tangem/core/decompose/context/DefaultAppComponentContext.kt @@ -2,7 +2,7 @@ package com.tangem.core.decompose.context import com.arkivanov.decompose.ComponentContext import com.arkivanov.essenty.instancekeeper.getOrCreate -import com.tangem.core.decompose.di.DecomposeComponent +import com.tangem.core.decompose.di.ModelComponent import com.tangem.core.decompose.navigation.AppNavigationProvider import com.tangem.core.decompose.navigation.DefaultAppNavigationProvider import com.tangem.core.decompose.navigation.DefaultRouter @@ -15,7 +15,7 @@ import kotlinx.coroutines.CoroutineScope class DefaultAppComponentContext( componentContext: ComponentContext, override val dispatchers: CoroutineDispatcherProvider, - override val hiltComponentBuilder: DecomposeComponent.Builder, + override val hiltComponentBuilder: ModelComponent.Builder, override val messageSender: UiMessageSender, private val replaceRouter: Router? = null, ) : AppComponentContext, ComponentContext by componentContext { diff --git a/core/decompose/src/main/kotlin/com/tangem/core/decompose/di/ComponentScoped.kt b/core/decompose/src/main/kotlin/com/tangem/core/decompose/di/ComponentScoped.kt deleted file mode 100644 index b5fde3b58f..0000000000 --- a/core/decompose/src/main/kotlin/com/tangem/core/decompose/di/ComponentScoped.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.tangem.core.decompose.di - -/** - * Annotation for marking a dependency as a component scoped. - * - * This means that the lifecycle of the dependency is limited to the lifecycle of the component it is attached to. - */ -@Retention(AnnotationRetention.SOURCE) -annotation class ComponentScoped \ No newline at end of file diff --git a/core/decompose/src/main/kotlin/com/tangem/core/decompose/di/HiltComponentBuilderOwner.kt b/core/decompose/src/main/kotlin/com/tangem/core/decompose/di/HiltComponentBuilderOwner.kt index d210c58019..99067c8ec4 100644 --- a/core/decompose/src/main/kotlin/com/tangem/core/decompose/di/HiltComponentBuilderOwner.kt +++ b/core/decompose/src/main/kotlin/com/tangem/core/decompose/di/HiltComponentBuilderOwner.kt @@ -8,5 +8,5 @@ interface HiltComponentBuilderOwner { /** * Provides access to the Hilt component builder instance. */ - val hiltComponentBuilder: DecomposeComponent.Builder + val hiltComponentBuilder: ModelComponent.Builder } \ No newline at end of file diff --git a/core/decompose/src/main/kotlin/com/tangem/core/decompose/di/DecomposeComponent.kt b/core/decompose/src/main/kotlin/com/tangem/core/decompose/di/ModelComponent.kt similarity index 88% rename from core/decompose/src/main/kotlin/com/tangem/core/decompose/di/DecomposeComponent.kt rename to core/decompose/src/main/kotlin/com/tangem/core/decompose/di/ModelComponent.kt index 74fba5a48e..6a94065ebf 100644 --- a/core/decompose/src/main/kotlin/com/tangem/core/decompose/di/DecomposeComponent.kt +++ b/core/decompose/src/main/kotlin/com/tangem/core/decompose/di/ModelComponent.kt @@ -10,11 +10,11 @@ import dagger.hilt.components.SingletonComponent /** * Interface for the Decompose component. * - * It is annotated as [ComponentScoped], meaning it has a lifecycle that is scoped to the component. + * It is annotated as [ModelScoped], meaning it has a lifecycle that is scoped to the component. */ -@ComponentScoped +@ModelScoped @DefineComponent(parent = SingletonComponent::class) -interface DecomposeComponent { +interface ModelComponent { /** * Builder interface for the component. @@ -51,6 +51,6 @@ interface DecomposeComponent { * * @return The built Decompose component. */ - fun build(): DecomposeComponent + fun build(): ModelComponent } } \ No newline at end of file diff --git a/core/decompose/src/main/kotlin/com/tangem/core/decompose/di/ModelScoped.kt b/core/decompose/src/main/kotlin/com/tangem/core/decompose/di/ModelScoped.kt new file mode 100644 index 0000000000..ad4308f3d1 --- /dev/null +++ b/core/decompose/src/main/kotlin/com/tangem/core/decompose/di/ModelScoped.kt @@ -0,0 +1,12 @@ +package com.tangem.core.decompose.di + +import javax.inject.Scope + +/** + * Annotation for marking a dependency as a model scoped. + * + * This means that the lifecycle of the dependency is limited to the lifecycle of the component's model + */ +@Scope +@Retention(AnnotationRetention.RUNTIME) +annotation class ModelScoped \ No newline at end of file diff --git a/core/decompose/src/main/kotlin/com/tangem/core/decompose/model/ModelEntryPoint.kt b/core/decompose/src/main/kotlin/com/tangem/core/decompose/model/ModelEntryPoint.kt index 56b718e970..d37de64a00 100644 --- a/core/decompose/src/main/kotlin/com/tangem/core/decompose/model/ModelEntryPoint.kt +++ b/core/decompose/src/main/kotlin/com/tangem/core/decompose/model/ModelEntryPoint.kt @@ -3,7 +3,7 @@ package com.tangem.core.decompose.model import com.arkivanov.essenty.instancekeeper.getOrCreate import com.arkivanov.essenty.instancekeeper.getOrCreateSimple import com.tangem.core.decompose.context.AppComponentContext -import com.tangem.core.decompose.di.DecomposeComponent +import com.tangem.core.decompose.di.ModelComponent import dagger.hilt.EntryPoint import dagger.hilt.EntryPoints import dagger.hilt.InstallIn @@ -15,7 +15,7 @@ import javax.inject.Provider * It provides a map of model providers. */ @EntryPoint -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) interface ModelsEntryPoint { fun models(): Map, Provider> diff --git a/core/decompose/src/main/kotlin/com/tangem/core/decompose/model/ParamsContainer.kt b/core/decompose/src/main/kotlin/com/tangem/core/decompose/model/ParamsContainer.kt index 910764d661..4ab544bf1b 100644 --- a/core/decompose/src/main/kotlin/com/tangem/core/decompose/model/ParamsContainer.kt +++ b/core/decompose/src/main/kotlin/com/tangem/core/decompose/model/ParamsContainer.kt @@ -3,7 +3,7 @@ package com.tangem.core.decompose.model /** * Lazy container for [Model] params. * - * This contrainer can be accessed by DI because it's provided via [com.tangem.core.decompose.di.DecomposeComponent]. + * This contrainer can be accessed by DI because it's provided via [com.tangem.core.decompose.di.ModelComponent]. * */ interface ParamsContainer { diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/di/ModelModule.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/di/ModelModule.kt index 63481527c2..25599bd30e 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/di/ModelModule.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/di/ModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.details.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.features.details.model.DetailsModel import com.tangem.features.details.model.UserWalletListModel @@ -11,7 +11,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface ModelModule { @Binds diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt index e6694cee44..99def3ec10 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt @@ -2,7 +2,7 @@ package com.tangem.features.details.model import arrow.core.getOrElse import com.tangem.core.analytics.AppInstanceIdProvider -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router @@ -32,7 +32,7 @@ import kotlinx.coroutines.launch import timber.log.Timber import javax.inject.Inject -@ComponentScoped +@ModelScoped @Suppress("LongParameterList") internal class DetailsModel @Inject constructor( socialsBuilder: SocialsBuilder, diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt index ef9905ff46..a29ea393b2 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt @@ -1,7 +1,7 @@ package com.tangem.features.details.model import com.tangem.common.ui.userwallet.state.UserWalletItemUM -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference @@ -19,7 +19,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.update import javax.inject.Inject -@ComponentScoped +@ModelScoped internal class UserWalletListModel @Inject constructor( userWalletsFetcher: UserWalletsFetcher, shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase, diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt index 70d3936e99..7cd8933ad5 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt @@ -1,7 +1,7 @@ package com.tangem.features.details.utils import com.tangem.common.routing.AppRoute -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.navigation.Router import com.tangem.core.ui.components.block.model.BlockUM import com.tangem.core.ui.extensions.resourceReference @@ -14,7 +14,7 @@ import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import javax.inject.Inject -@ComponentScoped +@ModelScoped internal class ItemsBuilder @Inject constructor(private val router: Router) { fun buildAll( diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/SocialsBuilder.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/SocialsBuilder.kt index 8282bbd41c..dda4068ab9 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/SocialsBuilder.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/SocialsBuilder.kt @@ -1,7 +1,7 @@ package com.tangem.features.details.utils import androidx.compose.ui.text.intl.Locale -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.navigation.url.UrlOpener import com.tangem.features.details.entity.DetailsFooterUM import com.tangem.features.details.impl.R @@ -9,7 +9,7 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import javax.inject.Inject -@ComponentScoped +@ModelScoped internal class SocialsBuilder @Inject constructor( private val urlOpener: UrlOpener, ) { diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletSaver.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletSaver.kt index fd621dbe14..6badebac2d 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletSaver.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletSaver.kt @@ -7,7 +7,7 @@ import arrow.core.raise.fold import arrow.core.raise.recover import com.tangem.common.routing.AppRoute import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.navigation.popTo import com.tangem.core.decompose.ui.UiMessageSender @@ -33,7 +33,7 @@ import kotlinx.coroutines.suspendCancellableCoroutine import javax.inject.Inject import kotlin.coroutines.resume -@ComponentScoped +@ModelScoped @Suppress("LongParameterList") internal class UserWalletSaver @Inject constructor( private val scanCardProcessor: ScanCardProcessor, diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletsFetcher.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletsFetcher.kt index c9115930ec..8de287944f 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletsFetcher.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletsFetcher.kt @@ -4,7 +4,7 @@ import arrow.core.Either import com.tangem.common.routing.AppRoute import com.tangem.common.ui.userwallet.converter.UserWalletItemUMConverter import com.tangem.common.ui.userwallet.state.UserWalletItemUM -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.extensions.resourceReference @@ -31,7 +31,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.* import javax.inject.Inject -@ComponentScoped +@ModelScoped internal class UserWalletsFetcher @Inject constructor( getWalletsUseCase: GetWalletsUseCase, private val getWalletTotalBalanceUseCase: GetWalletTotalBalanceUseCase, diff --git a/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/di/ModelModule.kt b/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/di/ModelModule.kt index a589336c78..4862b935c9 100644 --- a/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/di/ModelModule.kt +++ b/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/di/ModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.disclaimer.impl.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.features.disclaimer.impl.model.DisclaimerModel 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 diff --git a/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/model/DisclaimerModel.kt b/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/model/DisclaimerModel.kt index e2dffb37f3..f96cb66625 100644 --- a/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/model/DisclaimerModel.kt +++ b/features/disclaimer/impl/src/main/java/com/tangem/features/disclaimer/impl/model/DisclaimerModel.kt @@ -1,7 +1,7 @@ package com.tangem.features.disclaimer.impl.model import com.tangem.common.routing.AppRoute -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router @@ -17,7 +17,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch import javax.inject.Inject -@ComponentScoped +@ModelScoped @Suppress("LongParameterList") internal class DisclaimerModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/di/ModelModule.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/di/ModelModule.kt index 101e51cfdd..d9f4b0cb1d 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/di/ModelModule.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/di/ModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.managetokens.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.features.managetokens.model.CustomTokenFormModel import com.tangem.features.managetokens.model.CustomTokenSelectorModel @@ -13,7 +13,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface ModelModule { @Binds diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenFormModel.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenFormModel.kt index ad5db50c72..58b65ada79 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenFormModel.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenFormModel.kt @@ -2,7 +2,7 @@ package com.tangem.features.managetokens.model import arrow.core.getOrElse import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.ui.UiMessageSender @@ -37,7 +37,7 @@ import javax.inject.Inject // TODO: Divide to sub-components: [REDACTED_JIRA] @Suppress("LongParameterList", "LargeClass") -@ComponentScoped +@ModelScoped internal class CustomTokenFormModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val customCurrencyValidator: CustomCurrencyValidator, diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenSelectorModel.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenSelectorModel.kt index 998307191a..b1b01ab5ed 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenSelectorModel.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenSelectorModel.kt @@ -3,7 +3,7 @@ package com.tangem.features.managetokens.model import arrow.core.getOrElse import com.arkivanov.decompose.router.slot.SlotNavigation import com.arkivanov.decompose.router.slot.activate -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.ui.UiMessageSender @@ -33,7 +33,7 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import javax.inject.Inject -@ComponentScoped +@ModelScoped internal class CustomTokenSelectorModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val getSupportedNetworksUseCase: GetSupportedNetworksUseCase, diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/ManageTokensModel.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/ManageTokensModel.kt index 36916e335d..65be95e384 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/ManageTokensModel.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/ManageTokensModel.kt @@ -5,7 +5,7 @@ import arrow.core.getOrElse import com.arkivanov.decompose.router.slot.SlotNavigation import com.arkivanov.decompose.router.slot.activate import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router @@ -42,7 +42,7 @@ import timber.log.Timber import javax.inject.Inject @Suppress("LongParameterList") -@ComponentScoped +@ModelScoped internal class ManageTokensModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val router: Router, diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/OnboardingManageTokensModel.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/OnboardingManageTokensModel.kt index c5bb946e7d..485566a94a 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/OnboardingManageTokensModel.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/OnboardingManageTokensModel.kt @@ -3,7 +3,7 @@ package com.tangem.features.managetokens.model import arrow.core.flatten import arrow.core.getOrElse import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.ui.UiMessageSender @@ -37,7 +37,7 @@ import timber.log.Timber import javax.inject.Inject @Suppress("LongParameterList") -@ComponentScoped +@ModelScoped internal class OnboardingManageTokensModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val manageTokensListManager: ManageTokensListManager, diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/CustomCurrencyFormBuilder.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/CustomCurrencyFormBuilder.kt index caf9507cc2..f371da280d 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/CustomCurrencyFormBuilder.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/CustomCurrencyFormBuilder.kt @@ -3,7 +3,7 @@ package com.tangem.features.managetokens.utils import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference @@ -15,7 +15,7 @@ import com.tangem.features.managetokens.impl.R import kotlinx.collections.immutable.persistentMapOf import javax.inject.Inject -@ComponentScoped +@ModelScoped internal class CustomCurrencyFormBuilder @Inject constructor( paramsContainer: ParamsContainer, ) { diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/CustomCurrencyValidator.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/CustomCurrencyValidator.kt index 77a41933ea..fa0f6b6046 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/CustomCurrencyValidator.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/CustomCurrencyValidator.kt @@ -1,7 +1,7 @@ package com.tangem.features.managetokens.utils import arrow.core.getOrElse -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.managetokens.CheckIsCurrencyNotAddedUseCase import com.tangem.domain.managetokens.CreateCurrencyUseCase import com.tangem.domain.managetokens.FindTokenUseCase @@ -20,7 +20,7 @@ import kotlinx.coroutines.launch import timber.log.Timber import javax.inject.Inject -@ComponentScoped +@ModelScoped internal class CustomCurrencyValidator @Inject constructor( private val validateTokenFormUseCase: ValidateTokenFormUseCase, private val createCustomCurrencyUseCase: CreateCurrencyUseCase, diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListManager.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListManager.kt index d3a52095a7..7dde531506 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListManager.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListManager.kt @@ -4,7 +4,7 @@ import androidx.compose.ui.util.fastForEachIndexed import androidx.compose.ui.util.fastMap import arrow.core.getOrElse import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.clipboard.ClipboardManager import com.tangem.core.ui.extensions.resourceReference @@ -40,7 +40,7 @@ import timber.log.Timber import javax.inject.Inject @Suppress("LongParameterList") -@ComponentScoped +@ModelScoped internal class ManageTokensListManager @Inject constructor( private val getManagedTokensUseCase: GetManagedTokensUseCase, private val checkHasLinkedTokensUseCase: CheckHasLinkedTokensUseCase, diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/di/ModelModule.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/di/ModelModule.kt index 83e26ff055..2fda5dee58 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/di/ModelModule.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/di/ModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.markets.details.impl.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.features.markets.details.impl.model.MarketsTokenDetailsModel 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 diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/MarketsTokenDetailsModel.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/MarketsTokenDetailsModel.kt index 04d2edcb0c..3ba4dd807e 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/MarketsTokenDetailsModel.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/MarketsTokenDetailsModel.kt @@ -8,7 +8,7 @@ import com.tangem.common.ui.charts.state.MarketChartData import com.tangem.common.ui.charts.state.MarketChartDataProducer import com.tangem.common.ui.charts.state.sorted import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.navigation.url.UrlOpener @@ -53,7 +53,7 @@ import javax.inject.Inject @Suppress("LargeClass", "LongParameterList") @Stable -@ComponentScoped +@ModelScoped internal class MarketsTokenDetailsModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/di/ModelModule.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/di/ModelModule.kt index 38ea8f8688..2b35fe3c10 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/di/ModelModule.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/di/ModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.markets.portfolio.impl.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.features.markets.portfolio.impl.model.MarketsPortfolioModel 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 diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/MarketsPortfolioModel.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/MarketsPortfolioModel.kt index b28d495ac2..e31e23a7be 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/MarketsPortfolioModel.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/MarketsPortfolioModel.kt @@ -3,7 +3,7 @@ package com.tangem.features.markets.portfolio.impl.model import androidx.compose.runtime.Stable import arrow.core.getOrElse import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.ui.UiMessageSender @@ -38,7 +38,7 @@ import javax.inject.Inject @Suppress("LongParameterList") @Stable -@ComponentScoped +@ModelScoped internal class MarketsPortfolioModel @Inject constructor( paramsContainer: ParamsContainer, getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/TokenActionsHandler.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/TokenActionsHandler.kt index 471770d6a4..ab2b23c6c0 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/TokenActionsHandler.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/TokenActionsHandler.kt @@ -2,7 +2,6 @@ package com.tangem.features.markets.portfolio.impl.model import com.tangem.common.routing.AppRoute import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.core.decompose.di.ComponentScoped import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.clipboard.ClipboardManager @@ -31,7 +30,6 @@ import dagger.assisted.AssistedInject import kotlinx.collections.immutable.toImmutableList @Suppress("LongParameterList") -@ComponentScoped internal class TokenActionsHandler @AssistedInject constructor( private val router: Router, private val clipboardManager: ClipboardManager, diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/di/ModelModule.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/di/ModelModule.kt index fdb1ba90ba..e50f1793ed 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/di/ModelModule.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/di/ModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.markets.token.block.impl.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.features.markets.token.block.impl.model.TokenMarketBlockModel 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 diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/model/TokenMarketBlockModel.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/model/TokenMarketBlockModel.kt index 35346aeb94..372309d5ea 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/model/TokenMarketBlockModel.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/model/TokenMarketBlockModel.kt @@ -6,7 +6,7 @@ import com.tangem.common.routing.AppRoute import com.tangem.common.ui.charts.state.MarketChartData import com.tangem.common.ui.charts.state.converter.PriceAndTimePointValuesConverter import com.tangem.common.ui.charts.state.sorted -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router @@ -31,7 +31,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Stable -@ComponentScoped +@ModelScoped internal class TokenMarketBlockModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/di/ModelModule.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/di/ModelModule.kt index 17aa3f4cd5..fca279c2f6 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/di/ModelModule.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/di/ModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.markets.tokenlist.impl.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.features.markets.tokenlist.impl.model.MarketsListModel 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 diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/MarketsListModel.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/MarketsListModel.kt index 7e94d860a3..65622d2f0d 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/MarketsListModel.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/MarketsListModel.kt @@ -3,7 +3,7 @@ package com.tangem.features.markets.tokenlist.impl.model import androidx.compose.runtime.Stable import arrow.core.getOrElse import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency @@ -29,7 +29,7 @@ private const val UPDATE_QUOTES_TIMER_MILLIS = 60000L private const val SEARCH_QUERY_DEBOUNCE_MILLIS = 800L @OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class) -@ComponentScoped +@ModelScoped @Stable internal class MarketsListModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/di/ComponentModule.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/di/ComponentModule.kt index 1ea00b3585..4ce0d4c71d 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/di/ComponentModule.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/di/ComponentModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onboarding.v2.entry.impl.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.features.onboarding.v2.entry.OnboardingEntryComponent import com.tangem.features.onboarding.v2.entry.impl.DefaultOnboardingEntryComponent @@ -25,7 +25,7 @@ internal interface ComponentModule { } @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface ModelModule { @Binds @IntoMap diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/model/OnboardingEntryModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/model/OnboardingEntryModel.kt index 281ec29e57..a4478d44e3 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/model/OnboardingEntryModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/model/OnboardingEntryModel.kt @@ -3,7 +3,7 @@ package com.tangem.features.onboarding.v2.entry.impl.model import com.arkivanov.decompose.router.stack.StackNavigation import com.arkivanov.decompose.router.stack.navigate import com.tangem.common.routing.AppRoute -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router @@ -25,7 +25,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch import javax.inject.Inject -@ComponentScoped +@ModelScoped internal class OnboardingEntryModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/accesscode/model/MultiWalletAccessCodeModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/accesscode/model/MultiWalletAccessCodeModel.kt index a2f3f24de7..bd4a37a0b5 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/accesscode/model/MultiWalletAccessCodeModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/accesscode/model/MultiWalletAccessCodeModel.kt @@ -3,7 +3,7 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.child.accesscode.mode import androidx.compose.runtime.Stable import androidx.compose.ui.text.input.TextFieldValue import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.features.onboarding.v2.multiwallet.impl.analytics.OnboardingEvent @@ -22,7 +22,7 @@ import javax.inject.Inject private const val MINIMUM_ACCESS_CODE_LENGTH = 4 @Stable -@ComponentScoped +@ModelScoped internal class MultiWalletAccessCodeModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/model/MultiWalletBackupModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/model/MultiWalletBackupModel.kt index 48d3ead42a..46f6135d72 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/model/MultiWalletBackupModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/model/MultiWalletBackupModel.kt @@ -7,7 +7,7 @@ import com.tangem.common.core.TangemSdkError import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.ui.UiMessageSender @@ -38,7 +38,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Stable -@ComponentScoped +@ModelScoped @Suppress("LongParameterList") class MultiWalletBackupModel @Inject constructor( paramsContainer: ParamsContainer, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/chooseoption/model/Wallet1ChooseOptionModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/chooseoption/model/Wallet1ChooseOptionModel.kt index 69d37f496f..c460852063 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/chooseoption/model/Wallet1ChooseOptionModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/chooseoption/model/Wallet1ChooseOptionModel.kt @@ -2,7 +2,7 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.child.chooseoption.mo import androidx.compose.runtime.Stable import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +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.repository.CardRepository @@ -21,7 +21,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Stable -@ComponentScoped +@ModelScoped internal class Wallet1ChooseOptionModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, paramsContainer: ParamsContainer, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/model/MultiWalletCreateWalletModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/model/MultiWalletCreateWalletModel.kt index c41f5bdff9..235a5a45ff 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/model/MultiWalletCreateWalletModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/model/MultiWalletCreateWalletModel.kt @@ -4,7 +4,7 @@ import androidx.compose.runtime.Stable import com.tangem.common.CompletionResult import com.tangem.common.core.TangemSdkError import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.ui.extensions.resourceReference @@ -34,7 +34,7 @@ import javax.inject.Inject @Suppress("LongParameterList") @Stable -@ComponentScoped +@ModelScoped internal class MultiWalletCreateWalletModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/finalize/model/MultiWalletFinalizeModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/finalize/model/MultiWalletFinalizeModel.kt index c87784f4ad..a176555bb7 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/finalize/model/MultiWalletFinalizeModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/finalize/model/MultiWalletFinalizeModel.kt @@ -3,7 +3,7 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.child.finalize.model import androidx.compose.runtime.Stable import com.tangem.common.CompletionResult import com.tangem.common.core.TangemSdkError -import com.tangem.core.decompose.di.ComponentScoped +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.repository.CardRepository @@ -39,7 +39,7 @@ import javax.inject.Inject @Suppress("LongParameterList") @Stable -@ComponentScoped +@ModelScoped internal class MultiWalletFinalizeModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/model/Wallet1ScanPrimaryModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/model/Wallet1ScanPrimaryModel.kt index 504e556fbc..621279a14b 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/model/Wallet1ScanPrimaryModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/model/Wallet1ScanPrimaryModel.kt @@ -2,7 +2,7 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.child.scanprimary.mod import androidx.compose.runtime.Stable import com.tangem.common.CompletionResult -import com.tangem.core.decompose.di.ComponentScoped +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.common.util.cardTypesResolver @@ -15,7 +15,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Stable -@ComponentScoped +@ModelScoped internal class Wallet1ScanPrimaryModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/MultiWalletSeedPhraseModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/MultiWalletSeedPhraseModel.kt index 93bc3e193c..7b75b80c4e 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/MultiWalletSeedPhraseModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/MultiWalletSeedPhraseModel.kt @@ -4,7 +4,7 @@ import androidx.compose.runtime.Stable import com.tangem.common.CompletionResult import com.tangem.common.core.TangemSdkError import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.navigation.url.UrlOpener @@ -35,7 +35,7 @@ import javax.inject.Inject // ============================================= @Suppress("LongParameterList") @Stable -@ComponentScoped +@ModelScoped internal class MultiWalletSeedPhraseModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/di/ComponentModule.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/di/ComponentModule.kt index 1aee88709b..9054f73faa 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/di/ComponentModule.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/di/ComponentModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.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.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent import com.tangem.features.onboarding.v2.multiwallet.impl.DefaultOnboardingMultiWalletComponent @@ -30,7 +30,7 @@ internal interface ComponentModule { } @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface ModelModule { @Binds diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt index ad4786a6b7..725d8be92e 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt @@ -1,7 +1,7 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.model import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router @@ -22,7 +22,7 @@ import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import javax.inject.Inject -@ComponentScoped +@ModelScoped internal class OnboardingMultiWalletModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/model/OnboardingVisaAccessCodeModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/model/OnboardingVisaAccessCodeModel.kt index 2f56bd8ddb..086d02041d 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/model/OnboardingVisaAccessCodeModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/model/OnboardingVisaAccessCodeModel.kt @@ -4,7 +4,7 @@ import androidx.compose.runtime.Stable import androidx.compose.ui.text.input.TextFieldValue import com.tangem.common.CompletionResult import com.tangem.common.extensions.toHexString -import com.tangem.core.decompose.di.ComponentScoped +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.visa.model.VisaCardActivationStatus @@ -26,7 +26,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Stable -@ComponentScoped +@ModelScoped internal class OnboardingVisaAccessCodeModel @Inject constructor( paramsContainer: ParamsContainer, visaActivationRepositoryFactory: VisaActivationRepository.Factory, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/approve/model/OnboardingVisaApproveModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/approve/model/OnboardingVisaApproveModel.kt index 245dbb83cb..396a8039b2 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/approve/model/OnboardingVisaApproveModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/approve/model/OnboardingVisaApproveModel.kt @@ -3,7 +3,7 @@ package com.tangem.features.onboarding.v2.visa.impl.child.approve.model import androidx.compose.runtime.Stable import com.tangem.common.CompletionResult import com.tangem.common.extensions.toHexString -import com.tangem.core.decompose.di.ComponentScoped +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.visa.model.VisaCardId @@ -21,7 +21,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Stable -@ComponentScoped +@ModelScoped internal class OnboardingVisaApproveModel @Inject constructor( paramsContainer: ParamsContainer, visaActivationRepositoryFactory: VisaActivationRepository.Factory, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/model/OnboardingVisaChooseWalletModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/model/OnboardingVisaChooseWalletModel.kt index 4f6629cae9..381cfc11aa 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/model/OnboardingVisaChooseWalletModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/model/OnboardingVisaChooseWalletModel.kt @@ -1,7 +1,7 @@ package com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.model import androidx.compose.runtime.Stable -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.ui.extensions.TextReference import com.tangem.features.onboarding.v2.impl.R @@ -18,7 +18,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Stable -@ComponentScoped +@ModelScoped internal class OnboardingVisaChooseWalletModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, ) : Model() { diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/inprogress/model/OnboardingVisaInProgressModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/inprogress/model/OnboardingVisaInProgressModel.kt index 48ac5a404d..3d79bce2c1 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/inprogress/model/OnboardingVisaInProgressModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/inprogress/model/OnboardingVisaInProgressModel.kt @@ -2,7 +2,7 @@ package com.tangem.features.onboarding.v2.visa.impl.child.inprogress.model import androidx.compose.runtime.Stable import com.tangem.common.extensions.toHexString -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.datasource.local.visa.VisaAuthTokenStorage @@ -27,7 +27,7 @@ import javax.inject.Inject @Suppress("LongParameterList") @Stable -@ComponentScoped +@ModelScoped internal class OnboardingVisaInProgressModel @Inject constructor( paramsContainer: ParamsContainer, visaActivationRepositoryFactory: VisaActivationRepository.Factory, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/otherwallet/model/OnboardingVisaOtherWalletModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/otherwallet/model/OnboardingVisaOtherWalletModel.kt index 887cd4759f..53c043fbea 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/otherwallet/model/OnboardingVisaOtherWalletModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/otherwallet/model/OnboardingVisaOtherWalletModel.kt @@ -2,7 +2,7 @@ package com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.model import androidx.compose.runtime.Stable import com.tangem.common.extensions.toHexString -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.navigation.share.ShareManager @@ -22,7 +22,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Stable -@ComponentScoped +@ModelScoped internal class OnboardingVisaOtherWalletModel @Inject constructor( paramsContainer: ParamsContainer, visaActivationRepositoryFactory: VisaActivationRepository.Factory, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/pincode/model/OnboardingVisaPinCodeModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/pincode/model/OnboardingVisaPinCodeModel.kt index deae6ff93c..0b02574d50 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/pincode/model/OnboardingVisaPinCodeModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/pincode/model/OnboardingVisaPinCodeModel.kt @@ -2,7 +2,7 @@ package com.tangem.features.onboarding.v2.visa.impl.child.pincode.model import androidx.compose.runtime.Stable import com.tangem.common.extensions.toHexString -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.datasource.local.visa.VisaAuthTokenStorage @@ -26,7 +26,7 @@ import kotlinx.coroutines.withContext import javax.inject.Inject @Stable -@ComponentScoped +@ModelScoped @Suppress("LongParameterList") internal class OnboardingVisaPinCodeModel @Inject constructor( paramsContainer: ParamsContainer, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/welcome/model/OnboardingVisaWelcomeModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/welcome/model/OnboardingVisaWelcomeModel.kt index 526e51806f..82a7092b99 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/welcome/model/OnboardingVisaWelcomeModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/welcome/model/OnboardingVisaWelcomeModel.kt @@ -2,7 +2,7 @@ package com.tangem.features.onboarding.v2.visa.impl.child.welcome.model import com.tangem.common.CompletionResult import com.tangem.common.extensions.toHexString -import com.tangem.core.decompose.di.ComponentScoped +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.visa.model.VisaCardId @@ -22,7 +22,7 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import javax.inject.Inject -@ComponentScoped +@ModelScoped internal class OnboardingVisaWelcomeModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/di/ComponentModule.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/di/ComponentModule.kt index 15349b614b..d4421b9169 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/di/ComponentModule.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/di/ComponentModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onboarding.v2.visa.impl.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.features.onboarding.v2.visa.api.OnboardingVisaComponent import com.tangem.features.onboarding.v2.visa.impl.DefaultOnboardingVisaComponent @@ -30,7 +30,7 @@ internal interface ComponentModule { } @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface ModelModule { @Binds diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/model/OnboardingVisaModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/model/OnboardingVisaModel.kt index ca2b727f7c..5e98a81f2b 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/model/OnboardingVisaModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/model/OnboardingVisaModel.kt @@ -6,7 +6,7 @@ import com.arkivanov.decompose.router.stack.StackNavigation import com.arkivanov.decompose.router.stack.pop import com.arkivanov.decompose.router.stack.push import com.arkivanov.decompose.router.stack.pushNew -import com.tangem.core.decompose.di.ComponentScoped +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.common.visa.VisaUtilities @@ -31,7 +31,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Stable -@ComponentScoped +@ModelScoped internal class OnboardingVisaModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/di/OnrampConfirmResidencyModelModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/di/OnrampConfirmResidencyModelModule.kt index ab79a46e1c..b58e525556 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/di/OnrampConfirmResidencyModelModule.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/di/OnrampConfirmResidencyModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onramp.confirmresidency.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.features.onramp.confirmresidency.model.ConfirmResidencyModel import dagger.Binds @@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface OnrampConfirmResidencyModelModule { @Binds @IntoMap diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/model/ConfirmResidencyModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/model/ConfirmResidencyModel.kt index 270c3e6f73..3466152b67 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/model/ConfirmResidencyModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/model/ConfirmResidencyModel.kt @@ -3,7 +3,7 @@ package com.tangem.features.onramp.confirmresidency.model import com.arkivanov.decompose.router.slot.SlotNavigation import com.arkivanov.decompose.router.slot.activate import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router @@ -20,7 +20,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch import javax.inject.Inject -@ComponentScoped +@ModelScoped internal class ConfirmResidencyModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val analyticsEventHandler: AnalyticsEventHandler, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/di/HotCryptoModelModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/di/HotCryptoModelModule.kt index 7757a30590..7ed81b78db 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/di/HotCryptoModelModule.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/di/HotCryptoModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onramp.hottokens.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.features.onramp.hottokens.model.HotCryptoModel import dagger.Binds @@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface HotCryptoModelModule { @Binds diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/model/HotCryptoModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/model/HotCryptoModel.kt index 29a5b07946..be622c09d1 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/model/HotCryptoModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/model/HotCryptoModel.kt @@ -4,7 +4,7 @@ import arrow.core.getOrElse import com.arkivanov.decompose.router.slot.SlotNavigation import com.arkivanov.decompose.router.slot.activate import com.arkivanov.decompose.router.slot.dismiss -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.ui.components.token.state.TokenItemState @@ -40,7 +40,7 @@ import javax.inject.Inject * [REDACTED_AUTHOR] */ -@ComponentScoped +@ModelScoped internal class HotCryptoModel @Inject constructor( paramsContainer: ParamsContainer, getHotCryptoUseCase: GetHotCryptoUseCase, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/portfolio/di/OnrampAddToPortfolioModelModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/portfolio/di/OnrampAddToPortfolioModelModule.kt index 086a66b0d0..4db40ffeca 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/portfolio/di/OnrampAddToPortfolioModelModule.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/portfolio/di/OnrampAddToPortfolioModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onramp.hottokens.portfolio.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.features.onramp.hottokens.portfolio.model.OnrampAddToPortfolioModel import dagger.Binds @@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface OnrampAddToPortfolioModelModule { @Binds diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/portfolio/model/OnrampAddToPortfolioModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/portfolio/model/OnrampAddToPortfolioModel.kt index 9ca6e59406..ed8f3c543a 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/portfolio/model/OnrampAddToPortfolioModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/portfolio/model/OnrampAddToPortfolioModel.kt @@ -1,7 +1,7 @@ package com.tangem.features.onramp.hottokens.portfolio.model import arrow.core.getOrElse -import com.tangem.core.decompose.di.ComponentScoped +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.DerivePublicKeysUseCase @@ -29,7 +29,7 @@ import javax.inject.Inject * [REDACTED_AUTHOR] */ -@ComponentScoped +@ModelScoped internal class OnrampAddToPortfolioModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/di/OnrampMainComponentModelModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/di/OnrampMainComponentModelModule.kt index 99826bae5d..f3bbdba606 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/di/OnrampMainComponentModelModule.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/di/OnrampMainComponentModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onramp.main.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.features.onramp.main.model.OnrampMainComponentModel import dagger.Binds @@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface OnrampMainComponentModelModule { @Binds diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/di/SelectProviderModelModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/di/SelectProviderModelModule.kt index 812d6bd45d..3719bf0fae 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/di/SelectProviderModelModule.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/di/SelectProviderModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onramp.providers.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.features.onramp.providers.model.SelectProviderModel import dagger.Binds @@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface SelectProviderModelModule { @Binds diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt index bc077ed6a3..ea142aa30f 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt @@ -4,7 +4,7 @@ import com.arkivanov.decompose.router.slot.SlotNavigation import com.arkivanov.decompose.router.slot.activate import com.arkivanov.decompose.router.slot.dismiss import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.ui.extensions.resourceReference @@ -40,7 +40,7 @@ import java.math.BigDecimal import javax.inject.Inject @Suppress("LongParameterList") -@ComponentScoped +@ModelScoped internal class SelectProviderModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val analyticsEventHandler: AnalyticsEventHandler, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/di/OnrampRedirectModelModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/di/OnrampRedirectModelModule.kt index 21547db511..619e70ca91 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/di/OnrampRedirectModelModule.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/di/OnrampRedirectModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onramp.redirect.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.features.onramp.redirect.model.OnrampRedirectModel import dagger.Binds @@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface OnrampRedirectModelModule { @Binds diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/di/OnrampSelectCountryModelModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/di/OnrampSelectCountryModelModule.kt index 1230e7174d..8be0024799 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/di/OnrampSelectCountryModelModule.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/di/OnrampSelectCountryModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onramp.selectcountry.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.features.onramp.selectcountry.model.OnrampSelectCountryModel import dagger.Binds @@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface OnrampSelectCountryModelModule { @Binds diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/OnrampSelectCountryModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/OnrampSelectCountryModel.kt index 94296a59e1..e7a8f8dedf 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/OnrampSelectCountryModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/OnrampSelectCountryModel.kt @@ -1,7 +1,7 @@ package com.tangem.features.onramp.selectcountry.model import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.ui.components.fields.entity.SearchBarUM @@ -35,7 +35,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Suppress("LongParameterList") -@ComponentScoped +@ModelScoped internal class OnrampSelectCountryModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val analyticsEventHandler: AnalyticsEventHandler, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/di/OnrampSelectCurrencyModelModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/di/OnrampSelectCurrencyModelModule.kt index 3541b9cb45..f699c1205c 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/di/OnrampSelectCurrencyModelModule.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/di/OnrampSelectCurrencyModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onramp.selectcurrency.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.features.onramp.selectcurrency.model.OnrampSelectCurrencyModel import dagger.Binds @@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface OnrampSelectCurrencyModelModule { @Binds diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/model/OnrampSelectCurrencyModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/model/OnrampSelectCurrencyModel.kt index a297ae455a..93d64b7bca 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/model/OnrampSelectCurrencyModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/model/OnrampSelectCurrencyModel.kt @@ -1,7 +1,7 @@ package com.tangem.features.onramp.selectcurrency.model import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.ui.components.fields.entity.SearchBarUM @@ -35,7 +35,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Suppress("LongParameterList") -@ComponentScoped +@ModelScoped internal class OnrampSelectCurrencyModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val analyticsEventHandler: AnalyticsEventHandler, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selecttoken/di/OnrampOperationModelModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selecttoken/di/OnrampOperationModelModule.kt index 9c9eb054d2..7488094564 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selecttoken/di/OnrampOperationModelModule.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selecttoken/di/OnrampOperationModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onramp.selecttoken.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.features.onramp.selecttoken.model.OnrampOperationModel import dagger.Binds @@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface OnrampOperationModelModule { @Binds diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selecttoken/model/OnrampOperationModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selecttoken/model/OnrampOperationModel.kt index b0555c7c63..770e77d257 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selecttoken/model/OnrampOperationModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selecttoken/model/OnrampOperationModel.kt @@ -6,7 +6,7 @@ import com.tangem.common.ui.alerts.models.AlertDemoModeUM import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.ui.UiMessageSender @@ -33,7 +33,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Suppress("LongParameterList") -@ComponentScoped +@ModelScoped internal class OnrampOperationModel @Inject constructor( paramsContainer: ParamsContainer, getWalletsUseCase: GetWalletsUseCase, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/di/OnrampSettingsModelModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/di/OnrampSettingsModelModule.kt index f62678e7ee..8b90098a7f 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/di/OnrampSettingsModelModule.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/di/OnrampSettingsModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onramp.settings.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.features.onramp.settings.model.OnrampSettingsModel import dagger.Binds @@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface OnrampSettingsModelModule { @Binds diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt index a67426d614..95ed639744 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt @@ -4,7 +4,7 @@ import arrow.core.Either import com.arkivanov.decompose.router.slot.SlotNavigation import com.arkivanov.decompose.router.slot.activate import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +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.onramp.GetOnrampCountryUseCase @@ -21,7 +21,7 @@ import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.* import javax.inject.Inject -@ComponentScoped +@ModelScoped internal class OnrampSettingsModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val analyticsEventHandler: AnalyticsEventHandler, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/di/OnrampSuccessComponentModelModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/di/OnrampSuccessComponentModelModule.kt index ba6f6664fd..59b1e6f64a 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/di/OnrampSuccessComponentModelModule.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/di/OnrampSuccessComponentModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onramp.success.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.features.onramp.success.model.OnrampSuccessComponentModel import dagger.Binds @@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface OnrampSuccessComponentModelModule { @Binds @IntoMap diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/di/AvailableSwapPairsModelModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/di/AvailableSwapPairsModelModule.kt index 6bf7c67133..b68b705703 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/di/AvailableSwapPairsModelModule.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/di/AvailableSwapPairsModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onramp.swap.availablepairs.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.features.onramp.swap.availablepairs.model.AvailableSwapPairsModel import dagger.Binds @@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface AvailableSwapPairsModelModule { @Binds diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/di/SwapSelectTokensModelModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/di/SwapSelectTokensModelModule.kt index f7e0741156..01b1201354 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/di/SwapSelectTokensModelModule.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/di/SwapSelectTokensModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onramp.swap.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.features.onramp.swap.model.SwapSelectTokensModel import dagger.Binds @@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface SwapSelectTokensModelModule { @Binds diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/di/OnrampTokenListModelModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/di/OnrampTokenListModelModule.kt index 7977384f55..0f35146dfe 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/di/OnrampTokenListModelModule.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/di/OnrampTokenListModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.features.onramp.tokenlist.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.features.onramp.tokenlist.model.OnrampTokenListModel import dagger.Binds @@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface OnrampTokenListModelModule { @Binds diff --git a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsModel.kt b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsModel.kt index 4043db3350..fb23fe3946 100644 --- a/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsModel.kt +++ b/features/push-notifications/impl/src/main/java/com/tangem/features/pushnotifications/impl/model/PushNotificationsModel.kt @@ -5,7 +5,7 @@ import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRouter import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.domain.settings.NeverRequestPermissionUseCase import com.tangem.domain.settings.NeverToInitiallyAskPermissionUseCase @@ -16,7 +16,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Stable -@ComponentScoped +@ModelScoped class PushNotificationsModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val neverRequestPermissionUseCase: NeverRequestPermissionUseCase, diff --git a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/model/QrScanningModel.kt b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/model/QrScanningModel.kt index 1ba92657ba..ce3750e0c0 100644 --- a/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/model/QrScanningModel.kt +++ b/features/qr-scanning/impl/src/main/java/com/tangem/feature/qrscanning/model/QrScanningModel.kt @@ -2,7 +2,7 @@ package com.tangem.feature.qrscanning.model import androidx.compose.runtime.Stable import com.tangem.common.routing.AppRouter -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.navigation.settings.SettingsManager @@ -23,7 +23,7 @@ import javax.inject.Inject @Suppress("LongParameterList") @Stable -@ComponentScoped +@ModelScoped internal class QrScanningModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, paramsContainer: ParamsContainer, diff --git a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/di/ReferralDomainModule.kt b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/di/ReferralDomainModule.kt index 07ec550009..4e5166e070 100644 --- a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/di/ReferralDomainModule.kt +++ b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/di/ReferralDomainModule.kt @@ -1,7 +1,7 @@ package com.tangem.feature.referral.domain.di -import com.tangem.core.decompose.di.ComponentScoped -import com.tangem.core.decompose.di.DecomposeComponent +import com.tangem.core.decompose.di.ModelScoped +import com.tangem.core.decompose.di.ModelComponent import com.tangem.domain.card.DerivePublicKeysUseCase import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase import com.tangem.domain.wallets.usecase.GetUserWalletUseCase @@ -14,11 +14,11 @@ import dagger.Provides import dagger.hilt.InstallIn @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) class ReferralDomainModule { @Provides - @ComponentScoped + @ModelScoped fun provideReferralInteractor( referralRepository: ReferralRepository, userWalletManager: UserWalletManager, diff --git a/features/referral/impl/src/main/java/com/tangem/feature/referral/model/ReferralModel.kt b/features/referral/impl/src/main/java/com/tangem/feature/referral/model/ReferralModel.kt index 621ddbe1aa..a2379d3f8a 100644 --- a/features/referral/impl/src/main/java/com/tangem/feature/referral/model/ReferralModel.kt +++ b/features/referral/impl/src/main/java/com/tangem/feature/referral/model/ReferralModel.kt @@ -6,7 +6,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import com.tangem.common.routing.AppRouter import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.navigation.share.ShareManager @@ -30,7 +30,7 @@ import javax.inject.Inject @Suppress("LongParameterList") @Stable -@ComponentScoped +@ModelScoped internal class ReferralModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/di/SendModule.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/di/SendModule.kt index da5936ec7d..86c1ce5b9f 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/di/SendModule.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/di/SendModule.kt @@ -1,7 +1,7 @@ package com.tangem.features.send.impl.di -import com.tangem.core.decompose.di.ComponentScoped -import com.tangem.core.decompose.di.DecomposeComponent +import com.tangem.core.decompose.di.ModelScoped +import com.tangem.core.decompose.di.ModelComponent import com.tangem.core.decompose.model.Model import com.tangem.features.send.api.SendComponent import com.tangem.features.send.impl.DefaultSendComponent @@ -29,10 +29,10 @@ internal interface SendModule { } @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface SendModelModule { @Binds - @ComponentScoped + @ModelScoped fun bindRouter(router: DefaultSendRouter): InnerSendRouter } \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/navigation/DefaultSendRouter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/navigation/DefaultSendRouter.kt index fabef6c208..788ea93ba2 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/navigation/DefaultSendRouter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/navigation/DefaultSendRouter.kt @@ -2,14 +2,14 @@ package com.tangem.features.send.impl.navigation import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRouter -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.navigation.url.UrlOpener import com.tangem.domain.qrscanning.models.SourceType import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId import javax.inject.Inject -@ComponentScoped +@ModelScoped internal class DefaultSendRouter @Inject constructor( private val router: AppRouter, private val urlOpener: UrlOpener, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendModel.kt index 6c91254744..91af0581fc 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendModel.kt @@ -13,7 +13,7 @@ import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary import com.tangem.common.ui.notifications.NotificationUM import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.navigation.share.ShareManager @@ -75,7 +75,7 @@ import kotlin.properties.Delegates @Suppress("LongParameterList", "TooManyFunctions", "LargeClass") @Stable -@ComponentScoped +@ModelScoped internal class SendModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val getUserWalletUseCase: GetUserWalletUseCase, diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/di/StakingModule.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/di/StakingModule.kt index c2fc6404b9..912662375d 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/di/StakingModule.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/di/StakingModule.kt @@ -1,7 +1,7 @@ package com.tangem.features.staking.impl.di -import com.tangem.core.decompose.di.ComponentScoped -import com.tangem.core.decompose.di.DecomposeComponent +import com.tangem.core.decompose.di.ModelScoped +import com.tangem.core.decompose.di.ModelComponent import com.tangem.core.decompose.model.Model import com.tangem.features.staking.api.StakingComponent import com.tangem.features.staking.impl.DefaultStakingComponent @@ -29,10 +29,10 @@ internal interface StakingModule { } @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface StakingComponentModule { @Binds - @ComponentScoped + @ModelScoped fun bindRouter(impl: DefaultStakingRouter): InnerStakingRouter } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/navigation/DefaultStakingRouter.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/navigation/DefaultStakingRouter.kt index 9a600a0a93..c149089cad 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/navigation/DefaultStakingRouter.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/navigation/DefaultStakingRouter.kt @@ -2,13 +2,13 @@ package com.tangem.features.staking.impl.navigation import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRouter -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.navigation.url.UrlOpener import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId import javax.inject.Inject -@ComponentScoped +@ModelScoped internal class DefaultStakingRouter @Inject constructor( private val urlOpener: UrlOpener, private val router: AppRouter, diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt index 846032569e..b57e0256f7 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt @@ -12,7 +12,7 @@ import com.tangem.common.ui.bottomsheet.permission.state.GiveTxPermissionBottomS import com.tangem.common.ui.notifications.NotificationUM import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.ParamsInterceptorHolder -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.navigation.share.ShareManager @@ -89,7 +89,7 @@ import kotlin.properties.Delegates @Suppress("LargeClass", "TooManyFunctions", "LongParameterList") @Stable -@ComponentScoped +@ModelScoped internal class StakingModel @Inject constructor( paramsContainer: ParamsContainer, private val stateController: StakingStateController, diff --git a/features/stories/impl/src/main/java/com/tangem/feature/stories/impl/di/StoriesModelModule.kt b/features/stories/impl/src/main/java/com/tangem/feature/stories/impl/di/StoriesModelModule.kt index de6c20e886..f686729341 100644 --- a/features/stories/impl/src/main/java/com/tangem/feature/stories/impl/di/StoriesModelModule.kt +++ b/features/stories/impl/src/main/java/com/tangem/feature/stories/impl/di/StoriesModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.feature.stories.impl.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.feature.stories.impl.model.StoriesModel import dagger.Binds @@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface StoriesModelModule { @Binds diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/di/SwapModelModule.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/di/SwapModelModule.kt index 911918e2b6..4a40e11ce5 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/di/SwapModelModule.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/di/SwapModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.feature.swap.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.feature.swap.model.SwapModel import dagger.Binds @@ -10,7 +10,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface SwapModelModule { @Binds diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt index 1207f32248..05a89386ef 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt @@ -12,7 +12,7 @@ import com.tangem.common.ui.bottomsheet.permission.state.GiveTxPermissionState.I 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.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.navigation.url.UrlOpener @@ -76,7 +76,7 @@ typealias SuccessLoadedSwapData = Map @Suppress("LongParameterList", "LargeClass") @Stable -@ComponentScoped +@ModelScoped internal class SwapModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/di/TokenDetailsModule.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/di/TokenDetailsModule.kt index a7ad3dd026..356a4c6fe4 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/di/TokenDetailsModule.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/di/TokenDetailsModule.kt @@ -1,7 +1,7 @@ package com.tangem.feature.tokendetails.di -import com.tangem.core.decompose.di.ComponentScoped -import com.tangem.core.decompose.di.DecomposeComponent +import com.tangem.core.decompose.di.ModelScoped +import com.tangem.core.decompose.di.ModelComponent import com.tangem.core.decompose.model.Model import com.tangem.feature.tokendetails.DefaultTokenDetailsComponent import com.tangem.feature.tokendetails.presentation.router.DefaultTokenDetailsRouter @@ -29,10 +29,10 @@ internal interface TokenDetailsModule { } @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface StakingComponentModule { @Binds - @ComponentScoped + @ModelScoped fun bindRouter(impl: DefaultTokenDetailsRouter): InnerTokenDetailsRouter } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/DefaultTokenDetailsRouter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/DefaultTokenDetailsRouter.kt index 4ffdf4c587..9d48197b61 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/DefaultTokenDetailsRouter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/router/DefaultTokenDetailsRouter.kt @@ -2,7 +2,7 @@ package com.tangem.feature.tokendetails.presentation.router import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRouter -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.navigation.share.ShareManager import com.tangem.core.navigation.url.UrlOpener import com.tangem.domain.staking.model.stakekit.Yield @@ -10,7 +10,7 @@ import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId import javax.inject.Inject -@ComponentScoped +@ModelScoped internal class DefaultTokenDetailsRouter @Inject constructor( private val router: AppRouter, private val urlOpener: UrlOpener, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt index 90e3f19c4d..81bc77d74f 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt @@ -10,7 +10,7 @@ import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.GlobalUiMessageSender import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer @@ -89,7 +89,7 @@ import javax.inject.Inject @Suppress("LongParameterList", "LargeClass", "TooManyFunctions") @Stable -@ComponentScoped +@ModelScoped internal class TokenDetailsModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val getCurrencyStatusUpdatesUseCase: GetCurrencyStatusUpdatesUseCase, diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/model/RenameWalletModel.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/model/RenameWalletModel.kt index 2579a58329..ea34279a52 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/model/RenameWalletModel.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/model/RenameWalletModel.kt @@ -1,7 +1,7 @@ package com.tangem.feature.walletsettings.component.impl.model import androidx.compose.ui.text.input.TextFieldValue -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.ui.UiMessageSender @@ -36,7 +36,7 @@ import javax.inject.Inject * [REDACTED_AUTHOR] */ -@ComponentScoped +@ModelScoped internal class RenameWalletModel @Inject constructor( paramsContainer: ParamsContainer, getWalletNamesUseCase: GetWalletNamesUseCase, diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsModelModule.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsModelModule.kt index 6cc2cd67eb..195e71a172 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsModelModule.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/di/WalletSettingsModelModule.kt @@ -1,6 +1,6 @@ package com.tangem.feature.walletsettings.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.feature.walletsettings.component.impl.model.RenameWalletModel import com.tangem.feature.walletsettings.model.WalletSettingsModel @@ -11,7 +11,7 @@ import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -@InstallIn(DecomposeComponent::class) +@InstallIn(ModelComponent::class) internal interface WalletSettingsModelModule { @Binds diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt index 7952d3d3a1..388279ff22 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt @@ -6,7 +6,7 @@ import com.arkivanov.decompose.router.slot.activate import com.tangem.common.routing.AppRoute import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.utils.AnalyticsContextProxy -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router @@ -40,7 +40,7 @@ import timber.log.Timber import javax.inject.Inject @Suppress("LongParameterList") -@ComponentScoped +@ModelScoped internal class WalletSettingsModel @Inject constructor( getWalletUseCase: GetUserWalletUseCase, paramsContainer: ParamsContainer, diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/ItemsBuilder.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/ItemsBuilder.kt index c6b465997b..e57d76ef57 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/ItemsBuilder.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/ItemsBuilder.kt @@ -3,7 +3,7 @@ package com.tangem.feature.walletsettings.utils import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRoute.ManageTokens.Source import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.navigation.Router import com.tangem.core.ui.components.block.model.BlockUM import com.tangem.core.ui.extensions.resourceReference @@ -17,7 +17,7 @@ import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import javax.inject.Inject -@ComponentScoped +@ModelScoped internal class ItemsBuilder @Inject constructor( private val router: Router, private val analyticsEventHandler: AnalyticsEventHandler, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/WalletFragment.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/WalletFragment.kt index d8a119f840..446d5c41bb 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/WalletFragment.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/WalletFragment.kt @@ -8,7 +8,7 @@ import com.arkivanov.decompose.defaultComponentContext import com.tangem.common.routing.AppRouter import com.tangem.common.routing.utils.asRouter 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.ui.UiMessageSender import com.tangem.core.ui.UiDependencies @@ -38,7 +38,7 @@ internal class WalletFragment : ComposeFragment() { internal lateinit var coroutineDispatcherProvider: CoroutineDispatcherProvider @Inject - internal lateinit var componentBuilder: DecomposeComponent.Builder + internal lateinit var componentBuilder: ModelComponent.Builder @Inject internal lateinit var appRouter: AppRouter From 01cd52cabdeeec2a80240af8a5bd15180522c72a Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 26 Feb 2025 22:07:46 +0300 Subject: [PATCH 34/54] Updated on 2026-08-14 --- .../main/java/com/tangem/tap/MainActivity.kt | 4 - .../tap/di/domain/AnalyticsDomainModule.kt | 4 +- .../tangem/tap/routing/utils/ChildFactory.kt | 18 ++- .../com/tangem/common/routing/AppRoute.kt | 32 +--- .../tangem/utils/coroutines/CoroutineExt.kt | 12 ++ features/wallet/api/build.gradle.kts | 4 + .../features/wallet/WalletEntryComponent.kt | 9 ++ .../wallet/navigation/WalletRouter.kt | 14 -- features/wallet/impl/build.gradle.kts | 2 - .../wallet/DefaultWalletEntryComponent.kt | 64 ++++++++ .../organizetokens/OrganizeTokensComponent.kt | 39 +++++ .../model/OrganizeTokensModel.kt} | 58 +++---- .../wallet/child/wallet/WalletComponent.kt | 84 ++++++++++ .../wallet/model/WalletModel.kt} | 79 +++++----- .../model}/WalletsUpdateActionResolver.kt | 6 +- .../model}/intents/BaseWalletClickIntents.kt | 8 +- .../model}/intents/VisaWalletIntents.kt | 12 +- .../model}/intents/WalletCardClickIntents.kt | 6 +- .../model}/intents/WalletClickIntents.kt | 16 +- .../intents/WalletContentClickIntents.kt | 29 ++-- .../WalletCurrencyActionsClickIntents.kt | 30 ++-- .../WalletPushPermissionClickIntents.kt | 12 +- .../intents/WalletWarningsClickIntents.kt | 36 ++--- .../feature/wallet/di/WalletFeatureModule.kt | 31 ++++ .../feature/wallet/di/WalletRouterModule.kt | 12 +- .../feature/wallet/navigation/WalletRoute.kt | 14 ++ .../wallet/presentation/WalletFragment.kt | 85 ----------- .../presentation/common/WalletPreviewData.kt | 4 + .../common/preview/WalletScreenPreviewData.kt | 2 +- .../deeplink/WalletDeepLinksHandler.kt | 11 +- .../router/DefaultWalletRouter.kt | 144 ++---------------- .../presentation/router/InnerWalletRouter.kt | 20 +-- .../wallet/presentation/router/WalletRoute.kt | 24 --- .../utils/TokenListAnalyticsSender.kt | 4 +- .../utils/WalletWarningsAnalyticsSender.kt | 4 +- .../utils/WalletWarningsSingleEventSender.kt | 4 +- .../domain/GetMultiWalletWarningsFactory.kt | 6 +- .../domain/GetSingleWalletWarningsFactory.kt | 6 +- .../HasSingleWalletSignedHashesUseCase.kt | 4 +- .../domain/MultiWalletTokenListStore.kt | 4 +- .../wallet/domain/OnrampStatusFactory.kt | 4 +- .../loaders/WalletContentLoaderFactory.kt | 6 +- .../loaders/WalletScreenContentLoader.kt | 6 +- .../implementors/MultiWalletContentLoader.kt | 4 +- .../MultiWalletContentLoaderFactory.kt | 6 +- .../implementors/SingleWalletContentLoader.kt | 10 +- .../SingleWalletContentLoaderFactory.kt | 6 +- .../SingleWalletWithTokenContentLoader.kt | 7 +- ...ngleWalletWithTokenContentLoaderFactory.kt | 4 +- .../implementors/VisaWalletContentLoader.kt | 2 +- .../VisaWalletContentLoaderFactory.kt | 6 +- .../wallet/state/WalletStateController.kt | 1 - .../wallet/state/model/WalletScreenState.kt | 1 - .../transformers/AddWalletTransformer.kt | 2 +- .../InitializeWalletsTransformer.kt | 3 +- .../ReinitializeWalletTransformer.kt | 2 +- .../SetBalancesAndLimitsTransformer.kt | 2 +- .../SetCryptoCurrencyActionsTransformer.kt | 2 +- .../SetExpressStatusesTransformer.kt | 2 +- .../SetRefreshStateTransformer.kt | 2 + .../transformers/SetTokenListTransformer.kt | 2 +- .../SetTxHistoryCountErrorTransformer.kt | 2 +- .../SetTxHistoryCountTransformer.kt | 2 +- .../SetTxHistoryItemsErrorTransformer.kt | 2 +- .../SetTxHistoryItemsTransformer.kt | 2 +- .../SetWalletCardDropDownItemsTransformer.kt | 2 +- .../transformers/UnlockWalletTransformer.kt | 2 +- .../MultiWalletCurrencyActionsConverter.kt | 2 +- .../SingleWalletOnrampTransactionConverter.kt | 2 +- .../converter/TokenListStateConverter.kt | 2 +- .../converter/TxHistoryItemFlowConverter.kt | 2 +- .../converter/TxHistoryItemStateConverter.kt | 2 +- .../VisaTxDetailsBottomSheetConverter.kt | 2 +- .../VisaTxHistoryItemStateConverter.kt | 2 +- .../state/utils/WalletLoadingStateFactory.kt | 2 +- .../subscribers/BasicTokenListSubscriber.kt | 2 +- .../MultiWalletTokenListSubscriber.kt | 2 +- .../MultiWalletWarningsSubscriber.kt | 2 +- .../SingleWalletButtonsSubscriber.kt | 2 +- .../SingleWalletExpressStatusesSubscriber.kt | 2 +- .../SingleWalletNotificationsSubscriber.kt | 2 +- .../SingleWalletWithTokenListSubscriber.kt | 2 +- .../wallet/subscribers/TxHistorySubscriber.kt | 2 +- .../subscribers/VisaWalletSubscriber.kt | 2 +- .../WalletDropDownItemsSubscriber.kt | 2 +- .../presentation/wallet/ui/WalletScreen.kt | 6 +- .../wallet/utils/ScreenLifecycleProvider.kt | 13 +- 87 files changed, 540 insertions(+), 564 deletions(-) create mode 100644 features/wallet/api/src/main/kotlin/com/tangem/features/wallet/WalletEntryComponent.kt delete mode 100644 features/wallet/api/src/main/kotlin/com/tangem/features/wallet/navigation/WalletRouter.kt create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/DefaultWalletEntryComponent.kt create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/OrganizeTokensComponent.kt rename features/wallet/impl/src/main/java/com/tangem/feature/wallet/{presentation/organizetokens/OrganizeTokensViewModel.kt => child/organizetokens/model/OrganizeTokensModel.kt} (85%) create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt rename features/wallet/impl/src/main/java/com/tangem/feature/wallet/{presentation/wallet/viewmodels/WalletViewModel.kt => child/wallet/model/WalletModel.kt} (89%) rename features/wallet/impl/src/main/java/com/tangem/feature/wallet/{presentation/wallet/viewmodels => child/wallet/model}/WalletsUpdateActionResolver.kt (98%) rename features/wallet/impl/src/main/java/com/tangem/feature/wallet/{presentation/wallet/viewmodels => child/wallet/model}/intents/BaseWalletClickIntents.kt (70%) rename features/wallet/impl/src/main/java/com/tangem/feature/wallet/{presentation/wallet/viewmodels => child/wallet/model}/intents/VisaWalletIntents.kt (94%) rename features/wallet/impl/src/main/java/com/tangem/feature/wallet/{presentation/wallet/viewmodels => child/wallet/model}/intents/WalletCardClickIntents.kt (96%) rename features/wallet/impl/src/main/java/com/tangem/feature/wallet/{presentation/wallet/viewmodels => child/wallet/model}/intents/WalletClickIntents.kt (95%) rename features/wallet/impl/src/main/java/com/tangem/feature/wallet/{presentation/wallet/viewmodels => child/wallet/model}/intents/WalletContentClickIntents.kt (91%) rename features/wallet/impl/src/main/java/com/tangem/feature/wallet/{presentation/wallet/viewmodels => child/wallet/model}/intents/WalletCurrencyActionsClickIntents.kt (97%) rename features/wallet/impl/src/main/java/com/tangem/feature/wallet/{presentation/wallet/viewmodels => child/wallet/model}/intents/WalletPushPermissionClickIntents.kt (89%) rename features/wallet/impl/src/main/java/com/tangem/feature/wallet/{presentation/wallet/viewmodels => child/wallet/model}/intents/WalletWarningsClickIntents.kt (94%) create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/di/WalletFeatureModule.kt create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/navigation/WalletRoute.kt delete mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/WalletFragment.kt delete mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/WalletRoute.kt diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 3e81d97a82..1a8f31b510 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -63,7 +63,6 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION -import com.tangem.features.wallet.navigation.WalletRouter import com.tangem.google.GoogleServicesHelper import com.tangem.operations.backup.BackupService import com.tangem.sdk.api.BackupServiceHolder @@ -135,9 +134,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac @Inject lateinit var scanCardUseCase: ScanCardUseCase - @Inject - lateinit var walletRouter: WalletRouter - @Inject lateinit var walletConnectInteractor: WalletConnectInteractor diff --git a/app/src/main/java/com/tangem/tap/di/domain/AnalyticsDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/AnalyticsDomainModule.kt index dda9f2c253..8e89c073b8 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/AnalyticsDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/AnalyticsDomainModule.kt @@ -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 diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index 52cf5cc8ee..d800c86164 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -19,7 +19,7 @@ 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.TokenDetailsComponent -import com.tangem.features.wallet.navigation.WalletRouter +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 @@ -73,7 +73,7 @@ internal class ChildFactory @Inject constructor( private val resetCardComponentFactory: ResetCardComponent.Factory, private val referralComponentFactory: ReferralComponent.Factory, private val pushNotificationsComponentFactory: PushNotificationsComponent.Factory, - private val walletRouter: WalletRouter, + private val walletComponentFactory: WalletEntryComponent.Factory, private val testerRouter: TesterRouter, private val routingFeatureToggles: RoutingFeatureToggles, ) { @@ -357,12 +357,18 @@ internal class ChildFactory @Inject constructor( componentFactory = pushNotificationsComponentFactory, ) } + is AppRoute.Wallet -> { + createComponentChild( + contextProvider = contextProvider(route, contextFactory), + params = Unit, + componentFactory = walletComponentFactory, + ) + } is AppRoute.SaveWallet, is AppRoute.OnboardingNote, is AppRoute.OnboardingOther, is AppRoute.OnboardingTwins, is AppRoute.OnboardingWallet, - is AppRoute.Wallet, -> error("Unsupported route: $route") } // endregion @@ -520,7 +526,11 @@ 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.asComponentChild( diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt index dddee065b7..ac6bcf3d78 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt @@ -69,15 +69,7 @@ sealed class AppRoute(val path: String) : Route { data class CurrencyDetails( val userWalletId: UserWalletId, val currency: CryptoCurrency, - ) : AppRoute(path = "/currency_details/${userWalletId.stringValue}/${currency.id.value}"), RouteBundleParams { - - override fun getBundle(): Bundle = bundle(serializer()) - - companion object { - const val USER_WALLET_ID_KEY = "userWalletId" - const val CRYPTO_CURRENCY_KEY = "currency" - } - } + ) : AppRoute(path = "/currency_details/${userWalletId.stringValue}/${currency.id.value}") @Serializable data class Send( @@ -136,17 +128,13 @@ sealed class AppRoute(val path: String) : Route { ) @Serializable - data object AccessCodeRecovery : AppRoute(path = "/access_code_recovery"), RouteBundleParams { - - override fun getBundle(): Bundle = bundle(serializer()) - } + data object AccessCodeRecovery : AppRoute(path = "/access_code_recovery") @Serializable data class ManageTokens( val source: Source, val userWalletId: UserWalletId? = null, - ) : AppRoute(path = "${source.name.lowercase()}/manage_tokens/$userWalletId"), RouteBundleParams { - override fun getBundle(): Bundle = bundle(serializer()) + ) : AppRoute(path = "${source.name.lowercase()}/manage_tokens/$userWalletId") { enum class Source { STORIES, @@ -167,14 +155,7 @@ sealed class AppRoute(val path: String) : Route { @Serializable data class ReferralProgram( val userWalletId: UserWalletId, - ) : AppRoute(path = "/referral_program"), RouteBundleParams { - - override fun getBundle(): Bundle = bundle(serializer()) - - companion object { - const val USER_WALLET_ID_KEY = "userWalletId" - } - } + ) : AppRoute(path = "/referral_program") @Serializable data class Swap( @@ -194,6 +175,7 @@ sealed class AppRoute(val path: String) : Route { @Serializable data object TesterMenu : AppRoute(path = "/tester_menu") + @Deprecated("Do not use! Should be replaced by an implementation in wallet route component") @Serializable data object SaveWallet : AppRoute(path = "/save_wallet") @@ -285,7 +267,5 @@ sealed class AppRoute(val path: String) : Route { val storyId: String, val nextScreen: AppRoute, val screenSource: String, - ) : AppRoute(path = "/stories$storyId"), RouteBundleParams { - override fun getBundle(): Bundle = bundle(serializer()) - } + ) : AppRoute(path = "/stories$storyId") } \ No newline at end of file diff --git a/core/utils/src/main/java/com/tangem/utils/coroutines/CoroutineExt.kt b/core/utils/src/main/java/com/tangem/utils/coroutines/CoroutineExt.kt index d0b50ceab4..901cf071d6 100644 --- a/core/utils/src/main/java/com/tangem/utils/coroutines/CoroutineExt.kt +++ b/core/utils/src/main/java/com/tangem/utils/coroutines/CoroutineExt.kt @@ -42,4 +42,16 @@ class Debouncer { companion object { const val DEFAULT_WAIT_TIME_MS = 500L } +} + +fun CoroutineScope.launchOnCancellation(block: suspend () -> Unit) { + launch { + try { + awaitCancellation() + } finally { + withContext(NonCancellable) { + block() + } + } + } } \ No newline at end of file diff --git a/features/wallet/api/build.gradle.kts b/features/wallet/api/build.gradle.kts index 2e8f294e46..8e523e4ddd 100644 --- a/features/wallet/api/build.gradle.kts +++ b/features/wallet/api/build.gradle.kts @@ -11,4 +11,8 @@ android { dependencies { /** AndroidX */ implementation(deps.androidx.fragment.ktx) + + /** Core */ + implementation(projects.core.ui) + implementation(projects.core.decompose) } \ No newline at end of file diff --git a/features/wallet/api/src/main/kotlin/com/tangem/features/wallet/WalletEntryComponent.kt b/features/wallet/api/src/main/kotlin/com/tangem/features/wallet/WalletEntryComponent.kt new file mode 100644 index 0000000000..51b0a3f29e --- /dev/null +++ b/features/wallet/api/src/main/kotlin/com/tangem/features/wallet/WalletEntryComponent.kt @@ -0,0 +1,9 @@ +package com.tangem.features.wallet + +import com.tangem.core.decompose.factory.ComponentFactory +import com.tangem.core.ui.decompose.ComposableContentComponent + +interface WalletEntryComponent : ComposableContentComponent { + + interface Factory : ComponentFactory +} \ No newline at end of file diff --git a/features/wallet/api/src/main/kotlin/com/tangem/features/wallet/navigation/WalletRouter.kt b/features/wallet/api/src/main/kotlin/com/tangem/features/wallet/navigation/WalletRouter.kt deleted file mode 100644 index 168bb9eca5..0000000000 --- a/features/wallet/api/src/main/kotlin/com/tangem/features/wallet/navigation/WalletRouter.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.tangem.features.wallet.navigation - -import androidx.fragment.app.Fragment - -/** - * Wallet feature router - * -[REDACTED_AUTHOR] - */ -interface WalletRouter { - - /** Get feature entry point [Fragment] */ - fun getEntryFragment(): Fragment -} \ No newline at end of file diff --git a/features/wallet/impl/build.gradle.kts b/features/wallet/impl/build.gradle.kts index 99809111b3..d36dc2c763 100644 --- a/features/wallet/impl/build.gradle.kts +++ b/features/wallet/impl/build.gradle.kts @@ -24,8 +24,6 @@ dependencies { implementation(deps.compose.foundation) implementation(deps.compose.material) implementation(deps.compose.material3) - implementation(deps.compose.navigation) - implementation(deps.compose.navigation.hilt) implementation(deps.compose.paging) implementation(deps.compose.reorderable) implementation(deps.compose.shimmer) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/DefaultWalletEntryComponent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/DefaultWalletEntryComponent.kt new file mode 100644 index 0000000000..8f32b3bfa5 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/DefaultWalletEntryComponent.kt @@ -0,0 +1,64 @@ +package com.tangem.feature.wallet + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.arkivanov.decompose.extensions.compose.jetpack.stack.Children +import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.fade +import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.stackAnimation +import com.arkivanov.decompose.router.stack.StackNavigation +import com.arkivanov.decompose.router.stack.childStack +import com.arkivanov.decompose.router.stack.pop +import com.arkivanov.decompose.router.stack.pushNew +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.decompose.context.childByContext +import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.feature.wallet.child.organizetokens.OrganizeTokensComponent +import com.tangem.feature.wallet.child.wallet.WalletComponent +import com.tangem.feature.wallet.navigation.WalletRoute +import com.tangem.features.wallet.WalletEntryComponent +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +internal class DefaultWalletEntryComponent @AssistedInject constructor( + @Assisted appComponentContext: AppComponentContext, + @Assisted params: Unit, + walletComponentFactory: WalletComponent.Factory, +) : WalletEntryComponent, AppComponentContext by appComponentContext { + + private val navigation = StackNavigation() + + private val stack = childStack( + source = navigation, + serializer = WalletRoute.serializer(), + initialConfiguration = WalletRoute.Wallet, + childFactory = { route, context -> + when (route) { + WalletRoute.Wallet -> walletComponentFactory.create( + appComponentContext = childByContext(context), + navigate = { navigation.pushNew(it) }, + ) + is WalletRoute.OrganizeTokens -> OrganizeTokensComponent( + appComponentContext = childByContext(context), + params = OrganizeTokensComponent.Params(route.userWalletId), + onBack = { navigation.pop() }, + ) + } + }, + ) + + @Composable + override fun Content(modifier: Modifier) { + Children( + stack = stack, + animation = stackAnimation(fade()), + ) { + it.instance.Content(modifier) + } + } + + @AssistedFactory + interface Factory : WalletEntryComponent.Factory { + override fun create(context: AppComponentContext, params: Unit): DefaultWalletEntryComponent + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/OrganizeTokensComponent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/OrganizeTokensComponent.kt new file mode 100644 index 0000000000..2763610e1f --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/OrganizeTokensComponent.kt @@ -0,0 +1,39 @@ +package com.tangem.feature.wallet.child.organizetokens + +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.decompose.ComposableContentComponent +import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.feature.wallet.child.organizetokens.model.OrganizeTokensModel +import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensScreen +import kotlinx.coroutines.launch + +internal class OrganizeTokensComponent( + appComponentContext: AppComponentContext, + params: Params, + onBack: () -> Unit, +) : ComposableContentComponent, AppComponentContext by appComponentContext { + + private val model: OrganizeTokensModel = getOrCreateModel(params) + + init { + componentScope.launch { + model.onBack.collect { onBack() } + } + } + + data class Params(val userWalletId: UserWalletId) + + @Composable + override fun Content(modifier: Modifier) { + val uiState by model.uiState.collectAsStateWithLifecycle() + + OrganizeTokensScreen( + state = uiState, + ) + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/model/OrganizeTokensModel.kt similarity index 85% rename from features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensViewModel.kt rename to features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/model/OrganizeTokensModel.kt index a27f15bdab..9d064cf565 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/model/OrganizeTokensModel.kt @@ -1,9 +1,12 @@ -package com.tangem.feature.wallet.presentation.organizetokens +package com.tangem.feature.wallet.child.organizetokens.model -import androidx.lifecycle.* +import androidx.compose.runtime.Stable import arrow.core.getOrElse import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam +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.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase @@ -13,24 +16,27 @@ import com.tangem.domain.tokens.GetTokenListUseCase import com.tangem.domain.tokens.ToggleTokenListGroupingUseCase import com.tangem.domain.tokens.ToggleTokenListSortingUseCase import com.tangem.domain.tokens.model.TokenList -import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.feature.wallet.child.organizetokens.OrganizeTokensComponent +import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensIntents +import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensStateHolder import com.tangem.feature.wallet.presentation.organizetokens.analytics.PortfolioOrganizeTokensAnalyticsEvent import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensListState import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensState import com.tangem.feature.wallet.presentation.organizetokens.utils.CryptoCurrenciesIdsResolver import com.tangem.feature.wallet.presentation.organizetokens.utils.common.disableSortingByBalance import com.tangem.feature.wallet.presentation.organizetokens.utils.dnd.DragAndDropAdapter -import com.tangem.feature.wallet.presentation.router.InnerWalletRouter -import com.tangem.feature.wallet.presentation.router.WalletRoute import com.tangem.utils.Provider -import dagger.hilt.android.lifecycle.HiltViewModel +import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import javax.inject.Inject @Suppress("LongParameterList") -@HiltViewModel -internal class OrganizeTokensViewModel @Inject constructor( +@Stable +@ModelScoped +internal class OrganizeTokensModel @Inject constructor( + paramsContainer: ParamsContainer, + override val dispatchers: CoroutineDispatcherProvider, private val getTokenListUseCase: GetTokenListUseCase, private val toggleTokenListGroupingUseCase: ToggleTokenListGroupingUseCase, private val toggleTokenListSortingUseCase: ToggleTokenListSortingUseCase, @@ -38,10 +44,7 @@ internal class OrganizeTokensViewModel @Inject constructor( private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, private val analyticsEventsHandler: AnalyticsEventHandler, - savedStateHandle: SavedStateHandle, -) : ViewModel(), DefaultLifecycleObserver, OrganizeTokensIntents { - - lateinit var router: InnerWalletRouter +) : Model(), OrganizeTokensIntents { private val selectedAppCurrencyFlow = createSelectedAppCurrencyFlow() @@ -57,33 +60,30 @@ internal class OrganizeTokensViewModel @Inject constructor( appCurrencyProvider = Provider(selectedAppCurrencyFlow::value), ) - private val userWalletId: UserWalletId by lazy { - val userWalletIdValue: String = checkNotNull(savedStateHandle[WalletRoute.userWalletIdKey]) - - UserWalletId(userWalletIdValue) - } + private val userWalletId = paramsContainer.require().userWalletId private var cachedTokenList: TokenList? = null val uiState: StateFlow = stateHolder.stateFlow - override fun onCreate(owner: LifecycleOwner) { + val onBack = MutableSharedFlow() + + init { analyticsEventsHandler.send(PortfolioOrganizeTokensAnalyticsEvent.ScreenOpened) getBalanceHidingSettingsUseCase() - .flowWithLifecycle(owner.lifecycle) .onEach { isBalanceHidden = it.isBalanceHidden stateHolder.updateHiddenState(isBalanceHidden) } - .launchIn(viewModelScope) + .launchIn(modelScope) bootstrapTokenList() bootstrapDragAndDropUpdates() } override fun onBackClick() { - router.popBackStack() + modelScope.launch { onBack.emit(Unit) } } override fun onSortClick() { @@ -92,7 +92,7 @@ internal class OrganizeTokensViewModel @Inject constructor( analyticsEventsHandler.send(PortfolioOrganizeTokensAnalyticsEvent.ByBalance) - viewModelScope.launch { + modelScope.launch { toggleTokenListSortingUseCase(list).fold( ifLeft = stateHolder::updateStateWithError, ifRight = { @@ -108,7 +108,7 @@ internal class OrganizeTokensViewModel @Inject constructor( analyticsEventsHandler.send(PortfolioOrganizeTokensAnalyticsEvent.Group) - viewModelScope.launch { + modelScope.launch { toggleTokenListGroupingUseCase(list).fold( ifLeft = stateHolder::updateStateWithError, ifRight = { @@ -120,7 +120,7 @@ internal class OrganizeTokensViewModel @Inject constructor( } override fun onApplyClick() { - viewModelScope.launch { + modelScope.launch { stateHolder.updateStateToDisplayProgress() val listState = uiState.value.itemsState @@ -144,7 +144,7 @@ internal class OrganizeTokensViewModel @Inject constructor( result.fold( ifLeft = stateHolder::updateStateWithError, ifRight = { - router.popBackStack() + modelScope.launch { onBack.emit(Unit) } stateHolder.updateStateToHideProgress() }, ) @@ -154,11 +154,11 @@ internal class OrganizeTokensViewModel @Inject constructor( override fun onCancelClick() { analyticsEventsHandler.send(PortfolioOrganizeTokensAnalyticsEvent.Cancel) - router.popBackStack() + modelScope.launch { onBack.emit(Unit) } } private fun bootstrapTokenList() { - viewModelScope.launch { + modelScope.launch { val tokenList = getTokenList() ?: return@launch stateHolder.updateStateWithTokenList(tokenList) @@ -192,7 +192,7 @@ internal class OrganizeTokensViewModel @Inject constructor( stateHolder.updateStateWithManualSorting(updatedListState) } - .launchIn(viewModelScope) + .launchIn(modelScope) } private fun disableSortingByBalanceIfListChanged(dragOperationType: DragAndDropAdapter.DragOperation.Type) { @@ -210,7 +210,7 @@ internal class OrganizeTokensViewModel @Inject constructor( maybeAppCurrency.getOrElse { AppCurrency.Default } } .stateIn( - scope = viewModelScope, + scope = modelScope, started = SharingStarted.Eagerly, initialValue = AppCurrency.Default, ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt new file mode 100644 index 0000000000..6a00429983 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt @@ -0,0 +1,84 @@ +package com.tangem.feature.wallet.child.wallet + +import androidx.activity.compose.BackHandler +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState +import com.arkivanov.decompose.router.slot.childSlot +import com.arkivanov.decompose.router.slot.dismiss +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.decompose.context.child +import com.tangem.core.decompose.context.childByContext +import com.tangem.core.decompose.model.getOrCreateModel +import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.core.ui.utils.findActivity +import com.tangem.feature.wallet.child.wallet.model.WalletModel +import com.tangem.feature.wallet.navigation.WalletRoute +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDialogConfig +import com.tangem.feature.wallet.presentation.wallet.ui.WalletScreen +import com.tangem.feature.walletsettings.component.RenameWalletComponent +import com.tangem.features.markets.entry.MarketsEntryComponent +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.launch + +internal class WalletComponent @AssistedInject constructor( + @Assisted appComponentContext: AppComponentContext, + @Assisted navigate: (WalletRoute) -> Unit, + private val renameWalletComponentFactory: RenameWalletComponent.Factory, + private val marketsEntryComponentFactory: MarketsEntryComponent.Factory, +) : ComposableContentComponent, AppComponentContext by appComponentContext { + + private val model: WalletModel = getOrCreateModel() + + init { + lifecycle.subscribe(model.screenLifecycleProvider) + componentScope.launch { model.innerWalletRouter.navigateToFlow.collect { navigate(it) } } + } + + private val dialog = childSlot( + source = model.innerWalletRouter.dialogNavigation, + serializer = WalletDialogConfig.serializer(), + handleBackButton = true, + childFactory = { dialogConfig, componentContext -> + when (dialogConfig) { + is WalletDialogConfig.RenameWallet -> { + renameWalletComponentFactory.create( + context = childByContext(componentContext), + params = RenameWalletComponent.Params( + userWalletId = dialogConfig.userWalletId, + currentName = dialogConfig.currentName, + onDismiss = model.innerWalletRouter.dialogNavigation::dismiss, + ), + ) + } + } + }, + ) + + private val marketsEntryComponent = marketsEntryComponentFactory.create(child("marketsEntryComponent")) + + @Composable + override fun Content(modifier: Modifier) { + val activity = LocalContext.current.findActivity() + BackHandler { activity.finish() } + + val dialog by dialog.subscribeAsState() + + WalletScreen( + state = model.uiState.collectAsStateWithLifecycle().value, + marketsEntryComponent = marketsEntryComponent, + ) + + dialog.child?.instance?.Dialog() + } + + @AssistedFactory + interface Factory { + fun create(appComponentContext: AppComponentContext, navigate: (WalletRoute) -> Unit): WalletComponent + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt similarity index 89% rename from features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt rename to features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt index 1ddf2fdb9b..044aaec8c6 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt @@ -1,17 +1,17 @@ -package com.tangem.feature.wallet.presentation.wallet.viewmodels +package com.tangem.feature.wallet.child.wallet.model import androidx.compose.runtime.Stable -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope import arrow.core.getOrElse 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.balancehiding.GetBalanceHidingSettingsUseCase import com.tangem.domain.settings.* import com.tangem.domain.tokens.RefreshMultiCurrencyWalletQuotesUseCase import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase import com.tangem.domain.wallets.usecase.GetWalletsUseCase +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.deeplink.WalletDeepLinksHandler import com.tangem.feature.wallet.presentation.router.InnerWalletRouter import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent @@ -29,13 +29,11 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenSta import com.tangem.feature.wallet.presentation.wallet.state.transformers.* import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION import com.tangem.features.pushnotifications.api.utils.getPushPermissionOrNull import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles import com.tangem.utils.Provider import com.tangem.utils.coroutines.* -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch @@ -45,8 +43,9 @@ import javax.inject.Inject @Suppress("LongParameterList", "LargeClass") @Stable -@HiltViewModel -internal class WalletViewModel @Inject constructor( +@ModelScoped +internal class WalletModel @Inject constructor( + override val dispatchers: CoroutineDispatcherProvider, private val stateHolder: WalletStateController, private val clickIntents: WalletClickIntents, private val walletEventSender: WalletEventSender, @@ -59,8 +58,6 @@ internal class WalletViewModel @Inject constructor( private val canUseBiometryUseCase: CanUseBiometryUseCase, private val isWalletsScrollPreviewEnabled: IsWalletsScrollPreviewEnabled, private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, - private val dispatchers: CoroutineDispatcherProvider, - private val screenLifecycleProvider: ScreenLifecycleProvider, private val selectedWalletAnalyticsSender: SelectedWalletAnalyticsSender, private val walletDeepLinksHandler: WalletDeepLinksHandler, private val walletNameMigrationUseCase: WalletNameMigrationUseCase, @@ -70,12 +67,13 @@ internal class WalletViewModel @Inject constructor( private val tokenListStore: MultiWalletTokenListStore, private val onrampStatusFactory: OnrampStatusFactory, private val walletFeatureToggles: WalletFeatureToggles, + val screenLifecycleProvider: ScreenLifecycleProvider, + val innerWalletRouter: InnerWalletRouter, analyticsEventsHandler: AnalyticsEventHandler, -) : ViewModel() { +) : Model() { val uiState: StateFlow = stateHolder.uiState - private lateinit var router: InnerWalletRouter private val walletsUpdateJobHolder = JobHolder() private val refreshWalletJobHolder = JobHolder() private val expressStatusJobHolder = JobHolder() @@ -96,25 +94,18 @@ internal class WalletViewModel @Inject constructor( subscribeToScreenBackgroundState() subscribeOnPushNotificationsPermission() subscribeOnExpressTransactionsUpdates() + + clickIntents.initialize(innerWalletRouter, modelScope) } private fun maybeMigrateNames() { - viewModelScope.launch { + modelScope.launch { walletNameMigrationUseCase() } } - fun setWalletRouter(router: InnerWalletRouter) { - this.router = router - clickIntents.initialize(router, viewModelScope) - } - - fun subscribeToLifecycle(lifecycleOwner: LifecycleOwner) { - lifecycleOwner.lifecycle.addObserver(screenLifecycleProvider) - } - - override fun onCleared() { - super.onCleared() + override fun onDestroy() { + super.onDestroy() tokenListStore.clear() stateHolder.clear() @@ -122,15 +113,15 @@ internal class WalletViewModel @Inject constructor( } private fun suggestToEnableBiometrics() { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { withContext(dispatchers.io) { delay(timeMillis = 1_800) } - if (isShowSaveWalletScreenEnabled()) router.openSaveUserWalletScreen() + if (isShowSaveWalletScreenEnabled()) innerWalletRouter.openSaveUserWalletScreen() } } private fun suggestToOpenMarkets() { - viewModelScope.launch { + modelScope.launch { withContext(dispatchers.io) { delay(timeMillis = 1_800) } if (shouldShowMarketsTooltipUseCase()) { @@ -144,7 +135,7 @@ internal class WalletViewModel @Inject constructor( } private suspend fun isShowSaveWalletScreenEnabled(): Boolean { - return router.isWalletLastScreen() && shouldShowSaveWalletScreenUseCase() && canUseBiometryUseCase() + return innerWalletRouter.isWalletLastScreen() && shouldShowSaveWalletScreenUseCase() && canUseBiometryUseCase() } private fun subscribeToUserWalletsUpdates() { @@ -156,7 +147,7 @@ internal class WalletViewModel @Inject constructor( } .onEach(::updateWallets) .flowOn(dispatchers.main) - .launchIn(viewModelScope) + .launchIn(modelScope) .saveIn(walletsUpdateJobHolder) } @@ -168,11 +159,11 @@ internal class WalletViewModel @Inject constructor( stateHolder.update(transformer = UpdateBalanceHidingModeTransformer(it.isBalanceHidden)) } .flowOn(dispatchers.main) - .launchIn(viewModelScope) + .launchIn(modelScope) } private fun subscribeOnPushNotificationsPermission() { - viewModelScope.launch { + modelScope.launch { val shouldRequestPush = shouldAskPermissionUseCase(PUSH_PERMISSION) val isPushPermissionAvailable = getPushPermissionOrNull() != null if (!shouldRequestPush || !isPushPermissionAvailable) return@launch @@ -203,10 +194,10 @@ internal class WalletViewModel @Inject constructor( selectedWalletAnalyticsSender.send(selectedWallet) } - walletDeepLinksHandler.registerForWallet(viewModel = this, userWallet = selectedWallet) + walletDeepLinksHandler.registerForWallet(scope = modelScope, userWallet = selectedWallet) } .flowOn(dispatchers.main) - .launchIn(viewModelScope) + .launchIn(modelScope) } } @@ -227,14 +218,14 @@ internal class WalletViewModel @Inject constructor( !isBackground -> subscribeOnExpressTransactionsUpdates() } } - .launchIn(viewModelScope) + .launchIn(modelScope) } private fun subscribeOnExpressTransactionsUpdates() { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { expressTxStatusTaskScheduler.cancelTask() expressTxStatusTaskScheduler.scheduleTask( - viewModelScope, + modelScope, PeriodicTask( isDelayFirst = false, delay = EXPRESS_STATUS_UPDATE_DELAY, @@ -249,7 +240,7 @@ internal class WalletViewModel @Inject constructor( } private fun needToRefreshTimer() { - viewModelScope.launch { + modelScope.launch { delay(REFRESH_WALLET_BACKGROUND_TIMER_MILLIS) needToRefreshWallet = true }.saveIn(refreshWalletJobHolder) @@ -259,7 +250,7 @@ internal class WalletViewModel @Inject constructor( needToRefreshWallet = false val state = stateHolder.uiState.value val wallet = state.wallets.getOrNull(state.selectedWalletIndex) ?: return - viewModelScope.launch { + modelScope.launch { refreshMultiCurrencyWalletQuotesUseCase(wallet.walletCardState.id).getOrElse { Timber.e("Failed to refreshMultiCurrencyWalletQuotesUseCase $it") } @@ -279,7 +270,7 @@ internal class WalletViewModel @Inject constructor( userWallet = action.selectedWallet, clickIntents = clickIntents, isRefresh = true, - coroutineScope = viewModelScope, + coroutineScope = modelScope, ) stateHolder.update( @@ -312,7 +303,7 @@ internal class WalletViewModel @Inject constructor( walletScreenContentLoader.load( userWallet = action.selectedWallet, clickIntents = clickIntents, - coroutineScope = viewModelScope, + coroutineScope = modelScope, ) if (action.wallets.size > 1 && isWalletsScrollPreviewEnabled()) { @@ -337,7 +328,7 @@ internal class WalletViewModel @Inject constructor( walletScreenContentLoader.load( userWallet = action.selectedWallet, clickIntents = clickIntents, - coroutineScope = viewModelScope, + coroutineScope = modelScope, ) stateHolder.update( @@ -355,7 +346,7 @@ internal class WalletViewModel @Inject constructor( walletScreenContentLoader.load( userWallet = action.selectedWallet, clickIntents = clickIntents, - coroutineScope = viewModelScope, + coroutineScope = modelScope, ) stateHolder.update( @@ -381,7 +372,7 @@ internal class WalletViewModel @Inject constructor( walletScreenContentLoader.load( userWallet = action.selectedWallet, clickIntents = clickIntents, - coroutineScope = viewModelScope, + coroutineScope = modelScope, ) val newSelectedWalletIndex = if (action.selectedWalletIndex - action.deletedWalletIndex == 1) { @@ -439,7 +430,7 @@ internal class WalletViewModel @Inject constructor( walletScreenContentLoader.load( userWallet = action.selectedWallet, clickIntents = clickIntents, - coroutineScope = viewModelScope, + coroutineScope = modelScope, ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletsUpdateActionResolver.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletsUpdateActionResolver.kt similarity index 98% rename from features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletsUpdateActionResolver.kt rename to features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletsUpdateActionResolver.kt index 97073d4a82..5594553aab 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletsUpdateActionResolver.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletsUpdateActionResolver.kt @@ -1,6 +1,7 @@ -package com.tangem.feature.wallet.presentation.wallet.viewmodels +package com.tangem.feature.wallet.child.wallet.model import arrow.core.getOrElse +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.common.util.getCardsCount import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId @@ -9,7 +10,6 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.NOT_INITIALIZED import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState -import dagger.hilt.android.scopes.ViewModelScoped import timber.log.Timber import javax.inject.Inject @@ -18,7 +18,7 @@ import javax.inject.Inject * * @property getSelectedWalletSyncUseCase use case that returns selected wallet */ -@ViewModelScoped +@ModelScoped internal class WalletsUpdateActionResolver @Inject constructor( private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, ) { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/BaseWalletClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/BaseWalletClickIntents.kt similarity index 70% rename from features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/BaseWalletClickIntents.kt rename to features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/BaseWalletClickIntents.kt index d9be6984f5..d4e874fc9a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/BaseWalletClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/BaseWalletClickIntents.kt @@ -1,4 +1,4 @@ -package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents +package com.tangem.feature.wallet.child.wallet.model.intents import com.tangem.feature.wallet.presentation.router.InnerWalletRouter import kotlinx.coroutines.CoroutineScope @@ -14,13 +14,13 @@ import kotlin.properties.Delegates internal abstract class BaseWalletClickIntents { protected val router: InnerWalletRouter get() = _router - protected val viewModelScope: CoroutineScope get() = _viewModelScope + protected val modelScope: CoroutineScope get() = _modelScope private var _router: InnerWalletRouter by Delegates.notNull() - private var _viewModelScope: CoroutineScope by Delegates.notNull() + private var _modelScope: CoroutineScope by Delegates.notNull() open fun initialize(router: InnerWalletRouter, coroutineScope: CoroutineScope) { _router = router - _viewModelScope = coroutineScope + _modelScope = coroutineScope } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/VisaWalletIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/VisaWalletIntents.kt similarity index 94% rename from features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/VisaWalletIntents.kt rename to features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/VisaWalletIntents.kt index f93d82366d..4a0281d436 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/VisaWalletIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/VisaWalletIntents.kt @@ -1,6 +1,7 @@ -package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents +package com.tangem.feature.wallet.child.wallet.model.intents import arrow.core.getOrElse +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBottomSheetConfig import com.tangem.core.ui.components.bottomsheets.tokenreceive.mapToAddressModels @@ -15,7 +16,6 @@ import com.tangem.feature.wallet.presentation.wallet.state.transformers.converte import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.VisaTxDetailsBottomSheetConverter import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import dagger.hilt.android.scopes.ViewModelScoped import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.launch import timber.log.Timber @@ -32,7 +32,7 @@ internal interface VisaWalletIntents { fun onExploreClick(exploreUrl: String) } -@ViewModelScoped +@ModelScoped internal class VisaWalletIntentsImplementor @Inject constructor( private val stateController: WalletStateController, private val eventSender: WalletEventSender, @@ -49,7 +49,7 @@ internal class VisaWalletIntentsImplementor @Inject constructor( override fun onDepositClick() { val userWalletId = stateController.getSelectedWalletId() - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { val currencyStatus = getPrimaryCurrencyStatus(userWalletId) ?: return@launch createReceiveBottomSheetContent(currencyStatus)?.let { content -> @@ -79,7 +79,7 @@ internal class VisaWalletIntentsImplementor @Inject constructor( } override fun onBalancesAndLimitsClick() { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { val userWalletId = stateController.getSelectedWalletId() val balancesAndLimits = getVisaCurrencyUseCase(userWalletId) .getOrElse { @@ -104,7 +104,7 @@ internal class VisaWalletIntentsImplementor @Inject constructor( } override fun onVisaTransactionClick(id: String) { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { val userWalletId = stateController.getSelectedWalletId() val visaCurrency = getVisaCurrencyUseCase(userWalletId) .getOrElse { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCardClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCardClickIntents.kt similarity index 96% rename from features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCardClickIntents.kt rename to features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCardClickIntents.kt index 622afd1151..fcabcee5ad 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCardClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCardClickIntents.kt @@ -1,10 +1,11 @@ -package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents +package com.tangem.feature.wallet.child.wallet.model.intents import arrow.core.getOrElse import com.arkivanov.decompose.router.slot.activate import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRouter import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.card.DeleteSavedAccessCodesUseCase import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.wallets.models.UserWalletId @@ -35,6 +36,7 @@ internal interface WalletCardClickIntents { // TODO: Refactor @Suppress("LongParameterList") +@ModelScoped internal class WalletCardClickIntentsImplementor @Inject constructor( private val stateHolder: WalletStateController, private val tokenListStore: MultiWalletTokenListStore, @@ -74,7 +76,7 @@ internal class WalletCardClickIntentsImplementor @Inject constructor( } override fun onDeleteAfterConfirmationClick(userWalletId: UserWalletId) { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { walletScreenContentLoader.cancel(userWalletId) tokenListStore.remove(userWalletId) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletClickIntents.kt similarity index 95% rename from features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletClickIntents.kt rename to features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletClickIntents.kt index 289e9a955d..e84eccf060 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletClickIntents.kt @@ -1,5 +1,6 @@ -package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents +package com.tangem.feature.wallet.child.wallet.model.intents +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.extenstions.unwrap import com.tangem.domain.common.util.cardTypesResolver @@ -21,7 +22,6 @@ import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetRefre import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTokenListErrorTransformer import com.tangem.features.onramp.OnrampFeatureToggles import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import dagger.hilt.android.scopes.ViewModelScoped import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll @@ -29,7 +29,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @Suppress("LongParameterList") -@ViewModelScoped +@ModelScoped internal class WalletClickIntents @Inject constructor( private val walletCardClickIntentsImplementor: WalletCardClickIntentsImplementor, private val warningsClickIntentsImplementer: WalletWarningsClickIntentsImplementor, @@ -75,7 +75,7 @@ internal class WalletClickIntents @Inject constructor( return } - viewModelScope.launch { + modelScope.launch { launch { neverToShowWalletsScrollPreview() } val maybeUserWallet = selectWalletUseCase( @@ -88,7 +88,7 @@ internal class WalletClickIntents @Inject constructor( walletScreenContentLoader.load( userWallet = it, clickIntents = this@WalletClickIntents, - coroutineScope = viewModelScope, + coroutineScope = modelScope, ) } } @@ -123,7 +123,7 @@ internal class WalletClickIntents @Inject constructor( SetRefreshStateTransformer(userWalletId = userWallet.walletId, isRefreshing = showRefreshState), ) - viewModelScope.launch { + modelScope.launch { val maybeFetchResult = if (userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()) { fetchCardTokenListUseCase(userWalletId = userWallet.walletId, refresh = true) } else { @@ -168,14 +168,14 @@ internal class WalletClickIntents @Inject constructor( SetRefreshStateTransformer(userWalletId = userWallet.walletId, isRefreshing = showRefreshState), ) - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { fetchCurrencyStatusUseCase(userWallet.walletId, refresh = true) walletScreenContentLoader.load( userWallet = userWallet, clickIntents = this@WalletClickIntents, isRefresh = true, - coroutineScope = viewModelScope, + coroutineScope = modelScope, ) stateHolder.update( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletContentClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt similarity index 91% rename from features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletContentClickIntents.kt rename to features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt index 3d00a7564b..90fdd5b760 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletContentClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt @@ -1,7 +1,8 @@ -package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents +package com.tangem.feature.wallet.child.wallet.model.intents import arrow.core.getOrElse import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.settings.ShouldShowMarketsTooltipUseCase import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase @@ -16,15 +17,11 @@ import com.tangem.feature.wallet.presentation.wallet.domain.OnrampStatusFactory import com.tangem.feature.wallet.presentation.wallet.domain.unwrap import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.model.* -import com.tangem.feature.wallet.presentation.wallet.state.model.ActionsBottomSheetConfig -import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent -import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState import com.tangem.feature.wallet.presentation.wallet.state.transformers.CloseBottomSheetTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.OpenBottomSheetTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.MultiWalletCurrencyActionsConverter import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import dagger.hilt.android.scopes.ViewModelScoped import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.take import kotlinx.coroutines.launch @@ -33,8 +30,6 @@ import javax.inject.Inject internal interface WalletContentClickIntents { - fun onBackClick() - fun onDetailsClick() fun onManageTokensClick() @@ -53,7 +48,7 @@ internal interface WalletContentClickIntents { fun onDissmissBottomSheet() - fun onGoToProviderClick(externalTxId: String) + fun onGoToProviderClick(externalTxUrl: String) fun onExpressTransactionClick(txId: String) @@ -63,7 +58,7 @@ internal interface WalletContentClickIntents { } @Suppress("LongParameterList") -@ViewModelScoped +@ModelScoped internal class WalletContentClickIntentsImplementor @Inject constructor( private val stateHolder: WalletStateController, private val currencyActionsClickIntents: WalletCurrencyActionsClickIntentsImplementor, @@ -79,10 +74,8 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( private val walletEventSender: WalletEventSender, ) : BaseWalletClickIntents(), WalletContentClickIntents { - override fun onBackClick() = router.popBackStack() - override fun onDetailsClick() { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { val userWalletId = stateHolder.getSelectedWalletId() val userWallet = getUserWalletUseCase(userWalletId).getOrElse { Timber.e( @@ -124,7 +117,7 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( override fun onDismissMarketsOnboarding() { stateHolder.update { it.copy(showMarketsOnboarding = false) } - viewModelScope.launch { + modelScope.launch { shouldShowMarketsTooltipUseCase(isShown = true) } } @@ -134,7 +127,7 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( } override fun onTokenItemLongClick(cryptoCurrencyStatus: CryptoCurrencyStatus) { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { val userWalletId = stateHolder.getSelectedWalletId() val userWallet = getUserWalletUseCase(userWalletId).getOrElse { Timber.e( @@ -169,7 +162,7 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( } override fun onTransactionClick(txHash: String) { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { val currency = getPrimaryCurrencyStatusUpdatesUseCase.unwrap( userWalletId = stateHolder.getSelectedWalletId(), ) @@ -191,7 +184,7 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( override fun onDissmissBottomSheet() { val userWalletId = stateHolder.getSelectedWalletId() if (stateHolder.getSelectedWallet().bottomSheetConfig?.content is ExpressStatusBottomSheetConfig) { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { onrampStatusFactory.removeTransactionOnBottomSheetClosed(forceDispose = false) } } @@ -199,7 +192,7 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( } override fun onExpressTransactionClick(txId: String) { - viewModelScope.launch { + modelScope.launch { val userWalletId = stateHolder.getSelectedWalletId() val singleWalletState = stateHolder.getSelectedWallet() as? WalletState.SingleCurrency.Content ?: return@launch @@ -236,7 +229,7 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( override fun onDisposeExpressStatus() { val userWalletId = stateHolder.getSelectedWalletId() if (stateHolder.getSelectedWallet().bottomSheetConfig?.content is ExpressStatusBottomSheetConfig) { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { onrampStatusFactory.removeTransactionOnBottomSheetClosed(forceDispose = true) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCurrencyActionsClickIntents.kt similarity index 97% rename from features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt rename to features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCurrencyActionsClickIntents.kt index 47b8fc42ec..63b1330e09 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCurrencyActionsClickIntents.kt @@ -1,4 +1,4 @@ -package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents +package com.tangem.feature.wallet.child.wallet.model.intents import com.tangem.blockchain.common.address.AddressType import com.tangem.common.routing.AppRoute @@ -7,6 +7,7 @@ import com.tangem.common.ui.tokens.getUnavailabilityReasonText import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.navigation.share.ShareManager import com.tangem.core.ui.clipboard.ClipboardManager import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent @@ -55,7 +56,6 @@ import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSend import com.tangem.features.onramp.OnrampFeatureToggles import com.tangem.features.swap.SwapFeatureToggles import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import dagger.hilt.android.scopes.ViewModelScoped import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.firstOrNull @@ -101,7 +101,7 @@ interface WalletCurrencyActionsClickIntents { } @Suppress("LongParameterList", "LargeClass") -@ViewModelScoped +@ModelScoped internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( private val stateHolder: WalletStateController, private val walletEventSender: WalletEventSender, @@ -205,7 +205,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( event = TokenScreenAnalyticsEvent.ButtonCopyAddress(cryptoCurrencyStatus.currency.symbol), ) - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { walletManagersFacade.getDefaultAddress( userWalletId = stateHolder.getSelectedWalletId(), network = cryptoCurrencyStatus.currency.network, @@ -223,7 +223,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( event = TokenScreenAnalyticsEvent.ButtonRemoveToken(cryptoCurrencyStatus.currency.symbol), ) - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { walletEventSender.send( event = WalletEvent.ShowAlert( state = getHideTokeAlertConfig(stateHolder.getSelectedWalletId(), cryptoCurrencyStatus), @@ -270,7 +270,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( override fun onPerformHideToken(cryptoCurrencyStatus: CryptoCurrencyStatus) { val userWalletId = stateHolder.getSelectedWalletId() - viewModelScope.launch(dispatchers.io) { + modelScope.launch(dispatchers.io) { removeCurrencyUseCase(userWalletId, cryptoCurrencyStatus.currency) .fold( ifLeft = { @@ -296,7 +296,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( if (handleUnavailabilityReason(unavailabilityReason)) return showErrorIfDemoModeOrElse { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { reduxStateHolder.dispatch( action = TradeCryptoAction.Sell( cryptoCurrencyStatus = cryptoCurrencyStatus, @@ -329,7 +329,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( ) } else { showErrorIfDemoModeOrElse { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { reduxStateHolder.dispatch( TradeCryptoAction.Buy( userWallet = userWallet, @@ -368,7 +368,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( } override fun onAnalyticsClick(cryptoCurrencyStatus: CryptoCurrencyStatus) { - viewModelScope.launch { + modelScope.launch { val rawId = cryptoCurrencyStatus.currency.id.rawCurrencyId ?: return@launch val tokenMarketParams = TokenMarketParams( @@ -401,7 +401,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return stateHolder.update(CloseBottomSheetTransformer(userWalletId = userWallet.walletId)) - viewModelScope.launch { + modelScope.launch { val userWalletId = stateHolder.getSelectedWalletId() val cryptoCurrency = cryptoCurrencyStatus.currency @@ -436,7 +436,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( return } - viewModelScope.launch { + modelScope.launch { val swapRoute = getSwapRoute( AppRoute.SwapCrypto(userWalletId = userWalletId), ) @@ -463,7 +463,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( private fun openExplorer() { val userWalletId = stateHolder.getSelectedWalletId() - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { val currencyStatus = getPrimaryCurrencyStatusUpdatesUseCase.unwrap(userWalletId) ?: return@launch when (val addresses = currencyStatus.value.networkAddress) { @@ -509,7 +509,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( currency: CryptoCurrency, addressModel: AddressModel, ) { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { router.openUrl( url = getExploreUrlUseCase( userWalletId = userWalletId, @@ -543,7 +543,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( private fun handleUnavailabilityReason(unavailabilityReason: ScenarioUnavailabilityReason): Boolean { if (unavailabilityReason == ScenarioUnavailabilityReason.None) return false - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { walletEventSender.send( event = WalletEvent.ShowAlert( state = WalletAlertState.DefaultAlert( @@ -563,7 +563,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( route: AppRoute, eventCreator: (AnalyticsParam.Status) -> MainScreenAnalyticsEvent, ) { - viewModelScope.launch { + modelScope.launch { statusFlow.foldStatus( onContent = { handleContent(route, eventCreator) }, onError = { handleError(eventCreator = eventCreator) }, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletPushPermissionClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletPushPermissionClickIntents.kt similarity index 89% rename from features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletPushPermissionClickIntents.kt rename to features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletPushPermissionClickIntents.kt index 98560342e5..6c576964f8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletPushPermissionClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletPushPermissionClickIntents.kt @@ -1,11 +1,11 @@ -package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents +package com.tangem.feature.wallet.child.wallet.model.intents import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.settings.NeverRequestPermissionUseCase import com.tangem.features.pushnotifications.api.analytics.PushNotificationAnalyticEvents import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION -import dagger.hilt.android.scopes.ViewModelScoped import kotlinx.coroutines.launch import javax.inject.Inject @@ -20,7 +20,7 @@ internal interface WalletPushPermissionClickIntents { fun onAllowPushPermission() } -@ViewModelScoped +@ModelScoped internal class WalletPushPermissionClickIntentsImplementor @Inject constructor( private val neverRequestPermissionUseCase: NeverRequestPermissionUseCase, private val analyticsEventHandler: AnalyticsEventHandler, @@ -36,7 +36,7 @@ internal class WalletPushPermissionClickIntentsImplementor @Inject constructor( override fun onNeverAskPushPermission(isUserDismissed: Boolean) { if (isUserDismissedDialog != isUserDismissed) return - viewModelScope.launch { + modelScope.launch { analyticsEventHandler.send( PushNotificationAnalyticEvents.ButtonLater(AnalyticsParam.ScreensSources.Main), ) @@ -46,14 +46,14 @@ internal class WalletPushPermissionClickIntentsImplementor @Inject constructor( override fun onDenyPushPermission() { analyticsEventHandler.send(PushNotificationAnalyticEvents.PermissionStatus(isAllowed = false)) - viewModelScope.launch { + modelScope.launch { neverRequestPermissionUseCase(PUSH_PERMISSION) } } override fun onAllowPushPermission() { analyticsEventHandler.send(PushNotificationAnalyticEvents.PermissionStatus(isAllowed = true)) - viewModelScope.launch { + modelScope.launch { neverRequestPermissionUseCase(PUSH_PERMISSION) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt similarity index 94% rename from features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt rename to features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt index 6926361876..0b83df64af 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt @@ -1,9 +1,10 @@ -package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents +package com.tangem.feature.wallet.child.wallet.model.intents import arrow.core.getOrElse import com.tangem.common.TangemBlogUrlBuilder import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.navigation.url.UrlOpener import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.card.DerivePublicKeysUseCase @@ -38,7 +39,6 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent import com.tangem.feature.wallet.presentation.wallet.state.transformers.CloseBottomSheetTransformer import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import dagger.hilt.android.scopes.ViewModelScoped import kotlinx.coroutines.launch import timber.log.Timber import javax.inject.Inject @@ -81,7 +81,7 @@ internal interface WalletWarningsClickIntents { } @Suppress("LongParameterList") -@ViewModelScoped +@ModelScoped internal class WalletWarningsClickIntentsImplementor @Inject constructor( private val stateHolder: WalletStateController, private val walletEventSender: WalletEventSender, @@ -110,7 +110,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( } private fun prepareAndStartOnboardingProcess() { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { getSelectedUserWallet()?.let { reduxStateHolder.dispatch( LegacyAction.StartOnboardingProcess( @@ -129,7 +129,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( } override fun onCloseAlreadySignedHashesWarningClick() { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { val userWallet = getSelectedUserWallet() ?: return@launch setCardWasScannedUseCase(cardId = userWallet.cardId) @@ -140,7 +140,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( analyticsEventHandler.send(Basic.CardWasScanned(AnalyticsParam.ScreensSources.Main)) analyticsEventHandler.send(MainScreen.NoticeScanYourCardTapped) - viewModelScope.launch { + modelScope.launch { val userWallet = getSelectedUserWallet() ?: return@launch derivePublicKeysUseCase( @@ -171,7 +171,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( override fun onUnlockWalletClick() { analyticsEventHandler.send(MainScreen.UnlockAllWithBiometrics) - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { unlockWalletsUseCase(type = UnlockType.ALL_WITHOUT_SELECT) .onRight { stateHolder.update(CloseBottomSheetTransformer(stateHolder.getSelectedWalletId())) } .onLeft(::handleUnlockWalletsError) @@ -201,7 +201,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( } private fun openScanCardDialog() { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { scanCardToUnlockWalletClickHandler(walletId = stateHolder.getSelectedWalletId()) .onLeft { error -> when (error) { @@ -222,7 +222,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( walletEventSender.send( event = WalletEvent.RateApp( onDismissClick = { - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { neverToSuggestRateAppUseCase() } }, @@ -233,7 +233,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( override fun onDislikeAppClick() { analyticsEventHandler.send(MainScreen.NoticeRateAppButton(AnalyticsParam.RateApp.Disliked)) - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { neverToSuggestRateAppUseCase() val scanResponse = getSelectedUserWallet()?.scanResponse ?: return@launch @@ -246,7 +246,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( override fun onCloseRateAppWarningClick() { analyticsEventHandler.send(MainScreen.NoticeRateAppButton(AnalyticsParam.RateApp.Closed)) - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { remindToRateAppLaterUseCase() } } @@ -259,7 +259,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Closed, ), ) - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { shouldShowSwapPromoWalletUseCase.neverToShow() } } @@ -268,14 +268,14 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( val scanResponse = getSelectedUserWallet()?.scanResponse ?: return val cardInfo = getCardInfoUseCase(scanResponse).getOrNull() ?: return - viewModelScope.launch { + modelScope.launch { sendFeedbackEmailUseCase(type = FeedbackEmailType.DirectUserRequest(cardInfo = cardInfo)) } } override fun onNoteMigrationButtonClick(url: String) { analyticsEventHandler.send(MainScreen.NotePromoButton) - viewModelScope.launch(dispatchers.main) { + modelScope.launch(dispatchers.main) { router.openUrl(url) } } @@ -290,7 +290,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( state = WalletAlertState.SimpleOkAlert( message = resourceReference(R.string.warning_seedphrase_issue_answer_yes), onOkClick = { - viewModelScope.launch { + modelScope.launch { seedPhraseNotificationUseCase.confirm(userWalletId = userWallet.walletId) urlOpener.openUrl( @@ -313,7 +313,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( state = WalletAlertState.SimpleOkAlert( message = resourceReference(R.string.warning_seedphrase_issue_answer_no), onOkClick = { - viewModelScope.launch { + modelScope.launch { seedPhraseNotificationUseCase.decline(userWalletId = userWallet.walletId) } }, @@ -332,7 +332,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( state = WalletAlertState.SimpleOkAlert( message = resourceReference(R.string.warning_seedphrase_issue_answer_yes), onOkClick = { - viewModelScope.launch { + modelScope.launch { seedPhraseNotificationUseCase.acceptSecond(userWalletId = userWallet.walletId) urlOpener.openUrl( @@ -350,7 +350,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( analyticsEventHandler.send(MainScreen.NoticeSeedPhraseSupportButtonDeclined) - viewModelScope.launch { + modelScope.launch { seedPhraseNotificationUseCase.rejectSecond(userWalletId = userWallet.walletId) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/di/WalletFeatureModule.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/di/WalletFeatureModule.kt new file mode 100644 index 0000000000..22cf0f0df5 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/di/WalletFeatureModule.kt @@ -0,0 +1,31 @@ +package com.tangem.feature.wallet.di + +import com.tangem.core.decompose.model.Model +import com.tangem.feature.wallet.DefaultWalletEntryComponent +import com.tangem.feature.wallet.child.organizetokens.model.OrganizeTokensModel +import com.tangem.feature.wallet.child.wallet.model.WalletModel +import com.tangem.features.wallet.WalletEntryComponent +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 WalletFeatureModule { + + @Binds + fun bindComponentFactory(impl: DefaultWalletEntryComponent.Factory): WalletEntryComponent.Factory + + @Binds + @IntoMap + @ClassKey(WalletModel::class) + fun bindWalletModel(model: WalletModel): Model + + @Binds + @IntoMap + @ClassKey(OrganizeTokensModel::class) + fun bindOrganizeTokensModel(model: OrganizeTokensModel): Model +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/di/WalletRouterModule.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/di/WalletRouterModule.kt index 4d110cae5d..f82f682933 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/di/WalletRouterModule.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/di/WalletRouterModule.kt @@ -1,18 +1,18 @@ package com.tangem.feature.wallet.di +import com.tangem.core.decompose.di.ModelComponent +import com.tangem.core.decompose.di.ModelScoped import com.tangem.feature.wallet.presentation.router.DefaultWalletRouter -import com.tangem.features.wallet.navigation.WalletRouter +import com.tangem.feature.wallet.presentation.router.InnerWalletRouter import dagger.Binds import dagger.Module import dagger.hilt.InstallIn -import dagger.hilt.android.components.ActivityComponent -import dagger.hilt.android.scopes.ActivityScoped @Module -@InstallIn(ActivityComponent::class) +@InstallIn(ModelComponent::class) internal interface WalletRouterModule { @Binds - @ActivityScoped - fun bindsWalletRouter(defaultWalletRouter: DefaultWalletRouter): WalletRouter + @ModelScoped + fun bindsWalletRouter(defaultWalletRouter: DefaultWalletRouter): InnerWalletRouter } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/navigation/WalletRoute.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/navigation/WalletRoute.kt new file mode 100644 index 0000000000..54381da20a --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/navigation/WalletRoute.kt @@ -0,0 +1,14 @@ +package com.tangem.feature.wallet.navigation + +import com.tangem.domain.wallets.models.UserWalletId +import kotlinx.serialization.Serializable + +@Serializable +internal sealed class WalletRoute { + + @Serializable + data object Wallet : WalletRoute() + + @Serializable + data class OrganizeTokens(val userWalletId: UserWalletId) : WalletRoute() +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/WalletFragment.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/WalletFragment.kt deleted file mode 100644 index 446d5c41bb..0000000000 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/WalletFragment.kt +++ /dev/null @@ -1,85 +0,0 @@ -package com.tangem.feature.wallet.presentation - -import android.os.Bundle -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import com.arkivanov.decompose.defaultComponentContext -import com.tangem.common.routing.AppRouter -import com.tangem.common.routing.utils.asRouter -import com.tangem.core.decompose.context.DefaultAppComponentContext -import com.tangem.core.decompose.di.ModelComponent -import com.tangem.core.decompose.di.GlobalUiMessageSender -import com.tangem.core.decompose.ui.UiMessageSender -import com.tangem.core.ui.UiDependencies -import com.tangem.core.ui.screen.ComposeFragment -import com.tangem.feature.wallet.presentation.router.InnerWalletRouter -import com.tangem.features.wallet.navigation.WalletRouter -import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject - -/** - * Wallet fragment - * -[REDACTED_AUTHOR] - */ -@AndroidEntryPoint -internal class WalletFragment : ComposeFragment() { - - @Inject - override lateinit var uiDependencies: UiDependencies - - /** Feature router */ - @Inject - internal lateinit var walletRouter: WalletRouter - - @Inject - internal lateinit var coroutineDispatcherProvider: CoroutineDispatcherProvider - - @Inject - internal lateinit var componentBuilder: ModelComponent.Builder - - @Inject - internal lateinit var appRouter: AppRouter - - @Inject - @GlobalUiMessageSender - internal lateinit var messageSender: UiMessageSender - - private val _walletRouter: InnerWalletRouter - get() = requireNotNull(walletRouter as? InnerWalletRouter) { - "_walletRouter should be instance of InnerWalletRouter" - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - _walletRouter.initializeResources( - appComponentContext = DefaultAppComponentContext( - componentContext = defaultComponentContext(requireActivity().onBackPressedDispatcher), - messageSender = messageSender, - dispatchers = coroutineDispatcherProvider, - hiltComponentBuilder = componentBuilder, - replaceRouter = appRouter.asRouter(), - ), - ) - } - - @Composable - override fun ScreenContent(modifier: Modifier) { - _walletRouter.Initialize( - onFinish = remember(requireActivity()) { - { - requireActivity().finish() - } - }, - ) - } - - companion object { - - /** Create wallet fragment instance */ - fun create(): WalletFragment = WalletFragment() - } -} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt index 7fd53126fb..94875479d9 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt @@ -8,6 +8,10 @@ import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemColorPalette import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.feature.wallet.presentation.wallet.state.model.ActionsBottomSheetConfig +import com.tangem.feature.wallet.presentation.wallet.state.model.TokenActionButtonConfig +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAdditionalInfo +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletBottomSheetConfig import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensListState diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt index da8b495a9a..4f8cb9bdfd 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt @@ -9,6 +9,7 @@ import com.tangem.core.ui.event.consumedEvent import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.stringReference import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAdditionalInfo import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.presentation.common.WalletPreviewData.topBarConfig import com.tangem.feature.wallet.presentation.wallet.state.model.* @@ -144,7 +145,6 @@ internal object WalletScreenPreviewData { ) internal val walletScreenState = WalletScreenState( - onBackClick = {}, topBarConfig = topBarConfig, selectedWalletIndex = 0, wallets = persistentListOf( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt index e019c8dd88..a0b28f06fd 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt @@ -1,7 +1,5 @@ package com.tangem.feature.wallet.presentation.deeplink -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRouter import com.tangem.core.analytics.api.AnalyticsEventHandler @@ -13,8 +11,9 @@ import com.tangem.domain.tokens.GetCryptoCurrencyUseCase import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.features.onramp.OnrampFeatureToggles +import com.tangem.utils.coroutines.launchOnCancellation import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import timber.log.Timber @@ -32,14 +31,14 @@ internal class WalletDeepLinksHandler @Inject constructor( private var deepLinksMap = mutableMapOf>() - fun registerForWallet(viewModel: ViewModel, userWallet: UserWallet) { + fun registerForWallet(scope: CoroutineScope, userWallet: UserWallet) { val deepLinks = deepLinksMap.getOrPut(userWallet.walletId) { - getDeepLinks(userWallet, viewModel.viewModelScope) + getDeepLinks(userWallet, scope) } deepLinksRegistry.unregisterByIds(deepLinks.map { it.id }) deepLinksRegistry.register(deepLinks = deepLinks) - viewModel.addCloseable { + scope.launchOnCancellation { deepLinksRegistry.unregister(deepLinks) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt index 384435d2a8..fe1c52f5bc 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt @@ -1,144 +1,41 @@ package com.tangem.feature.wallet.presentation.router -import android.annotation.SuppressLint -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.fragment.app.Fragment -import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.compose.LocalLifecycleOwner -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation.NavHostController -import androidx.navigation.NavType -import androidx.navigation.compose.NavHost -import androidx.navigation.compose.composable -import androidx.navigation.compose.rememberNavController -import androidx.navigation.navArgument -import com.arkivanov.decompose.ComponentContext -import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState -import com.arkivanov.decompose.router.slot.ChildSlot import com.arkivanov.decompose.router.slot.SlotNavigation -import com.arkivanov.decompose.router.slot.childSlot -import com.arkivanov.decompose.router.slot.dismiss -import com.arkivanov.decompose.value.Value import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRoute.ManageTokens.Source import com.tangem.common.routing.AppRouter -import com.tangem.core.decompose.context.AppComponentContext -import com.tangem.core.decompose.context.childByContext +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.navigation.url.UrlOpener -import com.tangem.core.ui.decompose.ComposableDialogComponent import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.redux.StateDialog import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.feature.wallet.presentation.WalletFragment -import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensScreen -import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensViewModel +import com.tangem.feature.wallet.navigation.WalletRoute import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDialogConfig -import com.tangem.feature.wallet.presentation.wallet.ui.WalletScreen -import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletViewModel -import com.tangem.feature.walletsettings.component.RenameWalletComponent -import com.tangem.features.markets.entry.MarketsEntryComponent import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.flow.MutableSharedFlow import javax.inject.Inject -import kotlin.properties.Delegates /** Default implementation of wallet feature router */ +@ModelScoped internal class DefaultWalletRouter @Inject constructor( private val router: AppRouter, private val urlOpener: UrlOpener, private val reduxStateHolder: ReduxStateHolder, private val onboardingV2FeatureToggles: OnboardingV2FeatureToggles, - private val marketsEntryComponentFactory: MarketsEntryComponent.Factory, - private val renameWalletComponentFactory: RenameWalletComponent.Factory, ) : InnerWalletRouter { - private var navController: NavHostController by Delegates.notNull() - private var onFinish: () -> Unit = {} - - private lateinit var marketsEntryComponent: MarketsEntryComponent - private lateinit var dialog: Value> - override val dialogNavigation: SlotNavigation = SlotNavigation() - override fun initializeResources(appComponentContext: AppComponentContext) { - marketsEntryComponent = marketsEntryComponentFactory.create(appComponentContext) - dialog = appComponentContext.childSlot( - source = dialogNavigation, - serializer = WalletDialogConfig.serializer(), - handleBackButton = true, - childFactory = { dialogConfig, componentContext -> - dialogChild( - appContext = appComponentContext, - dialogConfig = dialogConfig, - componentContext = componentContext, - ) - }, - ) - } - - override fun getEntryFragment(): Fragment = WalletFragment.create() - - @Composable - override fun Initialize(onFinish: () -> Unit) { - this.onFinish = onFinish - - NavHost( - navController = rememberNavController().apply { navController = this }, - startDestination = WalletRoute.Wallet.route, - ) { - composable(WalletRoute.Wallet.route) { - val viewModel = hiltViewModel().apply { - setWalletRouter(router = this@DefaultWalletRouter) - subscribeToLifecycle(LocalLifecycleOwner.current) - } - - val dialog by dialog.subscribeAsState() - - WalletScreen( - state = viewModel.uiState.collectAsStateWithLifecycle().value, - marketsEntryComponent = marketsEntryComponent, - ) - - dialog.child?.instance?.Dialog() - } - - composable( - WalletRoute.OrganizeTokens.route, - arguments = listOf(navArgument(WalletRoute.userWalletIdKey) { type = NavType.StringType }), - ) { - val viewModel = hiltViewModel().apply { - router = this@DefaultWalletRouter - } - LocalLifecycleOwner.current.lifecycle.addObserver(viewModel) - - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - - OrganizeTokensScreen( - state = uiState, - ) - } - } - } - - @SuppressLint("RestrictedApi") - override fun popBackStack() { - /* - * It's hack that avoid issue with closing the wallet screen. - * We are using NavGraph only inside feature so first backstack's element is entry of NavGraph and - * next element is wallet screen entry. - * If backstack contains only NavGraph entry and wallet screen entry then we close the wallet fragment. - */ - if (navController.currentBackStack.value.size == BACKSTACK_ENTRY_COUNT_TO_CLOSE_WALLET_SCREEN) { - onFinish.invoke() - } else { - navController.popBackStack() - } - } + override val navigateToFlow = MutableSharedFlow( + extraBufferCapacity = 1, + onBufferOverflow = BufferOverflow.DROP_LATEST, + ) override fun openOrganizeTokensScreen(userWalletId: UserWalletId) { - navController.navigate(WalletRoute.OrganizeTokens.createRoute(userWalletId)) + navigateToFlow.tryEmit(WalletRoute.OrganizeTokens(userWalletId)) } override fun openDetailsScreen(selectedWalletId: UserWalletId) { @@ -215,25 +112,4 @@ internal class DefaultWalletRouter @Inject constructor( override fun openScanFailedDialog(onTryAgain: () -> Unit) { reduxStateHolder.dispatchDialogShow(StateDialog.ScanFailsDialog(StateDialog.ScanFailsSource.MAIN, onTryAgain)) } - - private fun dialogChild( - appContext: AppComponentContext, - dialogConfig: WalletDialogConfig, - componentContext: ComponentContext, - ): ComposableDialogComponent = when (dialogConfig) { - is WalletDialogConfig.RenameWallet -> { - renameWalletComponentFactory.create( - context = appContext.childByContext(componentContext), - params = RenameWalletComponent.Params( - userWalletId = dialogConfig.userWalletId, - currentName = dialogConfig.currentName, - onDismiss = dialogNavigation::dismiss, - ), - ) - } - } - - private companion object { - const val BACKSTACK_ENTRY_COUNT_TO_CLOSE_WALLET_SCREEN = 2 - } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt index f20dd1c443..9ec77cb66c 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt @@ -1,14 +1,13 @@ package com.tangem.feature.wallet.presentation.router -import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import com.arkivanov.decompose.router.slot.SlotNavigation -import com.tangem.core.decompose.context.AppComponentContext import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.feature.wallet.navigation.WalletRoute import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDialogConfig -import com.tangem.features.wallet.navigation.WalletRouter +import kotlinx.coroutines.flow.SharedFlow /** * Interface of inner wallet feature router @@ -19,22 +18,11 @@ import com.tangem.features.wallet.navigation.WalletRouter [REDACTED_AUTHOR] */ @Stable -internal interface InnerWalletRouter : WalletRouter { +internal interface InnerWalletRouter { val dialogNavigation: SlotNavigation - fun initializeResources(appComponentContext: AppComponentContext) - - /** - * Initialize router - * - * @param onFinish finish activity callback - */ - @Composable - fun Initialize(onFinish: () -> Unit) - - /** Pop back stack */ - fun popBackStack() + val navigateToFlow: SharedFlow /** Open organize tokens screen */ fun openOrganizeTokensScreen(userWalletId: UserWalletId) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/WalletRoute.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/WalletRoute.kt deleted file mode 100644 index 2cb8a4a91c..0000000000 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/WalletRoute.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.tangem.feature.wallet.presentation.router - -import com.tangem.domain.wallets.models.UserWalletId - -/** - * Wallet feature screens - * - * @property route route string representation - * -[REDACTED_AUTHOR] - */ -internal sealed class WalletRoute(val route: String) { - - object Wallet : WalletRoute(route = "wallet") - - object OrganizeTokens : WalletRoute(route = "wallet/{$userWalletIdKey}/organize_tokens") { - - fun createRoute(userWalletId: UserWalletId) = "wallet/${userWalletId.stringValue}/organize_tokens" - } - - companion object { - const val userWalletIdKey = "userWalletId" - } -} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt index a475d10af8..b057ac8dd5 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt @@ -8,6 +8,7 @@ import com.tangem.blockchainsdk.utils.fromNetworkId import com.tangem.common.extensions.isZero import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.analytics.CheckIsWalletToppedUpUseCase import com.tangem.domain.analytics.model.WalletBalanceState import com.tangem.domain.tokens.model.CryptoCurrencyStatus @@ -19,13 +20,12 @@ import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnaly import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider -import dagger.hilt.android.scopes.ViewModelScoped import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import java.math.BigDecimal import javax.inject.Inject -@ViewModelScoped +@ModelScoped internal class TokenListAnalyticsSender @Inject constructor( private val analyticsEventHandler: AnalyticsEventHandler, private val checkIsWalletToppedUpUseCase: CheckIsWalletToppedUpUseCase, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt index 12a4cf918c..36ed315d4b 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt @@ -3,16 +3,16 @@ package com.tangem.feature.wallet.presentation.wallet.analytics.utils import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.tokens.model.analytics.TokenSwapPromoAnalyticsEvent import com.tangem.domain.tokens.model.analytics.TokenSwapPromoAnalyticsEvent.ProgramName import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider -import dagger.hilt.android.scopes.ViewModelScoped import javax.inject.Inject -@ViewModelScoped +@ModelScoped internal class WalletWarningsAnalyticsSender @Inject constructor( private val analyticsEventHandler: AnalyticsEventHandler, private val screenLifecycleProvider: ScreenLifecycleProvider, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsSingleEventSender.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsSingleEventSender.kt index e00a7a429b..80735cc935 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsSingleEventSender.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsSingleEventSender.kt @@ -1,14 +1,14 @@ package com.tangem.feature.wallet.presentation.wallet.analytics.utils +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.usecase.SeedPhraseNotificationUseCase import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider -import dagger.hilt.android.scopes.ViewModelScoped import javax.inject.Inject -@ViewModelScoped +@ModelScoped internal class WalletWarningsSingleEventSender @Inject constructor( private val seedPhraseNotificationUseCase: SeedPhraseNotificationUseCase, private val screenLifecycleProvider: ScreenLifecycleProvider, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt index 5a5fa3536e..6fe75e5285 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt @@ -1,5 +1,6 @@ package com.tangem.feature.wallet.presentation.wallet.domain +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.core.lce.Lce @@ -16,8 +17,7 @@ import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase import com.tangem.domain.wallets.usecase.SeedPhraseNotificationUseCase import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents -import dagger.hilt.android.scopes.ViewModelScoped +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.Flow @@ -26,7 +26,7 @@ import javax.inject.Inject import kotlin.collections.count @Suppress("LongParameterList") -@ViewModelScoped +@ModelScoped internal class GetMultiWalletWarningsFactory @Inject constructor( private val tokenListStore: MultiWalletTokenListStore, private val isDemoCardUseCase: IsDemoCardUseCase, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetSingleWalletWarningsFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetSingleWalletWarningsFactory.kt index 21f40750f2..d753e4f8bf 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetSingleWalletWarningsFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetSingleWalletWarningsFactory.kt @@ -1,6 +1,7 @@ package com.tangem.feature.wallet.presentation.wallet.domain import arrow.core.Either +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.demo.IsDemoCardUseCase @@ -12,14 +13,13 @@ import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.usecase.GetWalletsUseCase import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents -import dagger.hilt.android.scopes.ViewModelScoped +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.* import javax.inject.Inject -@ViewModelScoped +@ModelScoped internal class GetSingleWalletWarningsFactory @Inject constructor( private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase, private val isDemoCardUseCase: IsDemoCardUseCase, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/HasSingleWalletSignedHashesUseCase.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/HasSingleWalletSignedHashesUseCase.kt index 0738db4676..7c8d7ab2b4 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/HasSingleWalletSignedHashesUseCase.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/HasSingleWalletSignedHashesUseCase.kt @@ -1,17 +1,17 @@ package com.tangem.feature.wallet.presentation.wallet.domain +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.card.repository.CardRepository import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.demo.DemoConfig import com.tangem.domain.tokens.model.Network import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.models.UserWallet -import dagger.hilt.android.scopes.ViewModelScoped import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import javax.inject.Inject -@ViewModelScoped +@ModelScoped class HasSingleWalletSignedHashesUseCase @Inject constructor( private val cardRepository: CardRepository, private val walletManagersFacade: WalletManagersFacade, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/MultiWalletTokenListStore.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/MultiWalletTokenListStore.kt index d25f60ca3e..82e1af33a4 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/MultiWalletTokenListStore.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/MultiWalletTokenListStore.kt @@ -1,11 +1,11 @@ package com.tangem.feature.wallet.presentation.wallet.domain +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.core.lce.LceFlow import com.tangem.domain.tokens.GetTokenListUseCase import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.tokens.model.TokenList import com.tangem.domain.wallets.models.UserWalletId -import dagger.hilt.android.scopes.ViewModelScoped import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ensureActive import kotlinx.coroutines.flow.SharingStarted @@ -14,7 +14,7 @@ import timber.log.Timber import java.util.concurrent.ConcurrentHashMap import javax.inject.Inject -@ViewModelScoped +@ModelScoped internal class MultiWalletTokenListStore @Inject constructor( private val getTokenListUseCase: GetTokenListUseCase, ) { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/OnrampStatusFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/OnrampStatusFactory.kt index 32450b5201..3c1961eee0 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/OnrampStatusFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/OnrampStatusFactory.kt @@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.domain import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.decompose.di.ModelScoped import com.tangem.datasource.local.swaptx.ExpressAnalyticsStatus import com.tangem.domain.onramp.GetOnrampStatusUseCase import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase @@ -13,14 +14,13 @@ import com.tangem.domain.tokens.model.analytics.TokenOnrampAnalyticsEvent import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import dagger.hilt.android.scopes.ViewModelScoped import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.withContext import timber.log.Timber import javax.inject.Inject -@ViewModelScoped +@ModelScoped internal class OnrampStatusFactory @Inject constructor( private val stateHolder: WalletStateController, private val onrampRemoveTransactionUseCase: OnrampRemoveTransactionUseCase, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/WalletContentLoaderFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/WalletContentLoaderFactory.kt index cbb2dad87f..95cb580695 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/WalletContentLoaderFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/WalletContentLoaderFactory.kt @@ -1,13 +1,13 @@ package com.tangem.feature.wallet.presentation.wallet.loaders +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.wallets.models.UserWallet +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.loaders.implementors.* -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents -import dagger.hilt.android.scopes.ViewModelScoped import javax.inject.Inject -@ViewModelScoped +@ModelScoped internal class WalletContentLoaderFactory @Inject constructor( private val multiWalletContentLoaderFactory: MultiWalletContentLoaderFactory, private val singleWalletWithTokenContentLoaderFactory: SingleWalletWithTokenContentLoaderFactory, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/WalletScreenContentLoader.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/WalletScreenContentLoader.kt index 66990ac417..83675a0199 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/WalletScreenContentLoader.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/WalletScreenContentLoader.kt @@ -1,10 +1,10 @@ package com.tangem.feature.wallet.presentation.wallet.loaders +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import dagger.hilt.android.scopes.ViewModelScoped import kotlinx.coroutines.CoroutineScope import timber.log.Timber import javax.inject.Inject @@ -18,7 +18,7 @@ import javax.inject.Inject * [REDACTED_AUTHOR] */ -@ViewModelScoped +@ModelScoped internal class WalletScreenContentLoader @Inject constructor( private val factory: WalletContentLoaderFactory, private val storage: WalletLoaderStorage, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoader.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoader.kt index a80ea9429f..402b03dec0 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoader.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoader.kt @@ -1,5 +1,6 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.deeplink.DeepLinksRegistry import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.promo.GetStoryContentUseCase @@ -7,6 +8,7 @@ import com.tangem.domain.tokens.ApplyTokenListSortingUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsSingleEventSender @@ -19,10 +21,10 @@ import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletActi import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletTokenListSubscriber import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletWarningsSubscriber import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import com.tangem.features.swap.SwapFeatureToggles @Suppress("LongParameterList") +@ModelScoped internal class MultiWalletContentLoader( private val userWallet: UserWallet, private val stateHolder: WalletStateController, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoaderFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoaderFactory.kt index 03ffae14b8..7bc706075d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoaderFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoaderFactory.kt @@ -1,5 +1,6 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.deeplink.DeepLinksRegistry import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.promo.GetStoryContentUseCase @@ -7,6 +8,7 @@ import com.tangem.domain.tokens.ApplyTokenListSortingUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsSingleEventSender @@ -14,13 +16,11 @@ import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarnin import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import com.tangem.features.swap.SwapFeatureToggles -import dagger.hilt.android.scopes.ViewModelScoped import javax.inject.Inject @Suppress("LongParameterList") -@ViewModelScoped +@ModelScoped internal class MultiWalletContentLoaderFactory @Inject constructor( private val stateHolder: WalletStateController, private val tokenListAnalyticsSender: TokenListAnalyticsSender, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoader.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoader.kt index 5ebe780476..e4167b9c20 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoader.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoader.kt @@ -11,11 +11,17 @@ import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase +import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.domain.GetSingleWalletWarningsFactory -import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.subscribers.* -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.presentation.wallet.subscribers.PrimaryCurrencySubscriber +import com.tangem.feature.wallet.presentation.wallet.subscribers.SingleWalletButtonsSubscriber +import com.tangem.feature.wallet.presentation.wallet.subscribers.SingleWalletNotificationsSubscriber +import com.tangem.feature.wallet.presentation.wallet.subscribers.TxHistorySubscriber +import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletDropDownItemsSubscriber +import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber @Suppress("LongParameterList") internal class SingleWalletContentLoader( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoaderFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoaderFactory.kt index d6a6f49dae..6e8e164e92 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoaderFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoaderFactory.kt @@ -1,6 +1,7 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.onramp.GetOnrampTransactionsUseCase import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase @@ -14,11 +15,10 @@ import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.domain.GetSingleWalletWarningsFactory import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents -import dagger.hilt.android.scopes.ViewModelScoped +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import javax.inject.Inject -@ViewModelScoped +@ModelScoped @Suppress("LongParameterList") internal class SingleWalletContentLoaderFactory @Inject constructor( private val stateHolder: WalletStateController, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoader.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoader.kt index 666c0eaacc..fd9277c21a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoader.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoader.kt @@ -6,6 +6,7 @@ import com.tangem.domain.promo.GetStoryContentUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsSingleEventSender @@ -14,12 +15,6 @@ import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenList import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.subscribers.* -import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletActionButtonsSubscriber -import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletWarningsSubscriber -import com.tangem.feature.wallet.presentation.wallet.subscribers.SingleWalletWithTokenListSubscriber -import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletDropDownItemsSubscriber -import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import com.tangem.features.swap.SwapFeatureToggles @Suppress("LongParameterList") diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoaderFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoaderFactory.kt index 78cd9fa1ca..1a7e15d40d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoaderFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoaderFactory.kt @@ -1,5 +1,6 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.deeplink.DeepLinksRegistry import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.promo.GetStoryContentUseCase @@ -13,12 +14,13 @@ import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarnin import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.features.swap.SwapFeatureToggles import javax.inject.Inject // TODO: Refactor @Suppress("LongParameterList") +@ModelScoped internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor( private val stateHolder: WalletStateController, private val tokenListAnalyticsSender: TokenListAnalyticsSender, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/VisaWalletContentLoader.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/VisaWalletContentLoader.kt index 63c0590221..496e989123 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/VisaWalletContentLoader.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/VisaWalletContentLoader.kt @@ -6,7 +6,7 @@ import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.subscribers.VisaWalletSubscriber import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents internal class VisaWalletContentLoader( private val userWallet: UserWallet, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/VisaWalletContentLoaderFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/VisaWalletContentLoaderFactory.kt index ff7033b81d..30dcbd7652 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/VisaWalletContentLoaderFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/VisaWalletContentLoaderFactory.kt @@ -1,14 +1,14 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors +import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.visa.GetVisaCurrencyUseCase import com.tangem.domain.visa.GetVisaTxHistoryUseCase import com.tangem.domain.wallets.models.UserWallet +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents -import dagger.hilt.android.scopes.ViewModelScoped import javax.inject.Inject -@ViewModelScoped +@ModelScoped internal class VisaWalletContentLoaderFactory @Inject constructor( private val stateHolder: WalletStateController, private val getVisaCurrencyUseCase: GetVisaCurrencyUseCase, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletStateController.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletStateController.kt index 6114dfeaf6..cf9c56b44c 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletStateController.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletStateController.kt @@ -87,7 +87,6 @@ internal class WalletStateController @Inject constructor() { private fun getInitialState(): WalletScreenState { return WalletScreenState( - onBackClick = {}, topBarConfig = WalletTopBarConfig(onDetailsClick = {}), selectedWalletIndex = NOT_INITIALIZED_WALLET_INDEX, wallets = persistentListOf(), diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletScreenState.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletScreenState.kt index 934382263b..df260b5856 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletScreenState.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletScreenState.kt @@ -6,7 +6,6 @@ import kotlinx.collections.immutable.ImmutableList @Immutable internal data class WalletScreenState( - val onBackClick: () -> Unit, val topBarConfig: WalletTopBarConfig, val selectedWalletIndex: Int, val wallets: ImmutableList, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/AddWalletTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/AddWalletTransformer.kt index 86e534351d..72d2e0f783 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/AddWalletTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/AddWalletTransformer.kt @@ -4,7 +4,7 @@ import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletLoadingStateFactory -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles import kotlinx.collections.immutable.toImmutableList diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/InitializeWalletsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/InitializeWalletsTransformer.kt index 63b2d6c2a6..ac0c59bc42 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/InitializeWalletsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/InitializeWalletsTransformer.kt @@ -7,7 +7,7 @@ import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver import com.tangem.feature.wallet.presentation.wallet.state.model.* import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletLoadingStateFactory import com.tangem.feature.wallet.presentation.wallet.state.utils.createStateByWalletType -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf @@ -31,7 +31,6 @@ internal class InitializeWalletsTransformer( override fun transform(prevState: WalletScreenState): WalletScreenState { return prevState.copy( - onBackClick = clickIntents::onBackClick, topBarConfig = createTopBarConfig(), selectedWalletIndex = selectedWalletIndex, wallets = wallets diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/ReinitializeWalletTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/ReinitializeWalletTransformer.kt index 45e0d62979..ceecfc9cfc 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/ReinitializeWalletTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/ReinitializeWalletTransformer.kt @@ -5,7 +5,7 @@ import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletLoadingStateFactory -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles import kotlinx.collections.immutable.toImmutableList diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetBalancesAndLimitsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetBalancesAndLimitsTransformer.kt index 421848db63..2655da4ba9 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetBalancesAndLimitsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetBalancesAndLimitsTransformer.kt @@ -14,7 +14,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.BalancesAndLimi import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAdditionalInfo import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.utils.extensions.isZero import org.joda.time.DateTime import org.joda.time.Days diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetCryptoCurrencyActionsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetCryptoCurrencyActionsTransformer.kt index c541164b5f..c1670481d5 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetCryptoCurrencyActionsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetCryptoCurrencyActionsTransformer.kt @@ -6,7 +6,7 @@ import com.tangem.domain.tokens.model.TokenActionsState import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.presentation.wallet.state.model.WalletManageButton import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.toPersistentList import timber.log.Timber diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetExpressStatusesTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetExpressStatusesTransformer.kt index 98058d6c2e..beccf302a6 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetExpressStatusesTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetExpressStatusesTransformer.kt @@ -10,7 +10,7 @@ import com.tangem.domain.wallets.models.UserWalletId import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.SingleWalletOnrampTransactionConverter -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import kotlinx.collections.immutable.toPersistentList import timber.log.Timber diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetRefreshStateTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetRefreshStateTransformer.kt index 08c92c4139..1465ccc33a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetRefreshStateTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetRefreshStateTransformer.kt @@ -2,6 +2,8 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.feature.wallet.presentation.wallet.state.model.BalancesAndLimitsBlockState +import com.tangem.feature.wallet.presentation.wallet.state.model.DepositButtonState import com.tangem.feature.wallet.presentation.wallet.state.model.* import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.mutate diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListTransformer.kt index 86d40d6d13..ed47e5d973 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListTransformer.kt @@ -9,7 +9,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensLis import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.MultiWalletCardStateConverter import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.TokenListStateConverter import com.tangem.feature.wallet.presentation.wallet.state.utils.enableButtons -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import timber.log.Timber internal class SetTokenListTransformer( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryCountErrorTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryCountErrorTransformer.kt index 7f7c2f2a2e..812449f1db 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryCountErrorTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryCountErrorTransformer.kt @@ -7,7 +7,7 @@ import com.tangem.domain.txhistory.models.TxHistoryStateError import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.TxHistoryItemStateConverter -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import kotlinx.collections.immutable.toImmutableList import timber.log.Timber diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryCountTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryCountTransformer.kt index e1f2e9145d..d42259d5a3 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryCountTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryCountTransformer.kt @@ -5,7 +5,7 @@ import com.tangem.core.ui.components.transactions.state.TransactionState import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update import timber.log.Timber diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryItemsErrorTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryItemsErrorTransformer.kt index 3dad635156..53c2a25d9d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryItemsErrorTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryItemsErrorTransformer.kt @@ -5,7 +5,7 @@ import com.tangem.domain.txhistory.models.TxHistoryListError import com.tangem.domain.visa.exception.RefreshTokenExpiredException import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import timber.log.Timber internal class SetTxHistoryItemsErrorTransformer( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryItemsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryItemsTransformer.kt index 712edaa421..4b43c69916 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryItemsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTxHistoryItemsTransformer.kt @@ -6,7 +6,7 @@ import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.TxHistoryItemFlowConverter -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import kotlinx.coroutines.flow.Flow import timber.log.Timber diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWalletCardDropDownItemsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWalletCardDropDownItemsTransformer.kt index f9ea74d599..c71f01c215 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWalletCardDropDownItemsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWalletCardDropDownItemsTransformer.kt @@ -9,7 +9,7 @@ import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDropDownItems import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletCardClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletCardClickIntents import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/UnlockWalletTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/UnlockWalletTransformer.kt index 32165880b8..61cb2c07b4 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/UnlockWalletTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/UnlockWalletTransformer.kt @@ -6,7 +6,7 @@ import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletLoadingStateFactory -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles import kotlinx.collections.immutable.toImmutableList import timber.log.Timber diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCurrencyActionsConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCurrencyActionsConverter.kt index 0ff004ae48..d00bb304d0 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCurrencyActionsConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCurrencyActionsConverter.kt @@ -9,7 +9,7 @@ import com.tangem.domain.tokens.model.TokenActionsState import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.presentation.wallet.state.model.TokenActionButtonConfig -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletCurrencyActionsClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletCurrencyActionsClickIntents import com.tangem.utils.converter.Converter import com.tangem.utils.isNullOrZero import kotlinx.collections.immutable.ImmutableList diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/SingleWalletOnrampTransactionConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/SingleWalletOnrampTransactionConverter.kt index a5a0ee99b1..c506948924 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/SingleWalletOnrampTransactionConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/SingleWalletOnrampTransactionConverter.kt @@ -26,7 +26,7 @@ import com.tangem.feature.wallet.impl.R import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateIconUM import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateInfoUM import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.utils.converter.Converter import kotlinx.collections.immutable.persistentListOf diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt index c3d4c02d9c..ac8b4feb69 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt @@ -13,7 +13,7 @@ import com.tangem.domain.tokens.model.TotalFiatBalance import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.utils.converter.Converter import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.mutate diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemFlowConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemFlowConverter.kt index b24e902bfa..a7ff9b5ba3 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemFlowConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemFlowConverter.kt @@ -5,7 +5,7 @@ import com.tangem.core.ui.components.transactions.state.TransactionState import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.core.ui.components.transactions.state.TxHistoryState.TxHistoryItemState import com.tangem.core.ui.utils.toDateFormatWithTodayYesterday -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.utils.converter.Converter import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt index a85ca99eab..ecd092b477 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt @@ -12,7 +12,7 @@ import com.tangem.core.ui.utils.toTimeFormat import com.tangem.domain.txhistory.models.TxHistoryItem import com.tangem.domain.txhistory.models.TxHistoryItem.* import com.tangem.feature.wallet.impl.R -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.utils.StringsSigns.MINUS import com.tangem.utils.StringsSigns.PLUS import com.tangem.utils.converter.Converter diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/VisaTxDetailsBottomSheetConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/VisaTxDetailsBottomSheetConverter.kt index e655973c16..dee6043f7c 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/VisaTxDetailsBottomSheetConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/VisaTxDetailsBottomSheetConverter.kt @@ -8,7 +8,7 @@ import com.tangem.core.ui.utils.DateTimeFormatters import com.tangem.domain.visa.model.VisaCurrency import com.tangem.domain.visa.model.VisaTxDetails import com.tangem.feature.wallet.presentation.wallet.state.model.VisaTxDetailsBottomSheetConfig -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.VisaWalletIntents +import com.tangem.feature.wallet.child.wallet.model.intents.VisaWalletIntents import com.tangem.utils.converter.Converter import kotlinx.collections.immutable.toImmutableList import org.joda.time.DateTimeZone diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/VisaTxHistoryItemStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/VisaTxHistoryItemStateConverter.kt index fe50fdf537..62d00e4c3c 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/VisaTxHistoryItemStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/VisaTxHistoryItemStateConverter.kt @@ -10,7 +10,7 @@ import com.tangem.core.ui.utils.DateTimeFormatters import com.tangem.domain.visa.model.VisaCurrency import com.tangem.domain.visa.model.VisaTxHistoryItem import com.tangem.feature.wallet.impl.R -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.VisaWalletIntents +import com.tangem.feature.wallet.child.wallet.model.intents.VisaWalletIntents import com.tangem.utils.StringsSigns import com.tangem.utils.converter.Converter import org.joda.time.DateTimeZone diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/WalletLoadingStateFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/WalletLoadingStateFactory.kt index 2ea461b088..6223bc1d05 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/WalletLoadingStateFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/WalletLoadingStateFactory.kt @@ -8,7 +8,7 @@ import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver import com.tangem.feature.wallet.presentation.wallet.state.model.* -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicTokenListSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicTokenListSubscriber.kt index 5ae57f60ab..34389c69a8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicTokenListSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicTokenListSubscriber.kt @@ -11,12 +11,12 @@ import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.tokens.model.TokenList import com.tangem.domain.wallets.models.UserWallet +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTokenListErrorTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTokenListTransformer -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.saveIn import kotlinx.coroutines.CoroutineScope diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/MultiWalletTokenListSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/MultiWalletTokenListSubscriber.kt index 63650daf64..260517ff46 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/MultiWalletTokenListSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/MultiWalletTokenListSubscriber.kt @@ -11,11 +11,11 @@ import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.TokenList import com.tangem.domain.tokens.model.TotalFiatBalance import com.tangem.domain.wallets.models.UserWallet +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import kotlinx.coroutines.CoroutineScope @Suppress("LongParameterList") diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/MultiWalletWarningsSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/MultiWalletWarningsSubscriber.kt index f4a628c17a..995348683f 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/MultiWalletWarningsSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/MultiWalletWarningsSubscriber.kt @@ -1,13 +1,13 @@ package com.tangem.feature.wallet.presentation.wallet.subscribers import com.tangem.domain.wallets.models.UserWallet +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsSingleEventSender import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarningsFactory import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetWarningsTransformer -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletButtonsSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletButtonsSubscriber.kt index 4751fed097..3404216570 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletButtonsSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletButtonsSubscriber.kt @@ -4,10 +4,10 @@ import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase import com.tangem.domain.tokens.model.TokenActionsState import com.tangem.domain.wallets.models.UserWallet +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.domain.collectLatest import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetCryptoCurrencyActionsTransformer -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.* diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletExpressStatusesSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletExpressStatusesSubscriber.kt index 37eb922c67..0e4df60030 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletExpressStatusesSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletExpressStatusesSubscriber.kt @@ -12,9 +12,9 @@ import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase import com.tangem.domain.tokens.error.CurrencyStatusError import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.wallets.models.UserWallet +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetExpressStatusesTransformer -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.* import timber.log.Timber diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletNotificationsSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletNotificationsSubscriber.kt index a1ef1d4ee6..e08eac5427 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletNotificationsSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletNotificationsSubscriber.kt @@ -1,12 +1,12 @@ package com.tangem.feature.wallet.presentation.wallet.subscribers import com.tangem.domain.wallets.models.UserWallet +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.domain.GetSingleWalletWarningsFactory import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetWarningsTransformer -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletWithTokenListSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletWithTokenListSubscriber.kt index 3cb19dbc3a..e52c903a67 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletWithTokenListSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletWithTokenListSubscriber.kt @@ -7,11 +7,11 @@ import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.tokens.model.TokenList import com.tangem.domain.wallets.models.UserWallet +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import kotlinx.coroutines.CoroutineScope @Suppress("LongParameterList") diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TxHistorySubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TxHistorySubscriber.kt index 7561ea68c5..ad67739b99 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TxHistorySubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TxHistorySubscriber.kt @@ -13,6 +13,7 @@ import com.tangem.domain.txhistory.models.TxHistoryStateError import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase import com.tangem.domain.wallets.models.UserWallet +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.domain.collectLatest import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryCountErrorTransformer @@ -20,7 +21,6 @@ import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHis import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryItemsErrorTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryItemsTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.TxHistoryItemStateConverter -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/VisaWalletSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/VisaWalletSubscriber.kt index 9f6c2b8eb2..239ee8c80d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/VisaWalletSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/VisaWalletSubscriber.kt @@ -11,13 +11,13 @@ import com.tangem.domain.visa.GetVisaTxHistoryUseCase import com.tangem.domain.visa.model.VisaCurrency import com.tangem.domain.visa.model.VisaTxHistoryItem import com.tangem.domain.wallets.models.UserWallet +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetBalancesAndLimitsTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryCountTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryItemsErrorTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryItemsTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.VisaTxHistoryItemStateConverter -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/WalletDropDownItemsSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/WalletDropDownItemsSubscriber.kt index b58c62f9a1..01df7c3340 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/WalletDropDownItemsSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/WalletDropDownItemsSubscriber.kt @@ -1,9 +1,9 @@ package com.tangem.feature.wallet.presentation.wallet.subscribers import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetWalletCardDropDownItemsTransformer -import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.* diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt index 414d14cd71..69c2f73c77 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt @@ -67,6 +67,10 @@ import com.tangem.core.ui.test.TestTags import com.tangem.core.ui.utils.lineTo import com.tangem.core.ui.utils.moveTo import com.tangem.core.ui.utils.toPx +import com.tangem.feature.wallet.presentation.wallet.state.model.ActionsBottomSheetConfig +import com.tangem.feature.wallet.presentation.wallet.state.model.BalancesAndLimitsBottomSheetConfig +import com.tangem.feature.wallet.presentation.wallet.state.model.VisaTxDetailsBottomSheetConfig +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAlertState import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.presentation.common.preview.WalletScreenPreviewData.walletScreenState import com.tangem.feature.wallet.presentation.wallet.state.model.* @@ -92,8 +96,6 @@ import kotlin.math.roundToInt @Composable internal fun WalletScreen(state: WalletScreenState, marketsEntryComponent: MarketsEntryComponent) { - BackHandler(onBack = state.onBackClick) - // It means that screen is still initializing if (state.selectedWalletIndex == NOT_INITIALIZED_WALLET_INDEX) return diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/ScreenLifecycleProvider.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/ScreenLifecycleProvider.kt index f2c721ac87..f9f55bea5a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/ScreenLifecycleProvider.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/ScreenLifecycleProvider.kt @@ -1,23 +1,22 @@ package com.tangem.feature.wallet.presentation.wallet.utils -import androidx.lifecycle.DefaultLifecycleObserver -import androidx.lifecycle.LifecycleOwner -import dagger.hilt.android.scopes.ViewModelScoped +import com.arkivanov.essenty.lifecycle.Lifecycle +import com.tangem.core.decompose.di.ModelScoped import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import javax.inject.Inject -@ViewModelScoped -internal class ScreenLifecycleProvider @Inject constructor() : DefaultLifecycleObserver { +@ModelScoped +internal class ScreenLifecycleProvider @Inject constructor() : Lifecycle.Callbacks { private val _isBackgroundState = MutableStateFlow(false) val isBackgroundState: StateFlow = _isBackgroundState - override fun onResume(owner: LifecycleOwner) { + override fun onResume() { _isBackgroundState.value = false } - override fun onPause(owner: LifecycleOwner) { + override fun onPause() { _isBackgroundState.value = true } } \ No newline at end of file From e1933a974a362bc1d366d7b7843a851dbd37a280 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 27 Feb 2025 08:30:53 +0300 Subject: [PATCH 35/54] Updated on 2026-08-14 --- .../v2/multiwallet/impl/ui/WalletArtwork.kt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/ui/WalletArtwork.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/ui/WalletArtwork.kt index 6ba4014a77..40eac45b30 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/ui/WalletArtwork.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/ui/WalletArtwork.kt @@ -15,6 +15,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource @@ -254,6 +255,7 @@ private fun WalletCard(url: String?, modifier: Modifier = Modifier) { placeholder = painterResource(R.drawable.card_placeholder_black), error = painterResource(R.drawable.card_placeholder_black), fallback = painterResource(R.drawable.card_placeholder_black), + contentScale = ContentScale.Fit, contentDescription = null, ) } @@ -263,16 +265,16 @@ private fun WalletArtworksState.toTransitionSetState(maxWidthDp: Float, maxHeigh WalletArtworksState.Hidden -> listOf() is WalletArtworksState.Folded -> listOf( CardsTransitionState( - WalletCardTransitionState(), - WalletCardTransitionState(), - WalletCardTransitionState(), + WalletCardTransitionState(alpha = 1f), + WalletCardTransitionState(alpha = 0f), + WalletCardTransitionState(alpha = 0f), ), ) is WalletArtworksState.Stack -> listOf( CardsTransitionState( - walletCard1 = WalletCardTransitionState(), - walletCard2 = WalletCardTransitionState(), - walletCard3 = WalletCardTransitionState(), + WalletCardTransitionState(alpha = 1f), + WalletCardTransitionState(alpha = 0f), + WalletCardTransitionState(alpha = 0f), ), CardsTransitionState( walletCard1 = WalletCardTransitionState().copy( From 5885360c721e60869683581c0b737650176c329e Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 27 Feb 2025 08:31:03 +0300 Subject: [PATCH 36/54] Updated on 2026-08-14 --- .../v2/entry/impl/model/OnboardingEntryModel.kt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/model/OnboardingEntryModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/model/OnboardingEntryModel.kt index a4478d44e3..6381beb925 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/model/OnboardingEntryModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/model/OnboardingEntryModel.kt @@ -9,6 +9,7 @@ import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.stringReference +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.settings.repositories.SettingsRepository @@ -79,8 +80,14 @@ internal class OnboardingEntryModel @Inject constructor( } private fun onMultiWalletOnboardingDone(userWallet: UserWallet) { - stackNavigation.navigate { - listOf(OnboardingRoute.ManageTokens(userWallet)) + if (userWallet.scanResponse.cardTypesResolver.isMultiwalletAllowed()) { + stackNavigation.navigate { + listOf(OnboardingRoute.ManageTokens(userWallet)) + } + } else { + stackNavigation.navigate { + listOf(OnboardingRoute.Done(onDone = ::navigateToWalletScreen)) + } } } From 28e2b3c45861512c32e531127ac58f3267bd91ca Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 26 Feb 2025 18:45:31 +0500 Subject: [PATCH 37/54] Updated on 2026-08-14 --- .../common/compose/TangemTextFieldsDefault.kt | 152 ------------ .../tangem/tap/common/extensions/TextView.kt | 58 ----- .../components/SettingsButtonItem.kt | 6 +- .../components/SettingsCardItem.kt | 8 +- .../components/SettingsSwitchItem.kt | 2 +- .../ui/cardsettings/CardSettingsScreen.kt | 2 +- .../features/home/compose/content/Content.kt | 2 +- .../compose/content/FirstStoriesContent.kt | 2 +- .../ui/components/SaveWalletScreenContent.kt | 6 +- .../ui/components/WelcomeScreenContent.kt | 4 +- .../ui/components/CurrencyPlaceholderIcon.kt | 2 +- .../core/ui/components/MiddleEllipsisText.kt | 4 +- .../com/tangem/core/ui/components/Notifier.kt | 2 +- .../core/ui/components/ResizableText.kt | 16 +- .../tangem/core/ui/components/SettingsRow.kt | 4 +- .../tangem/core/ui/components/TextFields.kt | 234 ++++++++---------- .../ui/components/appbar/AppBarWithSearch.kt | 10 +- .../core/ui/components/audits/AuditLabel.kt | 2 +- .../fields/SimpleDialogTextField.kt | 2 +- .../core/ui/components/rows/ActionRow.kt | 4 +- core/ui/src/main/res/drawable/ic_trash_24.xml | 9 + .../ui/MultiWalletSeedPhraseImport.kt | 3 +- .../wallet2/ui/AboutSeedPhraseScreen.kt | 4 +- .../wallet2/ui/ImportSeedPhraseScreen.kt | 4 +- .../wallet2/ui/PassphraseInfoBottomSheet.kt | 4 +- .../wallet2/ui/YourSeedPhraseScreen.kt | 2 +- .../components/OnboardingDescriptionBlock.kt | 2 +- .../feature/swap/ui/AutosizeTextField.kt | 2 +- .../swap/ui/ChooseProviderBottomSheet.kt | 4 +- .../feature/swap/ui/SwapSelectTokenScreen.kt | 4 +- .../tangem/feature/swap/ui/TransactionCard.kt | 11 +- .../wallet/state/model/WalletDropDownItems.kt | 4 +- .../SetWalletCardDropDownItemsTransformer.kt | 7 +- .../wallet/ui/components/common/WalletCard.kt | 3 +- 34 files changed, 183 insertions(+), 402 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/common/compose/TangemTextFieldsDefault.kt delete mode 100644 app/src/main/java/com/tangem/tap/common/extensions/TextView.kt create mode 100644 core/ui/src/main/res/drawable/ic_trash_24.xml diff --git a/app/src/main/java/com/tangem/tap/common/compose/TangemTextFieldsDefault.kt b/app/src/main/java/com/tangem/tap/common/compose/TangemTextFieldsDefault.kt deleted file mode 100644 index 945ffc182f..0000000000 --- a/app/src/main/java/com/tangem/tap/common/compose/TangemTextFieldsDefault.kt +++ /dev/null @@ -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 { - return rememberUpdatedState( - when { - !enabled -> disabledLeadingIconColor - isError -> errorLeadingIconColor - else -> leadingIconColor - }, - ) - } - - @Composable - override fun trailingIconColor(enabled: Boolean, isError: Boolean): State { - return rememberUpdatedState( - when { - !enabled -> disabledTrailingIconColor - isError -> errorTrailingIconColor - else -> trailingIconColor - }, - ) - } - - @Composable - override fun indicatorColor( - enabled: Boolean, - isError: Boolean, - interactionSource: InteractionSource, - ): State { - 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 { - return rememberUpdatedState(backgroundColor) - } - - @Composable - override fun placeholderColor(enabled: Boolean): State { - return rememberUpdatedState(if (enabled) placeholderColor else disabledPlaceholderColor) - } - - @Composable - override fun labelColor(enabled: Boolean, error: Boolean, interactionSource: InteractionSource): State { - 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 { - return rememberUpdatedState(if (enabled) textColor else disabledTextColor) - } - - @Composable - override fun cursorColor(isError: Boolean): State { - return rememberUpdatedState(if (isError) errorCursorColor else cursorColor) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/TextView.kt b/app/src/main/java/com/tangem/tap/common/extensions/TextView.kt deleted file mode 100644 index aef0701282..0000000000 --- a/app/src/main/java/com/tangem/tap/common/extensions/TextView.kt +++ /dev/null @@ -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 - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/SettingsButtonItem.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/SettingsButtonItem.kt index 17dccc7a63..537029db99 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/SettingsButtonItem.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/SettingsButtonItem.kt @@ -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( diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/SettingsCardItem.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/SettingsCardItem.kt index 1e43c8f328..0303b21733 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/SettingsCardItem.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/SettingsCardItem.kt @@ -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( diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/SettingsSwitchItem.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/SettingsSwitchItem.kt index a8476e3bd2..9ad210cbef 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/SettingsSwitchItem.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/SettingsSwitchItem.kt @@ -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 diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsScreen.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsScreen.kt index c4454f830f..44fdad55f0 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsScreen.kt @@ -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 diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/content/Content.kt b/app/src/main/java/com/tangem/tap/features/home/compose/content/Content.kt index 0a1f0fdaed..1635f234ad 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/content/Content.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/content/Content.kt @@ -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 diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/content/FirstStoriesContent.kt b/app/src/main/java/com/tangem/tap/features/home/compose/content/FirstStoriesContent.kt index 184bf8d37d..42fdcaf8fa 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/content/FirstStoriesContent.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/content/FirstStoriesContent.kt @@ -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 diff --git a/app/src/main/java/com/tangem/tap/features/saveWallet/ui/components/SaveWalletScreenContent.kt b/app/src/main/java/com/tangem/tap/features/saveWallet/ui/components/SaveWalletScreenContent.kt index c23f77abe1..403c914016 100644 --- a/app/src/main/java/com/tangem/tap/features/saveWallet/ui/components/SaveWalletScreenContent.kt +++ b/app/src/main/java/com/tangem/tap/features/saveWallet/ui/components/SaveWalletScreenContent.kt @@ -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 diff --git a/app/src/main/java/com/tangem/tap/features/welcome/ui/components/WelcomeScreenContent.kt b/app/src/main/java/com/tangem/tap/features/welcome/ui/components/WelcomeScreenContent.kt index c9bbbdf31c..433f9521fa 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/ui/components/WelcomeScreenContent.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/ui/components/WelcomeScreenContent.kt @@ -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 diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/CurrencyPlaceholderIcon.kt b/core/ui/src/main/java/com/tangem/core/ui/components/CurrencyPlaceholderIcon.kt index 71b0550226..0cfef1c3d7 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/CurrencyPlaceholderIcon.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/CurrencyPlaceholderIcon.kt @@ -5,7 +5,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.CircleShape -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 diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/MiddleEllipsisText.kt b/core/ui/src/main/java/com/tangem/core/ui/components/MiddleEllipsisText.kt index e67fbf3de2..892ef05493 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/MiddleEllipsisText.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/MiddleEllipsisText.kt @@ -1,7 +1,7 @@ package com.tangem.core.ui.components -import androidx.compose.material.LocalTextStyle -import androidx.compose.material.Text +import androidx.compose.material3.LocalTextStyle +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/Notifier.kt b/core/ui/src/main/java/com/tangem/core/ui/components/Notifier.kt index 5e3e78a06a..ad18ba92f0 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/Notifier.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/Notifier.kt @@ -5,7 +5,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.heightIn 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 diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/ResizableText.kt b/core/ui/src/main/java/com/tangem/core/ui/components/ResizableText.kt index 649e5c7788..f5d84c141b 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/ResizableText.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/ResizableText.kt @@ -2,8 +2,8 @@ package com.tangem.core.ui.components import androidx.annotation.FloatRange import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.material.LocalTextStyle -import androidx.compose.material.Text +import androidx.compose.material3.LocalTextStyle +import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawWithContent @@ -27,13 +27,13 @@ fun ResizableText( maxLines: Int = Int.MAX_VALUE, style: TextStyle = LocalTextStyle.current, ) { - val fontSizeValue = remember { mutableStateOf(fontSizeRange.max.value) } + val fontSizeValue = remember { mutableFloatStateOf(fontSizeRange.max.value) } val readyToDraw = remember { mutableStateOf(false) } val textState = remember { mutableStateOf(text) } if (textState.value != text) { readyToDraw.value = false - fontSizeValue.value = fontSizeRange.max.value + fontSizeValue.floatValue = fontSizeRange.max.value textState.value = text } @@ -41,18 +41,18 @@ fun ResizableText( text = text, modifier = modifier.drawWithContent { if (readyToDraw.value) drawContent() }, color = color, - fontSize = fontSizeValue.value.sp, + fontSize = fontSizeValue.floatValue.sp, overflow = overflow, softWrap = false, maxLines = maxLines, onTextLayout = { if (it.hasVisualOverflow) { - val nextFontSizeValue = fontSizeValue.value - fontSizeRange.step.value + val nextFontSizeValue = fontSizeValue.floatValue - fontSizeRange.step.value if (nextFontSizeValue <= fontSizeRange.min.value) { - fontSizeValue.value = fontSizeRange.min.value + fontSizeValue.floatValue = fontSizeRange.min.value readyToDraw.value = true } else { - fontSizeValue.value = nextFontSizeValue * COEFFICIENT + fontSizeValue.floatValue = nextFontSizeValue * COEFFICIENT } } else { readyToDraw.value = true diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/SettingsRow.kt b/core/ui/src/main/java/com/tangem/core/ui/components/SettingsRow.kt index cb5266dce9..b1b8fa87b0 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/SettingsRow.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/SettingsRow.kt @@ -5,8 +5,8 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.animateColorAsState import androidx.compose.foundation.clickable 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.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/TextFields.kt b/core/ui/src/main/java/com/tangem/core/ui/components/TextFields.kt index dbe2a76c91..2c8c37e80b 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/TextFields.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/TextFields.kt @@ -14,7 +14,8 @@ import androidx.compose.foundation.interaction.collectIsFocusedAsState import androidx.compose.foundation.layout.* import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.* +import androidx.compose.foundation.text.selection.LocalTextSelectionColors +import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -119,7 +120,7 @@ private fun TangemTextField( keyboardOptions: KeyboardOptions = KeyboardOptions.Default, keyboardActions: KeyboardActions = KeyboardActions(), interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, - colors: TangemTextFieldColors = TangemTextFieldsDefault.defaultTextFieldColors, + colors: TextFieldColors = TangemTextFieldsDefault.defaultTextFieldColors, size: TangemTextFieldSize = TangemTextFieldSize.Default, onClear: () -> Unit = { onValueChange(TextFieldValue()) }, ) { @@ -230,7 +231,7 @@ private fun TangemTextFieldWithIcon( keyboardOptions: KeyboardOptions = KeyboardOptions.Default, keyboardActions: KeyboardActions = KeyboardActions(), interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, - colors: TangemTextFieldColors = TangemTextFieldsDefault.defaultTextFieldColors, + colors: TextFieldColors = TangemTextFieldsDefault.defaultTextFieldColors, size: TangemTextFieldSize = TangemTextFieldSize.Default, onIconClick: () -> Unit = {}, ) { @@ -326,154 +327,139 @@ private fun TangemTextFieldSize.toShape(): Shape = when (this) { } object TangemTextFieldsDefault { - val defaultTextFieldColors: TangemTextFieldColors - @Composable @Stable get() = TangemTextFieldColors( - textColor = TangemTheme.colors.text.primary1, + val defaultTextFieldColors: TextFieldColors + @Composable @Stable get() = TextFieldColors( + focusedTextColor = TangemTheme.colors.text.primary1, + errorTextColor = TangemTheme.colors.text.primary1, + unfocusedTextColor = TangemTheme.colors.text.primary1, disabledTextColor = TangemTheme.colors.text.disabled, - backgroundColor = Color.Transparent, + focusedContainerColor = Color.Transparent, + unfocusedContainerColor = Color.Transparent, + disabledContainerColor = Color.Transparent, + errorContainerColor = Color.Transparent, cursorColor = TangemTheme.colors.icon.primary1, errorCursorColor = TangemTheme.colors.icon.warning, focusedIndicatorColor = TangemTheme.colors.icon.primary1, unfocusedIndicatorColor = TangemTheme.colors.stroke.secondary, disabledIndicatorColor = TangemTheme.colors.stroke.secondary, errorIndicatorColor = TangemTheme.colors.icon.warning, - leadingIconColor = TangemTheme.colors.icon.informative, + focusedLeadingIconColor = TangemTheme.colors.icon.informative, + unfocusedLeadingIconColor = TangemTheme.colors.icon.informative, disabledLeadingIconColor = Color.Transparent, errorLeadingIconColor = TangemTheme.colors.icon.warning, - trailingIconColor = TangemTheme.colors.icon.informative, + focusedTrailingIconColor = TangemTheme.colors.icon.informative, + unfocusedTrailingIconColor = 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, + focusedPlaceholderColor = TangemTheme.colors.text.secondary, + errorPlaceholderColor = TangemTheme.colors.text.secondary, + unfocusedPlaceholderColor = TangemTheme.colors.text.secondary, disabledPlaceholderColor = TangemTheme.colors.text.disabled, - captionColor = TangemTheme.colors.text.tertiary, - disabledCaptionColor = TangemTheme.colors.text.disabled, - errorCaptionColor = TangemTheme.colors.icon.warning, + focusedSupportingTextColor = TangemTheme.colors.text.tertiary, + unfocusedSupportingTextColor = TangemTheme.colors.text.tertiary, + disabledSupportingTextColor = TangemTheme.colors.text.disabled, + errorSupportingTextColor = TangemTheme.colors.icon.warning, + textSelectionColors = LocalTextSelectionColors.current, + focusedPrefixColor = Color.Transparent, + unfocusedPrefixColor = Color.Transparent, + disabledPrefixColor = Color.Transparent, + errorPrefixColor = Color.Transparent, + focusedSuffixColor = Color.Transparent, + unfocusedSuffixColor = Color.Transparent, + disabledSuffixColor = Color.Transparent, + errorSuffixColor = Color.Transparent, ) } -@Immutable -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 +fun TextFieldColors.leadingIconColor(enabled: Boolean, isError: Boolean): State { + return rememberUpdatedState( + when { + !enabled -> disabledLeadingIconColor + isError -> errorLeadingIconColor + else -> focusedLeadingIconColor + }, + ) +} - @Composable - override fun leadingIconColor(enabled: Boolean, isError: Boolean): State { - return rememberUpdatedState( - when { - !enabled -> disabledLeadingIconColor - isError -> errorLeadingIconColor - else -> leadingIconColor - }, +@Composable +fun TextFieldColors.trailingIconColor(enabled: Boolean, isError: Boolean): State { + return rememberUpdatedState( + when { + !enabled -> disabledTrailingIconColor + isError -> errorTrailingIconColor + else -> focusedTrailingIconColor + }, + ) +} + +@Composable +fun TextFieldColors.indicatorColor( + enabled: Boolean, + isError: Boolean, + interactionSource: InteractionSource, +): State { + val focused by interactionSource.collectIsFocusedAsState() + + val targetValue = when { + !enabled -> disabledIndicatorColor + isError -> errorIndicatorColor + focused -> focusedIndicatorColor + else -> unfocusedIndicatorColor + } + return if (enabled) { + animateColorAsState( + targetValue = targetValue, + animationSpec = tween(durationMillis = 120), + label = "IndicatorColor", ) + } else { + rememberUpdatedState(targetValue) } +} - @Composable - override fun trailingIconColor(enabled: Boolean, isError: Boolean): State { - return rememberUpdatedState( - when { - !enabled -> disabledTrailingIconColor - isError -> errorTrailingIconColor - else -> trailingIconColor - }, - ) +@Composable +fun TextFieldColors.placeholderColor(enabled: Boolean): State { + return rememberUpdatedState(if (enabled) focusedPlaceholderColor else disabledPlaceholderColor) +} + +@Composable +fun TextFieldColors.labelColor(enabled: Boolean, error: Boolean, interactionSource: InteractionSource): State { + val focused by interactionSource.collectIsFocusedAsState() + + val targetValue = when { + !enabled -> disabledLabelColor + error -> errorLabelColor + focused -> focusedLabelColor + else -> unfocusedLabelColor } + return rememberUpdatedState(targetValue) +} - @Composable - override fun indicatorColor( - enabled: Boolean, - isError: Boolean, - interactionSource: InteractionSource, - ): State { - val focused by interactionSource.collectIsFocusedAsState() +@Composable +fun TextFieldColors.textColor(enabled: Boolean): State { + return rememberUpdatedState(if (enabled) focusedTextColor else disabledTextColor) +} - val targetValue = when { - !enabled -> disabledIndicatorColor - isError -> errorIndicatorColor - focused -> focusedIndicatorColor - else -> unfocusedIndicatorColor - } - return if (enabled) { - animateColorAsState( - targetValue = targetValue, - animationSpec = tween(durationMillis = 120), - label = "IndicatorColor", - ) - } else { - rememberUpdatedState(targetValue) - } - } +@Composable +fun TextFieldColors.cursorColor(isError: Boolean): State { + return rememberUpdatedState(if (isError) errorCursorColor else cursorColor) +} - @Composable - override fun backgroundColor(enabled: Boolean): State { - return rememberUpdatedState(backgroundColor) - } - - @Composable - override fun placeholderColor(enabled: Boolean): State { - return rememberUpdatedState(if (enabled) placeholderColor else disabledPlaceholderColor) - } - - @Composable - override fun labelColor(enabled: Boolean, error: Boolean, interactionSource: InteractionSource): State { - 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 { - return rememberUpdatedState(if (enabled) textColor else disabledTextColor) - } - - @Composable - override fun cursorColor(isError: Boolean): State { - return rememberUpdatedState(if (isError) errorCursorColor else cursorColor) - } - - @Suppress("TopLevelComposableFunctions") - @Composable - fun captionColor(enabled: Boolean, isError: Boolean): State { - return rememberUpdatedState( - newValue = when { - !enabled -> disabledCaptionColor - isError -> errorCaptionColor - else -> captionColor - }, - ) - } +@Suppress("TopLevelComposableFunctions") +@Composable +fun TextFieldColors.captionColor(enabled: Boolean, isError: Boolean): State { + return rememberUpdatedState( + newValue = when { + !enabled -> disabledSupportingTextColor + isError -> errorSupportingTextColor + else -> focusedSupportingTextColor + }, + ) } // endregion Defaults diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/appbar/AppBarWithSearch.kt b/core/ui/src/main/java/com/tangem/core/ui/components/appbar/AppBarWithSearch.kt index ab6996b21d..b9c76c147c 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/appbar/AppBarWithSearch.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/appbar/AppBarWithSearch.kt @@ -7,7 +7,10 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.* +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.material3.TextField import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -105,7 +108,7 @@ private fun CollapsedSearchView( .padding(TangemTheme.dimens.spacing16) .size(TangemTheme.dimens.size24) .clickable { onBackClick() }, - tint = MaterialTheme.colors.onPrimary, + tint = TangemTheme.colors.icon.primary1, ) Column( verticalArrangement = Arrangement.Center, @@ -216,7 +219,8 @@ private fun ExpandedSearchView( onDone = { focusManager.clearFocus() }, ), colors = TangemTextFieldsDefault.defaultTextFieldColors.copy( - placeholderColor = TangemTheme.colors.text.disabled, + focusedPlaceholderColor = TangemTheme.colors.text.disabled, + unfocusedPlaceholderColor = TangemTheme.colors.text.disabled, cursorColor = TangemTheme.colors.text.tertiary, focusedIndicatorColor = Color.Transparent, unfocusedIndicatorColor = Color.Transparent, diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/audits/AuditLabel.kt b/core/ui/src/main/java/com/tangem/core/ui/components/audits/AuditLabel.kt index 8cc27144be..eed177c971 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/audits/AuditLabel.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/audits/AuditLabel.kt @@ -3,7 +3,7 @@ package com.tangem.core.ui.components.audits import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.padding -import androidx.compose.material.Text +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.ui.Modifier diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/fields/SimpleDialogTextField.kt b/core/ui/src/main/java/com/tangem/core/ui/components/fields/SimpleDialogTextField.kt index 098f576a94..197385d9d9 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/fields/SimpleDialogTextField.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/fields/SimpleDialogTextField.kt @@ -8,7 +8,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.BasicTextField -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.drawBehind diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/rows/ActionRow.kt b/core/ui/src/main/java/com/tangem/core/ui/components/rows/ActionRow.kt index 36c44d81b3..2f66450aba 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/rows/ActionRow.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/rows/ActionRow.kt @@ -3,8 +3,8 @@ package com.tangem.core.ui.components.rows import androidx.compose.animation.AnimatedContent 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 diff --git a/core/ui/src/main/res/drawable/ic_trash_24.xml b/core/ui/src/main/res/drawable/ic_trash_24.xml new file mode 100644 index 0000000000..eb3f278341 --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_trash_24.xml @@ -0,0 +1,9 @@ + + + diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseImport.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseImport.kt index f64fd62c0d..0fc50e414e 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseImport.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/ui/MultiWalletSeedPhraseImport.kt @@ -7,7 +7,7 @@ import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll -import androidx.compose.material.OutlinedTextField +import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -137,7 +137,6 @@ private fun PhraseBlock(state: MultiWalletSeedPhraseUM.Import, modifier: Modifie Column( modifier = modifier.fillMaxWidth(), ) { - // TODO migrate to material3 OutlinedTextField( modifier = Modifier .fillMaxWidth() diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/AboutSeedPhraseScreen.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/AboutSeedPhraseScreen.kt index bdeb4fe70e..e0cab80df9 100644 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/AboutSeedPhraseScreen.kt +++ b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/AboutSeedPhraseScreen.kt @@ -6,8 +6,8 @@ import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape -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 diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/ImportSeedPhraseScreen.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/ImportSeedPhraseScreen.kt index bc6e59c4dd..7c03fef7bc 100644 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/ImportSeedPhraseScreen.kt +++ b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/ImportSeedPhraseScreen.kt @@ -7,8 +7,8 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.OutlinedTextField -import androidx.compose.material.Text +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/PassphraseInfoBottomSheet.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/PassphraseInfoBottomSheet.kt index cf5f16d4d0..cddeb6277c 100644 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/PassphraseInfoBottomSheet.kt +++ b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/PassphraseInfoBottomSheet.kt @@ -5,8 +5,8 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -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 diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/YourSeedPhraseScreen.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/YourSeedPhraseScreen.kt index e5d110febd..2f7f864d6e 100644 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/YourSeedPhraseScreen.kt +++ b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/YourSeedPhraseScreen.kt @@ -5,7 +5,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.* 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.Alignment import androidx.compose.ui.Modifier diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/components/OnboardingDescriptionBlock.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/components/OnboardingDescriptionBlock.kt index e0ee2d086e..52806b14c3 100644 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/components/OnboardingDescriptionBlock.kt +++ b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/components/OnboardingDescriptionBlock.kt @@ -5,7 +5,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth 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.Modifier import androidx.compose.ui.text.style.TextAlign diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/AutosizeTextField.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/AutosizeTextField.kt index 0033a1971b..2a6b4ed8ea 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/AutosizeTextField.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/AutosizeTextField.kt @@ -7,7 +7,7 @@ import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.selection.LocalTextSelectionColors import androidx.compose.foundation.text.selection.TextSelectionColors -import androidx.compose.material.Text +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Modifier diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/ChooseProviderBottomSheet.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/ChooseProviderBottomSheet.kt index 44fae2d1f8..e8078c5bee 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/ChooseProviderBottomSheet.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/ChooseProviderBottomSheet.kt @@ -5,8 +5,8 @@ import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding -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 diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt index c06a97f04e..6da65023c5 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt @@ -8,8 +8,8 @@ import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.material.Scaffold -import androidx.compose.material.Text +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt index 81a94f3702..81430c0cfa 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt @@ -10,10 +10,9 @@ import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Icon -import androidx.compose.material.IconButton -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text import androidx.compose.material3.ripple import androidx.compose.runtime.* import androidx.compose.ui.Alignment @@ -195,7 +194,7 @@ private fun Header(type: TransactionCardType, balance: String, modifier: Modifie text = type.header.resolveReference(), color = titleColor, maxLines = 1, - style = MaterialTheme.typography.subtitle2, + style = TangemTheme.typography.subtitle2, modifier = Modifier .align(Alignment.CenterVertically), ) @@ -205,7 +204,7 @@ private fun Header(type: TransactionCardType, balance: String, modifier: Modifie Text( text = it, color = TangemTheme.colors.text.tertiary, - style = MaterialTheme.typography.body2, + style = TangemTheme.typography.body2, modifier = Modifier .align(Alignment.CenterVertically), ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletDropDownItems.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletDropDownItems.kt index 6e9166db40..a4270e37ee 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletDropDownItems.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletDropDownItems.kt @@ -1,10 +1,10 @@ package com.tangem.feature.wallet.presentation.wallet.state.model -import androidx.compose.ui.graphics.vector.ImageVector +import androidx.annotation.DrawableRes import com.tangem.core.ui.extensions.TextReference internal data class WalletDropDownItems( val text: TextReference, - val icon: ImageVector, + @DrawableRes val icon: Int, val onClick: () -> Unit, ) \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWalletCardDropDownItemsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWalletCardDropDownItemsTransformer.kt index f9ea74d599..9357042921 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWalletCardDropDownItemsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetWalletCardDropDownItemsTransformer.kt @@ -1,8 +1,5 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.Delete -import androidx.compose.material.icons.outlined.Edit import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.wallet.impl.R @@ -67,12 +64,12 @@ internal class SetWalletCardDropDownItemsTransformer( persistentListOf( WalletDropDownItems( text = resourceReference(id = R.string.common_rename), - icon = Icons.Outlined.Edit, + icon = R.drawable.ic_edit_24, onClick = { clickIntents.onRenameBeforeConfirmationClick(userWalletId) }, ), WalletDropDownItems( text = resourceReference(id = R.string.common_delete), - icon = Icons.Outlined.Delete, + icon = R.drawable.ic_trash_24, onClick = { clickIntents.onDeleteBeforeConfirmationClick(userWalletId) }, ), ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletCard.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletCard.kt index 3d366acb33..a11dba3be1 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletCard.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletCard.kt @@ -26,6 +26,7 @@ import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter @@ -227,7 +228,7 @@ private fun ManageWalletContextMenu( dropDownItems.fastForEach { item -> MenuItem( text = item.text, - imageVector = item.icon, + imageVector = ImageVector.vectorResource(id = item.icon), onClick = { onDismissRequest() item.onClick() From 6d7ae39ba2c9a5a2e4fa0df549ae56a027be358a Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 27 Feb 2025 17:02:13 +0300 Subject: [PATCH 38/54] Updated on 2026-08-14 --- .../DefaultOnboardingMultiWalletComponent.kt | 6 +- .../child/chooseoption/ui/CarouselItems.kt | 29 +++++++ .../chooseoption/ui/Wallet1ChooseOption.kt | 76 ++++++++++++++----- .../impl/model/OnboardingMultiWalletModel.kt | 10 ++- .../v2/multiwallet/impl/model/Utils.kt | 14 ++-- .../impl/ui/OnboardingMultiWallet.kt | 4 +- 6 files changed, 108 insertions(+), 31 deletions(-) create mode 100644 features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/chooseoption/ui/CarouselItems.kt diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt index 51bf2171ca..989f0fd302 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt @@ -81,6 +81,8 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor backups = model.backups, ) + val backButtonClickFlow = MutableSharedFlow() + private val childStack: Value> = childStack( key = "innerStack", @@ -96,8 +98,6 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor }, ) - val backButtonClickFlow = MutableSharedFlow() - override val innerNavigation: InnerNavigation = object : InnerNavigation { override val state = innerNavigationStateFlow @@ -117,7 +117,7 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor source = bottomSheetNavigation, serializer = null, handleBackButton = false, - childFactory = { configuration, componentContext -> + childFactory = { _, componentContext -> MultiWalletAccessCodeComponent( context = childByContext(componentContext), params = childParams, diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/chooseoption/ui/CarouselItems.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/chooseoption/ui/CarouselItems.kt new file mode 100644 index 0000000000..0af1cba768 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/chooseoption/ui/CarouselItems.kt @@ -0,0 +1,29 @@ +package com.tangem.features.onboarding.v2.multiwallet.impl.child.chooseoption.ui + +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.features.onboarding.v2.impl.R + +internal val CarouselItems = listOf( + CarouselItem( + title = resourceReference(R.string.onboarding_wallet_info_title_first), + subtitle = resourceReference(R.string.onboarding_wallet_info_subtitle_first), + ), + CarouselItem( + title = resourceReference(R.string.onboarding_wallet_info_title_second), + subtitle = resourceReference(R.string.onboarding_wallet_info_subtitle_second), + ), + CarouselItem( + title = resourceReference(R.string.onboarding_wallet_info_title_third), + subtitle = resourceReference(R.string.onboarding_wallet_info_subtitle_third), + ), + CarouselItem( + title = resourceReference(R.string.onboarding_wallet_info_title_fourth), + subtitle = resourceReference(R.string.onboarding_wallet_info_subtitle_fourth), + ), +) + +internal data class CarouselItem( + val title: TextReference, + val subtitle: TextReference, +) \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/chooseoption/ui/Wallet1ChooseOption.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/chooseoption/ui/Wallet1ChooseOption.kt index b873a9e6b8..02d9a6eb9f 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/chooseoption/ui/Wallet1ChooseOption.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/chooseoption/ui/Wallet1ChooseOption.kt @@ -1,10 +1,15 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.child.chooseoption.ui +import androidx.compose.animation.animateColorAsState +import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.* +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign @@ -12,6 +17,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.tangem.core.ui.components.PrimaryButton import com.tangem.core.ui.components.SecondaryButton +import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview @@ -30,30 +36,44 @@ fun Wallet1ChooseOption( .navigationBarsPadding(), verticalArrangement = Arrangement.Bottom, ) { - // val pagerState = rememberPagerState(pageCount = { 10 }) // TODO [REDACTED_TASK_KEY] - Column( Modifier .fillMaxWidth() .verticalScroll(rememberScrollState()) - .padding(start = 32.dp, end = 32.dp, bottom = 16.dp) - .weight(1f), + .weight(1f) + .padding(top = 32.dp, bottom = 16.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { - Text( - text = stringResourceSafe(R.string.onboarding_wallet_info_title_first), - style = TangemTheme.typography.h2, - color = TangemTheme.colors.text.primary1, - textAlign = TextAlign.Center, - modifier = Modifier.padding(top = 16.dp), - ) + val pagerState = rememberPagerState { CarouselItems.size } - Text( - text = stringResourceSafe(R.string.onboarding_wallet_info_subtitle_first), - style = TangemTheme.typography.body1, - color = TangemTheme.colors.text.secondary, - textAlign = TextAlign.Center, - modifier = Modifier.padding(top = 12.dp), + HorizontalPager(pagerState) { selectedIndex -> + Column( + modifier = Modifier + .padding(start = 32.dp, end = 32.dp, bottom = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + val item = CarouselItems[selectedIndex] + Text( + text = item.title.resolveReference(), + style = TangemTheme.typography.h2, + color = TangemTheme.colors.text.primary1, + textAlign = TextAlign.Center, + modifier = Modifier.padding(top = 16.dp), + ) + Text( + text = item.subtitle.resolveReference(), + style = TangemTheme.typography.body1, + color = TangemTheme.colors.text.secondary, + textAlign = TextAlign.Center, + modifier = Modifier.padding(top = 12.dp), + ) + } + } + + Dots( + modifier = Modifier.align(Alignment.CenterHorizontally), + count = CarouselItems.size, + selectedIndex = pagerState.currentPage, ) } @@ -77,6 +97,28 @@ fun Wallet1ChooseOption( } } +@Composable +private fun Dots(count: Int, selectedIndex: Int, modifier: Modifier = Modifier) { + val generalColor = TangemTheme.colors.icon.informative + val selectedColor = TangemTheme.colors.icon.primary1 + + Row( + modifier = modifier, + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + repeat(count) { index -> + val color by animateColorAsState(if (index == selectedIndex) selectedColor else generalColor) + + Canvas(Modifier.size(7.dp)) { + drawCircle( + color = color, + radius = size.width / 2f, + ) + } + } + } +} + @Preview(showBackground = true) @Composable private fun Preview() { diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt index 725d8be92e..8ca4e7faf4 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt @@ -8,6 +8,7 @@ import com.tangem.core.decompose.navigation.Router import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.datasource.local.preferences.PreferencesKeys import com.tangem.domain.models.scan.CardDTO +import com.tangem.domain.models.scan.ProductType import com.tangem.domain.wallets.usecase.GetCardImageUseCase import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent import com.tangem.features.onboarding.v2.multiwallet.impl.analytics.OnboardingEvent @@ -116,8 +117,13 @@ internal class OnboardingMultiWalletModel @Inject constructor( card.wallets.isNotEmpty() && card.backupStatus == CardDTO.BackupStatus.NoBackup && scanResponse.primaryCard == null -> OnboardingMultiWalletState.Step.ScanPrimary - card.wallets.isNotEmpty() && card.backupStatus == CardDTO.BackupStatus.NoBackup -> - OnboardingMultiWalletState.Step.AddBackupDevice + card.wallets.isNotEmpty() && card.backupStatus == CardDTO.BackupStatus.NoBackup -> { + if (scanResponse.productType == ProductType.Wallet) { + OnboardingMultiWalletState.Step.ChooseBackupOption + } else { + OnboardingMultiWalletState.Step.AddBackupDevice + } + } card.wallets.isNotEmpty() && card.backupStatus?.isActive == true -> OnboardingMultiWalletState.Step.Finalize else -> diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/Utils.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/Utils.kt index 7c1d7416ed..1f4d1ee3a6 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/Utils.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/Utils.kt @@ -5,13 +5,13 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.features.onboarding.v2.impl.R fun screenTitleByStep(step: OnboardingMultiWalletState.Step): TextReference = when (step) { - OnboardingMultiWalletState.Step.CreateWallet -> - resourceReference(R.string.onboarding_create_wallet_header) + OnboardingMultiWalletState.Step.SeedPhrase, + OnboardingMultiWalletState.Step.CreateWallet, + -> resourceReference(R.string.onboarding_create_wallet_header) OnboardingMultiWalletState.Step.ScanPrimary, OnboardingMultiWalletState.Step.AddBackupDevice, - -> - resourceReference(R.string.onboarding_navbar_title_creating_backup) - OnboardingMultiWalletState.Step.Finalize -> - resourceReference(R.string.onboarding_button_finalize_backup) - else -> error("No title for the step") + -> resourceReference(R.string.onboarding_navbar_title_creating_backup) + OnboardingMultiWalletState.Step.ChooseBackupOption -> resourceReference(R.string.onboarding_getting_started) + OnboardingMultiWalletState.Step.Finalize -> resourceReference(R.string.onboarding_button_finalize_backup) + OnboardingMultiWalletState.Step.Done -> resourceReference(R.string.common_done) } \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/ui/OnboardingMultiWallet.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/ui/OnboardingMultiWallet.kt index ae225a9f48..62bc6aaf7a 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/ui/OnboardingMultiWallet.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/ui/OnboardingMultiWallet.kt @@ -51,13 +51,13 @@ internal fun OnboardingMultiWallet( modifier = Modifier .padding(horizontal = 34.dp) .padding(top = 20.dp) - .weight(.4f) + .weight(.48f) .fillMaxWidth(), state = artworksState, ) Box( - modifier = Modifier.weight(.44f), + modifier = Modifier.weight(.52f), contentAlignment = Alignment.BottomStart, ) { childContent(Modifier) From a09aae7e41ae14827badc96fb988fa1e830a358a Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 25 Feb 2025 17:17:19 +0500 Subject: [PATCH 39/54] Updated on 2026-08-14 --- .../com/tangem/tap/domain/TangemSigner.kt | 36 +++++++++ .../tap/domain/tasks/MultiSignHashTask.kt | 80 +++++++++++++++++++ common/ui/build.gradle.kts | 1 + .../ui/notifications/NotificationsFactory.kt | 1 + .../ui/tokens/TokenItemStateConverter.kt | 14 +++- .../data/staking/DefaultStakingRepository.kt | 13 ++- .../stakekit/action/StakingActionType.kt | 8 ++ .../TokenListFiatBalanceOperations.kt | 24 ++++-- .../operations/TokenListSortingOperations.kt | 7 +- .../impl/presentation/model/StakingModel.kt | 45 ++++++----- .../presentation/state/StakingNotification.kt | 8 ++ .../SetConfirmationStateInitTransformer.kt | 9 +-- .../SetInitialDataStateTransformer.kt | 18 +++-- .../AddStakingNotificationsTransformer.kt | 14 +--- .../StakingInfoNotificationsFactory.kt | 57 ++++++++++++- .../state/utils/StakingPendingActionUtils.kt | 13 +-- .../ui/StakingConfirmationContent.kt | 2 + ...TokenDetailsBalanceSelectStateConverter.kt | 29 ++++--- .../TokenDetailsLoadedBalanceConverter.kt | 12 ++- .../tokendetails/state/utils/BalanceUtils.kt | 8 +- .../CryptoCurrencyToDraggableItemConverter.kt | 8 +- gradle/tangem_dependencies.toml | 4 +- .../com/tangem/lib/crypto/BlockchainUtils.kt | 13 +++ 23 files changed, 337 insertions(+), 87 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/domain/tasks/MultiSignHashTask.kt diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt b/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt index 7f5f095079..dffd82ec11 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt @@ -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, + publicKey: Wallet.PublicKey, + ): CompletionResult> { + 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( diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/MultiSignHashTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/MultiSignHashTask.kt new file mode 100644 index 0000000000..d1d0d3dc53 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/tasks/MultiSignHashTask.kt @@ -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, + val totalSignedHashes: Int?, + val remainingSignatures: Int?, + val batchId: String?, +) : CommandResponse + +class MultiSignHashTask( + private val dataToSign: List, + private val publicKey: Wallet.PublicKey, + private val pairWalletPublicKey: ByteArray?, +) : CardSessionRunnable { + + override fun run(session: CardSession, callback: CompletionCallback) { + 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, + ) { + 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)) + } + } + } + } +} \ No newline at end of file diff --git a/common/ui/build.gradle.kts b/common/ui/build.gradle.kts index a59d399816..42a053ad9b 100644 --- a/common/ui/build.gradle.kts +++ b/common/ui/build.gradle.kts @@ -27,6 +27,7 @@ dependencies { /** Project - Common */ implementation(projects.core.ui) implementation(projects.core.utils) + implementation(projects.libs.crypto) /** Project - Domain */ implementation(projects.domain.appCurrency.models) diff --git a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt index 78d11c9b2f..69f181a806 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt @@ -364,6 +364,7 @@ object NotificationsFactory { ) } } + else -> return } } diff --git a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt index d209e29338..481946ed6b 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt @@ -15,6 +15,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.models.StatusSource import com.tangem.domain.staking.model.stakekit.YieldBalance import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.lib.crypto.BlockchainUtils import com.tangem.utils.StringsSigns.DASH_SIGN import com.tangem.utils.converter.Converter import com.tangem.utils.extensions.isZero @@ -199,7 +200,11 @@ class TokenItemStateConverter( is CryptoCurrencyStatus.NoAccount, -> { TokenItemState.Subtitle2State.TextContent( - text = status.getFormattedCryptoAmount(includeStaking = true), + text = status.getFormattedCryptoAmount( + includeStaking = BlockchainUtils.isIncludeStakingTotalBalance( + status.currency.network.id.value, + ), + ), isFlickering = status.value.isFlickering(), ) } @@ -222,7 +227,12 @@ class TokenItemStateConverter( is CryptoCurrencyStatus.NoAccount, -> { TokenItemState.FiatAmountState.Content( - text = status.getFormattedFiatAmount(appCurrency = appCurrency, includeStaking = true), + text = status.getFormattedFiatAmount( + appCurrency = appCurrency, + includeStaking = BlockchainUtils.isIncludeStakingTotalBalance( + status.currency.network.id.value, + ), + ), isFlickering = status.value.isFlickering(), icons = buildList { if (!status.getStakedBalance().isZero()) { diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt index 25634c3787..750d106745 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt @@ -34,6 +34,7 @@ import com.tangem.datasource.local.token.StakingBalanceStore import com.tangem.datasource.local.token.StakingYieldsStore import com.tangem.datasource.local.token.converter.StakingNetworkTypeConverter import com.tangem.datasource.local.token.converter.TokenConverter +import com.tangem.domain.common.TapWorkarounds.isWallet2 import com.tangem.domain.staking.model.StakingApproval import com.tangem.domain.staking.model.StakingAvailability import com.tangem.domain.staking.model.StakingEntryInfo @@ -55,6 +56,7 @@ import com.tangem.domain.tokens.model.Network import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.usecase.GetUserWalletUseCase +import com.tangem.lib.crypto.BlockchainUtils.isCardano import com.tangem.lib.crypto.BlockchainUtils.isSolana import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.extensions.orZero @@ -219,14 +221,11 @@ internal class DefaultStakingRepository( val userWallet = getUserWalletUseCase(userWalletId).getOrElse { error("Failed to get user wallet") } - + val blockchainId = cryptoCurrency.network.id.value return when { - isSolana(cryptoCurrency.network.id.value) -> { - INVALID_BATCHES_FOR_SOLANA.contains(userWallet.scanResponse.card.batchId) - } - else -> { - false - } + isSolana(blockchainId) -> INVALID_BATCHES_FOR_SOLANA.contains(userWallet.scanResponse.card.batchId) + isCardano(blockchainId) -> !userWallet.scanResponse.card.isWallet2 + else -> false } } diff --git a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/action/StakingActionType.kt b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/action/StakingActionType.kt index 01e02cea2f..467bb051aa 100644 --- a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/action/StakingActionType.kt +++ b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/action/StakingActionType.kt @@ -39,4 +39,12 @@ enum class StakingActionType { MIGRATE -> "Migrate" UNKNOWN -> "Unknown" } + + val isRestake + get() = when (this) { + RESTAKE, + STAKE, + -> true + else -> false + } } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt index e4d319c4ff..a761548539 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt @@ -7,6 +7,7 @@ import com.tangem.domain.staking.model.stakekit.YieldBalance import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.model.TotalFiatBalance import com.tangem.lib.crypto.BlockchainUtils +import com.tangem.lib.crypto.BlockchainUtils.isIncludeStakingTotalBalance import com.tangem.utils.extensions.orZero import java.math.BigDecimal @@ -21,6 +22,8 @@ internal class TokenListFiatBalanceOperations( if (isAnyTokenLoading) return fiatBalance for (token in currencies) { + val networkId = token.currency.network.id.value + val includeStakingBalance = isIncludeStakingTotalBalance(networkId) when (val status = token.value) { is CryptoCurrencyStatus.Loading -> { fiatBalance = TotalFiatBalance.Loading @@ -35,7 +38,7 @@ internal class TokenListFiatBalanceOperations( is CryptoCurrencyStatus.Unreachable, is CryptoCurrencyStatus.NoAmount, -> { - if (BlockchainUtils.isIncludeToBalanceOnError(token.currency.network.id.value)) { + if (BlockchainUtils.isIncludeToBalanceOnError(networkId)) { fiatBalance = recalculateNoAccountBalance(status, fiatBalance) } else { fiatBalance = TotalFiatBalance.Failed @@ -46,10 +49,10 @@ internal class TokenListFiatBalanceOperations( fiatBalance = recalculateNoAccountBalance(status, fiatBalance) } is CryptoCurrencyStatus.Loaded -> { - fiatBalance = recalculateBalance(status, fiatBalance) + fiatBalance = recalculateBalance(status, fiatBalance, includeStakingBalance) } is CryptoCurrencyStatus.Custom -> { - fiatBalance = recalculateBalance(status, fiatBalance) + fiatBalance = recalculateBalance(status, fiatBalance, includeStakingBalance) } } } @@ -74,12 +77,16 @@ internal class TokenListFiatBalanceOperations( private fun recalculateBalance( status: CryptoCurrencyStatus.Loaded, currentBalance: TotalFiatBalance, + includeStakingBalance: Boolean, ): TotalFiatBalance { return with(currentBalance) { val yieldBalance = status.yieldBalance as? YieldBalance.Data val stakingBalance = yieldBalance?.getTotalWithRewardsStakingBalance().orZero() - val fiatStakingBalance = status.fiatRate.times(stakingBalance) - + val fiatStakingBalance = if (includeStakingBalance) { + status.fiatRate.times(stakingBalance) + } else { + BigDecimal.ZERO + } (this as? TotalFiatBalance.Loaded)?.copy( amount = this.amount + status.fiatAmount + fiatStakingBalance, ) ?: TotalFiatBalance.Loaded( @@ -93,11 +100,16 @@ internal class TokenListFiatBalanceOperations( private fun recalculateBalance( status: CryptoCurrencyStatus.Custom, currentBalance: TotalFiatBalance, + includeStakingBalance: Boolean, ): TotalFiatBalance { return with(currentBalance) { val isTokenAmountCanBeSummarized = status.fiatAmount != null val yieldBalance = (status.yieldBalance as? YieldBalance.Data)?.getTotalWithRewardsStakingBalance().orZero() - val fiatYieldBalance = status.fiatRate?.times(yieldBalance).orZero() + val fiatYieldBalance = if (includeStakingBalance) { + status.fiatRate?.times(yieldBalance).orZero() + } else { + BigDecimal.ZERO + } (this as? TotalFiatBalance.Loaded)?.copy( amount = this.amount + status.fiatAmount.orZero() + fiatYieldBalance, isAllAmountsSummarized = isTokenAmountCanBeSummarized, diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListSortingOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListSortingOperations.kt index 6e27d5c2d7..be9623f89e 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListSortingOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListSortingOperations.kt @@ -9,6 +9,7 @@ import arrow.core.raise.ensureNotNull import arrow.core.toNonEmptyListOrNull import com.tangem.domain.staking.model.stakekit.YieldBalance import com.tangem.domain.tokens.model.* +import com.tangem.lib.crypto.BlockchainUtils import com.tangem.utils.extensions.orZero import java.math.BigDecimal @@ -99,7 +100,11 @@ internal class TokenListSortingOperations( private fun CryptoCurrencyStatus.getTotalBalance(): BigDecimal { val yieldBalance = value.yieldBalance as? YieldBalance.Data val totalYieldBalance = yieldBalance?.getTotalWithRewardsStakingBalance().orZero() - val totalFiatYieldBalance = totalYieldBalance.multiply(value.fiatRate.orZero()) + val totalFiatYieldBalance = if (!BlockchainUtils.isIncludeStakingTotalBalance(currency.network.id.value)) { + totalYieldBalance.multiply(value.fiatRate.orZero()) + } else { + BigDecimal.ZERO + } return value.fiatAmount?.plus(totalFiatYieldBalance).orZero() } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt index b57e0256f7..b180a8eaa3 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt @@ -36,7 +36,6 @@ import com.tangem.domain.staking.model.StakingApproval import com.tangem.domain.staking.model.stakekit.* import com.tangem.domain.staking.model.stakekit.action.StakingAction import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType -import com.tangem.domain.staking.model.stakekit.action.StakingActionType import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction import com.tangem.domain.tokens.* import com.tangem.domain.tokens.model.CryptoCurrency @@ -45,8 +44,6 @@ import com.tangem.domain.transaction.error.GetFeeError import com.tangem.domain.transaction.usecase.CreateApprovalTransactionUseCase import com.tangem.domain.transaction.usecase.GetAllowanceUseCase import com.tangem.domain.transaction.usecase.SendTransactionUseCase -import com.tangem.domain.transaction.usecase.ValidateTransactionUseCase -import com.tangem.domain.utils.convertToSdkAmount import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.usecase.GetUserWalletUseCase @@ -72,6 +69,7 @@ import com.tangem.features.staking.impl.presentation.state.transformers.validato import com.tangem.features.staking.impl.presentation.state.utils.checkAndCalculateSubtractedAmount import com.tangem.features.staking.impl.presentation.state.utils.isSingleAction import com.tangem.features.staking.impl.presentation.state.utils.withStubUnstakeAction +import com.tangem.lib.crypto.BlockchainUtils import com.tangem.utils.Provider import com.tangem.utils.coroutines.* import com.tangem.utils.extensions.isSingleItem @@ -108,7 +106,6 @@ internal class StakingModel @Inject constructor( private val getCardInfoUseCase: GetCardInfoUseCase, private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase, private val getBalanceNotEnoughForFeeWarningUseCase: GetBalanceNotEnoughForFeeWarningUseCase, - private val validateTransactionUseCase: ValidateTransactionUseCase, private val getCurrencyCheckUseCase: GetCurrencyCheckUseCase, private val isAmountSubtractAvailableUseCase: IsAmountSubtractAvailableUseCase, private val isAnyTokenStakedUseCase: IsAnyTokenStakedUseCase, @@ -123,7 +120,7 @@ internal class StakingModel @Inject constructor( private val shareManager: ShareManager, @DelayedWork private val coroutineScope: CoroutineScope, private val innerRouter: InnerStakingRouter, - private val appRouter: AppRouter, + appRouter: AppRouter, ) : Model(), StakingClickIntents { val uiState: StateFlow = stateController.uiState @@ -239,7 +236,7 @@ internal class StakingModel @Inject constructor( return } isInitialInfoStep && noBalanceState -> { - stateController.update( + val list = buildList { SetConfirmationStateInitTransformer( isEnter = true, isExplicitExit = false, @@ -248,8 +245,27 @@ internal class StakingModel @Inject constructor( stakingApproval = stakingApproval, stakingAllowance = stakingAllowance, yieldArgs = yield.args, - ), - ) + ).let(::add) + if (BlockchainUtils.isSkipAmountEnter(uiState.value.cryptoCurrencyBlockchainId)) { + ValidatorSelectChangeTransformer( + selectedValidator = yield.preferredValidators.firstOrNull(), + yield = yield, + ).let(::add) + SetAmountDataTransformer( + clickIntents = this@StakingModel, + cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus }, + userWalletProvider = Provider { userWallet }, + appCurrencyProvider = Provider { appCurrency }, + ).let(::add) + AmountMaxValueStateTransformer( + cryptoCurrencyStatus = cryptoCurrencyStatus, + minimumTransactionAmount = minimumTransactionAmount, + actionType = uiState.value.actionType, + yield = yield, + ).let(::add) + } + } + stateController.updateAll(*list.toTypedArray()) } } stakingStateRouter.onNextClick() @@ -633,16 +649,6 @@ internal class StakingModel @Inject constructor( } else { null } - val validation = amount?.let { - validateTransactionUseCase( - userWalletId = userWalletId, - amount = amount.convertToSdkAmount(cryptoCurrencyStatus.currency), - fee = feeState?.fee, - memo = null, - destination = "", - network = cryptoCurrencyStatus.currency.network, - ).leftOrNull() - } val balanceAfterTransaction = calculateBalanceAfterTransaction( amount = amount.orZero(), @@ -663,7 +669,6 @@ internal class StakingModel @Inject constructor( appCurrencyProvider = Provider { appCurrency }, feeCryptoCurrencyStatus = feeCryptoCurrencyStatus, currencyWarning = currencyWarning, - validatorError = validation, currencyCheck = currencyStatus, isSubtractAvailable = isAmountSubtractAvailable, feeError = feeError, @@ -1021,7 +1026,7 @@ internal class StakingModel @Inject constructor( } private fun isExplicitExit(balanceType: BalanceType, pendingAction: PendingAction?): Boolean { - return balanceType == BalanceType.STAKED && pendingAction?.type != StakingActionType.RESTAKE + return balanceType == BalanceType.STAKED && pendingAction?.type?.isRestake == false } private fun isAssentState(): Boolean { diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingNotification.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingNotification.kt index d9fd203280..ef6fe9940e 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingNotification.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingNotification.kt @@ -29,6 +29,14 @@ internal object StakingNotification { title = resourceReference(R.string.common_error), subtitle = subtitle, ) + + data class CardanoMinimumBalance( + val title: TextReference, + val subtitle: TextReference, + ) : StakingNotification.Error( + title = title, + subtitle = subtitle, + ) } sealed class Warning( diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt index 8a2f781acc..dcc57f1a99 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt @@ -11,6 +11,7 @@ import com.tangem.features.staking.impl.presentation.state.* import com.tangem.features.staking.impl.presentation.state.utils.isCompositePendingActions import com.tangem.features.staking.impl.presentation.state.utils.isTronStakedBalance import com.tangem.lib.crypto.BlockchainUtils +import com.tangem.lib.crypto.BlockchainUtils.isSkipAmountEnter import com.tangem.utils.extensions.isPositive import com.tangem.utils.transformer.Transformer import kotlinx.collections.immutable.ImmutableList @@ -45,12 +46,12 @@ internal class SetConfirmationStateInitTransformer( override fun transform(prevState: StakingUiState): StakingUiState { val actionType = when { isEnter -> StakingActionCommonType.Enter( - skipEnterAmount = isAmountEnterSkipped(prevState), + skipEnterAmount = isSkipAmountEnter(prevState.cryptoCurrencyBlockchainId), ) isImplicitExit || isExplicitExit -> StakingActionCommonType.Exit(isPartiallyUnstakeDisabled(prevState)) else -> when (pendingAction?.type) { StakingActionType.STAKE -> StakingActionCommonType.Enter( - skipEnterAmount = isAmountEnterSkipped(prevState), + skipEnterAmount = isSkipAmountEnter(prevState.cryptoCurrencyBlockchainId), ) StakingActionType.UNSTAKE -> StakingActionCommonType.Exit( partiallyUnstakeDisabled = isPartiallyUnstakeDisabled(prevState), @@ -100,8 +101,4 @@ internal class SetConfirmationStateInitTransformer( val max = exitAmount.maximum ?: return false return !min.isPositive() && !max.isPositive() } - - private fun isAmountEnterSkipped(state: StakingUiState): Boolean { - return BlockchainUtils.isCardano(state.cryptoCurrencyBlockchainId) - } } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt index 873626c210..e168a4db08 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt @@ -1,30 +1,33 @@ package com.tangem.features.staking.impl.presentation.state.transformers +import com.tangem.blockchain.common.Blockchain import com.tangem.common.extensions.remove import com.tangem.common.ui.amountScreen.converters.AmountStateConverter import com.tangem.common.ui.amountScreen.models.AmountParameters import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary +import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter import com.tangem.core.ui.components.list.RoundedListWithDividersItemData import com.tangem.core.ui.extensions.* import com.tangem.core.ui.format.bigdecimal.crypto import com.tangem.core.ui.format.bigdecimal.format import com.tangem.core.ui.format.bigdecimal.percent -import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.staking.model.stakekit.BalanceItem import com.tangem.domain.staking.model.stakekit.Yield import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.wallets.models.UserWallet import com.tangem.features.staking.impl.R -import com.tangem.features.staking.impl.presentation.state.* +import com.tangem.features.staking.impl.presentation.model.StakingClickIntents +import com.tangem.features.staking.impl.presentation.state.InnerYieldBalanceState +import com.tangem.features.staking.impl.presentation.state.StakingStates +import com.tangem.features.staking.impl.presentation.state.StakingStep +import com.tangem.features.staking.impl.presentation.state.StakingUiState import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType import com.tangem.features.staking.impl.presentation.state.converters.RewardsValidatorStateConverter import com.tangem.features.staking.impl.presentation.state.converters.YieldBalancesConverter import com.tangem.features.staking.impl.presentation.state.utils.getRewardScheduleText -import com.tangem.features.staking.impl.presentation.model.StakingClickIntents -import com.tangem.lib.crypto.BlockchainUtils.isPolkadot import com.tangem.utils.Provider import com.tangem.utils.isNullOrZero import com.tangem.utils.transformer.Transformer @@ -145,7 +148,8 @@ internal class SetInitialDataStateTransformer( cryptoCurrencyStatus: CryptoCurrencyStatus, ): RoundedListWithDividersItemData? { val minimumCryptoAmount = yield.args.enter.args[Yield.Args.ArgType.AMOUNT]?.minimum ?: return null - if (!isPolkadot(cryptoCurrencyStatus.currency.network.id.value)) return null + val blockchainId = cryptoCurrencyStatus.currency.network.id.value + if (!showMinimumRequirementInfo(blockchainId)) return null val formattedAmount = minimumCryptoAmount.format { crypto(cryptoCurrencyStatus.currency) } @@ -239,6 +243,10 @@ internal class SetInitialDataStateTransformer( return resourceReference(R.string.common_range, wrappedList(formattedMinApr, formattedMaxApr)) } + private fun showMinimumRequirementInfo(blockchainId: String): Boolean { + return blockchainId == Blockchain.Polkadot.id || blockchainId == Blockchain.Cardano.id + } + private companion object { val EQUALITY_THRESHOLD = BigDecimal(1E-10) diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt index 7e8f2c875d..c388dff746 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt @@ -1,6 +1,5 @@ package com.tangem.features.staking.impl.presentation.state.transformers.notifications -import com.tangem.blockchain.common.transaction.Fee import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.common.ui.notifications.NotificationUM import com.tangem.common.ui.notifications.NotificationsFactory.addDustWarningNotification @@ -11,7 +10,6 @@ import com.tangem.common.ui.notifications.NotificationsFactory.addFeeUnreachable import com.tangem.common.ui.notifications.NotificationsFactory.addRentExemptionNotification import com.tangem.common.ui.notifications.NotificationsFactory.addReserveAmountErrorNotification import com.tangem.common.ui.notifications.NotificationsFactory.addTransactionLimitErrorNotification -import com.tangem.common.ui.notifications.NotificationsFactory.addValidateTransactionNotifications import com.tangem.core.ui.extensions.networkIconResId import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.staking.model.stakekit.Yield @@ -40,7 +38,6 @@ internal class AddStakingNotificationsTransformer( private val appCurrencyProvider: Provider, private val feeCryptoCurrencyStatus: CryptoCurrencyStatus?, private val currencyWarning: CryptoCurrencyWarning?, - private val validatorError: Throwable?, private val feeError: GetFeeError?, private val currencyCheck: CryptoCurrencyCheck, private val isSubtractAvailable: Boolean, @@ -81,7 +78,7 @@ internal class AddStakingNotificationsTransformer( amountValue = amountValue, feeValue = feeValue, reduceAmountBy = reduceAmountBy, - ).max(minimumRequirement) + ) } else { // No amount is taken from account balance on exit or pending actions BigDecimal.ZERO @@ -212,15 +209,6 @@ internal class AddStakingNotificationsTransformer( appCurrency = appCurrency, cryptoCurrencyStatus = cryptoCurrencyStatus, ) - - // blockchain specific - addValidateTransactionNotifications( - dustValue = currencyCheck.dustValue.orZero(), - minAdaValue = (feeState?.fee as? Fee.CardanoToken)?.minAdaValue, - validationError = validatorError, - cryptoCurrency = cryptoCurrency, - onReduceClick = prevState.clickIntents::onAmountReduceToClick, - ) } private fun MutableList.addStakeExceedBalanceNotification( diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/StakingInfoNotificationsFactory.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/StakingInfoNotificationsFactory.kt index a88e7ace69..ddff3c0e73 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/StakingInfoNotificationsFactory.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/StakingInfoNotificationsFactory.kt @@ -14,6 +14,7 @@ import com.tangem.features.staking.impl.R import com.tangem.features.staking.impl.presentation.state.StakingNotification import com.tangem.features.staking.impl.presentation.state.StakingStates import com.tangem.features.staking.impl.presentation.state.StakingUiState +import com.tangem.lib.crypto.BlockchainUtils.isCardano import com.tangem.lib.crypto.BlockchainUtils.isCosmos import com.tangem.lib.crypto.BlockchainUtils.isTron import com.tangem.utils.Provider @@ -46,7 +47,10 @@ internal class StakingInfoNotificationsFactory( when (prevState.actionType) { is StakingActionCommonType.Enter -> addEnterInfoNotifications(sendingAmount, feeValue) is StakingActionCommonType.Exit -> addExitInfoNotifications() - is StakingActionCommonType.Pending -> addPendingInfoNotifications(prevState) + is StakingActionCommonType.Pending -> { + addCardanoRestakeMinimumAmountNotification(feeValue) + addPendingInfoNotifications(prevState) + } } } @@ -70,7 +74,9 @@ internal class StakingInfoNotificationsFactory( sendingAmount: BigDecimal, feeValue: BigDecimal, ) { + addCardanoStakeMinimumAmountNotification(feeValue) addTronRevoteNotification() + addCardanoStakeNotification() addStakingEntireBalanceNotification(sendingAmount, feeValue) } @@ -149,6 +155,48 @@ internal class StakingInfoNotificationsFactory( } } + private fun MutableList.addCardanoStakeNotification() { + val cryptoCurrencyStatus = cryptoCurrencyStatusProvider() + val isCardano = isCardano(cryptoCurrencyStatus.currency.network.id.value) + + if (isCardano) { + add( + StakingNotification.Info.Ordinary( + title = resourceReference(R.string.staking_notification_additional_ada_deposit_title), + text = resourceReference(R.string.staking_notification_additional_ada_deposit_text), + ), + ) + } + } + + private fun MutableList.addCardanoStakeMinimumAmountNotification(feeValue: BigDecimal) { + val cryptoCurrencyStatus = cryptoCurrencyStatusProvider() + val isCardano = isCardano(cryptoCurrencyStatus.currency.network.id.value) + val balance = cryptoCurrencyStatus.value.amount.orZero() + if (isCardano && balance - feeValue < MINIMUM_STAKE_BALANCE) { + add( + StakingNotification.Error.CardanoMinimumBalance( + title = resourceReference(R.string.staking_notification_minimum_balance_title), + subtitle = resourceReference(R.string.staking_notification_minimum_stake_ada_text), + ), + ) + } + } + + private fun MutableList.addCardanoRestakeMinimumAmountNotification(feeValue: BigDecimal) { + val cryptoCurrencyStatus = cryptoCurrencyStatusProvider() + val isCardano = isCardano(cryptoCurrencyStatus.currency.network.id.value) + val balance = cryptoCurrencyStatus.value.amount.orZero() + if (isCardano && balance - feeValue < MINIMUM_RESTAKE_BALANCE) { + add( + StakingNotification.Error.CardanoMinimumBalance( + title = resourceReference(R.string.staking_notification_minimum_restake_ada_title), + subtitle = resourceReference(R.string.staking_notification_minimum_restake_ada_text), + ), + ) + } + } + private fun MutableList.addStakingEntireBalanceNotification( sendingAmount: BigDecimal, feeValue: BigDecimal, @@ -158,7 +206,7 @@ internal class StakingInfoNotificationsFactory( val isEntireBalance = sendingAmount.plus(feeValue) == balance - if (isEntireBalance && isSubtractAvailable) { + if (isEntireBalance && isSubtractAvailable && !isCardano(cryptoCurrencyStatus.currency.network.id.value)) { add(StakingNotification.Info.StakeEntireBalance) } } @@ -179,4 +227,9 @@ internal class StakingInfoNotificationsFactory( add(StakingNotification.Warning.LowStakedBalance) } } + + private companion object { + val MINIMUM_STAKE_BALANCE = "5".toBigDecimal() + val MINIMUM_RESTAKE_BALANCE = "3".toBigDecimal() + } } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/StakingPendingActionUtils.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/StakingPendingActionUtils.kt index 9287657626..70f2a487aa 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/StakingPendingActionUtils.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/StakingPendingActionUtils.kt @@ -7,6 +7,7 @@ import com.tangem.domain.staking.model.stakekit.PendingAction import com.tangem.domain.staking.model.stakekit.action.StakingActionType import com.tangem.features.staking.impl.presentation.state.BalanceState import com.tangem.lib.crypto.BlockchainUtils.isBSC +import com.tangem.lib.crypto.BlockchainUtils.isCardano import com.tangem.lib.crypto.BlockchainUtils.isSolana import com.tangem.lib.crypto.BlockchainUtils.isTron import kotlinx.collections.immutable.ImmutableList @@ -37,14 +38,12 @@ internal fun StakingActionType?.getPendingActionTitle(): TextReference = when (t internal fun isSingleAction(networkId: String, activeStake: BalanceState): Boolean { val isSingleAction = activeStake.pendingActions.size <= 1 // Either single or none pending actions val isCompositePendingActions = isCompositePendingActions(networkId, activeStake.pendingActions) - val isBscRestake = isBSC(networkId) && activeStake.pendingActions.any { - it.type == StakingActionType.RESTAKE - } + val isRestake = activeStake.pendingActions.any { it.type.isRestake } - return isSingleAction && !isBscRestake || isCompositePendingActions + return isSingleAction && !isRestake || isCompositePendingActions } -internal fun withStubUnstakeAction(networkId: String, activeStake: BalanceState) = if (isBSC(networkId)) { +internal fun withStubUnstakeAction(networkId: String, activeStake: BalanceState) = if (isStubUnstakeAction(networkId)) { activeStake.pendingActions.plus( PendingAction( type = StakingActionType.UNSTAKE, @@ -65,4 +64,8 @@ internal fun isCompositePendingActions(networkId: String, pendingActions: Immuta isSolana(networkId) -> pendingActions?.any { it.type == StakingActionType.WITHDRAW } == true else -> false } +} + +private fun isStubUnstakeAction(networkId: String): Boolean { + return isBSC(networkId) || isCardano(networkId) } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt index 866458c643..49d1aa49dd 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt @@ -5,6 +5,7 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -72,6 +73,7 @@ internal fun StakingConfirmationContent( ) StakingFeeBlock(feeState = state.feeState, isTransactionSent = isTransactionSent) NotificationsBlock(notifications = state.notifications) + Spacer(Modifier) } } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsBalanceSelectStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsBalanceSelectStateConverter.kt index 4a76d6f1c9..5ab5994819 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsBalanceSelectStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsBalanceSelectStateConverter.kt @@ -1,13 +1,14 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory import com.tangem.core.ui.format.bigdecimal.crypto +import com.tangem.core.ui.format.bigdecimal.fiat import com.tangem.core.ui.format.bigdecimal.format -import com.tangem.core.ui.utils.BigDecimalFormatter import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.staking.model.stakekit.YieldBalance import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.feature.tokendetails.presentation.tokendetails.state.* import com.tangem.feature.tokendetails.presentation.tokendetails.state.utils.getBalance +import com.tangem.lib.crypto.BlockchainUtils import com.tangem.utils.Provider import com.tangem.utils.converter.Converter import java.math.BigDecimal @@ -26,7 +27,8 @@ internal class TokenDetailsBalanceSelectStateConverter( val yieldBalance = cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data val stakingCryptoAmount = yieldBalance?.getTotalWithRewardsStakingBalance() val stakingFiatAmount = stakingCryptoAmount?.let { cryptoCurrencyStatus.value.fiatRate?.multiply(it) } - + val includeStakingTotalBalance = + BlockchainUtils.isIncludeStakingTotalBalance(cryptoCurrencyStatus.currency.network.id.value) copy( tokenBalanceBlockState = if (tokenBalanceBlockState is TokenDetailsBalanceBlockState.Content) { tokenBalanceBlockState.copy( @@ -36,11 +38,13 @@ internal class TokenDetailsBalanceSelectStateConverter( stakingFiatAmount = stakingFiatAmount, selectedBalanceType = value.type, appCurrency = appCurrencyProvider(), + includeStaking = includeStakingTotalBalance, ), displayCryptoBalance = formatCryptoAmount( status = cryptoCurrencyStatus, stakingCryptoAmount = stakingCryptoAmount, selectedBalanceType = value.type, + includeStaking = includeStakingTotalBalance, ), ) } else { @@ -55,25 +59,26 @@ internal class TokenDetailsBalanceSelectStateConverter( stakingFiatAmount: BigDecimal?, selectedBalanceType: BalanceType, appCurrency: AppCurrency, + includeStaking: Boolean, ): String { - val fiatAmount = status.fiatAmount ?: return BigDecimalFormatter.EMPTY_BALANCE_SIGN - val totalAmount = fiatAmount.getBalance(selectedBalanceType, stakingFiatAmount) + val fiatAmount = status.fiatAmount?.getBalance(selectedBalanceType, stakingFiatAmount, includeStaking) - return BigDecimalFormatter.formatFiatAmount( - fiatAmount = totalAmount, - fiatCurrencyCode = appCurrency.code, - fiatCurrencySymbol = appCurrency.symbol, - ) + return fiatAmount.format { + fiat( + fiatCurrencyCode = appCurrency.code, + fiatCurrencySymbol = appCurrency.symbol, + ) + } } private fun formatCryptoAmount( status: CryptoCurrencyStatus, stakingCryptoAmount: BigDecimal?, selectedBalanceType: BalanceType, + includeStaking: Boolean, ): String { - val amount = status.value.amount ?: return BigDecimalFormatter.EMPTY_BALANCE_SIGN - val totalAmount = amount.getBalance(selectedBalanceType, stakingCryptoAmount) + val amount = status.value.amount?.getBalance(selectedBalanceType, stakingCryptoAmount, includeStaking) - return totalAmount.format { crypto(status.currency) } + return amount.format { crypto(status.currency) } } } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt index c8b17e62c5..76a4e08cd5 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt @@ -19,13 +19,14 @@ import com.tangem.domain.staking.model.stakekit.RewardBlockType import com.tangem.domain.staking.model.stakekit.YieldBalance import com.tangem.domain.tokens.error.CurrencyStatusError import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.feature.tokendetails.presentation.tokendetails.state.* import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsTxHistoryTransactionStateConverter import com.tangem.feature.tokendetails.presentation.tokendetails.state.utils.getBalance -import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.features.tokendetails.impl.R import com.tangem.lib.crypto.BlockchainUtils.isBSC +import com.tangem.lib.crypto.BlockchainUtils.isIncludeStakingTotalBalance import com.tangem.lib.crypto.BlockchainUtils.isSolana import com.tangem.utils.Provider import com.tangem.utils.StringsSigns.DASH_SIGN @@ -98,6 +99,7 @@ internal class TokenDetailsLoadedBalanceConverter( val stakingCryptoAmount = (status.value.yieldBalance as? YieldBalance.Data)?.getTotalWithRewardsStakingBalance() val stakingFiatAmount = stakingCryptoAmount?.let { status.value.fiatRate?.multiply(it) } val isBalanceSelectorEnabled = !stakingCryptoAmount.isNullOrZero() + val includeStakingTotalBalance = isIncludeStakingTotalBalance(status.currency.network.id.value) return when (status.value) { is CryptoCurrencyStatus.NoQuote, is CryptoCurrencyStatus.Loaded, @@ -112,11 +114,13 @@ internal class TokenDetailsLoadedBalanceConverter( stakingFiatAmount, currentState.selectedBalanceType, appCurrencyProvider(), + includeStakingTotalBalance, ), displayCryptoBalance = formatCryptoAmount( status, stakingCryptoAmount, currentState.selectedBalanceType, + includeStakingTotalBalance, ), balanceSegmentedButtonConfig = currentState.balanceSegmentedButtonConfig, onBalanceSelect = clickIntents::onBalanceSelect, @@ -298,9 +302,10 @@ internal class TokenDetailsLoadedBalanceConverter( stakingFiatAmount: BigDecimal?, selectedBalanceType: BalanceType, appCurrency: AppCurrency, + includeStaking: Boolean, ): String { val fiatAmount = status.fiatAmount ?: return DASH_SIGN - val totalAmount = fiatAmount.getBalance(selectedBalanceType, stakingFiatAmount) + val totalAmount = fiatAmount.getBalance(selectedBalanceType, stakingFiatAmount, includeStaking) return totalAmount.format { fiat( @@ -314,9 +319,10 @@ internal class TokenDetailsLoadedBalanceConverter( status: CryptoCurrencyStatus, stakingCryptoAmount: BigDecimal?, selectedBalanceType: BalanceType, + includeStaking: Boolean, ): String { val amount = status.value.amount ?: return DASH_SIGN - val totalAmount = amount.getBalance(selectedBalanceType, stakingCryptoAmount) + val totalAmount = amount.getBalance(selectedBalanceType, stakingCryptoAmount, includeStaking) return totalAmount.format { crypto(status.currency) } } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/utils/BalanceUtils.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/utils/BalanceUtils.kt index fe714ff2ca..25b4f3ecc1 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/utils/BalanceUtils.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/utils/BalanceUtils.kt @@ -3,8 +3,12 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.utils import com.tangem.feature.tokendetails.presentation.tokendetails.state.BalanceType import java.math.BigDecimal -internal fun BigDecimal.getBalance(selectedBalanceType: BalanceType, stakingAmount: BigDecimal?): BigDecimal { - return if (selectedBalanceType == BalanceType.ALL && stakingAmount != null) { +internal fun BigDecimal.getBalance( + selectedBalanceType: BalanceType, + stakingAmount: BigDecimal?, + includeStaking: Boolean, +): BigDecimal { + return if (selectedBalanceType == BalanceType.ALL && stakingAmount != null && includeStaking) { this.plus(stakingAmount) } else { this diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/utils/converter/items/CryptoCurrencyToDraggableItemConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/utils/converter/items/CryptoCurrencyToDraggableItemConverter.kt index 15ca6ab348..c7302dd54a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/utils/converter/items/CryptoCurrencyToDraggableItemConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/utils/converter/items/CryptoCurrencyToDraggableItemConverter.kt @@ -12,8 +12,10 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem import com.tangem.feature.wallet.presentation.organizetokens.utils.common.getGroupHeaderId import com.tangem.feature.wallet.presentation.organizetokens.utils.common.getTokenItemId +import com.tangem.lib.crypto.BlockchainUtils import com.tangem.utils.Provider import com.tangem.utils.converter.Converter +import com.tangem.utils.extensions.orZero import java.math.BigDecimal internal class CryptoCurrencyToDraggableItemConverter( @@ -63,7 +65,11 @@ internal class CryptoCurrencyToDraggableItemConverter( private fun getFormattedFiatAmount(currency: CryptoCurrencyStatus, appCurrency: AppCurrency): String { val yieldBalance = currency.value.yieldBalance as? YieldBalance.Data val fiatRate = currency.value.fiatRate ?: BigDecimal.ZERO - val fiatYieldBalance = yieldBalance?.getTotalWithRewardsStakingBalance()?.multiply(fiatRate) ?: BigDecimal.ZERO + val fiatYieldBalance = if (BlockchainUtils.isIncludeStakingTotalBalance(currency.currency.network.id.value)) { + yieldBalance?.getTotalWithRewardsStakingBalance()?.multiply(fiatRate).orZero() + } else { + BigDecimal.ZERO + } val fiatAmount = currency.value.fiatAmount ?: return BigDecimalFormatConstants.EMPTY_BALANCE_SIGN return (fiatAmount + fiatYieldBalance).format { fiat(appCurrency.code, appCurrency.symbol) } diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 422608e325..c341dfec4e 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -1,7 +1,7 @@ [versions] -tangemBlockchainSdk = "develop-965" +tangemBlockchainSdk = "develop-967" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "develop-434" +tangemCardSdk = "develop-437" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "2.0.0-alpha.25-tangem-developments8" #tangemVico = "0.0.1" # Keep it! - used for local builds ^ diff --git a/libs/crypto/src/main/java/com/tangem/lib/crypto/BlockchainUtils.kt b/libs/crypto/src/main/java/com/tangem/lib/crypto/BlockchainUtils.kt index d34ef3b532..619324480d 100644 --- a/libs/crypto/src/main/java/com/tangem/lib/crypto/BlockchainUtils.kt +++ b/libs/crypto/src/main/java/com/tangem/lib/crypto/BlockchainUtils.kt @@ -18,6 +18,7 @@ import java.math.BigDecimal * Temporary solution for domain specific logic for Blockchain. * Instead of creating repositories and unnecessary and overkill use cases */ +@Suppress("TooManyFunctions") object BlockchainUtils { private const val XRP_X_ADDRESS = 'X' @@ -137,6 +138,18 @@ object BlockchainUtils { } } + fun isIncludeStakingTotalBalance(blockchainId: String): Boolean { + val blockchain = Blockchain.fromId(blockchainId) + + return blockchain != Blockchain.Cardano + } + + fun isSkipAmountEnter(blockchainId: String): Boolean { + val blockchain = Blockchain.fromId(blockchainId) + + return blockchain == Blockchain.Cardano + } + private fun getNetworkStandardName(blockchain: Blockchain): String { return when (blockchain) { Blockchain.Ethereum, Blockchain.EthereumTestnet -> "ERC20" From a608cec15389b5f61c9ee8b46a2fc619f95fb65a Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 24 Feb 2025 20:24:20 +0700 Subject: [PATCH 40/54] Updated on 2026-08-14 --- .../common/ui/notifications/NotificationUM.kt | 15 +++++++++++++++ .../ui/notifications/NotificationsFactory.kt | 2 ++ .../domain/transaction/error/GetFeeError.kt | 1 + .../domain/transaction/error/ErrorsMapper.kt | 3 +++ gradle/tangem_dependencies.toml | 2 +- 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationUM.kt b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationUM.kt index cb008ba04a..e37d15ae31 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationUM.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationUM.kt @@ -297,6 +297,21 @@ sealed class NotificationUM(val config: NotificationConfig) { ) } + sealed interface Sui { + + data object NotEnoughCoinForTokenTransaction : Error( + title = resourceReference(id = R.string.sui_not_enough_coin_for_fee_title), + subtitle = resourceReference( + id = R.string.sui_not_enough_coin_for_fee_description, + formatArgs = wrappedList( + BigDecimal.ONE.format { + crypto(Blockchain.Sui.currency, Blockchain.Sui.decimals()) + }, + ), + ), + ) + } + sealed interface Koinos { data class InsufficientRecoverableMana( val mana: BigDecimal, diff --git a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt index 69f181a806..347ac937ec 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt @@ -66,6 +66,8 @@ object NotificationsFactory { }, ), ) + is GetFeeError.BlockchainErrors.SuiOneCoinRequired -> + add(NotificationUM.Sui.NotEnoughCoinForTokenTransaction) is GetFeeError.DataError, is GetFeeError.UnknownError, -> add( diff --git a/domain/transaction/models/src/main/kotlin/com/tangem/domain/transaction/error/GetFeeError.kt b/domain/transaction/models/src/main/kotlin/com/tangem/domain/transaction/error/GetFeeError.kt index 48fd54937f..ef18d2916a 100644 --- a/domain/transaction/models/src/main/kotlin/com/tangem/domain/transaction/error/GetFeeError.kt +++ b/domain/transaction/models/src/main/kotlin/com/tangem/domain/transaction/error/GetFeeError.kt @@ -7,5 +7,6 @@ sealed class GetFeeError { sealed class BlockchainErrors : GetFeeError() { data object TronActivationError : BlockchainErrors() data object KaspaZeroUtxo : BlockchainErrors() + data object SuiOneCoinRequired : BlockchainErrors() } } \ No newline at end of file diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/error/ErrorsMapper.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/error/ErrorsMapper.kt index 5aa646c485..db5b877d46 100644 --- a/domain/transaction/src/main/java/com/tangem/domain/transaction/error/ErrorsMapper.kt +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/error/ErrorsMapper.kt @@ -16,6 +16,9 @@ fun Result.Failure.mapToFeeError(): GetFeeError { is BlockchainSdkError.Kaspa.ZeroUtxoError -> { GetFeeError.BlockchainErrors.KaspaZeroUtxo } + is BlockchainSdkError.Sui.OneSuiRequired -> { + GetFeeError.BlockchainErrors.SuiOneCoinRequired + } else -> GetFeeError.DataError(this.error) } } diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index c341dfec4e..d20b17869e 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -1,5 +1,5 @@ [versions] -tangemBlockchainSdk = "develop-967" +tangemBlockchainSdk = "develop-968" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "develop-437" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ From cdce0657123e72a8c40b5fdd363e2b6419eceb7b Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 3 Mar 2025 12:28:34 +0300 Subject: [PATCH 41/54] Updated on 2026-08-14 --- .gitignore | 3 +++ app/build.gradle.kts | 4 ++- .../main/java/com/tangem/tap/MainActivity.kt | 6 ++--- .../com/tangem/tap/routing/RootContent.kt | 2 +- .../component/impl/DefaultRoutingComponent.kt | 6 ++--- build.gradle.kts | 2 ++ core/config-toggles/build.gradle.kts | 3 ++- core/datasource/build.gradle.kts | 5 ++-- data/manage-tokens/build.gradle.kts | 3 ++- data/markets/build.gradle.kts | 3 ++- data/onramp/build.gradle.kts | 3 ++- data/settings/build.gradle.kts | 3 ++- data/staking/build.gradle.kts | 3 ++- data/tokens/build.gradle.kts | 3 ++- data/visa/build.gradle.kts | 3 ++- domain/analytics/build.gradle.kts | 5 +++- domain/legacy/build.gradle.kts | 6 ++--- domain/models/build.gradle.kts | 4 +-- domain/onramp/models/build.gradle.kts | 4 +-- domain/staking/models/build.gradle.kts | 4 +-- domain/visa/build.gradle.kts | 2 ++ domain/visa/models/build.gradle.kts | 2 ++ domain/wallets/models/build.gradle.kts | 4 +-- features/details/impl/build.gradle.kts | 2 ++ .../impl/DefaultAddCustomTokenComponent.kt | 6 ++--- .../DefaultCustomTokenSelectorComponent.kt | 2 +- .../impl/DefaultManageTokensComponent.kt | 2 +- .../impl/DefaultMarketsEntryComponent.kt | 2 +- .../entry/impl/ui/EntryBottomSheetContent.kt | 6 ++--- .../impl/DefaultOnboardingEntryComponent.kt | 9 +++++-- .../v2/entry/impl/ui/OnboardingEntry.kt | 6 ++--- .../DefaultOnboardingMultiWalletComponent.kt | 10 +++---- .../impl/DefaultOnboardingVisaComponent.kt | 12 ++++----- .../DefaultConfirmResidencyComponent.kt | 2 +- .../hottokens/DefaultHotCryptoComponent.kt | 2 +- .../onramp/main/DefaultOnrampMainComponent.kt | 2 +- .../DefaultSelectProviderComponent.kt | 2 +- .../onramp/root/DefaultOnrampComponent.kt | 6 ++--- .../DefaultOnrampSettingsComponent.kt | 2 +- .../state/helpers/StakingTransactionSender.kt | 2 +- features/swap/data/build.gradle.kts | 3 ++- features/swap/domain/build.gradle.kts | 3 ++- features/swap/domain/models/build.gradle.kts | 6 ++--- .../impl/DefaultWalletSettingsComponent.kt | 2 +- .../wallet/DefaultWalletEntryComponent.kt | 10 ++++--- .../wallet/child/wallet/WalletComponent.kt | 2 +- gradle/dependencies.toml | 27 ++++++++++--------- libs/blockchain-sdk/build.gradle.kts | 3 ++- libs/visa/build.gradle.kts | 3 ++- .../configurations/KotlinConfigurations.kt | 5 ++++ .../extension/BaseExtensionConfigurations.kt | 9 ++++--- 51 files changed, 135 insertions(+), 96 deletions(-) diff --git a/.gitignore b/.gitignore index 3e96fb9767..74ed0fd34b 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,6 @@ local.properties **/fastlane/Preview.html **/fastlane/screenshots **/fastlane/test_output + +# Kotlin Plugin +.kotlin/ diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c3a1e5b24a..5c9baecf6c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -10,6 +10,7 @@ plugins { alias(deps.plugins.hilt.android) alias(deps.plugins.firebase.crashlytics) alias(deps.plugins.firebase.perf) + alias(deps.plugins.ksp) id("configuration") } @@ -30,6 +31,7 @@ android { resources.excludes.add("META-INF/FastDoubleParser-LICENSE") resources.excludes.add("META-INF/io.netty.versions.properties") resources.excludes.add("META-INF/INDEX.LIST") + resources.excludes.add("META-INF/versions/9/OSGI-INF/MANIFEST.MF") } androidResources { generateLocaleConfig = true @@ -268,7 +270,7 @@ dependencies { implementation(deps.moshi.adapters) implementation(deps.moshi.kotlin) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) kaptForObfuscatingVariants(deps.retrofit.response.type.keeper) /** Testing libraries */ diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 1a8f31b510..6e0c6c7628 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -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 @@ -316,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 diff --git a/app/src/main/java/com/tangem/tap/routing/RootContent.kt b/app/src/main/java/com/tangem/tap/routing/RootContent.kt index 077688613f..669e7f44a3 100644 --- a/app/src/main/java/com/tangem/tap/routing/RootContent.kt +++ b/app/src/main/java/com/tangem/tap/routing/RootContent.kt @@ -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 diff --git a/app/src/main/java/com/tangem/tap/routing/component/impl/DefaultRoutingComponent.kt b/app/src/main/java/com/tangem/tap/routing/component/impl/DefaultRoutingComponent.kt index 2f709d7943..1cc059364d 100644 --- a/app/src/main/java/com/tangem/tap/routing/component/impl/DefaultRoutingComponent.kt +++ b/app/src/main/java/com/tangem/tap/routing/component/impl/DefaultRoutingComponent.kt @@ -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) { diff --git a/build.gradle.kts b/build.gradle.kts index 0ace95bd3b..4cbeef6686 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,6 +12,8 @@ plugins { alias(deps.plugins.firebase.crashlytics) apply false alias(deps.plugins.firebase.perf) apply false alias(deps.plugins.room) apply false + alias(deps.plugins.kotlin.compose.compiler) apply false + alias(deps.plugins.ksp) apply false } val clean by tasks.registering { diff --git a/core/config-toggles/build.gradle.kts b/core/config-toggles/build.gradle.kts index 97534f26fa..96fb87b639 100644 --- a/core/config-toggles/build.gradle.kts +++ b/core/config-toggles/build.gradle.kts @@ -5,6 +5,7 @@ plugins { alias(deps.plugins.kotlin.android) alias(deps.plugins.kotlin.kapt) alias(deps.plugins.hilt.android) + alias(deps.plugins.ksp) id("configuration") } @@ -24,7 +25,7 @@ dependencies { implementation(deps.moshi) implementation(deps.moshi.kotlin) implementation(deps.timber) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) /** Core modules */ implementation(projects.core.datasource) diff --git a/core/datasource/build.gradle.kts b/core/datasource/build.gradle.kts index 696989eaf7..97550bec4e 100644 --- a/core/datasource/build.gradle.kts +++ b/core/datasource/build.gradle.kts @@ -6,6 +6,7 @@ plugins { alias(deps.plugins.kotlin.kapt) alias(deps.plugins.hilt.android) alias(deps.plugins.room) + alias(deps.plugins.ksp) id("configuration") } @@ -57,7 +58,7 @@ dependencies { implementation(deps.okHttp.prettyLogging) implementation(deps.retrofit) implementation(deps.retrofit.moshi) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) kaptForObfuscatingVariants(deps.retrofit.response.type.keeper) /** Time */ @@ -78,7 +79,7 @@ dependencies { implementation(deps.androidx.datastore) implementation(deps.room.runtime) implementation(deps.room.ktx) - kapt(deps.room.compiler) + ksp(deps.room.compiler) testImplementation(deps.test.coroutine) testImplementation(deps.test.junit) diff --git a/data/manage-tokens/build.gradle.kts b/data/manage-tokens/build.gradle.kts index d303cffc3f..f0e57105f8 100644 --- a/data/manage-tokens/build.gradle.kts +++ b/data/manage-tokens/build.gradle.kts @@ -4,6 +4,7 @@ plugins { alias(deps.plugins.android.library) alias(deps.plugins.kotlin.android) alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.ksp) id("configuration") } @@ -46,6 +47,6 @@ dependencies { /** Other */ implementation(deps.moshi.kotlin) implementation(deps.timber) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) kaptForObfuscatingVariants(deps.retrofit.response.type.keeper) } \ No newline at end of file diff --git a/data/markets/build.gradle.kts b/data/markets/build.gradle.kts index 9f3c3fc995..fa746e853f 100644 --- a/data/markets/build.gradle.kts +++ b/data/markets/build.gradle.kts @@ -5,6 +5,7 @@ plugins { alias(deps.plugins.kotlin.android) alias(deps.plugins.kotlin.kapt) alias(deps.plugins.hilt.android) + alias(deps.plugins.ksp) id("configuration") } @@ -42,7 +43,7 @@ dependencies { implementation(deps.moshi.kotlin) implementation(deps.timber) implementation(tangemDeps.blockchain) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) kaptForObfuscatingVariants(deps.retrofit.response.type.keeper) // endregion } diff --git a/data/onramp/build.gradle.kts b/data/onramp/build.gradle.kts index fc4b8695b8..01a57f9c01 100644 --- a/data/onramp/build.gradle.kts +++ b/data/onramp/build.gradle.kts @@ -5,6 +5,7 @@ plugins { alias(deps.plugins.kotlin.android) alias(deps.plugins.kotlin.kapt) alias(deps.plugins.hilt.android) + alias(deps.plugins.ksp) id("configuration") } @@ -44,7 +45,7 @@ dependencies { implementation(deps.moshi) implementation(deps.moshi.kotlin) implementation(deps.timber) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) kaptForObfuscatingVariants(deps.retrofit.response.type.keeper) implementation(deps.kotlin.serialization) diff --git a/data/settings/build.gradle.kts b/data/settings/build.gradle.kts index 7997b79d5c..30c7231276 100644 --- a/data/settings/build.gradle.kts +++ b/data/settings/build.gradle.kts @@ -5,6 +5,7 @@ plugins { alias(deps.plugins.kotlin.android) alias(deps.plugins.kotlin.kapt) alias(deps.plugins.hilt.android) + alias(deps.plugins.ksp) id("configuration") } @@ -33,7 +34,7 @@ dependencies { implementation(deps.moshi) implementation(deps.moshi.kotlin) implementation(deps.timber) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) kaptForObfuscatingVariants(deps.retrofit.response.type.keeper) // endregion } diff --git a/data/staking/build.gradle.kts b/data/staking/build.gradle.kts index ee2849d585..537fae1b87 100644 --- a/data/staking/build.gradle.kts +++ b/data/staking/build.gradle.kts @@ -5,6 +5,7 @@ plugins { alias(deps.plugins.kotlin.android) alias(deps.plugins.kotlin.kapt) alias(deps.plugins.hilt.android) + alias(deps.plugins.ksp) id("configuration") } @@ -48,7 +49,7 @@ dependencies { implementation(deps.moshi) implementation(deps.moshi.kotlin) implementation(deps.timber) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) kaptForObfuscatingVariants(deps.retrofit.response.type.keeper) implementation(projects.libs.blockchainSdk) diff --git a/data/tokens/build.gradle.kts b/data/tokens/build.gradle.kts index 003cc83849..499154d785 100644 --- a/data/tokens/build.gradle.kts +++ b/data/tokens/build.gradle.kts @@ -4,6 +4,7 @@ plugins { alias(deps.plugins.android.library) alias(deps.plugins.kotlin.android) alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.ksp) id("configuration") } @@ -50,6 +51,6 @@ dependencies { implementation(deps.timber) implementation(deps.retrofit) // For HttpException implementation(deps.androidx.paging.runtime) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) kaptForObfuscatingVariants(deps.retrofit.response.type.keeper) } \ No newline at end of file diff --git a/data/visa/build.gradle.kts b/data/visa/build.gradle.kts index a4adc23b0f..035040383b 100644 --- a/data/visa/build.gradle.kts +++ b/data/visa/build.gradle.kts @@ -4,6 +4,7 @@ plugins { alias(deps.plugins.android.library) alias(deps.plugins.kotlin.android) alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.ksp) id("configuration") } @@ -39,7 +40,7 @@ dependencies { implementation(deps.timber) implementation(deps.androidx.paging.runtime) implementation(deps.moshi.kotlin) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) kaptForObfuscatingVariants(deps.retrofit.response.type.keeper) /** Libs - Tangem */ diff --git a/domain/analytics/build.gradle.kts b/domain/analytics/build.gradle.kts index f649160e1e..907caaa71d 100644 --- a/domain/analytics/build.gradle.kts +++ b/domain/analytics/build.gradle.kts @@ -1,6 +1,7 @@ plugins { alias(deps.plugins.kotlin.jvm) alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.ksp) id("configuration") } @@ -11,5 +12,7 @@ dependencies { implementation(projects.domain.core) implementation(projects.domain.wallets.models) implementation(deps.moshi.kotlin) - kapt(deps.moshi.kotlin.codegen) + implementation(deps.arrow.core) + implementation(deps.arrow.fx) + ksp(deps.moshi.kotlin.codegen) } \ No newline at end of file diff --git a/domain/legacy/build.gradle.kts b/domain/legacy/build.gradle.kts index 8a3a831cbe..11e080b895 100644 --- a/domain/legacy/build.gradle.kts +++ b/domain/legacy/build.gradle.kts @@ -1,9 +1,7 @@ -import com.tangem.plugin.configuration.configurations.extension.kaptForObfuscatingVariants - plugins { alias(deps.plugins.android.library) alias(deps.plugins.kotlin.android) - alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.ksp) id("configuration") } @@ -41,7 +39,7 @@ dependencies { implementation(deps.moshi.kotlin) implementation(deps.reKotlin) implementation(deps.timber) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) /** Testing libraries */ testImplementation(deps.test.junit) diff --git a/domain/models/build.gradle.kts b/domain/models/build.gradle.kts index aeafc373d1..38288fbd08 100644 --- a/domain/models/build.gradle.kts +++ b/domain/models/build.gradle.kts @@ -3,7 +3,7 @@ import com.tangem.plugin.configuration.configurations.extension.kaptForObfuscati plugins { alias(deps.plugins.kotlin.jvm) alias(deps.plugins.kotlin.serialization) - alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.ksp) id("configuration") } @@ -14,5 +14,5 @@ dependencies { implementation(deps.moshi.kotlin) implementation(deps.moshi.adapters) implementation(deps.kotlin.serialization) - kapt(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) } \ No newline at end of file diff --git a/domain/onramp/models/build.gradle.kts b/domain/onramp/models/build.gradle.kts index b717a7ae41..7428002d0d 100644 --- a/domain/onramp/models/build.gradle.kts +++ b/domain/onramp/models/build.gradle.kts @@ -1,7 +1,7 @@ plugins { alias(deps.plugins.kotlin.jvm) alias(deps.plugins.kotlin.serialization) - alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.ksp) id("configuration") } @@ -11,7 +11,7 @@ dependencies { implementation(projects.domain.wallets.models) implementation(deps.moshi.kotlin) - kapt(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) implementation(deps.kotlin.serialization) implementation(deps.jodatime) } \ No newline at end of file diff --git a/domain/staking/models/build.gradle.kts b/domain/staking/models/build.gradle.kts index ca12daff07..10abc551b9 100644 --- a/domain/staking/models/build.gradle.kts +++ b/domain/staking/models/build.gradle.kts @@ -3,7 +3,7 @@ import com.tangem.plugin.configuration.configurations.extension.kaptForObfuscati plugins { alias(deps.plugins.kotlin.jvm) alias(deps.plugins.kotlin.serialization) - alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.ksp) id("configuration") } @@ -15,5 +15,5 @@ dependencies { implementation(deps.jodatime) implementation(deps.moshi) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) } \ No newline at end of file diff --git a/domain/visa/build.gradle.kts b/domain/visa/build.gradle.kts index 96fb032e84..8ce37bc6d1 100644 --- a/domain/visa/build.gradle.kts +++ b/domain/visa/build.gradle.kts @@ -1,6 +1,7 @@ plugins { alias(deps.plugins.android.library) alias(deps.plugins.kotlin.android) + alias(deps.plugins.ksp) id("configuration") } @@ -24,4 +25,5 @@ dependencies { implementation(deps.androidx.paging.runtime) implementation(deps.moshi) implementation(deps.moshi.kotlin) + ksp(deps.moshi.kotlin.codegen) } \ No newline at end of file diff --git a/domain/visa/models/build.gradle.kts b/domain/visa/models/build.gradle.kts index 96a8bc4639..b2df1fba1f 100644 --- a/domain/visa/models/build.gradle.kts +++ b/domain/visa/models/build.gradle.kts @@ -1,11 +1,13 @@ plugins { alias(deps.plugins.kotlin.jvm) alias(deps.plugins.kotlin.serialization) + alias(deps.plugins.ksp) id("configuration") } dependencies { implementation(deps.moshi.kotlin) + ksp(deps.moshi.kotlin.codegen) implementation(deps.moshi.adapters) implementation(deps.kotlin.serialization) } \ No newline at end of file diff --git a/domain/wallets/models/build.gradle.kts b/domain/wallets/models/build.gradle.kts index 03afdb3da9..58d87775b5 100644 --- a/domain/wallets/models/build.gradle.kts +++ b/domain/wallets/models/build.gradle.kts @@ -1,7 +1,7 @@ plugins { alias(deps.plugins.kotlin.jvm) alias(deps.plugins.kotlin.serialization) - alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.ksp) id("configuration") } @@ -18,6 +18,6 @@ dependencies { implementation(deps.kotlin.serialization) implementation(deps.moshi.kotlin) implementation(deps.timber) - kapt(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) // endregion } \ No newline at end of file diff --git a/features/details/impl/build.gradle.kts b/features/details/impl/build.gradle.kts index 2ffdab4b0e..552f96b756 100644 --- a/features/details/impl/build.gradle.kts +++ b/features/details/impl/build.gradle.kts @@ -70,4 +70,6 @@ dependencies { implementation(deps.kotlin.immutable.collections) implementation(deps.reKotlin) implementation(deps.timber) + implementation(deps.arrow.core) + implementation(deps.arrow.fx) } \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultAddCustomTokenComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultAddCustomTokenComponent.kt index 10cf6ddcc7..edceddb46d 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultAddCustomTokenComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultAddCustomTokenComponent.kt @@ -4,9 +4,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import com.arkivanov.decompose.ComponentContext -import com.arkivanov.decompose.extensions.compose.jetpack.stack.Children -import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.stackAnimation -import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState +import com.arkivanov.decompose.extensions.compose.stack.Children +import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation +import com.arkivanov.decompose.extensions.compose.subscribeAsState import com.arkivanov.decompose.router.stack.* import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.decompose.context.AppComponentContext diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenSelectorComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenSelectorComponent.kt index 2d690a862c..edd8f52aa9 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenSelectorComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenSelectorComponent.kt @@ -5,7 +5,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle 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.slot.childSlot import com.arkivanov.decompose.router.slot.dismiss import com.tangem.core.decompose.context.AppComponentContext diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultManageTokensComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultManageTokensComponent.kt index 9a8b81b83a..a66edf956d 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultManageTokensComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultManageTokensComponent.kt @@ -6,7 +6,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle 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.slot.childSlot import com.arkivanov.decompose.router.slot.dismiss import com.tangem.core.decompose.context.AppComponentContext diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/entry/impl/DefaultMarketsEntryComponent.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/entry/impl/DefaultMarketsEntryComponent.kt index ae0a8b3e09..d175090f39 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/entry/impl/DefaultMarketsEntryComponent.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/entry/impl/DefaultMarketsEntryComponent.kt @@ -6,7 +6,7 @@ import androidx.compose.runtime.State import androidx.compose.ui.Modifier import androidx.compose.ui.unit.Dp import com.arkivanov.decompose.ExperimentalDecomposeApi -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.StackNavigation import com.arkivanov.decompose.router.stack.childStack diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/entry/impl/ui/EntryBottomSheetContent.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/entry/impl/ui/EntryBottomSheetContent.kt index 5f30e89585..4adeb8b8c5 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/entry/impl/ui/EntryBottomSheetContent.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/entry/impl/ui/EntryBottomSheetContent.kt @@ -11,9 +11,9 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.Dp -import com.arkivanov.decompose.extensions.compose.jetpack.stack.Children -import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.slide -import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.stackAnimation +import com.arkivanov.decompose.extensions.compose.stack.Children +import com.arkivanov.decompose.extensions.compose.stack.animation.slide +import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation import com.arkivanov.decompose.router.stack.ChildStack import com.tangem.core.ui.res.LocalMainBottomSheetColor import com.tangem.core.ui.res.TangemTheme diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/DefaultOnboardingEntryComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/DefaultOnboardingEntryComponent.kt index 6134fd218f..3c69bb169d 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/DefaultOnboardingEntryComponent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/DefaultOnboardingEntryComponent.kt @@ -4,9 +4,11 @@ import androidx.activity.compose.BackHandler import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier -import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState +import com.arkivanov.decompose.extensions.compose.subscribeAsState import com.arkivanov.decompose.router.stack.* +import com.arkivanov.decompose.value.ObserveLifecycleMode import com.arkivanov.decompose.value.Value +import com.arkivanov.decompose.value.subscribe import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.child import com.tangem.core.decompose.context.childByContext @@ -87,7 +89,10 @@ internal class DefaultOnboardingEntryComponent @AssistedInject constructor( @Suppress("MagicNumber") private fun linkToInnerNavigation() { // stepper linking - innerStack.observe { stack -> + innerStack.subscribe( + lifecycle = lifecycle, + mode = ObserveLifecycleMode.CREATE_DESTROY, + ) { stack -> val activeChild = stack.active.instance if (activeChild is InnerNavigationHolder) { componentScope.launch { diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/ui/OnboardingEntry.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/ui/OnboardingEntry.kt index e9d2be883a..3ed12bd0e7 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/ui/OnboardingEntry.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/ui/OnboardingEntry.kt @@ -4,9 +4,9 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import com.arkivanov.decompose.extensions.compose.jetpack.stack.Children -import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.slide -import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.stackAnimation +import com.arkivanov.decompose.extensions.compose.stack.Children +import com.arkivanov.decompose.extensions.compose.stack.animation.slide +import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation import com.arkivanov.decompose.router.stack.ChildStack import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.core.ui.res.TangemTheme diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt index 989f0fd302..0c783b964c 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt @@ -6,11 +6,11 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.arkivanov.decompose.FaultyDecomposeApi -import com.arkivanov.decompose.extensions.compose.jetpack.stack.Children -import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.fade -import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.slide -import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.stackAnimation -import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState +import com.arkivanov.decompose.extensions.compose.stack.Children +import com.arkivanov.decompose.extensions.compose.stack.animation.fade +import com.arkivanov.decompose.extensions.compose.stack.animation.slide +import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation +import com.arkivanov.decompose.extensions.compose.subscribeAsState import com.arkivanov.decompose.router.slot.SlotNavigation import com.arkivanov.decompose.router.slot.childSlot import com.arkivanov.decompose.router.slot.dismiss diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/DefaultOnboardingVisaComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/DefaultOnboardingVisaComponent.kt index 9ab73f41eb..b36dcef18f 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/DefaultOnboardingVisaComponent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/DefaultOnboardingVisaComponent.kt @@ -3,13 +3,13 @@ package com.tangem.features.onboarding.v2.visa.impl import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier -import com.arkivanov.decompose.extensions.compose.jetpack.stack.Children -import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.slide -import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.stackAnimation -import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState +import com.arkivanov.decompose.extensions.compose.stack.Children +import com.arkivanov.decompose.extensions.compose.stack.animation.slide +import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation +import com.arkivanov.decompose.extensions.compose.subscribeAsState import com.arkivanov.decompose.router.stack.* import com.arkivanov.decompose.value.Value -import com.arkivanov.decompose.value.observe +import com.arkivanov.decompose.value.subscribe import com.arkivanov.essenty.instancekeeper.getOrCreateSimple import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.childByContext @@ -85,7 +85,7 @@ internal class DefaultOnboardingVisaComponent @AssistedInject constructor( } // sets title and stepper value - childStack.observe(lifecycle) { stack -> + childStack.subscribe(lifecycle) { stack -> val currentRoute = stack.active.configuration params.titleProvider.changeTitle(currentRoute.screenTitle()) model.updateStepForNewRoute(currentRoute) diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/DefaultConfirmResidencyComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/DefaultConfirmResidencyComponent.kt index 0e1ea2888c..2ff2e6a708 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/DefaultConfirmResidencyComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/DefaultConfirmResidencyComponent.kt @@ -5,7 +5,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle 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.slot.childSlot import com.arkivanov.decompose.router.slot.dismiss import com.tangem.core.decompose.context.AppComponentContext diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/DefaultHotCryptoComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/DefaultHotCryptoComponent.kt index 4c6efe7cec..f284662276 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/DefaultHotCryptoComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/DefaultHotCryptoComponent.kt @@ -5,7 +5,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle 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.slot.childSlot import com.arkivanov.decompose.router.slot.dismiss import com.tangem.core.decompose.context.AppComponentContext diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/DefaultOnrampMainComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/DefaultOnrampMainComponent.kt index 5164c91d5b..f6c03525c1 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/DefaultOnrampMainComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/DefaultOnrampMainComponent.kt @@ -5,7 +5,7 @@ import androidx.compose.runtime.collectAsState 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.slot.childSlot import com.arkivanov.decompose.router.slot.dismiss import com.tangem.core.decompose.context.AppComponentContext diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/DefaultSelectProviderComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/DefaultSelectProviderComponent.kt index d0bcd4a3d0..df819c4c7f 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/DefaultSelectProviderComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/DefaultSelectProviderComponent.kt @@ -8,7 +8,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle 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.slot.childSlot import com.arkivanov.decompose.router.slot.dismiss import com.tangem.core.decompose.context.AppComponentContext diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt index 02047a8939..48804d46be 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt @@ -5,9 +5,9 @@ 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.stack.Children -import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.stackAnimation -import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState +import com.arkivanov.decompose.extensions.compose.stack.Children +import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation +import com.arkivanov.decompose.extensions.compose.subscribeAsState import com.arkivanov.decompose.router.stack.StackNavigation import com.arkivanov.decompose.router.stack.childStack import com.arkivanov.decompose.router.stack.pop diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/DefaultOnrampSettingsComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/DefaultOnrampSettingsComponent.kt index a3c7234332..941d543d82 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/DefaultOnrampSettingsComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/DefaultOnrampSettingsComponent.kt @@ -6,7 +6,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle 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.slot.childSlot import com.arkivanov.decompose.router.slot.dismiss import com.tangem.core.decompose.context.AppComponentContext diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingTransactionSender.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingTransactionSender.kt index 2810a6d3c3..27d87225e0 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingTransactionSender.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingTransactionSender.kt @@ -248,7 +248,7 @@ internal class StakingTransactionSender @AssistedInject constructor( val txUrl = getExplorerTransactionUrlUseCase( txHash = transactionHashes.last(), networkId = cryptoCurrencyStatus.currency.network.id, - ).getOrElse { "" } + ).getOrNull() ?: "" balanceUpdater.fullUpdate() onSendSuccess(txUrl) diff --git a/features/swap/data/build.gradle.kts b/features/swap/data/build.gradle.kts index f9af5bb02d..08890ead13 100644 --- a/features/swap/data/build.gradle.kts +++ b/features/swap/data/build.gradle.kts @@ -5,6 +5,7 @@ plugins { alias(deps.plugins.kotlin.android) alias(deps.plugins.kotlin.kapt) alias(deps.plugins.hilt.android) + alias(deps.plugins.ksp) id("configuration") } @@ -29,7 +30,7 @@ dependencies { implementation(deps.moshi) implementation(deps.moshi.kotlin) implementation(deps.arrow.core) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) kaptForObfuscatingVariants(deps.retrofit.response.type.keeper) /** Domain */ diff --git a/features/swap/domain/build.gradle.kts b/features/swap/domain/build.gradle.kts index 46a1c51668..14278f36c8 100644 --- a/features/swap/domain/build.gradle.kts +++ b/features/swap/domain/build.gradle.kts @@ -5,6 +5,7 @@ plugins { alias(deps.plugins.kotlin.android) alias(deps.plugins.kotlin.kapt) alias(deps.plugins.kotlin.serialization) + alias(deps.plugins.ksp) id("configuration") } @@ -54,5 +55,5 @@ dependencies { implementation(tangemDeps.blockchain) implementation(tangemDeps.card.core) implementation(deps.moshi) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) } \ No newline at end of file diff --git a/features/swap/domain/models/build.gradle.kts b/features/swap/domain/models/build.gradle.kts index dd42b09ca2..a90b3ed292 100644 --- a/features/swap/domain/models/build.gradle.kts +++ b/features/swap/domain/models/build.gradle.kts @@ -1,9 +1,7 @@ -import com.tangem.plugin.configuration.configurations.extension.kaptForObfuscatingVariants - plugins { alias(deps.plugins.android.library) alias(deps.plugins.kotlin.android) - alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.ksp) id("configuration") } @@ -24,6 +22,6 @@ dependencies { implementation(deps.kotlin.serialization) implementation(deps.arrow.core) implementation(deps.moshi.kotlin) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) } \ No newline at end of file diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/DefaultWalletSettingsComponent.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/DefaultWalletSettingsComponent.kt index 39ed1d65a5..1f4adf5af6 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/DefaultWalletSettingsComponent.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/impl/DefaultWalletSettingsComponent.kt @@ -5,7 +5,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle 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.slot.childSlot import com.arkivanov.decompose.router.slot.dismiss import com.tangem.core.decompose.context.AppComponentContext diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/DefaultWalletEntryComponent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/DefaultWalletEntryComponent.kt index 8f32b3bfa5..d4555ccf75 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/DefaultWalletEntryComponent.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/DefaultWalletEntryComponent.kt @@ -2,13 +2,15 @@ package com.tangem.feature.wallet import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import com.arkivanov.decompose.extensions.compose.jetpack.stack.Children -import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.fade -import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.stackAnimation +import com.arkivanov.decompose.extensions.compose.stack.Children +import com.arkivanov.decompose.extensions.compose.stack.animation.fade +import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation +import com.arkivanov.decompose.router.stack.ChildStack import com.arkivanov.decompose.router.stack.StackNavigation import com.arkivanov.decompose.router.stack.childStack import com.arkivanov.decompose.router.stack.pop import com.arkivanov.decompose.router.stack.pushNew +import com.arkivanov.decompose.value.Value import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.childByContext import com.tangem.core.ui.decompose.ComposableContentComponent @@ -28,7 +30,7 @@ internal class DefaultWalletEntryComponent @AssistedInject constructor( private val navigation = StackNavigation() - private val stack = childStack( + private val stack: Value> = childStack( source = navigation, serializer = WalletRoute.serializer(), initialConfiguration = WalletRoute.Wallet, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt index 6a00429983..a0bad13d8b 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt @@ -6,7 +6,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState +import com.arkivanov.decompose.extensions.compose.subscribeAsState import com.arkivanov.decompose.router.slot.childSlot import com.arkivanov.decompose.router.slot.dismiss import com.tangem.core.decompose.context.AppComponentContext diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 1ee33a57c2..03c21fccac 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -6,7 +6,8 @@ androidGradlePlugin = "8.2.2" firebaseCrashlytics = "3.0.1" googleServices = "4.4.1" -kotlin = "1.9.22" +kotlin = "2.1.10" +ksp = "2.1.10-1.0.30" firebasePerf = "1.4.2" # endregion Classpath @@ -26,11 +27,10 @@ androidxWindowManager = "1.3.0" # endregion AndroidX # region Compose -compose-compiler = "1.5.9" -compose-runtime = "1.7.1" -compose-foundation = "1.7.1" -compose-material = "1.7.1" -compose-material3 = "1.3.0" +compose-runtime = "1.7.8" +compose-foundation = "1.7.8" +compose-material = "1.7.8" +compose-material3 = "1.3.1" compose-constraint = "1.0.1" compose-navigation = "2.7.7" compose-accompanist = "0.30.1" @@ -44,14 +44,14 @@ amplitude = "2.36.1" armadillo = "0.9.0" coil = "2.1.0" compose-shimmer = "1.0.3" -coroutine = "1.7.2" +coroutine = "1.7.2" # 1.8+ is not compatible with tangem-sdk desugarJdkLibs = "1.1.5" firebase = "33.7.0" googleMaterialComponent = "1.6.1" googlePlayReview = "2.0.1" googlePlayReviewKtx = "2.0.1" googlePlayServicesWallet = "19.1.0" -hilt = "2.46" +hilt = "2.55" hilt-navigation = "1.0.0" jodatime = "2.12.1" kotlin-immutable-collections = "0.3.5" @@ -69,9 +69,8 @@ timber = "4.7.1" viewBindingDelegate = "1.5.9" xmlShimmer = "1.1.3" zxingQrCode = "3.5.1" -mviCore = "1.3.1" -kotlinSerialization = "1.4.1" -arrow = "1.2.3" +kotlinSerialization = "1.8.0" +arrow = "1.2.4" # 2.0.1 breaks the build reownCore = "1.1.2" reownWeb3 = "1.1.2" prettyLogger = "2.2.0" @@ -83,7 +82,7 @@ listenableFuture = "1.0" swipeRefreshLayout = "1.1.0" web3j = "4.12.3-SNAPSHOT" leakcanary = "2.13" -decompose = "2.2.2" +decompose = "3.3.0" room = "2.6.1" markdown = "0.7.2" markdownComposeView = "0.5.4" @@ -121,6 +120,8 @@ google-services = { id = "com.google.gms.google-services", version.ref = "google hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } room = { id = "androidx.room", version.ref = "room" } +kotlin-compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } [libraries] # region Classpath @@ -254,7 +255,7 @@ camera-view = { module = "androidx.camera:camera-view", version.ref = "androidXC web3j-core = { module = "org.web3j:core", version.ref = "web3j" } leakcanary = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakcanary" } decompose = { module = "com.arkivanov.decompose:decompose", version.ref = "decompose" } -decompose-ext-compose = { module = "com.arkivanov.decompose:extensions-compose-jetpack", version.ref = "decompose" } +decompose-ext-compose = { module = "com.arkivanov.decompose:extensions-compose", version.ref = "decompose" } room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" } room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" } room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" } diff --git a/libs/blockchain-sdk/build.gradle.kts b/libs/blockchain-sdk/build.gradle.kts index 31e9b0408e..3a1001135f 100644 --- a/libs/blockchain-sdk/build.gradle.kts +++ b/libs/blockchain-sdk/build.gradle.kts @@ -5,6 +5,7 @@ plugins { alias(deps.plugins.kotlin.android) alias(deps.plugins.kotlin.kapt) alias(deps.plugins.hilt.android) + alias(deps.plugins.ksp) id("configuration") } @@ -34,7 +35,7 @@ dependencies { implementation(deps.moshi) implementation(deps.moshi.kotlin) implementation(deps.timber) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) kaptForObfuscatingVariants(deps.retrofit.response.type.keeper) // endregion diff --git a/libs/visa/build.gradle.kts b/libs/visa/build.gradle.kts index d73b1485ff..c3a3b8674b 100644 --- a/libs/visa/build.gradle.kts +++ b/libs/visa/build.gradle.kts @@ -4,6 +4,7 @@ plugins { alias(deps.plugins.android.library) alias(deps.plugins.kotlin.android) alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.ksp) id("configuration") } @@ -30,7 +31,7 @@ dependencies { implementation(deps.okHttp.prettyLogging) implementation(deps.retrofit) implementation(deps.retrofit.moshi) - kaptForObfuscatingVariants(deps.moshi.kotlin.codegen) + ksp(deps.moshi.kotlin.codegen) kaptForObfuscatingVariants(deps.retrofit.response.type.keeper) /** Libs - Other */ diff --git a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/KotlinConfigurations.kt b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/KotlinConfigurations.kt index d0e39d6777..ae7e54965a 100644 --- a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/KotlinConfigurations.kt +++ b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/KotlinConfigurations.kt @@ -1,7 +1,12 @@ package com.tangem.plugin.configuration.configurations import org.gradle.api.Project +import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension +import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension +import org.jetbrains.kotlin.gradle.model.KotlinAndroidExtension import org.jetbrains.kotlin.gradle.tasks.KotlinCompile internal fun Project.configureKotlinCompilerOptions() { diff --git a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/BaseExtensionConfigurations.kt b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/BaseExtensionConfigurations.kt index fe2f2c147f..c19607fae8 100644 --- a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/BaseExtensionConfigurations.kt +++ b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/BaseExtensionConfigurations.kt @@ -2,9 +2,12 @@ package com.tangem.plugin.configuration.configurations.extension import com.android.build.gradle.BaseExtension import com.tangem.plugin.configuration.model.AppConfig +import com.tangem.plugin.configuration.utils.findPlugin import com.tangem.plugin.configuration.utils.findVersion import org.gradle.api.JavaVersion import org.gradle.api.Project +import org.gradle.kotlin.dsl.apply +import org.gradle.kotlin.dsl.plugins internal fun BaseExtension.configureCompileSdk() { compileSdkVersion(AppConfig.compileSdkVersion) @@ -30,10 +33,8 @@ internal fun BaseExtension.configureCompose(project: Project) { } buildFeatures.compose = useCompose - + if (useCompose) { - composeOptions { - kotlinCompilerExtensionVersion = project.findVersion(alias = "compose-compiler").requiredVersion - } + project.plugins.apply(project.findPlugin("kotlin-compose-compiler").pluginId) } } \ No newline at end of file From 0953fc93b48a0fa92d8576924d24638464be7e28 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 3 Mar 2025 17:03:07 +0000 Subject: [PATCH 42/54] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 3be6bacbc0..d20b17869e 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -1,7 +1,7 @@ [versions] -tangemBlockchainSdk = "release-app_5.21-963" +tangemBlockchainSdk = "develop-968" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "release-app_5.21-435" +tangemCardSdk = "develop-437" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "2.0.0-alpha.25-tangem-developments8" #tangemVico = "0.0.1" # Keep it! - used for local builds ^ From 354dc7d9b416ea4c116d2f6c9272eba030f36246 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 3 Mar 2025 21:06:12 +0200 Subject: [PATCH 43/54] Updated on 2026-08-14 --- .../presentation/tokendetails/model/TokenDetailsModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt index 81bc77d74f..545c8d7f8e 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt @@ -971,7 +971,7 @@ internal class TokenDetailsModel @Inject constructor( error("Staking is unavailable for ${cryptoCurrency.name}") } - router.openStaking(userWalletId, cryptoCurrency, yield) + router.openStaking(userWalletId, cryptoCurrency, yield.id) } } From 59031ba466849b16cbcfbb4528cc57b386cfd3c3 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 3 Mar 2025 19:44:16 +0200 Subject: [PATCH 44/54] Updated on 2026-08-14 --- .../impl/presentation/model/StakingModel.kt | 2 +- .../state/helpers/StakingBalanceUpdater.kt | 16 +++------------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt index b180a8eaa3..05558dc1b2 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt @@ -932,7 +932,7 @@ internal class StakingModel @Inject constructor( when { isInitState() -> { updateInitialData() - balanceUpdater.initialUpdate() + balanceUpdater.partialUpdate() } isAssentState() -> { getFee() diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingBalanceUpdater.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingBalanceUpdater.kt index c84db7f3ea..db7d970087 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingBalanceUpdater.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingBalanceUpdater.kt @@ -57,24 +57,14 @@ internal class StakingBalanceUpdater @AssistedInject constructor( } suspend fun partialUpdate() { - coroutineScope { - listOf( - async { - updateNetworkStatuses(delay = 0) - }, - async { - updateProcessingActions() - }, - ).awaitAll() - } - } - - suspend fun initialUpdate() { coroutineScope { listOf( async { updateStakeBalance() }, + async { + updateNetworkStatuses(delay = 0) + }, async { updateProcessingActions() }, From a5f895d9444fab4db6a8797aa8a74209301f8f46 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 4 Mar 2025 14:57:27 +0500 Subject: [PATCH 45/54] Updated on 2026-08-14 --- .../src/main/assets/configs/feature_toggles_config.json | 4 ++++ .../java/com/tangem/data/staking/DefaultStakingRepository.kt | 1 + .../data/staking/toggles/DefaultStakingFeatureToggles.kt | 3 +++ .../tangem/domain/staking/toggles/StakingFeatureToggles.kt | 1 + 4 files changed, 9 insertions(+) diff --git a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json index d2e46b6fea..0538c8067c 100644 --- a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json @@ -50,5 +50,9 @@ { "name": "NFT_ENABLED", "version": "undefined" + }, + { + "name": "STAKING_CARDANO_ENABLED", + "version": "undefined" } ] diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt index e9734b9fab..8918737e14 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt @@ -219,6 +219,7 @@ internal class DefaultStakingRepository( private fun checkFeatureToggleEnabled(networkId: Network.ID): Boolean { return when (Blockchain.fromId(networkId.value)) { Blockchain.TON -> stakingFeatureToggles.isTonStakingEnabled + Blockchain.Cardano -> stakingFeatureToggles.isCardanoStakingEnabled else -> true } } diff --git a/data/staking/src/main/java/com/tangem/data/staking/toggles/DefaultStakingFeatureToggles.kt b/data/staking/src/main/java/com/tangem/data/staking/toggles/DefaultStakingFeatureToggles.kt index 3b3259c021..a0c9e1640c 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/toggles/DefaultStakingFeatureToggles.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/toggles/DefaultStakingFeatureToggles.kt @@ -9,4 +9,7 @@ internal class DefaultStakingFeatureToggles( override val isTonStakingEnabled: Boolean get() = featureTogglesManager.isFeatureEnabled(name = "STAKING_TON_ENABLED") + + override val isCardanoStakingEnabled: Boolean + get() = featureTogglesManager.isFeatureEnabled("STAKING_CARDANO_ENABLED") } \ No newline at end of file diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/toggles/StakingFeatureToggles.kt b/domain/staking/src/main/java/com/tangem/domain/staking/toggles/StakingFeatureToggles.kt index 47949204f9..33ae4375b0 100644 --- a/domain/staking/src/main/java/com/tangem/domain/staking/toggles/StakingFeatureToggles.kt +++ b/domain/staking/src/main/java/com/tangem/domain/staking/toggles/StakingFeatureToggles.kt @@ -2,4 +2,5 @@ package com.tangem.domain.staking.toggles interface StakingFeatureToggles { val isTonStakingEnabled: Boolean + val isCardanoStakingEnabled: Boolean } \ No newline at end of file From 540a938993e7cadb228e2fa338172e3a4557c607 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 4 Mar 2025 14:27:13 +0300 Subject: [PATCH 46/54] Updated on 2026-08-14 --- .../core/decompose/model/ModelEntryPoint.kt | 14 +++- .../decompose/navigation/DefaultRouter.kt | 2 +- .../navigation/inner/InnerPopRouter.kt | 36 +++++++++ .../decompose/navigation/inner/InnerRouter.kt | 81 +++++++++++++++++++ 4 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 core/decompose/src/main/kotlin/com/tangem/core/decompose/navigation/inner/InnerPopRouter.kt create mode 100644 core/decompose/src/main/kotlin/com/tangem/core/decompose/navigation/inner/InnerRouter.kt diff --git a/core/decompose/src/main/kotlin/com/tangem/core/decompose/model/ModelEntryPoint.kt b/core/decompose/src/main/kotlin/com/tangem/core/decompose/model/ModelEntryPoint.kt index d37de64a00..329556fff3 100644 --- a/core/decompose/src/main/kotlin/com/tangem/core/decompose/model/ModelEntryPoint.kt +++ b/core/decompose/src/main/kotlin/com/tangem/core/decompose/model/ModelEntryPoint.kt @@ -4,6 +4,8 @@ import com.arkivanov.essenty.instancekeeper.getOrCreate import com.arkivanov.essenty.instancekeeper.getOrCreateSimple import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.di.ModelComponent +import com.tangem.core.decompose.navigation.Router +import com.tangem.core.decompose.ui.UiMessageSender import dagger.hilt.EntryPoint import dagger.hilt.EntryPoints import dagger.hilt.InstallIn @@ -35,11 +37,15 @@ inline fun AppComponentContext.getOrCreateModel(): M = getOr * @param params The parameters to store in the [ParamsContainer], */ -inline fun AppComponentContext.getOrCreateModel(params: P?): M { - val entryPoint = instanceKeeper.getOrCreateSimple(key = "modelsEntryPoint") { +inline fun AppComponentContext.getOrCreateModel( + params: P?, + messageSender: UiMessageSender? = null, + router: Router? = null, +): M { + val entryPoint = instanceKeeper.getOrCreateSimple(key = "modelsEntryPoint_${M::class.simpleName}") { val hiltComponent = hiltComponentBuilder - .router(router) - .uiMessageSender(messageSender) + .router(router ?: this@getOrCreateModel.router) + .uiMessageSender(messageSender ?: this@getOrCreateModel.messageSender) .paramsContainer(MutableParamsContainer(params ?: Unit)) .build() diff --git a/core/decompose/src/main/kotlin/com/tangem/core/decompose/navigation/DefaultRouter.kt b/core/decompose/src/main/kotlin/com/tangem/core/decompose/navigation/DefaultRouter.kt index d2d4fb95e7..ed5cb7be3f 100644 --- a/core/decompose/src/main/kotlin/com/tangem/core/decompose/navigation/DefaultRouter.kt +++ b/core/decompose/src/main/kotlin/com/tangem/core/decompose/navigation/DefaultRouter.kt @@ -24,7 +24,7 @@ internal class DefaultRouter( navigation.navigate( transformer = { newRoutes }, - onComplete = { newStack, _ -> onComplete(newStack.size == newRoutes.size) }, + onComplete = { newStack, _ -> newStack == newRoutes }, ) } diff --git a/core/decompose/src/main/kotlin/com/tangem/core/decompose/navigation/inner/InnerPopRouter.kt b/core/decompose/src/main/kotlin/com/tangem/core/decompose/navigation/inner/InnerPopRouter.kt new file mode 100644 index 0000000000..12242d09b7 --- /dev/null +++ b/core/decompose/src/main/kotlin/com/tangem/core/decompose/navigation/inner/InnerPopRouter.kt @@ -0,0 +1,36 @@ +package com.tangem.core.decompose.navigation.inner + +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.decompose.navigation.Route +import com.tangem.core.decompose.navigation.Router +import kotlin.reflect.KClass + +/** + * Creates an router for overriding the pop operation. + * + * @param popCallback The callback to pop the route. + */ +@Suppress("FunctionName") +inline fun AppComponentContext.InnerPopRouter( + crossinline popCallback: ((onComplete: (Boolean) -> Unit) -> Unit), +): Router = object : Router { + override fun push(route: Route, onComplete: (Boolean) -> Unit) { + router.push(route, onComplete) + } + + override fun replaceAll(vararg routes: Route, onComplete: (Boolean) -> Unit) { + router.replaceAll(*routes, onComplete = onComplete) + } + + override fun pop(onComplete: (Boolean) -> Unit) { + popCallback(onComplete) + } + + override fun popTo(route: Route, onComplete: (Boolean) -> Unit) { + router.popTo(route, onComplete) + } + + override fun popTo(routeClass: KClass, onComplete: (Boolean) -> Unit) { + router.popTo(routeClass, onComplete) + } +} \ No newline at end of file diff --git a/core/decompose/src/main/kotlin/com/tangem/core/decompose/navigation/inner/InnerRouter.kt b/core/decompose/src/main/kotlin/com/tangem/core/decompose/navigation/inner/InnerRouter.kt new file mode 100644 index 0000000000..788afecd42 --- /dev/null +++ b/core/decompose/src/main/kotlin/com/tangem/core/decompose/navigation/inner/InnerRouter.kt @@ -0,0 +1,81 @@ +package com.tangem.core.decompose.navigation.inner + +import com.arkivanov.decompose.router.stack.StackNavigation +import com.arkivanov.decompose.router.stack.pop +import com.arkivanov.decompose.router.stack.pushNew +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.decompose.navigation.Route +import com.tangem.core.decompose.navigation.Router +import kotlin.reflect.KClass + +/** + * Creates a router that can handle a specific type of route. + * + * @param stackNavigation The stack navigation instance. + * @param popCallback The callback to pop the route. + * @param fallBackRouter The fallback router. + * @return The router. + */ +@Suppress("FunctionName") +inline fun AppComponentContext.InnerRouter( + stackNavigation: StackNavigation, + fallBackRouter: Router = router, + noinline popCallback: ((onComplete: (Boolean) -> Unit) -> Unit) = + { onComplete -> stackNavigation.pop(onComplete) }, +): Router = object : Router { + + override fun push(route: Route, onComplete: (Boolean) -> Unit) { + if (route is T) { + stackNavigation.pushNew(route, onComplete) + } else { + fallBackRouter.push(route, onComplete) + } + } + + override fun replaceAll(vararg routes: Route, onComplete: (Boolean) -> Unit) { + if (routes.any { it is T }) { + val newRoutes = routes.toList().filterIsInstance() + + stackNavigation.navigate( + transformer = { newRoutes }, + onComplete = { newStack, _ -> onComplete(newStack == newRoutes) }, + ) + } else { + fallBackRouter.replaceAll(*routes, onComplete = onComplete) + } + } + + override fun pop(onComplete: (Boolean) -> Unit) { + popCallback(onComplete) + } + + override fun popTo(route: Route, onComplete: (Boolean) -> Unit) { + if (route is T) { + stackNavigation.navigate( + transformer = { stack -> + stack + .dropLastWhile { it != route } + .ifEmpty { stack } + }, + onComplete = { newStack, oldStack -> onComplete(newStack.size < oldStack.size) }, + ) + } else { + fallBackRouter.popTo(route, onComplete) + } + } + + override fun popTo(routeClass: KClass, onComplete: (Boolean) -> Unit) { + if (routeClass == T::class) { + stackNavigation.navigate( + transformer = { stack -> + stack + .dropLastWhile { it::class != routeClass } + .ifEmpty { stack } + }, + onComplete = { newStack, oldStack -> onComplete(newStack.size < oldStack.size) }, + ) + } else { + fallBackRouter.popTo(routeClass, onComplete) + } + } +} \ No newline at end of file From 2fb0ef193672f7341edae7548df7de3d59589649 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 3 Mar 2025 23:49:10 +0700 Subject: [PATCH 47/54] Updated on 2026-08-14 --- .../common/analytics/events/AnalyticsParam.kt | 1 + .../common/analytics/events/WalletConnect.kt | 58 +++++++++++++++++-- .../DefaultLegacyWalletConnectRepository.kt | 51 ++++++++++++---- .../di/WalletConnectInteractorModule.kt | 16 +++-- .../domain/LegacyWalletConnectRepository.kt | 3 +- .../domain/WalletConnectInteractor.kt | 7 ++- .../walletconnect/WalletConnectAction.kt | 5 +- .../walletconnect/WalletConnectMiddleware.kt | 2 +- .../ui/walletconnect/WalletConnectModel.kt | 4 +- .../dialogs/ClipboardOrScanQrDialog.kt | 2 +- 10 files changed, 120 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt index 8cfba8dd64..67cd08e295 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt @@ -113,6 +113,7 @@ sealed class AnalyticsParam { const val SEED_PHRASE_LENGTH = "Seed Phrase Length" const val DAPP_NAME = "DApp Name" const val DAPP_URL = "DApp Url" + const val NETWORKS = "Networks" const val METHOD_NAME = "Method Name" const val VALIDATION = "Validation" const val BLOCKCHAIN_EXCEPTION_HOST = "exception_host" diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt index d2870bbb6a..1725eabaaa 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt @@ -1,6 +1,7 @@ package com.tangem.tap.common.analytics.events import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction.OpenSession.SourceType /** [REDACTED_AUTHOR] @@ -12,8 +13,41 @@ internal sealed class WalletConnect( ) : AnalyticsEvent("Wallet Connect", event, params, error) { class ScreenOpened : WalletConnect(event = "WC Screen Opened") - class NewSessionEstablished(dAppName: String, dAppUrl: String, blockchainNames: List) : WalletConnect( - event = "New Session Established", + class NewSessionInitiated(source: SourceType) : WalletConnect( + event = "Session Initiated", + params = mapOf( + AnalyticsParam.SOURCE to when (source) { + SourceType.QR -> "QR" + SourceType.DEEPLINK -> "DeepLink" + SourceType.ETC -> "etc" + }, + ), + ) + + data object SessionFailed : WalletConnect( + event = "Session Failed", + ) + + class DAppConnectionRequested( + blockchainNames: List, + ) : WalletConnect( + event = "dApp Connection Requested", + params = mapOf( + AnalyticsParam.NETWORKS to blockchainNames.joinToString(","), + ), + ) + + class DAppConnected(dAppName: String, dAppUrl: String, blockchainNames: List) : WalletConnect( + event = "dApp Connected", + params = mapOf( + AnalyticsParam.DAPP_NAME to dAppName, + AnalyticsParam.DAPP_URL to dAppUrl, + AnalyticsParam.BLOCKCHAIN to blockchainNames.joinToString(","), + ), + ) + + class DAppConnectionFailed(dAppName: String, dAppUrl: String, blockchainNames: List) : WalletConnect( + event = "dApp Connection Failed", params = mapOf( AnalyticsParam.DAPP_NAME to dAppName, AnalyticsParam.DAPP_URL to dAppUrl, @@ -22,17 +56,31 @@ internal sealed class WalletConnect( ) class SessionDisconnected(dAppName: String, dAppUrl: String) : WalletConnect( - event = "Session Disconnected", + event = "dApp Disconnected", params = mapOf( AnalyticsParam.DAPP_NAME to dAppName, AnalyticsParam.DAPP_URL to dAppUrl, ), ) - class RequestHandled( + class SignatureRequestHandled( params: RequestHandledParams, ) : WalletConnect( - event = "Request Handled", + event = "Signature Request Handled", + params = params.toParamsMap(), + ) + + class SignatureRequestReceived( + params: RequestHandledParams, + ) : WalletConnect( + event = "Signature Request Received", + params = params.toParamsMap(), + ) + + class SignatureRequestFailed( + params: RequestHandledParams, + ) : WalletConnect( + event = "Signature Request Failed", params = params.toParamsMap(), ) diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/DefaultLegacyWalletConnectRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/DefaultLegacyWalletConnectRepository.kt index d49c3386d7..7517f4d57d 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/DefaultLegacyWalletConnectRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/DefaultLegacyWalletConnectRepository.kt @@ -9,11 +9,9 @@ import com.reown.walletkit.client.Wallet import com.reown.walletkit.client.WalletKit import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.tap.common.analytics.events.WalletConnect -import com.tangem.tap.domain.walletconnect2.domain.LegacyWalletConnectRepository -import com.tangem.tap.domain.walletconnect2.domain.WcJrpcMethods -import com.tangem.tap.domain.walletconnect2.domain.WcJrpcRequestsDeserializer -import com.tangem.tap.domain.walletconnect2.domain.WcRequest +import com.tangem.tap.domain.walletconnect2.domain.* import com.tangem.tap.domain.walletconnect2.domain.models.* +import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction.OpenSession.SourceType import kotlinx.coroutines.* import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -24,6 +22,7 @@ internal class DefaultLegacyWalletConnectRepository( private val application: Application, private val wcRequestDeserializer: WcJrpcRequestsDeserializer, private val analyticsHandler: AnalyticsEventHandler, + private val blockchainHelper: WcBlockchainHelper, ) : LegacyWalletConnectRepository { private var sessionProposal: Wallet.Model.SessionProposal? = null @@ -136,6 +135,13 @@ internal class DefaultLegacyWalletConnectRepository( userNamespaces = this@DefaultLegacyWalletConnectRepository.userNamespaces ?: emptyMap(), ) + val requiredChainIds = sessionProposal.requiredNamespaces.values.flatMap { it.chains ?: emptyList() } + val optionalChainIds = optionalWithoutMissingNetworks.toList() + val networks = (requiredChainIds + optionalChainIds) + .mapNotNull { blockchainHelper.chainIdToFullNameOrNull(it) } + .distinct() + analyticsHandler.send(WalletConnect.DAppConnectionRequested(networks)) + scope.launch { _events.emit( WalletConnectEvents.SessionProposal( @@ -143,8 +149,8 @@ internal class DefaultLegacyWalletConnectRepository( sessionProposal.description, sessionProposal.url, sessionProposal.icons, - sessionProposal.requiredNamespaces.values.flatMap { it.chains ?: emptyList() }, - optionalWithoutMissingNetworks.toList(), + requiredChainIds, + optionalChainIds, ), ) } @@ -176,7 +182,17 @@ internal class DefaultLegacyWalletConnectRepository( result = "", ) } - else -> + else -> { + val event = WalletConnect.SignatureRequestReceived( + WalletConnect.RequestHandledParams( + dAppName = sessionRequest.peerMetaData?.name ?: "", + dAppUrl = sessionRequest.peerMetaData?.url ?: "", + methodName = sessionRequest.request.method, + blockchain = sessionRequest.chainId + ?.let { blockchainHelper.chainIdToNetworkIdOrNull(it) } ?: "", + ), + ) + analyticsHandler.send(event) scope.launch { _events.emit( WalletConnectEvents.SessionRequest( @@ -190,6 +206,7 @@ internal class DefaultLegacyWalletConnectRepository( ), ) } + } } } @@ -247,7 +264,8 @@ internal class DefaultLegacyWalletConnectRepository( this.userNamespaces = userNamespaces } - override fun pair(uri: String) { + override fun pair(uri: String, source: SourceType) { + analyticsHandler.send(WalletConnect.NewSessionInitiated(source = source)) WalletKit.pair( params = Wallet.Params.Pair(uri), onSuccess = { @@ -255,6 +273,7 @@ internal class DefaultLegacyWalletConnectRepository( }, onError = { Timber.e("Error while pairing: $it") + analyticsHandler.send(WalletConnect.SessionFailed) scope.launch { _events.emit( WalletConnectEvents.PairConnectError(it.throwable), @@ -305,7 +324,7 @@ internal class DefaultLegacyWalletConnectRepository( onSuccess = { Timber.i("Approved successfully: $it") analyticsHandler.send( - WalletConnect.NewSessionEstablished( + WalletConnect.DAppConnected( dAppName = sessionProposal.name, dAppUrl = sessionProposal.url, blockchainNames = blockchainNames, @@ -314,6 +333,13 @@ internal class DefaultLegacyWalletConnectRepository( }, onError = { Timber.e("Error while approving: $it") + analyticsHandler.send( + WalletConnect.DAppConnectionFailed( + dAppName = sessionProposal.name, + dAppUrl = sessionProposal.url, + blockchainNames = blockchainNames, + ), + ) scope.launch { _events.emit( WalletConnectEvents.SessionApprovalError( @@ -352,7 +378,7 @@ internal class DefaultLegacyWalletConnectRepository( // Add Ethereum Chain method is processed without user input, skip logging it if (requestData.method != WcJrpcMethods.WALLET_ADD_ETHEREUM_CHAIN.code) { analyticsHandler.send( - WalletConnect.RequestHandled( + WalletConnect.SignatureRequestHandled( WalletConnect.RequestHandledParams( dAppName = session?.name ?: "", dAppUrl = session?.url ?: "", @@ -377,7 +403,7 @@ internal class DefaultLegacyWalletConnectRepository( onError = { error -> Timber.e(error.throwable, "Error while responging session request") - WalletConnect.RequestHandledParams( + val params = WalletConnect.RequestHandledParams( dAppName = session?.name ?: "", dAppUrl = session?.url ?: "", methodName = requestData.method, @@ -385,6 +411,7 @@ internal class DefaultLegacyWalletConnectRepository( errorCode = WalletConnectError.ValidationError.error, errorDescription = error.throwable.message, ) + analyticsHandler.send(WalletConnect.SignatureRequestFailed(params)) }, ) } @@ -393,7 +420,7 @@ internal class DefaultLegacyWalletConnectRepository( val session = currentSessions.find { it.topic == requestData.topic } analyticsHandler.send( - WalletConnect.RequestHandled( + WalletConnect.SignatureRequestHandled( WalletConnect.RequestHandledParams( dAppName = session?.name ?: "", dAppUrl = session?.url ?: "", diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/di/WalletConnectInteractorModule.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/di/WalletConnectInteractorModule.kt index 9b7a44b10d..754a727e54 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/di/WalletConnectInteractorModule.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/di/WalletConnectInteractorModule.kt @@ -14,9 +14,7 @@ import com.tangem.tap.domain.walletconnect2.app.TangemWcBlockchainHelper import com.tangem.tap.domain.walletconnect2.app.WalletConnectEventsHandlerImpl import com.tangem.tap.domain.walletconnect2.data.DefaultLegacyWalletConnectRepository import com.tangem.tap.domain.walletconnect2.data.DefaultWalletConnectSessionsRepository -import com.tangem.tap.domain.walletconnect2.domain.LegacyWalletConnectRepository -import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor -import com.tangem.tap.domain.walletconnect2.domain.WalletConnectSessionsRepository +import com.tangem.tap.domain.walletconnect2.domain.* import com.tangem.tap.domain.walletconnect2.domain.WcJrpcRequestsDeserializer import com.tangem.tap.domain.walletconnect2.toggles.WalletConnectFeatureToggles import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -35,7 +33,7 @@ internal object WalletConnectInteractorModule { fun provideWalletConnectInteractor( wcRepository: LegacyWalletConnectRepository, wcSessionsRepository: WalletConnectSessionsRepository, - walletConnectFeatureToggles: WalletConnectFeatureToggles, + wcBlockchainHelper: WcBlockchainHelper, currenciesRepository: CurrenciesRepository, walletManagersFacade: WalletManagersFacade, userWalletsListManager: UserWalletsListManager, @@ -46,7 +44,7 @@ internal object WalletConnectInteractorModule { walletConnectRepository = wcRepository, sessionsRepository = wcSessionsRepository, sdkHelper = WalletConnectSdkHelper(), - blockchainHelper = TangemWcBlockchainHelper(walletConnectFeatureToggles), + blockchainHelper = wcBlockchainHelper, currenciesRepository = currenciesRepository, walletManagersFacade = walletManagersFacade, userWalletsListManager = userWalletsListManager, @@ -65,17 +63,25 @@ internal object WalletConnectModule { return WalletConnectFeatureToggles(featureTogglesManager) } + @Provides + @Singleton + fun provideWcBlockchainHelper(walletConnectFeatureToggles: WalletConnectFeatureToggles): WcBlockchainHelper { + return TangemWcBlockchainHelper(walletConnectFeatureToggles) + } + @Provides @Singleton fun provideWalletConnectRepository( application: Application, wcRequestDeserializer: WcJrpcRequestsDeserializer, analyticsHandler: AnalyticsEventHandler, + wcBlockchainHelper: WcBlockchainHelper, ): LegacyWalletConnectRepository { return DefaultLegacyWalletConnectRepository( application = application, wcRequestDeserializer = wcRequestDeserializer, analyticsHandler = analyticsHandler, + blockchainHelper = wcBlockchainHelper, ) } diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/LegacyWalletConnectRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/LegacyWalletConnectRepository.kt index d755da5aea..289a2664b5 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/LegacyWalletConnectRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/LegacyWalletConnectRepository.kt @@ -1,6 +1,7 @@ package com.tangem.tap.domain.walletconnect2.domain import com.tangem.tap.domain.walletconnect2.domain.models.* +import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction.OpenSession.SourceType import kotlinx.coroutines.flow.Flow interface LegacyWalletConnectRepository { @@ -17,7 +18,7 @@ interface LegacyWalletConnectRepository { fun updateSessions() - fun pair(uri: String) + fun pair(uri: String, source: SourceType) fun disconnect(topic: String) diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt index 48f90f3554..8c3b553cfe 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt @@ -135,7 +135,9 @@ class WalletConnectInteractor( isWalletConnectReadyForDeepLinks = true if (deeplinkStack.empty()) return val lastDeeplink = deeplinkStack.pop() - store.dispatchOnMain(WalletConnectAction.OpenSession(lastDeeplink)) + val action = WalletConnectAction + .OpenSession(lastDeeplink, WalletConnectAction.OpenSession.SourceType.DEEPLINK) + store.dispatchOnMain(action) }.onFailure { Timber.e("WC deeplink handling failed. $it") } @@ -392,7 +394,8 @@ class WalletConnectInteractor( } if (isWalletConnectReadyForDeepLinks) { - store.dispatchOnMain(WalletConnectAction.OpenSession(deeplink)) + val action = WalletConnectAction.OpenSession(deeplink, WalletConnectAction.OpenSession.SourceType.DEEPLINK) + store.dispatchOnMain(action) } else { deeplinkStack.push(deeplink) } diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectAction.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectAction.kt index 476bcd288d..3383203b41 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectAction.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectAction.kt @@ -15,7 +15,10 @@ sealed class WalletConnectAction : Action { data class OpenSession( val wcUri: String, - ) : WalletConnectAction() + val source: SourceType, + ) : WalletConnectAction() { + enum class SourceType { QR, DEEPLINK, ETC } + } data class DisconnectSession(val topic: String) : WalletConnectAction() diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt index 4e7c5c7be2..8535bc008f 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt @@ -76,7 +76,7 @@ class WalletConnectMiddleware { is WalletConnectAction.OpenSession -> { val index = action.wcUri.indexOf("@") when (action.wcUri[index + 1]) { - '2' -> walletConnectRepository.pair(uri = action.wcUri) + '2' -> walletConnectRepository.pair(uri = action.wcUri, source = action.source) '1' -> { store.dispatchOnMain(WalletConnectAction.UnsupportedDappRequest) store.dispatchOnMain( diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectModel.kt index 39f27fb752..b940ddcc29 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectModel.kt @@ -13,6 +13,7 @@ import com.tangem.tap.store import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import timber.log.Timber import javax.inject.Inject @@ -29,7 +30,8 @@ internal class WalletConnectModel @Inject constructor( modelScope.launch { listenToQrScanningUseCase(SourceType.WALLET_CONNECT) .getOrElse { emptyFlow() } - .collect { store.dispatch(WalletConnectAction.OpenSession(it)) } + .map { WalletConnectAction.OpenSession(it, WalletConnectAction.OpenSession.SourceType.QR) } + .collect { store.dispatch(it) } } } diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/ClipboardOrScanQrDialog.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/ClipboardOrScanQrDialog.kt index 5411faec75..a6ac03c6c7 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/ClipboardOrScanQrDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/ClipboardOrScanQrDialog.kt @@ -17,7 +17,7 @@ object ClipboardOrScanQrDialog { setTitle(context.getString(R.string.common_select_action)) setMessage(context.getText(R.string.wallet_connect_clipboard_alert)) setPositiveButton(context.getText(R.string.wallet_connect_paste_from_clipboard)) { _, _ -> - store.dispatch(WalletConnectAction.OpenSession(wcUri)) + store.dispatch(WalletConnectAction.OpenSession(wcUri, WalletConnectAction.OpenSession.SourceType.ETC)) } setNegativeButton(context.getText(R.string.wallet_connect_scan_new_code)) { _, _ -> store.dispatchNavigationAction { From afb82a03f7513b5822414b7557980abb032e42c6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 4 Mar 2025 16:31:59 +0200 Subject: [PATCH 48/54] Updated on 2026-08-14 --- .../models/response/ExchangeStatusResponse.kt | 7 ++ .../analytics/TokenExchangeAnalyticsEvent.kt | 23 +++- features/swap/data/build.gradle.kts | 1 + .../converters/ExchangeStatusConverter.kt | 2 + features/swap/domain/models/build.gradle.kts | 1 + .../domain/models/domain/ExchangeStatus.kt | 14 ++- .../feature/swap/domain/SwapInteractorImpl.kt | 2 + ...tions.kt => ExchangeStatusNotification.kt} | 18 ++- .../tokendetails/state/express/ExchangeUM.kt | 5 +- ...enDetailsSwapTransactionsStateConverter.kt | 54 +++++---- .../factory/express/ExchangeStatusFactory.kt | 12 +- .../factory/express/ExpressStatusFactory.kt | 29 ++++- .../express/ExpressStatusBottomSheet.kt | 23 +++- .../ExpressStatusBottomSheetStateProvider.kt | 111 ++++++++++++++++++ .../ExchangeStatusBottomSheetContent.kt | 9 +- 15 files changed, 270 insertions(+), 41 deletions(-) rename features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/{ExchangeStatusNotifications.kt => ExchangeStatusNotification.kt} (84%) create mode 100644 features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/ExpressStatusBottomSheetStateProvider.kt diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeStatusResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeStatusResponse.kt index 043222d3e3..eaada836bf 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeStatusResponse.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeStatusResponse.kt @@ -2,6 +2,7 @@ package com.tangem.datasource.api.express.models.response import com.squareup.moshi.Json import com.squareup.moshi.JsonClass +import org.joda.time.DateTime @JsonClass(generateAdapter = true) data class ExchangeStatusResponse( @@ -26,6 +27,12 @@ data class ExchangeStatusResponse( @Json(name = "refundContractAddress") val refundContractAddress: String? = null, + + @Json(name = "createdAt") + val createdAt: DateTime? = null, + + @Json(name = "averageDuration") + val averageDuration: Int? = null, ) @JsonClass(generateAdapter = false) diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/TokenExchangeAnalyticsEvent.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/TokenExchangeAnalyticsEvent.kt index 9df2d8a224..7fe8dfdf64 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/TokenExchangeAnalyticsEvent.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/TokenExchangeAnalyticsEvent.kt @@ -26,17 +26,34 @@ class TokenExchangeAnalyticsEvent( ) class GoToProviderStatus(token: String) : TokenScreenAnalyticsEvent( - event = "Button - Go To Provider", + event = BUTTON_GO_TO_PROVIDER, params = mapOf(TOKEN_PARAM to token, PLACE to "Status"), ) class GoToProviderKYC(token: String) : TokenScreenAnalyticsEvent( - event = "Button - Go To Provider", + event = BUTTON_GO_TO_PROVIDER, params = mapOf(TOKEN_PARAM to token, PLACE to "KYC"), ) class GoToProviderFail(token: String) : TokenScreenAnalyticsEvent( - event = "Button - Go To Provider", + event = BUTTON_GO_TO_PROVIDER, params = mapOf(TOKEN_PARAM to token, PLACE to "Fail"), ) + + class GoToProviderLongTime(token: String) : TokenScreenAnalyticsEvent( + event = BUTTON_GO_TO_PROVIDER, + params = mapOf(TOKEN_PARAM to token, PLACE to "LongTime"), + ) + + class LongTimeTransaction(token: String, provider: String) : TokenScreenAnalyticsEvent( + event = "Notice - Long Time Transaction", + params = mapOf( + TOKEN_PARAM to token, + PROVIDER to provider, + ), + ) + + private companion object { + const val BUTTON_GO_TO_PROVIDER = "Button - Go To Provider" + } } \ No newline at end of file diff --git a/features/swap/data/build.gradle.kts b/features/swap/data/build.gradle.kts index 08890ead13..0134f08d66 100644 --- a/features/swap/data/build.gradle.kts +++ b/features/swap/data/build.gradle.kts @@ -49,6 +49,7 @@ dependencies { /** Others */ implementation(deps.timber) + implementation(deps.jodatime) /** DI */ implementation(deps.hilt.android) diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ExchangeStatusConverter.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ExchangeStatusConverter.kt index cb3ba18d9f..a1cd69d8cb 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ExchangeStatusConverter.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ExchangeStatusConverter.kt @@ -17,6 +17,8 @@ internal class ExchangeStatusConverter : Converter createdAt + } else { + false + } +} @JsonClass(generateAdapter = false) enum class ExchangeStatus { diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index a36223d839..717a096159 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -1006,6 +1006,7 @@ internal class SwapInteractorImpl @AssistedInject constructor( timestamp: Long, txExternalUrl: String? = null, txExternalId: String? = null, + averageDuration: Int? = null, ) { swapTransactionRepository.storeTransaction( userWalletId = userWalletId, @@ -1023,6 +1024,7 @@ internal class SwapInteractorImpl @AssistedInject constructor( txId = swapDataModel.transaction.txId, txExternalUrl = txExternalUrl, txExternalId = txExternalId, + averageDuration = averageDuration, ), ), ) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/ExchangeStatusNotifications.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/ExchangeStatusNotification.kt similarity index 84% rename from features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/ExchangeStatusNotifications.kt rename to features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/ExchangeStatusNotification.kt index 599abba71d..348e8e63ba 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/ExchangeStatusNotifications.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/ExchangeStatusNotification.kt @@ -15,9 +15,9 @@ import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.features.tokendetails.impl.R @Immutable -internal sealed interface ExchangeStatusNotifications { +internal sealed interface ExchangeStatusNotification { - sealed class CommonNotification(val config: NotificationConfig) : ExchangeStatusNotifications + sealed class CommonNotification(val config: NotificationConfig) : ExchangeStatusNotification @Deprecated("Use one in ExpressNotificationsUM") data class NeedVerification(val onGoToProviderClick: () -> Unit) : CommonNotification( @@ -45,11 +45,23 @@ internal sealed interface ExchangeStatusNotifications { ), ) + data class LongTimeExchange(val onGoToProviderClick: () -> Unit) : CommonNotification( + config = NotificationConfig( + title = resourceReference(R.string.express_exchange_notification_long_transaction_time_title), + subtitle = resourceReference(R.string.express_exchange_notification_long_transaction_time_text), + iconResId = R.drawable.ic_alert_triangle_20, + buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig( + text = resourceReference(R.string.common_go_to_provider), + onClick = onGoToProviderClick, + ), + ), + ) + data class TokenRefunded( val cryptoCurrency: CryptoCurrency, val onReadMoreClick: () -> Unit, val onGoToTokenClick: () -> Unit, - ) : ExchangeStatusNotifications { + ) : ExchangeStatusNotification { val config = CurrencyNotificationConfig( title = resourceReference( diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/express/ExchangeUM.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/express/ExchangeUM.kt index ac23c537eb..85d610e7d9 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/express/ExchangeUM.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/express/ExchangeUM.kt @@ -5,7 +5,7 @@ import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.feature.swap.domain.models.domain.ExchangeStatus import com.tangem.feature.swap.domain.models.domain.SwapProvider -import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotifications +import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotification import kotlinx.collections.immutable.ImmutableList internal data class ExchangeUM( @@ -13,8 +13,9 @@ internal data class ExchangeUM( val provider: SwapProvider, val activeStatus: ExchangeStatus?, val statuses: ImmutableList, - val notification: ExchangeStatusNotifications? = null, + val notification: ExchangeStatusNotification?, val showProviderLink: Boolean, val fromCryptoCurrency: CryptoCurrency, val toCryptoCurrency: CryptoCurrency, + val hasLongTime: Boolean, ) : ExpressTransactionStateUM \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt index d13c0cab28..780910ba7b 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt @@ -24,7 +24,7 @@ import com.tangem.feature.swap.domain.models.domain.ExchangeStatus.Companion.isF import com.tangem.feature.swap.domain.models.domain.ExchangeStatusModel import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionListModel import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionModel -import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotifications +import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotification import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeStatusState import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents @@ -82,17 +82,18 @@ internal class TokenDetailsSwapTransactionsStateConverter( } } val statusModel = transaction.status - val notifications = getNotification( + val notification = getNotification( status = statusModel?.status, txUrl = statusModel?.txExternalUrl, refundToken = statusModel?.refundCurrency, + hasLongTime = statusModel?.hasLongTime, ) - val showProviderLink = getShowProviderLink(notifications, transaction.status) + val showProviderLink = getShowProviderLink(notification, transaction.status) result.add( ExchangeUM( provider = transaction.provider, statuses = getStatuses(statusModel?.status), - notification = notifications, + notification = notification, activeStatus = statusModel?.status, showProviderLink = showProviderLink, fromCryptoCurrency = fromCryptoCurrency, @@ -104,6 +105,7 @@ internal class TokenDetailsSwapTransactionsStateConverter( toFiatAmount, fromFiatAmount, ), + hasLongTime = transaction.status?.hasLongTime ?: false, ), ) } @@ -111,17 +113,22 @@ internal class TokenDetailsSwapTransactionsStateConverter( return result.toPersistentList() } - fun updateTxStatus(tx: ExchangeUM, statusModel: ExchangeStatusModel?): ExchangeUM { - if (statusModel == null || tx.activeStatus == statusModel.status) { + fun updateTxStatus(tx: ExchangeUM, statusModel: ExchangeStatusModel): ExchangeUM { + if (tx.activeStatus == statusModel.status && tx.hasLongTime == statusModel.hasLongTime) { Timber.e("UpdateTxStatus isn't required. Current status isn't changed") return tx } val hasFailed = statusModel.status.isFailed() - val notifications = getNotification(statusModel.status, statusModel.txExternalUrl, statusModel.refundCurrency) - val showProviderLink = getShowProviderLink(notifications, statusModel) + val notification = getNotification( + status = statusModel.status, + txUrl = statusModel.txExternalUrl, + refundToken = statusModel.refundCurrency, + hasLongTime = statusModel.hasLongTime, + ) + val showProviderLink = getShowProviderLink(notification, statusModel) return tx.copy( activeStatus = statusModel.status, - notification = notifications, + notification = notification, statuses = getStatuses(statusModel.status, hasFailed), showProviderLink = showProviderLink, info = tx.info.copy(txExternalUrl = statusModel.txExternalUrl), @@ -184,39 +191,46 @@ internal class TokenDetailsSwapTransactionsStateConverter( status: ExchangeStatus?, txUrl: String?, refundToken: CryptoCurrency?, - ): ExchangeStatusNotifications? { - return when (status) { - ExchangeStatus.Failed, - ExchangeStatus.TxFailed, - -> { + hasLongTime: Boolean?, + ): ExchangeStatusNotification? { + return when { + status == ExchangeStatus.Failed || status == ExchangeStatus.TxFailed -> { if (txUrl == null) return null - ExchangeStatusNotifications.Failed { + ExchangeStatusNotification.Failed { analyticsEventsHandler.send( TokenExchangeAnalyticsEvent.GoToProviderFail(cryptoCurrency.symbol), ) clickIntents.onGoToProviderClick(txUrl) } } - ExchangeStatus.Verifying -> { + status == ExchangeStatus.Verifying -> { if (txUrl == null) return null - ExchangeStatusNotifications.NeedVerification { + ExchangeStatusNotification.NeedVerification { analyticsEventsHandler.send( TokenExchangeAnalyticsEvent.GoToProviderKYC(cryptoCurrency.symbol), ) clickIntents.onGoToProviderClick(txUrl) } } - ExchangeStatus.Refunded -> { + status == ExchangeStatus.Refunded -> { if (refundToken == null) { null } else { - ExchangeStatusNotifications.TokenRefunded( + ExchangeStatusNotification.TokenRefunded( cryptoCurrency = refundToken, onReadMoreClick = { clickIntents.onOpenUrlClick(url = getAboutCrossChainBridgesLink()) }, onGoToTokenClick = { clickIntents.onGoToRefundedTokenClick(refundToken) }, ) } } + status?.isTerminal == false && txUrl != null && hasLongTime == true -> { + ExchangeStatusNotification.LongTimeExchange { + analyticsEventsHandler.send( + event = TokenExchangeAnalyticsEvent.GoToProviderLongTime(cryptoCurrency.symbol), + ) + clickIntents.onGoToProviderClick(txUrl) + } + } else -> null } } @@ -239,7 +253,7 @@ internal class TokenDetailsSwapTransactionsStateConverter( statuses = persistentListOf(), ) - private fun getShowProviderLink(notifications: ExchangeStatusNotifications?, status: ExchangeStatusModel?) = + private fun getShowProviderLink(notifications: ExchangeStatusNotification?, status: ExchangeStatusModel?) = notifications == null && status?.txExternalUrl != null && status.status != ExchangeStatus.Cancelled private fun getStatuses(status: ExchangeStatus?, hasFailed: Boolean = false): ImmutableList { diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt index 8596a83abd..f9d9aed682 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt @@ -101,10 +101,14 @@ internal class ExchangeStatusFactory @AssistedInject constructor( } else { val statusModel = getExchangeStatus(swapTx.info.txId, swapTx.provider) - swapTransactionsStateConverter.updateTxStatus( - tx = swapTx, - statusModel = statusModel, - ) + if (statusModel != null) { + swapTransactionsStateConverter.updateTxStatus( + tx = swapTx, + statusModel = statusModel, + ) + } else { + swapTx + } } } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt index 289cfffede..636fa5cc1f 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt @@ -12,6 +12,7 @@ import com.tangem.domain.tokens.model.analytics.TokenOnrampAnalyticsEvent import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.swap.domain.models.domain.ExchangeStatus import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState +import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotification import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.utils.Provider @@ -110,9 +111,7 @@ internal class ExpressStatusFactory @AssistedInject constructor( return state.copy( expressTxs = expressTxs, expressTxsToDisplay = expressTxsToDisplay, - bottomSheetConfig = currentTx?.let( - ::updateStateWithExpressStatusBottomSheet, - ) ?: config, + bottomSheetConfig = currentTx?.let(::updateStateWithExpressStatusBottomSheet) ?: config, ) } @@ -146,6 +145,12 @@ internal class ExpressStatusFactory @AssistedInject constructor( val state = currentStateProvider() val bottomSheetConfig = state.bottomSheetConfig val currentConfig = bottomSheetConfig?.content as? ExpressStatusBottomSheetConfig ?: return bottomSheetConfig + + sendLongTimeExchangeNotificationShowEvent( + expressState = expressState, + currentStateNotification = (currentConfig.value as? ExchangeUM)?.notification, + ) + return bottomSheetConfig.copy( content = if (currentConfig.value != expressState) { ExpressStatusBottomSheetConfig(expressState) @@ -167,6 +172,24 @@ internal class ExpressStatusFactory @AssistedInject constructor( } } + private fun sendLongTimeExchangeNotificationShowEvent( + expressState: ExpressTransactionStateUM, + currentStateNotification: ExchangeStatusNotification?, + ) { + val newState = expressState as? ExchangeUM + val newStateNotification = newState?.notification + if (currentStateNotification !is ExchangeStatusNotification.LongTimeExchange && + newStateNotification is ExchangeStatusNotification.LongTimeExchange + ) { + analyticsEventsHandler.send( + TokenExchangeAnalyticsEvent.LongTimeTransaction( + token = cryptoCurrency.symbol, + provider = newState.provider.name, + ), + ) + } + } + @AssistedFactory interface Factory { @Suppress("LongParameterList") diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/ExpressStatusBottomSheet.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/ExpressStatusBottomSheet.kt index 8eec7243af..0bf0416539 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/ExpressStatusBottomSheet.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/ExpressStatusBottomSheet.kt @@ -1,12 +1,16 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express +import android.content.res.Configuration import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig import com.tangem.common.ui.expressStatus.OnrampStatusBottomSheetContent -import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM +import com.tangem.common.ui.expressStatus.state.* import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.exchange.ExchangeStatusBottomSheetContent @@ -21,4 +25,21 @@ internal fun ExpressStatusBottomSheet(config: TangemBottomSheetConfig) { is ExchangeUM -> ExchangeStatusBottomSheetContent(state) } } +} + +@Preview(showBackground = true, widthDp = 360, heightDp = 720) +@Preview(showBackground = true, widthDp = 360, heightDp = 720, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun PreviewExpressStatusBottomSheet( + @PreviewParameter(ExpressStatusBottomSheetStateProvider::class) param: ExpressStatusBottomSheetConfig, +) { + TangemThemePreview { + ExpressStatusBottomSheet( + config = TangemBottomSheetConfig( + isShown = true, + onDismissRequest = {}, + content = param, + ), + ) + } } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/ExpressStatusBottomSheetStateProvider.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/ExpressStatusBottomSheetStateProvider.kt new file mode 100644 index 0000000000..c5ae881c94 --- /dev/null +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/ExpressStatusBottomSheetStateProvider.kt @@ -0,0 +1,111 @@ +package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig +import com.tangem.common.ui.expressStatus.state.* +import com.tangem.core.ui.components.currency.icon.CurrencyIconState +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.stringReference +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.tokens.model.CryptoCurrency.ID +import com.tangem.domain.tokens.model.Network +import com.tangem.feature.swap.domain.models.domain.ExchangeProviderType +import com.tangem.feature.swap.domain.models.domain.ExchangeStatus +import com.tangem.feature.swap.domain.models.domain.SwapProvider +import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotification +import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeStatusState +import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM +import kotlinx.collections.immutable.persistentListOf +import java.math.BigDecimal + +class ExpressStatusBottomSheetStateProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + ExpressStatusBottomSheetConfig( + ExchangeUM( + info = ExpressTransactionStateInfoUM( + title = TextReference.Str("Transaction Status"), + status = ExpressStatusUM( + title = TextReference.Str("Status Details"), + link = ExpressLinkUM.Empty, + statuses = persistentListOf( + ExpressStatusItemUM(TextReference.Str("Created"), ExpressStatusItemState.Active), + ExpressStatusItemUM(TextReference.Str("Exchanging"), ExpressStatusItemState.Active), + ExpressStatusItemUM(TextReference.Str("Done"), ExpressStatusItemState.Active), + ), + ), + notification = null, + txId = "123456", + txExternalId = "78910", + txExternalUrl = "https://example.com/tx/78910", + timestamp = System.currentTimeMillis(), + timestampFormatted = TextReference.Str("Just now"), + onGoToProviderClick = {}, + onClick = {}, + onDisposeExpressStatus = {}, + iconState = ExpressTransactionStateIconUM.None, + toAmount = TextReference.Str("0.1 BTC"), + toFiatAmount = TextReference.Str("$5000"), + toAmountSymbol = "BTC", + toCurrencyIcon = CurrencyIconState.Empty(), + fromAmount = TextReference.Str("5000 USDT"), + fromFiatAmount = TextReference.Str("$5000"), + fromAmountSymbol = "USDT", + fromCurrencyIcon = CurrencyIconState.Empty(), + ), + provider = SwapProvider( + providerId = "1", + rateTypes = emptyList(), + name = "Provider", + type = ExchangeProviderType.DEX, + imageLarge = "", + termsOfUse = null, + privacyPolicy = null, + slippage = BigDecimal.ZERO, + ), + activeStatus = null, + statuses = persistentListOf( + ExchangeStatusState( + status = ExchangeStatus.Exchanging, + text = stringReference("Exchanging"), + isActive = true, + isDone = false, + ), + ), + notification = ExchangeStatusNotification.LongTimeExchange {}, + showProviderLink = false, + fromCryptoCurrency = token, + toCryptoCurrency = token, + hasLongTime = true, + ), + ), + ) + + private val token + get() = CryptoCurrency.Coin( + id = ID( + ID.Prefix.COIN_PREFIX, + ID.Body.NetworkId(network.id.value), + ID.Suffix.RawID("token1"), + ), + network = network, + name = "Token 1", + symbol = "T1", + decimals = 8, + iconUrl = null, + isCustom = false, + ) + + private val network = Network( + id = Network.ID("network1"), + name = "Network One", + isTestnet = false, + standardType = Network.StandardType.ERC20, + backendId = "network1", + currencySymbol = "ETH", + derivationPath = Network.DerivationPath.None, + hasFiatFeeRate = true, + canHandleTokens = true, + transactionExtrasType = Network.TransactionExtrasType.NONE, + ) +} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/exchange/ExchangeStatusBottomSheetContent.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/exchange/ExchangeStatusBottomSheetContent.kt index c91628293c..581f05d757 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/exchange/ExchangeStatusBottomSheetContent.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/exchange/ExchangeStatusBottomSheetContent.kt @@ -24,7 +24,7 @@ import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.swap.domain.models.domain.ExchangeStatus import com.tangem.feature.swap.domain.models.domain.ExchangeStatus.Companion.isFailed -import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotifications +import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotification import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM @Composable @@ -88,14 +88,15 @@ internal fun ExchangeStatusBottomSheetContent(state: ExchangeUM) { } @Composable -private fun Notification(state: ExchangeStatusNotifications, activeStatus: ExchangeStatus?) { +private fun Notification(state: ExchangeStatusNotification, activeStatus: ExchangeStatus?) { AnimatedContent( targetState = state, modifier = Modifier.padding(top = TangemTheme.dimens.spacing12), label = "Exchange Status Notification Change", + contentKey = { it::class.java }, ) { notification -> when (notification) { - is ExchangeStatusNotifications.CommonNotification -> { + is ExchangeStatusNotification.CommonNotification -> { com.tangem.core.ui.components.notifications.Notification( config = notification.config, iconTint = when { @@ -106,7 +107,7 @@ private fun Notification(state: ExchangeStatusNotifications, activeStatus: Excha containerColor = TangemTheme.colors.background.action, ) } - is ExchangeStatusNotifications.TokenRefunded -> { + is ExchangeStatusNotification.TokenRefunded -> { CurrencyNotification( config = notification.config, containerColor = TangemTheme.colors.background.action, From 1437c14019f6e4f063527e7d7bf0f84e8a18fc91 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 4 Mar 2025 21:26:41 +0200 Subject: [PATCH 49/54] Updated on 2026-08-14 --- version.properties | 1 - 1 file changed, 1 deletion(-) delete mode 100644 version.properties diff --git a/version.properties b/version.properties deleted file mode 100644 index 60c5fb9778..0000000000 --- a/version.properties +++ /dev/null @@ -1 +0,0 @@ -versionName=5.21.0 \ No newline at end of file From 3f671e3e0f0f4da0ece0e120162860cd1a20e4d5 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 5 Mar 2025 13:16:45 +0500 Subject: [PATCH 50/54] Updated on 2026-08-14 --- app/build.gradle.kts | 2 + .../configs/feature_toggles_config.json | 4 + .../com/tangem/pagination/BatchListSource.kt | 2 +- .../ui/components/transactions/Transaction.kt | 1 + .../transactions/TransactionList.kt | 2 +- .../components/transactions/TxHistoryTitle.kt | 2 +- data/txhistory/build.gradle.kts | 1 + .../data/txhistory/di/TxHistoryDataModule.kt | 16 ++ .../RefactoredTxHistoryRepository.kt | 126 +++++++++++ .../paging/TxHistoryPageBatchFetcher.kt | 73 +++++++ domain/txhistory/build.gradle.kts | 2 + .../tangem/domain/txhistory/models/Page.kt | 4 +- .../txhistory/model/TxHistoryListConfig.kt | 6 + .../txhistory/model/TxHistoryTypealiases.kt | 10 + .../repository/TxHistoryRepositoryV2.kt | 9 + features/send/impl/build.gradle.kts | 1 + .../send/impl/presentation/model/SendModel.kt | 18 +- features/staking/impl/build.gradle.kts | 1 + .../state/helpers/StakingBalanceUpdater.kt | 18 +- features/tokendetails/impl/build.gradle.kts | 1 + .../DefaultTokenDetailsComponent.kt | 14 +- .../tokendetails/model/TokenDetailsModel.kt | 52 +++-- .../tokendetails/ui/TokenDetailsScreen.kt | 48 ++++- features/txhistory/api/.gitignore | 1 + features/txhistory/api/build.gradle.kts | 26 +++ .../txhistory/TxHistoryFeatureToggles.kt | 5 + .../txhistory/component/TxHistoryComponent.kt | 28 +++ .../entity/TxHistoryContentUpdateEmitter.kt | 5 + .../features/txhistory/entity/TxHistoryUM.kt | 93 ++++++++ features/txhistory/impl/.gitignore | 1 + features/txhistory/impl/build.gradle.kts | 59 +++++ .../DefaultTxHistoryFeatureToggles.kt | 11 + .../component/DefaultTxHistoryComponent.kt | 38 ++++ ...xHistoryItemToTransactionStateConverter.kt | 129 +++++++++++ .../txhistory/di/TxHistoryFeatureModule.kt | 23 ++ .../txhistory/di/TxHistoryModelModule.kt | 19 ++ .../txhistory/di/TxHistoryUpdaterModule.kt | 23 ++ .../entity/DefaultTxHistoryUpdater.kt | 18 ++ .../entity/TxHistoryUpdateListener.kt | 7 + .../txhistory/model/TxHistoryModel.kt | 202 ++++++++++++++++++ .../features/txhistory/ui/TxHistoryContent.kt | 164 ++++++++++++++ .../txhistory/utils/TxHistoryListManager.kt | 99 +++++++++ .../txhistory/utils/TxHistoryListState.kt | 10 + .../txhistory/utils/TxHistoryUiActions.kt | 7 + .../txhistory/utils/TxHistoryUiManager.kt | 113 ++++++++++ settings.gradle.kts | 3 + 46 files changed, 1454 insertions(+), 43 deletions(-) create mode 100644 data/txhistory/src/main/kotlin/com/tangem/data/txhistory/repository/RefactoredTxHistoryRepository.kt create mode 100644 data/txhistory/src/main/kotlin/com/tangem/data/txhistory/repository/paging/TxHistoryPageBatchFetcher.kt create mode 100644 domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/model/TxHistoryListConfig.kt create mode 100644 domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/model/TxHistoryTypealiases.kt create mode 100644 domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/repository/TxHistoryRepositoryV2.kt create mode 100644 features/txhistory/api/.gitignore create mode 100644 features/txhistory/api/build.gradle.kts create mode 100644 features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/TxHistoryFeatureToggles.kt create mode 100644 features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/component/TxHistoryComponent.kt create mode 100644 features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/entity/TxHistoryContentUpdateEmitter.kt create mode 100644 features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/entity/TxHistoryUM.kt create mode 100644 features/txhistory/impl/.gitignore create mode 100644 features/txhistory/impl/build.gradle.kts create mode 100644 features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/DefaultTxHistoryFeatureToggles.kt create mode 100644 features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/component/DefaultTxHistoryComponent.kt create mode 100644 features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt create mode 100644 features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/di/TxHistoryFeatureModule.kt create mode 100644 features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/di/TxHistoryModelModule.kt create mode 100644 features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/di/TxHistoryUpdaterModule.kt create mode 100644 features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/entity/DefaultTxHistoryUpdater.kt create mode 100644 features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/entity/TxHistoryUpdateListener.kt create mode 100644 features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/model/TxHistoryModel.kt create mode 100644 features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/ui/TxHistoryContent.kt create mode 100644 features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryListManager.kt create mode 100644 features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryListState.kt create mode 100644 features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryUiActions.kt create mode 100644 features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryUiManager.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5c9baecf6c..6f39ce42e9 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -186,6 +186,8 @@ dependencies { implementation(projects.features.onboardingV2.impl) implementation(projects.features.stories.api) implementation(projects.features.stories.impl) + implementation(projects.features.txhistory.api) + implementation(projects.features.txhistory.impl) /** AndroidX libraries */ implementation(deps.androidx.core.ktx) diff --git a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json index 0538c8067c..a9a8c23e01 100644 --- a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json @@ -54,5 +54,9 @@ { "name": "STAKING_CARDANO_ENABLED", "version": "undefined" + }, + { + "name": "TX_HISTORY_REFACTORING_ENABLED", + "version": "undefined" } ] diff --git a/core/pagination/src/main/java/com/tangem/pagination/BatchListSource.kt b/core/pagination/src/main/java/com/tangem/pagination/BatchListSource.kt index 535c7deea4..dab020caa2 100644 --- a/core/pagination/src/main/java/com/tangem/pagination/BatchListSource.kt +++ b/core/pagination/src/main/java/com/tangem/pagination/BatchListSource.kt @@ -289,7 +289,7 @@ private class DefaultBatchListSource batchFetcher.fetchNext(action.requestParams, lastResult) }.getOrElse { BatchFetchResult.Error(it) } - lastRequestResult.value = lastResult + lastRequestResult.value = res state.update { currentState -> when (res) { diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/transactions/Transaction.kt b/core/ui/src/main/java/com/tangem/core/ui/components/transactions/Transaction.kt index 8c7bdbc6d9..761db501ac 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/transactions/Transaction.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/transactions/Transaction.kt @@ -445,5 +445,6 @@ private class TransactionItemStateProvider : CollectionPreviewParameterProvider< onClick = {}, ), TransactionState.Loading(txHash = UUID.randomUUID().toString()), + TransactionState.Locked(txHash = UUID.randomUUID().toString()), ), ) \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/transactions/TransactionList.kt b/core/ui/src/main/java/com/tangem/core/ui/components/transactions/TransactionList.kt index 7aeca782bf..5ff2f3c7bc 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/transactions/TransactionList.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/transactions/TransactionList.kt @@ -104,7 +104,7 @@ private fun LazyListScope.contentItems( } @Composable -private fun PendingTxsBlock(pendingTxs: ImmutableList, isBalanceHidden: Boolean) { +fun PendingTxsBlock(pendingTxs: ImmutableList, isBalanceHidden: Boolean) { Column( modifier = Modifier .padding(top = TangemTheme.dimens.spacing12) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/transactions/TxHistoryTitle.kt b/core/ui/src/main/java/com/tangem/core/ui/components/transactions/TxHistoryTitle.kt index 4f8201f07c..f7cb3263ce 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/transactions/TxHistoryTitle.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/transactions/TxHistoryTitle.kt @@ -23,7 +23,7 @@ import com.tangem.core.ui.res.TangemThemePreview * @param modifier modifier */ @Composable -internal fun TxHistoryTitle(onExploreClick: () -> Unit, modifier: Modifier = Modifier) { +fun TxHistoryTitle(onExploreClick: () -> Unit, modifier: Modifier = Modifier) { Row( modifier = modifier .background(TangemTheme.colors.background.primary) diff --git a/data/txhistory/build.gradle.kts b/data/txhistory/build.gradle.kts index 23bb1bd73d..0a6a9baf74 100644 --- a/data/txhistory/build.gradle.kts +++ b/data/txhistory/build.gradle.kts @@ -14,6 +14,7 @@ dependencies { implementation(projects.core.utils) implementation(projects.core.datasource) + implementation(projects.core.pagination) implementation(projects.domain.legacy) implementation(projects.libs.blockchainSdk) implementation(projects.domain.tokens.models) diff --git a/data/txhistory/src/main/kotlin/com/tangem/data/txhistory/di/TxHistoryDataModule.kt b/data/txhistory/src/main/kotlin/com/tangem/data/txhistory/di/TxHistoryDataModule.kt index ebc92a5036..1a756f54e1 100644 --- a/data/txhistory/src/main/kotlin/com/tangem/data/txhistory/di/TxHistoryDataModule.kt +++ b/data/txhistory/src/main/kotlin/com/tangem/data/txhistory/di/TxHistoryDataModule.kt @@ -2,9 +2,11 @@ package com.tangem.data.txhistory.di import com.tangem.data.common.cache.CacheRegistry import com.tangem.data.txhistory.repository.DefaultTxHistoryRepository +import com.tangem.data.txhistory.repository.RefactoredTxHistoryRepository import com.tangem.datasource.local.txhistory.TxHistoryItemsStore import com.tangem.datasource.local.userwallet.UserWalletsStore import com.tangem.domain.txhistory.repository.TxHistoryRepository +import com.tangem.domain.txhistory.repository.TxHistoryRepositoryV2 import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module @@ -32,4 +34,18 @@ internal object TxHistoryDataModule { txHistoryItemsStore, dispatchers, ) + + @Provides + @Singleton + fun provideTxHistoryRepositoryV2( + walletManagersFacade: WalletManagersFacade, + dispatchers: CoroutineDispatcherProvider, + txHistoryItemsStore: TxHistoryItemsStore, + cacheRegistry: CacheRegistry, + ): TxHistoryRepositoryV2 = RefactoredTxHistoryRepository( + walletManagersFacade = walletManagersFacade, + dispatchers = dispatchers, + txHistoryItemsStore = txHistoryItemsStore, + cacheRegistry = cacheRegistry, + ) } \ No newline at end of file diff --git a/data/txhistory/src/main/kotlin/com/tangem/data/txhistory/repository/RefactoredTxHistoryRepository.kt b/data/txhistory/src/main/kotlin/com/tangem/data/txhistory/repository/RefactoredTxHistoryRepository.kt new file mode 100644 index 0000000000..97c64d5f55 --- /dev/null +++ b/data/txhistory/src/main/kotlin/com/tangem/data/txhistory/repository/RefactoredTxHistoryRepository.kt @@ -0,0 +1,126 @@ +package com.tangem.data.txhistory.repository + +import com.tangem.data.common.cache.CacheRegistry +import com.tangem.data.txhistory.repository.paging.TxHistoryPageBatchFetcher +import com.tangem.datasource.local.txhistory.TxHistoryItemsStore +import com.tangem.domain.txhistory.model.TxHistoryListBatchFlow +import com.tangem.domain.txhistory.model.TxHistoryListBatchingContext +import com.tangem.domain.txhistory.model.TxHistoryListConfig +import com.tangem.domain.txhistory.models.Page +import com.tangem.domain.txhistory.models.PaginationWrapper +import com.tangem.domain.txhistory.models.TxHistoryItem +import com.tangem.domain.txhistory.repository.TxHistoryRepositoryV2 +import com.tangem.domain.walletmanager.WalletManagersFacade +import com.tangem.domain.walletmanager.utils.SdkPageConverter +import com.tangem.pagination.BatchFetchResult +import com.tangem.pagination.BatchListSource +import com.tangem.pagination.toBatchFlow +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import timber.log.Timber + +internal class RefactoredTxHistoryRepository( + private val walletManagersFacade: WalletManagersFacade, + private val txHistoryItemsStore: TxHistoryItemsStore, + private val cacheRegistry: CacheRegistry, + private val dispatchers: CoroutineDispatcherProvider, +) : TxHistoryRepositoryV2 { + + private val sdkPageConverter = SdkPageConverter() + private val TxHistoryListConfig.storeKey get() = TxHistoryItemsStore.Key(userWalletId, currency) + + override fun getTxHistoryBatchFlow(batchSize: Int, context: TxHistoryListBatchingContext): TxHistoryListBatchFlow { + return BatchListSource( + fetchDispatcher = dispatchers.io, + context = context, + generateNewKey = { keys -> keys.lastOrNull()?.inc() ?: 0 }, + batchFetcher = createFetcher(batchSize), + ).toBatchFlow() + } + + private fun createFetcher( + batchSize: Int, + ): TxHistoryPageBatchFetcher> = + TxHistoryPageBatchFetcher { request, _ -> + val wrappedItems = loadItems(request, batchSize) + BatchFetchResult.Success( + data = wrappedItems, + empty = wrappedItems.items.isEmpty(), + last = wrappedItems.nextPage is Page.LastPage, + ) + } + + private suspend fun loadItems( + request: TxHistoryPageBatchFetcher.Request, + batchSize: Int, + ): PaginationWrapper { + cacheRegistry.invokeOnExpire( + key = getTxHistoryPageKey(request.page, request.params), + skipCache = request.params.refresh, + block = { fetch(request, batchSize) }, + ) + + return txHistoryItemsStore.getSync(request.page, request.params) + } + + private suspend fun fetch(request: TxHistoryPageBatchFetcher.Request, batchSize: Int) { + val wrappedItems = walletManagersFacade.getTxHistoryItems( + userWalletId = request.params.userWalletId, + currency = request.params.currency, + page = sdkPageConverter.convertBack(request.page), + pageSize = batchSize, + ) + + txHistoryItemsStore.store(key = request.params.storeKey, value = wrappedItems) + } + + private suspend fun TxHistoryItemsStore.getSync( + pageToLoad: Page, + config: TxHistoryListConfig, + ): PaginationWrapper { + val storedItems = requireNotNull(getSyncOrNull(config.storeKey, pageToLoad)) { + "The transaction history page #$pageToLoad could not be retrieved" + } + + return if (pageToLoad is Page.Initial) storedItems.addRecentTransactions(config) else storedItems + } + + private suspend fun PaginationWrapper.addRecentTransactions( + config: TxHistoryListConfig, + ): PaginationWrapper { + val recentItems = walletManagersFacade.getRecentTransactions( + userWalletId = config.userWalletId, + currency = config.currency, + ) + .filterUnconfirmedTransaction() + .sortedByDescending { it.timestampInMillis } + .filterIfTxAlreadyAdded(apiItems = items) + + return if (recentItems.isEmpty()) { + Timber.d("Nothing to add to TxHistory") + this + } else { + Timber.d( + "Recent transactions were added to TxHistory: %s", + recentItems.joinToString( + prefix = "[", + postfix = "]", + transform = TxHistoryItem::txHash, + ), + ) + + return copy(items = recentItems + items) + } + } + + private fun List.filterUnconfirmedTransaction(): List { + return filter { it.status == TxHistoryItem.TransactionStatus.Unconfirmed } + } + + private fun List.filterIfTxAlreadyAdded(apiItems: List): List { + return filter { item -> apiItems.none { it.txHash == item.txHash } } + } + + private fun getTxHistoryPageKey(page: Page, config: TxHistoryListConfig): String { + return "tx_history_page_${config.currency}_${config.userWalletId}_$page" + } +} \ No newline at end of file diff --git a/data/txhistory/src/main/kotlin/com/tangem/data/txhistory/repository/paging/TxHistoryPageBatchFetcher.kt b/data/txhistory/src/main/kotlin/com/tangem/data/txhistory/repository/paging/TxHistoryPageBatchFetcher.kt new file mode 100644 index 0000000000..429f0a6f30 --- /dev/null +++ b/data/txhistory/src/main/kotlin/com/tangem/data/txhistory/repository/paging/TxHistoryPageBatchFetcher.kt @@ -0,0 +1,73 @@ +package com.tangem.data.txhistory.repository.paging + +import com.tangem.domain.txhistory.models.Page +import com.tangem.domain.txhistory.models.PaginationWrapper +import com.tangem.domain.txhistory.models.TxHistoryItem +import com.tangem.pagination.BatchFetchResult +import com.tangem.pagination.exception.EndOfPaginationException +import com.tangem.pagination.fetcher.BatchFetcher +import kotlinx.coroutines.currentCoroutineContext +import kotlinx.coroutines.ensureActive +import kotlinx.coroutines.flow.MutableStateFlow + +internal class TxHistoryPageBatchFetcher>( + private val subFetcher: SubFetcher, +) : BatchFetcher { + data class Request(val page: Page, val params: TRequestParams) + fun interface SubFetcher { + suspend fun fetch( + request: Request, + lastResult: BatchFetchResult?, + ): BatchFetchResult + } + + private val lastRequest = MutableStateFlow?>(null) + + override suspend fun fetchFirst(requestParams: TRequestParams): BatchFetchResult { + val req = Request( + page = Page.Initial, + params = requestParams, + ) + + val res = runCatching { + subFetcher.fetch(request = req, lastResult = null) + }.getOrElse { + currentCoroutineContext().ensureActive() + BatchFetchResult.Error(it) + } + + lastRequest.value = req + return res + } + + override suspend fun fetchNext( + overrideRequestParams: TRequestParams?, + lastResult: BatchFetchResult, + ): BatchFetchResult { + val last = lastRequest.value + requireNotNull(last) + + val req = if (lastResult is BatchFetchResult.Success) { + if (lastResult.last && overrideRequestParams == null) { + return BatchFetchResult.Error(EndOfPaginationException()) + } + + Request( + page = lastResult.data.nextPage, + params = overrideRequestParams ?: last.params, + ) + } else { + last + } + + val res = runCatching { + subFetcher.fetch(request = req, lastResult = lastResult) + }.getOrElse { + currentCoroutineContext().ensureActive() + BatchFetchResult.Error(it) + } + + lastRequest.value = req + return res + } +} \ No newline at end of file diff --git a/domain/txhistory/build.gradle.kts b/domain/txhistory/build.gradle.kts index 892e55e639..269f30a989 100644 --- a/domain/txhistory/build.gradle.kts +++ b/domain/txhistory/build.gradle.kts @@ -20,4 +20,6 @@ dependencies { /** Android - Other */ implementation(deps.androidx.paging.runtime) + + api(projects.core.pagination) } \ No newline at end of file diff --git a/domain/txhistory/models/src/main/kotlin/com/tangem/domain/txhistory/models/Page.kt b/domain/txhistory/models/src/main/kotlin/com/tangem/domain/txhistory/models/Page.kt index 9e18e15403..4633490788 100644 --- a/domain/txhistory/models/src/main/kotlin/com/tangem/domain/txhistory/models/Page.kt +++ b/domain/txhistory/models/src/main/kotlin/com/tangem/domain/txhistory/models/Page.kt @@ -1,7 +1,7 @@ package com.tangem.domain.txhistory.models sealed class Page { - object Initial : Page() + data object Initial : Page() data class Next(val value: String) : Page() - object LastPage : Page() + data object LastPage : Page() } \ No newline at end of file diff --git a/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/model/TxHistoryListConfig.kt b/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/model/TxHistoryListConfig.kt new file mode 100644 index 0000000000..303b464ff3 --- /dev/null +++ b/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/model/TxHistoryListConfig.kt @@ -0,0 +1,6 @@ +package com.tangem.domain.txhistory.model + +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWalletId + +data class TxHistoryListConfig(val userWalletId: UserWalletId, val currency: CryptoCurrency, val refresh: Boolean) \ No newline at end of file diff --git a/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/model/TxHistoryTypealiases.kt b/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/model/TxHistoryTypealiases.kt new file mode 100644 index 0000000000..334b31fc10 --- /dev/null +++ b/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/model/TxHistoryTypealiases.kt @@ -0,0 +1,10 @@ +package com.tangem.domain.txhistory.model + +import com.tangem.domain.txhistory.models.PaginationWrapper +import com.tangem.domain.txhistory.models.TxHistoryItem +import com.tangem.pagination.BatchFlow +import com.tangem.pagination.BatchingContext + +typealias TxHistoryListBatchingContext = BatchingContext + +typealias TxHistoryListBatchFlow = BatchFlow, Nothing> \ No newline at end of file diff --git a/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/repository/TxHistoryRepositoryV2.kt b/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/repository/TxHistoryRepositoryV2.kt new file mode 100644 index 0000000000..ae9ea875ea --- /dev/null +++ b/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/repository/TxHistoryRepositoryV2.kt @@ -0,0 +1,9 @@ +package com.tangem.domain.txhistory.repository + +import com.tangem.domain.txhistory.model.TxHistoryListBatchFlow +import com.tangem.domain.txhistory.model.TxHistoryListBatchingContext + +interface TxHistoryRepositoryV2 { + + fun getTxHistoryBatchFlow(batchSize: Int, context: TxHistoryListBatchingContext): TxHistoryListBatchFlow +} \ No newline at end of file diff --git a/features/send/impl/build.gradle.kts b/features/send/impl/build.gradle.kts index 7df0d26ab3..8883699dbb 100644 --- a/features/send/impl/build.gradle.kts +++ b/features/send/impl/build.gradle.kts @@ -84,6 +84,7 @@ dependencies { /** Feature modules */ implementation(projects.features.send.api) implementation(projects.features.tokendetails.api) + implementation(projects.features.txhistory.api) implementation(projects.features.qrScanning.api) /** DI */ diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendModel.kt index 91af0581fc..55e0edc294 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendModel.kt @@ -60,6 +60,8 @@ import com.tangem.features.send.impl.presentation.state.amount.AmountStateFactor import com.tangem.features.send.impl.presentation.state.confirm.SendNotificationFactory import com.tangem.features.send.impl.presentation.state.fee.* import com.tangem.features.send.impl.presentation.state.recipient.RecipientSendFactory +import com.tangem.features.txhistory.TxHistoryFeatureToggles +import com.tangem.features.txhistory.entity.TxHistoryContentUpdateEmitter import com.tangem.lib.crypto.BlockchainUtils import com.tangem.utils.Provider import com.tangem.utils.coroutines.* @@ -110,6 +112,8 @@ internal class SendModel @Inject constructor( private val getCardInfoUseCase: GetCardInfoUseCase, private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, private val shareManager: ShareManager, + private val txHistoryFeatureToggles: TxHistoryFeatureToggles, + private val txHistoryContentUpdateEmitter: TxHistoryContentUpdateEmitter, @DelayedWork private val coroutineScope: CoroutineScope, private val innerRouter: InnerSendRouter, private val appRouter: AppRouter, @@ -1012,11 +1016,15 @@ internal class SendModel @Inject constructor( ) txHistoryItemsCountEither.onRight { - getTxHistoryItemsUseCase( - userWalletId = userWalletId, - currency = cryptoCurrency, - refresh = true, - ) + if (txHistoryFeatureToggles.isFeatureEnabled) { + txHistoryContentUpdateEmitter.triggerUpdate() + } else { + getTxHistoryItemsUseCase( + userWalletId = userWalletId, + currency = cryptoCurrency, + refresh = true, + ) + } } } diff --git a/features/staking/impl/build.gradle.kts b/features/staking/impl/build.gradle.kts index bbfa41e6e2..6ffb00cc29 100644 --- a/features/staking/impl/build.gradle.kts +++ b/features/staking/impl/build.gradle.kts @@ -75,6 +75,7 @@ dependencies { /** Feature modules */ implementation(projects.features.staking.api) + implementation(projects.features.txhistory.api) /** DI */ implementation(deps.hilt.android) diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingBalanceUpdater.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingBalanceUpdater.kt index db7d970087..6c26ecf208 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingBalanceUpdater.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingBalanceUpdater.kt @@ -10,6 +10,8 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase import com.tangem.domain.wallets.models.UserWallet +import com.tangem.features.txhistory.TxHistoryFeatureToggles +import com.tangem.features.txhistory.entity.TxHistoryContentUpdateEmitter import com.tangem.utils.coroutines.DelayedWork import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -24,6 +26,8 @@ internal class StakingBalanceUpdater @AssistedInject constructor( private val getTxHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase, private val getTxHistoryItemsUseCase: GetTxHistoryItemsUseCase, private val fetchActionsUseCase: FetchActionsUseCase, + private val txHistoryFeatureToggles: TxHistoryFeatureToggles, + private val txHistoryContentUpdateEmitter: TxHistoryContentUpdateEmitter, @DelayedWork private val coroutineScope: CoroutineScope, @Assisted private val userWallet: UserWallet, @Assisted private val cryptoCurrencyStatus: CryptoCurrencyStatus, @@ -97,11 +101,15 @@ internal class StakingBalanceUpdater @AssistedInject constructor( ) txHistoryItemsCountEither.onRight { - getTxHistoryItemsUseCase( - userWalletId = userWallet.walletId, - currency = cryptoCurrencyStatus.currency, - refresh = true, - ) + if (txHistoryFeatureToggles.isFeatureEnabled) { + txHistoryContentUpdateEmitter.triggerUpdate() + } else { + getTxHistoryItemsUseCase( + userWalletId = userWallet.walletId, + currency = cryptoCurrencyStatus.currency, + refresh = true, + ) + } } } diff --git a/features/tokendetails/impl/build.gradle.kts b/features/tokendetails/impl/build.gradle.kts index 1457affebd..e725d7833a 100644 --- a/features/tokendetails/impl/build.gradle.kts +++ b/features/tokendetails/impl/build.gradle.kts @@ -99,5 +99,6 @@ dependencies { implementation(projects.features.markets.api) implementation(projects.features.onramp.api) implementation(projects.features.swap.api) + implementation(projects.features.txhistory.api) } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/DefaultTokenDetailsComponent.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/DefaultTokenDetailsComponent.kt index 5d4274694f..b89234b7b6 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/DefaultTokenDetailsComponent.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/DefaultTokenDetailsComponent.kt @@ -17,6 +17,8 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDeta import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreen import com.tangem.features.markets.token.block.TokenMarketBlockComponent import com.tangem.features.tokendetails.TokenDetailsComponent +import com.tangem.features.txhistory.TxHistoryFeatureToggles +import com.tangem.features.txhistory.component.TxHistoryComponent import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -25,10 +27,20 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor( @Assisted appComponentContext: AppComponentContext, @Assisted params: TokenDetailsComponent.Params, tokenMarketBlockComponentFactory: TokenMarketBlockComponent.Factory, + txHistoryComponentFactory: TxHistoryComponent.Factory, + txHistoryFeatureToggles: TxHistoryFeatureToggles, deepLinksRegistry: DeepLinksRegistry, ) : TokenDetailsComponent, AppComponentContext by appComponentContext { private val model: TokenDetailsModel = getOrCreateModel(params) + private val txHistoryComponent = txHistoryComponentFactory.create( + context = child("txHistoryComponent"), + params = TxHistoryComponent.Params( + userWalletId = params.userWalletId, + currency = params.currency, + openExplorer = { model.onExploreClick() }, + ), + ).takeIf { txHistoryFeatureToggles.isFeatureEnabled } init { lifecycle.subscribe( @@ -54,11 +66,11 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor( @Composable override fun Content(modifier: Modifier) { val state by model.uiState.collectAsStateWithLifecycle() - NavigationBar3ButtonsScrim() TokenDetailsScreen( state = state, tokenMarketBlockComponent = tokenMarketBlockComponent, + txHistoryComponent = txHistoryComponent, ) } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt index 545c8d7f8e..c166236643 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt @@ -10,8 +10,8 @@ import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.GlobalUiMessageSender +import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.ui.UiMessageSender @@ -76,6 +76,8 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.e import com.tangem.features.onramp.OnrampFeatureToggles import com.tangem.features.tokendetails.TokenDetailsComponent import com.tangem.features.tokendetails.impl.R +import com.tangem.features.txhistory.TxHistoryFeatureToggles +import com.tangem.features.txhistory.entity.TxHistoryContentUpdateEmitter import com.tangem.utils.Provider import com.tangem.utils.coroutines.* import kotlinx.collections.immutable.PersistentList @@ -122,6 +124,8 @@ internal class TokenDetailsModel @Inject constructor( private val onrampFeatureToggles: OnrampFeatureToggles, private val shareManager: ShareManager, @GlobalUiMessageSender private val uiMessageSender: UiMessageSender, + private val txHistoryFeatureToggles: TxHistoryFeatureToggles, + private val txHistoryContentUpdateEmitter: TxHistoryContentUpdateEmitter, paramsContainer: ParamsContainer, expressStatusFactory: ExpressStatusFactory.Factory, getUserWalletUseCase: GetUserWalletUseCase, @@ -240,7 +244,7 @@ internal class TokenDetailsModel @Inject constructor( private fun updateContent() { subscribeOnCurrencyStatusUpdates() subscribeOnExpressTransactionsUpdates() - updateTxHistory(refresh = false, showItemsLoading = true) + updateTxHistory(refresh = false, showItemsLoading = true, initialUpdating = true) updateStakingInfo() } @@ -362,29 +366,33 @@ internal class TokenDetailsModel @Inject constructor( * @param refresh - invalidate cache and get data from remote * @param showItemsLoading - show loading items placeholder. */ - private fun updateTxHistory(refresh: Boolean, showItemsLoading: Boolean) { - modelScope.launch(dispatchers.main) { - val txHistoryItemsCountEither = txHistoryItemsCountUseCase( - userWalletId = userWalletId, - currency = cryptoCurrency, - ) - - // if countEither is left, handling error state run inside getLoadingTxHistoryState - if (showItemsLoading || txHistoryItemsCountEither.isLeft()) { - internalUiState.value = stateFactory.getLoadingTxHistoryState( - itemsCountEither = txHistoryItemsCountEither, - pendingTransactions = internalUiState.value.pendingTxs, - ) - } - - txHistoryItemsCountEither.onRight { - val maybeTxHistory = txHistoryItemsUseCase( + private fun updateTxHistory(refresh: Boolean, showItemsLoading: Boolean, initialUpdating: Boolean = false) { + if (txHistoryFeatureToggles.isFeatureEnabled && !initialUpdating) { + modelScope.launch { txHistoryContentUpdateEmitter.triggerUpdate() } + } else { + modelScope.launch(dispatchers.main) { + val txHistoryItemsCountEither = txHistoryItemsCountUseCase( userWalletId = userWalletId, currency = cryptoCurrency, - refresh = refresh, - ).map { it.cachedIn(modelScope) } + ) - internalUiState.value = stateFactory.getLoadedTxHistoryState(maybeTxHistory) + // if countEither is left, handling error state run inside getLoadingTxHistoryState + if (showItemsLoading || txHistoryItemsCountEither.isLeft()) { + internalUiState.value = stateFactory.getLoadingTxHistoryState( + itemsCountEither = txHistoryItemsCountEither, + pendingTransactions = internalUiState.value.pendingTxs, + ) + } + + txHistoryItemsCountEither.onRight { + val maybeTxHistory = txHistoryItemsUseCase( + userWalletId = userWalletId, + currency = cryptoCurrency, + refresh = refresh, + ).map { it.cachedIn(modelScope) } + + internalUiState.value = stateFactory.getLoadedTxHistoryState(maybeTxHistory) + } } } } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt index 29775149aa..f315753e17 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt @@ -3,16 +3,18 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.ui import android.content.res.Configuration import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.* import androidx.compose.material3.Scaffold import androidx.compose.material3.ScaffoldDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.State import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig import com.tangem.common.ui.expressStatus.expressTransactionsItems @@ -39,11 +41,18 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.T import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressStatusBottomSheet import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.staking.TokenStakingBlock import com.tangem.features.markets.token.block.TokenMarketBlockComponent +import com.tangem.features.txhistory.component.TxHistoryComponent +import com.tangem.features.txhistory.entity.TxHistoryUM +import kotlin.reflect.KProperty // TODO: Split to blocks [REDACTED_JIRA] @Suppress("LongMethod") @Composable -internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockComponent: TokenMarketBlockComponent?) { +internal fun TokenDetailsScreen( + state: TokenDetailsState, + tokenMarketBlockComponent: TokenMarketBlockComponent?, + txHistoryComponent: TxHistoryComponent?, +) { BackHandler(onBack = state.topAppBarConfig.onBackClick) val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() } @@ -57,6 +66,8 @@ internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockCompon } else { null } + val listState = rememberLazyListState() + val txHistoryComponentState by txHistoryComponent?.txHistoryState?.collectAsStateWithLifecycle() val betweenItemsPadding = TangemTheme.dimens.spacing12 val horizontalPadding = TangemTheme.dimens.spacing16 val itemModifier = Modifier @@ -69,6 +80,7 @@ internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockCompon ) { LazyColumn( modifier = Modifier.fillMaxSize(), + state = listState, contentPadding = PaddingValues( bottom = TangemTheme.dimens.spacing16 + bottomBarHeight, ), @@ -145,9 +157,12 @@ internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockCompon ) txHistoryItems( - state = state.txHistoryState, - isBalanceHidden = state.isBalanceHidden, + listState = listState, + txHistoryComponent = txHistoryComponent, + txHistoryComponentState = txHistoryComponentState, + txHistoryState = state.txHistoryState, txHistoryItems = txHistoryItems, + isBalanceHidden = state.isBalanceHidden, ) } } @@ -170,6 +185,28 @@ internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockCompon } } +@Suppress("LongParameterList") +private fun LazyListScope.txHistoryItems( + listState: LazyListState, + txHistoryComponent: TxHistoryComponent?, + txHistoryComponentState: TxHistoryUM?, + txHistoryState: TxHistoryState, + txHistoryItems: LazyPagingItems?, + isBalanceHidden: Boolean, +) { + if (txHistoryComponent != null && txHistoryComponentState != null) { + with(txHistoryComponent) { txHistoryContent(listState = listState, state = txHistoryComponentState) } + } else { + txHistoryItems( + state = txHistoryState, + isBalanceHidden = isBalanceHidden, + txHistoryItems = txHistoryItems, + ) + } +} + +private inline operator fun State?.getValue(thisObj: Any?, property: KProperty<*>): T? = this?.value + // region Preview @Preview(showBackground = true, widthDp = 360) @Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) @@ -181,6 +218,7 @@ private fun TokenDetailsScreenPreview( TokenDetailsScreen( state = state, tokenMarketBlockComponent = null, + txHistoryComponent = null, ) } } diff --git a/features/txhistory/api/.gitignore b/features/txhistory/api/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/features/txhistory/api/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/features/txhistory/api/build.gradle.kts b/features/txhistory/api/build.gradle.kts new file mode 100644 index 0000000000..7b0b2e9ff0 --- /dev/null +++ b/features/txhistory/api/build.gradle.kts @@ -0,0 +1,26 @@ +plugins { + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) + id("configuration") +} + +android { + namespace = "com.tangem.features.txhistory.api" +} + +dependencies { + /** Project - Core */ + implementation(projects.core.ui) + implementation(projects.core.decompose) + + /** Domain models */ + implementation(projects.domain.tokens.models) + implementation(projects.domain.wallets.models) + + /** Compose */ + implementation(deps.compose.runtime) + implementation(deps.compose.foundation) + + /** Other */ + implementation(deps.kotlin.immutable.collections) +} \ No newline at end of file diff --git a/features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/TxHistoryFeatureToggles.kt b/features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/TxHistoryFeatureToggles.kt new file mode 100644 index 0000000000..a0cb28761f --- /dev/null +++ b/features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/TxHistoryFeatureToggles.kt @@ -0,0 +1,5 @@ +package com.tangem.features.txhistory + +interface TxHistoryFeatureToggles { + val isFeatureEnabled: Boolean +} \ No newline at end of file diff --git a/features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/component/TxHistoryComponent.kt b/features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/component/TxHistoryComponent.kt new file mode 100644 index 0000000000..8fa11c9c93 --- /dev/null +++ b/features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/component/TxHistoryComponent.kt @@ -0,0 +1,28 @@ +package com.tangem.features.txhistory.component + +import androidx.compose.runtime.Stable +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.foundation.lazy.LazyListState +import com.tangem.core.decompose.factory.ComponentFactory +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.features.txhistory.entity.TxHistoryUM +import kotlinx.coroutines.flow.StateFlow + +@Stable +interface TxHistoryComponent { + + val txHistoryState: StateFlow + + fun LazyListScope.txHistoryContent(listState: LazyListState, state: TxHistoryUM) + + fun reload() + + data class Params( + val userWalletId: UserWalletId, + val currency: CryptoCurrency, + val openExplorer: () -> Unit, + ) + + interface Factory : ComponentFactory +} \ No newline at end of file diff --git a/features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/entity/TxHistoryContentUpdateEmitter.kt b/features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/entity/TxHistoryContentUpdateEmitter.kt new file mode 100644 index 0000000000..8f8f68a500 --- /dev/null +++ b/features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/entity/TxHistoryContentUpdateEmitter.kt @@ -0,0 +1,5 @@ +package com.tangem.features.txhistory.entity + +interface TxHistoryContentUpdateEmitter { + suspend fun triggerUpdate() +} \ No newline at end of file diff --git a/features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/entity/TxHistoryUM.kt b/features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/entity/TxHistoryUM.kt new file mode 100644 index 0000000000..9a9960fc8e --- /dev/null +++ b/features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/entity/TxHistoryUM.kt @@ -0,0 +1,93 @@ +package com.tangem.features.txhistory.entity + +import com.tangem.core.ui.components.transactions.state.TransactionState +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf + +sealed interface TxHistoryUM { + + val isBalanceHidden: Boolean + + data class Loading(override val isBalanceHidden: Boolean, private val onExploreClick: () -> Unit) : TxHistoryUM { + val items = persistentListOf( + TxHistoryItemUM.Title(onExploreClick = onExploreClick), + TxHistoryItemUM.Transaction(TransactionState.Loading("LOADING_TX_HASH_1")), + TxHistoryItemUM.Transaction(TransactionState.Loading("LOADING_TX_HASH_2")), + TxHistoryItemUM.Transaction(TransactionState.Loading("LOADING_TX_HASH_3")), + ) + } + + /** + * Wallet transaction history state with content + */ + data class Content( + override val isBalanceHidden: Boolean, + val items: ImmutableList, + val loadMore: () -> Boolean, + ) : TxHistoryUM + + /** Empty state */ + data class Empty(override val isBalanceHidden: Boolean, val onExploreClick: () -> Unit) : TxHistoryUM + + /** + * Not supported tx history state + * + * @property pendingTransactions pending transactions + * @property onExploreClick lambda be invoke when explore button was clicked + */ + data class NotSupported( + override val isBalanceHidden: Boolean, + val pendingTransactions: ImmutableList, + val onExploreClick: () -> Unit, + ) : TxHistoryUM + + /** + * Error state + * + * @property onReloadClick lambda be invoke when reload button was clicked + */ + data class Error( + override val isBalanceHidden: Boolean, + val onReloadClick: () -> Unit, + val onExploreClick: () -> Unit, + ) : TxHistoryUM + + fun copySealed(isBalanceHidden: Boolean): TxHistoryUM { + return when (this) { + is Content -> copy(isBalanceHidden = isBalanceHidden) + is NotSupported -> copy(isBalanceHidden = isBalanceHidden) + is Empty -> copy(isBalanceHidden = isBalanceHidden) + is Error -> copy(isBalanceHidden = isBalanceHidden) + is Loading -> copy(isBalanceHidden = isBalanceHidden) + } + } + + /** Transactions history item state */ + sealed interface TxHistoryItemUM { + + /** + * Title item + * + * @property onExploreClick lambda be invoke when explore button was clicked + */ + data class Title(val onExploreClick: () -> Unit) : TxHistoryItemUM + + /** + * Group title item + * + * @property title title + * @property itemKey key to use in compose + */ + data class GroupTitle( + val title: String, + val itemKey: String, + ) : TxHistoryItemUM + + /** + * Transaction item + * + * @property state transaction state + */ + data class Transaction(val state: TransactionState) : TxHistoryItemUM + } +} \ No newline at end of file diff --git a/features/txhistory/impl/.gitignore b/features/txhistory/impl/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/features/txhistory/impl/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/features/txhistory/impl/build.gradle.kts b/features/txhistory/impl/build.gradle.kts new file mode 100644 index 0000000000..b0cc54f7ef --- /dev/null +++ b/features/txhistory/impl/build.gradle.kts @@ -0,0 +1,59 @@ +plugins { + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) + alias(deps.plugins.kotlin.serialization) + alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.hilt.android) + id("configuration") +} + +android { + namespace = "com.tangem.features.txhistory.impl" +} + +dependencies { + /* Project - API */ + implementation(projects.features.txhistory.api) + + /* Project - Core */ + implementation(projects.core.decompose) + implementation(projects.core.ui) + implementation(projects.common.routing) + implementation(projects.core.configToggles) + implementation(projects.core.analytics) + implementation(projects.core.pagination) + implementation(projects.core.navigation) + + /* Project - Domain */ + implementation(projects.domain.models) + implementation(projects.domain.legacy) + implementation(projects.domain.txhistory) + implementation(projects.domain.txhistory.models) + implementation(projects.domain.wallets) + implementation(projects.domain.wallets.models) + implementation(projects.domain.tokens) + implementation(projects.domain.tokens.models) + implementation(projects.domain.balanceHiding) + implementation(projects.domain.balanceHiding.models) + + /* AndroidX */ + implementation(deps.androidx.activity.compose) + implementation(deps.lifecycle.compose) + + /* Compose */ + implementation(deps.compose.ui) + implementation(deps.compose.ui.tooling) + implementation(deps.compose.foundation) + implementation(deps.compose.material3) + implementation(deps.compose.shimmer) + + /* DI */ + implementation(deps.hilt.android) + kapt(deps.hilt.kapt) + + /* Other */ + implementation(deps.arrow.core) + implementation(deps.kotlin.immutable.collections) + implementation(deps.decompose.ext.compose) + implementation(deps.timber) +} \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/DefaultTxHistoryFeatureToggles.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/DefaultTxHistoryFeatureToggles.kt new file mode 100644 index 0000000000..862db63ebb --- /dev/null +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/DefaultTxHistoryFeatureToggles.kt @@ -0,0 +1,11 @@ +package com.tangem.features.txhistory + +import com.tangem.core.configtoggle.feature.FeatureTogglesManager +import javax.inject.Inject + +internal class DefaultTxHistoryFeatureToggles @Inject constructor( + private val featureTogglesManager: FeatureTogglesManager, +) : TxHistoryFeatureToggles { + override val isFeatureEnabled: Boolean + get() = featureTogglesManager.isFeatureEnabled("TX_HISTORY_REFACTORING_ENABLED") +} \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/component/DefaultTxHistoryComponent.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/component/DefaultTxHistoryComponent.kt new file mode 100644 index 0000000000..e3e25ebc5e --- /dev/null +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/component/DefaultTxHistoryComponent.kt @@ -0,0 +1,38 @@ +package com.tangem.features.txhistory.component + +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.runtime.* +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.decompose.model.getOrCreateModel +import com.tangem.features.txhistory.entity.TxHistoryUM +import com.tangem.features.txhistory.model.TxHistoryModel +import com.tangem.features.txhistory.ui.txHistoryItems +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.flow.StateFlow + +internal class DefaultTxHistoryComponent @AssistedInject constructor( + @Assisted appComponentContext: AppComponentContext, + @Assisted params: TxHistoryComponent.Params, +) : TxHistoryComponent, AppComponentContext by appComponentContext { + + private val model: TxHistoryModel = getOrCreateModel(params) + + override val txHistoryState: StateFlow + get() = model.uiState + + override fun LazyListScope.txHistoryContent(listState: LazyListState, state: TxHistoryUM) { + txHistoryItems(listState, state) + } + + override fun reload() { + model.reload() + } + + @AssistedFactory + interface Factory : TxHistoryComponent.Factory { + override fun create(context: AppComponentContext, params: TxHistoryComponent.Params): DefaultTxHistoryComponent + } +} \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt new file mode 100644 index 0000000000..7db10fcb7b --- /dev/null +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt @@ -0,0 +1,129 @@ +package com.tangem.features.txhistory.converter + +import com.tangem.core.ui.components.transactions.state.TransactionState +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.extensions.wrappedList +import com.tangem.core.ui.format.bigdecimal.crypto +import com.tangem.core.ui.format.bigdecimal.format +import com.tangem.core.ui.utils.toTimeFormat +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.txhistory.models.TxHistoryItem +import com.tangem.features.txhistory.impl.R +import com.tangem.features.txhistory.utils.TxHistoryUiActions +import com.tangem.utils.StringsSigns +import com.tangem.utils.converter.Converter +import com.tangem.utils.extensions.isZero +import com.tangem.utils.toBriefAddressFormat + +internal class TxHistoryItemToTransactionStateConverter( + private val currency: CryptoCurrency, + private val txHistoryUiActions: TxHistoryUiActions, +) : Converter { + override fun convert(value: TxHistoryItem): TransactionState { + return TransactionState.Content( + txHash = value.txHash, + amount = value.getAmount(), + time = value.timestampInMillis.toTimeFormat(), + status = value.status.tiUiStatus(), + direction = value.extractDirection(), + iconRes = value.extractIcon(), + title = value.extractTitle(), + subtitle = value.extractSubtitle(), + timestamp = value.timestampInMillis, + onClick = { txHistoryUiActions.openTxInExplorer(value.txHash) }, + ) + } + + private fun TxHistoryItem.extractIcon(): Int = if (status == TxHistoryItem.TransactionStatus.Failed) { + R.drawable.ic_close_24 + } else { + when (type) { + is TxHistoryItem.TransactionType.Approve -> R.drawable.ic_doc_24 + is TxHistoryItem.TransactionType.Staking.Stake, + is TxHistoryItem.TransactionType.Staking.Vote, + is TxHistoryItem.TransactionType.Staking.Restake, + -> R.drawable.ic_transaction_history_staking_24 + is TxHistoryItem.TransactionType.Staking.ClaimRewards, + -> R.drawable.ic_transaction_history_claim_rewards_24 + is TxHistoryItem.TransactionType.Staking.Unstake, + is TxHistoryItem.TransactionType.Staking.Withdraw, + -> R.drawable.ic_transaction_history_unstaking_24 + is TxHistoryItem.TransactionType.Operation, + is TxHistoryItem.TransactionType.Swap, + is TxHistoryItem.TransactionType.Transfer, + is TxHistoryItem.TransactionType.UnknownOperation, + -> if (isOutgoing) R.drawable.ic_arrow_up_24 else R.drawable.ic_arrow_down_24 + } + } + + private fun TxHistoryItem.extractTitle(): TextReference = when (val type = type) { + is TxHistoryItem.TransactionType.Approve -> resourceReference(R.string.common_approval) + is TxHistoryItem.TransactionType.Operation -> stringReference(type.name) + is TxHistoryItem.TransactionType.Swap -> resourceReference(R.string.common_swap) + is TxHistoryItem.TransactionType.Transfer -> resourceReference(R.string.common_transfer) + is TxHistoryItem.TransactionType.Staking.Stake -> resourceReference(R.string.common_stake) + is TxHistoryItem.TransactionType.Staking.Unstake -> resourceReference(R.string.common_unstake) + is TxHistoryItem.TransactionType.Staking.Vote -> resourceReference(R.string.staking_vote) + is TxHistoryItem.TransactionType.Staking.ClaimRewards -> resourceReference(R.string.common_claim_rewards) + is TxHistoryItem.TransactionType.Staking.Withdraw -> resourceReference(R.string.staking_withdraw) + is TxHistoryItem.TransactionType.Staking.Restake -> resourceReference(R.string.staking_restake) + is TxHistoryItem.TransactionType.UnknownOperation -> resourceReference(R.string.transaction_history_operation) + } + + private fun TxHistoryItem.extractSubtitle(): TextReference = + when (val interactionAddress = interactionAddressType) { + is TxHistoryItem.InteractionAddressType.Contract -> resourceReference( + id = R.string.transaction_history_contract_address, + formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), + ) + is TxHistoryItem.InteractionAddressType.Multiple -> resourceReference( + id = if (isOutgoing) { + R.string.transaction_history_transaction_to_address + } else { + R.string.transaction_history_transaction_from_address + }, + formatArgs = wrappedList(resourceReference(R.string.transaction_history_multiple_addresses)), + ) + is TxHistoryItem.InteractionAddressType.User -> resourceReference( + id = if (isOutgoing) { + R.string.transaction_history_transaction_to_address + } else { + R.string.transaction_history_transaction_from_address + }, + formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), + ) + is TxHistoryItem.InteractionAddressType.Validator -> resourceReference( + id = R.string.transaction_history_transaction_validator, + formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), + ) + null -> { + TextReference.EMPTY + } + } + + private fun TxHistoryItem.extractDirection() = + if (isOutgoing) TransactionState.Content.Direction.OUTGOING else TransactionState.Content.Direction.INCOMING + + private fun TxHistoryItem.getAmount(): String { + if (type is TxHistoryItem.TransactionType.Staking.Vote || + type == TxHistoryItem.TransactionType.Staking.ClaimRewards || + type == TxHistoryItem.TransactionType.Staking.Withdraw + ) { + return "" + } + val prefix = when { + status == TxHistoryItem.TransactionStatus.Failed -> "" + this.amount.isZero() -> "" + else -> if (isOutgoing) StringsSigns.MINUS else StringsSigns.PLUS + } + return prefix + amount.format { crypto(symbol = currency.symbol, decimals = currency.decimals) } + } + + private fun TxHistoryItem.TransactionStatus.tiUiStatus() = when (this) { + TxHistoryItem.TransactionStatus.Confirmed -> TransactionState.Content.Status.Confirmed + TxHistoryItem.TransactionStatus.Failed -> TransactionState.Content.Status.Failed + TxHistoryItem.TransactionStatus.Unconfirmed -> TransactionState.Content.Status.Unconfirmed + } +} \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/di/TxHistoryFeatureModule.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/di/TxHistoryFeatureModule.kt new file mode 100644 index 0000000000..7ea832e433 --- /dev/null +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/di/TxHistoryFeatureModule.kt @@ -0,0 +1,23 @@ +package com.tangem.features.txhistory.di + +import com.tangem.features.txhistory.DefaultTxHistoryFeatureToggles +import com.tangem.features.txhistory.TxHistoryFeatureToggles +import com.tangem.features.txhistory.component.DefaultTxHistoryComponent +import com.tangem.features.txhistory.component.TxHistoryComponent +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal interface TxHistoryFeatureModule { + @Binds + @Singleton + fun provideFeatureToggles(featureToggles: DefaultTxHistoryFeatureToggles): TxHistoryFeatureToggles + + @Binds + @Singleton + fun bindComponentFactory(factory: DefaultTxHistoryComponent.Factory): TxHistoryComponent.Factory +} \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/di/TxHistoryModelModule.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/di/TxHistoryModelModule.kt new file mode 100644 index 0000000000..a968473a55 --- /dev/null +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/di/TxHistoryModelModule.kt @@ -0,0 +1,19 @@ +package com.tangem.features.txhistory.di + +import com.tangem.core.decompose.di.ModelComponent +import com.tangem.core.decompose.model.Model +import com.tangem.features.txhistory.model.TxHistoryModel +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap + +@Module +@InstallIn(ModelComponent::class) +internal interface TxHistoryModelModule { + @Binds + @IntoMap + @ClassKey(TxHistoryModel::class) + fun bindModel(model: TxHistoryModel): Model +} \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/di/TxHistoryUpdaterModule.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/di/TxHistoryUpdaterModule.kt new file mode 100644 index 0000000000..e5b1f73531 --- /dev/null +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/di/TxHistoryUpdaterModule.kt @@ -0,0 +1,23 @@ +package com.tangem.features.txhistory.di + +import com.tangem.features.txhistory.entity.DefaultTxHistoryUpdater +import com.tangem.features.txhistory.entity.TxHistoryContentUpdateEmitter +import com.tangem.features.txhistory.entity.TxHistoryUpdateListener +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal object TxHistoryUpdaterModule { + + @Provides + @Singleton + fun provideTxHistoryContentContentUpdateEmitter(impl: DefaultTxHistoryUpdater): TxHistoryContentUpdateEmitter = impl + + @Provides + @Singleton + fun provideTxHistoryUpdaterListener(impl: DefaultTxHistoryUpdater): TxHistoryUpdateListener = impl +} \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/entity/DefaultTxHistoryUpdater.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/entity/DefaultTxHistoryUpdater.kt new file mode 100644 index 0000000000..fd2bf297da --- /dev/null +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/entity/DefaultTxHistoryUpdater.kt @@ -0,0 +1,18 @@ +package com.tangem.features.txhistory.entity + +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.receiveAsFlow +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +internal class DefaultTxHistoryUpdater @Inject constructor() : TxHistoryUpdateListener, TxHistoryContentUpdateEmitter { + + private val updateChannel = Channel(Channel.BUFFERED) + override val updates: Flow = updateChannel.receiveAsFlow() + + override suspend fun triggerUpdate() { + updateChannel.send(Unit) + } +} \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/entity/TxHistoryUpdateListener.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/entity/TxHistoryUpdateListener.kt new file mode 100644 index 0000000000..32dd1035a7 --- /dev/null +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/entity/TxHistoryUpdateListener.kt @@ -0,0 +1,7 @@ +package com.tangem.features.txhistory.entity + +import kotlinx.coroutines.flow.Flow + +internal interface TxHistoryUpdateListener { + val updates: Flow +} \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/model/TxHistoryModel.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/model/TxHistoryModel.kt new file mode 100644 index 0000000000..593f171318 --- /dev/null +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/model/TxHistoryModel.kt @@ -0,0 +1,202 @@ +package com.tangem.features.txhistory.model + +import androidx.compose.runtime.Stable +import arrow.core.Either +import com.tangem.core.decompose.di.ModelScoped +import com.tangem.core.decompose.model.Model +import com.tangem.core.decompose.model.ParamsContainer +import com.tangem.core.navigation.url.UrlOpener +import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase +import com.tangem.domain.common.util.cardTypesResolver +import com.tangem.domain.tokens.error.CurrencyStatusError +import com.tangem.domain.tokens.GetCurrencyStatusUpdatesUseCase +import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.domain.txhistory.models.TxHistoryStateError +import com.tangem.domain.txhistory.repository.TxHistoryRepositoryV2 +import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase +import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase +import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.wallets.usecase.GetUserWalletUseCase +import com.tangem.features.txhistory.component.TxHistoryComponent +import com.tangem.features.txhistory.converter.TxHistoryItemToTransactionStateConverter +import com.tangem.features.txhistory.entity.TxHistoryUM +import com.tangem.features.txhistory.entity.TxHistoryUpdateListener +import com.tangem.features.txhistory.utils.TxHistoryListManager +import com.tangem.features.txhistory.utils.TxHistoryUiActions +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toPersistentList +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import timber.log.Timber +import javax.inject.Inject + +@Suppress("LongParameterList") +@Stable +@ModelScoped +internal class TxHistoryModel @Inject constructor( + override val dispatchers: CoroutineDispatcherProvider, + private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, + private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase, + private val getCurrencyStatusUpdatesUseCase: GetCurrencyStatusUpdatesUseCase, + private val getUserWalletUseCase: GetUserWalletUseCase, + private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase, + private val urlOpener: UrlOpener, + private val txHistoryUpdateListener: TxHistoryUpdateListener, + repository: TxHistoryRepositoryV2, + paramsContainer: ParamsContainer, +) : Model(), TxHistoryUiActions { + + private val params: TxHistoryComponent.Params = paramsContainer.require() + private val txHistoryItemConverter = + TxHistoryItemToTransactionStateConverter(currency = params.currency, txHistoryUiActions = this) + private val txHistoryListManager = TxHistoryListManager( + repository = repository, + dispatchers = dispatchers, + userWalletId = params.userWalletId, + currency = params.currency, + txHistoryItemConverter = txHistoryItemConverter, + txHistoryUiActions = this, + ) + private val _uiState: MutableStateFlow = + MutableStateFlow(TxHistoryUM.Loading(isBalanceHidden = true, onExploreClick = ::openExplorer)) + val uiState: StateFlow = _uiState.asStateFlow() + + init { + handleBalanceHiding() + subscribeToUiItemChanges() + loadTxInfo() + subscribeToUpdateListener() + subscribeOnCurrencyStatusUpdates() + } + + private fun subscribeToUiItemChanges() { + txHistoryListManager.uiItems + .onEach { updateState(it) } + .launchIn(modelScope) + } + + private fun subscribeToUpdateListener() { + txHistoryUpdateListener.updates + .onEach { reload() } + .launchIn(modelScope) + } + + private fun loadTxInfo() { + _uiState.update { state -> getLoadingState(state.isBalanceHidden) } + modelScope.launch { + txHistoryItemsCountUseCase.invoke(userWalletId = params.userWalletId, currency = params.currency) + .onLeft(::handleErrorState) + .onRight { txHistoryListManager.startLoading() } + } + } + + fun reload() { + // fast exit + if (uiState.value is TxHistoryUM.NotSupported) return + + _uiState.update { state -> + if (state !is TxHistoryUM.Content) getLoadingState(state.isBalanceHidden) else state + } + modelScope.launch { + txHistoryItemsCountUseCase.invoke(userWalletId = params.userWalletId, currency = params.currency) + .onLeft(::handleErrorState) + .onRight { txHistoryListManager.reload() } + } + } + + private fun handleBalanceHiding() { + getBalanceHidingSettingsUseCase() + .onEach { _uiState.update { state -> state.copySealed(isBalanceHidden = it.isBalanceHidden) } } + .launchIn(modelScope) + } + + private fun loadMoreItems(): Boolean { + modelScope.launch { txHistoryListManager.loadMore(params.userWalletId, params.currency) } + return true + } + + private fun updateState(items: ImmutableList) { + _uiState.update { state -> + if (state is TxHistoryUM.Content) { + state.copy(items = items) + } else { + TxHistoryUM.Content( + items = items, + isBalanceHidden = state.isBalanceHidden, + loadMore = ::loadMoreItems, + ) + } + } + } + + private fun handleErrorState(error: TxHistoryStateError) { + _uiState.update { state -> + when (error) { + is TxHistoryStateError.DataError -> TxHistoryUM.Error( + isBalanceHidden = state.isBalanceHidden, + onReloadClick = ::reload, + onExploreClick = ::openExplorer, + ) + TxHistoryStateError.EmptyTxHistories -> TxHistoryUM.Empty( + isBalanceHidden = state.isBalanceHidden, + onExploreClick = ::openExplorer, + ) + TxHistoryStateError.TxHistoryNotImplemented -> TxHistoryUM.NotSupported( + isBalanceHidden = state.isBalanceHidden, + pendingTransactions = persistentListOf(), + onExploreClick = ::openExplorer, + ) + } + } + } + + private fun getLoadingState(isBalanceHidden: Boolean): TxHistoryUM.Loading { + return TxHistoryUM.Loading(isBalanceHidden = isBalanceHidden, onExploreClick = ::openExplorer) + } + + private fun subscribeOnCurrencyStatusUpdates() { + val userWallet: UserWallet = requireNotNull(getUserWalletUseCase(params.userWalletId).getOrNull()) { + "User wallet not found" + } + getCurrencyStatusUpdatesUseCase( + userWalletId = params.userWalletId, + currencyId = params.currency.id, + isSingleWalletWithTokens = userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken(), + ) + .distinctUntilChanged() + .onEach(::handlePendingTxsChanges) + .flowOn(dispatchers.main) + .launchIn(modelScope) + } + + private fun handlePendingTxsChanges(maybeCurrencyStatus: Either) { + maybeCurrencyStatus.onRight { status -> + val pendingTxs = status.value.pendingTransactions + .map(txHistoryItemConverter::convert) + .toPersistentList() + _uiState.update { state -> + if (state is TxHistoryUM.NotSupported) { + state.copy(pendingTransactions = pendingTxs) + } else { + state + } + } + } + } + + override fun openExplorer() { + params.openExplorer() + } + + override fun openTxInExplorer(txHash: String) { + getExplorerTransactionUrlUseCase( + txHash = txHash, + networkId = params.currency.network.id, + ).fold( + ifLeft = { Timber.e(it.toString()) }, + ifRight = { urlOpener.openUrl(url = it) }, + ) + } +} \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/ui/TxHistoryContent.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/ui/TxHistoryContent.kt new file mode 100644 index 0000000000..9525d0ede2 --- /dev/null +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/ui/TxHistoryContent.kt @@ -0,0 +1,164 @@ +package com.tangem.features.txhistory.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.tangem.core.ui.components.list.InfiniteListHandler +import com.tangem.core.ui.components.transactions.PendingTxsBlock +import com.tangem.core.ui.components.transactions.Transaction +import com.tangem.core.ui.components.transactions.TxHistoryTitle +import com.tangem.core.ui.components.transactions.empty.EmptyTransactionBlock +import com.tangem.core.ui.components.transactions.empty.EmptyTransactionsBlockState +import com.tangem.core.ui.components.transactions.state.TransactionState +import com.tangem.core.ui.decorations.roundedShapeItemDecoration +import com.tangem.core.ui.res.TangemTheme +import com.tangem.features.txhistory.entity.TxHistoryUM + +private const val LOAD_ITEMS_BUFFER = 20 + +internal fun LazyListScope.txHistoryItems(listState: LazyListState, state: TxHistoryUM) { + when (state) { + is TxHistoryUM.Content -> contentItems(listState, state) + is TxHistoryUM.Empty -> nonContentItem(state = EmptyTransactionsBlockState.Empty(state.onExploreClick)) + is TxHistoryUM.Error -> nonContentItem( + state = EmptyTransactionsBlockState.FailedToLoad( + onReload = state.onReloadClick, + onExplore = state.onExploreClick, + ), + ) + is TxHistoryUM.Loading -> loadingItems(state) + is TxHistoryUM.NotSupported -> { + if (state.pendingTransactions.isNotEmpty()) { + item(key = "PendingTxsBlock", contentType = "PendingTxsBlock") { + PendingTxsBlock(pendingTxs = state.pendingTransactions, isBalanceHidden = state.isBalanceHidden) + } + } + + nonContentItem( + state = EmptyTransactionsBlockState.NotImplemented(onExplore = state.onExploreClick), + ) + } + } +} + +private fun LazyListScope.nonContentItem(state: EmptyTransactionsBlockState, modifier: Modifier = Modifier) { + item(key = state::class.java, contentType = state::class.java) { + EmptyTransactionBlock( + state = state, + modifier = modifier + .animateItem(fadeInSpec = null, fadeOutSpec = null) + .padding(horizontal = TangemTheme.dimens.spacing16, vertical = TangemTheme.dimens.spacing12) + .fillMaxWidth(), + ) + } +} + +private fun LazyListScope.loadingItems(state: TxHistoryUM.Loading) { + itemsIndexed( + items = state.items, + key = { _, item -> + when (item) { + is TxHistoryUM.TxHistoryItemUM.GroupTitle -> item.itemKey + is TxHistoryUM.TxHistoryItemUM.Title -> item.onExploreClick.hashCode() + is TxHistoryUM.TxHistoryItemUM.Transaction -> + item.state.txHash + (item.state as? TransactionState.Content)?.hashCode() + } + }, + contentType = { _, item -> item::class.java }, + itemContent = { index, item -> + TxHistoryListItem( + state = item, + isBalanceHidden = true, + modifier = Modifier.roundedShapeItemDecoration( + currentIndex = index, + lastIndex = state.items.lastIndex, + ), + ) + }, + ) +} + +private fun LazyListScope.contentItems(listState: LazyListState, state: TxHistoryUM.Content) { + itemsIndexed( + items = state.items, + key = { _, item -> + when (item) { + is TxHistoryUM.TxHistoryItemUM.GroupTitle -> item.itemKey + is TxHistoryUM.TxHistoryItemUM.Title -> item.onExploreClick.hashCode() + is TxHistoryUM.TxHistoryItemUM.Transaction -> + item.state.txHash + (item.state as? TransactionState.Content)?.hashCode() + } + }, + contentType = { _, item -> item::class.java }, + itemContent = { index, item -> + TxHistoryListItem( + state = item, + isBalanceHidden = state.isBalanceHidden, + modifier = Modifier.roundedShapeItemDecoration( + currentIndex = index, + lastIndex = state.items.lastIndex, + ), + ) + }, + ) + item { + InfiniteListHandler( + listState = listState, + buffer = LOAD_ITEMS_BUFFER, + onLoadMore = state.loadMore, + ) + } +} + +@Composable +internal fun TxHistoryListItem( + state: TxHistoryUM.TxHistoryItemUM, + isBalanceHidden: Boolean, + modifier: Modifier = Modifier, +) { + when (state) { + is TxHistoryUM.TxHistoryItemUM.GroupTitle -> { + TxHistoryGroupTitle(config = state, modifier = modifier) + } + is TxHistoryUM.TxHistoryItemUM.Title -> { + TxHistoryTitle(onExploreClick = state.onExploreClick, modifier = modifier) + } + is TxHistoryUM.TxHistoryItemUM.Transaction -> { + Transaction( + state = state.state, + isBalanceHidden = isBalanceHidden, + modifier = modifier, + ) + } + } +} + +@Composable +private fun TxHistoryGroupTitle(config: TxHistoryUM.TxHistoryItemUM.GroupTitle, modifier: Modifier = Modifier) { + Box( + modifier = modifier + .background(TangemTheme.colors.background.primary) + .padding( + vertical = TangemTheme.dimens.spacing8, + horizontal = TangemTheme.dimens.spacing12, + ) + .fillMaxWidth() + .heightIn(min = TangemTheme.dimens.size24), + contentAlignment = Alignment.CenterStart, + ) { + Text( + text = config.title, + color = TangemTheme.colors.text.tertiary, + style = TangemTheme.typography.body2, + ) + } +} \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryListManager.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryListManager.kt new file mode 100644 index 0000000000..91894dd1d1 --- /dev/null +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryListManager.kt @@ -0,0 +1,99 @@ +package com.tangem.features.txhistory.utils + +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.txhistory.model.TxHistoryListBatchingContext +import com.tangem.domain.txhistory.model.TxHistoryListConfig +import com.tangem.domain.txhistory.models.PaginationWrapper +import com.tangem.domain.txhistory.models.TxHistoryItem +import com.tangem.domain.txhistory.repository.TxHistoryRepositoryV2 +import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.features.txhistory.converter.TxHistoryItemToTransactionStateConverter +import com.tangem.features.txhistory.entity.TxHistoryUM +import com.tangem.pagination.BatchAction +import com.tangem.pagination.BatchListState +import com.tangem.pagination.PaginationStatus +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import com.tangem.utils.coroutines.JobHolder +import com.tangem.utils.coroutines.saveIn +import kotlinx.collections.immutable.ImmutableList +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.* + +private typealias TxHistoryBatchAction = BatchAction + +internal class TxHistoryListManager( + private val repository: TxHistoryRepositoryV2, + private val dispatchers: CoroutineDispatcherProvider, + private val userWalletId: UserWalletId, + private val currency: CryptoCurrency, + txHistoryItemConverter: TxHistoryItemToTransactionStateConverter, + txHistoryUiActions: TxHistoryUiActions, +) { + + private val jobHolder = JobHolder() + private val actionsFlow: MutableSharedFlow = MutableSharedFlow( + replay = 1, + onBufferOverflow = BufferOverflow.DROP_OLDEST, + ) + private val state: MutableStateFlow = MutableStateFlow(TxHistoryListState()) + private val uiManager = TxHistoryUiManager( + state = state, + txHistoryItemConverter = txHistoryItemConverter, + txHistoryUiActions = txHistoryUiActions, + ) + + val uiItems: Flow> = uiManager.items + + suspend fun startLoading() = coroutineScope { + val batchFlow = repository.getTxHistoryBatchFlow( + context = TxHistoryListBatchingContext( + actionsFlow = actionsFlow, + coroutineScope = this, + ), + batchSize = 50, + ) + + batchFlow.state + .onEach { state -> updateState(state) } + .flowOn(dispatchers.default) + .launchIn(scope = this) + .saveIn(jobHolder) + + actionsFlow.emit( + BatchAction.Reload( + requestParams = TxHistoryListConfig(userWalletId, currency, refresh = false), + ), + ) + } + + suspend fun reload() { + actionsFlow.emit( + BatchAction.Reload( + requestParams = TxHistoryListConfig(userWalletId, currency, refresh = true), + ), + ) + } + + suspend fun loadMore(userWalletId: UserWalletId, currency: CryptoCurrency) { + actionsFlow.emit( + BatchAction.LoadMore( + requestParams = TxHistoryListConfig(userWalletId, currency, refresh = false), + ), + ) + } + + private fun updateState(batchListState: BatchListState>) { + state.update { state -> + val clearUiBatches = + state.status is PaginationStatus.InitialLoading && batchListState.status is PaginationStatus.Paginating + state.copy( + status = batchListState.status, + uiBatches = uiManager.createOrUpdateUiBatches( + newCurrencyBatches = batchListState.data, + clearUiBatches = clearUiBatches, + ), + ) + } + } +} \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryListState.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryListState.kt new file mode 100644 index 0000000000..8e553fe6ac --- /dev/null +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryListState.kt @@ -0,0 +1,10 @@ +package com.tangem.features.txhistory.utils + +import com.tangem.features.txhistory.entity.TxHistoryUM +import com.tangem.pagination.Batch +import com.tangem.pagination.PaginationStatus + +data class TxHistoryListState( + val status: PaginationStatus<*> = PaginationStatus.None, + val uiBatches: List>> = listOf(), +) \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryUiActions.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryUiActions.kt new file mode 100644 index 0000000000..57a50a9014 --- /dev/null +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryUiActions.kt @@ -0,0 +1,7 @@ +package com.tangem.features.txhistory.utils + +internal interface TxHistoryUiActions { + + fun openExplorer() + fun openTxInExplorer(txHash: String) +} \ No newline at end of file diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryUiManager.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryUiManager.kt new file mode 100644 index 0000000000..2f4aba1080 --- /dev/null +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryUiManager.kt @@ -0,0 +1,113 @@ +package com.tangem.features.txhistory.utils + +import com.tangem.core.ui.utils.toDateFormatWithTodayYesterday +import com.tangem.domain.txhistory.models.PaginationWrapper +import com.tangem.domain.txhistory.models.TxHistoryItem +import com.tangem.features.txhistory.converter.TxHistoryItemToTransactionStateConverter +import com.tangem.features.txhistory.entity.TxHistoryUM +import com.tangem.pagination.Batch +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.mapLatest +import java.util.UUID + +internal class TxHistoryUiManager( + private val state: MutableStateFlow, + private val txHistoryItemConverter: TxHistoryItemToTransactionStateConverter, + private val txHistoryUiActions: TxHistoryUiActions, +) { + + @OptIn(ExperimentalCoroutinesApi::class) + val items: Flow> = state + .mapLatest { state -> + state.uiBatches.asSequence() + .flatMap { it.data } + .toImmutableList() + } + .distinctUntilChanged() + + fun createOrUpdateUiBatches( + newCurrencyBatches: List>>, + clearUiBatches: Boolean, + ): List>> { + val currentUiBatches = state.value.uiBatches + val batches = if (clearUiBatches) mutableListOf() else currentUiBatches.toMutableList() + + for ((key, data) in newCurrencyBatches) { + // Find if batch with same key exists + val existingBatchIndex = batches.indexOfFirst { it.key == key } + val shouldUpdateExisting = existingBatchIndex != -1 && + currentUiBatches[existingBatchIndex].data.transactionItemsSizeNotEqual(data.items) + + // Case 1: Update existing batch if sizes differ + if (shouldUpdateExisting) { + val items = generateUiItems(key, data) + batches[existingBatchIndex] = Batch(key = key, data = items) + continue + } + + // Case 2: Skip if batch exists and has same size + if (existingBatchIndex != -1) { + continue + } + + // Case 3: Create new batch + val items = generateUiItems(key, data) + batches.add(Batch(key = key, data = items)) + } + + return batches + } + + private fun generateUiItems(key: Int, data: PaginationWrapper): List { + val items = mutableListOf() + + // Add title for the first batch + if (key == 0) { + items.add(TxHistoryUM.TxHistoryItemUM.Title(onExploreClick = txHistoryUiActions::openExplorer)) + } + + // Process batch items only if there are any + if (data.items.isNotEmpty()) { + // Add first item with its group title + val firstItem = data.items.first() + val firstDate = firstItem.timestampInMillis.toDateFormatWithTodayYesterday() + + items.add( + TxHistoryUM.TxHistoryItemUM.GroupTitle( + title = firstDate, + itemKey = UUID.randomUUID().toString(), + ), + ) + items.add(TxHistoryUM.TxHistoryItemUM.Transaction(txHistoryItemConverter.convert(firstItem))) + + // Process remaining items with date separators when needed + data.items.zipWithNext { current, next -> + val currentDate = current.timestampInMillis.toDateFormatWithTodayYesterday() + val nextDate = next.timestampInMillis.toDateFormatWithTodayYesterday() + + if (currentDate != nextDate) { + items.add( + TxHistoryUM.TxHistoryItemUM.GroupTitle( + title = nextDate, + itemKey = UUID.randomUUID().toString(), + ), + ) + } + items.add(TxHistoryUM.TxHistoryItemUM.Transaction(txHistoryItemConverter.convert(next))) + } + } + + return items + } + + private fun List.transactionItemsSizeNotEqual( + txHistoryItems: List, + ): Boolean { + return this.filterIsInstance().size != txHistoryItems.size + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index ddb8968ba6..2e31c05b4e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -224,6 +224,9 @@ include(":features:onramp:impl") include(":features:stories:api") include(":features:stories:impl") + +include(":features:txhistory:api") +include(":features:txhistory:impl") // endregion Feature modules // region Domain modules From d62c1627373c9ef0d5d305f33fcc0725dd621233 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 5 Mar 2025 17:01:01 +0700 Subject: [PATCH 51/54] Updated on 2026-08-14 --- .../data/DefaultLegacyWalletConnectRepository.kt | 5 ++++- .../di/WalletConnectInteractorModule.kt | 14 ++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/DefaultLegacyWalletConnectRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/DefaultLegacyWalletConnectRepository.kt index 7517f4d57d..27eb47df0b 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/DefaultLegacyWalletConnectRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/DefaultLegacyWalletConnectRepository.kt @@ -9,8 +9,10 @@ import com.reown.walletkit.client.Wallet import com.reown.walletkit.client.WalletKit import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.tap.common.analytics.events.WalletConnect +import com.tangem.tap.domain.walletconnect2.app.TangemWcBlockchainHelper import com.tangem.tap.domain.walletconnect2.domain.* import com.tangem.tap.domain.walletconnect2.domain.models.* +import com.tangem.tap.domain.walletconnect2.toggles.WalletConnectFeatureToggles import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction.OpenSession.SourceType import kotlinx.coroutines.* import kotlinx.coroutines.flow.Flow @@ -22,7 +24,7 @@ internal class DefaultLegacyWalletConnectRepository( private val application: Application, private val wcRequestDeserializer: WcJrpcRequestsDeserializer, private val analyticsHandler: AnalyticsEventHandler, - private val blockchainHelper: WcBlockchainHelper, + private val walletConnectFeatureToggles: WalletConnectFeatureToggles, ) : LegacyWalletConnectRepository { private var sessionProposal: Wallet.Model.SessionProposal? = null @@ -34,6 +36,7 @@ internal class DefaultLegacyWalletConnectRepository( private val _activeSessions: MutableSharedFlow> = MutableSharedFlow() override val activeSessions: Flow> = _activeSessions + private val blockchainHelper by lazy { TangemWcBlockchainHelper(walletConnectFeatureToggles) } override var currentSessions: List = emptyList() private set diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/di/WalletConnectInteractorModule.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/di/WalletConnectInteractorModule.kt index 754a727e54..80319c8ce3 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/di/WalletConnectInteractorModule.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/di/WalletConnectInteractorModule.kt @@ -33,7 +33,7 @@ internal object WalletConnectInteractorModule { fun provideWalletConnectInteractor( wcRepository: LegacyWalletConnectRepository, wcSessionsRepository: WalletConnectSessionsRepository, - wcBlockchainHelper: WcBlockchainHelper, + walletConnectFeatureToggles: WalletConnectFeatureToggles, currenciesRepository: CurrenciesRepository, walletManagersFacade: WalletManagersFacade, userWalletsListManager: UserWalletsListManager, @@ -44,7 +44,7 @@ internal object WalletConnectInteractorModule { walletConnectRepository = wcRepository, sessionsRepository = wcSessionsRepository, sdkHelper = WalletConnectSdkHelper(), - blockchainHelper = wcBlockchainHelper, + blockchainHelper = TangemWcBlockchainHelper(walletConnectFeatureToggles), currenciesRepository = currenciesRepository, walletManagersFacade = walletManagersFacade, userWalletsListManager = userWalletsListManager, @@ -63,25 +63,19 @@ internal object WalletConnectModule { return WalletConnectFeatureToggles(featureTogglesManager) } - @Provides - @Singleton - fun provideWcBlockchainHelper(walletConnectFeatureToggles: WalletConnectFeatureToggles): WcBlockchainHelper { - return TangemWcBlockchainHelper(walletConnectFeatureToggles) - } - @Provides @Singleton fun provideWalletConnectRepository( application: Application, wcRequestDeserializer: WcJrpcRequestsDeserializer, analyticsHandler: AnalyticsEventHandler, - wcBlockchainHelper: WcBlockchainHelper, + walletConnectFeatureToggles: WalletConnectFeatureToggles, ): LegacyWalletConnectRepository { return DefaultLegacyWalletConnectRepository( application = application, wcRequestDeserializer = wcRequestDeserializer, analyticsHandler = analyticsHandler, - blockchainHelper = wcBlockchainHelper, + walletConnectFeatureToggles = walletConnectFeatureToggles, ) } From 9535d484397e10c6c260aa6232ad2c7a4f76ca3a Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 5 Mar 2025 10:54:46 +0000 Subject: [PATCH 52/54] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 86711746f2..d20b17869e 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -1,7 +1,7 @@ [versions] -tangemBlockchainSdk = "release-app_5.21-969" +tangemBlockchainSdk = "develop-968" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "release-app_5.21-435" +tangemCardSdk = "develop-437" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "2.0.0-alpha.25-tangem-developments8" #tangemVico = "0.0.1" # Keep it! - used for local builds ^ From eb0b62da9d44323eb72dae66946733b1fae66442 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 5 Mar 2025 17:58:49 +0700 Subject: [PATCH 53/54] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index d20b17869e..5a5650618e 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -1,5 +1,5 @@ [versions] -tangemBlockchainSdk = "develop-968" +tangemBlockchainSdk = "develop-973" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "develop-437" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ From ed53e6a3c23f7b07dda2bc3ba540a4bf495b6047 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 5 Mar 2025 14:43:28 +0300 Subject: [PATCH 54/54] Updated on 2026-08-14 --- .../main/java/com/tangem/domain/common/visa/VisaUtilities.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/visa/VisaUtilities.kt b/domain/legacy/src/main/java/com/tangem/domain/common/visa/VisaUtilities.kt index de113d6a18..fbd488d355 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/common/visa/VisaUtilities.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/common/visa/VisaUtilities.kt @@ -6,6 +6,7 @@ import com.tangem.common.card.FirmwareVersion import com.tangem.domain.models.scan.CardDTO private const val VISA_BATCH_START = "AE" +private const val VISA_BATCH_START_2 = "FFFC" object VisaUtilities { @@ -24,6 +25,6 @@ object VisaUtilities { fun isVisaCard(firmwareVersion: Double, batchId: String): Boolean { return firmwareVersion in FirmwareVersion.visaRange && - batchId.startsWith(VISA_BATCH_START) + (batchId.startsWith(VISA_BATCH_START) || batchId.startsWith(VISA_BATCH_START_2)) } } \ No newline at end of file