Skip to content

Commit

Permalink
Features/mob 400 adjust margin screen bottom (#87)
Browse files Browse the repository at this point in the history
* Margin type and leverage screens skeleton

* MOB-356 MOB-358 Margin mode screen

* Change bg color

* MOB-360 rough UX for target leverage screen

* Fixed PR

* move modifier to param

* In the middle of coding

* lint

* There is no longer InputFieldScarfold

* Put back InputFieldScaffold

* More placeholder code and it compiles

* rough amount input

* Formatting "Add Margin" and "Remove Margin"

* MOB-400 placeholder for bottom

* Adjust margin receipt area

* MOB-400 rearranging receipt data

* MOB-400 liquidation price

* Fix copy and modified code

* PR review

* spotless

* fix build
  • Loading branch information
johnqh authored May 9, 2024
1 parent 37b9a09 commit b1dcdb4
Show file tree
Hide file tree
Showing 15 changed files with 1,334 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import exchange.dydx.abacus.protocols.LocalizerProtocol
Expand All @@ -24,13 +25,16 @@ import exchange.dydx.trading.common.compose.collectAsStateWithLifecycle
import exchange.dydx.trading.common.theme.DydxThemedPreviewSurface
import exchange.dydx.trading.common.theme.MockLocalizer
import exchange.dydx.trading.feature.receipt.components.buyingpower.DydxReceiptBuyingPowerView
import exchange.dydx.trading.feature.receipt.components.buyingpower.DydxReceiptFreeCollateralView
import exchange.dydx.trading.feature.receipt.components.equity.DydxReceiptEquityView
import exchange.dydx.trading.feature.receipt.components.exchangerate.DydxReceiptExchangeRateView
import exchange.dydx.trading.feature.receipt.components.exchangereceived.DydxReceiptExchangeReceivedView
import exchange.dydx.trading.feature.receipt.components.expectedprice.DydxReceiptExpectedPriceView
import exchange.dydx.trading.feature.receipt.components.fee.DydxReceiptBridgeFeeView
import exchange.dydx.trading.feature.receipt.components.fee.DydxReceiptFeeView
import exchange.dydx.trading.feature.receipt.components.fee.DydxReceiptGasFeeView
import exchange.dydx.trading.feature.receipt.components.isolatedmargin.DydxReceiptIsolatedPositionLeverageView
import exchange.dydx.trading.feature.receipt.components.isolatedmargin.DydxReceiptIsolatedPositionMarginUsageView
import exchange.dydx.trading.feature.receipt.components.marginusage.DydxReceiptMarginUsageView
import exchange.dydx.trading.feature.receipt.components.rewards.DydxReceiptRewardsView
import exchange.dydx.trading.feature.receipt.components.slippage.DydxReceiptSlippageView
Expand All @@ -46,8 +50,11 @@ fun Preview_DydxReceiptView() {

object DydxReceiptView : DydxComponent {
enum class ReceiptLineType {
FreeCollateral,
BuyingPower,
MarginUsage,
IsolatedPositionLeverage,
IsolatedPositionMarginUsage,
Fee,
GasFee,
BridgeFee,
Expand All @@ -62,6 +69,8 @@ object DydxReceiptView : DydxComponent {

data class ViewState(
val localizer: LocalizerProtocol,
val height: Dp? = null,
val padding: Dp? = null,
val lineTypes: List<ReceiptLineType> = emptyList(),
) {
companion object {
Expand Down Expand Up @@ -93,9 +102,9 @@ object DydxReceiptView : DydxComponent {

Box(
modifier = modifier
.height(210.dp)
.height(state.height ?: 210.dp)
.fillMaxWidth()
.padding(horizontal = ThemeShapes.HorizontalPadding)
.padding(horizontal = state.padding ?: ThemeShapes.HorizontalPadding)
.background(
color = ThemeColor.SemanticColor.layer_1.color,
shape = RoundedCornerShape(10.dp),
Expand All @@ -110,6 +119,10 @@ object DydxReceiptView : DydxComponent {
) {
items(state.lineTypes, key = { it }) { lineType ->
when (lineType) {
ReceiptLineType.FreeCollateral -> {
DydxReceiptFreeCollateralView.Content(Modifier.animateItemPlacement())
}

ReceiptLineType.BuyingPower -> {
DydxReceiptBuyingPowerView.Content(Modifier.animateItemPlacement())
}
Expand All @@ -118,6 +131,14 @@ object DydxReceiptView : DydxComponent {
DydxReceiptMarginUsageView.Content(Modifier.animateItemPlacement())
}

ReceiptLineType.IsolatedPositionLeverage -> {
DydxReceiptIsolatedPositionLeverageView.Content(Modifier.animateItemPlacement())
}

ReceiptLineType.IsolatedPositionMarginUsage -> {
DydxReceiptIsolatedPositionMarginUsageView.Content(Modifier.animateItemPlacement())
}

ReceiptLineType.Fee -> {
DydxReceiptFeeView.Content(Modifier.animateItemPlacement())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package exchange.dydx.trading.feature.receipt.components.buyingpower

import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.navigation.compose.hiltViewModel
import exchange.dydx.abacus.protocols.LocalizerProtocol
import exchange.dydx.platformui.components.changes.PlatformAmountChange
import exchange.dydx.platformui.components.changes.PlatformDirection
import exchange.dydx.platformui.designSystem.theme.ThemeColor
import exchange.dydx.platformui.designSystem.theme.ThemeFont
import exchange.dydx.platformui.designSystem.theme.dydxDefault
import exchange.dydx.platformui.designSystem.theme.themeColor
import exchange.dydx.platformui.designSystem.theme.themeFont
import exchange.dydx.trading.common.component.DydxComponent
import exchange.dydx.trading.common.compose.collectAsStateWithLifecycle
import exchange.dydx.trading.common.theme.DydxThemedPreviewSurface
import exchange.dydx.trading.common.theme.MockLocalizer
import exchange.dydx.trading.feature.shared.views.AmountText

@Preview
@Composable
fun Preview_DydxReceiptFreeCollateralView() {
DydxThemedPreviewSurface {
DydxReceiptFreeCollateralView.Content(
Modifier,
DydxReceiptFreeCollateralView.ViewState.preview,
)
}
}

object DydxReceiptFreeCollateralView : DydxComponent {
data class ViewState(
val localizer: LocalizerProtocol,
val before: AmountText.ViewState? = null,
val after: AmountText.ViewState? = null,

) {
companion object {
val preview = ViewState(
localizer = MockLocalizer(),
before = AmountText.ViewState.preview,
after = AmountText.ViewState.preview,
)
}
}

@Composable
override fun Content(modifier: Modifier) {
val viewModel: DydxReceiptFreeCollateralViewModel = hiltViewModel()

val state = viewModel.state.collectAsStateWithLifecycle(initialValue = null).value
Content(modifier, state)
}

@Composable
fun Content(modifier: Modifier, state: ViewState?) {
if (state == null) return

Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = state.localizer.localize("APP.GENERAL.FREE_COLLATERAL"),
style = TextStyle.dydxDefault
.themeFont(fontSize = ThemeFont.FontSize.small)
.themeColor(ThemeColor.SemanticColor.text_tertiary),
)

Spacer(modifier = Modifier.weight(0.1f))

PlatformAmountChange(
modifier = Modifier.weight(1f),
before = if (state.before != null) {
{
AmountText.Content(
state = state.before,
textStyle = TextStyle.dydxDefault
.themeFont(
fontType = ThemeFont.FontType.number,
fontSize = ThemeFont.FontSize.small,
)
.themeColor(ThemeColor.SemanticColor.text_tertiary),
)
}
} else {
null
},
after = if (state.after != null) {
{
AmountText.Content(
state = state.after,
textStyle = TextStyle.dydxDefault
.themeFont(
fontType = ThemeFont.FontType.number,
fontSize = ThemeFont.FontSize.small,
)
.themeColor(ThemeColor.SemanticColor.text_primary),
)
}
} else {
null
},
direction = PlatformDirection.from(state.before?.amount, state.after?.amount),
textStyle = TextStyle.dydxDefault
.themeFont(fontSize = ThemeFont.FontSize.small)
.themeColor(ThemeColor.SemanticColor.text_tertiary),
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package exchange.dydx.trading.feature.receipt.components.buyingpower

import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import exchange.dydx.abacus.output.Subaccount
import exchange.dydx.abacus.output.SubaccountPosition
import exchange.dydx.abacus.output.input.TradeInput
import exchange.dydx.abacus.output.input.TransferInput
import exchange.dydx.abacus.protocols.LocalizerProtocol
import exchange.dydx.dydxstatemanager.AbacusStateManagerProtocol
import exchange.dydx.trading.common.DydxViewModel
import exchange.dydx.trading.common.formatter.DydxFormatter
import exchange.dydx.trading.feature.receipt.ReceiptType
import exchange.dydx.trading.feature.shared.views.AmountText
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import javax.inject.Inject

@HiltViewModel
class DydxReceiptFreeCollateralViewModel @Inject constructor(
private val localizer: LocalizerProtocol,
private val abacusStateManager: AbacusStateManagerProtocol,
private val formatter: DydxFormatter,
private val receiptTypeFlow: Flow<@JvmSuppressWildcards ReceiptType?>,
) : ViewModel(), DydxViewModel {

@OptIn(ExperimentalCoroutinesApi::class)
val state: Flow<DydxReceiptFreeCollateralView.ViewState?> =
receiptTypeFlow
.flatMapLatest { receiptType ->
when (receiptType) {
is ReceiptType.Trade -> {
combine(
abacusStateManager.state.selectedSubaccountPositions,
abacusStateManager.state.tradeInput,
) { positions, tradeInput ->
createViewState(positions, tradeInput)
}
}
is ReceiptType.Transfer -> {
combine(
abacusStateManager.state.selectedSubaccount,
abacusStateManager.state.transferInput,
) { subaccount, transferInput ->
createViewState(subaccount, transferInput)
}
}
else -> flowOf()
}
}
.distinctUntilChanged()

private fun createViewState(
positions: List<SubaccountPosition>?,
tradeInput: TradeInput?,
): DydxReceiptFreeCollateralView.ViewState {
val marketId = tradeInput?.marketId ?: "ETH-USD"
val position = positions?.firstOrNull { it.id == marketId }
return DydxReceiptFreeCollateralView.ViewState(
localizer = localizer,
before = if (position?.freeCollateral?.current != null) {
AmountText.ViewState(
localizer = localizer,
formatter = formatter,
amount = position.freeCollateral?.current,
tickSize = 0,
requiresPositive = true,
)
} else {
null
},
after = if (position?.freeCollateral?.postOrder != null) {
AmountText.ViewState(
localizer = localizer,
formatter = formatter,
amount = position.freeCollateral?.postOrder,
tickSize = 0,
requiresPositive = true,
)
} else {
null
},
)
}

private fun createViewState(
subaccount: Subaccount?,
transferInput: TransferInput?,
): DydxReceiptFreeCollateralView.ViewState {
return DydxReceiptFreeCollateralView.ViewState(
localizer = localizer,
before = if (subaccount?.freeCollateral?.current != null) {
AmountText.ViewState(
localizer = localizer,
formatter = formatter,
amount = subaccount.freeCollateral?.current,
tickSize = 0,
requiresPositive = true,
)
} else {
null
},
after = if (subaccount?.freeCollateral?.postOrder != null) {
AmountText.ViewState(
localizer = localizer,
formatter = formatter,
amount = subaccount.freeCollateral?.postOrder,
tickSize = 0,
requiresPositive = true,
)
} else {
null
},
)
}
}
Loading

0 comments on commit b1dcdb4

Please sign in to comment.