Skip to content

Commit

Permalink
MOB-601 : Position Card Updates (#206)
Browse files Browse the repository at this point in the history
* add notional value to position card

* remove null checks to display empty state

* cache displayed alerts to not display again

* display liq/oracle price

* Revert "cache displayed alerts to not display again"

This reverts commit 3500ff0.

* use notional instead of value total
  • Loading branch information
mike-dydx committed Aug 21, 2024
1 parent f013079 commit 716929e
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class dydxMarketPositionViewPresenter: HostedViewPresenter<dydxMarketPositionVie
viewModel?.logoUrl = sharedOrderViewModel.logoUrl
viewModel?.gradientType = sharedOrderViewModel.gradientType

viewModel?.amount = dydxFormatter.shared.dollar(number: position.valueTotal.current?.doubleValue, digits: 2)
viewModel?.amount = dydxFormatter.shared.dollar(number: position.notionalTotal.current?.doubleValue, digits: 2)

viewModel?.openPrice = dydxFormatter.shared.dollar(number: position.entryPrice.current?.doubleValue, digits: configs.displayTickSizeDecimals?.intValue ?? 0)
viewModel?.closePrice = dydxFormatter.shared.dollar(number: position.exitPrice?.doubleValue, digits: configs.displayTickSizeDecimals?.intValue ?? 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ class dydxPortfolioPositionsViewPresenter: HostedViewPresenter<dydxPortfolioPosi
let item = positionsCache?[position.assetId] ?? dydxPortfolioPositionItemViewModel()

let positionSize = abs(position.size.current?.doubleValue ?? 0)
let notionalValue = abs(position.notionalTotal.current?.doubleValue ?? 0)
item.size = dydxFormatter.shared.localFormatted(number: positionSize, digits: configs.displayStepSizeDecimals?.intValue ?? 1)
item.notionalValue = dydxFormatter.shared.dollar(number: notionalValue, digits: 2) ?? "--"
item.token?.symbol = asset.id

if position.resources.indicator.current == "long" {
Expand All @@ -136,7 +138,11 @@ class dydxPortfolioPositionsViewPresenter: HostedViewPresenter<dydxPortfolioPosi
}

item.indexPrice = dydxFormatter.shared.dollar(number: market.oraclePrice, digits: configs.displayTickSizeDecimals?.intValue ?? 0)
item.entryPrice = dydxFormatter.shared.dollar(number: position.entryPrice.current, digits: configs.displayTickSizeDecimals?.intValue ?? 0)
if let liquidationPrice = position.liquidationPrice.current {
item.liquidationPrice = dydxFormatter.shared.dollar(number: liquidationPrice, digits: configs.displayTickSizeDecimals?.intValue ?? 0)
} else {
item.liquidationPrice = DataLocalizer.localize(path: "APP.GENERAL.NONE")
}

item.unrealizedPnl = SignedAmountViewModel(amount: position.unrealizedPnl.current?.doubleValue ?? 0, displayType: .dollar, coloringOption: .allText)
item.unrealizedPnlPercent = dydxFormatter.shared.percent(number: position.unrealizedPnlPercent.current?.doubleValue, digits: 2) ?? ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,16 @@ final class dydxTradeReceiptPresenter: dydxReceiptPresenter {
AbacusStateManager.shared.state.selectedSubaccountPositions,
AbacusStateManager.shared.state.marketMap)
.sink { [weak self] input, positions, marketMap in
if let tradeSummary = input.summary,
let marketId = input.marketId,
let market = marketMap[marketId],
let position = positions.first(where: { $0.id == marketId }) {
self?.updateExpectedPrice(tradeSummary: tradeSummary, market: market)
self?.updateLiquidationPrice(position: position, market: market)
self?.updatePositionMargin(position: position)
self?.updatePositionLeverage(position: position)
self?.updateTradingFee(tradeSummary: tradeSummary)
self?.updateTradingRewards(tradeSummary: tradeSummary)
}
let tradeSummary = input.summary
let marketId = input.marketId
let market = marketMap[marketId ?? ""]
let position = positions.first(where: { $0.id == marketId })
self?.updateExpectedPrice(tradeSummary: tradeSummary, market: market)
self?.updateLiquidationPrice(position: position, market: market)
self?.updatePositionMargin(position: position)
self?.updatePositionLeverage(position: position)
self?.updateTradingFee(tradeSummary: tradeSummary)
self?.updateTradingRewards(tradeSummary: tradeSummary)
}
.store(in: &subscriptions)

Expand Down Expand Up @@ -85,16 +84,16 @@ final class dydxTradeReceiptPresenter: dydxReceiptPresenter {
}
}

private func updateExpectedPrice(tradeSummary: TradeInputSummary?, market: PerpetualMarket) {
let value = dydxFormatter.shared.dollar(number: tradeSummary?.price?.doubleValue, digits: market.configs?.displayTickSizeDecimals?.intValue ?? 0)
private func updateExpectedPrice(tradeSummary: TradeInputSummary?, market: PerpetualMarket?) {
let value = dydxFormatter.shared.dollar(number: tradeSummary?.price?.doubleValue, digits: market?.configs?.displayTickSizeDecimals?.intValue ?? 2)
expectedPriceViewModel.title = DataLocalizer.localize(path: "APP.TRADE.EXPECTED_PRICE")
expectedPriceViewModel.value = value
}

private func updateLiquidationPrice(position: SubaccountPosition?, market: PerpetualMarket) {
private func updateLiquidationPrice(position: SubaccountPosition?, market: PerpetualMarket?) {
let title = DataLocalizer.localize(path: "APP.TRADE.LIQUIDATION_PRICE_SHORT")
let unit = AmountTextModel.Unit.dollar
let tickSize = market.configs?.displayTickSizeDecimals?.intValue.asNsNumber
let tickSize = market?.configs?.displayTickSizeDecimals?.intValue.asNsNumber ?? 2
liquidationPriceViewModel.title = title
liquidationPriceViewModel.value = createAmountChangeViewModel(title: title, tradeState: position?.liquidationPrice, tickSize: tickSize, unit: unit)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ public class dydxPortfolioPositionItemViewModel: PlatformViewModel {
}

public init(size: String? = nil,
notionalValue: String? = nil,
token: TokenTextViewModel? = TokenTextViewModel(),
sideText: SideTextViewModel = SideTextViewModel(),
leverage: String? = nil,
leverageIcon: LeverageRiskModel? = nil,
liquidationPrice: String? = nil,
indexPrice: String? = nil,
entryPrice: String? = nil,
unrealizedPnl: SignedAmountViewModel? = nil,
Expand All @@ -38,25 +40,27 @@ public class dydxPortfolioPositionItemViewModel: PlatformViewModel {
onTapAction: (() -> Void)? = nil,
onMarginEditAction: (() -> Void)? = nil) {
self.size = size
self.notionalValue = notionalValue
self.token = token
self.sideText = sideText
self.leverage = leverage
self.leverageIcon = leverageIcon
self.liquidationPrice = liquidationPrice
self.indexPrice = indexPrice
self.entryPrice = entryPrice
self.unrealizedPnlPercent = "10%"
self.gradientType = gradientType
self.logoUrl = logoUrl
self.handler = Handler(onTapAction: onTapAction, onMarginEditAction: onMarginEditAction)
}

@Published public var size: String?
@Published public var notionalValue: String?
@Published public var token: TokenTextViewModel?
@Published public var sideText = SideTextViewModel()
@Published public var leverage: String?
@Published public var leverageIcon: LeverageRiskModel?
@Published public var liquidationPrice: String?
@Published public var indexPrice: String?
@Published public var entryPrice: String?
@Published public var unrealizedPnl: SignedAmountViewModel?
@Published public var unrealizedPnlPercent: String = ""
@Published public var marginValue: String = "--"
Expand All @@ -69,6 +73,7 @@ public class dydxPortfolioPositionItemViewModel: PlatformViewModel {
public static var previewValue: dydxPortfolioPositionItemViewModel {
let item = dydxPortfolioPositionItemViewModel(
size: "299",
notionalValue: "$420.69",
token: .previewValue,
sideText: .previewValue,
leverage: "0.01x",
Expand All @@ -94,13 +99,12 @@ public class dydxPortfolioPositionItemViewModel: PlatformViewModel {
}

return AnyView(
VStack {
VStack(spacing: 20) {
self.createTopView(parentStyle: style)
self.createBottomView(parentStyle: style)
}
.frame(height: 120)
.padding(.vertical, 12)
.padding(.horizontal, 8)
.padding(.vertical, 16)
.padding(.horizontal, 20)
.themeGradient(background: .layer3, gradientType: self.gradientType)
.cornerRadius(16)
.onTapGesture { [weak self] in
Expand All @@ -112,89 +116,90 @@ public class dydxPortfolioPositionItemViewModel: PlatformViewModel {
}

private func createTopView(parentStyle: ThemeStyle) -> some View {
let icon = self.createLogo(parentStyle: parentStyle)
let main = self.createMain(parentStyle: parentStyle)

return PlatformTableViewCellViewModel(logo: icon.wrappedViewModel,
main: main.wrappedViewModel)
.createView(parentStyle: parentStyle)
HStack(spacing: 0) {
createLogo(parentStyle: parentStyle)
Spacer(minLength: 8)
createTopRowStats(parentStyle: parentStyle)
}
}

private func createBottomView(parentStyle: ThemeStyle) -> some View {
GeometryReader { geo in
HStack(alignment: .top) {
SingleAxisGeometryReader(axis: .horizontal, alignment: .center) { width in
let numElements: CGFloat = 3.0
let spacing: CGFloat = 8
let elementWidth = max(0, (width - (numElements - 1) * spacing) / numElements)
return HStack(alignment: .top, spacing: 8) {
VStack(alignment: .leading, spacing: 4) {
Text(DataLocalizer.localize(path: "APP.GENERAL.INDEX_ENTRY"))
.themeFont(fontSize: .smaller)
.themeColor(foreground: .textTertiary)

Text(self.indexPrice ?? "")
.themeFont(fontSize: .small)
.themeColor(foreground: .textPrimary)
.minimumScaleFactor(0.5)

Text(self.entryPrice ?? "")
.themeFont(fontSize: .smaller)
.themeColor(foreground: .textTertiary)
.minimumScaleFactor(0.5)
Group {
Text(DataLocalizer.localize(path: "APP.GENERAL.LIQ_ORACLE"))
.themeFont(fontSize: .smaller)
.themeColor(foreground: .textTertiary)

Text(self.liquidationPrice ?? "")
.themeFont(fontSize: .small)
.themeColor(foreground: .textPrimary)

Text(self.indexPrice ?? "")
.themeFont(fontSize: .smaller)
.themeColor(foreground: .textTertiary)
}
.lineLimit(1)
.minimumScaleFactor(0.5)
.frame(width: elementWidth, alignment: .leading)
}
.leftAligned()
.frame(width: geo.size.width / 3)

VStack(alignment: .leading, spacing: 4) {
Text(DataLocalizer.localize(path: "APP.GENERAL.PROFIT_AND_LOSS"))
.themeFont(fontSize: .smaller)
.themeColor(foreground: .textTertiary)

self.unrealizedPnl?.createView(parentStyle: parentStyle.themeFont(fontType: .number, fontSize: .small))
Text(self.unrealizedPnlPercent)
.themeFont(fontSize: .smaller)
.themeColor(foreground: .textTertiary)
Group {
Text(DataLocalizer.localize(path: "APP.GENERAL.PROFIT_AND_LOSS"))
.themeFont(fontSize: .smaller)
.themeColor(foreground: .textTertiary)

self.unrealizedPnl?.createView(parentStyle: parentStyle.themeFont(fontType: .number, fontSize: .small))
Text(self.unrealizedPnlPercent)
.themeFont(fontSize: .smaller)
.themeColor(foreground: .textTertiary)
}
.frame(width: elementWidth, alignment: .leading)
}
.leftAligned()
.frame(width: geo.size.width / 3)

VStack(alignment: .leading, spacing: 4) {
Text(DataLocalizer.localize(path: "APP.GENERAL.MARGIN"))
.themeFont(fontSize: .smaller)
.themeColor(foreground: .textTertiary)

HStack {
VStack(alignment: .leading, spacing: 4) {
Text(self.marginValue)
.themeFont(fontSize: .small)
.themeColor(foreground: .textPrimary)
.minimumScaleFactor(0.5)

Text(self.marginMode)
.themeFont(fontSize: .smaller)
.themeColor(foreground: .textTertiary)
.minimumScaleFactor(0.5)
}

Spacer()

if self.isMarginAdjustable {
Group {
Text(DataLocalizer.localize(path: "APP.GENERAL.MARGIN"))
.themeFont(fontSize: .smaller)
.themeColor(foreground: .textTertiary)

HStack(spacing: 8) {
VStack(alignment: .leading, spacing: 4) {
Text(self.marginValue)
.themeFont(fontSize: .small)
.themeColor(foreground: .textPrimary)

Text(self.marginMode)
.themeFont(fontSize: .smaller)
.themeColor(foreground: .textTertiary)
}

let buttonContent = PlatformIconViewModel(type: .asset(name: "icon_edit", bundle: Bundle.dydxView),
size: CGSize(width: 20, height: 20),
templateColor: .textSecondary)
PlatformButtonViewModel(content: buttonContent,
type: PlatformButtonType.iconType) { [weak self] in
self?.handler?.onMarginEditAction?()
if self.isMarginAdjustable {

let buttonContent = PlatformIconViewModel(type: .asset(name: "icon_edit", bundle: Bundle.dydxView),
size: CGSize(width: 20, height: 20),
templateColor: .textSecondary)
PlatformButtonViewModel(content: buttonContent,
type: PlatformButtonType.iconType) { [weak self] in
self?.handler?.onMarginEditAction?()
}
.createView(parentStyle: parentStyle)
.frame(width: 32, height: 32)
.themeColor(background: .layer6)
.border(borderWidth: 1, cornerRadius: 7, borderColor: ThemeColor.SemanticColor.layer7.color)
}
.createView(parentStyle: parentStyle)
.frame(width: 32, height: 32)
.themeColor(background: .layer6)
.border(borderWidth: 1, cornerRadius: 7, borderColor: ThemeColor.SemanticColor.layer7.color)
}
}
.frame(width: elementWidth, alignment: .leading)
}
.leftAligned()
.frame(width: geo.size.width / 3)
}

}
.padding(.horizontal, 16)
}

private func createLogo( parentStyle: ThemeStyle) -> some View {
Expand All @@ -206,28 +211,33 @@ public class dydxPortfolioPositionItemViewModel: PlatformViewModel {
}
}

private func createMain(parentStyle: ThemeStyle) -> some View {
VStack(alignment: .leading, spacing: 0) {
HStack(spacing: 2) {
Text(size ?? "")
.themeFont(fontType: .number, fontSize: .small)

token?.createView(parentStyle: parentStyle.themeFont(fontSize: .smallest))
private func createTopRowStats(parentStyle: ThemeStyle) -> some View {
HStack(alignment: .top, spacing: 0) {
VStack(alignment: .leading, spacing: 2) {
HStack(spacing: 4) {
Text(size ?? "")
.themeFont(fontType: .base, fontSize: .small)
.themeColor(foreground: .textPrimary)
token?.createView(parentStyle: parentStyle.themeFont(fontSize: .smallest))
}
Text(notionalValue ?? "")
.themeFont(fontSize: .smaller)
.themeColor(foreground: .textTertiary)
}

HStack(spacing: 2) {
Spacer(minLength: 8)
HStack(alignment: .top, spacing: 2) {
sideText
.createView(parentStyle: parentStyle.themeFont(fontSize: .smaller))
Text("@")
.themeFont(fontSize: .smaller)
.themeColor(foreground: .textTertiary)

Text(leverage ?? "")
.themeFont(fontType: .number, fontSize: .smaller)
.themeFont(fontType: .base, fontSize: .smaller)
.themeColor(foreground: .textPrimary)
}
}
.leftAligned()
.minimumScaleFactor(0.5)
}
}

Expand Down Expand Up @@ -282,7 +292,6 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel {
.borderAndClip(style: .circle, borderColor: .borderDefault)
Spacer()
}
.padding(.horizontal, 16)
.frame(width: UIScreen.main.bounds.width - 32)
.themeFont(fontSize: .small)
.themeColor(foreground: .textTertiary)
Expand Down

0 comments on commit 716929e

Please sign in to comment.