From dc13e05a32daa2f153eb03bd6caa3e37069009eb Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Tue, 11 Jun 2024 22:28:53 -0500 Subject: [PATCH 01/20] remove unused files --- .../xcshareddata/swiftpm/Package.resolved | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved b/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved index 22de51701..dacd8494d 100644 --- a/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "975d00e29efb8d2ca017c5e61df90418ac01f7d7143e85a3f9ddb4eb982154e4", + "originHash" : "3cd7346cace16cf660f9c22302c5ca6770335c67902f3fd155011356a9d43929", "pins" : [ { "identity" : "bigint", @@ -37,15 +37,6 @@ "version" : "2.0.2" } }, - { - "identity" : "keyboardobserving", - "kind" : "remoteSourceControl", - "location" : "https://github.com/nickffox/KeyboardObserving", - "state" : { - "branch" : "master", - "revision" : "48134b5460435cc9d048223ad7560ee2e40f3d4a" - } - }, { "identity" : "percy-xcui-swift", "kind" : "remoteSourceControl", @@ -199,15 +190,6 @@ "version" : "9.0.9" } }, - { - "identity" : "swiftui-introspect", - "kind" : "remoteSourceControl", - "location" : "https://github.com/siteline/SwiftUI-Introspect.git", - "state" : { - "revision" : "121c146fe591b1320238d054ae35c81ffa45f45a", - "version" : "0.12.0" - } - }, { "identity" : "wallet-mobile-sdk", "kind" : "remoteSourceControl", From 772a36386b943314241ec701eaee5966284dff64 Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Wed, 12 Jun 2024 11:13:16 -0500 Subject: [PATCH 02/20] dismiss on success, update button state on submission --- .../xcshareddata/swiftpm/Package.resolved | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved b/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved index dacd8494d..22de51701 100644 --- a/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "3cd7346cace16cf660f9c22302c5ca6770335c67902f3fd155011356a9d43929", + "originHash" : "975d00e29efb8d2ca017c5e61df90418ac01f7d7143e85a3f9ddb4eb982154e4", "pins" : [ { "identity" : "bigint", @@ -37,6 +37,15 @@ "version" : "2.0.2" } }, + { + "identity" : "keyboardobserving", + "kind" : "remoteSourceControl", + "location" : "https://github.com/nickffox/KeyboardObserving", + "state" : { + "branch" : "master", + "revision" : "48134b5460435cc9d048223ad7560ee2e40f3d4a" + } + }, { "identity" : "percy-xcui-swift", "kind" : "remoteSourceControl", @@ -190,6 +199,15 @@ "version" : "9.0.9" } }, + { + "identity" : "swiftui-introspect", + "kind" : "remoteSourceControl", + "location" : "https://github.com/siteline/SwiftUI-Introspect.git", + "state" : { + "revision" : "121c146fe591b1320238d054ae35c81ffa45f45a", + "version" : "0.12.0" + } + }, { "identity" : "wallet-mobile-sdk", "kind" : "remoteSourceControl", From aa9add32526be4f39ff6cbbbcf342d23f73cea0c Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Wed, 12 Jun 2024 16:50:03 -0500 Subject: [PATCH 03/20] multi-line receipt line item title --- dydx/dydxViews/dydxViews/Shared/BeforeArrowAfter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dydx/dydxViews/dydxViews/Shared/BeforeArrowAfter.swift b/dydx/dydxViews/dydxViews/Shared/BeforeArrowAfter.swift index 6bc2d458e..c352d8020 100644 --- a/dydx/dydxViews/dydxViews/Shared/BeforeArrowAfter.swift +++ b/dydx/dydxViews/dydxViews/Shared/BeforeArrowAfter.swift @@ -55,7 +55,7 @@ public class BeforeArrowAfterModel: PlatformViewModel, .createView(parentStyle: style.themeColor(foreground: .textPrimary), styleKey: nil) } } - .fixedSize() + ) } } From 85178da5073aa9ef0b89156a70c478367acd7364 Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Wed, 12 Jun 2024 18:04:32 -0500 Subject: [PATCH 04/20] stubbed unopened isolated positions UI --- .../xcshareddata/swiftpm/Package.resolved | 20 +-- .../Sections/dydxPortfolioPositionsView.swift | 33 +++-- ...openedIsolatedPositionsItemViewModel.swift | 116 ++++++++++++++++++ 3 files changed, 139 insertions(+), 30 deletions(-) create mode 100644 dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift diff --git a/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved b/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved index 22de51701..dacd8494d 100644 --- a/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "975d00e29efb8d2ca017c5e61df90418ac01f7d7143e85a3f9ddb4eb982154e4", + "originHash" : "3cd7346cace16cf660f9c22302c5ca6770335c67902f3fd155011356a9d43929", "pins" : [ { "identity" : "bigint", @@ -37,15 +37,6 @@ "version" : "2.0.2" } }, - { - "identity" : "keyboardobserving", - "kind" : "remoteSourceControl", - "location" : "https://github.com/nickffox/KeyboardObserving", - "state" : { - "branch" : "master", - "revision" : "48134b5460435cc9d048223ad7560ee2e40f3d4a" - } - }, { "identity" : "percy-xcui-swift", "kind" : "remoteSourceControl", @@ -199,15 +190,6 @@ "version" : "9.0.9" } }, - { - "identity" : "swiftui-introspect", - "kind" : "remoteSourceControl", - "location" : "https://github.com/siteline/SwiftUI-Introspect.git", - "state" : { - "revision" : "121c146fe591b1320238d054ae35c81ffa45f45a", - "version" : "0.12.0" - } - }, { "identity" : "wallet-mobile-sdk", "kind" : "remoteSourceControl", diff --git a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift index 28b478a52..972baa414 100644 --- a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift +++ b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift @@ -251,7 +251,7 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel { contentChanged?() } } - @Published public var pendingPositionItems: [dydxPortfolioPendingPositionsItemViewModel] { + @Published public var unopenedIsolatedPositionItems: [dydxPortfolioUnopenedIsolatedPositionsItemViewModel] { didSet { contentChanged?() } @@ -261,11 +261,11 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel { init( positionItems: [dydxPortfolioPositionItemViewModel] = [], - pendingPositionItems: [dydxPortfolioPendingPositionsItemViewModel] = [], + unopenedIsolatedPositionItems: [dydxPortfolioUnopenedIsolatedPositionsItemViewModel] = [], emptyText: String? = nil ) { self.positionItems = positionItems - self.pendingPositionItems = pendingPositionItems + self.unopenedIsolatedPositionItems = unopenedIsolatedPositionItems self.emptyText = emptyText } @@ -275,7 +275,7 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel { .previewValue, .previewValue ], - pendingPositionItems: [ + unopenedIsolatedPositionItems: [ .previewValue ], emptyText: "empty") @@ -288,10 +288,8 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel { .themeFont(fontSize: .larger) .themeColor(foreground: .textPrimary) .fixedSize() - Text("\(pendingPositionItems.count)") + Text("\(unopenedIsolatedPositionItems.count)") .frame(width: 28, height: 28) - .themeColor(background: .layer3) - .themeColor(foreground: .textSecondary) .borderAndClip(style: .circle, borderColor: .borderDefault) Spacer() } @@ -326,18 +324,31 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel { 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, pendingPositionItems.isEmpty { + 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 { - VStack(spacing: 24) { - self.openPositionsView - self.pendingPositionsView + 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] + } } } ) diff --git a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift new file mode 100644 index 000000000..483df291b --- /dev/null +++ b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift @@ -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 From 1857630cd195f44e0071b0f2720f92a2baa0fe6e Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Thu, 13 Jun 2024 14:59:12 -0500 Subject: [PATCH 05/20] wire up abacus data for unopened positions --- ...rtfolioPendingPositionsItemViewModel.swift | 9 +- .../Sections/dydxPortfolioPositionsView.swift | 39 +++--- ...openedIsolatedPositionsItemViewModel.swift | 116 ------------------ 3 files changed, 26 insertions(+), 138 deletions(-) delete mode 100644 dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift diff --git a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPendingPositionsItemViewModel.swift b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPendingPositionsItemViewModel.swift index 97422b084..656c44335 100644 --- a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPendingPositionsItemViewModel.swift +++ b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPendingPositionsItemViewModel.swift @@ -68,15 +68,14 @@ public class dydxPortfolioPendingPositionsItemViewModel: PlatformViewModel { } private var divider: some View { - Rectangle() - .frame(height: 1) + Spacer(minLength: 1) .overlay(ThemeColor.SemanticColor.borderDefault.color) } private var bottomContent: some View { let viewOrdersStringKey: String let viewOrdersStringParams: [String: String]? - if orderCount == 1 { + if orderCount > 1 { viewOrdersStringKey = "APP.GENERAL.VIEW_ORDER" viewOrdersStringParams = nil } else { @@ -103,14 +102,12 @@ public class dydxPortfolioPendingPositionsItemViewModel: PlatformViewModel { PlatformView(viewModel: self, parentStyle: parentStyle, styleKey: styleKey) { [weak self] _ in guard let self = self else { return AnyView(PlatformView.nilView) } - let horizontalPadding: CGFloat = 12 return VStack(spacing: 0) { self.topContent self.divider - .padding(.horizontal, -horizontalPadding) self.bottomContent } - .padding(.horizontal, horizontalPadding) + .padding(.horizontal, 12) .themeColor(background: .layer3) .clipShape(.rect(cornerRadius: 10)) .wrappedInAnyView() diff --git a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift index 972baa414..b21b1182b 100644 --- a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift +++ b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift @@ -251,7 +251,7 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel { contentChanged?() } } - @Published public var unopenedIsolatedPositionItems: [dydxPortfolioUnopenedIsolatedPositionsItemViewModel] { + @Published public var pendingPositionItems: [dydxPortfolioPendingPositionsItemViewModel] { didSet { contentChanged?() } @@ -261,11 +261,11 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel { init( positionItems: [dydxPortfolioPositionItemViewModel] = [], - unopenedIsolatedPositionItems: [dydxPortfolioUnopenedIsolatedPositionsItemViewModel] = [], + pendingPositionItems: [dydxPortfolioPendingPositionsItemViewModel] = [], emptyText: String? = nil ) { self.positionItems = positionItems - self.unopenedIsolatedPositionItems = unopenedIsolatedPositionItems + self.pendingPositionItems = pendingPositionItems self.emptyText = emptyText } @@ -275,7 +275,7 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel { .previewValue, .previewValue ], - unopenedIsolatedPositionItems: [ + pendingPositionItems: [ .previewValue ], emptyText: "empty") @@ -288,8 +288,9 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel { .themeFont(fontSize: .larger) .themeColor(foreground: .textPrimary) .fixedSize() - Text("\(unopenedIsolatedPositionItems.count)") + Text("\(pendingPositionItems.count)") .frame(width: 28, height: 28) + .themeColor(background: .layer6) .borderAndClip(style: .circle, borderColor: .borderDefault) Spacer() } @@ -324,7 +325,7 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel { 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 { + if let emptyText = self.emptyText, positionItems.isEmpty, pendingPositionItems.isEmpty { return AnyView( PlaceholderViewModel(text: emptyText) .createView(parentStyle: style) @@ -332,22 +333,28 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel { } let items = self.positionItems.map { $0.createView(parentStyle: style) } - let unopenedItems = self.unopenedIsolatedPositionItems.map { $0.createView(parentStyle: style) } + let unopenedItems = self.pendingPositionItems.map { $0.createView(parentStyle: style) } return AnyView( ScrollView { - LazyVStack { - self.positionsHeader?.createView(parentStyle: style) + VStack(spacing: 24) { + LazyVStack { + self.positionsHeader?.createView(parentStyle: style) - ForEach(items.indices, id: \.self) { index in - items[index] - } + ForEach(items.indices, id: \.self) { index in + items[index] + } - self.positionsFooter?.createView(parentStyle: style) - self.unopenedIsolatedPositionsHeader?.createView(parentStyle: style) + self.positionsFooter?.createView(parentStyle: style) + } + if dydxBoolFeatureFlag.enable_isolated_margins.isEnabled { + LazyVStack { + self.pendingPositionsHeader?.createView(parentStyle: style) - ForEach(unopenedItems.indices, id: \.self) { index in - unopenedItems[index] + ForEach(unopenedItems.indices, id: \.self) { index in + unopenedItems[index] + } + } } } } diff --git a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift deleted file mode 100644 index 483df291b..000000000 --- a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift +++ /dev/null @@ -1,116 +0,0 @@ -// -// 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 From 3c4489a17b6b254c8140f848562ca6b8ddb8e6bd Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Thu, 13 Jun 2024 16:52:45 -0500 Subject: [PATCH 06/20] put back fixed size, clean up --- .../dydxViews/Shared/BeforeArrowAfter.swift | 2 +- .../Sections/dydxPortfolioPositionsView.swift | 23 ++----------------- 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/dydx/dydxViews/dydxViews/Shared/BeforeArrowAfter.swift b/dydx/dydxViews/dydxViews/Shared/BeforeArrowAfter.swift index c352d8020..95554887e 100644 --- a/dydx/dydxViews/dydxViews/Shared/BeforeArrowAfter.swift +++ b/dydx/dydxViews/dydxViews/Shared/BeforeArrowAfter.swift @@ -55,7 +55,7 @@ public class BeforeArrowAfterModel: PlatformViewModel, .createView(parentStyle: style.themeColor(foreground: .textPrimary), styleKey: nil) } } - + .fixedSize() ) } } diff --git a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift index b21b1182b..800adf1c1 100644 --- a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift +++ b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift @@ -332,30 +332,11 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel { ) } - let items = self.positionItems.map { $0.createView(parentStyle: style) } - let unopenedItems = self.pendingPositionItems.map { $0.createView(parentStyle: style) } - return AnyView( ScrollView { VStack(spacing: 24) { - LazyVStack { - self.positionsHeader?.createView(parentStyle: style) - - ForEach(items.indices, id: \.self) { index in - items[index] - } - - self.positionsFooter?.createView(parentStyle: style) - } - if dydxBoolFeatureFlag.enable_isolated_margins.isEnabled { - LazyVStack { - self.pendingPositionsHeader?.createView(parentStyle: style) - - ForEach(unopenedItems.indices, id: \.self) { index in - unopenedItems[index] - } - } - } + self.openPositionsView + self.pendingPositionsView } } ) From 987f18b4eeaa9d3667915825437edabe23c8853b Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Fri, 14 Jun 2024 14:47:42 -0500 Subject: [PATCH 07/20] update button state after validation --- .../xcshareddata/swiftpm/Package.resolved | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved b/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved index dacd8494d..22de51701 100644 --- a/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "3cd7346cace16cf660f9c22302c5ca6770335c67902f3fd155011356a9d43929", + "originHash" : "975d00e29efb8d2ca017c5e61df90418ac01f7d7143e85a3f9ddb4eb982154e4", "pins" : [ { "identity" : "bigint", @@ -37,6 +37,15 @@ "version" : "2.0.2" } }, + { + "identity" : "keyboardobserving", + "kind" : "remoteSourceControl", + "location" : "https://github.com/nickffox/KeyboardObserving", + "state" : { + "branch" : "master", + "revision" : "48134b5460435cc9d048223ad7560ee2e40f3d4a" + } + }, { "identity" : "percy-xcui-swift", "kind" : "remoteSourceControl", @@ -190,6 +199,15 @@ "version" : "9.0.9" } }, + { + "identity" : "swiftui-introspect", + "kind" : "remoteSourceControl", + "location" : "https://github.com/siteline/SwiftUI-Introspect.git", + "state" : { + "revision" : "121c146fe591b1320238d054ae35c81ffa45f45a", + "version" : "0.12.0" + } + }, { "identity" : "wallet-mobile-sdk", "kind" : "remoteSourceControl", From 743b0917556475f2e98a77fc3e73f1269eccfcb8 Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Fri, 14 Jun 2024 14:54:03 -0500 Subject: [PATCH 08/20] clean up --- dydx/dydxViews/dydxViews/Shared/BeforeArrowAfter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dydx/dydxViews/dydxViews/Shared/BeforeArrowAfter.swift b/dydx/dydxViews/dydxViews/Shared/BeforeArrowAfter.swift index 95554887e..6bc2d458e 100644 --- a/dydx/dydxViews/dydxViews/Shared/BeforeArrowAfter.swift +++ b/dydx/dydxViews/dydxViews/Shared/BeforeArrowAfter.swift @@ -55,7 +55,7 @@ public class BeforeArrowAfterModel: PlatformViewModel, .createView(parentStyle: style.themeColor(foreground: .textPrimary), styleKey: nil) } } - .fixedSize() + .fixedSize() ) } } From 1aceff55e34c29f884c18a5977e1a7bb9ae1de77 Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Mon, 17 Jun 2024 13:57:14 -0400 Subject: [PATCH 09/20] ui tweaks --- .../dydxPortfolioPendingPositionsItemViewModel.swift | 9 ++++++--- .../Components/Sections/dydxPortfolioPositionsView.swift | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPendingPositionsItemViewModel.swift b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPendingPositionsItemViewModel.swift index 656c44335..97422b084 100644 --- a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPendingPositionsItemViewModel.swift +++ b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPendingPositionsItemViewModel.swift @@ -68,14 +68,15 @@ public class dydxPortfolioPendingPositionsItemViewModel: PlatformViewModel { } private var divider: some View { - Spacer(minLength: 1) + Rectangle() + .frame(height: 1) .overlay(ThemeColor.SemanticColor.borderDefault.color) } private var bottomContent: some View { let viewOrdersStringKey: String let viewOrdersStringParams: [String: String]? - if orderCount > 1 { + if orderCount == 1 { viewOrdersStringKey = "APP.GENERAL.VIEW_ORDER" viewOrdersStringParams = nil } else { @@ -102,12 +103,14 @@ public class dydxPortfolioPendingPositionsItemViewModel: PlatformViewModel { PlatformView(viewModel: self, parentStyle: parentStyle, styleKey: styleKey) { [weak self] _ in guard let self = self else { return AnyView(PlatformView.nilView) } + let horizontalPadding: CGFloat = 12 return VStack(spacing: 0) { self.topContent self.divider + .padding(.horizontal, -horizontalPadding) self.bottomContent } - .padding(.horizontal, 12) + .padding(.horizontal, horizontalPadding) .themeColor(background: .layer3) .clipShape(.rect(cornerRadius: 10)) .wrappedInAnyView() diff --git a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift index 800adf1c1..28b478a52 100644 --- a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift +++ b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift @@ -290,7 +290,8 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel { .fixedSize() Text("\(pendingPositionItems.count)") .frame(width: 28, height: 28) - .themeColor(background: .layer6) + .themeColor(background: .layer3) + .themeColor(foreground: .textSecondary) .borderAndClip(style: .circle, borderColor: .borderDefault) Spacer() } From 57f8a0962e33a7e23cc5f7306c2dcb8b166d68c4 Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Tue, 18 Jun 2024 15:45:29 -0400 Subject: [PATCH 10/20] Update Package.resolved --- .../xcshareddata/swiftpm/Package.resolved | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved b/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved index 22de51701..dacd8494d 100644 --- a/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "975d00e29efb8d2ca017c5e61df90418ac01f7d7143e85a3f9ddb4eb982154e4", + "originHash" : "3cd7346cace16cf660f9c22302c5ca6770335c67902f3fd155011356a9d43929", "pins" : [ { "identity" : "bigint", @@ -37,15 +37,6 @@ "version" : "2.0.2" } }, - { - "identity" : "keyboardobserving", - "kind" : "remoteSourceControl", - "location" : "https://github.com/nickffox/KeyboardObserving", - "state" : { - "branch" : "master", - "revision" : "48134b5460435cc9d048223ad7560ee2e40f3d4a" - } - }, { "identity" : "percy-xcui-swift", "kind" : "remoteSourceControl", @@ -199,15 +190,6 @@ "version" : "9.0.9" } }, - { - "identity" : "swiftui-introspect", - "kind" : "remoteSourceControl", - "location" : "https://github.com/siteline/SwiftUI-Introspect.git", - "state" : { - "revision" : "121c146fe591b1320238d054ae35c81ffa45f45a", - "version" : "0.12.0" - } - }, { "identity" : "wallet-mobile-sdk", "kind" : "remoteSourceControl", From 257f83c3f857707ea74d00ca8230583628d4e15f Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Wed, 12 Jun 2024 18:04:32 -0500 Subject: [PATCH 11/20] stubbed unopened isolated positions UI --- ...openedIsolatedPositionsItemViewModel.swift | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift diff --git a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift new file mode 100644 index 000000000..483df291b --- /dev/null +++ b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift @@ -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 From f9395f016b05c0bb448c0cf1213a96554248effc Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Thu, 13 Jun 2024 14:59:12 -0500 Subject: [PATCH 12/20] wire up abacus data for unopened positions --- ...openedIsolatedPositionsItemViewModel.swift | 116 ------------------ 1 file changed, 116 deletions(-) delete mode 100644 dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift diff --git a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift deleted file mode 100644 index 483df291b..000000000 --- a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioUnopenedIsolatedPositionsItemViewModel.swift +++ /dev/null @@ -1,116 +0,0 @@ -// -// 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 From fb4d92a84d502d6030129a0e67c719f8a4876acc Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Fri, 14 Jun 2024 14:47:42 -0500 Subject: [PATCH 13/20] update button state after validation --- .../xcshareddata/swiftpm/Package.resolved | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved b/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved index dacd8494d..22de51701 100644 --- a/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/dydx/dydx.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "3cd7346cace16cf660f9c22302c5ca6770335c67902f3fd155011356a9d43929", + "originHash" : "975d00e29efb8d2ca017c5e61df90418ac01f7d7143e85a3f9ddb4eb982154e4", "pins" : [ { "identity" : "bigint", @@ -37,6 +37,15 @@ "version" : "2.0.2" } }, + { + "identity" : "keyboardobserving", + "kind" : "remoteSourceControl", + "location" : "https://github.com/nickffox/KeyboardObserving", + "state" : { + "branch" : "master", + "revision" : "48134b5460435cc9d048223ad7560ee2e40f3d4a" + } + }, { "identity" : "percy-xcui-swift", "kind" : "remoteSourceControl", @@ -190,6 +199,15 @@ "version" : "9.0.9" } }, + { + "identity" : "swiftui-introspect", + "kind" : "remoteSourceControl", + "location" : "https://github.com/siteline/SwiftUI-Introspect.git", + "state" : { + "revision" : "121c146fe591b1320238d054ae35c81ffa45f45a", + "version" : "0.12.0" + } + }, { "identity" : "wallet-mobile-sdk", "kind" : "remoteSourceControl", From 6615d98f08701763ce2ba342bfc442add85157fb Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Fri, 14 Jun 2024 16:16:14 -0500 Subject: [PATCH 14/20] change routing to orders tab, populate unopened isolated position --- .../Components/Position/dydxMarketPositionView.swift | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/dydx/dydxViews/dydxViews/_v4/MarketInfo/Components/Position/dydxMarketPositionView.swift b/dydx/dydxViews/dydxViews/_v4/MarketInfo/Components/Position/dydxMarketPositionView.swift index 4b652d0ff..b18659ce1 100644 --- a/dydx/dydxViews/dydxViews/_v4/MarketInfo/Components/Position/dydxMarketPositionView.swift +++ b/dydx/dydxViews/dydxViews/_v4/MarketInfo/Components/Position/dydxMarketPositionView.swift @@ -33,13 +33,7 @@ public class dydxMarketPositionViewModel: PlatformViewModel { @Published public var takeProfitStatusViewModel: dydxTakeProfitStopLossStatusViewModel? @Published public var stopLossStatusViewModel: dydxTakeProfitStopLossStatusViewModel? - @Published public var pendingPosition: dydxPortfolioPendingPositionsItemViewModel? { - didSet { - contentChanged?() - } - } - - @Published public var contentChanged: (() -> Void)? + @Published public var pendingPosition: dydxPortfolioPendingPositionsItemViewModel? public init() { } From 004d79d8969eebc26baa2c8f681a069733702ce0 Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Mon, 17 Jun 2024 16:11:38 -0400 Subject: [PATCH 15/20] show unopened isolated position in market info view --- .../Components/Position/dydxMarketPositionView.swift | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dydx/dydxViews/dydxViews/_v4/MarketInfo/Components/Position/dydxMarketPositionView.swift b/dydx/dydxViews/dydxViews/_v4/MarketInfo/Components/Position/dydxMarketPositionView.swift index b18659ce1..4b652d0ff 100644 --- a/dydx/dydxViews/dydxViews/_v4/MarketInfo/Components/Position/dydxMarketPositionView.swift +++ b/dydx/dydxViews/dydxViews/_v4/MarketInfo/Components/Position/dydxMarketPositionView.swift @@ -33,7 +33,13 @@ public class dydxMarketPositionViewModel: PlatformViewModel { @Published public var takeProfitStatusViewModel: dydxTakeProfitStopLossStatusViewModel? @Published public var stopLossStatusViewModel: dydxTakeProfitStopLossStatusViewModel? - @Published public var pendingPosition: dydxPortfolioPendingPositionsItemViewModel? + @Published public var pendingPosition: dydxPortfolioPendingPositionsItemViewModel? { + didSet { + contentChanged?() + } + } + + @Published public var contentChanged: (() -> Void)? public init() { } From 511176754203e1702e1e673a74f77ed400a6a29b Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Tue, 18 Jun 2024 10:49:08 -0400 Subject: [PATCH 16/20] stub UI for cancel orders --- ...ncelPendingIsolatedOrdersViewBuilder.swift | 89 +-------------- .../dydxCancelPendingIsolatedOrdersView.swift | 103 ++---------------- 2 files changed, 10 insertions(+), 182 deletions(-) diff --git a/dydx/dydxPresenters/dydxPresenters/_v4/CancelOrders/dydxCancelPendingIsolatedOrdersViewBuilder.swift b/dydx/dydxPresenters/dydxPresenters/_v4/CancelOrders/dydxCancelPendingIsolatedOrdersViewBuilder.swift index a2bef61be..a40da1f03 100644 --- a/dydx/dydxPresenters/dydxPresenters/_v4/CancelOrders/dydxCancelPendingIsolatedOrdersViewBuilder.swift +++ b/dydx/dydxPresenters/dydxPresenters/_v4/CancelOrders/dydxCancelPendingIsolatedOrdersViewBuilder.swift @@ -11,8 +11,6 @@ import PlatformParticles import RoutingKit import ParticlesKit import PlatformUI -import dydxStateManager -import Combine public class dydxCancelPendingIsolatedOrdersViewBuilder: NSObject, ObjectBuilderProtocol { public func build() -> T? { @@ -24,10 +22,7 @@ public class dydxCancelPendingIsolatedOrdersViewBuilder: NSObject, ObjectBuilder private class dydxCancelPendingIsolatedOrdersViewBuilderController: HostingViewController { override public func arrive(to request: RoutingRequest?, animated: Bool) -> Bool { - if let marketId = request?.params?["market"] as? String, - request?.path == "/portfolio/cancel_pending_position", - let presenter = presenter as? dydxCancelPendingIsolatedOrdersViewBuilderPresenterProtocol { - presenter.marketId = marketId + if request?.path == "/portfolio/cancel_pending_position" { return true } return false @@ -36,92 +31,12 @@ private class dydxCancelPendingIsolatedOrdersViewBuilderController: HostingViewC private protocol dydxCancelPendingIsolatedOrdersViewBuilderPresenterProtocol: HostedViewPresenterProtocol { var viewModel: dydxCancelPendingIsolatedOrdersViewModel? { get } - var marketId: String? { get set } } private class dydxCancelPendingIsolatedOrdersViewBuilderPresenter: HostedViewPresenter, dydxCancelPendingIsolatedOrdersViewBuilderPresenterProtocol { - fileprivate var marketId: String? - override init() { super.init() - self.viewModel = .init(marketLogoUrl: nil, marketName: "", marketId: "", orderCount: 0, cancelAction: {}) - } - - override func start() { - super.start() - - Publishers.CombineLatest( - AbacusStateManager.shared.state.configsAndAssetMap, - AbacusStateManager.shared.state.selectedSubaccountOrders - ) - .receive(on: RunLoop.main) - .sink { [weak self] configsAndAssetMap, orders in - guard let self = self, - let marketId = self.marketId, - let asset = configsAndAssetMap[marketId]?.asset - else { return } - let pendingOrders = orders.filter { $0.marketId == marketId && $0.status == .open } - self.viewModel?.marketLogoUrl = URL(string: asset.resources?.imageUrl ?? "") - self.viewModel?.marketName = asset.name ?? "--" - self.viewModel?.marketId = asset.id - self.viewModel?.orderCount = pendingOrders.count - self.viewModel?.failureCount = self.viewModel?.failureCount - self.viewModel?.cancelAction = { [weak self] in - self?.tryCancelOrders(orderIds: orders.map(\.id)) - } - } - .store(in: &subscriptions) - } - - private func tryCancelOrders(orderIds: [String]) { - viewModel?.state = viewModel?.failureCount == nil ? .submitting : .resubmitting - Task { [weak self] in - guard let self = self else { return } - - // Create an array to hold the results of the cancellations - var results: [Result] = [] - - // Use a TaskGroup to kick off multiple calls and wait for all to finish - await withTaskGroup(of: Result.self) { group in - for orderId in orderIds { - group.addTask { - do { - let status = try await AbacusStateManager.shared.cancelOrder(orderId: orderId) - return .success(status) - } catch { - return .failure(error) - } - } - } - - // Collect the results of all tasks - for await result in group { - results.append(result) - } - } - - // Count the number of failed cancellations - let failureCount = results.filter { result in - if case .failure = result { - return true - } - return false - }.count - - await updateState(failureCount: failureCount) - } + self.viewModel = .previewValue } - - @MainActor - private func updateState(failureCount: Int) { - self.viewModel?.failureCount = failureCount - - if failureCount > 0 { - self.viewModel?.state = .failed - } else { - Router.shared?.navigate(to: RoutingRequest(path: "/action/dismiss"), animated: true, completion: nil) - } - } - } diff --git a/dydx/dydxViews/dydxViews/_v4/CancelOrders/dydxCancelPendingIsolatedOrdersView.swift b/dydx/dydxViews/dydxViews/_v4/CancelOrders/dydxCancelPendingIsolatedOrdersView.swift index d34ce5783..54782a51c 100644 --- a/dydx/dydxViews/dydxViews/_v4/CancelOrders/dydxCancelPendingIsolatedOrdersView.swift +++ b/dydx/dydxViews/dydxViews/_v4/CancelOrders/dydxCancelPendingIsolatedOrdersView.swift @@ -11,34 +11,22 @@ import Utilities import SDWebImageSwiftUI public class dydxCancelPendingIsolatedOrdersViewModel: PlatformViewModel { - public enum State { - case readyToSubmit - case failed - case submitting - case resubmitting - } - - @Published public var state: State = .readyToSubmit - @Published public var marketLogoUrl: URL? @Published public var marketName: String @Published public var marketId: String @Published public var orderCount: Int - @Published public var failureCount: Int? @Published public var cancelAction: (() -> Void) public init(marketLogoUrl: URL?, marketName: String, marketId: String, orderCount: Int, - failureCount: Int? = nil, cancelAction: @escaping (() -> Void) ) { self.marketLogoUrl = marketLogoUrl self.marketName = marketName self.marketId = marketId self.orderCount = orderCount - self.failureCount = failureCount self.cancelAction = cancelAction } @@ -47,7 +35,6 @@ public class dydxCancelPendingIsolatedOrdersViewModel: PlatformViewModel { marketName: "Ethereum", marketId: "ETH-USDC", orderCount: 1, - failureCount: nil, cancelAction: {} ) } @@ -55,74 +42,8 @@ public class dydxCancelPendingIsolatedOrdersViewModel: PlatformViewModel { public override func createView(parentStyle: ThemeStyle = ThemeStyle.defaultStyle, styleKey: String? = nil) -> PlatformUI.PlatformView { PlatformView(viewModel: self, parentStyle: parentStyle, styleKey: styleKey) { [weak self] _ in guard let self = self else { return AnyView(PlatformView.nilView) } - switch self.state { - case .readyToSubmit, .submitting: - return CancelView(viewModel: self).wrappedInAnyView() - case .failed, .resubmitting: - return TryAgainView(viewModel: self).wrappedInAnyView() - } - } - } -} - -private struct TryAgainView: View { - @StateObject var viewModel = dydxCancelPendingIsolatedOrdersViewModel.previewValue - - var errorImage: some View { - Image("icon_error", bundle: .dydxView) - .resizable() - .templateColor(.colorRed) - .scaledToFit() - .frame(width: 40, height: 40) - .padding(.all, 20) - .themeColor(background: .layer3) - .clipShape(.circle) - } - - var title: some View { - if let failureCount = viewModel.failureCount { - let key = viewModel.failureCount == 1 ? "APP.TRADE.CANCELING_ONE_ORDER_FAILED" : "APP.TRADE.CANCELING_N_ORDERS_FAILED" - let params = ["COUNT": "\(failureCount)"] - return Text(localizerPathKey: key, params: params) - .themeFont(fontType: .plus, fontSize: .largest) - .themeColor(foreground: .textPrimary) - } else { - return Text("") - } - - } - - var button: some View { - let content: Text - let buttonState: PlatformButtonState = viewModel.state == .resubmitting ? .disabled : .destructive - if viewModel.state == .resubmitting { - content = Text(localizerPathKey: "APP.TRADE.CANCELING_ORDERS_COUNT", params: ["COUNT": "\(viewModel.orderCount)"]) - .themeFont(fontType: .base, fontSize: .medium) - .themeColor(foreground: .textTertiary) - } else { - content = Text(localizerPathKey: "APP.ONBOARDING.TRY_AGAIN") - .themeFont(fontType: .base, fontSize: .medium) - .themeColor(foreground: .textPrimary) + return AnyView(CancelView(viewModel: self)) } - return PlatformButtonViewModel(content: content.wrappedViewModel, - type: .defaultType(), - state: buttonState, - action: viewModel.cancelAction) - .createView() - } - - var body: some View { - VStack(spacing: 24) { - errorImage - title - button - } - .padding(.horizontal, 24) - .padding(.top, 60) - .padding(.bottom, max((safeAreaInsets?.bottom ?? 0), 24)) - .themeColor(background: .layer4) - .makeSheet(sheetStyle: .fitSize) - .ignoresSafeArea(edges: [.bottom]) } } @@ -139,7 +60,7 @@ private struct CancelView: View { var title: some View { return Text(localizerPathKey: "APP.TRADE.CANCEL_ORDERS") - .themeFont(fontType: .plus, fontSize: .largest) + .themeFont(fontType: .base, fontSize: .large) .themeColor(foreground: .textPrimary) } @@ -172,22 +93,14 @@ private struct CancelView: View { } var button: some View { - let content: Text - let buttonState: PlatformButtonState = viewModel.state == .submitting ? .disabled : .destructive - if viewModel.state == .submitting { - content = Text(localizerPathKey: "APP.TRADE.CANCELING_ORDERS_COUNT", params: ["COUNT": "\(viewModel.orderCount)"]) - .themeFont(fontType: .base, fontSize: .medium) - .themeColor(foreground: .textTertiary) - } else { - let key = viewModel.orderCount == 1 ? "APP.TRADE.CANCEL_ORDER" : "APP.TRADE.CANCEL_ORDERS_COUNT" - let params = ["COUNT": "\(viewModel.orderCount)"] - content = Text(localizerPathKey: key, params: params) - .themeFont(fontType: .base, fontSize: .medium) - .themeColor(foreground: .colorRed) - } + let key = viewModel.orderCount == 1 ? "APP.TRADE.CANCEL_ORDER" : "APP.TRADE.CANCEL_ORDERS_COUNT" + let params = ["COUNT": "\(viewModel.orderCount)"] + let content = Text(localizerPathKey: key, params: params) + .themeFont(fontType: .base, fontSize: .medium) + .themeColor(foreground: .textPrimary) return PlatformButtonViewModel(content: content.wrappedViewModel, type: .defaultType(), - state: buttonState, + state: .destructive, action: viewModel.cancelAction) .createView() } From 21f29ce49cd8dbcadf5f5c2a398f47df41349e3f Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Wed, 19 Jun 2024 15:13:29 -0400 Subject: [PATCH 17/20] cancel orders --- ...ncelPendingIsolatedOrdersViewBuilder.swift | 89 ++++++++++++++- .../dydxCancelPendingIsolatedOrdersView.swift | 103 ++++++++++++++++-- 2 files changed, 182 insertions(+), 10 deletions(-) diff --git a/dydx/dydxPresenters/dydxPresenters/_v4/CancelOrders/dydxCancelPendingIsolatedOrdersViewBuilder.swift b/dydx/dydxPresenters/dydxPresenters/_v4/CancelOrders/dydxCancelPendingIsolatedOrdersViewBuilder.swift index a40da1f03..a2bef61be 100644 --- a/dydx/dydxPresenters/dydxPresenters/_v4/CancelOrders/dydxCancelPendingIsolatedOrdersViewBuilder.swift +++ b/dydx/dydxPresenters/dydxPresenters/_v4/CancelOrders/dydxCancelPendingIsolatedOrdersViewBuilder.swift @@ -11,6 +11,8 @@ import PlatformParticles import RoutingKit import ParticlesKit import PlatformUI +import dydxStateManager +import Combine public class dydxCancelPendingIsolatedOrdersViewBuilder: NSObject, ObjectBuilderProtocol { public func build() -> T? { @@ -22,7 +24,10 @@ public class dydxCancelPendingIsolatedOrdersViewBuilder: NSObject, ObjectBuilder private class dydxCancelPendingIsolatedOrdersViewBuilderController: HostingViewController { override public func arrive(to request: RoutingRequest?, animated: Bool) -> Bool { - if request?.path == "/portfolio/cancel_pending_position" { + if let marketId = request?.params?["market"] as? String, + request?.path == "/portfolio/cancel_pending_position", + let presenter = presenter as? dydxCancelPendingIsolatedOrdersViewBuilderPresenterProtocol { + presenter.marketId = marketId return true } return false @@ -31,12 +36,92 @@ private class dydxCancelPendingIsolatedOrdersViewBuilderController: HostingViewC private protocol dydxCancelPendingIsolatedOrdersViewBuilderPresenterProtocol: HostedViewPresenterProtocol { var viewModel: dydxCancelPendingIsolatedOrdersViewModel? { get } + var marketId: String? { get set } } private class dydxCancelPendingIsolatedOrdersViewBuilderPresenter: HostedViewPresenter, dydxCancelPendingIsolatedOrdersViewBuilderPresenterProtocol { + fileprivate var marketId: String? + override init() { super.init() - self.viewModel = .previewValue + self.viewModel = .init(marketLogoUrl: nil, marketName: "", marketId: "", orderCount: 0, cancelAction: {}) + } + + override func start() { + super.start() + + Publishers.CombineLatest( + AbacusStateManager.shared.state.configsAndAssetMap, + AbacusStateManager.shared.state.selectedSubaccountOrders + ) + .receive(on: RunLoop.main) + .sink { [weak self] configsAndAssetMap, orders in + guard let self = self, + let marketId = self.marketId, + let asset = configsAndAssetMap[marketId]?.asset + else { return } + let pendingOrders = orders.filter { $0.marketId == marketId && $0.status == .open } + self.viewModel?.marketLogoUrl = URL(string: asset.resources?.imageUrl ?? "") + self.viewModel?.marketName = asset.name ?? "--" + self.viewModel?.marketId = asset.id + self.viewModel?.orderCount = pendingOrders.count + self.viewModel?.failureCount = self.viewModel?.failureCount + self.viewModel?.cancelAction = { [weak self] in + self?.tryCancelOrders(orderIds: orders.map(\.id)) + } + } + .store(in: &subscriptions) + } + + private func tryCancelOrders(orderIds: [String]) { + viewModel?.state = viewModel?.failureCount == nil ? .submitting : .resubmitting + Task { [weak self] in + guard let self = self else { return } + + // Create an array to hold the results of the cancellations + var results: [Result] = [] + + // Use a TaskGroup to kick off multiple calls and wait for all to finish + await withTaskGroup(of: Result.self) { group in + for orderId in orderIds { + group.addTask { + do { + let status = try await AbacusStateManager.shared.cancelOrder(orderId: orderId) + return .success(status) + } catch { + return .failure(error) + } + } + } + + // Collect the results of all tasks + for await result in group { + results.append(result) + } + } + + // Count the number of failed cancellations + let failureCount = results.filter { result in + if case .failure = result { + return true + } + return false + }.count + + await updateState(failureCount: failureCount) + } } + + @MainActor + private func updateState(failureCount: Int) { + self.viewModel?.failureCount = failureCount + + if failureCount > 0 { + self.viewModel?.state = .failed + } else { + Router.shared?.navigate(to: RoutingRequest(path: "/action/dismiss"), animated: true, completion: nil) + } + } + } diff --git a/dydx/dydxViews/dydxViews/_v4/CancelOrders/dydxCancelPendingIsolatedOrdersView.swift b/dydx/dydxViews/dydxViews/_v4/CancelOrders/dydxCancelPendingIsolatedOrdersView.swift index 54782a51c..d34ce5783 100644 --- a/dydx/dydxViews/dydxViews/_v4/CancelOrders/dydxCancelPendingIsolatedOrdersView.swift +++ b/dydx/dydxViews/dydxViews/_v4/CancelOrders/dydxCancelPendingIsolatedOrdersView.swift @@ -11,22 +11,34 @@ import Utilities import SDWebImageSwiftUI public class dydxCancelPendingIsolatedOrdersViewModel: PlatformViewModel { + public enum State { + case readyToSubmit + case failed + case submitting + case resubmitting + } + + @Published public var state: State = .readyToSubmit + @Published public var marketLogoUrl: URL? @Published public var marketName: String @Published public var marketId: String @Published public var orderCount: Int + @Published public var failureCount: Int? @Published public var cancelAction: (() -> Void) public init(marketLogoUrl: URL?, marketName: String, marketId: String, orderCount: Int, + failureCount: Int? = nil, cancelAction: @escaping (() -> Void) ) { self.marketLogoUrl = marketLogoUrl self.marketName = marketName self.marketId = marketId self.orderCount = orderCount + self.failureCount = failureCount self.cancelAction = cancelAction } @@ -35,6 +47,7 @@ public class dydxCancelPendingIsolatedOrdersViewModel: PlatformViewModel { marketName: "Ethereum", marketId: "ETH-USDC", orderCount: 1, + failureCount: nil, cancelAction: {} ) } @@ -42,8 +55,74 @@ public class dydxCancelPendingIsolatedOrdersViewModel: PlatformViewModel { public override func createView(parentStyle: ThemeStyle = ThemeStyle.defaultStyle, styleKey: String? = nil) -> PlatformUI.PlatformView { PlatformView(viewModel: self, parentStyle: parentStyle, styleKey: styleKey) { [weak self] _ in guard let self = self else { return AnyView(PlatformView.nilView) } - return AnyView(CancelView(viewModel: self)) + switch self.state { + case .readyToSubmit, .submitting: + return CancelView(viewModel: self).wrappedInAnyView() + case .failed, .resubmitting: + return TryAgainView(viewModel: self).wrappedInAnyView() + } + } + } +} + +private struct TryAgainView: View { + @StateObject var viewModel = dydxCancelPendingIsolatedOrdersViewModel.previewValue + + var errorImage: some View { + Image("icon_error", bundle: .dydxView) + .resizable() + .templateColor(.colorRed) + .scaledToFit() + .frame(width: 40, height: 40) + .padding(.all, 20) + .themeColor(background: .layer3) + .clipShape(.circle) + } + + var title: some View { + if let failureCount = viewModel.failureCount { + let key = viewModel.failureCount == 1 ? "APP.TRADE.CANCELING_ONE_ORDER_FAILED" : "APP.TRADE.CANCELING_N_ORDERS_FAILED" + let params = ["COUNT": "\(failureCount)"] + return Text(localizerPathKey: key, params: params) + .themeFont(fontType: .plus, fontSize: .largest) + .themeColor(foreground: .textPrimary) + } else { + return Text("") + } + + } + + var button: some View { + let content: Text + let buttonState: PlatformButtonState = viewModel.state == .resubmitting ? .disabled : .destructive + if viewModel.state == .resubmitting { + content = Text(localizerPathKey: "APP.TRADE.CANCELING_ORDERS_COUNT", params: ["COUNT": "\(viewModel.orderCount)"]) + .themeFont(fontType: .base, fontSize: .medium) + .themeColor(foreground: .textTertiary) + } else { + content = Text(localizerPathKey: "APP.ONBOARDING.TRY_AGAIN") + .themeFont(fontType: .base, fontSize: .medium) + .themeColor(foreground: .textPrimary) } + return PlatformButtonViewModel(content: content.wrappedViewModel, + type: .defaultType(), + state: buttonState, + action: viewModel.cancelAction) + .createView() + } + + var body: some View { + VStack(spacing: 24) { + errorImage + title + button + } + .padding(.horizontal, 24) + .padding(.top, 60) + .padding(.bottom, max((safeAreaInsets?.bottom ?? 0), 24)) + .themeColor(background: .layer4) + .makeSheet(sheetStyle: .fitSize) + .ignoresSafeArea(edges: [.bottom]) } } @@ -60,7 +139,7 @@ private struct CancelView: View { var title: some View { return Text(localizerPathKey: "APP.TRADE.CANCEL_ORDERS") - .themeFont(fontType: .base, fontSize: .large) + .themeFont(fontType: .plus, fontSize: .largest) .themeColor(foreground: .textPrimary) } @@ -93,14 +172,22 @@ private struct CancelView: View { } var button: some View { - let key = viewModel.orderCount == 1 ? "APP.TRADE.CANCEL_ORDER" : "APP.TRADE.CANCEL_ORDERS_COUNT" - let params = ["COUNT": "\(viewModel.orderCount)"] - let content = Text(localizerPathKey: key, params: params) - .themeFont(fontType: .base, fontSize: .medium) - .themeColor(foreground: .textPrimary) + let content: Text + let buttonState: PlatformButtonState = viewModel.state == .submitting ? .disabled : .destructive + if viewModel.state == .submitting { + content = Text(localizerPathKey: "APP.TRADE.CANCELING_ORDERS_COUNT", params: ["COUNT": "\(viewModel.orderCount)"]) + .themeFont(fontType: .base, fontSize: .medium) + .themeColor(foreground: .textTertiary) + } else { + let key = viewModel.orderCount == 1 ? "APP.TRADE.CANCEL_ORDER" : "APP.TRADE.CANCEL_ORDERS_COUNT" + let params = ["COUNT": "\(viewModel.orderCount)"] + content = Text(localizerPathKey: key, params: params) + .themeFont(fontType: .base, fontSize: .medium) + .themeColor(foreground: .colorRed) + } return PlatformButtonViewModel(content: content.wrappedViewModel, type: .defaultType(), - state: .destructive, + state: buttonState, action: viewModel.cancelAction) .createView() } From b5b0a4a73e53918c96ea97636b74e84381a1f4d7 Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Wed, 19 Jun 2024 18:17:08 -0400 Subject: [PATCH 18/20] remove isolated checks --- .../Portfolio/Components/dydxPortfolioOrdersViewPresenter.swift | 2 -- .../Components/dydxPortfolioPositionsViewPresenter.swift | 2 -- .../Portfolio/Components/Sections/dydxPortfolioOrdersView.swift | 1 - .../Components/Sections/dydxPortfolioPositionsView.swift | 2 -- 4 files changed, 7 deletions(-) diff --git a/dydx/dydxPresenters/dydxPresenters/_v4/Portfolio/Components/dydxPortfolioOrdersViewPresenter.swift b/dydx/dydxPresenters/dydxPresenters/_v4/Portfolio/Components/dydxPortfolioOrdersViewPresenter.swift index c77c0ce95..f331ee241 100644 --- a/dydx/dydxPresenters/dydxPresenters/_v4/Portfolio/Components/dydxPortfolioOrdersViewPresenter.swift +++ b/dydx/dydxPresenters/dydxPresenters/_v4/Portfolio/Components/dydxPortfolioOrdersViewPresenter.swift @@ -36,8 +36,6 @@ class dydxPortfolioOrdersViewPresenter: HostedViewPresenter Date: Wed, 19 Jun 2024 18:17:46 -0400 Subject: [PATCH 19/20] remove "USD" from market names --- .../_v4/Markets/Components/dydxMarketAssetItemView.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dydx/dydxViews/dydxViews/_v4/Markets/Components/dydxMarketAssetItemView.swift b/dydx/dydxViews/dydxViews/_v4/Markets/Components/dydxMarketAssetItemView.swift index 35e565a53..bfa0353d7 100644 --- a/dydx/dydxViews/dydxViews/_v4/Markets/Components/dydxMarketAssetItemView.swift +++ b/dydx/dydxViews/dydxViews/_v4/Markets/Components/dydxMarketAssetItemView.swift @@ -91,10 +91,6 @@ open class dydxMarketAssetItemViewModel: PlatformViewModel { .themeColor(foreground: .textPrimary) .themeFont(fontType: .plus, fontSize: .medium) .layoutPriority(1) - Text("USD") - .themeColor(foreground: .textSecondary) - .themeFont(fontType: .plus, fontSize: .medium) - .minimumScaleFactor(0.5) } Text(sharedMarketViewModel?.volume24H ?? "") .themeFont(fontType: .base, fontSize: .small) From 981eb80bd74b3a3327c270315fdfbfa437217d28 Mon Sep 17 00:00:00 2001 From: mike-dydx Date: Wed, 19 Jun 2024 18:18:38 -0400 Subject: [PATCH 20/20] always show positions/orders/fills in market view --- .../dydxMarketPositionViewPresenter.swift | 14 ++++++++ .../dydxMarketInfoViewBuilder.swift | 14 ++------ .../Position/dydxMarketPositionView.swift | 33 ++++++++++++++----- .../_v4/MarketInfo/dydxMarketInfoView.swift | 8 ++--- ...rtfolioPendingPositionsItemViewModel.swift | 21 ++++++------ .../Sections/dydxPortfolioPositionsView.swift | 23 ++++++------- 6 files changed, 66 insertions(+), 47 deletions(-) diff --git a/dydx/dydxPresenters/dydxPresenters/_v4/MarketInfo/Components/dydxMarketPositionViewPresenter.swift b/dydx/dydxPresenters/dydxPresenters/_v4/MarketInfo/Components/dydxMarketPositionViewPresenter.swift index c3348de9a..3c80b6559 100644 --- a/dydx/dydxPresenters/dydxPresenters/_v4/MarketInfo/Components/dydxMarketPositionViewPresenter.swift +++ b/dydx/dydxPresenters/dydxPresenters/_v4/MarketInfo/Components/dydxMarketPositionViewPresenter.swift @@ -55,6 +55,20 @@ class dydxMarketPositionViewPresenter: HostedViewPresenter 0, let viewModel = viewModel { - viewModel.showPositionSection = true + } else if let pendingPosition, pendingPosition.orderCount > 0 { fillsPresenter.filterByMarketId = pendingPosition.marketId fundingPresenter.filterByMarketId = pendingPosition.marketId ordersPresenter.filterByMarketId = pendingPosition.marketId positionPresenter.position = nil positionPresenter.pendingPosition = pendingPosition - resetPresentersForVisibilityChange() - } else { - viewModel?.showPositionSection = false - for (_, presenter) in selectionPresenters { - presenter.stop() - } } + resetPresentersForVisibilityChange() } private func resetPresentersForVisibilityChange() { diff --git a/dydx/dydxViews/dydxViews/_v4/MarketInfo/Components/Position/dydxMarketPositionView.swift b/dydx/dydxViews/dydxViews/_v4/MarketInfo/Components/Position/dydxMarketPositionView.swift index 4b652d0ff..5a867de8a 100644 --- a/dydx/dydxViews/dydxViews/_v4/MarketInfo/Components/Position/dydxMarketPositionView.swift +++ b/dydx/dydxViews/dydxViews/_v4/MarketInfo/Components/Position/dydxMarketPositionView.swift @@ -11,6 +11,8 @@ import PlatformUI import Utilities public class dydxMarketPositionViewModel: PlatformViewModel { + @Published public var emptyText: String? + @Published public var takeProfitStopLossAction: (() -> Void)? @Published public var closeAction: (() -> Void)? @Published public var unrealizedPNLAmount: SignedAmountViewModel? @@ -69,20 +71,28 @@ public class dydxMarketPositionViewModel: PlatformViewModel { guard let self = self else { return AnyView(PlatformView.nilView) } return AnyView( - Group { - if let pendingPosition = self.pendingPosition { - pendingPosition.createView(parentStyle: style) - } else { - VStack { + VStack(spacing: 24) { + // check size to determine if there is current position data to display + VStack { + if let emptyText = self.emptyText { + PlaceholderViewModel(text: emptyText) + .createView() + } else { self.createCollection(parentStyle: style) - self.createButtons(parentStyle: style) - self.createList(parentStyle: style) } - .themeColor(background: .layer2) + } + + if let pendingPosition = self.pendingPosition { + VStack(spacing: 16) { + self.createPendingPositionsHeader(parentStyle: style) + pendingPosition.createView(parentStyle: style) + } + .frame(width: UIScreen.main.bounds.width - 32) } } + .themeColor(background: .layer2) .frame(width: UIScreen.main.bounds.width - 16) ) } @@ -310,6 +320,13 @@ public class dydxMarketPositionViewModel: PlatformViewModel { } .padding(.horizontal, 8) } + + private func createPendingPositionsHeader(parentStyle: ThemeStyle) -> some View { + Text(localizerPathKey: "APP.TRADE.UNOPENED_ISOLATED_POSITIONS") + .themeFont(fontSize: .larger) + .themeColor(foreground: .textSecondary) + .leftAligned() + } } #if DEBUG diff --git a/dydx/dydxViews/dydxViews/_v4/MarketInfo/dydxMarketInfoView.swift b/dydx/dydxViews/dydxViews/_v4/MarketInfo/dydxMarketInfoView.swift index ee2e5752e..5c38ce247 100644 --- a/dydx/dydxViews/dydxViews/_v4/MarketInfo/dydxMarketInfoView.swift +++ b/dydx/dydxViews/dydxViews/_v4/MarketInfo/dydxMarketInfoView.swift @@ -17,7 +17,6 @@ public class dydxMarketInfoViewModel: PlatformViewModel { @Published public var resources = dydxMarketResourcesViewModel() @Published public var configs: dydxMarketConfigsViewModel? = dydxMarketConfigsViewModel() - @Published public var showPositionSection: Bool = false @Published public var sections = dydxPortfolioSectionsViewModel() @Published public var fills = dydxPortfolioFillsViewModel() @Published public var position = dydxMarketPositionViewModel() @@ -48,7 +47,6 @@ public class dydxMarketInfoViewModel: PlatformViewModel { vm.stats = .previewValue vm.resources = .previewValue vm.configs = .previewValue - vm.showPositionSection = true vm.sections = .previewValue vm.position = .previewValue vm.orders = .previewValue @@ -70,10 +68,8 @@ public class dydxMarketInfoViewModel: PlatformViewModel { LazyVStack(pinnedViews: [.sectionHeaders]) { self.createChartPagesSection(parentStyle: style) - if self.showPositionSection { - self.createPositionSection(parentStyle: style) - Spacer(minLength: 24) - } + self.createPositionSection(parentStyle: style) + Spacer(minLength: 24) self.createStatsSection(parentStyle: style) diff --git a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPendingPositionsItemViewModel.swift b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPendingPositionsItemViewModel.swift index 97422b084..845a9ec4c 100644 --- a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPendingPositionsItemViewModel.swift +++ b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPendingPositionsItemViewModel.swift @@ -43,28 +43,27 @@ public class dydxPortfolioPendingPositionsItemViewModel: PlatformViewModel { }() private var topContent: some View { - VStack(spacing: 8) { + VStack(spacing: 12) { HStack(spacing: 8) { PlatformIconViewModel(type: .url(url: marketLogoUrl), clip: .defaultCircle, size: CGSize(width: 20, height: 20)) .createView() Text(marketName) - .themeFont(fontSize: .small) + .themeFont(fontSize: .large) .themeColor(foreground: .textSecondary) Spacer() } HStack(spacing: 0) { Text(localizerPathKey: "APP.GENERAL.MARGIN") - .themeFont(fontSize: .smaller) + .themeFont(fontSize: .medium) .themeColor(foreground: .textTertiary) Spacer() Text(margin) - .themeFont(fontSize: .smaller) + .themeFont(fontSize: .medium) .themeColor(foreground: .textSecondary) } } - .padding(.vertical, 10) } private var divider: some View { @@ -85,13 +84,11 @@ public class dydxPortfolioPendingPositionsItemViewModel: PlatformViewModel { } let viewOrders = Text(localizerPathKey: viewOrdersStringKey, params: viewOrdersStringParams) - .themeFont(fontSize: .smaller) + .themeFont(fontSize: .medium) .themeColor(foreground: .colorPurple) - .padding(.vertical, 8) let cancel = Text(localizerPathKey: "APP.GENERAL.CANCEL") - .themeFont(fontSize: .smaller) + .themeFont(fontSize: .medium) .themeColor(foreground: .colorRed) - .padding(.vertical, 8) return HStack(spacing: 0) { Button(action: viewOrdersAction, label: { viewOrders }) Spacer() @@ -103,14 +100,16 @@ public class dydxPortfolioPendingPositionsItemViewModel: PlatformViewModel { PlatformView(viewModel: self, parentStyle: parentStyle, styleKey: styleKey) { [weak self] _ in guard let self = self else { return AnyView(PlatformView.nilView) } - let horizontalPadding: CGFloat = 12 - return VStack(spacing: 0) { + let verticalPadding: CGFloat = 16 + let horizontalPadding: CGFloat = 20 + return VStack(spacing: 12) { self.topContent self.divider .padding(.horizontal, -horizontalPadding) self.bottomContent } .padding(.horizontal, horizontalPadding) + .padding(.vertical, verticalPadding) .themeColor(background: .layer3) .clipShape(.rect(cornerRadius: 10)) .wrappedInAnyView() diff --git a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift index 629e4b4df..914a170a7 100644 --- a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift +++ b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift @@ -294,6 +294,7 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel { Spacer() } .padding(.horizontal, 16) + .frame(width: UIScreen.main.bounds.width - 32) .themeFont(fontSize: .small) .themeColor(foreground: .textTertiary) .wrappedViewModel @@ -301,9 +302,16 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel { private var openPositionsView: some View { LazyVStack { - let items = self.positionItems.map { $0.createView() } - ForEach(items.indices, id: \.self) { index in - items[index] + if let emptyText = self.emptyText, positionItems.isEmpty { + AnyView( + PlaceholderViewModel(text: emptyText) + .createView() + ) + } else { + let items = self.positionItems.map { $0.createView() } + ForEach(items.indices, id: \.self) { index in + items[index] + } } } } @@ -321,16 +329,9 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel { } public override func createView(parentStyle: ThemeStyle = ThemeStyle.defaultStyle, styleKey: String? = nil) -> PlatformView { - PlatformView(viewModel: self, parentStyle: parentStyle, styleKey: styleKey) { [weak self] style in + PlatformView(viewModel: self, parentStyle: parentStyle, styleKey: styleKey) { [weak self] _ in guard let self = self else { return AnyView(PlatformView.nilView) } - if let emptyText = self.emptyText, positionItems.isEmpty, pendingPositionItems.isEmpty { - return AnyView( - PlaceholderViewModel(text: emptyText) - .createView(parentStyle: style) - ) - } - return AnyView( ScrollView { VStack(spacing: 24) {