From cf757a2d7667c79ae727f8e2fb30f4dee1fc9fa2 Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 15 Aug 2024 16:36:44 -0400 Subject: [PATCH 1/5] add sections to vault position view --- .../_v4/Vault/dydxVaultViewBuilder.swift | 8 + .../dydxViews.xcodeproj/project.pbxproj | 8 + .../dydxViews/dydxViews/Shared/SideText.swift | 11 ++ .../dydxViews/Shared/SparklineChart.swift | 57 ++++++ .../dydxViews/Shared/TokenText.swift | 2 + .../Vault/Landing/dydxVaultPositionView.swift | 166 ++++++++++++++++++ .../Vault/Landing/dydxVaultViewModel.swift | 109 +++++++++--- 7 files changed, 337 insertions(+), 24 deletions(-) create mode 100644 dydx/dydxViews/dydxViews/Shared/SparklineChart.swift create mode 100644 dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultPositionView.swift diff --git a/dydx/dydxPresenters/dydxPresenters/_v4/Vault/dydxVaultViewBuilder.swift b/dydx/dydxPresenters/dydxPresenters/_v4/Vault/dydxVaultViewBuilder.swift index 850f9183b..e3e98e2c4 100644 --- a/dydx/dydxPresenters/dydxPresenters/_v4/Vault/dydxVaultViewBuilder.swift +++ b/dydx/dydxPresenters/dydxPresenters/_v4/Vault/dydxVaultViewBuilder.swift @@ -41,5 +41,13 @@ private class dydxVaultViewBuilderPresenter: HostedViewPresenter= (entries.first?.y ?? -Double.infinity) + let color = isPositive ? ThemeSettings.positiveColor.uiColor : ThemeSettings.negativeColor.uiColor + + //colors + dataSet.setColor(color) + + //shapes + dataSet.lineWidth = 1.5 + dataSet.lineCapType = .round + dataSet.mode = .linear + dataSet.label = nil + dataSet.drawCirclesEnabled = false + dataSet.drawValuesEnabled = false + + // interactions + dataSet.highlightEnabled = false + dataSet.drawHorizontalHighlightIndicatorEnabled = false + + chart.data = LineChartData(dataSet: dataSet) + return chart.swiftUIView + } + + var body: some View { + lineChart + } +} diff --git a/dydx/dydxViews/dydxViews/Shared/TokenText.swift b/dydx/dydxViews/dydxViews/Shared/TokenText.swift index cc3e71906..402091c4c 100644 --- a/dydx/dydxViews/dydxViews/Shared/TokenText.swift +++ b/dydx/dydxViews/dydxViews/Shared/TokenText.swift @@ -26,6 +26,8 @@ public class TokenTextViewModel: PlatformViewModel, Hashable { return AnyView( Group { Text(self.symbol) + .lineLimit(1) + .minimumScaleFactor(0.5) .padding(.vertical, 1) .padding(.horizontal, 3) } diff --git a/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultPositionView.swift b/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultPositionView.swift new file mode 100644 index 000000000..59908565a --- /dev/null +++ b/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultPositionView.swift @@ -0,0 +1,166 @@ +// +// dydxVaultPositionView.swift +// dydxUI +// +// Created by Michael Maguire on 8/14/24. +// Copyright © 2024 dYdX Trading Inc. All rights reserved. +// + +import SwiftUI +import PlatformUI +import Utilities +import Charts +import dydxFormatter + +public class dydxVaultPositionViewModel: PlatformViewModel { + static var marketSectionWidth: CGFloat = 130 + static var interSectionPadding: CGFloat = 12 + static var sparklineWidth: CGFloat = 24 + static var pnlSpacing: CGFloat = 3 + + @Published public var assetName: String + @Published public var market: String + @Published public var side: SideTextViewModel.Side + @Published public var leverage: Double + @Published public var notionalValue: Double + @Published public var positionSize: Double + @Published public var tokenUnitPrecision: Int + @Published public var token: String + @Published public var pnlAmount: Double + @Published public var pnlPercentage: Double + @Published public var sparklineValues: [Double] + + fileprivate var sideLeverageAttributedText: AttributedString { + let attributedSideText = AttributedString(text: side.text, urlString: nil).themeColor(foreground: side.color) + let leverageText = dydxFormatter.shared.leverage(number: leverage) ?? "--" + let attributedLeverageText = AttributedString(text: "@ " + leverageText, urlString: nil).themeColor(foreground: .textTertiary) + return attributedSideText + attributedLeverageText + } + + fileprivate var notionalValueText: String { + dydxFormatter.shared.dollar(number: notionalValue) ?? "--" + } + + fileprivate var positionSizeText: String { + dydxFormatter.shared.localFormatted(number: positionSize, digits: tokenUnitPrecision) ?? "--" + } + + fileprivate var pnlColor: ThemeColor.SemanticColor { + pnlAmount >= 0 ? ThemeSettings.positiveColor : ThemeSettings.negativeColor + } + + fileprivate var pnlAmountText: String { + dydxFormatter.shared.dollar(number: pnlAmount) ?? "--" + } + + fileprivate var pnlPercentageText: String { + dydxFormatter.shared.percent(number: pnlPercentage, digits: 2) ?? "--" + } + + public init( + assetName: String, + market: String, + side: SideTextViewModel.Side, + leverage: Double, + notionalValue: Double, + positionSize: Double, + token: String, + tokenUnitPrecision: Int, + pnlAmount: Double, + pnlPercentage: Double, + sparklineValues: [Double]) { + self.assetName = assetName + self.market = market + self.side = side + self.leverage = leverage + self.notionalValue = notionalValue + self.positionSize = positionSize + self.token = token + self.tokenUnitPrecision = tokenUnitPrecision + self.pnlAmount = pnlAmount + self.pnlPercentage = pnlPercentage + self.sparklineValues = sparklineValues + } + + public override func createView(parentStyle: ThemeStyle = ThemeStyle.defaultStyle, styleKey: String? = nil) -> PlatformView { + PlatformView(viewModel: self, parentStyle: parentStyle, styleKey: styleKey) { [weak self] style in + guard let self = self else { return AnyView(PlatformView.nilView) } + return VaultPositionView(viewModel: self) + .wrappedInAnyView() + } + } +} + +private struct VaultPositionView: View { + @ObservedObject var viewModel: dydxVaultPositionViewModel + + var marketSection: some View { + HStack(spacing: 8) { + PlatformIconViewModel(type: .asset(name: viewModel.assetName, bundle: .dydxView), + clip: .circle(background: .transparent, spacing: 0, borderColor: nil), + size: .init(width: 24, height: 24), + templateColor: nil) + .createView() + VStack(alignment: .leading, spacing: 2) { + Text(viewModel.market) + .themeFont(fontType: .base, fontSize: .small) + .themeColor(foreground: .textSecondary) + .lineLimit(1) + .minimumScaleFactor(0.5) + Text(viewModel.sideLeverageAttributedText) + .lineLimit(1) + .minimumScaleFactor(0.5) + } + } + .leftAligned() + } + + var sizeSection: some View { + VStack(alignment: .leading, spacing: 2) { + Text(viewModel.notionalValueText) + .themeFont(fontType: .base, fontSize: .small) + .themeColor(foreground: .textSecondary) + .lineLimit(1) + .minimumScaleFactor(0.5) + HStack(alignment: .top, spacing: 2) { + Text(viewModel.positionSizeText) + .themeFont(fontType: .base, fontSize: .smaller) + .themeColor(foreground: .textTertiary) + .lineLimit(1) + .minimumScaleFactor(0.5) + TokenTextViewModel(symbol: viewModel.token) + .createView(parentStyle: ThemeStyle.defaultStyle.themeFont(fontSize: .smallest)) + } + } + .leftAligned() + } + + var pnlSection: some View { + HStack(alignment: .center, spacing: dydxVaultPositionViewModel.pnlSpacing) { + VStack(alignment: .trailing, spacing: 2) { + Text(viewModel.pnlAmountText) + .themeFont(fontType: .base, fontSize: .small) + .themeColor(foreground: viewModel.pnlColor) + .lineLimit(1) + .minimumScaleFactor(0.5) + Text(viewModel.pnlPercentageText) + .themeFont(fontType: .base, fontSize: .smaller) + .themeColor(foreground: .textTertiary) + .lineLimit(1) + .minimumScaleFactor(0.5) + } + SparklineView(values: viewModel.sparklineValues) + .frame(width: dydxVaultPositionViewModel.sparklineWidth, height: 24) + } + } + + var body: some View { + HStack(spacing: dydxVaultPositionViewModel.interSectionPadding) { + marketSection + .frame(width: dydxVaultPositionViewModel.marketSectionWidth) + sizeSection + pnlSection + } + } +} + diff --git a/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultViewModel.swift b/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultViewModel.swift index 843ea69c7..6d6a18a5d 100644 --- a/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultViewModel.swift +++ b/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultViewModel.swift @@ -15,11 +15,10 @@ public class dydxVaultViewModel: PlatformViewModel { @Published public var vaultBalance: Double? @Published public var profitDollars: Double? @Published public var profitPercentage: Double? + @Published public var positions: [dydxVaultPositionViewModel]? @Published public var cancelAction: (() -> Void)? @Published public var learnMoreAction: (() -> Void)? - public init() { } - 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) } @@ -32,20 +31,36 @@ private struct dydxVaultView: View { @ObservedObject var viewModel: dydxVaultViewModel var body: some View { - VStack(spacing: 0) { - titleRow - Spacer().frame(height: 28) - vaultPnlRow - Spacer().frame(height: 16) - div - Spacer().frame(height: 16) - aprTvlRow - Spacer().frame(height: 16) - div - Spacer().frame(height: 16) - chart - Spacer() - + ScrollView { + LazyVStack(pinnedViews: [.sectionHeaders]) { + VStack(spacing: 0) { + titleRow + Spacer().frame(height: 28) + vaultPnlRow + Spacer().frame(height: 16) + div + Spacer().frame(height: 16) + aprTvlRow + Spacer().frame(height: 16) + div + Spacer().frame(height: 16) + chart + Spacer().frame(height: 16) + div + } + Section { + VStack(spacing: 0) { + Spacer().frame(height: 16) + openPositionsHeader + Spacer().frame(height: 8) + div + Spacer().frame(height: 16) + } + } + positionsListHeader + Spacer().frame(height: 16) + positionsList + } } .frame(maxWidth: .infinity) .themeColor(background: .layer2) @@ -60,18 +75,12 @@ private struct dydxVaultView: View { // MARK: - Header var titleRow: some View { HStack(spacing: 16) { - backButton titleImage titleText Spacer() learnMore } - .padding(.horizontal, 12) - } - - var backButton: some View { - ChevronBackButtonModel(onBackButtonTap: viewModel.cancelAction ?? {}) - .createView() + .padding(.horizontal, 16) } var titleImage: some View { @@ -151,7 +160,6 @@ private struct dydxVaultView: View { tvlTitleValue } .leftAligned() - .padding(.horizontal, 16) } var aprTitleValue: some View { @@ -182,4 +190,57 @@ private struct dydxVaultView: View { .createView() .frame(height: 174) } + + // MARK: - Section 4 - positions + var openPositionsHeader: some View { + HStack(spacing: 8) { + Text(DataLocalizer.shared?.localize(path: "APP.TRADE.OPEN_POSITIONS", params: nil) ?? "") + .themeColor(foreground: .textSecondary) + .themeFont(fontType: .base, fontSize: .larger) + Text("\(viewModel.positions?.count ?? 0)") + .themeColor(foreground: .textSecondary) + .themeFont(fontType: .base, fontSize: .small) + .padding(.vertical, 2.5) + .padding(.horizontal, 6.5) + .themeColor(background: .layer6) + .clipShape(RoundedRectangle(cornerRadius: 4)) + } + .leftAligned() + .padding(.horizontal, 16) + } + + var positionsListHeader: some View { + HStack(spacing: dydxVaultPositionViewModel.interSectionPadding) { + Group { + Text(DataLocalizer.shared?.localize(path: "APP.GENERAL.MARKET", params: nil) ?? "") + .themeColor(foreground: .textTertiary) + .themeFont(fontType: .base, fontSize: .small) + .leftAligned() + .frame(width: dydxVaultPositionViewModel.marketSectionWidth) + .lineLimit(1) + Text(DataLocalizer.shared?.localize(path: "APP.GENERAL.SIZE", params: nil) ?? "") + .themeColor(foreground: .textTertiary) + .themeFont(fontType: .base, fontSize: .small) + .lineLimit(1) + Spacer() + Text(DataLocalizer.shared?.localize(path: "APP.VAULTS.VAULT_THIRTY_DAY_PNL", params: nil) ?? "") + .themeColor(foreground: .textTertiary) + .themeFont(fontType: .base, fontSize: .small) + .lineLimit(1) + .fixedSize(horizontal: true, vertical: false) + .padding(.trailing, dydxVaultPositionViewModel.pnlSpacing + dydxVaultPositionViewModel.sparklineWidth) + } + } + .padding(.horizontal, 16) + } + + var positionsList: some View { + ForEach(viewModel.positions ?? [], id: \.id) { position in + position.createView() + .centerAligned() + .frame(height: 53) + div + } + .padding(.horizontal, 16) + } } From f9b8ed4f7d3754434e659e9f0c625fa0ea4f4d1f Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 15 Aug 2024 16:56:02 -0400 Subject: [PATCH 2/5] scrolling touchups --- .../_v4/Vault/dydxVaultViewBuilder.swift | 14 ++++- .../Vault/Landing/dydxVaultViewModel.swift | 60 +++++++++++-------- 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/dydx/dydxPresenters/dydxPresenters/_v4/Vault/dydxVaultViewBuilder.swift b/dydx/dydxPresenters/dydxPresenters/_v4/Vault/dydxVaultViewBuilder.swift index e3e98e2c4..bc305c98b 100644 --- a/dydx/dydxPresenters/dydxPresenters/_v4/Vault/dydxVaultViewBuilder.swift +++ b/dydx/dydxPresenters/dydxPresenters/_v4/Vault/dydxVaultViewBuilder.swift @@ -18,7 +18,7 @@ public class dydxVaultViewBuilder: NSObject, ObjectBuilderProtocol { public func build() -> T? { let presenter = dydxVaultViewBuilderPresenter() let view = presenter.viewModel?.createView() ?? PlatformViewModel().createView() - return dydxVaultViewController(presenter: presenter, view: view, configuration: .default) as? T + return dydxVaultViewController(presenter: presenter, view: view, configuration: .tabbarItemView) as? T // return HostingViewController(presenter: presenter, view: view) as? T } } @@ -46,7 +46,17 @@ private class dydxVaultViewBuilderPresenter: HostedViewPresenter PlatformView { PlatformView(viewModel: self, parentStyle: parentStyle, styleKey: styleKey) { [weak self] _ in guard let self = self else { return AnyView(PlatformView.nilView) } - return AnyView(dydxVaultView(viewModel: self)).wrappedInAnyView() + return AnyView(dydxVaultView(viewModel: self)) + .wrappedInAnyView() } } } private struct dydxVaultView: View { @ObservedObject var viewModel: dydxVaultViewModel - + var body: some View { - ScrollView { - LazyVStack(pinnedViews: [.sectionHeaders]) { - VStack(spacing: 0) { - titleRow - Spacer().frame(height: 28) - vaultPnlRow - Spacer().frame(height: 16) - div - Spacer().frame(height: 16) - aprTvlRow - Spacer().frame(height: 16) - div - Spacer().frame(height: 16) - chart - Spacer().frame(height: 16) - div - } - Section { + VStack { + Spacer().frame(height: 12) + titleRow + Spacer().frame(height: 20) + ScrollView { + LazyVStack(pinnedViews: [.sectionHeaders]) { VStack(spacing: 0) { + vaultPnlRow + Spacer().frame(height: 16) + div + Spacer().frame(height: 16) + aprTvlRow Spacer().frame(height: 16) - openPositionsHeader - Spacer().frame(height: 8) div Spacer().frame(height: 16) + chart + Spacer().frame(height: 16) + div + Spacer().frame(height: 16) + } + Section(header: positionsStickyHeader) { + positionsList } } - positionsListHeader - Spacer().frame(height: 16) - positionsList } } .frame(maxWidth: .infinity) @@ -208,8 +204,20 @@ private struct dydxVaultView: View { .leftAligned() .padding(.horizontal, 16) } + + private var positionsStickyHeader: some View { + VStack(spacing: 0) { + openPositionsHeader + Spacer().frame(height: 8) + div + Spacer().frame(height: 16) + positionsColumnsHeader + Spacer().frame(height: 8) + } + .themeColor(background: .layer2) + } - var positionsListHeader: some View { + var positionsColumnsHeader: some View { HStack(spacing: dydxVaultPositionViewModel.interSectionPadding) { Group { Text(DataLocalizer.shared?.localize(path: "APP.GENERAL.MARKET", params: nil) ?? "") From 3389bc09df6726c89edb46a416b4ae2f7fd02715 Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 15 Aug 2024 17:11:27 -0400 Subject: [PATCH 3/5] keep chart vm in memory --- .../_v4/Vault/dydxVaultViewBuilder.swift | 51 ++++++++++++++----- .../Landing/dydxVaultChartViewModel.swift | 46 ++++------------- .../Vault/Landing/dydxVaultViewModel.swift | 3 +- 3 files changed, 48 insertions(+), 52 deletions(-) diff --git a/dydx/dydxPresenters/dydxPresenters/_v4/Vault/dydxVaultViewBuilder.swift b/dydx/dydxPresenters/dydxPresenters/_v4/Vault/dydxVaultViewBuilder.swift index bc305c98b..13a16344b 100644 --- a/dydx/dydxPresenters/dydxPresenters/_v4/Vault/dydxVaultViewBuilder.swift +++ b/dydx/dydxPresenters/dydxPresenters/_v4/Vault/dydxVaultViewBuilder.swift @@ -13,6 +13,7 @@ import PlatformParticles import RoutingKit import ParticlesKit import PlatformUI +import Charts public class dydxVaultViewBuilder: NSObject, ObjectBuilderProtocol { public func build() -> T? { @@ -41,23 +42,45 @@ private class dydxVaultViewBuilderPresenter: HostedViewPresenter [ChartDataEntry] { + let selectedValueTime = viewModel?.vaultChart?.selectedValueTime ?? .oneDay + let now = Date().timeIntervalSince1970 + let finalTimeSecondsAway = selectedValueTime == .oneDay ? 3600.0*24.0 : selectedValueTime == .sevenDays ? 3600.0*24.0*7.0 : 3600.0*24.0*30.0 + let numEntries = Int.random(in: 0..<100) + let entries = (0.. [dydxVaultPositionViewModel] { + return [ + dydxVaultPositionViewModel(assetName: "logo_bitcoin", market: "BTC", side: .long, leverage: 10.80, notionalValue: 100000, positionSize: 10000, token: "BTC", tokenUnitPrecision: 6, pnlAmount: 1000, pnlPercentage: 10, sparklineValues: (0..<10).map { _ in Double.random(in: 0.0...1.0) }), + dydxVaultPositionViewModel(assetName: "logo_ethereum", market: "ETH", side: .short, leverage: 88.88, notionalValue: 50000, positionSize: 10000, token: "ETH", tokenUnitPrecision: -1, pnlAmount: -500, pnlPercentage: -1, sparklineValues: (0..<10).map { _ in Double.random(in: 0.0...1.0) }), + dydxVaultPositionViewModel(assetName: "logo_bitcoin", market: "BTC", side: .long, leverage: 10.80, notionalValue: 100000, positionSize: 10000, token: "BTC", tokenUnitPrecision: 6, pnlAmount: 1000, pnlPercentage: 10, sparklineValues: (0..<10).map { _ in Double.random(in: 0.0...1.0) }), + dydxVaultPositionViewModel(assetName: "logo_ethereum", market: "ETH", side: .short, leverage: 88.88, notionalValue: 50000, positionSize: 10000, token: "ETH", tokenUnitPrecision: -1, pnlAmount: -500, pnlPercentage: -1, sparklineValues: (0..<10).map { _ in Double.random(in: 0.0...1.0) }), + dydxVaultPositionViewModel(assetName: "logo_bitcoin", market: "BTC", side: .long, leverage: 10.80, notionalValue: 100000, positionSize: 10000, token: "BTC", tokenUnitPrecision: 6, pnlAmount: 1000, pnlPercentage: 10, sparklineValues: (0..<10).map { _ in Double.random(in: 0.0...1.0) }), + dydxVaultPositionViewModel(assetName: "logo_ethereum", market: "ETH", side: .short, leverage: 88.88, notionalValue: 50000, positionSize: 10000, token: "ETH", tokenUnitPrecision: -1, pnlAmount: -500, pnlPercentage: -1, sparklineValues: (0..<10).map { _ in Double.random(in: 0.0...1.0) }), + dydxVaultPositionViewModel(assetName: "logo_bitcoin", market: "BTC", side: .long, leverage: 10.80, notionalValue: 100000, positionSize: 10000, token: "BTC", tokenUnitPrecision: 6, pnlAmount: 1000, pnlPercentage: 10, sparklineValues: (0..<10).map { _ in Double.random(in: 0.0...1.0) }), + dydxVaultPositionViewModel(assetName: "logo_ethereum", market: "ETH", side: .short, leverage: 88.88, notionalValue: 50000, positionSize: 10000, token: "ETH", tokenUnitPrecision: -1, pnlAmount: -500, pnlPercentage: -1, sparklineValues: (0..<10).map { _ in Double.random(in: 0.0...1.0) }), + dydxVaultPositionViewModel(assetName: "logo_bitcoin", market: "BTC", side: .long, leverage: 10.80, notionalValue: 100000, positionSize: 10000, token: "BTC", tokenUnitPrecision: 6, pnlAmount: 1000, pnlPercentage: 10, sparklineValues: (0..<10).map { _ in Double.random(in: 0.0...1.0) }), + dydxVaultPositionViewModel(assetName: "logo_ethereum", market: "ETH", side: .short, leverage: 88.88, notionalValue: 50000, positionSize: 10000, token: "ETH", tokenUnitPrecision: -1, pnlAmount: -500, pnlPercentage: -1, sparklineValues: (0..<10).map { _ in Double.random(in: 0.0...1.0) }), + dydxVaultPositionViewModel(assetName: "logo_bitcoin", market: "BTC", side: .long, leverage: 10.80, notionalValue: 100000, positionSize: 10000, token: "BTC", tokenUnitPrecision: 6, pnlAmount: 1000, pnlPercentage: 10, sparklineValues: (0..<10).map { _ in Double.random(in: 0.0...1.0) }), + dydxVaultPositionViewModel(assetName: "logo_ethereum", market: "ETH", side: .short, leverage: 88.88, notionalValue: 50000, positionSize: 10000, token: "ETH", tokenUnitPrecision: -1, pnlAmount: -500, pnlPercentage: -1, sparklineValues: (0..<10).map { _ in Double.random(in: 0.0...1.0) }), + ] + + } } diff --git a/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultChartViewModel.swift b/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultChartViewModel.swift index 906ad2fd4..96b4bf07f 100644 --- a/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultChartViewModel.swift +++ b/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultChartViewModel.swift @@ -15,18 +15,12 @@ import dydxChart public class dydxVaultChartViewModel: PlatformViewModel { - @Published var selectedValueType: ValueTypeOption = .pnl - @Published var selectedValueTime: ValueTimeOption = .oneDay { - didSet { - //TODO: remove, just for testing - guard oldValue != selectedValueTime else { return } - setEntries(selectedValueTime: selectedValueTime, selectedValueType: selectedValueType) - } - } + @Published public var selectedValueType: ValueTypeOption = .pnl + @Published public var selectedValueTime: ValueTimeOption = .oneDay fileprivate let valueTypeOptions = ValueTypeOption.allCases fileprivate let valueTimeOptions = ValueTimeOption.allCases - + fileprivate let lineChart = { let lineChart = LineChartView() lineChart.data = LineChartData() @@ -55,23 +49,10 @@ public class dydxVaultChartViewModel: PlatformViewModel { return lineChart }() - // TODO: replace with actual data, delete cancellables - public func setEntries(entries: [ChartDataEntry] = [], selectedValueTime newSelectedValueTime: ValueTimeOption? = nil, selectedValueType newSelectedValueType: ValueTypeOption? = nil) { - if let newSelectedValueType { - selectedValueType = newSelectedValueType - } - if let newSelectedValueTime { - selectedValueTime = newSelectedValueTime - } - //TODO: remove - // this is just for testing - let now = Date().timeIntervalSince1970 - let finalTimeSecondsAway = selectedValueTime == .oneDay ? 3600.0*24.0 : selectedValueTime == .sevenDays ? 3600.0*24.0*7.0 : 3600.0*24.0*30.0 - let numEntries = Int.random(in: 0..<100) - let entries = (0..= (entries.first?.y ?? -Double.infinity) let color = isPositive ? ThemeSettings.positiveColor.uiColor : ThemeSettings.negativeColor.uiColor @@ -101,17 +82,8 @@ public class dydxVaultChartViewModel: PlatformViewModel { lineChart.xAxis.valueFormatter = selectedValueTime.valueFormatter lineChart.data = LineChartData(dataSet: dataSet) - } - - // TODO: delete and replace with real data - private var cancellables = Set() - init() { - super.init() - Timer.publish(every: 1, triggerNow: true) - .sink { [weak self] _ in - self?.setEntries() - } - .store(in: &cancellables) + lineChart.notifyDataSetChanged() + objectWillChange.send() } public enum ValueTypeOption: CaseIterable, RadioButtonContentDisplayable { diff --git a/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultViewModel.swift b/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultViewModel.swift index 0bfab4ded..4a2fa90b0 100644 --- a/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultViewModel.swift +++ b/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultViewModel.swift @@ -15,6 +15,7 @@ public class dydxVaultViewModel: PlatformViewModel { @Published public var vaultBalance: Double? @Published public var profitDollars: Double? @Published public var profitPercentage: Double? + @Published public var vaultChart: dydxVaultChartViewModel? @Published public var positions: [dydxVaultPositionViewModel]? @Published public var cancelAction: (() -> Void)? @Published public var learnMoreAction: (() -> Void)? @@ -182,7 +183,7 @@ private struct dydxVaultView: View { // MARK: - Section 3 - graph var chart: some View { - dydxVaultChartViewModel() + viewModel.vaultChart? .createView() .frame(height: 174) } From 2c2b210fb863225fadb47e7a859f461669540f9d Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 19 Aug 2024 10:13:41 -0400 Subject: [PATCH 4/5] polish --- .../_v4/Vault/Landing/dydxVaultPositionView.swift | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultPositionView.swift b/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultPositionView.swift index 59908565a..00573fe14 100644 --- a/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultPositionView.swift +++ b/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultPositionView.swift @@ -31,10 +31,13 @@ public class dydxVaultPositionViewModel: PlatformViewModel { @Published public var sparklineValues: [Double] fileprivate var sideLeverageAttributedText: AttributedString { - let attributedSideText = AttributedString(text: side.text, urlString: nil).themeColor(foreground: side.color) + let attributedSideText = AttributedString(text: side.text, urlString: nil) + .themeColor(foreground: side.color) let leverageText = dydxFormatter.shared.leverage(number: leverage) ?? "--" - let attributedLeverageText = AttributedString(text: "@ " + leverageText, urlString: nil).themeColor(foreground: .textTertiary) - return attributedSideText + attributedLeverageText + let attributedLeverageText = AttributedString(text: "@ " + leverageText, urlString: nil) + .themeColor(foreground: .textTertiary) + return (attributedSideText + attributedLeverageText) + .themeFont(fontType: .base, fontSize: .smaller) } fileprivate var notionalValueText: String { From ea02ac2b5d159fc33219f14f9b1203cbab049ce5 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 19 Aug 2024 10:47:45 -0400 Subject: [PATCH 5/5] remove unnecessary chart notifications --- .../dydxViews/_v4/Vault/Landing/dydxVaultChartViewModel.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultChartViewModel.swift b/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultChartViewModel.swift index 96b4bf07f..39255fe66 100644 --- a/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultChartViewModel.swift +++ b/dydx/dydxViews/dydxViews/_v4/Vault/Landing/dydxVaultChartViewModel.swift @@ -82,8 +82,6 @@ public class dydxVaultChartViewModel: PlatformViewModel { lineChart.xAxis.valueFormatter = selectedValueTime.valueFormatter lineChart.data = LineChartData(dataSet: dataSet) - lineChart.notifyDataSetChanged() - objectWillChange.send() } public enum ValueTypeOption: CaseIterable, RadioButtonContentDisplayable {