Updated on 2026-08-14

This commit is contained in:
Tangem 2024-12-18 13:06:49 +04:00
parent 1e7ef6ec50
commit e5c9320ea5
8 changed files with 325 additions and 82 deletions

View file

@ -0,0 +1,43 @@
package com.tangem.tap.routing.component
import android.content.Intent
import androidx.compose.runtime.Immutable
import androidx.fragment.app.Fragment
import com.arkivanov.decompose.router.stack.ChildStack
import com.arkivanov.decompose.value.Value
import com.tangem.common.routing.AppRoute
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.utils.Provider
internal interface RoutingComponent : ComposableContentComponent {
// TODO: Remove after full navigation refactoring
val router: Router
// TODO: Remove after full navigation refactoring
val stack: Value<ChildStack<AppRoute, Child>>
@Immutable
sealed class Child {
// TODO: Remove and find initial intent in RoutingComponent: [REDACTED_JIRA]
data object Initial : Child()
data class LegacyFragment(
val name: String,
val fragmentProvider: Provider<Fragment>,
) : Child()
data class LegacyIntent(val intent: Intent) : Child()
data class ComposableComponent(
val component: ComposableContentComponent,
) : Child()
}
interface Factory {
fun create(context: AppComponentContext): RoutingComponent
}
}

View file

@ -0,0 +1,118 @@
package com.tangem.tap.routing.component.impl
import androidx.compose.material3.SnackbarDuration
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.router.stack.ChildStack
import com.arkivanov.decompose.router.stack.childStack
import com.arkivanov.decompose.value.Value
import com.arkivanov.decompose.value.observe
import com.arkivanov.essenty.backhandler.BackCallback
import com.arkivanov.essenty.lifecycle.doOnDestroy
import com.google.android.material.snackbar.Snackbar
import com.tangem.common.routing.AppRoute
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.navigation.getOrCreateTyped
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.message.SnackbarMessage
import com.tangem.tap.common.SnackbarHandler
import com.tangem.tap.routing.component.RoutingComponent
import com.tangem.tap.routing.component.RoutingComponent.Child
import com.tangem.tap.routing.configurator.AppRouterConfig
import com.tangem.tap.routing.toggle.RoutingFeatureToggles
import com.tangem.tap.routing.utils.ChildFactory
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@Suppress("LongParameterList")
internal class DefaultRoutingComponent @AssistedInject constructor(
@Assisted context: AppComponentContext,
private val childFactory: ChildFactory,
private val appRouterConfig: AppRouterConfig,
private val routingFeatureToggles: RoutingFeatureToggles,
) : RoutingComponent,
AppComponentContext by context,
SnackbarHandler {
private val backCallback = BackCallback(priority = Int.MIN_VALUE, onBack = router::pop)
override val stack: Value<ChildStack<AppRoute, Child>> = childStack(
source = navigationProvider.getOrCreateTyped(),
serializer = AppRoute.serializer(), // TODO Maybe set this to null for AppRoute.Onboarding case. Need to check
initialConfiguration = getInitialRoute(),
handleBackButton = false,
childFactory = ::child,
)
init {
backHandler.register(backCallback)
lifecycle.doOnDestroy {
childFactory.doOnDestroy()
}
if (routingFeatureToggles.isNavigationRefactoringEnabled) {
appRouterConfig.routerScope = componentScope
appRouterConfig.componentRouter = router
appRouterConfig.snackbarHandler = this
stack.observe(lifecycle) { stack ->
val stackItems = stack.items.map { it.configuration }
if (appRouterConfig.stack != stackItems) {
appRouterConfig.stack = stackItems
}
}
}
}
@Composable
override fun Content(modifier: Modifier) {
// TODO: Implement in [REDACTED_JIRA]
}
override fun showSnackbar(text: Int, length: Int, buttonTitle: Int?, action: (() -> Unit)?) {
showSnackbar(
text = resourceReference(text),
length = length,
buttonTitle = buttonTitle?.let(::resourceReference),
action = action,
)
}
override fun showSnackbar(text: TextReference, length: Int, buttonTitle: TextReference?, action: (() -> Unit)?) {
val message = SnackbarMessage(
message = text,
duration = when (length) {
Snackbar.LENGTH_SHORT -> SnackbarDuration.Short
Snackbar.LENGTH_LONG -> SnackbarDuration.Long
Snackbar.LENGTH_INDEFINITE -> SnackbarDuration.Indefinite
else -> SnackbarDuration.Short
},
actionLabel = buttonTitle,
action = action,
)
messageSender.send(message)
}
override fun dismissSnackbar() {
messageSender.send(SnackbarMessage(message = TextReference.EMPTY))
}
// TODO: Find correct initial route here: [REDACTED_JIRA]
private fun getInitialRoute(): AppRoute = AppRoute.Initial
private fun child(route: AppRoute, context: ComponentContext): Child {
return childFactory.createChild(route) { childByContext(context) }
}
@AssistedFactory
interface Factory : RoutingComponent.Factory {
override fun create(context: AppComponentContext): DefaultRoutingComponent
}
}