Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI-628: vault landing screen positions list #234

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import PlatformParticles
import RoutingKit
import ParticlesKit
import PlatformUI
import Charts

public class dydxVaultViewBuilder: NSObject, ObjectBuilderProtocol {
public func build<T>() -> 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
}
}
Expand All @@ -41,5 +42,45 @@ private class dydxVaultViewBuilderPresenter: HostedViewPresenter<dydxVaultViewMo
super.init()

viewModel = dydxVaultViewModel()
viewModel?.vaultChart = dydxVaultChartViewModel()

//TODO: remove & replace, test only
Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { [weak self] _ in
guard let self = self else { return }
self.viewModel?.vaultChart?.setEntries(entries: self.generateEntries())
self.viewModel?.positions = self.generatePositions()
}
}

// TODO: remove, just for testing
private func generateEntries() -> [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..<numEntries).map { i in
ChartDataEntry(x: now + Double(i)/Double(numEntries) * finalTimeSecondsAway, y: Double.random(in: 0..<100))
}
return entries
}

//TODO: remove
// this is just for testing
private func generatePositions() -> [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) }),
]

}
}
8 changes: 8 additions & 0 deletions dydx/dydxViews/dydxViews.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@
27DBF3C92C4A05B9009EB2D6 /* dydxTitledNumberField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27DBF3C82C4A05B9009EB2D6 /* dydxTitledNumberField.swift */; };
27E072D22C1A095C0034B963 /* dydxPortfolioPendingPositionsItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27E072D12C1A095C0034B963 /* dydxPortfolioPendingPositionsItemViewModel.swift */; };
27E0736B2C20D27F0034B963 /* dydxCancelPendingIsolatedOrdersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27E0736A2C20D27F0034B963 /* dydxCancelPendingIsolatedOrdersView.swift */; };
27EB25832C6D1E5E008C187B /* dydxVaultPositionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27EB25822C6D1E5E008C187B /* dydxVaultPositionView.swift */; };
27EB25852C6D28BF008C187B /* SparklineChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27EB25842C6D28BF008C187B /* SparklineChart.swift */; };
27ED340C2AD47CB100C159F5 /* dydxBannerErrorAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27ED340B2AD47CB100C159F5 /* dydxBannerErrorAlert.swift */; };
27ED365C2AD735A800C159F5 /* dydxSecurityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27ED365B2AD735A800C159F5 /* dydxSecurityView.swift */; };
27F624112BBD9FEB00AB6D1A /* dydxPriceInputViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F624042BBD9FEB00AB6D1A /* dydxPriceInputViewModel.swift */; };
Expand Down Expand Up @@ -583,6 +585,8 @@
27DBF3C82C4A05B9009EB2D6 /* dydxTitledNumberField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxTitledNumberField.swift; sourceTree = "<group>"; };
27E072D12C1A095C0034B963 /* dydxPortfolioPendingPositionsItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxPortfolioPendingPositionsItemViewModel.swift; sourceTree = "<group>"; };
27E0736A2C20D27F0034B963 /* dydxCancelPendingIsolatedOrdersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxCancelPendingIsolatedOrdersView.swift; sourceTree = "<group>"; };
27EB25822C6D1E5E008C187B /* dydxVaultPositionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxVaultPositionView.swift; sourceTree = "<group>"; };
27EB25842C6D28BF008C187B /* SparklineChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SparklineChart.swift; sourceTree = "<group>"; };
27ED340B2AD47CB100C159F5 /* dydxBannerErrorAlert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = dydxBannerErrorAlert.swift; sourceTree = "<group>"; };
27ED365B2AD735A800C159F5 /* dydxSecurityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSecurityView.swift; sourceTree = "<group>"; };
27F624042BBD9FEB00AB6D1A /* dydxPriceInputViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = dydxPriceInputViewModel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -938,6 +942,7 @@
0273A15E2ACCDDB1001B89F5 /* SelectionBar.swift */,
273F50152B7C3F120034792A /* SignedAmountView.swift */,
27D276222C519C98002775F2 /* dydxComponents */,
27EB25842C6D28BF008C187B /* SparklineChart.swift */,
);
path = Shared;
sourceTree = "<group>";
Expand Down Expand Up @@ -1500,6 +1505,7 @@
27C6AE0A2C618044005517B5 /* RadioButtons */,
2751D6542C59646700B36F95 /* dydxVaultViewModel.swift */,
2700A3162C5D72BB00880AFA /* dydxVaultChartViewModel.swift */,
27EB25822C6D1E5E008C187B /* dydxVaultPositionView.swift */,
);
path = Landing;
sourceTree = "<group>";
Expand Down Expand Up @@ -2066,6 +2072,7 @@
0279DE892BED402C00F9ECF8 /* dydxAdjustMarginPercentageView.swift in Sources */,
026382EB28F0EF0000F766FA /* dydxMarketPriceCandlesResolutionsView.swift in Sources */,
02F99F3E29E4D5750009B3E8 /* dydxTransferSearchItemView.swift in Sources */,
27EB25832C6D1E5E008C187B /* dydxVaultPositionView.swift in Sources */,
27DBF3C92C4A05B9009EB2D6 /* dydxTitledNumberField.swift in Sources */,
0284201629AD71B600C0E7CC /* Enums.swift in Sources */,
02678FA629666BE600EE346B /* dydxPortfolioOrdersView.swift in Sources */,
Expand Down Expand Up @@ -2098,6 +2105,7 @@
277E918B2B27762F005CCBCB /* dydxRewardsLaunchIncentivesView.swift in Sources */,
0268BBF92A8BE08C00D0C59B /* dydxTransferOutView.swift in Sources */,
0279DE452BEBE75100F9ECF8 /* dydxTargetLeverageCtaButtonView.swift in Sources */,
27EB25852C6D28BF008C187B /* SparklineChart.swift in Sources */,
0208627A28F4D95F00C9D3A0 /* dydxMarketInfoPagingView.swift in Sources */,
027F3EF72AB93ADC00602E5B /* dydxProfileBalancesViewModel.swift in Sources */,
024B44F52983E38D00E35D54 /* dydxTradeStatusLogoView.swift in Sources */,
Expand Down
11 changes: 11 additions & 0 deletions dydx/dydxViews/dydxViews/Shared/SideText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@ public class SideTextViewModel: PlatformViewModel, Hashable {
return ""
}
}

var color: ThemeColor.SemanticColor {
switch self {
case .long, .buy:
return ThemeSettings.positiveColor
case .short, .sell:
return ThemeSettings.negativeColor
case .custom, .none:
return ThemeColor.SemanticColor.textPrimary
}
}

public init(positionSide: PositionSide) {
switch positionSide {
Expand Down
57 changes: 57 additions & 0 deletions dydx/dydxViews/dydxViews/Shared/SparklineChart.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// SparklineChart.swift
// dydxViews
//
// Created by Michael Maguire on 8/14/24.
//

import Foundation
import SwiftUI
import Charts
import PlatformUI

struct SparklineView: View {
@State var values: [Double]

private var lineChart: some View {
let chart = LineChartView()
chart.data = LineChartData()
chart.xAxis.drawGridLinesEnabled = false
chart.leftAxis.enabled = false
chart.rightAxis.enabled = false
chart.xAxis.enabled = false
chart.setViewPortOffsets(left: 0, top: 0, right: 0, bottom: 0)
chart.pinchZoomEnabled = false
chart.doubleTapToZoomEnabled = false
// enables dragging the highlighted value indicator
chart.dragEnabled = false
chart.legend.enabled = false

let entries = (0..<values.count).map { ChartDataEntry(x: Double($0), y: values[$0]) }
let dataSet = LineChartDataSet(entries: entries)
let isPositive = (entries.last?.y ?? -Double.infinity) >= (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
}
}
2 changes: 2 additions & 0 deletions dydx/dydxViews/dydxViews/Shared/TokenText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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..<numEntries).map { i in
ChartDataEntry(x: now + Double(i)/Double(numEntries) * finalTimeSecondsAway, y: Double.random(in: 0..<100))
}

public init() {}

// TODO: replace with actual data
public func setEntries(entries: [ChartDataEntry] = []) {
let dataSet = LineChartDataSet(entries: entries)
let isPositive = (entries.last?.y ?? -Double.infinity) >= (entries.first?.y ?? -Double.infinity)
let color = isPositive ? ThemeSettings.positiveColor.uiColor : ThemeSettings.negativeColor.uiColor
Expand Down Expand Up @@ -102,17 +83,6 @@ public class dydxVaultChartViewModel: PlatformViewModel {

lineChart.data = LineChartData(dataSet: dataSet)
}

// TODO: delete and replace with real data
private var cancellables = Set<AnyCancellable>()
init() {
super.init()
Timer.publish(every: 1, triggerNow: true)
.sink { [weak self] _ in
self?.setEntries()
}
.store(in: &cancellables)
}

public enum ValueTypeOption: CaseIterable, RadioButtonContentDisplayable {
case pnl
Expand Down
Loading
Loading