From 2744b71c5da5171591b9e5cc34465e56963b943f Mon Sep 17 00:00:00 2001 From: Rui Date: Thu, 26 Dec 2024 17:42:10 -0800 Subject: [PATCH] Position info --- .../dydxPresenters.xcodeproj/project.pbxproj | 4 + .../dydxPortfolioPositionsViewPresenter.swift | 1 + ...xSimpleUIMarketPositionViewPresenter.swift | 70 ++++++ .../dydxSimpleUIMarketInfoViewBuilder.swift | 6 +- .../dydxSimpleUIPortfolioViewPresenter.swift | 10 +- .../dydxViews.xcodeproj/project.pbxproj | 4 + .../_v4/MarketInfo/dydxMarketInfoView.swift | 26 +- .../Sections/dydxPortfolioPositionsView.swift | 1 + .../_v4/Search/dydxLineChartView.swift | 2 +- .../dydxSimpleUIMarketPositionView.swift | 225 ++++++++++++++++++ .../dydxSimpleUIMarketInfoView.swift | 9 +- 11 files changed, 349 insertions(+), 9 deletions(-) create mode 100644 dydx/dydxPresenters/dydxPresenters/_v4/SimpleUI/MarketInfo/components/dydxSimpleUIMarketPositionViewPresenter.swift create mode 100644 dydx/dydxViews/dydxViews/_v4/SimpleUI/MarketInfo/components/dydxSimpleUIMarketPositionView.swift diff --git a/dydx/dydxPresenters/dydxPresenters.xcodeproj/project.pbxproj b/dydx/dydxPresenters/dydxPresenters.xcodeproj/project.pbxproj index faff6a0cc..dac626b19 100644 --- a/dydx/dydxPresenters/dydxPresenters.xcodeproj/project.pbxproj +++ b/dydx/dydxPresenters/dydxPresenters.xcodeproj/project.pbxproj @@ -74,6 +74,7 @@ 027885E82D1DD67200366321 /* dydxSimpleUIMarketInfoViewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027885E72D1DD66500366321 /* dydxSimpleUIMarketInfoViewBuilder.swift */; }; 027885F02D1DE14600366321 /* dydxSimpleUIMarketInfoHeaderViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027885EF2D1DE14500366321 /* dydxSimpleUIMarketInfoHeaderViewPresenter.swift */; }; 027885F42D1DEBF700366321 /* dydxSimpleUIMarketCandlesViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027885F32D1DEBF600366321 /* dydxSimpleUIMarketCandlesViewPresenter.swift */; }; + 027885FC2D1E171C00366321 /* dydxSimpleUIMarketPositionViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027885FB2D1E171B00366321 /* dydxSimpleUIMarketPositionViewPresenter.swift */; }; 0279656A29D795E8004DEB20 /* tabs_v4.json in Resources */ = {isa = PBXBuildFile; fileRef = 0279655B29D795E7004DEB20 /* tabs_v4.json */; }; 0279656C29D795E8004DEB20 /* routing_swiftui.json in Resources */ = {isa = PBXBuildFile; fileRef = 0279656929D795E7004DEB20 /* routing_swiftui.json */; }; 0279DE482BEBE76900F9ECF8 /* dydxTargetLeverageCtaButtonViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0279DE472BEBE76900F9ECF8 /* dydxTargetLeverageCtaButtonViewPresenter.swift */; }; @@ -481,6 +482,7 @@ 027885E72D1DD66500366321 /* dydxSimpleUIMarketInfoViewBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSimpleUIMarketInfoViewBuilder.swift; sourceTree = ""; }; 027885EF2D1DE14500366321 /* dydxSimpleUIMarketInfoHeaderViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSimpleUIMarketInfoHeaderViewPresenter.swift; sourceTree = ""; }; 027885F32D1DEBF600366321 /* dydxSimpleUIMarketCandlesViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSimpleUIMarketCandlesViewPresenter.swift; sourceTree = ""; }; + 027885FB2D1E171B00366321 /* dydxSimpleUIMarketPositionViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSimpleUIMarketPositionViewPresenter.swift; sourceTree = ""; }; 0279655B29D795E7004DEB20 /* tabs_v4.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tabs_v4.json; sourceTree = ""; }; 0279656929D795E7004DEB20 /* routing_swiftui.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = routing_swiftui.json; sourceTree = ""; }; 0279DE472BEBE76900F9ECF8 /* dydxTargetLeverageCtaButtonViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxTargetLeverageCtaButtonViewPresenter.swift; sourceTree = ""; }; @@ -1122,6 +1124,7 @@ children = ( 027885EF2D1DE14500366321 /* dydxSimpleUIMarketInfoHeaderViewPresenter.swift */, 027885F32D1DEBF600366321 /* dydxSimpleUIMarketCandlesViewPresenter.swift */, + 027885FB2D1E171B00366321 /* dydxSimpleUIMarketPositionViewPresenter.swift */, ); path = components; sourceTree = ""; @@ -2122,6 +2125,7 @@ 023789ED28BD381C00F212E1 /* dydxPresenters.docc in Sources */, 2751D6462C59643800B36F95 /* dydxVaultViewBuilder.swift in Sources */, 277E908B2B2118AE005CCBCB /* dydxRewardsHistoryViewPresenter.swift in Sources */, + 027885FC2D1E171C00366321 /* dydxSimpleUIMarketPositionViewPresenter.swift in Sources */, 0279DE952BED63E100F9ECF8 /* dydxAdjustMarginCtaButtonViewPresenter.swift in Sources */, 0230376F28C11BE600412B72 /* dydxMarketsViewBuilder.swift in Sources */, 023AB3C42BEAD56A005230B2 /* dydxMarginModeViewBuilder.swift in Sources */, diff --git a/dydx/dydxPresenters/dydxPresenters/_v4/Portfolio/Components/dydxPortfolioPositionsViewPresenter.swift b/dydx/dydxPresenters/dydxPresenters/_v4/Portfolio/Components/dydxPortfolioPositionsViewPresenter.swift index 39a016f15..abdb2de43 100644 --- a/dydx/dydxPresenters/dydxPresenters/_v4/Portfolio/Components/dydxPortfolioPositionsViewPresenter.swift +++ b/dydx/dydxPresenters/dydxPresenters/_v4/Portfolio/Components/dydxPortfolioPositionsViewPresenter.swift @@ -165,6 +165,7 @@ class dydxPortfolioPositionsViewPresenter: HostedViewPresenter, dydxSimpleUIMarketPositionViewPresenterProtocol { + @Published var marketId: String? + + override init() { + super.init() + + viewModel = dydxSimpleUIMarketPositionViewModel() + } + + override func start() { + super.start() + + Publishers + .CombineLatest4(AbacusStateManager.shared.state.selectedSubaccountPositions, + $marketId, + AbacusStateManager.shared.state.marketMap, + AbacusStateManager.shared.state.assetMap) + .sink { [weak self] position, marketId, marketMap, assetMap in + let position = position.first { position in + position.id == marketId && + (position.side.current == Abacus.PositionSide.long_ || position.side.current == Abacus.PositionSide.short_) + } + self?.updatePositionSection(position: position, marketMap: marketMap, assetMap: assetMap) + } + .store(in: &subscriptions) + } + + private func updatePositionSection(position: SubaccountPosition?, marketMap: [String: PerpetualMarket], assetMap: [String: Asset]) { + guard let position, let sharedOrderViewModel = dydxPortfolioPositionsViewPresenter.createPositionViewModelItem(position: position, + marketMap: marketMap, + assetMap: assetMap) + else { + viewModel?.side = nil // hide the view + return + } + + viewModel?.symbol = sharedOrderViewModel.token?.symbol + viewModel?.unrealizedPNLAmount = sharedOrderViewModel.unrealizedPnl + viewModel?.size = sharedOrderViewModel.size + viewModel?.side = SideTextViewModel(side: sharedOrderViewModel.sideText.side, coloringOption: .withBackground) + viewModel?.liquidationPrice = sharedOrderViewModel.liquidationPrice + viewModel?.entryPrice = sharedOrderViewModel.entryPrice + + viewModel?.logoUrl = sharedOrderViewModel.logoUrl + viewModel?.amount = dydxFormatter.shared.dollar(number: position.notionalTotal.current?.doubleValue, digits: 2) + viewModel?.funding = SignedAmountViewModel(amount: position.netFunding?.doubleValue, displayType: .dollar, coloringOption: .allText) + } +} diff --git a/dydx/dydxPresenters/dydxPresenters/_v4/SimpleUI/MarketInfo/dydxSimpleUIMarketInfoViewBuilder.swift b/dydx/dydxPresenters/dydxPresenters/_v4/SimpleUI/MarketInfo/dydxSimpleUIMarketInfoViewBuilder.swift index b8054b241..da9a8f6f1 100644 --- a/dydx/dydxPresenters/dydxPresenters/_v4/SimpleUI/MarketInfo/dydxSimpleUIMarketInfoViewBuilder.swift +++ b/dydx/dydxPresenters/dydxPresenters/_v4/SimpleUI/MarketInfo/dydxSimpleUIMarketInfoViewBuilder.swift @@ -48,13 +48,15 @@ private class dydxSimpleUIMarketInfoViewPresenter: HostedViewPresenter 1.0 { + viewModel?.chart.entries = chartEntries + } + viewModel?.chart.showYLabels = false viewModel?.chart.valueLowerBoundOffset = (maxValue - minValue) * 0.8 } diff --git a/dydx/dydxViews/dydxViews.xcodeproj/project.pbxproj b/dydx/dydxViews/dydxViews.xcodeproj/project.pbxproj index 48c485886..af23f3b2e 100644 --- a/dydx/dydxViews/dydxViews.xcodeproj/project.pbxproj +++ b/dydx/dydxViews/dydxViews.xcodeproj/project.pbxproj @@ -105,6 +105,7 @@ 027885ED2D1DE12C00366321 /* dydxSimpleUIMarketInfoHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027885EC2D1DE12C00366321 /* dydxSimpleUIMarketInfoHeaderView.swift */; }; 027885F22D1DEBE300366321 /* dydxSimpleUIMarketCandlesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027885F12D1DEBE300366321 /* dydxSimpleUIMarketCandlesView.swift */; }; 027885F62D1E0C5500366321 /* dydxSimpleUIMarketCandlesResolutionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027885F52D1E0C5500366321 /* dydxSimpleUIMarketCandlesResolutionsView.swift */; }; + 027885FA2D1E170900366321 /* dydxSimpleUIMarketPositionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027885F92D1E170900366321 /* dydxSimpleUIMarketPositionView.swift */; }; 0279DE452BEBE75100F9ECF8 /* dydxTargetLeverageCtaButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0279DE442BEBE75100F9ECF8 /* dydxTargetLeverageCtaButtonView.swift */; }; 0279DE6B2BEC471700F9ECF8 /* dydxAdjustMarginInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0279DE6A2BEC471700F9ECF8 /* dydxAdjustMarginInputView.swift */; }; 0279DE872BED3F5400F9ECF8 /* dydxAdjustMarginDirectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0279DE862BED3F5400F9ECF8 /* dydxAdjustMarginDirectionView.swift */; }; @@ -511,6 +512,7 @@ 027885EC2D1DE12C00366321 /* dydxSimpleUIMarketInfoHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSimpleUIMarketInfoHeaderView.swift; sourceTree = ""; }; 027885F12D1DEBE300366321 /* dydxSimpleUIMarketCandlesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSimpleUIMarketCandlesView.swift; sourceTree = ""; }; 027885F52D1E0C5500366321 /* dydxSimpleUIMarketCandlesResolutionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSimpleUIMarketCandlesResolutionsView.swift; sourceTree = ""; }; + 027885F92D1E170900366321 /* dydxSimpleUIMarketPositionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSimpleUIMarketPositionView.swift; sourceTree = ""; }; 0279DE442BEBE75100F9ECF8 /* dydxTargetLeverageCtaButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxTargetLeverageCtaButtonView.swift; sourceTree = ""; }; 0279DE6A2BEC471700F9ECF8 /* dydxAdjustMarginInputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxAdjustMarginInputView.swift; sourceTree = ""; }; 0279DE862BED3F5400F9ECF8 /* dydxAdjustMarginDirectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxAdjustMarginDirectionView.swift; sourceTree = ""; }; @@ -1283,6 +1285,7 @@ 027885EC2D1DE12C00366321 /* dydxSimpleUIMarketInfoHeaderView.swift */, 027885F12D1DEBE300366321 /* dydxSimpleUIMarketCandlesView.swift */, 027885F52D1E0C5500366321 /* dydxSimpleUIMarketCandlesResolutionsView.swift */, + 027885F92D1E170900366321 /* dydxSimpleUIMarketPositionView.swift */, ); path = components; sourceTree = ""; @@ -2286,6 +2289,7 @@ 027885F22D1DEBE300366321 /* dydxSimpleUIMarketCandlesView.swift in Sources */, 02FF0BD529AEB91900781EDA /* dydxWalletView.swift in Sources */, 024B44D12982D1FF00E35D54 /* dydxTradeStatusView.swift in Sources */, + 027885FA2D1E170900366321 /* dydxSimpleUIMarketPositionView.swift in Sources */, 02A9B60E29005D5A00AE1516 /* AmountText.swift in Sources */, 02FCF0E728E795FA00D350CE /* HostedViewPresenter.swift in Sources */, 0258BA1D2992949D0098E1BE /* dydxProfileView.swift in Sources */, diff --git a/dydx/dydxViews/dydxViews/_v4/MarketInfo/dydxMarketInfoView.swift b/dydx/dydxViews/dydxViews/_v4/MarketInfo/dydxMarketInfoView.swift index 5c38ce247..1314020ee 100644 --- a/dydx/dydxViews/dydxViews/_v4/MarketInfo/dydxMarketInfoView.swift +++ b/dydx/dydxViews/dydxViews/_v4/MarketInfo/dydxMarketInfoView.swift @@ -132,14 +132,14 @@ public class dydxMarketInfoViewModel: PlatformViewModel { stats? .createView(parentStyle: parentStyle) .frame(width: UIScreen.main.bounds.width) - .section(path: "APP.GENERAL.STATISTICS") + .sectionHeader(path: "APP.GENERAL.STATISTICS") } private func createDetailsSection(parentStyle: ThemeStyle) -> some View { resources .createView(parentStyle: parentStyle) .frame(width: UIScreen.main.bounds.width) - .section(path: "APP.GENERAL.DETAILS") + .sectionHeader(path: "APP.GENERAL.DETAILS") } private func createConfigsSection(parentStyle: ThemeStyle) -> some View { @@ -151,9 +151,13 @@ public class dydxMarketInfoViewModel: PlatformViewModel { } extension View { - func section(path: String) -> some View { + func sectionHeader(path: String) -> some View { self.modifier(SectionModifier(localizedStringPath: path)) } + + func sectionHeader(header: @escaping (() -> some View)) -> some View { + self.modifier(SectionHeaderModifier(header: header)) + } } private struct SectionModifier: ViewModifier { @@ -182,6 +186,22 @@ private struct SectionModifier: ViewModifier { } } +private struct SectionHeaderModifier: ViewModifier where Parent: View { + var header: (() -> Parent) + + func body(content: Content) -> some View { + Section { + VStack(alignment: .leading) { + content + Spacer(minLength: 24) + } + } header: { + header() + .themeColor(background: .layer2) + } + } +} + #if DEBUG struct dydxMarketInfoView_Previews_Dark: PreviewProvider { @StateObject static var themeSettings = ThemeSettings.shared diff --git a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift index a164882aa..c5ebeaae3 100644 --- a/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift +++ b/dydx/dydxViews/dydxViews/_v4/Portfolio/Components/Sections/dydxPortfolioPositionsView.swift @@ -60,6 +60,7 @@ public class dydxPortfolioPositionItemViewModel: PlatformViewModel { @Published public var leverage: String? @Published public var leverageIcon: LeverageRiskModel? @Published public var liquidationPrice: String? + @Published public var entryPrice: String? @Published public var indexPrice: String? @Published public var unrealizedPnl: SignedAmountViewModel? @Published public var unrealizedPnlPercent: String = "" diff --git a/dydx/dydxViews/dydxViews/_v4/Search/dydxLineChartView.swift b/dydx/dydxViews/dydxViews/_v4/Search/dydxLineChartView.swift index 4c6829797..82d99337c 100644 --- a/dydx/dydxViews/dydxViews/_v4/Search/dydxLineChartView.swift +++ b/dydx/dydxViews/dydxViews/_v4/Search/dydxLineChartView.swift @@ -15,7 +15,7 @@ import dydxChart import dydxFormatter public class dydxLineChartViewModel: PlatformViewModel { - public struct Entry { + public struct Entry: Equatable { public let date: Double public let value: Double diff --git a/dydx/dydxViews/dydxViews/_v4/SimpleUI/MarketInfo/components/dydxSimpleUIMarketPositionView.swift b/dydx/dydxViews/dydxViews/_v4/SimpleUI/MarketInfo/components/dydxSimpleUIMarketPositionView.swift new file mode 100644 index 000000000..31840f745 --- /dev/null +++ b/dydx/dydxViews/dydxViews/_v4/SimpleUI/MarketInfo/components/dydxSimpleUIMarketPositionView.swift @@ -0,0 +1,225 @@ +// +// dydxSimpleUIMarketPositionView.swift +// dydxUI +// +// Created by Rui Huang on 26/12/2024. +// Copyright © 2024 dYdX Trading Inc. All rights reserved. +// + +import SwiftUI +import PlatformUI +import Utilities + +public class dydxSimpleUIMarketPositionViewModel: PlatformViewModel { + @Published public var closeAction: (() -> Void)? + @Published public var shareAction: (() -> Void)? + @Published public var unrealizedPNLAmount: SignedAmountViewModel? + @Published public var entryPrice: String? + @Published public var side: SideTextViewModel? + @Published public var size: String? + @Published public var amount: String? + @Published public var logoUrl: URL? + @Published public var funding: SignedAmountViewModel? + @Published public var liquidationPrice: String? + @Published public var symbol: String? + + public init() { } + + public static var previewValue: dydxSimpleUIMarketPositionViewModel { + let vm = dydxSimpleUIMarketPositionViewModel() + vm.closeAction = {} + vm.unrealizedPNLAmount = .previewValue + vm.side = .previewValue + vm.entryPrice = "$120.00" + vm.size = "0.0012" + vm.amount = "$120.00" + vm.logoUrl = URL(string: "https://media.dydx.exchange/currencies/eth.png") + vm.funding = .previewValue + vm.liquidationPrice = "$120.00" + vm.symbol = "USD" + return vm + } + + 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, self.side != nil else { return AnyView(PlatformView.nilView) } + + return AnyView( + self.createContent(style: style) + .sectionHeader { + self.createHeader(style: style) + } + ) + } + } + + private func createContent(style: ThemeStyle) -> some View { + VStack(alignment: .leading, spacing: 8) { + DividerModel().createView(parentStyle: style) + + HStack { + let amountHeader = HStack { + Text(DataLocalizer.localize(path: "APP.GENERAL.SIZE")) + .themeFont(fontType: .plus, fontSize: .small) + .themeColor(foreground: .textTertiary) + TokenTextViewModel(symbol: symbol ?? "-") + .createView(parentStyle: style.themeFont(fontSize: .smaller)) + } + createCollectionItem(parentStyle: style, + titleViewModel: amountHeader.wrappedViewModel, + value: size) + .frame(minWidth: 0, maxWidth: .infinity) + + let sizeHeader = HStack { + Text(DataLocalizer.localize(path: "APP.GENERAL.SIZE")) + .themeFont(fontType: .plus, fontSize: .small) + .themeColor(foreground: .textTertiary) + TokenTextViewModel(symbol: "USD") + .createView(parentStyle: style.themeFont(fontSize: .smaller)) + } + createCollectionItem(parentStyle: style, + titleViewModel: sizeHeader.wrappedViewModel, + value: amount) + .frame(minWidth: 0, maxWidth: .infinity) + + createCollectionItem(parentStyle: style, + title: DataLocalizer.localize(path: "APP.SHARE_ACTIVITY_MODAL.PROFIT"), + valueViewModel: unrealizedPNLAmount) + .frame(minWidth: 0, maxWidth: .infinity) + } + .frame(maxWidth: .infinity) + .padding(.horizontal, 16) + + DividerModel().createView(parentStyle: style) + + HStack { + createCollectionItem(parentStyle: style, + title: DataLocalizer.localize(path: "APP.GENERAL.FUNDING_RATE_CHART_SHORT"), + valueViewModel: funding) + .frame(minWidth: 0, maxWidth: .infinity) + + createCollectionItem(parentStyle: style, + title: DataLocalizer.localize(path: "APP.GENERAL.AVG_ENTRY"), + value: entryPrice) + .frame(minWidth: 0, maxWidth: .infinity) + + createCollectionItem(parentStyle: style, + title: DataLocalizer.localize(path: "APP.TRADE.LIQUIDATION_PRICE_SHORT"), + value: liquidationPrice) + .frame(minWidth: 0, maxWidth: .infinity) + } + .frame(maxWidth: .infinity) + .padding(.horizontal, 16) + + DividerModel().createView(parentStyle: style) + + } + .frame(minWidth: 0, maxWidth: .infinity) + } + + private func createCollectionItem(parentStyle: ThemeStyle, title: String?, valueViewModel: PlatformViewModel?) -> some View { + let titleViewModel = Text(title ?? "") + .themeFont(fontType: .plus, fontSize: .small) + .themeColor(foreground: .textTertiary) + .wrappedViewModel + return createCollectionItem(parentStyle: parentStyle, titleViewModel: titleViewModel, valueViewModel: valueViewModel) + } + + private func createCollectionItem(parentStyle: ThemeStyle, titleViewModel: PlatformViewModel?, value: String?) -> some View { + let valueViewModel = Text(value ?? "-") + .themeFont(fontSize: .large) + .themeColor(foreground: .textSecondary) + .lineLimit(1) + .minimumScaleFactor(0.5) + // .fixedSize(horizontal: true, vertical: false) + .leftAligned() + .wrappedViewModel + return createCollectionItem(parentStyle: parentStyle, titleViewModel: titleViewModel, valueViewModel: valueViewModel) + } + + private func createCollectionItem(parentStyle: ThemeStyle, title: String?, value: String?) -> some View { + let titleViewModel = Text(title ?? "") + .themeFont(fontType: .plus, fontSize: .small) + .themeColor(foreground: .textTertiary) + .wrappedViewModel + let valueViewModel = Text(value ?? "-") + .themeFont(fontSize: .large) + .themeColor(foreground: .textSecondary) + .lineLimit(1) + .minimumScaleFactor(0.5) + // .fixedSize(horizontal: true, vertical: false) + .leftAligned() + .wrappedViewModel + return createCollectionItem(parentStyle: parentStyle, titleViewModel: titleViewModel, valueViewModel: valueViewModel) + } + + private func createCollectionItem(parentStyle: ThemeStyle, titleViewModel: PlatformViewModel?, valueViewModel: PlatformViewModel?) -> some View { + VStack(spacing: 0) { + VStack(alignment: .leading, spacing: 8) { + titleViewModel?.createView(parentStyle: parentStyle) + valueViewModel?.createView(parentStyle: parentStyle, styleKey: nil) + } + Spacer() + } + .leftAligned() + } + + private func createHeader(style: ThemeStyle) -> some View { + VStack { + HStack { + Text(DataLocalizer.localize(path: "APP.GENERAL.POSITION")) + .themeFont(fontType: .plus, fontSize: .largest) + .padding(.leading, 16) + + self.side?.createView(parentStyle: style) + + Spacer() + + Button(action: self.closeAction ?? {}) { + Text(DataLocalizer.localize(path: "APP.GENERAL.CLOSE")) + .themeColor(foreground: .colorRed) + } + .buttonStyle(BorderlessButtonStyle()) + .padding([.bottom, .top], 4) + .padding([.leading, .trailing], 12) + .themeColor(background: .colorFadedRed) + .clipShape(Capsule()) + } + .padding(.trailing, 16) + + Spacer(minLength: 24) + } + } +} + +#if DEBUG +struct dydxSimpleUIMarketPositionView_Previews_Dark: PreviewProvider { + @StateObject static var themeSettings = ThemeSettings.shared + + static var previews: some View { + ThemeSettings.applyDarkTheme() + ThemeSettings.applyStyles() + return dydxSimpleUIMarketPositionViewModel.previewValue + .createView() + .themeColor(background: .layer0) + .environmentObject(themeSettings) + // .edgesIgnoringSafeArea(.bottom) + .previewLayout(.sizeThatFits) + } +} + +struct dydxSimpleUIMarketPositionView_Previews_Light: PreviewProvider { + @StateObject static var themeSettings = ThemeSettings.shared + + static var previews: some View { + ThemeSettings.applyLightTheme() + ThemeSettings.applyStyles() + return dydxSimpleUIMarketPositionViewModel.previewValue + .createView() + .themeColor(background: .layer0) + .environmentObject(themeSettings) + // .edgesIgnoringSafeArea(.bottom) + .previewLayout(.sizeThatFits) + } +} +#endif diff --git a/dydx/dydxViews/dydxViews/_v4/SimpleUI/MarketInfo/dydxSimpleUIMarketInfoView.swift b/dydx/dydxViews/dydxViews/_v4/SimpleUI/MarketInfo/dydxSimpleUIMarketInfoView.swift index b44664306..201d53592 100644 --- a/dydx/dydxViews/dydxViews/_v4/SimpleUI/MarketInfo/dydxSimpleUIMarketInfoView.swift +++ b/dydx/dydxViews/dydxViews/_v4/SimpleUI/MarketInfo/dydxSimpleUIMarketInfoView.swift @@ -16,6 +16,7 @@ public class dydxSimpleUIMarketInfoViewModel: PlatformViewModel { @Published public var stats: dydxMarketStatsViewModel? = dydxMarketStatsViewModel() @Published public var resources: dydxMarketResourcesViewModel = dydxMarketResourcesViewModel() @Published public var configs: dydxMarketConfigsViewModel? = dydxMarketConfigsViewModel() + @Published public var position: dydxSimpleUIMarketPositionViewModel? public init() { } @@ -23,6 +24,7 @@ public class dydxSimpleUIMarketInfoViewModel: PlatformViewModel { let vm = dydxSimpleUIMarketInfoViewModel() vm.header = .previewValue vm.chart = .previewValue + vm.position = .previewValue return vm } @@ -36,12 +38,15 @@ public class dydxSimpleUIMarketInfoViewModel: PlatformViewModel { ScrollView(showsIndicators: false) { LazyVStack(pinnedViews: [.sectionHeaders]) { self.chart?.createView(parentStyle: style) + .padding(.bottom, 18) + + self.position?.createView(parentStyle: style) self.stats?.createView(parentStyle: style) - .section(path: "APP.GENERAL.STATISTICS") + .sectionHeader(path: "APP.GENERAL.STATISTICS") self.resources.createView(parentStyle: style) - .section(path: "APP.GENERAL.DETAILS") + .sectionHeader(path: "APP.GENERAL.DETAILS") self.configs?.createView(parentStyle: style)