Skip to content

Commit

Permalink
stubbed unopened isolated positions UI
Browse files Browse the repository at this point in the history
  • Loading branch information
mike-dydx committed Jun 12, 2024
1 parent bb6510b commit 38f23e7
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ class dydxPortfolioPositionsViewPresenter: HostedViewPresenter<dydxPortfolioPosi
// TODO: remove once isolated markets is supported and force released
self?.viewModel?.shouldDisplayIsolatedPositionsWarning = onboarded
if onboarded {
self?.viewModel?.placeholderText = DataLocalizer.localize(path: "APP.GENERAL.PLACEHOLDER_NO_POSITIONS")
self?.viewModel?.emptyText = DataLocalizer.localize(path: "APP.GENERAL.PLACEHOLDER_NO_POSITIONS")
} else {
self?.viewModel?.placeholderText = DataLocalizer.localize(path: "APP.GENERAL.PLACEHOLDER_NO_POSITIONS_LOG_IN")
self?.viewModel?.emptyText = DataLocalizer.localize(path: "APP.GENERAL.PLACEHOLDER_NO_POSITIONS_LOG_IN")
}
}
.store(in: &subscriptions)
Expand All @@ -61,7 +61,8 @@ class dydxPortfolioPositionsViewPresenter: HostedViewPresenter<dydxPortfolioPosi
return item
}

self.viewModel?.items = items
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? {
Expand Down
4 changes: 4 additions & 0 deletions dydx/dydxViews/dydxViews.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +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 */; };
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 @@ -565,6 +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>"; };
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 @@ -1141,6 +1143,7 @@
02678FA329666BD800EE346B /* dydxPortfolioPositionsView.swift */,
02678FA529666BE600EE346B /* dydxPortfolioOrdersView.swift */,
024F488D2965C91D00E40247 /* dydxPortfolioChartView.swift */,
27E072D12C1A095C0034B963 /* dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift */,
);
path = Sections;
sourceTree = "<group>";
Expand Down Expand Up @@ -2011,6 +2014,7 @@
029CBE7728F608F400259C1D /* dydxMarketTradesView.swift in Sources */,
0238FC46296DA53F002E1C1A /* dydxOrderDetailsView.swift in Sources */,
2769090E2AAFD8030075B2D6 /* TransferInstanceViewModel.swift in Sources */,
27E072D22C1A095C0034B963 /* dydxPortfolioUnopenedIsolatedPositionsItemViewModel.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
Expand Up @@ -319,41 +319,47 @@ public class dydxPortfolioPositionItemViewModel: PlatformViewModel {
}
}

public class dydxPortfolioPositionsViewModel: PlatformListViewModel {
public class dydxPortfolioPositionsViewModel: PlatformViewModel {
// TODO: remove once isolated markets is supported and force released
@Published public var shouldDisplayIsolatedPositionsWarning: Bool = false
@Published public var placeholderText: String?

public override var placeholder: PlatformViewModel? {
let vm = PlaceholderViewModel()
vm.text = placeholderText
return vm
@Published public var emptyText: String?
@Published public var positionItems: [dydxPortfolioPositionItemViewModel] {
didSet {
contentChanged?()
}
}
@Published public var unopenedIsolatedPositionItems: [dydxPortfolioUnopenedIsolatedPositionsItemViewModel] {
didSet {
contentChanged?()
}
}

public override init(items: [PlatformViewModel] = [],
intraItemSeparator: Bool = false,
firstListItemTopSeparator: Bool = false,
lastListItemBottomSeparator: Bool = false,
contentChanged: (() -> Void)? = nil) {
super.init(items: items,
intraItemSeparator: intraItemSeparator,
firstListItemTopSeparator: firstListItemTopSeparator,
lastListItemBottomSeparator: lastListItemBottomSeparator,
contentChanged: contentChanged)
self.width = UIScreen.main.bounds.width - 32
public var contentChanged: (() -> Void)?

init(
positionItems: [dydxPortfolioPositionItemViewModel] = [],
unopenedIsolatedPositionItems: [dydxPortfolioUnopenedIsolatedPositionsItemViewModel] = [],
emptyText: String? = nil
) {
self.positionItems = positionItems
self.unopenedIsolatedPositionItems = unopenedIsolatedPositionItems
self.emptyText = emptyText
}

public static var previewValue: dydxPortfolioPositionsViewModel {
let vm = dydxPortfolioPositionsViewModel {}
vm.items = [
dydxPortfolioPositionItemViewModel.previewValue,
dydxPortfolioPositionItemViewModel.previewValue
]
return vm
dydxPortfolioPositionsViewModel(
positionItems: [
.previewValue,
.previewValue
],
unopenedIsolatedPositionItems: [
.previewValue
],
emptyText: "empty")
}

public override var header: PlatformViewModel? {
guard dydxBoolFeatureFlag.enable_isolated_margins.isEnabled == false, !items.isEmpty else { return nil }
public var positionsHeader: PlatformViewModel? {
guard dydxBoolFeatureFlag.enable_isolated_margins.isEnabled == false, !positionItems.isEmpty else { return nil }
return HStack {
Text(DataLocalizer.localize(path: "APP.GENERAL.DETAILS"))
Spacer()
Expand All @@ -371,7 +377,7 @@ public class dydxPortfolioPositionsViewModel: PlatformListViewModel {
.wrappedViewModel
}

public override var footer: PlatformViewModel? {
public var positionsFooter: PlatformViewModel? {
guard shouldDisplayIsolatedPositionsWarning && !dydxBoolFeatureFlag.enable_isolated_margins.isEnabled else { return nil }
return Text(localizerPathKey: "APP.GENERAL.ISOLATED_POSITIONS_COMING_SOON")
.multilineTextAlignment(.center)
Expand All @@ -382,6 +388,59 @@ public class dydxPortfolioPositionsViewModel: PlatformListViewModel {
.padding(.bottom, 16)
.wrappedViewModel
}

public var unopenedIsolatedPositionsHeader: PlatformViewModel? {
guard dydxBoolFeatureFlag.enable_isolated_margins.isEnabled == true, !unopenedIsolatedPositionItems.isEmpty else { return nil }
return HStack(spacing: 8) {
Text(localizerPathKey: "APP.TRADE.UNOPENED_ISOLATED_POSITIONS")
.themeFont(fontSize: .larger)
.themeColor(foreground: .textPrimary)
.fixedSize()
Text("\(unopenedIsolatedPositionItems.count)")
.frame(width: 28, height: 28)
.borderAndClip(style: .circle, borderColor: .borderDefault)
Spacer()
}
.padding(.horizontal, 16)
.themeFont(fontSize: .small)
.themeColor(foreground: .textTertiary)
.wrappedViewModel
}

public override func createView(parentStyle: ThemeStyle = ThemeStyle.defaultStyle, styleKey: String? = nil) -> PlatformView {
PlatformView(viewModel: self, parentStyle: parentStyle, styleKey: styleKey) { [weak self] style in
guard let self = self else { return AnyView(PlatformView.nilView) }

if let emptyText = self.emptyText, positionItems.isEmpty, unopenedIsolatedPositionItems.isEmpty {
return AnyView(
PlaceholderViewModel(text: emptyText)
.createView(parentStyle: style)
)
}

let items = self.positionItems.map { $0.createView(parentStyle: style) }
let unopenedItems = self.unopenedIsolatedPositionItems.map { $0.createView(parentStyle: style) }

return AnyView(
ScrollView {
LazyVStack {
self.positionsHeader?.createView(parentStyle: style)

ForEach(items.indices, id: \.self) { index in
items[index]
}

self.positionsFooter?.createView(parentStyle: style)
self.unopenedIsolatedPositionsHeader?.createView(parentStyle: style)

ForEach(unopenedItems.indices, id: \.self) { index in
unopenedItems[index]
}
}
}
)
}
}
}

#if DEBUG
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//
// dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift
// dydxUI
//
// Created by Michael Maguire on 6/12/24.
// Copyright © 2024 dYdX Trading Inc. All rights reserved.
//

import PlatformUI
import SwiftUI

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

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

public static var previewValue: dydxPortfolioUnopenedIsolatedPositionsItemViewModel = {
.init(marketLogoUrl: URL(string: "https://v4.testnet.dydx.exchange/currencies/eth.png"),
marketName: "ETH-USD",
margin: "$1000.00",
viewOrdersAction: {},
cancelOrdersAction: {}
)
}()

private var topContent: some View {
VStack(spacing: 8) {
HStack(spacing: 8) {
PlatformIconViewModel(type: .url(url: marketLogoUrl),
clip: .defaultCircle,
size: CGSize(width: 20, height: 20))
.createView()
Text(marketName)
.themeFont(fontSize: .small)
.themeColor(foreground: .textSecondary)
Spacer()
}
HStack(spacing: 0) {
Text(localizerPathKey: "APP.GENERAL.MARGIN")
.themeFont(fontSize: .smaller)
.themeColor(foreground: .textTertiary)
Spacer()
Text(margin)
.themeFont(fontSize: .smaller)
.themeColor(foreground: .textSecondary)
}
}
.padding(.vertical, 10)
}

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

private var bottomContent: some View {
let viewOrders = Text(localizerPathKey: "APP.CLOSE_POSITIONS_CONFIRMATION_TOAST.VIEW_ORDERS")
.themeFont(fontSize: .smaller)
.themeColor(foreground: .colorPurple)
.padding(.vertical, 8)
let cancel = Text(localizerPathKey: "APP.GENERAL.CANCEL")
.themeFont(fontSize: .smaller)
.themeColor(foreground: .colorRed)
.padding(.vertical, 8)
return HStack(spacing: 0) {
Button(action: viewOrdersAction, label: { viewOrders })
Spacer()
Button(action: cancelOrdersAction, label: { cancel })
}
}

public override func createView(parentStyle: ThemeStyle = ThemeStyle.defaultStyle, styleKey: String? = nil) -> PlatformView {
PlatformView(viewModel: self, parentStyle: parentStyle, styleKey: styleKey) { [weak self] _ in
guard let self = self else { return AnyView(PlatformView.nilView) }

return VStack(spacing: 0) {
self.topContent
self.divider
self.bottomContent
}
.padding(.horizontal, 12)
.themeColor(background: .layer3)
.clipShape(.rect(cornerRadius: 10))
.wrappedInAnyView()
}
}
}

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

static var previews: some View {
Group {
dydxPortfolioUnopenedIsolatedPositionsItemViewModel.previewValue
.createView()
.environmentObject(themeSettings)
.previewLayout(.sizeThatFits)
}
}
}
#endif

0 comments on commit 38f23e7

Please sign in to comment.