Skip to content
This repository was archived by the owner on Mar 26, 2026. It is now read-only.

Commit b69593f

Browse files
gemdev111claude
andauthored
Perps account stats (#1619)
* Refactor balance privacy and header view actions Replaces the allowHiddenBalance property with a new BalanceActionType enum to better handle privacy toggling and header actions. Updates WalletHeaderView and related scenes to use isPrivacyEnabled and balanceActionType for improved flexibility. Adds PerpetualPortfolioScene and integrates portfolio presentation in PerpetualsScene. Cleans up unused allowHiddenBalance properties from view models and protocol. * Add Perpetual portfolio chart data support Introduces PerpetualPortfolioChartData and related types for representing portfolio chart data. Adds mapping extensions for GemPerpetualPortfolio types, updates GatewayService and PerpetualService protocols and implementations to support fetching and returning portfolio chart data, and updates test mocks accordingly. * Refactor chart components to primitives packages Moved and refactored chart-related types and view models from MarketInsight to Primitives and PrimitivesComponents packages. Unified chart state and price view models, introduced ChartStateView, and updated usages in Perpetuals and MarketInsight features. Improved chart value calculations and formatting, and enhanced modularity and reusability of chart UI components. * Add test kits and unit tests for chart and portfolio view models Introduces test kit utilities and mock data generators for chart-related models in Primitives and PrimitivesComponents. Adds comprehensive unit tests for ChartValues, ChartPriceViewModel, ChartValuesViewModel, and PerpetualPortfolioSceneViewModel to ensure correct behavior and improve test coverage. Updates Price mock defaults for consistency. * Update PerpetualPortfolioSceneViewModelTests.swift * Update core * Show value change instead of current value in portfolio chart Like Hyperdash, display the change amount (e.g., "+$8.48" or "-$0.75") rather than the current value with percentage. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Update tests * Update core * Refactor PerpetualPortfolioChartData to PerpetualPortfolio Replaces PerpetualPortfolioChartData and related types with PerpetualPortfolio, PerpetualPortfolioTimeframeData, and PerpetualPortfolioDataPoint. Updates all usages, extensions, and test kits to use the new structures, and removes the old files and mocks. This unifies and simplifies portfolio data modeling across the codebase. * Refactor chart value handling and add portfolio stats Introduces ChartValueType to distinguish between price and price change chart types, refactors related view models to use this type instead of a 'signed' boolean, and centralizes price change formatting in a new PriceChangeViewModel. Adds an info section to PerpetualPortfolioScene displaying unrealized PnL, all-time PnL, and volume, with supporting logic in PerpetualPortfolioSceneViewModel. Updates tests and related code to reflect these changes. * Refactor ChartView and add PulsingDotView Refactored ChartView for improved readability and modularity, including UI extraction and enhanced drag/selection logic. Added PulsingDotView to display a pulsing indicator on the chart, improving visual feedback for the latest data point. * Update core * Localize Perpetuals portfolio stats and chart labels Replaced hardcoded PerpetualPortfolioSceneViewModel strings with localized values. Added new keys for perpetuals-related terms to Localized.swift and updated all Localizable.strings files with translations for these keys. * Add account summary to PerpetualPortfolio Introduces the PerpetualAccountSummary struct and adds an accountSummary property to PerpetualPortfolio. Updates mapping and view model logic to display account leverage and margin usage in the portfolio scene, and ensures unrealized PnL is sourced from accountSummary. * Refactor portfolio data to use ChartDateValue Replaces PerpetualPortfolioDataPoint with ChartDateValue in portfolio models, extensions, and tests for consistency and simplification. Removes obsolete mapping and mock helpers, updates related code to use ChartDateValue directly, and adds a GemChartDateValue mapping extension. * Update PerpetualService+TestKit.swift * Update core * Update core * Refactor Perpetual portfolio and position updates to use address Replaces usage of Wallet in PerpetualService and related view models with explicit address and walletId parameters for portfolio and position updates. Introduces PerpetualPortfolioChartType in Primitives, updates related types and extensions, and moves PortfolioChartType logic. Refactors chart price change calculation into a static method and adds corresponding tests. Adds test kit and unit tests for PriceChangeViewModel. * Update core * Refactor to use Wallet.perpetualAddress extension Replaces repeated logic for retrieving the perpetual address from Wallet with a new Wallet.perpetualAddress computed property. Updates all usages in Perpetuals view models and PerpetualObserverService to use this extension, improving code clarity and maintainability. --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 37dd695 commit b69593f

93 files changed

Lines changed: 1656 additions & 514 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Features/Assets/Sources/Scenes/AssetScene.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ public struct AssetScene: View {
1919
Section { } header: {
2020
WalletHeaderView(
2121
model: model.assetHeaderModel,
22-
isHideBalanceEnalbed: .constant(false),
22+
isPrivacyEnabled: .constant(false),
23+
balanceActionType: .none,
2324
onHeaderAction: model.onSelectHeader,
2425
onInfoAction: model.onSelectWalletHeaderInfo
2526
)

Features/Assets/Sources/ViewModels/AssetHeaderViewModel.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ struct AssetHeaderViewModel: Sendable {
1212
}
1313

1414
extension AssetHeaderViewModel: HeaderViewModel {
15-
var allowHiddenBalance: Bool { false }
16-
1715
var isWatchWallet: Bool {
1816
walletModel.wallet.type == .view
1917
}

Features/MarketInsight/Sources/Scenes/ChartScene.swift

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,10 @@ public struct ChartScene: View {
2222
public var body: some View {
2323
List {
2424
Section { } header: {
25-
VStack {
26-
VStack {
27-
switch model.state {
28-
case .noData:
29-
StateEmptyView(title: model.emptyTitle)
30-
case .loading:
31-
LoadingView()
32-
case .data(let chartModel):
33-
ChartView(model: chartModel)
34-
case .error(let error):
35-
StateEmptyView(
36-
title: Localized.Errors.errorOccured,
37-
description: error.networkOrNoDataDescription,
38-
image: Images.ErrorConent.error
39-
)
40-
}
41-
}
42-
.frame(height: 320)
43-
44-
PeriodSelectorView(selectedPeriod: $model.currentPeriod)
45-
}
25+
ChartStateView(
26+
state: model.state,
27+
selectedPeriod: $model.selectedPeriod
28+
)
4629
}
4730
.cleanListRow()
4831

Features/MarketInsight/Sources/Types/ChartDateValue.swift

Lines changed: 0 additions & 13 deletions
This file was deleted.

Features/MarketInsight/Sources/ViewModels/ChartPriceModel.swift

Lines changed: 0 additions & 38 deletions
This file was deleted.

Features/MarketInsight/Sources/ViewModels/ChartSceneViewModel.swift

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import PriceService
1111
import Preferences
1212
import PriceAlertService
1313
import SwiftUI
14+
import Formatters
1415

1516
@MainActor
1617
@Observable
@@ -25,7 +26,7 @@ public final class ChartSceneViewModel {
2526
private let preferences: Preferences = .standard
2627

2728
var state: StateViewType<ChartValuesViewModel> = .loading
28-
var currentPeriod: ChartPeriod {
29+
var selectedPeriod: ChartPeriod {
2930
didSet {
3031
Task { await fetch() }
3132
}
@@ -41,7 +42,7 @@ public final class ChartSceneViewModel {
4142
var emptyTitle: String { Localized.Common.notAvailable }
4243
var errorTitle: String { Localized.Errors.errorOccured }
4344
var hasMarketData: Bool { priceData?.market != nil }
44-
45+
4546
var priceAlertsViewModel: PriceAlertsViewModel { PriceAlertsViewModel(priceAlerts: priceData?.priceAlerts ?? []) }
4647
var showPriceAlerts: Bool { priceAlertsViewModel.hasPriceAlerts && isPriceAvailable }
4748
var isPriceAvailable: Bool { PriceViewModel(price: priceData?.price, currencyCode: preferences.currency).isPriceAvailable }
@@ -60,7 +61,7 @@ public final class ChartSceneViewModel {
6061
self.assetModel = assetModel
6162
self.priceAlertService = priceAlertService
6263
self.walletId = walletId
63-
self.currentPeriod = currentPeriod
64+
self.selectedPeriod = currentPeriod
6465
self.priceRequest = PriceRequest(assetId: assetModel.asset.id)
6566
self.isPresentingSetPriceAlert = isPresentingSetPriceAlert
6667
}
@@ -79,7 +80,7 @@ extension ChartSceneViewModel {
7980
do {
8081
let values = try await service.getCharts(
8182
assetId: assetModel.asset.id,
82-
period: currentPeriod
83+
period: selectedPeriod
8384
)
8485
if let market = values.market {
8586
try priceService.updateMarketPrice(assetId: assetModel.asset.id, market: market, currency: preferences.currency)
@@ -90,13 +91,19 @@ extension ChartSceneViewModel {
9091
var charts = values.prices.map {
9192
ChartDateValue(date: Date(timeIntervalSince1970: TimeInterval($0.timestamp)), value: Double($0.value) * rate)
9293
}
93-
94+
9495
if let price = price, let last = charts.last, price.updatedAt > last.date {
9596
charts.append(ChartDateValue(date: .now, value: price.price))
9697
}
9798

9899
let chartValues = try ChartValues.from(charts: charts)
99-
let model = ChartValuesViewModel(period: currentPeriod, price: price?.mapToPrice(), values: chartValues)
100+
let formatter = CurrencyFormatter(currencyCode: preferences.currency)
101+
let model = ChartValuesViewModel(
102+
period: selectedPeriod,
103+
price: price?.mapToPrice(),
104+
values: chartValues,
105+
formatter: formatter
106+
)
100107
state = .data(model)
101108
} catch {
102109
state = .error(error)

Features/MarketInsight/Sources/ViewModels/ChartValuesViewModel.swift

Lines changed: 0 additions & 55 deletions
This file was deleted.

0 commit comments

Comments
 (0)