Updated on 2026-08-14

This commit is contained in:
Tangem 2025-01-10 12:32:32 +05:00
parent 5f6e5e328f
commit ccaaab6ffe
11 changed files with 35 additions and 98 deletions

View file

@ -42,8 +42,8 @@ internal data class SwapStateHolder(
val onRefresh: () -> Unit,
val onBackClicked: () -> Unit,
val onChangeCardsClicked: () -> Unit,
val onSelectTokenClick: (() -> Unit)? = null,
val onSuccess: (() -> Unit)? = null,
val onSelectTokenClick: (() -> Unit),
val onSuccess: (() -> Unit),
val onMaxAmountSelected: (() -> Unit)? = null,
val onShowPermissionBottomSheet: () -> Unit = {},
)

View file

@ -27,8 +27,8 @@ data class UiActions(
val onProviderClick: (String) -> Unit,
val onProviderSelect: (String) -> Unit,
val onBuyClick: (CryptoCurrency) -> Unit,
val onPolicyClick: (String) -> Unit,
val onTosClick: (String) -> Unit,
val onSelectTokenClick: () -> Unit,
val onSuccess: () -> Unit,
val onLinkClick: (String) -> Unit,
val onReceiveCardWarningClick: () -> Unit,
val onFeeReadMoreClick: (String) -> Unit,
)

View file

@ -6,20 +6,16 @@ import androidx.compose.foundation.background
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.fragment.app.viewModels
import com.tangem.common.routing.AppRouter
import com.tangem.core.ui.UiDependencies
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.screen.ComposeFragment
import com.tangem.feature.swap.router.CustomTabsManager
import com.tangem.feature.swap.router.SwapNavScreen
import com.tangem.feature.swap.router.SwapRouter
import com.tangem.feature.swap.ui.SwapScreen
import com.tangem.feature.swap.ui.SwapSelectTokenScreen
import com.tangem.feature.swap.ui.SwapSuccessScreen
import com.tangem.feature.swap.viewmodels.SwapViewModel
import dagger.hilt.android.AndroidEntryPoint
import java.lang.ref.WeakReference
import javax.inject.Inject
@AndroidEntryPoint
@ -28,20 +24,11 @@ class SwapFragment : ComposeFragment() {
@Inject
override lateinit var uiDependencies: UiDependencies
@Inject
lateinit var appRouter: AppRouter
private val viewModel by viewModels<SwapViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycle.addObserver(viewModel)
viewModel.setRouter(
SwapRouter(
customTabsManager = CustomTabsManager(WeakReference(context)),
router = appRouter,
),
)
}
@Composable

View file

@ -1,39 +0,0 @@
package com.tangem.feature.swap.router
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import androidx.browser.customtabs.CustomTabColorSchemeParams
import androidx.browser.customtabs.CustomTabsIntent
import java.lang.ref.WeakReference
@Deprecated("Replace with CustomTabsUrlOpener")
class CustomTabsManager(private val context: WeakReference<Context>) {
fun openUrl(url: String) {
val mContext = context.get() ?: return
val browserIntent = Intent()
.setAction(Intent.ACTION_VIEW)
.addCategory(Intent.CATEGORY_BROWSABLE)
.setDataAndType(Uri.fromParts("http", "", null), "text/plain")
var possibleBrowsers =
mContext.packageManager.queryIntentActivities(browserIntent, PackageManager.MATCH_DEFAULT_ONLY)
if (possibleBrowsers.isEmpty()) {
possibleBrowsers =
mContext.packageManager.queryIntentActivities(browserIntent, PackageManager.MATCH_ALL)
}
if (possibleBrowsers.isNotEmpty()) {
val customTabsIntent = CustomTabsIntent.Builder()
.setDefaultColorSchemeParams(
CustomTabColorSchemeParams.Builder().build(),
)
.build()
customTabsIntent.intent.setPackage(possibleBrowsers[0].activityInfo.packageName)
context.get()?.let { customTabsIntent.launchUrl(it, Uri.parse(url)) }
} else {
val browserIntent2 = Intent(Intent.ACTION_VIEW, Uri.parse(url))
mContext.startActivity(browserIntent2)
}
}
}

View file

@ -9,7 +9,6 @@ import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
internal class SwapRouter(
private val customTabsManager: CustomTabsManager,
private val router: AppRouter,
) {
@ -45,10 +44,6 @@ internal class SwapRouter(
}
}
fun openUrl(url: String) {
customTabsManager.openUrl(url)
}
fun openTokenDetails(userWalletId: UserWalletId, currency: CryptoCurrency) {
val route = AppRoute.CurrencyDetails(
userWalletId = userWalletId,

View file

@ -116,6 +116,8 @@ internal class StateBuilder(
onMaxAmountSelected = actions.onMaxAmountSelected,
changeCardsButtonState = ChangeCardsButtonState.UPDATE_IN_PROGRESS,
onShowPermissionBottomSheet = actions.openPermissionBottomSheet,
onSelectTokenClick = actions.onSelectTokenClick,
onSuccess = actions.onSuccess,
providerState = ProviderState.Empty(),
shouldShowMaxAmount = false,
priceImpact = PriceImpact.Empty(),
@ -352,14 +354,14 @@ internal class StateBuilder(
LegalState(
title = resourceReference(R.string.common_terms_of_use),
link = it,
onClick = actions.onTosClick,
onClick = actions.onLinkClick,
)
},
policyLink = swapProvider.privacyPolicy?.let {
LegalState(
title = resourceReference(R.string.common_privacy_policy),
link = it,
onClick = actions.onPolicyClick,
onClick = actions.onLinkClick,
)
},
)
@ -1039,7 +1041,7 @@ internal class StateBuilder(
readMoreUrl = buildReadMoreUrl(),
feeItems = txFeeState.toFeeItemState(),
readMore = resourceReference(R.string.common_read_more),
onReadMoreClick = actions.onFeeReadMoreClick,
onReadMoreClick = actions.onLinkClick,
)
return uiState.copy(
bottomSheetConfig = TangemBottomSheetConfig(

View file

@ -444,6 +444,8 @@ private val state = SwapStateHolder(
priceImpact = PriceImpact.Empty(),
shouldShowMaxAmount = true,
isInsufficientFunds = false,
onSuccess = {},
onSelectTokenClick = {},
tosState = TosState(
tosLink = LegalState(
title = stringReference("Terms of Use"),

View file

@ -8,12 +8,14 @@ import androidx.lifecycle.*
import arrow.core.Either
import arrow.core.getOrElse
import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRouter
import com.tangem.common.routing.bundle.unbundle
import com.tangem.common.ui.bottomsheet.permission.state.ApproveType
import com.tangem.common.ui.bottomsheet.permission.state.GiveTxPermissionState.InProgress.getApproveTypeOrNull
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.navigation.url.UrlOpener
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.utils.InputNumberFormatter
@ -86,6 +88,8 @@ internal class SwapViewModel @Inject constructor(
private val getMinimumTransactionAmountSyncUseCase: GetMinimumTransactionAmountSyncUseCase,
swapInteractorFactory: SwapInteractor.Factory,
private val savedStateHandle: SavedStateHandle,
private val urlOpener: UrlOpener,
router: AppRouter,
) : ViewModel(), DefaultLifecycleObserver {
private val initialCurrencyFrom: CryptoCurrency
@ -141,7 +145,7 @@ internal class SwapViewModel @Inject constructor(
private var isOrderReversed = false
private val lastAmount = mutableStateOf(INITIAL_AMOUNT)
private val lastReducedBalanceBy = mutableStateOf(BigDecimal.ZERO)
private var swapRouter: SwapRouter by Delegates.notNull()
private var swapRouter: SwapRouter = SwapRouter(router = router)
private val isUserResolvableError: (SwapState) -> Boolean = {
it is SwapState.SwapError &&
@ -201,19 +205,6 @@ internal class SwapViewModel @Inject constructor(
analyticsEventHandler.send(SwapEvents.SwapScreenOpened(initialCurrencyFrom.symbol))
}
fun setRouter(router: SwapRouter) {
swapRouter = router
uiState = uiState.copy(
onSelectTokenClick = {
router.openScreen(SwapNavScreen.SelectToken)
sendSelectTokenScreenOpenedEvent()
},
onSuccess = {
router.openScreen(SwapNavScreen.Success)
},
)
}
private fun sendSelectTokenScreenOpenedEvent() {
val isAnyAvailableTokensTo = dataState.tokensDataState?.toGroup?.available?.isNotEmpty() ?: false
val isAnyAvailableTokensFrom = dataState.tokensDataState?.fromGroup?.available?.isNotEmpty() ?: false
@ -609,7 +600,7 @@ internal class SwapViewModel @Inject constructor(
txUrl = url,
onExploreClick = {
if (it.txHash.isNotEmpty()) {
swapRouter.openUrl(url)
urlOpener.openUrl(url)
}
analyticsEventHandler.send(
event = SwapEvents.ButtonExplore(initialCurrencyFrom.symbol),
@ -618,7 +609,7 @@ internal class SwapViewModel @Inject constructor(
onStatusClick = {
val txExternalUrl = it.txExternalUrl
if (!txExternalUrl.isNullOrBlank()) {
swapRouter.openUrl(txExternalUrl)
urlOpener.openUrl(txExternalUrl)
analyticsEventHandler.send(
event = SwapEvents.ButtonStatus(initialCurrencyFrom.symbol),
)
@ -1103,12 +1094,6 @@ internal class SwapViewModel @Inject constructor(
onRetryClick = {
startLoadingQuotesFromLastState()
},
onPolicyClick = {
swapRouter.openUrl(it)
},
onTosClick = {
swapRouter.openUrl(it)
},
onReceiveCardWarningClick = {
val selectedProvider = dataState.selectedProvider ?: return@UiActions
val currencySymbol = dataState.toCryptoCurrency?.currency?.symbol ?: return@UiActions
@ -1122,8 +1107,13 @@ internal class SwapViewModel @Inject constructor(
uiState = stateBuilder.clearAlert(uiState)
}
},
onFeeReadMoreClick = {
swapRouter.openUrl(it)
onLinkClick = urlOpener::openUrl,
onSelectTokenClick = {
swapRouter.openScreen(SwapNavScreen.SelectToken)
sendSelectTokenScreenOpenedEvent()
},
onSuccess = {
swapRouter.openScreen(SwapNavScreen.Success)
},
)
}