Skip to content
Merged
9 changes: 5 additions & 4 deletions app/src/main/java/one/mixin/android/extension/Dimesions.kt
Original file line number Diff line number Diff line change
@@ -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)
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
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
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
Expand Down Expand Up @@ -66,41 +73,66 @@ fun FloatingActions(
}
}
FocusedField.PRICE -> {
Row(
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 priceActions = priceQuickActions(
fromToken = fromToken,
toToken = toToken,
isPriceInverted = isPriceInverted,
onSetPriceMultiplier = onSetPriceMultiplier,
onMarketPriceClick = onMarketPriceClick,
onDone = onDone,
doneLabel = stringResource(R.string.Done),
)
if (priceActions.size == 4) {
Row(
modifier = Modifier
.fillMaxWidth()
.background(MixinAppTheme.colors.backgroundWindow)
.padding(horizontal = 12.dp, vertical = 8.dp),
horizontalArrangement = Arrangement.SpaceBetween,
) {
priceActions.forEach { action ->
InputAction(
text = action.label,
showBorder = action.showBorder,
onAction = action.onClick,
)
}
}
} 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

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))
}
} else {
InputAction("-10%", showBorder = true) {
onSetPriceMultiplier(displayPriceMultiplier(0.9f, isPriceInverted))
}
InputAction("-20%", showBorder = true) {
onSetPriceMultiplier(displayPriceMultiplier(0.8f, isPriceInverted))
Row(
modifier = Modifier
.fillMaxWidth()
.horizontalScroll(rememberScrollState())
.padding(horizontal = 8.dp, vertical = 8.dp),
horizontalArrangement = Arrangement.Start,
) {
priceActions.forEachIndexed { index, action ->
InputAction(
text = action.label,
modifier = Modifier.widthIn(min = buttonWidth),
showBorder = action.showBorder,
horizontalPadding = 14.dp,
verticalPadding = 6.dp,
fontSize = 13.sp,
onAction = action.onClick,
)
if (index != priceActions.lastIndex) {
Spacer(modifier = Modifier.width(buttonSpacing))
}
}
}
Comment thread
SeniorZhai marked this conversation as resolved.
}
InputAction(stringResource(R.string.Done), showBorder = false) { onDone() }
}
}
else -> {}
Expand All @@ -114,3 +146,69 @@ private fun displayPriceMultiplier(displayMultiplier: Float, isPriceInverted: Bo
.divide(BigDecimal(displayMultiplier.toString()), 8, RoundingMode.HALF_UP)
.toFloat()
}

private data class PriceQuickAction(
val label: String,
val showBorder: Boolean = true,
val onClick: () -> Unit,
)

private fun priceQuickActions(
fromToken: SwapToken?,
toToken: SwapToken?,
isPriceInverted: Boolean,
onSetPriceMultiplier: (Float?) -> Unit,
onMarketPriceClick: (() -> Unit)?,
onDone: () -> Unit,
doneLabel: String,
): List<PriceQuickAction> {
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)
add(PriceQuickAction(doneLabel, showBorder = false, onClick = onDone))
}
} else {
buildList {
add(marketAction)
addAll(decreaseActions)
add(PriceQuickAction(doneLabel, showBorder = false, onClick = onDone))
}
}
}

private fun SwapToken?.isUsdToken(): Boolean {
val assetId = this?.assetId ?: return false
return assetId in Constants.AssetId.usdtAssets || assetId in Constants.AssetId.usdcAssets
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -18,25 +19,30 @@ 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.Dp
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

@Composable
fun InputAction(
text: String,
modifier: Modifier = Modifier,
showBorder: Boolean = true,
horizontalPadding: Dp = 20.dp,
verticalPadding: Dp = 6.dp,
fontSize: TextUnit = 14.sp,
onAction: () -> Unit,
) {
val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()

Box(
modifier = if (showBorder) {
Modifier
modifier
.wrapContentWidth()
.wrapContentHeight()
.clip(RoundedCornerShape(20.dp))
Expand All @@ -47,9 +53,10 @@ fun InputAction(
) {
onAction.invoke()
}
.padding(20.dp, 6.dp)
.defaultMinSize(minHeight = 32.dp)
.padding(horizontalPadding, verticalPadding)
} else {
Modifier
modifier
.wrapContentWidth()
.wrapContentHeight()
.clickable(
Expand All @@ -58,14 +65,16 @@ fun InputAction(
) {
onAction.invoke()
}
.padding(6.dp, 6.dp)
.defaultMinSize(minHeight = 32.dp)
.padding(verticalPadding, verticalPadding)
Comment thread
SeniorZhai marked this conversation as resolved.
},
contentAlignment = Alignment.Center,
) {
Text(
text = text,
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = fontSize,
lineHeight = 16.sp,
color = if (isPressed) MixinAppTheme.colors.textAssist else MixinAppTheme.colors.textPrimary,
),
Expand All @@ -78,4 +87,3 @@ fun InputAction(
fun PreviewInputActionMax() {
InputAction("MAX") {}
}

Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -532,8 +533,8 @@ private fun PerpsCandleChartCanvas(
items: List<CandleItem>,
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ class MnemonicPhraseFragment : BaseFragment(R.layout.fragment_compose) {

private fun anonymousRequest(words: List<String>? = null) {
lifecycleScope.launch {
errorInfo = null
landingViewModel.updateMnemonicPhraseState(MnemonicPhraseState.Creating)
val sessionKey = generateEd25519KeyPair()
val edKey = if (!words.isNullOrEmpty()) {
Expand Down Expand Up @@ -183,12 +184,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
landingViewModel.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)
Expand Down Expand Up @@ -216,6 +219,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
landingViewModel.updateMnemonicPhraseState(MnemonicPhraseState.Creating)
if (captchaView == null) {
captchaView =
CaptchaView(
Expand Down Expand Up @@ -258,6 +263,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
landingViewModel.updateMnemonicPhraseState(MnemonicPhraseState.Creating)
val (messageHex, signatureHex) = buildAnonymousRequestPayload(edKey)
val r = handleMixinResponse(
invokeNetwork = {
Expand All @@ -277,6 +284,7 @@ class MnemonicPhraseFragment : BaseFragment(R.layout.fragment_compose) {

failureBlock = { r ->
if (r.errorCode == NEED_CAPTCHA) {
errorInfo = null
landingViewModel.updateMnemonicPhraseState(MnemonicPhraseState.Creating)
initAndLoadCaptcha(sessionKey, edKey, r.errorDescription)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,7 @@ class SwapTransferBottomSheetDialogFragment : MixinComposeBottomSheetDialogFragm
}

private fun showPin() {
errorInfo = null
PinInputBottomSheetDialogFragment.newInstance(biometricInfo = getBiometricInfo(), from = 1).setOnPinComplete { pin ->
lifecycleScope.launch(
CoroutineExceptionHandler { _, error ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 ->
Expand Down
Loading
Loading