From 391ac0cda5dadd4591314e0878328603cf830a79 Mon Sep 17 00:00:00 2001 From: SeniorZhai Date: Thu, 26 Mar 2026 22:28:36 +0800 Subject: [PATCH 1/6] fix: clear stale retry errors --- .../ui/landing/MnemonicPhraseFragment.kt | 30 +++++++++---------- .../LimitTransferBottomSheetDialogFragment.kt | 1 + .../SwapTransferBottomSheetDialogFragment.kt | 1 + .../TransferBottomSheetDialogFragment.kt | 1 + ...ransferInvoiceBottomSheetDialogFragment.kt | 1 + 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/one/mixin/android/ui/landing/MnemonicPhraseFragment.kt b/app/src/main/java/one/mixin/android/ui/landing/MnemonicPhraseFragment.kt index e0b42635b5..f4e09e95b9 100644 --- a/app/src/main/java/one/mixin/android/ui/landing/MnemonicPhraseFragment.kt +++ b/app/src/main/java/one/mixin/android/ui/landing/MnemonicPhraseFragment.kt @@ -129,6 +129,7 @@ class MnemonicPhraseFragment : BaseFragment(R.layout.fragment_compose) { private fun anonymousRequest(words: List? = null) { lifecycleScope.launch { + errorInfo = null mobileViewModel.updateMnemonicPhraseState(MnemonicPhraseState.Creating) val sessionKey = generateEd25519KeyPair() val edKey = if (!words.isNullOrEmpty()) { @@ -189,12 +190,14 @@ class MnemonicPhraseFragment : BaseFragment(R.layout.fragment_compose) { }, failureBlock = { r -> - if (r.errorCode == NEED_CAPTCHA) { - if (words.isNullOrEmpty()) { - AnalyticsTracker.trackSignUpCaptcha() - } else { - AnalyticsTracker.trackLoginCaptcha("mnemonic_phrase") - } + if (r.errorCode == NEED_CAPTCHA) { + errorInfo = null + mobileViewModel.updateMnemonicPhraseState(MnemonicPhraseState.Creating) + if (words.isNullOrEmpty()) { + AnalyticsTracker.trackSignUpCaptcha() + } else { + AnalyticsTracker.trackLoginCaptcha("mnemonic_phrase") + } initAndLoadCaptcha(sessionKey, edKey, r.errorDescription) } else { errorInfo = requireContext().getMixinErrorStringByCode(r.errorCode, r.errorDescription) @@ -222,6 +225,8 @@ class MnemonicPhraseFragment : BaseFragment(R.layout.fragment_compose) { private var captchaView: CaptchaView? = null private fun initAndLoadCaptcha(sessionKey: EdKeyPair, edKey: EdKeyPair, errorDescription: String) = lifecycleScope.launch { + errorInfo = null + mobileViewModel.updateMnemonicPhraseState(MnemonicPhraseState.Creating) if (captchaView == null) { captchaView = CaptchaView( @@ -264,6 +269,8 @@ class MnemonicPhraseFragment : BaseFragment(R.layout.fragment_compose) { private fun reSend(sessionKey: EdKeyPair, edKey: EdKeyPair, hCaptchaResponse: String? = null, gRecaptchaResponse: String? = null, gtRecaptchaResponse: String? = null) { lifecycleScope.launch { + errorInfo = null + mobileViewModel.updateMnemonicPhraseState(MnemonicPhraseState.Creating) val (messageHex, signatureHex) = buildAnonymousRequestPayload(edKey) val r = handleMixinResponse( invokeNetwork = { @@ -283,6 +290,7 @@ class MnemonicPhraseFragment : BaseFragment(R.layout.fragment_compose) { failureBlock = { r -> if (r.errorCode == NEED_CAPTCHA) { + errorInfo = null mobileViewModel.updateMnemonicPhraseState(MnemonicPhraseState.Creating) initAndLoadCaptcha(sessionKey, edKey, r.errorDescription) } else { @@ -302,16 +310,6 @@ class MnemonicPhraseFragment : BaseFragment(R.layout.fragment_compose) { } else { createAccount(sessionKey, edKey, r.data!!.id) } - } else { - if (r != null) { - if (r.errorCode == NEED_CAPTCHA) { - mobileViewModel.updateMnemonicPhraseState(MnemonicPhraseState.Creating) - initAndLoadCaptcha(sessionKey, edKey, r.errorDescription) - return@launch - } - errorInfo = requireActivity().getMixinErrorStringByCode(r.errorCode, r.errorDescription) - } - mobileViewModel.updateMnemonicPhraseState(MnemonicPhraseState.Failure) } } } diff --git a/app/src/main/java/one/mixin/android/ui/wallet/LimitTransferBottomSheetDialogFragment.kt b/app/src/main/java/one/mixin/android/ui/wallet/LimitTransferBottomSheetDialogFragment.kt index 9665a98e32..1ef34d477a 100644 --- a/app/src/main/java/one/mixin/android/ui/wallet/LimitTransferBottomSheetDialogFragment.kt +++ b/app/src/main/java/one/mixin/android/ui/wallet/LimitTransferBottomSheetDialogFragment.kt @@ -434,6 +434,7 @@ class LimitTransferBottomSheetDialogFragment : MixinComposeBottomSheetDialogFrag override fun onDismiss(dialog: DialogInterface) { super.onDismiss(dialog); onDestroyAction?.invoke() } private fun showPin() { + errorInfo = null PinInputBottomSheetDialogFragment.newInstance(biometricInfo = getBiometricInfo(), from = 1).setOnPinComplete { pin -> lifecycleScope.launch(CoroutineExceptionHandler { _, error -> handleException(error) }) { doAfterPinComplete(pin) diff --git a/app/src/main/java/one/mixin/android/ui/wallet/SwapTransferBottomSheetDialogFragment.kt b/app/src/main/java/one/mixin/android/ui/wallet/SwapTransferBottomSheetDialogFragment.kt index db0f5437ad..01d592e2fa 100644 --- a/app/src/main/java/one/mixin/android/ui/wallet/SwapTransferBottomSheetDialogFragment.kt +++ b/app/src/main/java/one/mixin/android/ui/wallet/SwapTransferBottomSheetDialogFragment.kt @@ -603,6 +603,7 @@ class SwapTransferBottomSheetDialogFragment : MixinComposeBottomSheetDialogFragm } private fun showPin() { + errorInfo = null PinInputBottomSheetDialogFragment.newInstance(biometricInfo = getBiometricInfo(), from = 1).setOnPinComplete { pin -> lifecycleScope.launch( CoroutineExceptionHandler { _, error -> diff --git a/app/src/main/java/one/mixin/android/ui/wallet/transfer/TransferBottomSheetDialogFragment.kt b/app/src/main/java/one/mixin/android/ui/wallet/transfer/TransferBottomSheetDialogFragment.kt index e068782303..62c5bbef60 100644 --- a/app/src/main/java/one/mixin/android/ui/wallet/transfer/TransferBottomSheetDialogFragment.kt +++ b/app/src/main/java/one/mixin/android/ui/wallet/transfer/TransferBottomSheetDialogFragment.kt @@ -644,6 +644,7 @@ class TransferBottomSheetDialogFragment : MixinBottomSheetDialogFragment() { } private fun showPin() { + transferViewModel.errorMessage = null PinInputBottomSheetDialogFragment.newInstance(biometricInfo = getBiometricInfo(), from = 1).setOnPinComplete { pin -> lifecycleScope.launch( CoroutineExceptionHandler { _, error -> diff --git a/app/src/main/java/one/mixin/android/ui/wallet/transfer/TransferInvoiceBottomSheetDialogFragment.kt b/app/src/main/java/one/mixin/android/ui/wallet/transfer/TransferInvoiceBottomSheetDialogFragment.kt index 01e569551e..5dd8fcbf0e 100644 --- a/app/src/main/java/one/mixin/android/ui/wallet/transfer/TransferInvoiceBottomSheetDialogFragment.kt +++ b/app/src/main/java/one/mixin/android/ui/wallet/transfer/TransferInvoiceBottomSheetDialogFragment.kt @@ -359,6 +359,7 @@ class TransferInvoiceBottomSheetDialogFragment : MixinBottomSheetDialogFragment( } private fun showPin() { + transferViewModel.errorMessage = null PinInputBottomSheetDialogFragment.newInstance(biometricInfo = getBiometricInfo(), from = 1).setOnPinComplete { pin -> lifecycleScope.launch( CoroutineExceptionHandler { _, error -> From 3be453c9556707bc336c39bf09c7de7d6018ec7e Mon Sep 17 00:00:00 2001 From: SeniorZhai Date: Fri, 27 Mar 2026 10:49:56 +0800 Subject: [PATCH 2/6] Update --- .../mixin/android/ui/landing/MnemonicPhraseFragment.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/src/main/java/one/mixin/android/ui/landing/MnemonicPhraseFragment.kt b/app/src/main/java/one/mixin/android/ui/landing/MnemonicPhraseFragment.kt index f4e09e95b9..9a82fc30c4 100644 --- a/app/src/main/java/one/mixin/android/ui/landing/MnemonicPhraseFragment.kt +++ b/app/src/main/java/one/mixin/android/ui/landing/MnemonicPhraseFragment.kt @@ -310,6 +310,16 @@ class MnemonicPhraseFragment : BaseFragment(R.layout.fragment_compose) { } else { createAccount(sessionKey, edKey, r.data!!.id) } + } else { + if (r != null) { + if (r.errorCode == NEED_CAPTCHA) { + mobileViewModel.updateMnemonicPhraseState(MnemonicPhraseState.Creating) + initAndLoadCaptcha(sessionKey, edKey, r.errorDescription) + return@launch + } + errorInfo = requireActivity().getMixinErrorStringByCode(r.errorCode, r.errorDescription) + } + mobileViewModel.updateMnemonicPhraseState(MnemonicPhraseState.Failure) } } } From 164bebd0c9ca2c4087c016505071728d9e3b4439 Mon Sep 17 00:00:00 2001 From: SeniorZhai Date: Fri, 27 Mar 2026 11:10:01 +0800 Subject: [PATCH 3/6] Adjust limit order price quick actions --- .../home/web3/components/FloatingActions.kt | 100 +++++++++++++----- .../ui/home/web3/components/InputAction.kt | 19 ++-- .../ui/home/web3/trade/LimitOrderContent.kt | 2 - 3 files changed, 84 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/one/mixin/android/ui/home/web3/components/FloatingActions.kt b/app/src/main/java/one/mixin/android/ui/home/web3/components/FloatingActions.kt index 1c52f69609..8df495c31b 100644 --- a/app/src/main/java/one/mixin/android/ui/home/web3/components/FloatingActions.kt +++ b/app/src/main/java/one/mixin/android/ui/home/web3/components/FloatingActions.kt @@ -2,17 +2,22 @@ package one.mixin.android.ui.home.web3.components import androidx.compose.foundation.background +import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.rememberScrollState import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import one.mixin.android.Constants +import androidx.compose.ui.unit.sp import one.mixin.android.R -import one.mixin.android.api.response.web3.SwapToken import one.mixin.android.compose.theme.MixinAppTheme import one.mixin.android.ui.home.web3.trade.FocusedField import java.math.BigDecimal @@ -22,8 +27,6 @@ import java.math.RoundingMode fun FloatingActions( focusedField: FocusedField, fromBalance: String?, - fromToken: SwapToken?, - toToken: SwapToken?, isPriceInverted: Boolean, onSetInput: (String) -> Unit, onSetPriceMultiplier: (Float?) -> Unit, @@ -66,41 +69,80 @@ fun FloatingActions( } } FocusedField.PRICE -> { - Row( + BoxWithConstraints( modifier = Modifier .fillMaxWidth() .background(MixinAppTheme.colors.backgroundWindow) - .padding(horizontal = 12.dp, vertical = 8.dp), - horizontalArrangement = Arrangement.SpaceBetween, ) { - InputAction(stringResource(R.string.market_price), showBorder = true) { - onSetPriceMultiplier(1.0f) - onMarketPriceClick?.invoke() - } + val buttonSpacing = 3.dp + val minButtonWidth = 72.dp + val availableWidth = maxWidth - 16.dp + val calculatedButtonWidth = (availableWidth - buttonSpacing * 4) / 5 + val buttonWidth = if (calculatedButtonWidth > minButtonWidth) calculatedButtonWidth else minButtonWidth - val isFromUsd = fromToken?.assetId?.let { id -> - Constants.AssetId.usdtAssets.containsKey(id) || Constants.AssetId.usdcAssets.containsKey(id) - } == true - val isToUsd = toToken?.assetId?.let { id -> - Constants.AssetId.usdtAssets.containsKey(id) || Constants.AssetId.usdcAssets.containsKey(id) - } == true - - if (isToUsd && !isFromUsd) { - InputAction("+10%", showBorder = true) { - onSetPriceMultiplier(displayPriceMultiplier(1.1f, isPriceInverted)) - } - InputAction("+20%", showBorder = true) { - onSetPriceMultiplier(displayPriceMultiplier(1.2f, isPriceInverted)) + Row( + modifier = Modifier + .fillMaxWidth() + .horizontalScroll(rememberScrollState()) + .padding(horizontal = 8.dp, vertical = 8.dp), + horizontalArrangement = Arrangement.Start, + ) { + InputAction( + text = "-20%", + modifier = Modifier.widthIn(min = buttonWidth), + showBorder = true, + horizontalPadding = 14.dp, + verticalPadding = 6.dp, + fontSize = 13.sp, + ) { + onSetPriceMultiplier(displayPriceMultiplier(0.8f, isPriceInverted)) } - } else { - InputAction("-10%", showBorder = true) { + Spacer(modifier = Modifier.width(buttonSpacing)) + InputAction( + text = "-10%", + modifier = Modifier.widthIn(min = buttonWidth), + showBorder = true, + horizontalPadding = 14.dp, + verticalPadding = 6.dp, + fontSize = 13.sp, + ) { onSetPriceMultiplier(displayPriceMultiplier(0.9f, isPriceInverted)) } - InputAction("-20%", showBorder = true) { - onSetPriceMultiplier(displayPriceMultiplier(0.8f, isPriceInverted)) + Spacer(modifier = Modifier.width(buttonSpacing)) + InputAction( + text = "market", + modifier = Modifier.widthIn(min = buttonWidth), + showBorder = true, + horizontalPadding = 14.dp, + verticalPadding = 6.dp, + fontSize = 13.sp, + ) { + onSetPriceMultiplier(1.0f) + onMarketPriceClick?.invoke() + } + Spacer(modifier = Modifier.width(buttonSpacing)) + InputAction( + text = "+10%", + modifier = Modifier.widthIn(min = buttonWidth), + showBorder = true, + horizontalPadding = 14.dp, + verticalPadding = 6.dp, + fontSize = 13.sp, + ) { + onSetPriceMultiplier(displayPriceMultiplier(1.1f, isPriceInverted)) + } + Spacer(modifier = Modifier.width(buttonSpacing)) + InputAction( + text = "+20%", + modifier = Modifier.widthIn(min = buttonWidth), + showBorder = true, + horizontalPadding = 14.dp, + verticalPadding = 6.dp, + fontSize = 13.sp, + ) { + onSetPriceMultiplier(displayPriceMultiplier(1.2f, isPriceInverted)) } } - InputAction(stringResource(R.string.Done), showBorder = false) { onDone() } } } else -> {} diff --git a/app/src/main/java/one/mixin/android/ui/home/web3/components/InputAction.kt b/app/src/main/java/one/mixin/android/ui/home/web3/components/InputAction.kt index cc00538974..0c196a6313 100644 --- a/app/src/main/java/one/mixin/android/ui/home/web3/components/InputAction.kt +++ b/app/src/main/java/one/mixin/android/ui/home/web3/components/InputAction.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.collectIsPressedAsState import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentWidth @@ -18,9 +19,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import one.mixin.android.compose.theme.MixinAppTheme @@ -28,7 +29,11 @@ import one.mixin.android.compose.theme.MixinAppTheme @Composable fun InputAction( text: String, + modifier: Modifier = Modifier, showBorder: Boolean = true, + horizontalPadding: androidx.compose.ui.unit.Dp = 20.dp, + verticalPadding: androidx.compose.ui.unit.Dp = 6.dp, + fontSize: TextUnit = 14.sp, onAction: () -> Unit, ) { val interactionSource = remember { MutableInteractionSource() } @@ -36,7 +41,7 @@ fun InputAction( Box( modifier = if (showBorder) { - Modifier + modifier .wrapContentWidth() .wrapContentHeight() .clip(RoundedCornerShape(20.dp)) @@ -47,9 +52,10 @@ fun InputAction( ) { onAction.invoke() } - .padding(20.dp, 6.dp) + .defaultMinSize(minHeight = 32.dp) + .padding(horizontalPadding, verticalPadding) } else { - Modifier + modifier .wrapContentWidth() .wrapContentHeight() .clickable( @@ -58,7 +64,8 @@ fun InputAction( ) { onAction.invoke() } - .padding(6.dp, 6.dp) + .defaultMinSize(minHeight = 32.dp) + .padding(verticalPadding, verticalPadding) }, contentAlignment = Alignment.Center, ) { @@ -66,6 +73,7 @@ fun InputAction( text = text, textAlign = TextAlign.Center, style = TextStyle( + fontSize = fontSize, lineHeight = 16.sp, color = if (isPressed) MixinAppTheme.colors.textAssist else MixinAppTheme.colors.textPrimary, ), @@ -78,4 +86,3 @@ fun InputAction( fun PreviewInputActionMax() { InputAction("MAX") {} } - diff --git a/app/src/main/java/one/mixin/android/ui/home/web3/trade/LimitOrderContent.kt b/app/src/main/java/one/mixin/android/ui/home/web3/trade/LimitOrderContent.kt index 02b496f480..d345dcae1d 100644 --- a/app/src/main/java/one/mixin/android/ui/home/web3/trade/LimitOrderContent.kt +++ b/app/src/main/java/one/mixin/android/ui/home/web3/trade/LimitOrderContent.kt @@ -592,8 +592,6 @@ fun LimitOrderContent( FloatingActions( focusedField = focusedField, fromBalance = fromBalance, - fromToken = fromToken, - toToken = toToken, isPriceInverted = isPriceInverted, onSetPriceMultiplier = { priceMultiplier = it }, onSetInput = { From 9840258fda01a25bb3e86796d8a77d384ec9f922 Mon Sep 17 00:00:00 2001 From: SeniorZhai Date: Wed, 1 Apr 2026 17:45:24 +0800 Subject: [PATCH 4/6] Adjust limit order price quick actions for USD pairs --- .../home/web3/components/FloatingActions.kt | 181 +++++++++++------- .../ui/home/web3/trade/LimitOrderContent.kt | 2 + 2 files changed, 117 insertions(+), 66 deletions(-) diff --git a/app/src/main/java/one/mixin/android/ui/home/web3/components/FloatingActions.kt b/app/src/main/java/one/mixin/android/ui/home/web3/components/FloatingActions.kt index 8df495c31b..36097fbc8f 100644 --- a/app/src/main/java/one/mixin/android/ui/home/web3/components/FloatingActions.kt +++ b/app/src/main/java/one/mixin/android/ui/home/web3/components/FloatingActions.kt @@ -1,6 +1,8 @@ package one.mixin.android.ui.home.web3.components +import one.mixin.android.Constants +import one.mixin.android.api.response.web3.SwapToken import androidx.compose.foundation.background import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement @@ -27,6 +29,8 @@ import java.math.RoundingMode fun FloatingActions( focusedField: FocusedField, fromBalance: String?, + fromToken: SwapToken?, + toToken: SwapToken?, isPriceInverted: Boolean, onSetInput: (String) -> Unit, onSetPriceMultiplier: (Float?) -> Unit, @@ -69,78 +73,62 @@ fun FloatingActions( } } FocusedField.PRICE -> { - BoxWithConstraints( - modifier = Modifier - .fillMaxWidth() - .background(MixinAppTheme.colors.backgroundWindow) - ) { - val buttonSpacing = 3.dp - val minButtonWidth = 72.dp - val availableWidth = maxWidth - 16.dp - val calculatedButtonWidth = (availableWidth - buttonSpacing * 4) / 5 - val buttonWidth = if (calculatedButtonWidth > minButtonWidth) calculatedButtonWidth else minButtonWidth - + val priceActions = priceQuickActions( + fromToken = fromToken, + toToken = toToken, + isPriceInverted = isPriceInverted, + onSetPriceMultiplier = onSetPriceMultiplier, + onMarketPriceClick = onMarketPriceClick, + ) + if (priceActions.size == 3) { Row( modifier = Modifier .fillMaxWidth() - .horizontalScroll(rememberScrollState()) - .padding(horizontal = 8.dp, vertical = 8.dp), - horizontalArrangement = Arrangement.Start, + .background(MixinAppTheme.colors.backgroundWindow) + .padding(horizontal = 12.dp, vertical = 8.dp), + horizontalArrangement = Arrangement.SpaceBetween, ) { - InputAction( - text = "-20%", - modifier = Modifier.widthIn(min = buttonWidth), - showBorder = true, - horizontalPadding = 14.dp, - verticalPadding = 6.dp, - fontSize = 13.sp, - ) { - onSetPriceMultiplier(displayPriceMultiplier(0.8f, isPriceInverted)) - } - Spacer(modifier = Modifier.width(buttonSpacing)) - InputAction( - text = "-10%", - modifier = Modifier.widthIn(min = buttonWidth), - showBorder = true, - horizontalPadding = 14.dp, - verticalPadding = 6.dp, - fontSize = 13.sp, - ) { - onSetPriceMultiplier(displayPriceMultiplier(0.9f, isPriceInverted)) + priceActions.forEach { action -> + InputAction( + text = action.label, + showBorder = true, + onAction = action.onClick, + ) } - Spacer(modifier = Modifier.width(buttonSpacing)) - InputAction( - text = "market", - modifier = Modifier.widthIn(min = buttonWidth), - showBorder = true, - horizontalPadding = 14.dp, - verticalPadding = 6.dp, - fontSize = 13.sp, - ) { - onSetPriceMultiplier(1.0f) - onMarketPriceClick?.invoke() - } - Spacer(modifier = Modifier.width(buttonSpacing)) - InputAction( - text = "+10%", - modifier = Modifier.widthIn(min = buttonWidth), - showBorder = true, - horizontalPadding = 14.dp, - verticalPadding = 6.dp, - fontSize = 13.sp, - ) { - onSetPriceMultiplier(displayPriceMultiplier(1.1f, isPriceInverted)) - } - Spacer(modifier = Modifier.width(buttonSpacing)) - InputAction( - text = "+20%", - modifier = Modifier.widthIn(min = buttonWidth), - showBorder = true, - horizontalPadding = 14.dp, - verticalPadding = 6.dp, - fontSize = 13.sp, + } + } else { + BoxWithConstraints( + modifier = Modifier + .fillMaxWidth() + .background(MixinAppTheme.colors.backgroundWindow) + ) { + val buttonSpacing = 3.dp + val minButtonWidth = 72.dp + val availableWidth = maxWidth - 16.dp + val calculatedButtonWidth = (availableWidth - buttonSpacing * (priceActions.size - 1)) / priceActions.size + val buttonWidth = if (calculatedButtonWidth > minButtonWidth) calculatedButtonWidth else minButtonWidth + + Row( + modifier = Modifier + .fillMaxWidth() + .horizontalScroll(rememberScrollState()) + .padding(horizontal = 8.dp, vertical = 8.dp), + horizontalArrangement = Arrangement.Start, ) { - onSetPriceMultiplier(displayPriceMultiplier(1.2f, isPriceInverted)) + priceActions.forEachIndexed { index, action -> + InputAction( + text = action.label, + modifier = Modifier.widthIn(min = buttonWidth), + showBorder = true, + horizontalPadding = 14.dp, + verticalPadding = 6.dp, + fontSize = 13.sp, + onAction = action.onClick, + ) + if (index != priceActions.lastIndex) { + Spacer(modifier = Modifier.width(buttonSpacing)) + } + } } } } @@ -156,3 +144,64 @@ private fun displayPriceMultiplier(displayMultiplier: Float, isPriceInverted: Bo .divide(BigDecimal(displayMultiplier.toString()), 8, RoundingMode.HALF_UP) .toFloat() } + +private data class PriceQuickAction( + val label: String, + val onClick: () -> Unit, +) + +private fun priceQuickActions( + fromToken: SwapToken?, + toToken: SwapToken?, + isPriceInverted: Boolean, + onSetPriceMultiplier: (Float?) -> Unit, + onMarketPriceClick: (() -> Unit)?, +): List { + val isFromUsd = fromToken.isUsdToken() + val isToUsd = toToken.isUsdToken() + val marketAction = PriceQuickAction("market") { + onSetPriceMultiplier(1.0f) + onMarketPriceClick?.invoke() + } + val decreaseActions = listOf( + PriceQuickAction("-10%") { + onSetPriceMultiplier(displayPriceMultiplier(0.9f, isPriceInverted)) + }, + PriceQuickAction("-20%") { + onSetPriceMultiplier(displayPriceMultiplier(0.8f, isPriceInverted)) + }, + ) + val increaseActions = listOf( + PriceQuickAction("+10%") { + onSetPriceMultiplier(displayPriceMultiplier(1.1f, isPriceInverted)) + }, + PriceQuickAction("+20%") { + onSetPriceMultiplier(displayPriceMultiplier(1.2f, isPriceInverted)) + }, + ) + + return if (isFromUsd == isToUsd) { + listOf( + decreaseActions[1], + decreaseActions[0], + marketAction, + increaseActions[0], + increaseActions[1], + ) + } else if (isToUsd) { + buildList { + add(marketAction) + addAll(increaseActions) + } + } else { + buildList { + add(marketAction) + addAll(decreaseActions) + } + } +} + +private fun SwapToken?.isUsdToken(): Boolean { + val assetId = this?.assetId ?: return false + return assetId in Constants.AssetId.usdtAssets || assetId in Constants.AssetId.usdcAssets +} diff --git a/app/src/main/java/one/mixin/android/ui/home/web3/trade/LimitOrderContent.kt b/app/src/main/java/one/mixin/android/ui/home/web3/trade/LimitOrderContent.kt index d345dcae1d..02b496f480 100644 --- a/app/src/main/java/one/mixin/android/ui/home/web3/trade/LimitOrderContent.kt +++ b/app/src/main/java/one/mixin/android/ui/home/web3/trade/LimitOrderContent.kt @@ -592,6 +592,8 @@ fun LimitOrderContent( FloatingActions( focusedField = focusedField, fromBalance = fromBalance, + fromToken = fromToken, + toToken = toToken, isPriceInverted = isPriceInverted, onSetPriceMultiplier = { priceMultiplier = it }, onSetInput = { From c3a105b79c866caa6ba488cebc8cfa0867d5b971 Mon Sep 17 00:00:00 2001 From: SeniorZhai Date: Wed, 1 Apr 2026 18:07:46 +0800 Subject: [PATCH 5/6] Restore done action for directional price quick actions --- .../ui/home/web3/components/FloatingActions.kt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/one/mixin/android/ui/home/web3/components/FloatingActions.kt b/app/src/main/java/one/mixin/android/ui/home/web3/components/FloatingActions.kt index 36097fbc8f..1e7c698b63 100644 --- a/app/src/main/java/one/mixin/android/ui/home/web3/components/FloatingActions.kt +++ b/app/src/main/java/one/mixin/android/ui/home/web3/components/FloatingActions.kt @@ -79,8 +79,10 @@ fun FloatingActions( isPriceInverted = isPriceInverted, onSetPriceMultiplier = onSetPriceMultiplier, onMarketPriceClick = onMarketPriceClick, + onDone = onDone, + doneLabel = stringResource(R.string.Done), ) - if (priceActions.size == 3) { + if (priceActions.size == 4) { Row( modifier = Modifier .fillMaxWidth() @@ -91,7 +93,7 @@ fun FloatingActions( priceActions.forEach { action -> InputAction( text = action.label, - showBorder = true, + showBorder = action.showBorder, onAction = action.onClick, ) } @@ -119,7 +121,7 @@ fun FloatingActions( InputAction( text = action.label, modifier = Modifier.widthIn(min = buttonWidth), - showBorder = true, + showBorder = action.showBorder, horizontalPadding = 14.dp, verticalPadding = 6.dp, fontSize = 13.sp, @@ -147,6 +149,7 @@ private fun displayPriceMultiplier(displayMultiplier: Float, isPriceInverted: Bo private data class PriceQuickAction( val label: String, + val showBorder: Boolean = true, val onClick: () -> Unit, ) @@ -156,6 +159,8 @@ private fun priceQuickActions( isPriceInverted: Boolean, onSetPriceMultiplier: (Float?) -> Unit, onMarketPriceClick: (() -> Unit)?, + onDone: () -> Unit, + doneLabel: String, ): List { val isFromUsd = fromToken.isUsdToken() val isToUsd = toToken.isUsdToken() @@ -192,11 +197,13 @@ private fun priceQuickActions( buildList { add(marketAction) addAll(increaseActions) + add(PriceQuickAction(doneLabel, showBorder = false, onClick = onDone)) } } else { buildList { add(marketAction) addAll(decreaseActions) + add(PriceQuickAction(doneLabel, showBorder = false, onClick = onDone)) } } } From ef151bd759a42e7bacf8cba4393fbd1315ffae9c Mon Sep 17 00:00:00 2001 From: SeniorZhai Date: Tue, 7 Apr 2026 16:51:32 +0800 Subject: [PATCH 6/6] Code clean --- .../main/java/one/mixin/android/extension/Dimesions.kt | 9 +++++---- .../mixin/android/ui/home/web3/components/InputAction.kt | 5 +++-- .../one/mixin/android/ui/home/web3/trade/CandleChart.kt | 5 +++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/one/mixin/android/extension/Dimesions.kt b/app/src/main/java/one/mixin/android/extension/Dimesions.kt index c45ca9b1dc..21833e431f 100644 --- a/app/src/main/java/one/mixin/android/extension/Dimesions.kt +++ b/app/src/main/java/one/mixin/android/extension/Dimesions.kt @@ -1,16 +1,17 @@ package one.mixin.android.extension +import androidx.compose.ui.unit.Dp import one.mixin.android.MixinApplication val Int.dp: Int get() = MixinApplication.appContext.dpToPx(this.toFloat()) -val Int.composeDp: androidx.compose.ui.unit.Dp - get() = androidx.compose.ui.unit.Dp(this.toFloat()) +val Int.composeDp: Dp + get() = Dp(this.toFloat()) val Int.sp: Int get() = MixinApplication.appContext.spToPx(this.toFloat()) val Float.dp: Int get() = MixinApplication.appContext.dpToPx(this) -val Float.composeDp: androidx.compose.ui.unit.Dp - get() = androidx.compose.ui.unit.Dp(this.toFloat()) +val Float.composeDp: Dp + get() = Dp(this.toFloat()) val Float.sp: Int get() = MixinApplication.appContext.spToPx(this) diff --git a/app/src/main/java/one/mixin/android/ui/home/web3/components/InputAction.kt b/app/src/main/java/one/mixin/android/ui/home/web3/components/InputAction.kt index 0c196a6313..cca601d60c 100644 --- a/app/src/main/java/one/mixin/android/ui/home/web3/components/InputAction.kt +++ b/app/src/main/java/one/mixin/android/ui/home/web3/components/InputAction.kt @@ -21,6 +21,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -31,8 +32,8 @@ fun InputAction( text: String, modifier: Modifier = Modifier, showBorder: Boolean = true, - horizontalPadding: androidx.compose.ui.unit.Dp = 20.dp, - verticalPadding: androidx.compose.ui.unit.Dp = 6.dp, + horizontalPadding: Dp = 20.dp, + verticalPadding: Dp = 6.dp, fontSize: TextUnit = 14.sp, onAction: () -> Unit, ) { diff --git a/app/src/main/java/one/mixin/android/ui/home/web3/trade/CandleChart.kt b/app/src/main/java/one/mixin/android/ui/home/web3/trade/CandleChart.kt index 1332e45d65..869f32bb37 100644 --- a/app/src/main/java/one/mixin/android/ui/home/web3/trade/CandleChart.kt +++ b/app/src/main/java/one/mixin/android/ui/home/web3/trade/CandleChart.kt @@ -51,6 +51,7 @@ import androidx.compose.ui.text.drawText import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel @@ -531,8 +532,8 @@ private fun PerpsCandleChartCanvas( items: List, timeFrame: String, context: android.content.Context, - candleWidth: androidx.compose.ui.unit.Dp, - spacing: androidx.compose.ui.unit.Dp, + candleWidth: Dp, + spacing: Dp, touchXOnChart: Float?, scrollOffset: Float, viewportWidth: Float,