Updated on 2026-08-14

This commit is contained in:
Tangem 2026-07-07 13:31:41 +02:00
parent fcfbe7ca92
commit 370d902dad
13 changed files with 138 additions and 5 deletions

View file

@ -0,0 +1,37 @@
package com.tangem.features.promobanners.impl.campaigns.deeplink
import com.tangem.common.routing.deeplink.DeeplinkConst
import com.tangem.features.promobanners.api.deeplink.CampaignsDeepLinkHandler
import com.tangem.features.promobanners.api.toggles.PromoBannersFeatureToggles
import com.tangem.features.promobanners.impl.campaigns.service.CampaignsService
import com.tangem.utils.logging.TangemLogger
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
/**
* Handles the campaigns deeplink (`tangem://campaigns?campaignId=1&lang=ru`): extracts the `campaignId` and
* pushes it to the promo-campaigns bus. The always-alive [com.tangem.features.promobanners.api.swapcashback
* .SwapCashbackCampaignComponent] listens to the bus, maps the id to a campaign type, resolves the campaign
* state and shows the right sheet over the current screen.
*/
internal class DefaultCampaignsDeepLinkHandler @AssistedInject constructor(
@Assisted private val queryParams: Map<String, String>,
campaignsService: CampaignsService,
private val promoBannersFeatureToggles: PromoBannersFeatureToggles,
) : CampaignsDeepLinkHandler {
init {
if (promoBannersFeatureToggles.isCampaignsToggleEnabled) {
val campaignId = queryParams[DeeplinkConst.CAMPAIGN_ID_KEY].orEmpty()
campaignsService.show(campaignId)
} else {
TangemLogger.i("Campaigns feature is disabled")
}
}
@AssistedFactory
interface Factory : CampaignsDeepLinkHandler.Factory {
override fun create(queryParams: Map<String, String>): DefaultCampaignsDeepLinkHandler
}
}

View file

@ -2,10 +2,14 @@ package com.tangem.features.promobanners.impl.campaigns.di
import com.tangem.core.decompose.di.ModelComponent
import com.tangem.core.decompose.model.Model
import com.tangem.features.promobanners.api.deeplink.CampaignsDeepLinkHandler
import com.tangem.features.promobanners.api.swapcashback.CampaignsComponent
import com.tangem.features.promobanners.impl.campaigns.component.DefaultCampaignsComponent
import com.tangem.features.promobanners.impl.campaigns.deeplink.DefaultCampaignsDeepLinkHandler
import com.tangem.features.promobanners.impl.campaigns.model.ActivateCampaignsModel
import com.tangem.features.promobanners.impl.campaigns.model.CampaignsModel
import com.tangem.features.promobanners.impl.campaigns.service.CampaignsService
import com.tangem.features.promobanners.impl.campaigns.service.DefaultCampaignsService
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
@ -21,6 +25,16 @@ internal interface CampaignsModule {
@Binds
@Singleton
fun bindCampaignsComponentFactory(factory: DefaultCampaignsComponent.Factory): CampaignsComponent.Factory
@Binds
@Singleton
fun bindCampaignsDeepLinkHandlerFactory(
factory: DefaultCampaignsDeepLinkHandler.Factory,
): CampaignsDeepLinkHandler.Factory
@Binds
@Singleton
fun bindCampaignsService(service: DefaultCampaignsService): CampaignsService
}
@Module

View file

@ -5,24 +5,28 @@ import com.arkivanov.decompose.router.slot.activate
import com.arkivanov.decompose.router.slot.dismiss
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.features.promobanners.impl.campaigns.converters.CampaignIdConverter
import com.tangem.features.promobanners.impl.campaigns.entity.CampaignsBottomSheetConfig
import com.tangem.features.promobanners.impl.campaigns.entity.CampaignType
import com.tangem.features.promobanners.impl.campaigns.service.CampaignsService
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject
@ModelScoped
internal class CampaignsModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
// private val campaignIdConverter: CampaignIdConverter,
// campaignsService: CampaignsService,
private val campaignIdConverter: CampaignIdConverter,
campaignsService: CampaignsService,
) : Model() {
val bottomSheetNavigation: SlotNavigation<CampaignsBottomSheetConfig> = SlotNavigation()
init {
// campaignsService.campaignFlow
// .onEach { campaignId -> resolveStartNavigation(campaignIdConverter.convert(campaignId)) }
// .launchIn(modelScope)
campaignsService.campaignFlow
.onEach { campaignId -> resolveStartNavigation(campaignIdConverter.convert(campaignId)) }
.launchIn(modelScope)
}
@Suppress("UnusedPrivateMember")

View file

@ -0,0 +1,17 @@
package com.tangem.features.promobanners.impl.campaigns.service
import kotlinx.coroutines.flow.Flow
/**
* App-wide bus that decouples the promo-campaigns deeplink handler from the UI that shows the campaign
* bottom sheet. A producer (deeplink handler) calls [show]; the always-alive campaign component listens
* to [campaignFlow] and activates the appropriate sheet over the current screen.
*/
internal interface CampaignsService {
/** Emits the campaignId requested via [show]. */
val campaignFlow: Flow<String>
/** Requests showing the campaign identified by [campaignId]. */
fun show(campaignId: String)
}

View file

@ -0,0 +1,18 @@
package com.tangem.features.promobanners.impl.campaigns.service
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.receiveAsFlow
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
internal class DefaultCampaignsService @Inject constructor() : CampaignsService {
private val _campaignFlow: Channel<String> = Channel(Channel.BUFFERED)
override val campaignFlow: Flow<String> = _campaignFlow.receiveAsFlow()
override fun show(campaignId: String) {
_campaignFlow.trySend(campaignId)
}
}