Skip to content

Commit

Permalink
wire up abacus data for unopened positions
Browse files Browse the repository at this point in the history
  • Loading branch information
mike-dydx committed Jun 13, 2024
1 parent 9ff9773 commit 7c859d8
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class dydxMarketPositionViewPresenter: HostedViewPresenter<dydxMarketPositionVie
}

private func updatePosition(position: SubaccountPosition, triggerOrders: [SubaccountOrder], marketMap: [String: PerpetualMarket], assetMap: [String: Asset]) {
guard let sharedOrderViewModel = dydxPortfolioPositionsViewPresenter.createViewModelItem(position: position, marketMap: marketMap, assetMap: assetMap) else {
guard let sharedOrderViewModel = dydxPortfolioPositionsViewPresenter.createPositionViewModelItem(position: position, marketMap: marketMap, assetMap: assetMap) else {
return
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ protocol dydxPortfolioPositionsViewPresenterProtocol: HostedViewPresenterProtoco
}

class dydxPortfolioPositionsViewPresenter: HostedViewPresenter<dydxPortfolioPositionsViewModel>, dydxPortfolioPositionsViewPresenterProtocol {
private var cache = [String: dydxPortfolioPositionItemViewModel]()
private var positionsCache = [String: dydxPortfolioPositionItemViewModel]()
private var pendingPositionsCache = [String: dydxPortfolioPendingPositionsItemViewModel]()

init(viewModel: dydxPortfolioPositionsViewModel?) {
super.init()
Expand All @@ -45,33 +46,89 @@ class dydxPortfolioPositionsViewPresenter: HostedViewPresenter<dydxPortfolioPosi
.store(in: &subscriptions)

Publishers
.CombineLatest3(AbacusStateManager.shared.state.selectedSubaccountPositions,
.CombineLatest4(AbacusStateManager.shared.state.selectedSubaccountPositions,
AbacusStateManager.shared.state.selectedSubaccountPendingPositions,
AbacusStateManager.shared.state.marketMap,
AbacusStateManager.shared.state.assetMap)
.sink { [weak self] positions, marketMap, assetMap in
.sink { [weak self] positions, pendingPositions, marketMap, assetMap in
self?.updatePositions(positions: positions, marketMap: marketMap, assetMap: assetMap)
self?.updatePendingPositions(pendingPositions: pendingPositions, marketMap: marketMap, assetMap: assetMap)
}
.store(in: &subscriptions)
}

private func updatePositions(positions: [SubaccountPosition], marketMap: [String: PerpetualMarket], assetMap: [String: Asset]) {
let items: [dydxPortfolioPositionItemViewModel] = positions.compactMap { position -> dydxPortfolioPositionItemViewModel? in
let item = Self.createViewModelItem(position: position, marketMap: marketMap, assetMap: assetMap, cache: cache)
cache[position.assetId] = item
let item = Self.createPositionViewModelItem(position: position,
marketMap: marketMap,
assetMap: assetMap,
positionsCache: positionsCache)
positionsCache[position.assetId] = item
return item
}

self.viewModel?.positionItems = items
self.viewModel?.unopenedIsolatedPositionItems = [.previewValue, .previewValue, .previewValue]
}

static func createViewModelItem(position: SubaccountPosition, marketMap: [String: PerpetualMarket], assetMap: [String: Asset], cache: [String: dydxPortfolioPositionItemViewModel]? = nil) -> dydxPortfolioPositionItemViewModel? {
private func updatePendingPositions(pendingPositions: [SubaccountPendingPosition], marketMap: [String: PerpetualMarket], assetMap: [String: Asset]) {
let items: [dydxPortfolioPendingPositionsItemViewModel] = pendingPositions.compactMap { pendingPosition -> dydxPortfolioPendingPositionsItemViewModel? in
let item = Self.createPendingPositionsViewModelItem(pendingPosition: pendingPosition,
marketMap: marketMap,
assetMap: assetMap,
pendingPositionsCache: pendingPositionsCache)
pendingPositionsCache[pendingPosition.assetId] = item
return item
}

self.viewModel?.pendingPositionItems = items
}

static func s() {
}

static func createPendingPositionsViewModelItem(
pendingPosition: SubaccountPendingPosition,
marketMap: [String: PerpetualMarket],
assetMap: [String: Asset],
pendingPositionsCache: [String: dydxPortfolioPendingPositionsItemViewModel]? = nil
) -> dydxPortfolioPendingPositionsItemViewModel? {

guard let market = marketMap[pendingPosition.marketId],
let configs = market.configs,
let asset = assetMap[pendingPosition.assetId],
let margin = pendingPosition.equity?.current?.doubleValue,
margin != 0,
let marginFormatted = dydxFormatter.shared.dollar(number: margin, digits: 2)
else {
return nil
}

let viewOrdersAction: () -> Void = {
Router.shared?.navigate(to: RoutingRequest(path: "/market",
params: ["market": market.id,
"currentSection": "positions"]),
animated: true,
completion: nil)
}
let cancelOrdersAction: () -> Void = {
Router.shared?.navigate(to: RoutingRequest(path: "/trade/markets", params: ["market": market.id]), animated: true, completion: nil)
}

return dydxPortfolioPendingPositionsItemViewModel(marketLogoUrl: URL(string: asset.resources?.imageUrl ?? ""),
marketName: asset.name!,
margin: marginFormatted,
orderCount: pendingPosition.orderCount,
viewOrdersAction: viewOrdersAction,
cancelOrdersAction: cancelOrdersAction)
}

static func createPositionViewModelItem(position: SubaccountPosition, marketMap: [String: PerpetualMarket], assetMap: [String: Asset], positionsCache: [String: dydxPortfolioPositionItemViewModel]? = nil) -> dydxPortfolioPositionItemViewModel? {
guard let market = marketMap[position.id], let configs = market.configs, let asset = assetMap[position.assetId],
(position.size.current?.doubleValue ?? 0) != 0 else {
return nil
}

let item = cache?[position.assetId] ?? dydxPortfolioPositionItemViewModel()
let item = positionsCache?[position.assetId] ?? dydxPortfolioPositionItemViewModel()

let positionSize = abs(position.size.current?.doubleValue ?? 0)
item.size = dydxFormatter.shared.localFormatted(number: positionSize, digits: configs.displayStepSizeDecimals?.intValue ?? 1)
Expand Down
11 changes: 11 additions & 0 deletions dydx/dydxStateManager/dydxStateManager/AbacusState+Combine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,17 @@ public final class AbacusState {
.eraseToAnyPublisher()
}

public var selectedSubaccountPendingPositions: AnyPublisher<[SubaccountPendingPosition], Never> {
selectedSubaccount
.compactMap { subaccount in
subaccount?.pendingPositions
}
.prepend([])
.removeDuplicates()
.share()
.eraseToAnyPublisher()
}

public var selectedSubaccountOrders: AnyPublisher<[SubaccountOrder], Never> {
selectedSubaccount
.compactMap { subaccount in
Expand Down
8 changes: 4 additions & 4 deletions dydx/dydxViews/dydxViews.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@
27C027452AFD734800E92CCB /* dydxSettingsHelpRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27C027442AFD734800E92CCB /* dydxSettingsHelpRowView.swift */; };
27C6E4C92BC8C30E00ED892A /* dydxCustomLimitPriceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27C6E4BC2BC8C30E00ED892A /* dydxCustomLimitPriceViewModel.swift */; };
27CDA3D42BBF1AD700FEAFFE /* dydxMultipleOrdersExistViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27CDA3D32BBF1AD700FEAFFE /* dydxMultipleOrdersExistViewModel.swift */; };
27E072D22C1A095C0034B963 /* dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27E072D12C1A095C0034B963 /* dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift */; };
27E072D22C1A095C0034B963 /* dydxPortfolioPendingPositionsItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27E072D12C1A095C0034B963 /* dydxPortfolioPendingPositionsItemViewModel.swift */; };
27ED340C2AD47CB100C159F5 /* dydxBannerErrorAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27ED340B2AD47CB100C159F5 /* dydxBannerErrorAlert.swift */; };
27ED365C2AD735A800C159F5 /* dydxSecurityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27ED365B2AD735A800C159F5 /* dydxSecurityView.swift */; };
27F624112BBD9FEB00AB6D1A /* dydxPriceInputViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F624042BBD9FEB00AB6D1A /* dydxPriceInputViewModel.swift */; };
Expand Down Expand Up @@ -566,7 +566,7 @@
27C027442AFD734800E92CCB /* dydxSettingsHelpRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSettingsHelpRowView.swift; sourceTree = "<group>"; };
27C6E4BC2BC8C30E00ED892A /* dydxCustomLimitPriceViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = dydxCustomLimitPriceViewModel.swift; sourceTree = "<group>"; };
27CDA3D32BBF1AD700FEAFFE /* dydxMultipleOrdersExistViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxMultipleOrdersExistViewModel.swift; sourceTree = "<group>"; };
27E072D12C1A095C0034B963 /* dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift; sourceTree = "<group>"; };
27E072D12C1A095C0034B963 /* dydxPortfolioPendingPositionsItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxPortfolioPendingPositionsItemViewModel.swift; sourceTree = "<group>"; };
27ED340B2AD47CB100C159F5 /* dydxBannerErrorAlert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = dydxBannerErrorAlert.swift; sourceTree = "<group>"; };
27ED365B2AD735A800C159F5 /* dydxSecurityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSecurityView.swift; sourceTree = "<group>"; };
27F624042BBD9FEB00AB6D1A /* dydxPriceInputViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = dydxPriceInputViewModel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1143,7 +1143,7 @@
02678FA329666BD800EE346B /* dydxPortfolioPositionsView.swift */,
02678FA529666BE600EE346B /* dydxPortfolioOrdersView.swift */,
024F488D2965C91D00E40247 /* dydxPortfolioChartView.swift */,
27E072D12C1A095C0034B963 /* dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift */,
27E072D12C1A095C0034B963 /* dydxPortfolioPendingPositionsItemViewModel.swift */,
);
path = Sections;
sourceTree = "<group>";
Expand Down Expand Up @@ -2014,7 +2014,7 @@
029CBE7728F608F400259C1D /* dydxMarketTradesView.swift in Sources */,
0238FC46296DA53F002E1C1A /* dydxOrderDetailsView.swift in Sources */,
2769090E2AAFD8030075B2D6 /* TransferInstanceViewModel.swift in Sources */,
27E072D22C1A095C0034B963 /* dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift in Sources */,
27E072D22C1A095C0034B963 /* dydxPortfolioPendingPositionsItemViewModel.swift in Sources */,
024FEB642ACB75E10087A55E /* dydxFeesStuctureView.swift in Sources */,
277E918B2B27762F005CCBCB /* dydxRewardsLaunchIncentivesView.swift in Sources */,
0268BBF92A8BE08C00D0C59B /* dydxTransferOutView.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift
// dydxPortfolioPendingPositionsItemViewModel.swift
// dydxUI
//
// Created by Michael Maguire on 6/12/24.
Expand All @@ -8,30 +8,35 @@

import PlatformUI
import SwiftUI
import Utilities

public class dydxPortfolioUnopenedIsolatedPositionsItemViewModel: PlatformViewModel {
public class dydxPortfolioPendingPositionsItemViewModel: PlatformViewModel {
@Published public var marketLogoUrl: URL?
@Published public var marketName: String
@Published public var margin: String
@Published public var orderCount: Int32
@Published public var viewOrdersAction: (() -> Void)
@Published public var cancelOrdersAction: (() -> Void)

public init(marketLogoUrl: URL? = nil,
public init(marketLogoUrl: URL?,
marketName: String,
margin: String,
orderCount: Int32,
viewOrdersAction: @escaping () -> Void,
cancelOrdersAction: @escaping () -> Void) {
self.marketLogoUrl = marketLogoUrl
self.marketName = marketName
self.margin = margin
self.orderCount = orderCount
self.viewOrdersAction = viewOrdersAction
self.cancelOrdersAction = cancelOrdersAction
}

public static var previewValue: dydxPortfolioUnopenedIsolatedPositionsItemViewModel = {
public static var previewValue: dydxPortfolioPendingPositionsItemViewModel = {
.init(marketLogoUrl: URL(string: "https://v4.testnet.dydx.exchange/currencies/eth.png"),
marketName: "ETH-USD",
margin: "$1000.00",
orderCount: 2,
viewOrdersAction: {},
cancelOrdersAction: {}
)
Expand Down Expand Up @@ -63,12 +68,22 @@ public class dydxPortfolioUnopenedIsolatedPositionsItemViewModel: PlatformViewMo
}

private var divider: some View {
Divider()
Spacer(minLength: 1)
.overlay(ThemeColor.SemanticColor.borderDefault.color)
}

private var bottomContent: some View {
let viewOrders = Text(localizerPathKey: "APP.CLOSE_POSITIONS_CONFIRMATION_TOAST.VIEW_ORDERS")
let viewOrdersStringKey: String
let viewOrdersStringParams: [String: String]?
if orderCount > 1 {
viewOrdersStringKey = "APP.GENERAL.VIEW_ORDER"
viewOrdersStringParams = nil
} else {
viewOrdersStringKey = "APP.GENERAL.VIEW_ORDERS_COUNT"
viewOrdersStringParams = ["NUM_ORDERS": "\(orderCount)"]
}

let viewOrders = Text(localizerPathKey: viewOrdersStringKey, params: viewOrdersStringParams)
.themeFont(fontSize: .smaller)
.themeColor(foreground: .colorPurple)
.padding(.vertical, 8)
Expand Down Expand Up @@ -101,12 +116,12 @@ public class dydxPortfolioUnopenedIsolatedPositionsItemViewModel: PlatformViewMo
}

#if DEBUG
struct dydxPortfolioUnopenedIsolatedPositionsItemView_Previews: PreviewProvider {
struct dydxPortfolioPendingPositionsItemView_Previews: PreviewProvider {
@StateObject static var themeSettings = ThemeSettings.shared

static var previews: some View {
Group {
dydxPortfolioUnopenedIsolatedPositionsItemViewModel.previewValue
dydxPortfolioPendingPositionsItemViewModel.previewValue
.createView()
.environmentObject(themeSettings)
.previewLayout(.sizeThatFits)
Expand Down
Loading

0 comments on commit 7c859d8

Please sign in to comment.