tangem-app-android-audited/app/src/main/java/com/tangem/tap/routing/ProxyAppRouter.kt
2026-03-24 10:52:49 +04:00

102 lines
No EOL
3.7 KiB
Kotlin

package com.tangem.tap.routing
import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRouter
import com.tangem.core.analytics.api.AnalyticsExceptionHandler
import com.tangem.core.analytics.models.ExceptionAnalyticsEvent
import com.tangem.core.decompose.navigation.Router
import com.tangem.tap.routing.configurator.AppRouterConfig
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.runSuspendCatching
import com.tangem.utils.logging.TangemLogger
import com.tangem.wallet.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlin.reflect.KClass
internal class ProxyAppRouter(
private val config: AppRouterConfig,
private val dispatchers: CoroutineDispatcherProvider,
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
) : AppRouter {
private val logger = TangemLogger.withTag("AppRouter")
private val routerScope: CoroutineScope
get() = requireNotNull(config.routerScope) {
"Router scope is not set in config"
}
private val innerRouter: Router
get() = requireNotNull(config.componentRouter) {
"Inner router is not set in config"
}
override val stack: List<AppRoute>
get() = requireNotNull(config.stack) {
"Stack is not set in config"
}
override fun push(route: AppRoute, onComplete: (isSuccess: Boolean) -> Unit) {
safeNavigate(onComplete, message = "Push $route") {
innerRouter.push(route, onComplete)
}
}
override fun replaceCurrent(route: AppRoute, onComplete: (Boolean) -> Unit) {
safeNavigate(onComplete, message = "Replace a current route with $route") {
innerRouter.replaceCurrent(route, onComplete)
}
}
override fun replaceAll(vararg routes: AppRoute, onComplete: (isSuccess: Boolean) -> Unit) {
safeNavigate(onComplete, message = "Replace all routes with ${routes.toList().ifEmpty { "<empty>" }}") {
innerRouter.replaceAll(*routes, onComplete = onComplete)
}
}
override fun pop(onComplete: (isSuccess: Boolean) -> Unit) {
safeNavigate(onComplete, message = "Pop route") {
innerRouter.pop(onComplete)
}
}
override fun popTo(route: AppRoute, onComplete: (isSuccess: Boolean) -> Unit) {
safeNavigate(onComplete, message = "Pop to $route") {
innerRouter.popTo(route, onComplete)
}
}
override fun popTo(routeClass: KClass<out AppRoute>, onComplete: (isSuccess: Boolean) -> Unit) {
safeNavigate(onComplete, message = "Pop to $routeClass") {
innerRouter.popTo(routeClass, onComplete)
}
}
private fun safeNavigate(onComplete: (isSuccess: Boolean) -> Unit, message: String, block: () -> Unit) {
routerScope.launch(dispatchers.mainImmediate) {
logger.i(message)
runSuspendCatching(block = { block() })
.onFailure { throwable ->
logger.e(messageString = "Error", throwable = throwable)
onComplete(false)
}
}
}
override fun defaultCompletionHandler(isSuccess: Boolean, errorMessage: String) {
if (!isSuccess) {
analyticsExceptionHandler.sendException(ExceptionAnalyticsEvent(RuntimeException(errorMessage)))
logger.w(errorMessage)
with(receiver = config.snackbarHandler ?: return) {
showSnackbar(
text = R.string.common_unknown_error,
buttonTitle = R.string.common_ok,
action = { dismissSnackbar() },
)
}
}
}
}