From fb54de419b0410683984152f36cb8386e10c07e6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 30 Jul 2025 17:56:53 +0500 Subject: [PATCH] Updated on 2026-08-14 --- app/build.gradle.kts | 2 + .../kotlin/com/tangem/tests/StoriesTest.kt | 4 +- .../main/java/com/tangem/tap/MainActivity.kt | 31 +- .../analytics/events/IntroductionProcess.kt | 18 -- .../tap/common/analytics/events/Shop.kt | 30 -- .../CardContextInterceptor.kt | 2 +- .../tap/common/compose/extensions/Dp.kt | 17 -- .../tap/common/compose/extensions/Painter.kt | 20 -- .../com/tangem/tap/common/extensions/Int.kt | 3 - .../com/tangem/tap/common/redux/AppReducer.kt | 2 - .../com/tangem/tap/common/redux/AppState.kt | 4 - .../tangem/tap/common/ui/ScanFailsDialog.kt | 8 +- .../com/tangem/tap/di/IntentHandlingModule.kt | 34 +++ .../details/redux/DetailsMiddleware.kt | 2 +- .../ui/resetcard/model/ResetCardModel.kt | 2 +- .../tap/features/home/DefaultHomeComponent.kt | 90 ------ .../com/tangem/tap/features/home/HomeModel.kt | 166 ----------- .../tap/features/home/RegionProvider.kt | 16 -- .../home/TangemTangemErrorsHandler.kt | 44 --- .../tap/features/home/api/HomeComponent.kt | 9 - .../tap/features/home/di/HomeFeatureModule.kt | 25 -- .../home/errors/TangemSdkErrorHandler.kt | 8 - .../tap/features/home/redux/HomeAction.kt | 21 -- .../tap/features/home/redux/HomeMiddleware.kt | 147 ---------- .../tap/features/home/redux/HomeReducer.kt | 31 -- .../handlers/BackgroundScanIntentHandler.kt | 32 +-- .../WalletConnectLinkIntentHandler.kt | 2 +- .../welcome/component/WelcomeComponent.kt | 2 + .../features/welcome/model/WelcomeModel.kt | 8 +- .../welcome/redux/WelcomeMiddleware.kt | 15 +- .../tangem/tap/routing/utils/ChildFactory.kt | 7 +- .../com/tangem/common/routing/AppRoute.kt | 7 +- .../routing/entity/InitScreenLaunchMode.kt | 13 + .../routing/entity/SerializableIntent.kt | 1 + .../tangem/core/ui/utils}/AnimatedValue.kt | 2 +- .../com/tangem/core/ui/utils/DensityUtils.kt | 20 +- .../com/tangem/core/ui/utils}/ImageBitmap.kt | 2 +- .../res/drawable-hdpi/img_meet_tangem.webp | Bin .../img_revolutionary_wallet.webp | Bin .../img_tangem_for_everyone.webp | Bin .../res/drawable-mdpi/img_meet_tangem.webp | Bin .../img_revolutionary_wallet.webp | Bin .../img_tangem_for_everyone.webp | Bin .../res/drawable-xhdpi/img_meet_tangem.webp | Bin .../img_revolutionary_wallet.webp | Bin .../img_tangem_for_everyone.webp | Bin .../res/drawable-xxhdpi/img_meet_tangem.webp | Bin .../img_revolutionary_wallet.webp | Bin .../img_tangem_for_everyone.webp | Bin .../res/drawable-xxxhdpi/img_meet_tangem.webp | Bin .../img_revolutionary_wallet.webp | Bin .../img_tangem_for_everyone.webp | Bin .../ui}/src/main/res/drawable/currency0.webp | Bin .../ui}/src/main/res/drawable/currency1.webp | Bin .../ui}/src/main/res/drawable/currency2.webp | Bin .../ui}/src/main/res/drawable/currency3.webp | Bin .../ui}/src/main/res/drawable/currency4.webp | Bin .../ui}/src/main/res/drawable/dapps1.webp | Bin .../ui}/src/main/res/drawable/dapps2.webp | Bin .../ui}/src/main/res/drawable/dapps3.webp | Bin .../ui}/src/main/res/drawable/dapps4.webp | Bin .../ui}/src/main/res/drawable/dapps5.webp | Bin .../src/main/res/drawable/ic_tangem_logo.xml | 0 .../img_card_placeholder_wallet_2.webp | Bin .../java/com/tangem/utils/extensions/Int.kt | 6 - .../disclaimer/impl/model/DisclaimerModel.kt | 2 +- features/home/api/.gitignore | 1 + features/home/api/build.gradle.kts | 17 ++ .../tangem/features/home/api/HomeComponent.kt | 17 ++ features/home/impl/.gitignore | 1 + features/home/impl/build.gradle.kts | 69 +++++ .../home/impl/DefaultHomeComponent.kt | 40 +++ .../home/impl/analytics/AnalyticsParam.kt | 9 + .../impl/analytics/IntroductionProcess.kt | 14 + .../analytics/ParamCardCurrencyConverter.kt | 23 ++ .../features/home/impl/analytics/Shop.kt | 11 + .../home/impl/di/HomeFeatureModule.kt | 33 +++ .../features/home/impl/model/HomeModel.kt | 268 ++++++++++++++++++ .../com/tangem/features/home/impl/ui/Home.kt | 35 +++ .../home/impl/ui}/compose/StoriesAnimation.kt | 6 +- .../home/impl/ui}/compose/StoriesScreen.kt | 25 +- .../home/impl/ui}/compose/StoriesScreenV2.kt | 23 +- .../home/impl/ui}/compose/content/Content.kt | 8 +- .../compose/content/CurrenciesWeb3Content.kt | 18 +- .../compose/content/FirstStoriesContent.kt | 6 +- .../compose/content/FloatingCardsContent.kt | 10 +- .../impl/ui}/compose/views/HomeButtons.kt | 4 +- .../impl/ui}/compose/views/HomeButtonsV2.kt | 4 +- .../compose/views/SearchCurrenciesButton.kt | 4 +- .../impl/ui}/compose/views/StoriesButton.kt | 2 +- .../ui}/compose/views/StoriesProgressBar.kt | 2 +- .../features/home/impl/ui/state/HomeUM.kt | 19 +- .../entry/impl/model/OnboardingEntryModel.kt | 2 +- .../model/WalletSettingsModel.kt | 2 +- .../model/intents/WalletCardClickIntents.kt | 2 +- .../router/DefaultWalletRouter.kt | 2 +- .../features/welcome/WelcomeComponent.kt | 2 + settings.gradle.kts | 3 + 98 files changed, 750 insertions(+), 787 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/common/analytics/events/IntroductionProcess.kt delete mode 100644 app/src/main/java/com/tangem/tap/common/analytics/events/Shop.kt delete mode 100644 app/src/main/java/com/tangem/tap/common/compose/extensions/Dp.kt delete mode 100644 app/src/main/java/com/tangem/tap/common/compose/extensions/Painter.kt delete mode 100644 app/src/main/java/com/tangem/tap/common/extensions/Int.kt create mode 100644 app/src/main/java/com/tangem/tap/di/IntentHandlingModule.kt delete 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/HomeModel.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/home/RegionProvider.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/home/TangemTangemErrorsHandler.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/home/api/HomeComponent.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/home/di/HomeFeatureModule.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/home/errors/TangemSdkErrorHandler.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt create mode 100644 common/routing/src/main/kotlin/com/tangem/common/routing/entity/InitScreenLaunchMode.kt rename {app/src/main/java/com/tangem/tap/common/compose/extensions => core/ui/src/main/java/com/tangem/core/ui/utils}/AnimatedValue.kt (96%) rename {app/src/main/java/com/tangem/tap/common/compose/extensions => core/ui/src/main/java/com/tangem/core/ui/utils}/ImageBitmap.kt (92%) rename {app => core/ui}/src/main/res/drawable-hdpi/img_meet_tangem.webp (100%) rename {app => core/ui}/src/main/res/drawable-hdpi/img_revolutionary_wallet.webp (100%) rename {app => core/ui}/src/main/res/drawable-hdpi/img_tangem_for_everyone.webp (100%) rename {app => core/ui}/src/main/res/drawable-mdpi/img_meet_tangem.webp (100%) rename {app => core/ui}/src/main/res/drawable-mdpi/img_revolutionary_wallet.webp (100%) rename {app => core/ui}/src/main/res/drawable-mdpi/img_tangem_for_everyone.webp (100%) rename {app => core/ui}/src/main/res/drawable-xhdpi/img_meet_tangem.webp (100%) rename {app => core/ui}/src/main/res/drawable-xhdpi/img_revolutionary_wallet.webp (100%) rename {app => core/ui}/src/main/res/drawable-xhdpi/img_tangem_for_everyone.webp (100%) rename {app => core/ui}/src/main/res/drawable-xxhdpi/img_meet_tangem.webp (100%) rename {app => core/ui}/src/main/res/drawable-xxhdpi/img_revolutionary_wallet.webp (100%) rename {app => core/ui}/src/main/res/drawable-xxhdpi/img_tangem_for_everyone.webp (100%) rename {app => core/ui}/src/main/res/drawable-xxxhdpi/img_meet_tangem.webp (100%) rename {app => core/ui}/src/main/res/drawable-xxxhdpi/img_revolutionary_wallet.webp (100%) rename {app => core/ui}/src/main/res/drawable-xxxhdpi/img_tangem_for_everyone.webp (100%) rename {app => core/ui}/src/main/res/drawable/currency0.webp (100%) rename {app => core/ui}/src/main/res/drawable/currency1.webp (100%) rename {app => core/ui}/src/main/res/drawable/currency2.webp (100%) rename {app => core/ui}/src/main/res/drawable/currency3.webp (100%) rename {app => core/ui}/src/main/res/drawable/currency4.webp (100%) rename {app => core/ui}/src/main/res/drawable/dapps1.webp (100%) rename {app => core/ui}/src/main/res/drawable/dapps2.webp (100%) rename {app => core/ui}/src/main/res/drawable/dapps3.webp (100%) rename {app => core/ui}/src/main/res/drawable/dapps4.webp (100%) rename {app => core/ui}/src/main/res/drawable/dapps5.webp (100%) rename {app => core/ui}/src/main/res/drawable/ic_tangem_logo.xml (100%) rename {app => core/ui}/src/main/res/drawable/img_card_placeholder_wallet_2.webp (100%) delete mode 100644 core/utils/src/main/java/com/tangem/utils/extensions/Int.kt create mode 100644 features/home/api/.gitignore create mode 100644 features/home/api/build.gradle.kts create mode 100644 features/home/api/src/main/kotlin/com/tangem/features/home/api/HomeComponent.kt create mode 100644 features/home/impl/.gitignore create mode 100644 features/home/impl/build.gradle.kts create mode 100644 features/home/impl/src/main/kotlin/com/tangem/features/home/impl/DefaultHomeComponent.kt create mode 100644 features/home/impl/src/main/kotlin/com/tangem/features/home/impl/analytics/AnalyticsParam.kt create mode 100644 features/home/impl/src/main/kotlin/com/tangem/features/home/impl/analytics/IntroductionProcess.kt create mode 100644 features/home/impl/src/main/kotlin/com/tangem/features/home/impl/analytics/ParamCardCurrencyConverter.kt create mode 100644 features/home/impl/src/main/kotlin/com/tangem/features/home/impl/analytics/Shop.kt create mode 100644 features/home/impl/src/main/kotlin/com/tangem/features/home/impl/di/HomeFeatureModule.kt create mode 100644 features/home/impl/src/main/kotlin/com/tangem/features/home/impl/model/HomeModel.kt create mode 100644 features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/Home.kt rename {app/src/main/java/com/tangem/tap/features/home => features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui}/compose/StoriesAnimation.kt (96%) rename {app/src/main/java/com/tangem/tap/features/home => features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui}/compose/StoriesScreen.kt (94%) rename {app/src/main/java/com/tangem/tap/features/home => features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui}/compose/StoriesScreenV2.kt (94%) rename {app/src/main/java/com/tangem/tap/features/home => features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui}/compose/content/Content.kt (96%) rename {app/src/main/java/com/tangem/tap/features/home => features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui}/compose/content/CurrenciesWeb3Content.kt (93%) rename {app/src/main/java/com/tangem/tap/features/home => features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui}/compose/content/FirstStoriesContent.kt (94%) rename {app/src/main/java/com/tangem/tap/features/home => features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui}/compose/content/FloatingCardsContent.kt (92%) rename {app/src/main/java/com/tangem/tap/features/home => features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui}/compose/views/HomeButtons.kt (97%) rename {app/src/main/java/com/tangem/tap/features/home => features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui}/compose/views/HomeButtonsV2.kt (98%) rename {app/src/main/java/com/tangem/tap/features/home => features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui}/compose/views/SearchCurrenciesButton.kt (94%) rename {app/src/main/java/com/tangem/tap/features/home => features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui}/compose/views/StoriesButton.kt (97%) rename {app/src/main/java/com/tangem/tap/features/home => features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui}/compose/views/StoriesProgressBar.kt (98%) rename app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt => features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/state/HomeUM.kt (58%) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 040b46b637..19dd55b0e1 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -232,6 +232,8 @@ dependencies { implementation(projects.features.welcome.impl) implementation(projects.features.createWalletSelection.api) implementation(projects.features.createWalletSelection.impl) + implementation(projects.features.home.api) + implementation(projects.features.home.impl) /** AndroidX libraries */ implementation(deps.androidx.core.ktx) diff --git a/app/src/androidTest/kotlin/com/tangem/tests/StoriesTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/StoriesTest.kt index 303ce3f6a0..8fe8ee6203 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/StoriesTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/StoriesTest.kt @@ -3,8 +3,8 @@ package com.tangem.tests import android.content.Intent.ACTION_VIEW import com.tangem.common.BaseTestCase import com.tangem.common.extensions.clickWithAssertion -import com.tangem.screens.onDisclaimerScreen -import com.tangem.screens.onStoriesScreen +import com.tangem.screens.DisclaimerTestScreen +import com.tangem.screens.StoriesTestScreen import com.tangem.tap.features.home.redux.HomeMiddleware.NEW_BUY_WALLET_URL import dagger.hilt.android.testing.HiltAndroidTest import io.github.kakaocup.kakao.intent.KIntent diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 776dbb7b61..7be16eab0a 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -176,13 +176,22 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder { @Inject internal lateinit var testerMenuLauncher: TesterMenuLauncher + @Inject + internal lateinit var intentProcessor: IntentProcessor + + @Inject + internal lateinit var walletConnectLinkIntentHandler: WalletConnectLinkIntentHandler + + @Inject + internal lateinit var onPushClickedIntentHandler: OnPushClickedIntentHandler + + @Inject + internal lateinit var backgroundScanIntentHandler: BackgroundScanIntentHandler + internal val viewModel: MainViewModel by viewModels() private lateinit var appThemeModeFlow: SharedFlow - // TODO: fixme: inject through DI - private val intentProcessor: IntentProcessor = IntentProcessor() - private val dialogManager = DialogManager() private val onActivityResultCallbacks = mutableListOf() @@ -344,12 +353,10 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder { } private fun initIntentHandlers() { - val hasSavedWalletsProvider = { userWalletsListManager.hasUserWallets } - intentProcessor.addHandler(OnPushClickedIntentHandler(analyticsEventsHandler)) - intentProcessor.addHandler(BackgroundScanIntentHandler(hasSavedWalletsProvider, lifecycleScope)) + intentProcessor.addHandler(onPushClickedIntentHandler) if (!walletConnectFeatureToggles.isRedesignedWalletConnectEnabled) { - intentProcessor.addHandler(WalletConnectLinkIntentHandler()) + intentProcessor.addHandler(walletConnectLinkIntentHandler) } } @@ -435,9 +442,15 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder { } private fun navigateToInitialScreen(intentWhichStartedActivity: Intent?) { + val launchMode = backgroundScanIntentHandler.getInitScreenLaunchMode(intentWhichStartedActivity) if (userWalletsListManager.isLockable && userWalletsListManager.hasUserWallets) { store.dispatchNavigationAction { - replaceAll(AppRoute.Welcome(intentWhichStartedActivity?.let(::SerializableIntent))) + replaceAll( + AppRoute.Welcome( + launchMode = launchMode, + intent = intentWhichStartedActivity?.let(::SerializableIntent), + ), + ) } intentProcessor.handleIntent( intent = intentWhichStartedActivity, @@ -452,7 +465,7 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder { val route = when { shouldShowTos -> AppRoute.Disclaimer(isTosAccepted = false) shouldShowInitialPush -> AppRoute.PushNotification - else -> AppRoute.Home + else -> AppRoute.Home(launchMode = launchMode) } store.dispatchNavigationAction { replaceAll(route) } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/IntroductionProcess.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/IntroductionProcess.kt deleted file mode 100644 index b5ce0042ae..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/IntroductionProcess.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.tangem.tap.common.analytics.events - -import com.tangem.core.analytics.models.AnalyticsEvent - -/** -[REDACTED_AUTHOR] - */ -sealed class IntroductionProcess( - event: String, - params: Map = mapOf(), -) : AnalyticsEvent("Introduction Process", event, params) { - - class ScreenOpened : IntroductionProcess("Introduction Process Screen Opened") - class ButtonTokensList : IntroductionProcess("Button - Tokens List") - class ButtonBuyCards : IntroductionProcess("Button - Buy Cards") - class ButtonScanCard : IntroductionProcess("Button - Scan Card") - class ButtonRequestSupport : IntroductionProcess("Button - Request Support") -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Shop.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Shop.kt deleted file mode 100644 index 4076de8685..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Shop.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.tangem.tap.common.analytics.events - -import com.tangem.core.analytics.models.AnalyticsEvent -import com.tangem.tap.common.extensions.filterNotNull - -/** -[REDACTED_AUTHOR] - */ -sealed class Shop( - event: String, - params: Map = mapOf(), -) : AnalyticsEvent("Shop", event, params) { - - class ScreenOpened : Shop("Shop Screen Opened") - - class Purchased(sku: String, count: String, amount: String, couponCode: String?) : Shop( - event = "Purchased", - params = mapOf( - "SKU" to sku, - "Count" to count, - "Amount" to amount, - "Coupon Code" to couponCode, - ).filterNotNull(), - ) - - class Redirected(partnerName: String?) : Shop( - event = "Redirected", - params = partnerName?.let { mapOf("Partner" to partnerName) } ?: mapOf(), - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt index 654dbe07ca..8f14501047 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt @@ -6,9 +6,9 @@ import com.tangem.domain.card.common.util.cardTypesResolver import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.wallets.builder.UserWalletIdBuilder +import com.tangem.features.home.impl.analytics.IntroductionProcess import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter import com.tangem.tap.common.analytics.events.AnalyticsParam -import com.tangem.tap.common.analytics.events.IntroductionProcess import com.tangem.tap.common.extensions.inject import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.proxy.redux.DaggerGraphState diff --git a/app/src/main/java/com/tangem/tap/common/compose/extensions/Dp.kt b/app/src/main/java/com/tangem/tap/common/compose/extensions/Dp.kt deleted file mode 100644 index 04240d7b55..0000000000 --- a/app/src/main/java/com/tangem/tap/common/compose/extensions/Dp.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.tangem.tap.common.compose.extensions - -import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.DpSize - -/** -[REDACTED_AUTHOR] - */ -@Composable -fun Dp.toPx(): Float { - val currentDp = this - return with(LocalDensity.current) { currentDp.toPx() } -} - -fun DpSize.halfHeight(): Dp = this.height / 2 \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/compose/extensions/Painter.kt b/app/src/main/java/com/tangem/tap/common/compose/extensions/Painter.kt deleted file mode 100644 index dfabb2cddf..0000000000 --- a/app/src/main/java/com/tangem/tap/common/compose/extensions/Painter.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.tangem.tap.common.compose.extensions - -import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.unit.DpSize -import androidx.compose.ui.unit.dp -import com.tangem.sdk.extensions.pxToDp - -/** -[REDACTED_AUTHOR] - */ -@Composable -fun Painter.dpSize(): DpSize = DpSize( - intrinsicSize.width.pxToDp().dp, - intrinsicSize.height.pxToDp().dp, -) - -@Composable -private fun Float.pxToDp(): Float = LocalContext.current.pxToDp(this) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Int.kt b/app/src/main/java/com/tangem/tap/common/extensions/Int.kt deleted file mode 100644 index 555dc252bd..0000000000 --- a/app/src/main/java/com/tangem/tap/common/extensions/Int.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.tangem.tap.common.extensions - -fun Int.isEven() = this and 1 == 0 \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt index 111bad630c..8bd03da756 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt @@ -3,7 +3,6 @@ package com.tangem.tap.common.redux import com.tangem.tap.common.redux.global.globalReducer import com.tangem.tap.features.details.redux.DetailsReducer import com.tangem.tap.features.details.redux.walletconnect.WalletConnectReducer -import com.tangem.tap.features.home.redux.HomeReducer import com.tangem.tap.features.welcome.redux.WelcomeReducer import com.tangem.tap.proxy.redux.DaggerGraphReducer import org.rekotlin.Action @@ -14,7 +13,6 @@ fun appReducer(action: Action, state: AppState?): AppState { return AppState( globalState = globalReducer(action, state), - homeState = HomeReducer.reduce(action, state), detailsState = DetailsReducer.reduce(action, state), walletConnectState = WalletConnectReducer.reduce(action, state.walletConnectState), welcomeState = WelcomeReducer.reduce(action, state), diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt index 3df1fae79b..427a103a98 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt @@ -7,8 +7,6 @@ import com.tangem.tap.features.details.redux.DetailsMiddleware import com.tangem.tap.features.details.redux.DetailsState import com.tangem.tap.features.details.redux.walletconnect.WalletConnectMiddleware import com.tangem.tap.features.details.redux.walletconnect.WalletConnectState -import com.tangem.tap.features.home.redux.HomeMiddleware -import com.tangem.tap.features.home.redux.HomeState import com.tangem.tap.features.onboarding.products.wallet.redux.BackupMiddleware import com.tangem.tap.features.wallet.redux.middlewares.TradeCryptoMiddleware import com.tangem.tap.features.welcome.redux.WelcomeMiddleware @@ -20,7 +18,6 @@ import org.rekotlin.StateType data class AppState( val globalState: GlobalState = GlobalState(), - val homeState: HomeState = HomeState(), val detailsState: DetailsState = DetailsState(), val walletConnectState: WalletConnectState = WalletConnectState(), val welcomeState: WelcomeState = WelcomeState(), @@ -32,7 +29,6 @@ data class AppState( return listOf( logMiddleware, GlobalMiddleware.handler, - HomeMiddleware.handler, DetailsMiddleware().detailsMiddleware, WalletConnectMiddleware().walletConnectMiddleware, BackupMiddleware().backupMiddleware, diff --git a/app/src/main/java/com/tangem/tap/common/ui/ScanFailsDialog.kt b/app/src/main/java/com/tangem/tap/common/ui/ScanFailsDialog.kt index 6096730a8e..61b24a7d63 100644 --- a/app/src/main/java/com/tangem/tap/common/ui/ScanFailsDialog.kt +++ b/app/src/main/java/com/tangem/tap/common/ui/ScanFailsDialog.kt @@ -4,6 +4,7 @@ import android.content.Context import android.view.View import android.widget.TextView import androidx.appcompat.app.AlertDialog +import androidx.compose.ui.text.intl.Locale import androidx.core.view.isVisible import com.tangem.core.analytics.Analytics import com.tangem.core.analytics.models.AnalyticsParam @@ -14,8 +15,6 @@ import com.tangem.tap.common.analytics.events.ScanFailsDialogAnalytics import com.tangem.tap.common.extensions.dispatchDialogHide import com.tangem.tap.common.extensions.dispatchOpenUrl import com.tangem.tap.common.extensions.inject -import com.tangem.tap.features.home.LocaleRegionProvider -import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope import com.tangem.tap.store @@ -29,6 +28,7 @@ internal object ScanFailsDialog { private const val HOW_TO_SCAN_RU_LINK = "https://tangem.com/ru/blog/post/scan-tangem-card/" private const val HOW_TO_SCAN_LINK = "https://tangem.com/en/blog/post/scan-tangem-card/" + private const val RUSSIA_LOCALE = "ru" fun create(context: Context, source: StateDialog.ScanFailsSource, onTryAgain: (() -> Unit)? = null): AlertDialog { return AlertDialog.Builder(context, R.style.CustomMaterialDialog).apply { @@ -62,8 +62,8 @@ internal object ScanFailsDialog { source = sourceAnalytics, ), ) - val locale = LocaleRegionProvider().getRegion() - val link = if (locale.lowercase() == RUSSIA_COUNTRY_CODE) HOW_TO_SCAN_RU_LINK else HOW_TO_SCAN_LINK + val locale = Locale.current.region + val link = if (locale.lowercase() == RUSSIA_LOCALE) HOW_TO_SCAN_RU_LINK else HOW_TO_SCAN_LINK store.dispatchOpenUrl(link) } customView.findViewById(R.id.request_support_button)?.setOnClickListener { diff --git a/app/src/main/java/com/tangem/tap/di/IntentHandlingModule.kt b/app/src/main/java/com/tangem/tap/di/IntentHandlingModule.kt new file mode 100644 index 0000000000..cd7becb2e0 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/di/IntentHandlingModule.kt @@ -0,0 +1,34 @@ +package com.tangem.tap.di + +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.tap.features.intentHandler.IntentProcessor +import com.tangem.tap.features.intentHandler.handlers.BackgroundScanIntentHandler +import com.tangem.tap.features.intentHandler.handlers.OnPushClickedIntentHandler +import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler +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 IntentHandlingModule { + + @Provides + @Singleton + fun provideBackgroundScanIntentHandler(): BackgroundScanIntentHandler = BackgroundScanIntentHandler() + + @Provides + @Singleton + fun provideWalletConnectLinkIntentHandler(): WalletConnectLinkIntentHandler = WalletConnectLinkIntentHandler() + + @Provides + @Singleton + fun provideOnPushClickedIntentHandler(analyticsEventHandler: AnalyticsEventHandler): OnPushClickedIntentHandler = + OnPushClickedIntentHandler(analyticsEventHandler) + + @Provides + @Singleton + fun provideIntentProcessor(): IntentProcessor = IntentProcessor() +} \ No newline at end of file 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 af4c05b261..3aece96fa9 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 @@ -233,7 +233,7 @@ class DetailsMiddleware { deleteSavedAccessCodes() store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = false) - store.dispatchNavigationAction { replaceAll(AppRoute.Home) } + store.dispatchNavigationAction { replaceAll(AppRoute.Home()) } return CompletionResult.Success(Unit) } 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 34e073bf69..2d0af3ca0b 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 @@ -268,7 +268,7 @@ internal class ResetCardModel @Inject constructor( if (isLocked && userWalletsListManager.hasUserWallets) { store.dispatchNavigationAction { popTo() } } else { - store.dispatchNavigationAction { replaceAll(AppRoute.Home) } + store.dispatchNavigationAction { replaceAll(AppRoute.Home()) } } } } 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 deleted file mode 100644 index b89b6f5255..0000000000 --- a/app/src/main/java/com/tangem/tap/features/home/DefaultHomeComponent.kt +++ /dev/null @@ -1,90 +0,0 @@ -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.graphics.Color -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.ChangeRootBackgroundColorEffect -import com.tangem.core.ui.utils.findActivity -import com.tangem.features.hotwallet.HotWalletFeatureToggles -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.compose.StoriesScreenV2 -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, - private val hotWalletFeatureToggles: HotWalletFeatureToggles, -) : 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) - if (hotWalletFeatureToggles.isHotWalletEnabled) { - StoriesScreenV2( - homeState = homeState, - onCreateNewWalletButtonClick = model::onCreateNewWalletScreen, - onAddExistingWalletButtonClick = model::onAddExistingWalletScreen, - onScanButtonClick = model::onScanClick, - ) - } else { - StoriesScreen( - homeState = homeState, - onScanButtonClick = model::onScanClick, - onShopButtonClick = model::onShopClick, - onSearchTokensClick = model::onSearchClick, - ) - } - - ChangeRootBackgroundColorEffect(Color(color = 0xFF010101)) - } - - 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/HomeModel.kt b/app/src/main/java/com/tangem/tap/features/home/HomeModel.kt deleted file mode 100644 index 6110c7ff0c..0000000000 --- a/app/src/main/java/com/tangem/tap/features/home/HomeModel.kt +++ /dev/null @@ -1,166 +0,0 @@ -package com.tangem.tap.features.home - -import androidx.compose.runtime.Stable -import com.google.firebase.analytics.ktx.analytics -import com.google.firebase.ktx.Firebase -import com.tangem.common.routing.AppRoute -import com.tangem.common.routing.AppRoute.ManageTokens.Source -import com.tangem.core.analytics.Analytics -import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.core.analytics.models.Basic -import com.tangem.core.decompose.di.ModelScoped -import com.tangem.core.decompose.model.Model -import com.tangem.core.decompose.navigation.Router -import com.tangem.core.navigation.url.UrlOpener -import com.tangem.domain.card.ScanCardProcessor -import com.tangem.domain.card.repository.CardSdkConfigRepository -import com.tangem.domain.card.common.util.cardTypesResolver -import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.settings.repositories.SettingsRepository -import com.tangem.domain.settings.usercountry.GetUserCountryUseCase -import com.tangem.domain.settings.usercountry.models.UserCountry -import com.tangem.domain.tokens.TokensAction -import com.tangem.domain.wallets.builder.ColdUserWalletBuilder -import com.tangem.domain.wallets.usecase.SaveWalletUseCase -import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter -import com.tangem.tap.common.analytics.events.IntroductionProcess -import com.tangem.tap.common.analytics.events.Shop -import com.tangem.tap.common.extensions.dispatchNavigationAction -import com.tangem.tap.common.extensions.dispatchOnMain -import com.tangem.tap.common.extensions.dispatchWithMain -import com.tangem.tap.common.extensions.onUserWalletSelected -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 com.tangem.utils.coroutines.CoroutineDispatcherProvider -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.* -import kotlinx.coroutines.launch -import timber.log.Timber -import java.util.Locale -import javax.inject.Inject - -@Suppress("LongParameterList") -@Stable -@ModelScoped -internal class HomeModel @Inject constructor( - override val dispatchers: CoroutineDispatcherProvider, - private val scanCardProcessor: ScanCardProcessor, - private val saveWalletUseCase: SaveWalletUseCase, - private val cardSdkConfigRepository: CardSdkConfigRepository, - private val settingsRepository: SettingsRepository, - private val urlOpener: UrlOpener, - private val analyticsEventHandler: AnalyticsEventHandler, - private val coldUserWalletBuilderFactory: ColdUserWalletBuilder.Factory, - private val router: Router, - getUserCountryUseCase: GetUserCountryUseCase, -) : Model() { - - private val tangemErrorHandler = TangemTangemErrorsHandler(store) - - init { - getUserCountryUseCase.invoke() - .distinctUntilChanged() - .filterNotNull() - .onEach { - val userCountry = it.getOrNull() ?: UserCountry.Other(Locale.getDefault().country) - store.dispatchOnMain(HomeAction.UserCountryLoaded(userCountry)) - } - .flowOn(dispatchers.io) - .launchIn(modelScope) - } - - fun onCreateNewWalletScreen() { - router.push(AppRoute.CreateWalletSelection) - } - - fun onAddExistingWalletScreen() { - router.push(AppRoute.AddExistingWallet) - } - - fun onScanClick() { - analyticsEventHandler.send(IntroductionProcess.ButtonScanCard()) - scanCard() - } - - fun onShopClick() { - analyticsEventHandler.send(IntroductionProcess.ButtonBuyCards()) - analyticsEventHandler.send(Shop.ScreenOpened()) - - Firebase.analytics.appInstanceId - .addOnSuccessListener { urlOpener.openUrl(url = "$NEW_BUY_WALLET_URL&app_instance_id=$it") } - .addOnFailureListener { urlOpener.openUrl(url = NEW_BUY_WALLET_URL) } - } - - fun onSearchClick() { - analyticsEventHandler.send(IntroductionProcess.ButtonTokensList()) - - store.dispatch(TokensAction.SetArgs.ReadAccess) - store.dispatchNavigationAction { push(AppRoute.ManageTokens(Source.STORIES)) } - } - - private fun scanCard() { - modelScope.launch { - cardSdkConfigRepository.isBiometricsRequestPolicy = settingsRepository.shouldSaveAccessCodes() - - scanCardProcessor.scan( - analyticsSource = AnalyticsParam.ScreensSources.Intro, - onProgressStateChange = { showProgress -> - if (showProgress) { - store.dispatch(HomeAction.ScanInProgress(scanInProgress = true)) - } else { - delay(HIDE_PROGRESS_DELAY) - store.dispatch(HomeAction.ScanInProgress(scanInProgress = false)) - } - }, - onFailure = { - tangemErrorHandler.onErrorReceived(error = it) - delay(HIDE_PROGRESS_DELAY) - store.dispatch(HomeAction.ScanInProgress(scanInProgress = false)) - }, - onSuccess = ::proceedWithScanResponse, - ) - } - } - - private suspend fun proceedWithScanResponse(scanResponse: ScanResponse) { - val userWallet = coldUserWalletBuilderFactory.create(scanResponse = scanResponse).build() - - if (userWallet == null) { - Timber.e("User wallet not created") - return - } - - saveWalletUseCase(userWallet).fold( - ifLeft = { Timber.e(it.toString(), "Unable to save user wallet") }, - ifRight = { - sendSignedInCardAnalyticsEvent(scanResponse) - coroutineScope { store.onUserWalletSelected(userWallet = userWallet) } - }, - ) - - store.dispatchWithMain(HomeAction.ScanInProgress(scanInProgress = false)) - delay(HIDE_PROGRESS_DELAY) - - store.dispatchNavigationAction { replaceAll(AppRoute.Wallet) } - } - - private fun sendSignedInCardAnalyticsEvent(scanResponse: ScanResponse) { - val currency = ParamCardCurrencyConverter().convert(value = scanResponse.cardTypesResolver) - - if (currency != null) { - Analytics.send( - event = Basic.SignedIn( - currency = currency, - batch = scanResponse.card.batchId, - signInType = Basic.SignedIn.SignInType.Card, - walletsCount = "1", - hasBackup = scanResponse.card.backupStatus?.isActive, - ), - ) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/RegionProvider.kt b/app/src/main/java/com/tangem/tap/features/home/RegionProvider.kt deleted file mode 100644 index fb4ae25b2b..0000000000 --- a/app/src/main/java/com/tangem/tap/features/home/RegionProvider.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.tangem.tap.features.home - -import androidx.compose.ui.text.intl.Locale - -/** -[REDACTED_AUTHOR] - */ -interface RegionProvider { - fun getRegion(): String? -} - -class LocaleRegionProvider : RegionProvider { - override fun getRegion(): String = Locale.current.region -} - -const val RUSSIA_COUNTRY_CODE = "ru" \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/TangemTangemErrorsHandler.kt b/app/src/main/java/com/tangem/tap/features/home/TangemTangemErrorsHandler.kt deleted file mode 100644 index 40e51a8de8..0000000000 --- a/app/src/main/java/com/tangem/tap/features/home/TangemTangemErrorsHandler.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.tangem.tap.features.home - -import com.tangem.blockchain.common.BlockchainError -import com.tangem.common.core.TangemError -import com.tangem.common.core.TangemSdkError -import com.tangem.domain.redux.StateDialog -import com.tangem.tap.common.extensions.dispatchOnMain -import com.tangem.tap.common.redux.AppState -import com.tangem.tap.common.redux.global.GlobalAction -import com.tangem.tap.features.home.errors.TangemSdkErrorHandler -import org.rekotlin.Store -import timber.log.Timber - -class TangemTangemErrorsHandler(val store: Store) : TangemSdkErrorHandler { - - override fun onErrorReceived(error: TangemError) { - when (error) { - is TangemSdkError -> { - handleCardSdkError(error) - } - is BlockchainError -> { - handleBlockchainSdkError(error) - } - else -> { - Timber.e("Error happened", error) - } - } - } - - private fun handleCardSdkError(error: TangemSdkError) { - when (error) { - is TangemSdkError.NfcFeatureIsUnavailable -> { - store.dispatchOnMain(GlobalAction.ShowDialog(StateDialog.NfcFeatureIsUnavailable)) - } - else -> { - Timber.e(error, "Unable to scan card") - } - } - } - - private fun handleBlockchainSdkError(error: TangemError) { - Timber.e("Sdk error happened", error) - } -} \ No newline at end of file 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 deleted file mode 100644 index 0c63e10a1c..0000000000 --- a/app/src/main/java/com/tangem/tap/features/home/api/HomeComponent.kt +++ /dev/null @@ -1,9 +0,0 @@ -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 deleted file mode 100644 index 9f92cc5583..0000000000 --- a/app/src/main/java/com/tangem/tap/features/home/di/HomeFeatureModule.kt +++ /dev/null @@ -1,25 +0,0 @@ -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/features/home/errors/TangemSdkErrorHandler.kt b/app/src/main/java/com/tangem/tap/features/home/errors/TangemSdkErrorHandler.kt deleted file mode 100644 index 7946b7ec5e..0000000000 --- a/app/src/main/java/com/tangem/tap/features/home/errors/TangemSdkErrorHandler.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.tap.features.home.errors - -import com.tangem.common.core.TangemError - -interface TangemSdkErrorHandler { - - fun onErrorReceived(error: TangemError) -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt deleted file mode 100644 index 9a449e938e..0000000000 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.tap.features.home.redux - -import com.tangem.domain.settings.usercountry.models.UserCountry -import kotlinx.coroutines.CoroutineScope -import org.rekotlin.Action - -sealed class HomeAction : Action { - - data object OnCreate : HomeAction() - - /** - * Action for scanning card - * - * @property scope lifecycle scope. It will be canceled when lifecycle-aware component is destroyed - */ - data class ReadCard(val scope: CoroutineScope) : HomeAction() - - data class ScanInProgress(val scanInProgress: Boolean) : HomeAction() - - data class UserCountryLoaded(val userCountry: UserCountry) : HomeAction() -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt deleted file mode 100644 index e66b7f8c84..0000000000 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt +++ /dev/null @@ -1,147 +0,0 @@ -package com.tangem.tap.features.home.redux - -import android.content.res.Resources -import com.tangem.common.doOnFailure -import com.tangem.common.doOnResult -import com.tangem.common.doOnSuccess -import com.tangem.common.extensions.guard -import com.tangem.common.routing.AppRoute -import com.tangem.core.analytics.Analytics -import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.core.analytics.models.Basic -import com.tangem.domain.card.common.util.cardTypesResolver -import com.tangem.domain.models.scan.ScanResponse -import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter -import com.tangem.tap.common.analytics.events.IntroductionProcess -import com.tangem.tap.common.extensions.dispatchNavigationAction -import com.tangem.tap.common.extensions.eraseContext -import com.tangem.tap.common.extensions.inject -import com.tangem.tap.common.extensions.onUserWalletSelected -import com.tangem.tap.common.redux.AppState -import com.tangem.tap.common.redux.global.GlobalAction -import com.tangem.tap.proxy.redux.DaggerGraphState -import com.tangem.tap.scope -import com.tangem.tap.store -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import org.rekotlin.Action -import org.rekotlin.Middleware -import timber.log.Timber -import java.util.Locale - -internal const val HIDE_PROGRESS_DELAY = 400L - -object HomeMiddleware { - val handler = homeMiddleware - - private val SYSTEM_LANGUAGE = - runCatching { Resources.getSystem().configuration.locales[0].language }.getOrElse { "" } - private val APP_LANGUAGE = Locale.getDefault().language - private val UTM_MARKS = "utm_source=tangem-app" + - "&utm_medium=app" + - "&utm_campaign=prospect-$SYSTEM_LANGUAGE" + - "&utm_content=devicelang-$APP_LANGUAGE" - - val NEW_BUY_WALLET_URL = "https://buy.tangem.com/?$UTM_MARKS" -} - -private val homeMiddleware: Middleware = { _, _ -> - { next -> - { action -> - handleHomeAction(action) - next(action) - } - } -} - -private fun handleHomeAction(action: Action) { - when (action) { - is HomeAction.OnCreate -> { - Analytics.eraseContext() - Analytics.send(IntroductionProcess.ScreenOpened()) - - store.dispatch(GlobalAction.RestoreAppCurrency) - } - is HomeAction.ReadCard -> { - action.scope.launch { - readCard() - } - } - } -} - -private suspend fun readCard() { - val shouldSaveAccessCodes = store.inject(DaggerGraphState::settingsRepository).shouldSaveAccessCodes() - - store.inject(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy( - isBiometricsRequestPolicy = shouldSaveAccessCodes, - ) - - store.inject(DaggerGraphState::scanCardProcessor).scan( - analyticsSource = AnalyticsParam.ScreensSources.Intro, - onProgressStateChange = { showProgress -> - if (showProgress) { - store.dispatch(HomeAction.ScanInProgress(scanInProgress = true)) - } else { - delay(HIDE_PROGRESS_DELAY) - store.dispatch(HomeAction.ScanInProgress(scanInProgress = false)) - } - }, - onFailure = { - Timber.e(it, "Unable to scan card") - delay(HIDE_PROGRESS_DELAY) - store.dispatch(HomeAction.ScanInProgress(scanInProgress = false)) - }, - onSuccess = { scanResponse -> - proceedWithScanResponse(scanResponse) - }, - ) -} - -private fun proceedWithScanResponse(scanResponse: ScanResponse) = scope.launch { - val userWalletBuilder = store.inject(DaggerGraphState::coldUserWalletBuilderFactory).create(scanResponse) - - val userWallet = userWalletBuilder.build().guard { - Timber.e("User wallet not created") - return@launch - } - - val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager) - userWalletsListManager.save(userWallet) - .doOnFailure { error -> - Timber.e(error, "Unable to save user wallet") - } - .doOnSuccess { - sendSignedInCardAnalyticsEvent(scanResponse) - store.onUserWalletSelected(userWallet = userWallet) - } - .doOnResult { - navigateTo(AppRoute.Wallet) - } -} - -private fun sendSignedInCardAnalyticsEvent(scanResponse: ScanResponse) { - val currency = ParamCardCurrencyConverter().convert( - value = scanResponse.cardTypesResolver, - ) - - if (currency != null) { - val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager) - - Analytics.send( - event = Basic.SignedIn( - currency = currency, - batch = scanResponse.card.batchId, - signInType = Basic.SignedIn.SignInType.Card, - walletsCount = userWalletsListManager.walletsCount.toString(), - hasBackup = scanResponse.card.backupStatus?.isActive, - ), - ) - } -} - -private suspend fun navigateTo(route: AppRoute) { - store.dispatchNavigationAction { push(route) } - delay(HIDE_PROGRESS_DELAY) - store.dispatch(HomeAction.ScanInProgress(scanInProgress = false)) -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt deleted file mode 100644 index 678de45d76..0000000000 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.tangem.tap.features.home.redux - -import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions -import com.tangem.tap.common.redux.AppState -import kotlinx.collections.immutable.toImmutableList -import org.rekotlin.Action - -object HomeReducer { - fun reduce(action: Action, state: AppState): HomeState = internalReduce(action, state) -} - -private fun internalReduce(action: Action, appState: AppState): HomeState { - if (action !is HomeAction) return appState.homeState - - return when (action) { - is HomeAction.ScanInProgress -> { - appState.homeState.copy(scanInProgress = action.scanInProgress) - } - is HomeAction.UserCountryLoaded -> { - val stories = if (action.userCountry.needApplyFCARestrictions()) { - getRestrictedStories() - } else { - Stories.entries - } - appState.homeState.copy( - stories = stories.toImmutableList(), - ) - } - else -> appState.homeState - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/BackgroundScanIntentHandler.kt b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/BackgroundScanIntentHandler.kt index 90ef042a6b..766392b9dd 100644 --- a/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/BackgroundScanIntentHandler.kt +++ b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/BackgroundScanIntentHandler.kt @@ -4,21 +4,12 @@ import android.content.Intent import android.nfc.NfcAdapter import android.nfc.Tag import android.os.Build -import com.tangem.tap.common.extensions.dispatchOnMain -import com.tangem.tap.features.home.redux.HomeAction -import com.tangem.tap.features.intentHandler.IntentHandler -import com.tangem.tap.features.intentHandler.AffectsNavigation -import com.tangem.tap.features.welcome.redux.WelcomeAction -import com.tangem.tap.store -import kotlinx.coroutines.CoroutineScope +import com.tangem.common.routing.entity.InitScreenLaunchMode /** [REDACTED_AUTHOR] */ -class BackgroundScanIntentHandler( - private val hasSavedUserWalletsProvider: () -> Boolean, - private val scope: CoroutineScope, -) : IntentHandler, AffectsNavigation { +class BackgroundScanIntentHandler { private val nfcActions = arrayOf( NfcAdapter.ACTION_NDEF_DISCOVERED, @@ -26,8 +17,15 @@ class BackgroundScanIntentHandler( NfcAdapter.ACTION_TAG_DISCOVERED, ) - override fun handleIntent(intent: Intent?, isFromForeground: Boolean): Boolean { - if (isFromForeground) return true + fun getInitScreenLaunchMode(intent: Intent?): InitScreenLaunchMode { + return if (shouldOpenScanCard(intent)) { + InitScreenLaunchMode.WithCardScan + } else { + InitScreenLaunchMode.Standard + } + } + + private fun shouldOpenScanCard(intent: Intent?): Boolean { if (intent == null || intent.action !in nfcActions) return false val tag: Tag? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { @@ -36,15 +34,9 @@ class BackgroundScanIntentHandler( @Suppress("DEPRECATION") intent.getParcelableExtra(NfcAdapter.EXTRA_TAG) } - if (tag == null) return false intent.action = null - if (hasSavedUserWalletsProvider.invoke()) { - store.dispatchOnMain(WelcomeAction.ProceedWithCard) - } else { - store.dispatchOnMain(HomeAction.ReadCard(scope = scope)) - } - return true + return tag != null } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/WalletConnectLinkIntentHandler.kt b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/WalletConnectLinkIntentHandler.kt index 6f138c18e5..e715290a1e 100644 --- a/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/WalletConnectLinkIntentHandler.kt +++ b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/WalletConnectLinkIntentHandler.kt @@ -4,8 +4,8 @@ import android.content.Intent import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.removePrefixOrNull import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction -import com.tangem.tap.features.intentHandler.IntentHandler import com.tangem.tap.features.intentHandler.AffectsNavigation +import com.tangem.tap.features.intentHandler.IntentHandler import com.tangem.tap.store import timber.log.Timber import java.net.URLDecoder diff --git a/app/src/main/java/com/tangem/tap/features/welcome/component/WelcomeComponent.kt b/app/src/main/java/com/tangem/tap/features/welcome/component/WelcomeComponent.kt index 07a92373e1..215560a1ad 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/component/WelcomeComponent.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/component/WelcomeComponent.kt @@ -1,5 +1,6 @@ package com.tangem.tap.features.welcome.component +import com.tangem.common.routing.entity.InitScreenLaunchMode import com.tangem.common.routing.entity.SerializableIntent import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.ui.decompose.ComposableContentComponent @@ -7,6 +8,7 @@ import com.tangem.core.ui.decompose.ComposableContentComponent interface WelcomeComponent : ComposableContentComponent { data class Params( + val launchMode: InitScreenLaunchMode, val intent: SerializableIntent?, ) diff --git a/app/src/main/java/com/tangem/tap/features/welcome/model/WelcomeModel.kt b/app/src/main/java/com/tangem/tap/features/welcome/model/WelcomeModel.kt index 8b1dc10be1..5965f011f3 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/model/WelcomeModel.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/model/WelcomeModel.kt @@ -1,6 +1,7 @@ package com.tangem.tap.features.welcome.model import com.tangem.common.core.TangemError +import com.tangem.common.routing.entity.InitScreenLaunchMode import com.tangem.core.analytics.Analytics import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model @@ -44,10 +45,9 @@ internal class WelcomeModel @Inject constructor( subscribeToStoreChanges() initGlobalState() - val welcomeAction = if (params.intent != null) { - WelcomeAction.ProceedWithIntent(params.intent.toIntent()) - } else { - WelcomeAction.ProceedWithBiometrics() + val welcomeAction = when (params.launchMode) { + is InitScreenLaunchMode.WithCardScan -> WelcomeAction.ProceedWithCard + is InitScreenLaunchMode.Standard -> WelcomeAction.ProceedWithBiometrics(params.intent?.toIntent()) } store.dispatch(welcomeAction) diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt index ebbc8b2fc6..15c1ace4f6 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt @@ -20,10 +20,8 @@ import com.tangem.tap.* import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter import com.tangem.tap.common.extensions.* import com.tangem.tap.common.redux.AppState -import com.tangem.tap.features.intentHandler.handlers.BackgroundScanIntentHandler import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler import com.tangem.tap.proxy.redux.DaggerGraphState -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.rekotlin.Middleware import timber.log.Timber @@ -44,7 +42,7 @@ internal class WelcomeMiddleware { private fun handleAction(action: WelcomeAction, state: WelcomeState) { mainScope.launch { when (action) { - is WelcomeAction.ProceedWithIntent -> proceedWithIntent(action.intent, scope = this) + is WelcomeAction.ProceedWithIntent -> proceedWithIntent(action.intent) is WelcomeAction.ProceedWithBiometrics -> proceedWithBiometrics( afterUnlockIntent = action.afterUnlockIntent ?: state.intent, ) @@ -55,7 +53,7 @@ internal class WelcomeMiddleware { } } - private suspend fun proceedWithIntent(initialIntent: Intent, scope: CoroutineScope) { + private suspend fun proceedWithIntent(initialIntent: Intent) { Timber.d( """ Proceeding with intent @@ -63,15 +61,12 @@ internal class WelcomeMiddleware { """.trimIndent(), ) - val handler = BackgroundScanIntentHandler( - scope = scope, - hasSavedUserWalletsProvider = { true }, - ) - val isBackgroundScanHandled = handler.handleIntent(initialIntent, isFromForeground = false) val hasUncompletedBackup = backupService.hasIncompletedBackup - if (!isBackgroundScanHandled && !hasUncompletedBackup) { + if (!hasUncompletedBackup) { store.dispatchWithMain(WelcomeAction.ProceedWithBiometrics(initialIntent)) + } else { + store.dispatchWithMain(WelcomeAction.ProceedWithCard) } } 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 894658edf5..9ecfe8e5c6 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 @@ -40,7 +40,7 @@ import com.tangem.tap.features.details.ui.cardsettings.coderecovery.api.AccessCo 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.features.home.api.HomeComponent import com.tangem.tap.features.welcome.component.WelcomeComponent import com.tangem.tap.routing.component.RoutingComponent.Child import dagger.hilt.android.scopes.ActivityScoped @@ -131,6 +131,7 @@ internal class ChildFactory @Inject constructor( createComponentChild( context = context, params = WelcomeComponent.Params( + launchMode = route.launchMode, intent = route.intent, ), componentFactory = welcomeComponentFactory, @@ -288,7 +289,7 @@ internal class ChildFactory @Inject constructor( is AppRoute.Home -> { createComponentChild( context = context, - params = Unit, + params = HomeComponent.Params(route.launchMode), componentFactory = homeComponentFactory, ) } @@ -380,7 +381,7 @@ internal class ChildFactory @Inject constructor( is AppRoute.PushNotification -> { createComponentChild( context = context, - params = PushNotificationsComponent.Params.Route(AppRoute.Home), + params = PushNotificationsComponent.Params.Route(AppRoute.Home()), componentFactory = pushNotificationsComponentFactory, ) } 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 77a7b1f113..d1afb593f0 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 @@ -3,6 +3,7 @@ package com.tangem.common.routing import android.os.Bundle import com.tangem.common.routing.bundle.RouteBundleParams import com.tangem.common.routing.bundle.bundle +import com.tangem.common.routing.entity.InitScreenLaunchMode import com.tangem.common.routing.entity.SerializableIntent import com.tangem.core.decompose.navigation.Route import com.tangem.domain.appcurrency.model.AppCurrency @@ -22,10 +23,14 @@ sealed class AppRoute(val path: String) : Route { data object Initial : AppRoute(path = "/initial") @Serializable - data object Home : AppRoute(path = "/home") + data class Home( + val launchMode: InitScreenLaunchMode = InitScreenLaunchMode.Standard, + ) : AppRoute(path = "/home") @Serializable data class Welcome( + val launchMode: InitScreenLaunchMode = InitScreenLaunchMode.Standard, + // we still have this param to be handled by WalletConnectLinkIntentHandler in WelcomeMiddleware val intent: SerializableIntent? = null, ) : AppRoute(path = "/welcome"), RouteBundleParams { diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/entity/InitScreenLaunchMode.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/entity/InitScreenLaunchMode.kt new file mode 100644 index 0000000000..3e1e008994 --- /dev/null +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/entity/InitScreenLaunchMode.kt @@ -0,0 +1,13 @@ +package com.tangem.common.routing.entity + +import kotlinx.serialization.Serializable + +@Serializable +sealed class InitScreenLaunchMode { + + @Serializable + data object Standard : InitScreenLaunchMode() + + @Serializable + data object WithCardScan : InitScreenLaunchMode() +} \ No newline at end of file diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/entity/SerializableIntent.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/entity/SerializableIntent.kt index 38ef6f2096..cb4f2b871a 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/entity/SerializableIntent.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/entity/SerializableIntent.kt @@ -14,6 +14,7 @@ data class SerializableIntent( val packageValue: String?, val component: String?, val flags: Int, + // CAUTION: works wrong with SerializableBundle constructor(bundle: Bundle), need to be removed val extras: SerializableBundle?, ) { diff --git a/app/src/main/java/com/tangem/tap/common/compose/extensions/AnimatedValue.kt b/core/ui/src/main/java/com/tangem/core/ui/utils/AnimatedValue.kt similarity index 96% rename from app/src/main/java/com/tangem/tap/common/compose/extensions/AnimatedValue.kt rename to core/ui/src/main/java/com/tangem/core/ui/utils/AnimatedValue.kt index b21726c8e7..20ba1ea49a 100644 --- a/app/src/main/java/com/tangem/tap/common/compose/extensions/AnimatedValue.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/utils/AnimatedValue.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.common.compose.extensions +package com.tangem.core.ui.utils import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.AnimationVector1D diff --git a/core/ui/src/main/java/com/tangem/core/ui/utils/DensityUtils.kt b/core/ui/src/main/java/com/tangem/core/ui/utils/DensityUtils.kt index 105d2416d3..0a3bb10329 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/utils/DensityUtils.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/utils/DensityUtils.kt @@ -1,9 +1,15 @@ package com.tangem.core.ui.utils +import android.content.Context import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import kotlin.math.roundToInt @Stable @Composable @@ -15,4 +21,16 @@ fun convertPxToDp(px: Float): Dp = convertPxToDp(px, density = LocalDensity.curr fun Dp.toPx(density: Float): Float = this.value * density -fun convertPxToDp(px: Float, density: Float): Dp = Dp(value = px / density) \ No newline at end of file +fun convertPxToDp(px: Float, density: Float): Dp = Dp(value = px / density) + +fun Context.dpToPx(dp: Float): Float = dp * resources.displayMetrics.density +fun Context.pxToDp(px: Float): Float = (px / resources.displayMetrics.density).roundToInt().toFloat() + +@Composable +fun Painter.dpSize(): DpSize = DpSize( + intrinsicSize.width.pxToDp().dp, + intrinsicSize.height.pxToDp().dp, +) + +@Composable +private fun Float.pxToDp(): Float = LocalContext.current.pxToDp(this) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/compose/extensions/ImageBitmap.kt b/core/ui/src/main/java/com/tangem/core/ui/utils/ImageBitmap.kt similarity index 92% rename from app/src/main/java/com/tangem/tap/common/compose/extensions/ImageBitmap.kt rename to core/ui/src/main/java/com/tangem/core/ui/utils/ImageBitmap.kt index 99911d9e6f..4f4cff9559 100644 --- a/app/src/main/java/com/tangem/tap/common/compose/extensions/ImageBitmap.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/utils/ImageBitmap.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.common.compose.extensions +package com.tangem.core.ui.utils import androidx.annotation.DrawableRes import androidx.appcompat.content.res.AppCompatResources diff --git a/app/src/main/res/drawable-hdpi/img_meet_tangem.webp b/core/ui/src/main/res/drawable-hdpi/img_meet_tangem.webp similarity index 100% rename from app/src/main/res/drawable-hdpi/img_meet_tangem.webp rename to core/ui/src/main/res/drawable-hdpi/img_meet_tangem.webp diff --git a/app/src/main/res/drawable-hdpi/img_revolutionary_wallet.webp b/core/ui/src/main/res/drawable-hdpi/img_revolutionary_wallet.webp similarity index 100% rename from app/src/main/res/drawable-hdpi/img_revolutionary_wallet.webp rename to core/ui/src/main/res/drawable-hdpi/img_revolutionary_wallet.webp diff --git a/app/src/main/res/drawable-hdpi/img_tangem_for_everyone.webp b/core/ui/src/main/res/drawable-hdpi/img_tangem_for_everyone.webp similarity index 100% rename from app/src/main/res/drawable-hdpi/img_tangem_for_everyone.webp rename to core/ui/src/main/res/drawable-hdpi/img_tangem_for_everyone.webp diff --git a/app/src/main/res/drawable-mdpi/img_meet_tangem.webp b/core/ui/src/main/res/drawable-mdpi/img_meet_tangem.webp similarity index 100% rename from app/src/main/res/drawable-mdpi/img_meet_tangem.webp rename to core/ui/src/main/res/drawable-mdpi/img_meet_tangem.webp diff --git a/app/src/main/res/drawable-mdpi/img_revolutionary_wallet.webp b/core/ui/src/main/res/drawable-mdpi/img_revolutionary_wallet.webp similarity index 100% rename from app/src/main/res/drawable-mdpi/img_revolutionary_wallet.webp rename to core/ui/src/main/res/drawable-mdpi/img_revolutionary_wallet.webp diff --git a/app/src/main/res/drawable-mdpi/img_tangem_for_everyone.webp b/core/ui/src/main/res/drawable-mdpi/img_tangem_for_everyone.webp similarity index 100% rename from app/src/main/res/drawable-mdpi/img_tangem_for_everyone.webp rename to core/ui/src/main/res/drawable-mdpi/img_tangem_for_everyone.webp diff --git a/app/src/main/res/drawable-xhdpi/img_meet_tangem.webp b/core/ui/src/main/res/drawable-xhdpi/img_meet_tangem.webp similarity index 100% rename from app/src/main/res/drawable-xhdpi/img_meet_tangem.webp rename to core/ui/src/main/res/drawable-xhdpi/img_meet_tangem.webp diff --git a/app/src/main/res/drawable-xhdpi/img_revolutionary_wallet.webp b/core/ui/src/main/res/drawable-xhdpi/img_revolutionary_wallet.webp similarity index 100% rename from app/src/main/res/drawable-xhdpi/img_revolutionary_wallet.webp rename to core/ui/src/main/res/drawable-xhdpi/img_revolutionary_wallet.webp diff --git a/app/src/main/res/drawable-xhdpi/img_tangem_for_everyone.webp b/core/ui/src/main/res/drawable-xhdpi/img_tangem_for_everyone.webp similarity index 100% rename from app/src/main/res/drawable-xhdpi/img_tangem_for_everyone.webp rename to core/ui/src/main/res/drawable-xhdpi/img_tangem_for_everyone.webp diff --git a/app/src/main/res/drawable-xxhdpi/img_meet_tangem.webp b/core/ui/src/main/res/drawable-xxhdpi/img_meet_tangem.webp similarity index 100% rename from app/src/main/res/drawable-xxhdpi/img_meet_tangem.webp rename to core/ui/src/main/res/drawable-xxhdpi/img_meet_tangem.webp diff --git a/app/src/main/res/drawable-xxhdpi/img_revolutionary_wallet.webp b/core/ui/src/main/res/drawable-xxhdpi/img_revolutionary_wallet.webp similarity index 100% rename from app/src/main/res/drawable-xxhdpi/img_revolutionary_wallet.webp rename to core/ui/src/main/res/drawable-xxhdpi/img_revolutionary_wallet.webp diff --git a/app/src/main/res/drawable-xxhdpi/img_tangem_for_everyone.webp b/core/ui/src/main/res/drawable-xxhdpi/img_tangem_for_everyone.webp similarity index 100% rename from app/src/main/res/drawable-xxhdpi/img_tangem_for_everyone.webp rename to core/ui/src/main/res/drawable-xxhdpi/img_tangem_for_everyone.webp diff --git a/app/src/main/res/drawable-xxxhdpi/img_meet_tangem.webp b/core/ui/src/main/res/drawable-xxxhdpi/img_meet_tangem.webp similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/img_meet_tangem.webp rename to core/ui/src/main/res/drawable-xxxhdpi/img_meet_tangem.webp diff --git a/app/src/main/res/drawable-xxxhdpi/img_revolutionary_wallet.webp b/core/ui/src/main/res/drawable-xxxhdpi/img_revolutionary_wallet.webp similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/img_revolutionary_wallet.webp rename to core/ui/src/main/res/drawable-xxxhdpi/img_revolutionary_wallet.webp diff --git a/app/src/main/res/drawable-xxxhdpi/img_tangem_for_everyone.webp b/core/ui/src/main/res/drawable-xxxhdpi/img_tangem_for_everyone.webp similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/img_tangem_for_everyone.webp rename to core/ui/src/main/res/drawable-xxxhdpi/img_tangem_for_everyone.webp diff --git a/app/src/main/res/drawable/currency0.webp b/core/ui/src/main/res/drawable/currency0.webp similarity index 100% rename from app/src/main/res/drawable/currency0.webp rename to core/ui/src/main/res/drawable/currency0.webp diff --git a/app/src/main/res/drawable/currency1.webp b/core/ui/src/main/res/drawable/currency1.webp similarity index 100% rename from app/src/main/res/drawable/currency1.webp rename to core/ui/src/main/res/drawable/currency1.webp diff --git a/app/src/main/res/drawable/currency2.webp b/core/ui/src/main/res/drawable/currency2.webp similarity index 100% rename from app/src/main/res/drawable/currency2.webp rename to core/ui/src/main/res/drawable/currency2.webp diff --git a/app/src/main/res/drawable/currency3.webp b/core/ui/src/main/res/drawable/currency3.webp similarity index 100% rename from app/src/main/res/drawable/currency3.webp rename to core/ui/src/main/res/drawable/currency3.webp diff --git a/app/src/main/res/drawable/currency4.webp b/core/ui/src/main/res/drawable/currency4.webp similarity index 100% rename from app/src/main/res/drawable/currency4.webp rename to core/ui/src/main/res/drawable/currency4.webp diff --git a/app/src/main/res/drawable/dapps1.webp b/core/ui/src/main/res/drawable/dapps1.webp similarity index 100% rename from app/src/main/res/drawable/dapps1.webp rename to core/ui/src/main/res/drawable/dapps1.webp diff --git a/app/src/main/res/drawable/dapps2.webp b/core/ui/src/main/res/drawable/dapps2.webp similarity index 100% rename from app/src/main/res/drawable/dapps2.webp rename to core/ui/src/main/res/drawable/dapps2.webp diff --git a/app/src/main/res/drawable/dapps3.webp b/core/ui/src/main/res/drawable/dapps3.webp similarity index 100% rename from app/src/main/res/drawable/dapps3.webp rename to core/ui/src/main/res/drawable/dapps3.webp diff --git a/app/src/main/res/drawable/dapps4.webp b/core/ui/src/main/res/drawable/dapps4.webp similarity index 100% rename from app/src/main/res/drawable/dapps4.webp rename to core/ui/src/main/res/drawable/dapps4.webp diff --git a/app/src/main/res/drawable/dapps5.webp b/core/ui/src/main/res/drawable/dapps5.webp similarity index 100% rename from app/src/main/res/drawable/dapps5.webp rename to core/ui/src/main/res/drawable/dapps5.webp diff --git a/app/src/main/res/drawable/ic_tangem_logo.xml b/core/ui/src/main/res/drawable/ic_tangem_logo.xml similarity index 100% rename from app/src/main/res/drawable/ic_tangem_logo.xml rename to core/ui/src/main/res/drawable/ic_tangem_logo.xml diff --git a/app/src/main/res/drawable/img_card_placeholder_wallet_2.webp b/core/ui/src/main/res/drawable/img_card_placeholder_wallet_2.webp similarity index 100% rename from app/src/main/res/drawable/img_card_placeholder_wallet_2.webp rename to core/ui/src/main/res/drawable/img_card_placeholder_wallet_2.webp diff --git a/core/utils/src/main/java/com/tangem/utils/extensions/Int.kt b/core/utils/src/main/java/com/tangem/utils/extensions/Int.kt deleted file mode 100644 index 357b26203c..0000000000 --- a/core/utils/src/main/java/com/tangem/utils/extensions/Int.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.tangem.utils.extensions - -/** -[REDACTED_AUTHOR] - */ -fun Int.isEven(): Boolean = this % 2 == 0 \ No newline at end of file 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 f96cb66625..1ea5597638 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 @@ -51,7 +51,7 @@ internal class DisclaimerModel @Inject constructor( } else { neverToInitiallyAskPermissionUseCase(PUSH_PERMISSION) neverRequestPermissionUseCase(PUSH_PERMISSION) - router.replaceAll(AppRoute.Home) + router.replaceAll(AppRoute.Home()) } } } diff --git a/features/home/api/.gitignore b/features/home/api/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/features/home/api/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/features/home/api/build.gradle.kts b/features/home/api/build.gradle.kts new file mode 100644 index 0000000000..7f07d748d7 --- /dev/null +++ b/features/home/api/build.gradle.kts @@ -0,0 +1,17 @@ +plugins { + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) + id("configuration") +} + +android { + namespace = "com.tangem.features.home.api" +} + +dependencies { + implementation(projects.core.decompose) + implementation(projects.core.ui) + + /** Common */ + implementation(projects.common.routing) +} \ No newline at end of file diff --git a/features/home/api/src/main/kotlin/com/tangem/features/home/api/HomeComponent.kt b/features/home/api/src/main/kotlin/com/tangem/features/home/api/HomeComponent.kt new file mode 100644 index 0000000000..05a94c2090 --- /dev/null +++ b/features/home/api/src/main/kotlin/com/tangem/features/home/api/HomeComponent.kt @@ -0,0 +1,17 @@ +package com.tangem.features.home.api + +import com.tangem.common.routing.entity.InitScreenLaunchMode +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.decompose.factory.ComponentFactory +import com.tangem.core.ui.decompose.ComposableContentComponent + +interface HomeComponent : ComposableContentComponent { + + data class Params( + val launchMode: InitScreenLaunchMode = InitScreenLaunchMode.Standard, + ) + + interface Factory : ComponentFactory { + override fun create(context: AppComponentContext, params: Params): HomeComponent + } +} \ No newline at end of file diff --git a/features/home/impl/.gitignore b/features/home/impl/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/features/home/impl/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/features/home/impl/build.gradle.kts b/features/home/impl/build.gradle.kts new file mode 100644 index 0000000000..4a4f17d3bf --- /dev/null +++ b/features/home/impl/build.gradle.kts @@ -0,0 +1,69 @@ +plugins { + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) + alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.hilt.android) + id("configuration") +} + +android { + namespace = "com.tangem.features.home.impl" +} + +dependencies { + /** Api */ + implementation(projects.features.home.api) + implementation(projects.features.hotWallet.api) + + /** Core modules */ + implementation(projects.core.decompose) + implementation(projects.core.ui) + implementation(projects.core.res) + implementation(projects.core.analytics) + implementation(projects.core.analytics.models) + implementation(projects.core.navigation) + + /** Common */ + implementation(projects.common.routing) + + /** Domain */ + implementation(projects.domain.models) + implementation(projects.domain.core) + implementation(projects.domain.card) + implementation(projects.domain.settings) + implementation(projects.domain.tokens) + implementation(projects.domain.wallets) + implementation(projects.domain.wallets.models) + implementation(projects.domain.legacy) + implementation(projects.domain.feedback) + implementation(projects.domain.feedback.models) + + /** AndroidX libraries */ + implementation(deps.androidx.activity.compose) + implementation(deps.lifecycle.runtime.ktx) + + /** Compose libraries */ + implementation(deps.compose.ui) + implementation(deps.compose.ui.tooling) + implementation(deps.compose.foundation) + implementation(deps.compose.material3) + implementation(deps.compose.animation) + implementation(deps.compose.coil) + implementation(deps.decompose.ext.compose) + + /** Firebase */ + implementation(deps.firebase.analytics) + + /** Tangem libraries */ + implementation(tangemDeps.card.android) + implementation(tangemDeps.card.core) + implementation(tangemDeps.blockchain) + + /** Other libraries */ + implementation(deps.kotlin.immutable.collections) + implementation(deps.timber) + + /** DI */ + implementation(deps.hilt.android) + kapt(deps.hilt.kapt) +} \ No newline at end of file diff --git a/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/DefaultHomeComponent.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/DefaultHomeComponent.kt new file mode 100644 index 0000000000..7c210b9af7 --- /dev/null +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/DefaultHomeComponent.kt @@ -0,0 +1,40 @@ +package com.tangem.features.home.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.home.api.HomeComponent +import com.tangem.features.home.impl.model.HomeModel +import com.tangem.features.home.impl.ui.Home +import com.tangem.features.hotwallet.HotWalletFeatureToggles +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +internal class DefaultHomeComponent @AssistedInject constructor( + @Assisted appComponentContext: AppComponentContext, + @Assisted params: HomeComponent.Params, + private val hotWalletFeatureToggles: HotWalletFeatureToggles, +) : HomeComponent, AppComponentContext by appComponentContext { + + private val model: HomeModel = getOrCreateModel(params) + + @Composable + override fun Content(modifier: Modifier) { + val state by model.uiState.collectAsStateWithLifecycle() + + Home( + state = state, + modifier = modifier, + isV2StoriesEnabled = hotWalletFeatureToggles.isHotWalletEnabled, + ) + } + + @AssistedFactory + interface Factory : HomeComponent.Factory { + override fun create(context: AppComponentContext, params: HomeComponent.Params): DefaultHomeComponent + } +} \ No newline at end of file diff --git a/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/analytics/AnalyticsParam.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/analytics/AnalyticsParam.kt new file mode 100644 index 0000000000..def2ff2645 --- /dev/null +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/analytics/AnalyticsParam.kt @@ -0,0 +1,9 @@ +package com.tangem.features.home.impl.analytics + +internal sealed class AnalyticsParam { + + sealed class CurrencyType(val value: String) { + class Blockchain(blockchain: com.tangem.blockchain.common.Blockchain) : CurrencyType(blockchain.currency) + class Token(token: com.tangem.blockchain.common.Token) : CurrencyType(token.symbol) + } +} \ No newline at end of file diff --git a/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/analytics/IntroductionProcess.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/analytics/IntroductionProcess.kt new file mode 100644 index 0000000000..6115389bfd --- /dev/null +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/analytics/IntroductionProcess.kt @@ -0,0 +1,14 @@ +package com.tangem.features.home.impl.analytics + +import com.tangem.core.analytics.models.AnalyticsEvent + +sealed class IntroductionProcess( + event: String, + params: Map = mapOf(), +) : AnalyticsEvent("Introduction Process", event, params) { + + object ScreenOpened : IntroductionProcess("Introduction Process Screen Opened") + object ButtonTokensList : IntroductionProcess("Button - Tokens List") + object ButtonBuyCards : IntroductionProcess("Button - Buy Cards") + object ButtonScanCard : IntroductionProcess("Button - Scan Card") +} \ No newline at end of file diff --git a/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/analytics/ParamCardCurrencyConverter.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/analytics/ParamCardCurrencyConverter.kt new file mode 100644 index 0000000000..16c104323b --- /dev/null +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/analytics/ParamCardCurrencyConverter.kt @@ -0,0 +1,23 @@ +package com.tangem.features.home.impl.analytics + +import com.tangem.blockchain.common.Blockchain +import com.tangem.domain.card.CardTypesResolver +import com.tangem.utils.converter.Converter +import com.tangem.core.analytics.models.AnalyticsParam as CoreAnalyticsParam + +internal class ParamCardCurrencyConverter : Converter { + + override fun convert(value: CardTypesResolver): CoreAnalyticsParam.WalletType? { + if (value.isMultiwalletAllowed()) return CoreAnalyticsParam.WalletType.MultiCurrency + + val type = when { + value.isTangemNote() -> AnalyticsParam.CurrencyType.Blockchain(value.getBlockchain()) + value.isTangemTwins() -> AnalyticsParam.CurrencyType.Blockchain(Blockchain.Bitcoin) + value.getBlockchain() != Blockchain.Unknown -> AnalyticsParam.CurrencyType.Blockchain(value.getBlockchain()) + value.getPrimaryToken() != null -> AnalyticsParam.CurrencyType.Token(value.getPrimaryToken()!!) + else -> null + } ?: return null + + return CoreAnalyticsParam.WalletType.SingleCurrency(type.value) + } +} \ No newline at end of file diff --git a/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/analytics/Shop.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/analytics/Shop.kt new file mode 100644 index 0000000000..632cc66ef2 --- /dev/null +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/analytics/Shop.kt @@ -0,0 +1,11 @@ +package com.tangem.features.home.impl.analytics + +import com.tangem.core.analytics.models.AnalyticsEvent + +internal sealed class Shop( + event: String, + params: Map = mapOf(), +) : AnalyticsEvent("Shop", event, params) { + + object ScreenOpened : Shop("Shop Screen Opened") +} \ No newline at end of file diff --git a/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/di/HomeFeatureModule.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/di/HomeFeatureModule.kt new file mode 100644 index 0000000000..cb6516bc9b --- /dev/null +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/di/HomeFeatureModule.kt @@ -0,0 +1,33 @@ +package com.tangem.features.home.impl.di + +import com.tangem.core.decompose.di.ModelComponent +import com.tangem.core.decompose.model.Model +import com.tangem.features.home.api.HomeComponent +import com.tangem.features.home.impl.DefaultHomeComponent +import com.tangem.features.home.impl.model.HomeModel +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal interface ComponentModule { + + @Binds + @Singleton + fun bindComponent(factory: DefaultHomeComponent.Factory): HomeComponent.Factory +} + +@Module +@InstallIn(ModelComponent::class) +internal interface ModelModule { + + @Binds + @IntoMap + @ClassKey(HomeModel::class) + fun provideModel(model: HomeModel): Model +} \ No newline at end of file diff --git a/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/model/HomeModel.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/model/HomeModel.kt new file mode 100644 index 0000000000..61614e3a62 --- /dev/null +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/model/HomeModel.kt @@ -0,0 +1,268 @@ +package com.tangem.features.home.impl.model + +import com.google.firebase.analytics.ktx.analytics +import com.google.firebase.ktx.Firebase +import com.tangem.common.core.TangemError +import com.tangem.common.core.TangemSdkError +import com.tangem.common.routing.AppRoute +import com.tangem.common.routing.AppRoute.ManageTokens.Source +import com.tangem.common.routing.AppRouter +import com.tangem.common.routing.entity.InitScreenLaunchMode +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.analytics.models.Basic.SignedIn +import com.tangem.core.analytics.models.Basic.SignedIn.SignInType +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.navigation.Router +import com.tangem.core.decompose.ui.UiMessageSender +import com.tangem.core.navigation.url.UrlOpener +import com.tangem.core.ui.R +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.message.DialogMessage +import com.tangem.domain.card.ScanCardProcessor +import com.tangem.domain.card.common.util.cardTypesResolver +import com.tangem.domain.card.repository.CardSdkConfigRepository +import com.tangem.domain.models.scan.ScanResponse +import com.tangem.domain.settings.repositories.SettingsRepository +import com.tangem.domain.settings.usercountry.GetUserCountryUseCase +import com.tangem.domain.settings.usercountry.models.UserCountry +import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions +import com.tangem.domain.wallets.builder.ColdUserWalletBuilder +import com.tangem.domain.wallets.usecase.SaveWalletUseCase +import com.tangem.domain.wallets.usecase.SelectWalletUseCase +import com.tangem.features.home.api.HomeComponent +import com.tangem.features.home.impl.analytics.IntroductionProcess +import com.tangem.features.home.impl.analytics.ParamCardCurrencyConverter +import com.tangem.features.home.impl.analytics.Shop +import com.tangem.features.home.impl.ui.state.HomeUM +import com.tangem.features.home.impl.ui.state.Stories +import com.tangem.features.home.impl.ui.state.getRestrictedStories +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import timber.log.Timber +import java.util.Locale +import javax.inject.Inject + +private const val HIDE_PROGRESS_DELAY = 400L + +@Suppress("LongParameterList") +@ModelScoped +internal class HomeModel @Inject constructor( + paramsContainer: ParamsContainer, + override val dispatchers: CoroutineDispatcherProvider, + private val scanCardProcessor: ScanCardProcessor, + private val saveWalletUseCase: SaveWalletUseCase, + private val cardSdkConfigRepository: CardSdkConfigRepository, + private val settingsRepository: SettingsRepository, + private val urlOpener: UrlOpener, + private val analyticsEventHandler: AnalyticsEventHandler, + private val coldUserWalletBuilderFactory: ColdUserWalletBuilder.Factory, + private val router: Router, + private val selectWalletUseCase: SelectWalletUseCase, + private val appRouter: AppRouter, + private val getUserCountryUseCase: GetUserCountryUseCase, + @GlobalUiMessageSender private val uiMessageSender: UiMessageSender, +) : Model() { + + val params = paramsContainer.require() + + private val _uiState = MutableStateFlow( + HomeUM( + scanInProgress = false, + stories = getRestrictedStories().toImmutableList(), + onScanClick = ::onScanClick, + onShopClick = ::onShopClick, + onSearchTokensClick = ::onSearchTokensClick, + onCreateNewWalletClick = ::onCreateNewWalletClick, + onAddExistingWalletClick = ::onAddExistingWalletClick, + ), + ) + + val uiState = _uiState.asStateFlow() + + init { + analyticsEventHandler.send(IntroductionProcess.ScreenOpened) + observeUserCountryChanges() + + when (params.launchMode) { + InitScreenLaunchMode.Standard -> Unit + InitScreenLaunchMode.WithCardScan -> scanCard() + } + } + + private fun observeUserCountryChanges() { + getUserCountryUseCase.invoke() + .distinctUntilChanged() + .filterNotNull() + .onEach { result -> + val userCountry = result.getOrNull() ?: UserCountry.Other(Locale.getDefault().country) + updateStoriesForCountry(userCountry) + } + .flowOn(dispatchers.io) + .launchIn(modelScope) + } + + private fun updateStoriesForCountry(userCountry: UserCountry) { + val stories = if (userCountry.needApplyFCARestrictions()) { + getRestrictedStories() + } else { + Stories.entries + } + + _uiState.update { + it.copy(stories = stories.toImmutableList()) + } + } + + private fun onScanClick() { + analyticsEventHandler.send(IntroductionProcess.ButtonScanCard) + scanCard() + } + + private fun onShopClick() { + analyticsEventHandler.send(IntroductionProcess.ButtonBuyCards) + analyticsEventHandler.send(Shop.ScreenOpened) + + Firebase.analytics.appInstanceId + .addOnSuccessListener { urlOpener.openUrl(url = "$NEW_BUY_WALLET_URL&app_instance_id=$it") } + .addOnFailureListener { urlOpener.openUrl(url = NEW_BUY_WALLET_URL) } + } + + private fun onSearchTokensClick() { + analyticsEventHandler.send(IntroductionProcess.ButtonTokensList) + router.push(AppRoute.ManageTokens(Source.STORIES)) + } + + private fun onCreateNewWalletClick() { + router.push(AppRoute.CreateWalletSelection) + } + + private fun onAddExistingWalletClick() { + router.push(AppRoute.AddExistingWallet) + } + + private fun scanCard() { + modelScope.launch { + setLoading(true) + + val shouldSaveAccessCodes = settingsRepository.shouldSaveAccessCodes() + cardSdkConfigRepository.setAccessCodeRequestPolicy( + isBiometricsRequestPolicy = shouldSaveAccessCodes, + ) + + val analyticsSource = AnalyticsParam.ScreensSources.Intro + + scanCardProcessor.scan( + analyticsSource = analyticsSource, + onProgressStateChange = { showProgress -> + if (!showProgress) { + delay(HIDE_PROGRESS_DELAY) + setLoading(false) + } else { + setLoading(true) + } + }, + onFailure = { error -> + handleScanError(error) + delay(HIDE_PROGRESS_DELAY) + setLoading(false) + }, + onSuccess = { scanResponse -> + proceedWithScanResponse(scanResponse) + }, + ) + } + } + + private suspend fun proceedWithScanResponse(scanResponse: ScanResponse) { + val userWallet = coldUserWalletBuilderFactory.create(scanResponse = scanResponse).build() + + if (userWallet == null) { + Timber.e("User wallet not created") + setLoading(false) + return + } + + saveWalletUseCase(userWallet).fold( + ifLeft = { + Timber.e(it.toString(), "Unable to save user wallet") + setLoading(false) + }, + ifRight = { + sendSignedInCardAnalyticsEvent(scanResponse) + + // Select the wallet using new mechanism + selectWalletUseCase(userWallet.walletId).fold( + ifLeft = { + Timber.e("Unable to select user wallet: $it") + setLoading(false) + }, + ifRight = { + delay(HIDE_PROGRESS_DELAY) + setLoading(false) + appRouter.replaceAll(AppRoute.Wallet) + }, + ) + }, + ) + } + + private fun sendSignedInCardAnalyticsEvent(scanResponse: ScanResponse) { + val currency = ParamCardCurrencyConverter().convert(value = scanResponse.cardTypesResolver) + if (currency != null) { + analyticsEventHandler.send( + SignedIn( + currency = currency, + batch = scanResponse.card.batchId, + signInType = SignInType.Card, + walletsCount = "1", + hasBackup = scanResponse.card.backupStatus?.isActive, + ), + ) + } + } + + private fun setLoading(isLoading: Boolean) { + _uiState.update { it.copy(scanInProgress = isLoading) } + } + + fun handleScanError(error: TangemError) { + when (error) { + is TangemSdkError.NfcFeatureIsUnavailable -> { + handleNfcFeatureUnavailable() + } + is TangemSdkError -> { + Timber.e(error, "Scan error occurred") + } + else -> { + Timber.e(error, "Error happened") + } + } + } + + private fun handleNfcFeatureUnavailable() { + uiMessageSender.send( + message = DialogMessage( + message = resourceReference(R.string.nfc_error_unavailable), + title = resourceReference(id = R.string.common_error), + ), + ) + } + + companion object { + const val NEW_BUY_WALLET_URL = "https://buy.tangem.com/?utm_source=tangem-app&utm_medium=app" + } +} \ No newline at end of file diff --git a/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/Home.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/Home.kt new file mode 100644 index 0000000000..24025e1627 --- /dev/null +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/Home.kt @@ -0,0 +1,35 @@ +package com.tangem.features.home.impl.ui + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.tangem.core.ui.components.SystemBarsIconsDisposable +import com.tangem.core.ui.res.TangemColorPalette +import com.tangem.core.ui.utils.ChangeRootBackgroundColorEffect +import com.tangem.features.home.impl.ui.compose.StoriesScreen +import com.tangem.features.home.impl.ui.compose.StoriesScreenV2 +import com.tangem.features.home.impl.ui.state.HomeUM + +@Composable +internal fun Home(state: HomeUM, isV2StoriesEnabled: Boolean, modifier: Modifier = Modifier) { + SystemBarsIconsDisposable(darkIcons = false) + + if (isV2StoriesEnabled) { + StoriesScreenV2( + modifier = modifier, + state = state, + onCreateNewWalletButtonClick = state.onCreateNewWalletClick, + onAddExistingWalletButtonClick = state.onAddExistingWalletClick, + onScanButtonClick = state.onScanClick, + ) + } else { + StoriesScreen( + modifier = modifier, + state = state, + onScanButtonClick = state.onScanClick, + onShopButtonClick = state.onShopClick, + onSearchTokensClick = state.onSearchTokensClick, + ) + } + + ChangeRootBackgroundColorEffect(TangemColorPalette.Black) +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesAnimation.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/StoriesAnimation.kt similarity index 96% rename from app/src/main/java/com/tangem/tap/features/home/compose/StoriesAnimation.kt rename to features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/StoriesAnimation.kt index 5265c91db4..3bf071d96a 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesAnimation.kt +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/StoriesAnimation.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.home.compose +package com.tangem.features.home.impl.ui.compose import androidx.compose.animation.core.* import androidx.compose.foundation.Image @@ -19,8 +19,8 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp -import com.tangem.tap.common.compose.extensions.AnimatedValue -import com.tangem.tap.common.compose.extensions.toAnimatable +import com.tangem.core.ui.utils.AnimatedValue +import com.tangem.core.ui.utils.toAnimatable private const val SCALE_SWITCH_BARRIER = 1.15f diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/StoriesScreen.kt similarity index 94% rename from app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt rename to features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/StoriesScreen.kt index 3ccd4ba7fe..704485cb28 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/StoriesScreen.kt @@ -1,6 +1,6 @@ @file:Suppress("MagicNumber") -package com.tangem.tap.features.home.compose +package com.tangem.features.home.impl.ui.compose import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn @@ -23,24 +23,23 @@ import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameter import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.test.StoriesScreenTestTags -import com.tangem.tap.features.home.compose.content.* -import com.tangem.tap.features.home.compose.views.HomeButtons -import com.tangem.tap.features.home.compose.views.SearchCurrenciesButton -import com.tangem.tap.features.home.compose.views.StoriesProgressBar -import com.tangem.tap.features.home.redux.HomeState -import com.tangem.tap.features.home.redux.Stories -import com.tangem.wallet.R +import com.tangem.features.home.impl.ui.compose.content.* +import com.tangem.features.home.impl.ui.compose.views.HomeButtons +import com.tangem.features.home.impl.ui.compose.views.SearchCurrenciesButton +import com.tangem.features.home.impl.ui.compose.views.StoriesProgressBar +import com.tangem.features.home.impl.ui.state.Stories +import com.tangem.core.ui.R +import com.tangem.features.home.impl.ui.state.HomeUM import kotlin.math.max @Composable internal fun StoriesScreen( - homeState: MutableState, + state: HomeUM, onScanButtonClick: () -> Unit, onShopButtonClick: () -> Unit, onSearchTokensClick: () -> Unit, + modifier: Modifier = Modifier, ) { - val state = homeState.value - var currentStory by remember { mutableStateOf(state.firstStory) } val currentStoryIndex by rememberUpdatedState(newValue = state.stepOf(currentStory)) @@ -59,14 +58,14 @@ internal fun StoriesScreen( // todo refactor [REDACTED_TASK_KEY] StoriesScreenContent( - modifier = Modifier + modifier = modifier .fillMaxSize() .testTag(StoriesScreenTestTags.SCREEN_CONTAINER), config = StoriesScreenContentConfig( storiesSize = state.stories.lastIndex, currentStoryIndex = currentStoryIndex, currentStory = currentStory, - isScanInProgress = homeState.value.scanInProgress, + isScanInProgress = state.scanInProgress, onGoToPreviousStory = goToPreviousStory, onGoToNextStory = goToNextStory, onSearchTokensClick = onSearchTokensClick, diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreenV2.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/StoriesScreenV2.kt similarity index 94% rename from app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreenV2.kt rename to features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/StoriesScreenV2.kt index 5ba5f44315..0554472199 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreenV2.kt +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/StoriesScreenV2.kt @@ -1,6 +1,6 @@ @file:Suppress("MagicNumber") -package com.tangem.tap.features.home.compose +package com.tangem.features.home.impl.ui.compose import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -20,23 +20,22 @@ import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameter import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.test.StoriesScreenTestTags -import com.tangem.tap.features.home.compose.content.* -import com.tangem.tap.features.home.compose.views.HomeButtonsV2 -import com.tangem.tap.features.home.compose.views.StoriesProgressBar -import com.tangem.tap.features.home.redux.HomeState -import com.tangem.tap.features.home.redux.Stories -import com.tangem.wallet.R +import com.tangem.features.home.impl.ui.compose.content.* +import com.tangem.features.home.impl.ui.compose.views.HomeButtonsV2 +import com.tangem.features.home.impl.ui.compose.views.StoriesProgressBar +import com.tangem.features.home.impl.ui.state.Stories import kotlin.math.max +import com.tangem.core.ui.R +import com.tangem.features.home.impl.ui.state.HomeUM @Composable internal fun StoriesScreenV2( - homeState: MutableState, + state: HomeUM, onCreateNewWalletButtonClick: () -> Unit, onAddExistingWalletButtonClick: () -> Unit, onScanButtonClick: () -> Unit, + modifier: Modifier = Modifier, ) { - val state = homeState.value - var currentStory by remember { mutableStateOf(state.firstStory) } val currentStoryIndex by rememberUpdatedState(newValue = state.stepOf(currentStory)) @@ -55,14 +54,14 @@ internal fun StoriesScreenV2( // todo refactor [REDACTED_TASK_KEY] StoriesScreenContentV2( - modifier = Modifier + modifier = modifier .fillMaxSize() .testTag(StoriesScreenTestTags.SCREEN_CONTAINER), config = StoriesScreenContentV2Config( storiesSize = state.stories.lastIndex, currentStoryIndex = currentStoryIndex, currentStory = currentStory, - isScanInProgress = homeState.value.scanInProgress, + isScanInProgress = state.scanInProgress, onGoToPreviousStory = goToPreviousStory, onGoToNextStory = goToNextStory, onCreateNewWalletButtonClick = onCreateNewWalletButtonClick, diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/content/Content.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/content/Content.kt similarity index 96% rename from app/src/main/java/com/tangem/tap/features/home/compose/content/Content.kt rename to features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/content/Content.kt index 1635f234ad..33bf6db728 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/content/Content.kt +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/content/Content.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.home.compose.content +package com.tangem.features.home.impl.ui.compose.content import androidx.annotation.DrawableRes import androidx.compose.foundation.Image @@ -21,9 +21,9 @@ import com.tangem.core.ui.components.SpacerH32 import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.features.home.compose.StoriesBottomImageAnimation -import com.tangem.tap.features.home.compose.StoriesTextAnimation -import com.tangem.wallet.R +import com.tangem.features.home.impl.ui.compose.StoriesBottomImageAnimation +import com.tangem.features.home.impl.ui.compose.StoriesTextAnimation +import com.tangem.core.ui.R @Composable fun StoriesRevolutionaryWallet() { diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/content/CurrenciesWeb3Content.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/content/CurrenciesWeb3Content.kt similarity index 93% rename from app/src/main/java/com/tangem/tap/features/home/compose/content/CurrenciesWeb3Content.kt rename to features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/content/CurrenciesWeb3Content.kt index ec1cb88957..66f639bc51 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/content/CurrenciesWeb3Content.kt +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/content/CurrenciesWeb3Content.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.home.compose.content +package com.tangem.features.home.impl.ui.compose.content import androidx.compose.foundation.background import androidx.compose.foundation.layout.* @@ -17,12 +17,10 @@ import androidx.compose.ui.unit.dp import com.tangem.core.ui.components.SpacerH12 import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.common.compose.extensions.dpSize -import com.tangem.tap.common.compose.extensions.halfHeight -import com.tangem.tap.common.compose.extensions.toPx -import com.tangem.tap.common.extensions.isEven -import com.tangem.tap.features.home.compose.HorizontalSlidingImage -import com.tangem.wallet.R +import com.tangem.features.home.impl.ui.compose.HorizontalSlidingImage +import com.tangem.core.ui.R +import com.tangem.core.ui.utils.dpSize +import com.tangem.core.ui.utils.toPx @Composable fun StoriesCurrenciesContent(paused: Boolean, duration: Int) { @@ -138,4 +136,8 @@ private val BottomGradient: Brush = Brush.verticalGradient( TangemColorPalette.Black.copy(alpha = 0.95f), TangemColorPalette.Black, ), -) \ No newline at end of file +) + +fun DpSize.halfHeight(): Dp = this.height / 2 + +fun Int.isEven() = this and 1 == 0 \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/content/FirstStoriesContent.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/content/FirstStoriesContent.kt similarity index 94% rename from app/src/main/java/com/tangem/tap/features/home/compose/content/FirstStoriesContent.kt rename to features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/content/FirstStoriesContent.kt index 42fdcaf8fa..f7f6debd9c 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/content/FirstStoriesContent.kt +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/content/FirstStoriesContent.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.home.compose.content +package com.tangem.features.home.impl.ui.compose.content import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.LinearEasing @@ -25,8 +25,8 @@ import com.tangem.core.ui.components.SpacerH import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.features.home.compose.StoriesTextAnimation -import com.tangem.wallet.R +import com.tangem.features.home.impl.ui.compose.StoriesTextAnimation +import com.tangem.core.ui.R @Suppress("LongMethod", "ComplexMethod", "MagicNumber") @Composable diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/content/FloatingCardsContent.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/content/FloatingCardsContent.kt similarity index 92% rename from app/src/main/java/com/tangem/tap/features/home/compose/content/FloatingCardsContent.kt rename to features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/content/FloatingCardsContent.kt index 6a010d28ed..e846781ec0 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/content/FloatingCardsContent.kt +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/content/FloatingCardsContent.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.home.compose.content +package com.tangem.features.home.impl.ui.compose.content import androidx.compose.foundation.Image import androidx.compose.foundation.layout.* @@ -6,10 +6,10 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.graphicsLayer -import com.tangem.tap.common.compose.extensions.AnimatedValue -import com.tangem.tap.common.compose.extensions.asImageBitmap -import com.tangem.tap.common.compose.extensions.toAnimatable -import com.tangem.wallet.R +import com.tangem.core.ui.R +import com.tangem.core.ui.utils.AnimatedValue +import com.tangem.core.ui.utils.asImageBitmap +import com.tangem.core.ui.utils.toAnimatable /** [REDACTED_AUTHOR] diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/views/HomeButtons.kt similarity index 97% rename from app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt rename to features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/views/HomeButtons.kt index eab6ba4ced..5b0615495b 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/views/HomeButtons.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.home.compose.views +package com.tangem.features.home.impl.ui.compose.views import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -18,7 +18,7 @@ import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.test.StoriesScreenTestTags -import com.tangem.wallet.R +import com.tangem.core.ui.R @Composable internal fun HomeButtons( diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtonsV2.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/views/HomeButtonsV2.kt similarity index 98% rename from app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtonsV2.kt rename to features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/views/HomeButtonsV2.kt index dc2192b603..c68825891d 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtonsV2.kt +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/views/HomeButtonsV2.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.home.compose.views +package com.tangem.features.home.impl.ui.compose.views import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -19,7 +19,7 @@ import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.test.StoriesScreenTestTags -import com.tangem.wallet.R +import com.tangem.core.ui.R @Composable internal fun HomeButtonsV2( diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/views/SearchCurrenciesButton.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/views/SearchCurrenciesButton.kt similarity index 94% rename from app/src/main/java/com/tangem/tap/features/home/compose/views/SearchCurrenciesButton.kt rename to features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/views/SearchCurrenciesButton.kt index 4d70d5f2f6..0987e2193b 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/views/SearchCurrenciesButton.kt +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/views/SearchCurrenciesButton.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.home.compose.views +package com.tangem.features.home.impl.ui.compose.views import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box @@ -12,7 +12,7 @@ import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.wallet.R +import com.tangem.core.ui.R @Composable internal fun SearchCurrenciesButton(onClick: () -> Unit, modifier: Modifier = Modifier) { diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesButton.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/views/StoriesButton.kt similarity index 97% rename from app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesButton.kt rename to features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/views/StoriesButton.kt index 66fc2bd6f1..ddcc652d3f 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesButton.kt +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/views/StoriesButton.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.home.compose.views +package com.tangem.features.home.impl.ui.compose.views import androidx.compose.material3.ButtonColors import androidx.compose.runtime.Composable diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/views/StoriesProgressBar.kt similarity index 98% rename from app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt rename to features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/views/StoriesProgressBar.kt index ef3514bce4..cc6ea2107c 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/compose/views/StoriesProgressBar.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.home.compose.views +package com.tangem.features.home.impl.ui.compose.views import android.provider.Settings import androidx.compose.animation.core.Animatable diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/state/HomeUM.kt similarity index 58% rename from app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt rename to features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/state/HomeUM.kt index b1d45779ba..d727df8990 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/ui/state/HomeUM.kt @@ -1,15 +1,16 @@ -package com.tangem.tap.features.home.redux +package com.tangem.features.home.impl.ui.state import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.toImmutableList -import org.rekotlin.StateType - -// todo refactor [REDACTED_TASK_KEY] -data class HomeState( - val scanInProgress: Boolean = false, - val stories: ImmutableList = getRestrictedStories().toImmutableList(), -) : StateType { +data class HomeUM( + val scanInProgress: Boolean, + val stories: ImmutableList, + val onScanClick: () -> Unit, + val onShopClick: () -> Unit, + val onSearchTokensClick: () -> Unit, + val onCreateNewWalletClick: () -> Unit, + val onAddExistingWalletClick: () -> Unit, +) { val firstStory: Stories get() = stories[0] fun stepOf(story: Stories): Int = stories.indexOf(story) 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 ac205fd637..24dc8aaa95 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 @@ -206,7 +206,7 @@ internal class OnboardingEntryModel @Inject constructor( router.replaceAll(AppRoute.Wallet) } } else { - router.replaceAll(AppRoute.Home) + router.replaceAll(AppRoute.Home()) } } 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 520d031d69..dcdfa6c203 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 @@ -197,7 +197,7 @@ internal class WalletSettingsModel @Inject constructor( if (hasUserWallets) { router.pop() } else { - router.replaceAll(AppRoute.Home) + router.replaceAll(AppRoute.Home()) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCardClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCardClickIntents.kt index 2ecee965b3..466f15890e 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCardClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCardClickIntents.kt @@ -102,7 +102,7 @@ internal class WalletCardClickIntentsImplementor @Inject constructor( } else { tokenListStore.clear() stateHolder.clear() - appRouter.replaceAll(AppRoute.Home) + appRouter.replaceAll(AppRoute.Home()) } } } 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 2567421144..846fe77ccb 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 @@ -75,7 +75,7 @@ internal class DefaultWalletRouter @Inject constructor( } override fun openStoriesScreen() { - router.push(AppRoute.Home) + router.push(AppRoute.Home()) } override fun isWalletLastScreen(): Boolean { diff --git a/features/welcome/api/src/main/kotlin/com/tangem/features/welcome/WelcomeComponent.kt b/features/welcome/api/src/main/kotlin/com/tangem/features/welcome/WelcomeComponent.kt index 50b914548b..6d9044f216 100644 --- a/features/welcome/api/src/main/kotlin/com/tangem/features/welcome/WelcomeComponent.kt +++ b/features/welcome/api/src/main/kotlin/com/tangem/features/welcome/WelcomeComponent.kt @@ -1,5 +1,6 @@ package com.tangem.features.welcome +import com.tangem.common.routing.entity.InitScreenLaunchMode import com.tangem.common.routing.entity.SerializableIntent import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.ui.decompose.ComposableContentComponent @@ -7,6 +8,7 @@ import com.tangem.core.ui.decompose.ComposableContentComponent interface WelcomeComponent : ComposableContentComponent { data class Params( + val launchMode: InitScreenLaunchMode, val intent: SerializableIntent?, ) diff --git a/settings.gradle.kts b/settings.gradle.kts index 0550f19562..9eb66f4052 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -183,6 +183,9 @@ include(":libs:tangem-sdk-api") include(":features:onboarding-v2:api") include(":features:onboarding-v2:impl") +include(":features:home:api") +include(":features:home:impl") + include(":features:referral:api") include(":features:referral:data") include(":features:referral:domain")