diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a5fdb2e580..3458dfc6a4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -270,6 +270,8 @@ dependencies { implementation(projects.features.tangempay.details.impl) implementation(projects.features.tangempay.main.api) implementation(projects.features.tangempay.main.impl) + implementation(projects.features.tangempay.onboarding.api) + implementation(projects.features.tangempay.onboarding.impl) implementation(projects.features.tokenRecieve.api) implementation(projects.features.tokenRecieve.impl) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index baf6ae4211..87d3840efe 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -264,6 +264,16 @@ android:host="promo" android:scheme="tangem" /> + + + + + + + + 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 9525c29fa0..653b45d4c1 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 @@ -55,6 +55,7 @@ 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.welcome.component.WelcomeComponent import com.tangem.tap.routing.component.RoutingComponent.Child +import com.tangem.features.tangempay.components.TangemPayOnboardingComponent import dagger.hilt.android.scopes.ActivityScoped import javax.inject.Inject import com.tangem.features.walletconnect.components.WalletConnectEntryComponent as RedesignedWalletConnectComponent @@ -114,6 +115,7 @@ internal class ChildFactory @Inject constructor( private val sendWithSwapComponentFactory: SendWithSwapComponent.Factory, private val sendEntryPointComponentFactory: SendEntryPointComponent.Factory, private val tangemPayDetailsComponentFactory: TangemPayDetailsComponent.Factory, + private val tangemPayOnboardingComponentFactory: TangemPayOnboardingComponent.Factory, private val walletConnectFeatureToggles: WalletConnectFeatureToggles, private val hotWalletFeatureToggles: HotWalletFeatureToggles, ) { @@ -606,6 +608,13 @@ internal class ChildFactory @Inject constructor( componentFactory = tangemPayDetailsComponentFactory, ) } + is AppRoute.TangemPayOnboarding -> { + createComponentChild( + context = context, + params = TangemPayOnboardingComponent.Params(route.deeplink), + componentFactory = tangemPayOnboardingComponentFactory, + ) + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/routing/utils/DeepLinkFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/DeepLinkFactory.kt index 3412cac097..45a9e27528 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/DeepLinkFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/DeepLinkFactory.kt @@ -14,6 +14,7 @@ import com.tangem.features.onramp.deeplink.SellDeepLinkHandler import com.tangem.features.onramp.deeplink.SwapDeepLinkHandler import com.tangem.features.send.v2.api.deeplink.SellRedirectDeepLinkHandler import com.tangem.features.staking.api.deeplink.StakingDeepLinkHandler +import com.tangem.features.tangempay.deeplink.OnboardVisaDeepLinkHandler import com.tangem.features.tokendetails.deeplink.TokenDetailsDeepLinkHandler import com.tangem.features.wallet.deeplink.PromoDeeplinkHandler import com.tangem.features.wallet.deeplink.WalletDeepLinkHandler @@ -48,6 +49,7 @@ internal class DeepLinkFactory @Inject constructor( private val sellDeepLink: SellDeepLinkHandler.Factory, private val swapDeepLink: SwapDeepLinkHandler.Factory, private val promoDeepLink: PromoDeeplinkHandler.Factory, + private val onboardVisaDeepLink: OnboardVisaDeepLinkHandler.Factory, ) { private val permittedAppRoute = MutableStateFlow(false) @@ -135,6 +137,7 @@ internal class DeepLinkFactory @Inject constructor( DeepLinkRoute.Swap.host -> swapDeepLink.create() DeepLinkRoute.WalletConnect.host -> walletConnectDeepLink.create(deeplinkUri) DeepLinkRoute.Promo.host -> promoDeepLink.create(coroutineScope, queryParams) + DeepLinkRoute.OnboardVisa.host -> onboardVisaDeepLink.create(deeplinkUri) else -> { Timber.i( """ 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 06cede4e5a..96fcdbc5fd 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 @@ -375,4 +375,9 @@ sealed class AppRoute(val path: String) : Route { @Serializable data class TangemPayDetails(val userWalletId: UserWalletId) : AppRoute(path = "/tangem_pay_details") + + @Serializable + data class TangemPayOnboarding( + val deeplink: String, + ) : AppRoute(path = "/tangem_pay_onboarding/$deeplink") } \ No newline at end of file diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/DeepLinkRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/DeepLinkRoute.kt index 1fbffcb8a8..9b5ba24bfa 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/DeepLinkRoute.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/DeepLinkRoute.kt @@ -59,6 +59,10 @@ sealed class DeepLinkRoute { data object Promo : DeepLinkRoute() { override val host: String = "promo" } + + data object OnboardVisa : DeepLinkRoute() { + override val host: String = "onboard-visa" + } } enum class DeepLinkScheme(val scheme: String) { diff --git a/features/tangempay/onboarding/api/.gitignore b/features/tangempay/onboarding/api/.gitignore new file mode 100644 index 0000000000..796b96d1c4 --- /dev/null +++ b/features/tangempay/onboarding/api/.gitignore @@ -0,0 +1 @@ +/build diff --git a/features/tangempay/onboarding/api/build.gradle.kts b/features/tangempay/onboarding/api/build.gradle.kts new file mode 100644 index 0000000000..a52e5bbccd --- /dev/null +++ b/features/tangempay/onboarding/api/build.gradle.kts @@ -0,0 +1,18 @@ +plugins { + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) + id("configuration") +} + +android { + namespace = "com.tangem.features.tangempay.onboarding.api" +} + +dependencies { + /** Core */ + implementation(projects.core.decompose) + implementation(projects.core.ui) + + /** Compose */ + implementation(deps.compose.runtime) +} \ No newline at end of file diff --git a/features/tangempay/onboarding/api/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayOnboardingComponent.kt b/features/tangempay/onboarding/api/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayOnboardingComponent.kt new file mode 100644 index 0000000000..d2257362fb --- /dev/null +++ b/features/tangempay/onboarding/api/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayOnboardingComponent.kt @@ -0,0 +1,13 @@ +package com.tangem.features.tangempay.components + +import com.tangem.core.decompose.factory.ComponentFactory +import com.tangem.core.ui.decompose.ComposableContentComponent + +interface TangemPayOnboardingComponent : ComposableContentComponent { + + data class Params( + val deeplink: String, + ) + + interface Factory : ComponentFactory +} \ No newline at end of file diff --git a/features/tangempay/onboarding/api/src/main/kotlin/com/tangem/features/tangempay/deeplink/OnboardVisaDeepLinkHandler.kt b/features/tangempay/onboarding/api/src/main/kotlin/com/tangem/features/tangempay/deeplink/OnboardVisaDeepLinkHandler.kt new file mode 100644 index 0000000000..eb9bd4ac28 --- /dev/null +++ b/features/tangempay/onboarding/api/src/main/kotlin/com/tangem/features/tangempay/deeplink/OnboardVisaDeepLinkHandler.kt @@ -0,0 +1,10 @@ +package com.tangem.features.tangempay.deeplink + +import android.net.Uri + +interface OnboardVisaDeepLinkHandler { + + interface Factory { + fun create(uri: Uri): OnboardVisaDeepLinkHandler + } +} \ No newline at end of file diff --git a/features/tangempay/onboarding/impl/.gitignore b/features/tangempay/onboarding/impl/.gitignore new file mode 100644 index 0000000000..796b96d1c4 --- /dev/null +++ b/features/tangempay/onboarding/impl/.gitignore @@ -0,0 +1 @@ +/build diff --git a/features/tangempay/onboarding/impl/build.gradle.kts b/features/tangempay/onboarding/impl/build.gradle.kts new file mode 100644 index 0000000000..ab2de5b977 --- /dev/null +++ b/features/tangempay/onboarding/impl/build.gradle.kts @@ -0,0 +1,34 @@ +plugins { + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) + alias(deps.plugins.kotlin.serialization) + alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.hilt.android) + id("configuration") +} + +android { + namespace = "com.tangem.features.tangempay.onboarding.impl" +} + +dependencies { + /** Core */ + implementation(projects.core.decompose) + implementation(projects.core.ui) + + /** Common */ + implementation(projects.common.routing) + + /** Features api */ + implementation(projects.features.tangempay.onboarding.api) + + /** Compose */ + implementation(deps.compose.foundation) + implementation(deps.compose.material3) + implementation(deps.compose.ui) + implementation(deps.compose.ui.tooling) + + /** DI */ + implementation(deps.hilt.android) + kapt(deps.hilt.kapt) +} \ No newline at end of file diff --git a/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayOnboardingComponent.kt b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayOnboardingComponent.kt new file mode 100644 index 0000000000..c770c768d1 --- /dev/null +++ b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayOnboardingComponent.kt @@ -0,0 +1,35 @@ +package com.tangem.features.tangempay.components + +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.tangempay.model.TangemPayOnboardingModel +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import com.tangem.features.tangempay.ui.TandemPayOnboardingScreen + +internal class DefaultTangemPayOnboardingComponent @AssistedInject constructor( + @Assisted appComponentContext: AppComponentContext, + @Assisted params: TangemPayOnboardingComponent.Params, +) : TangemPayOnboardingComponent, AppComponentContext by appComponentContext { + + private val model: TangemPayOnboardingModel = getOrCreateModel(params) + + @Composable + override fun Content(modifier: Modifier) { + val state by model.screenState.collectAsStateWithLifecycle() + TandemPayOnboardingScreen(modifier = modifier, state = state) + } + + @AssistedFactory + interface Factory : TangemPayOnboardingComponent.Factory { + override fun create( + context: AppComponentContext, + params: TangemPayOnboardingComponent.Params, + ): DefaultTangemPayOnboardingComponent + } +} \ No newline at end of file diff --git a/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/deeplink/DefaultOnboardVisaDeepLinkHandler.kt b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/deeplink/DefaultOnboardVisaDeepLinkHandler.kt new file mode 100644 index 0000000000..a843aade0a --- /dev/null +++ b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/deeplink/DefaultOnboardVisaDeepLinkHandler.kt @@ -0,0 +1,23 @@ +package com.tangem.features.tangempay.deeplink + +import android.net.Uri +import dagger.assisted.Assisted +import com.tangem.common.routing.AppRoute +import com.tangem.common.routing.AppRouter +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +internal class DefaultOnboardVisaDeepLinkHandler @AssistedInject constructor( + @Assisted uri: Uri, + appRouter: AppRouter, +) : OnboardVisaDeepLinkHandler { + + init { + appRouter.push(AppRoute.TangemPayOnboarding(uri.toString())) + } + + @AssistedFactory + interface Factory : OnboardVisaDeepLinkHandler.Factory { + override fun create(uri: Uri): DefaultOnboardVisaDeepLinkHandler + } +} \ No newline at end of file diff --git a/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayDeeplinkModule.kt b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayDeeplinkModule.kt new file mode 100644 index 0000000000..a1d13bcabc --- /dev/null +++ b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayDeeplinkModule.kt @@ -0,0 +1,18 @@ +package com.tangem.features.tangempay.di + +import com.tangem.features.tangempay.deeplink.DefaultOnboardVisaDeepLinkHandler +import com.tangem.features.tangempay.deeplink.OnboardVisaDeepLinkHandler +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal interface TangemPayDeeplinkModule { + + @Binds + @Singleton + fun bindDeepLinkHandlerFactory(impl: DefaultOnboardVisaDeepLinkHandler.Factory): OnboardVisaDeepLinkHandler.Factory +} \ No newline at end of file diff --git a/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayOnboardingFeatureModule.kt b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayOnboardingFeatureModule.kt new file mode 100644 index 0000000000..6e36c8215a --- /dev/null +++ b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayOnboardingFeatureModule.kt @@ -0,0 +1,16 @@ +package com.tangem.features.tangempay.di + +import com.tangem.features.tangempay.components.DefaultTangemPayOnboardingComponent +import com.tangem.features.tangempay.components.TangemPayOnboardingComponent +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +internal interface TangemPayOnboardingFeatureModule { + + @Binds + fun bindFactory(impl: DefaultTangemPayOnboardingComponent.Factory): TangemPayOnboardingComponent.Factory +} \ No newline at end of file diff --git a/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayOnboardingModelsModule.kt b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayOnboardingModelsModule.kt new file mode 100644 index 0000000000..b4b1892e56 --- /dev/null +++ b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayOnboardingModelsModule.kt @@ -0,0 +1,20 @@ +package com.tangem.features.tangempay.di + +import com.tangem.core.decompose.di.ModelComponent +import com.tangem.core.decompose.model.Model +import com.tangem.features.tangempay.model.TangemPayOnboardingModel +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap + +@Module +@InstallIn(ModelComponent::class) +internal interface TangemPayOnboardingModelsModule { + + @Binds + @IntoMap + @ClassKey(TangemPayOnboardingModel::class) + fun bindModel(model: TangemPayOnboardingModel): Model +} \ No newline at end of file diff --git a/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayOnboardingModel.kt b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayOnboardingModel.kt new file mode 100644 index 0000000000..02ca64323d --- /dev/null +++ b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayOnboardingModel.kt @@ -0,0 +1,28 @@ +package com.tangem.features.tangempay.model + +import androidx.compose.runtime.Stable +import com.tangem.core.decompose.di.ModelScoped +import com.tangem.core.decompose.model.Model +import com.tangem.core.decompose.model.ParamsContainer +import com.tangem.features.tangempay.components.TangemPayOnboardingComponent +import com.tangem.features.tangempay.ui.TangemPayOnboardingScreenState +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import javax.inject.Inject + +@Stable +@ModelScoped +internal class TangemPayOnboardingModel @Inject constructor( + paramsContainer: ParamsContainer, + override val dispatchers: CoroutineDispatcherProvider, +) : Model() { + + @Suppress("UnusedPrivateMember") + private val params = paramsContainer.require() + + private val _screenState: MutableStateFlow = MutableStateFlow(getInitState()) + val screenState = _screenState.asStateFlow() + + private fun getInitState() = TangemPayOnboardingScreenState +} \ No newline at end of file diff --git a/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TandemPayOnboardingScreen.kt b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TandemPayOnboardingScreen.kt new file mode 100644 index 0000000000..008f2c8798 --- /dev/null +++ b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TandemPayOnboardingScreen.kt @@ -0,0 +1,31 @@ +package com.tangem.features.tangempay.ui + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.statusBarsPadding +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.tangem.core.ui.R +import com.tangem.core.ui.components.appbar.AppBarWithBackButton + +@Suppress("UnusedPrivateMember") +@Composable +internal fun TandemPayOnboardingScreen(state: TangemPayOnboardingScreenState, modifier: Modifier = Modifier) { + Scaffold( + modifier = modifier, + topBar = { + AppBarWithBackButton( + modifier = Modifier.statusBarsPadding(), + onBackClick = {}, + text = "", + iconRes = R.drawable.ic_back_24, + ) + }, + content = { paddingValues -> + val contentModifier = Modifier + .padding(paddingValues) + .fillMaxSize() + }, + ) +} \ No newline at end of file diff --git a/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayOnboardingScreenState.kt b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayOnboardingScreenState.kt new file mode 100644 index 0000000000..a0681a0db9 --- /dev/null +++ b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayOnboardingScreenState.kt @@ -0,0 +1,3 @@ +package com.tangem.features.tangempay.ui + +internal object TangemPayOnboardingScreenState \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 19c6d1c875..99aee86df3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -272,6 +272,9 @@ include(":features:tangempay:main:impl") include(":features:tangempay:details:api") include(":features:tangempay:details:impl") +include(":features:tangempay:onboarding:api") +include(":features:tangempay:onboarding:impl") + include(":features:create-wallet-selection:api") include(":features:create-wallet-selection:impl") @@ -380,4 +383,5 @@ include(":data:blockaid") include(":data:swap") include(":data:express") include(":data:wallet-manager") -// endregion Data modules \ No newline at end of file +// endregion Data modules +include(":features:tangempay:onboarding") \ No newline at end of file