diff --git a/PlatformUI/PlatformUI/Components/Input/PlatformInput.swift b/PlatformUI/PlatformUI/Components/Input/PlatformInput.swift index 832a23401..c68752b60 100644 --- a/PlatformUI/PlatformUI/Components/Input/PlatformInput.swift +++ b/PlatformUI/PlatformUI/Components/Input/PlatformInput.swift @@ -432,7 +432,7 @@ open class PlatformPopoverOptionsInputViewModel: PlatformOptionsInputViewModel { guard let self = self else { return } - attrs.position = self.position + attrs.position = self.position attrs.sourceFrameInset.top = -8 let animation = Animation.easeOut(duration: 0.2) attrs.presentation.animation = animation @@ -504,6 +504,17 @@ open class PlatformBooleanInputViewModel: PlatformValueInputViewModel { open var isEnabled: Bool = true + open override var header: PlatformViewModel { + if let label = label, label.length > 0 { + return Text(label) + .themeColor(foreground: isEnabled ? .textSecondary : .textTertiary) + .themeFont(fontSize: .smaller) + .wrappedViewModel + + } + return PlatformView.nilViewModel + } + override open var value: String? { didSet { inputBinding.update() @@ -525,8 +536,9 @@ open class PlatformBooleanInputViewModel: PlatformValueInputViewModel { guard let self = self else { return AnyView(PlatformView.nilView) } return AnyView( - HStack { + HStack(spacing: 0) { self.header.createView(parentStyle: style) + .fixedSize() Spacer() Toggle("", isOn: self.inputBinding) .toggleStyle(SwitchToggleStyle(tint: ThemeColor.SemanticColor.colorPurple.color)) diff --git a/dydx/dydxPresenters/dydxPresenters.xcodeproj/project.pbxproj b/dydx/dydxPresenters/dydxPresenters.xcodeproj/project.pbxproj index d4af7aebc..3f4919709 100644 --- a/dydx/dydxPresenters/dydxPresenters.xcodeproj/project.pbxproj +++ b/dydx/dydxPresenters/dydxPresenters.xcodeproj/project.pbxproj @@ -71,7 +71,7 @@ 027CA87229EDFC990069781A /* dydxTransferInputCtaButtonViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027CA87129EDFC990069781A /* dydxTransferInputCtaButtonViewPresenter.swift */; }; 027CB28729EEFF910069781A /* dydxTransferStatusViewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027CB28629EEFF910069781A /* dydxTransferStatusViewBuilder.swift */; }; 027E1EF829CA27CD0098666F /* dydxSettingsLandingViewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027E1EF729CA27CD0098666F /* dydxSettingsLandingViewBuilder.swift */; }; - 027F3F062AB93B3700602E5B /* dydxProfileRewardsViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027F3F052AB93B3700602E5B /* dydxProfileRewardsViewPresenter.swift */; }; + 027F3F062AB93B3700602E5B /* dydxProfileBalancesViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027F3F052AB93B3700602E5B /* dydxProfileBalancesViewPresenter.swift */; }; 0280B3A629CB63E10017D64A /* dydxOnboardWelcomeViewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0280B3A529CB63E10017D64A /* dydxOnboardWelcomeViewBuilder.swift */; }; 0284202F29AD727200C0E7CC /* dydxViews.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0284201F29AD725000C0E7CC /* dydxViews.framework */; }; 02860A9F29C15E760079E644 /* dydxOnboardScanViewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02860A9329C15E760079E644 /* dydxOnboardScanViewBuilder.swift */; }; @@ -130,6 +130,7 @@ 2741E3702A68787A000FA190 /* settings_direction_color_preference.json in Resources */ = {isa = PBXBuildFile; fileRef = 2741E3632A68787A000FA190 /* settings_direction_color_preference.json */; }; 2741E3732A689740000FA190 /* dydxDirectionColorPreferenceViewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2741E3722A689740000FA190 /* dydxDirectionColorPreferenceViewBuilder.swift */; }; 276908FF2AAFB22F0075B2D6 /* dydxPortfolioTransfersViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 276908FE2AAFB22F0075B2D6 /* dydxPortfolioTransfersViewPresenter.swift */; }; + 277E8FC92B1E576B005CCBCB /* dydxProfileRewardsViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277E8FC82B1E576B005CCBCB /* dydxProfileRewardsViewPresenter.swift */; }; 27C027532AFD761300E92CCB /* dydxSettingsHelpRowViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27C027522AFD761300E92CCB /* dydxSettingsHelpRowViewPresenter.swift */; }; 27DB2EA32AC1E7B20047BC39 /* dydxTradeRestrictedViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27DB2EA22AC1E7B20047BC39 /* dydxTradeRestrictedViewPresenter.swift */; }; 314BBDE9F332ECA910BC414E /* Pods_iOS_dydxPresenters.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F1551C00FFF41C29CFC5BD94 /* Pods_iOS_dydxPresenters.framework */; }; @@ -409,7 +410,7 @@ 027CA87129EDFC990069781A /* dydxTransferInputCtaButtonViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxTransferInputCtaButtonViewPresenter.swift; sourceTree = ""; }; 027CB28629EEFF910069781A /* dydxTransferStatusViewBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxTransferStatusViewBuilder.swift; sourceTree = ""; }; 027E1EF729CA27CD0098666F /* dydxSettingsLandingViewBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSettingsLandingViewBuilder.swift; sourceTree = ""; }; - 027F3F052AB93B3700602E5B /* dydxProfileRewardsViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxProfileRewardsViewPresenter.swift; sourceTree = ""; }; + 027F3F052AB93B3700602E5B /* dydxProfileBalancesViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxProfileBalancesViewPresenter.swift; sourceTree = ""; }; 0280B3A529CB63E10017D64A /* dydxOnboardWelcomeViewBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxOnboardWelcomeViewBuilder.swift; sourceTree = ""; }; 0284201929AD725000C0E7CC /* dydxViews.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = dydxViews.xcodeproj; path = ../dydxViews/dydxViews.xcodeproj; sourceTree = ""; }; 02860A9329C15E760079E644 /* dydxOnboardScanViewBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = dydxOnboardScanViewBuilder.swift; sourceTree = ""; }; @@ -468,6 +469,7 @@ 2741E3632A68787A000FA190 /* settings_direction_color_preference.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = settings_direction_color_preference.json; sourceTree = ""; }; 2741E3722A689740000FA190 /* dydxDirectionColorPreferenceViewBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = dydxDirectionColorPreferenceViewBuilder.swift; sourceTree = ""; }; 276908FE2AAFB22F0075B2D6 /* dydxPortfolioTransfersViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxPortfolioTransfersViewPresenter.swift; sourceTree = ""; }; + 277E8FC82B1E576B005CCBCB /* dydxProfileRewardsViewPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = dydxProfileRewardsViewPresenter.swift; sourceTree = ""; }; 27C027522AFD761300E92CCB /* dydxSettingsHelpRowViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSettingsHelpRowViewPresenter.swift; sourceTree = ""; }; 27DB2EA22AC1E7B20047BC39 /* dydxTradeRestrictedViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxTradeRestrictedViewPresenter.swift; sourceTree = ""; }; 64487FFE2AA248340068DD87 /* dydxAlertsWorker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = dydxAlertsWorker.swift; sourceTree = ""; }; @@ -867,7 +869,8 @@ 0258BA2729929E7D0098E1BE /* Components */ = { isa = PBXGroup; children = ( - 027F3F052AB93B3700602E5B /* dydxProfileRewardsViewPresenter.swift */, + 277E8FC82B1E576B005CCBCB /* dydxProfileRewardsViewPresenter.swift */, + 027F3F052AB93B3700602E5B /* dydxProfileBalancesViewPresenter.swift */, 0258BA2829929E870098E1BE /* dydxProfileButtonsViewPresenter.swift */, 028DB33F2A05893D0090BE58 /* dydxProfileHeaderViewPresenter.swift */, 02F95A8D2A1D6AAD00828F9A /* dydxProfileHistoryViewPresenter.swift */, @@ -1802,6 +1805,7 @@ 02669B7C2AD8661F00A756AA /* dydxCarteraConfigWorker.swift in Sources */, 02B841B228EF6C6400C4D25B /* dydxMarketInfoViewBuilder.swift in Sources */, 02031F1C2AC3A7130069E00D /* dydxTradeSheetTipDraftViewPresenter.swift in Sources */, + 277E8FC92B1E576B005CCBCB /* dydxProfileRewardsViewPresenter.swift in Sources */, 64A4DB9B2966490C008D8E20 /* dydxTradeInputOrderTypePresenter.swift in Sources */, 0236F118296ABEF500EB995F /* dydxPortfolioPositionsViewPresenter.swift in Sources */, 02282E752AC8860300BC9F01 /* dydxOrderbookGroupViewPresenter.swift in Sources */, @@ -1821,7 +1825,7 @@ 02031F142AC374150069E00D /* dydxTradeSheetTipBuySellViewPresenter.swift in Sources */, 02B6CE752A7087A700C5F088 /* dydxTransferSubaccountWorker.swift in Sources */, 02FF0BD229AE92FE00781EDA /* dydxWalletListViewBuilder.swift in Sources */, - 027F3F062AB93B3700602E5B /* dydxProfileRewardsViewPresenter.swift in Sources */, + 027F3F062AB93B3700602E5B /* dydxProfileBalancesViewPresenter.swift in Sources */, 02F6E71F2A8293270018F00C /* dydxProfileFeesViewPresenter.swift in Sources */, 647D0F152A9FB1C600DA7815 /* dydxFrontendAlertsProvider.swift in Sources */, 02D1345828ECF30000B46941 /* dydxMarketsSearchViewBuilder.swift in Sources */, diff --git a/dydx/dydxPresenters/dydxPresenters/_v4/Profile/Components/dydxProfileBalancesViewPresenter.swift b/dydx/dydxPresenters/dydxPresenters/_v4/Profile/Components/dydxProfileBalancesViewPresenter.swift new file mode 100644 index 000000000..161e97e80 --- /dev/null +++ b/dydx/dydxPresenters/dydxPresenters/_v4/Profile/Components/dydxProfileBalancesViewPresenter.swift @@ -0,0 +1,59 @@ +// +// dydxProfileBalancesViewPresenter.swift +// dydxPresenters +// +// Created by Rui Huang on 9/18/23. +// + +import Utilities +import dydxViews +import PlatformParticles +import RoutingKit +import ParticlesKit +import PlatformUI +import Abacus +import dydxStateManager +import dydxFormatter +import Combine + +public protocol dydxProfileBalancesViewPresenterProtocol: HostedViewPresenterProtocol { + var viewModel: dydxProfileBalancesViewModel? { get } +} + +public class dydxProfileBalancesViewPresenter: HostedViewPresenter, dydxProfileBalancesViewPresenterProtocol { + override init() { + super.init() + + viewModel = dydxProfileBalancesViewModel() + viewModel?.nativeTokenName = dydxTokenConstants.nativeTokenName + viewModel?.nativeTokenLogoUrl = dydxTokenConstants.nativeTokenLogoUrl + } + + public override func start() { + super.start() + + AbacusStateManager.shared.state.accountBalance(of: .dydx) + .sink { [weak self] dydxAmount in + if let dydxAmount = dydxAmount { + self?.viewModel?.walletAmount = dydxFormatter.shared.raw(number: Parser.standard.asNumber(dydxAmount), digits: 4) + self?.viewModel?.transferAction = { + Router.shared?.navigate(to: RoutingRequest(path: "/transfer", params: ["section": "transferOut"]), animated: true, completion: nil) + } + } else { + self?.viewModel?.walletAmount = "-" + self?.viewModel?.transferAction = nil + } + } + .store(in: &subscriptions) + + AbacusStateManager.shared.state.stakingBalance(of: .dydx) + .sink { [weak self] dydxAmount in + if let dydxAmount = dydxAmount { + self?.viewModel?.stakedAmount = dydxFormatter.shared.raw(number: Parser.standard.asNumber(dydxAmount), digits: 4) + } else { + self?.viewModel?.stakedAmount = "-" + } + } + .store(in: &subscriptions) + } +} diff --git a/dydx/dydxPresenters/dydxPresenters/_v4/Profile/Components/dydxProfileRewardsViewPresenter.swift b/dydx/dydxPresenters/dydxPresenters/_v4/Profile/Components/dydxProfileRewardsViewPresenter.swift index 3b98e3d41..6a810f316 100644 --- a/dydx/dydxPresenters/dydxPresenters/_v4/Profile/Components/dydxProfileRewardsViewPresenter.swift +++ b/dydx/dydxPresenters/dydxPresenters/_v4/Profile/Components/dydxProfileRewardsViewPresenter.swift @@ -25,35 +25,7 @@ public class dydxProfileRewardsViewPresenter: HostedViewPresenter Bool { lhs.tradingVolume == rhs.tradingVolume && lhs.takerFeeRate == rhs.takerFeeRate && @@ -20,11 +20,12 @@ public class dydxProfileFeesViewModel: PlatformViewModel, Equatable { @Published public var tradingVolume: String? @Published public var takerFeeRate: String? @Published public var makerFeeRate: String? - @Published public var tapAction: (() -> Void)? - public init() { } + public init() { + super.init(title: DataLocalizer.localize(path: "APP.GENERAL.FEES")) + } - public static var previewValue: dydxProfileFeesViewModel { + fileprivate static var previewValue: dydxProfileFeesViewModel { let vm = dydxProfileFeesViewModel() vm.tradingVolume = "$120,000" vm.takerFeeRate = "0.01%" @@ -32,76 +33,49 @@ public class dydxProfileFeesViewModel: PlatformViewModel, Equatable { 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 else { return AnyView(PlatformView.nilView) } + override func createContent(parentStyle: ThemeStyle = ThemeStyle.defaultStyle, styleKey: String? = nil) -> AnyView? { + VStack(spacing: 16) { + HStack { + VStack(spacing: 8) { + Text(DataLocalizer.localize(path: "APP.TRADE.TAKER")) + .themeFont(fontType: .text, fontSize: .smaller) + .leftAligned() - let view = VStack(spacing: 0) { - HStack { - Text(DataLocalizer.localize(path: "APP.GENERAL.FEES")) - .themeFont(fontSize: .small) - Spacer() - PlatformIconViewModel(type: .system(name: "chevron.right"), - size: CGSize(width: 10, height: 10), - templateColor: .textSecondary) - .createView(parentStyle: style) + Text(self.takerFeeRate ?? "-") + .themeFont(fontType: .text, fontSize: .small) + .themeColor(foreground: .textPrimary) + .leftAligned() } - .padding() - - DividerModel() - .createView(parentStyle: style) - - VStack(spacing: 16) { - HStack { - VStack(spacing: 8) { - Text(DataLocalizer.localize(path: "APP.TRADE.TAKER")) - .themeFont(fontType: .text, fontSize: .smaller) - .leftAligned() - - Text(self.takerFeeRate ?? "-") - .themeFont(fontType: .text, fontSize: .small) - .themeColor(foreground: .textPrimary) - .leftAligned() - } - - VStack(spacing: 8) { - Text(DataLocalizer.localize(path: "APP.TRADE.MAKER")) - .themeFont(fontType: .text, fontSize: .smaller) - .leftAligned() - - Text(self.makerFeeRate ?? "-") - .themeFont(fontType: .text, fontSize: .small) - .themeColor(foreground: .textPrimary) - .leftAligned() - } - } - - VStack(spacing: 8) { - HStack { - Text(DataLocalizer.localize(path: "APP.TRADE.VOLUME")) - - Text(DataLocalizer.localize(path: "APP.GENERAL.TIME_STRINGS.30D")) - .themeColor(foreground: .textTertiary) - } + + VStack(spacing: 8) { + Text(DataLocalizer.localize(path: "APP.TRADE.MAKER")) .themeFont(fontType: .text, fontSize: .smaller) .leftAligned() - Text(self.tradingVolume ?? "-") - .themeFont(fontType: .text, fontSize: .small) - .themeColor(foreground: .textPrimary) - .leftAligned() - } + Text(self.makerFeeRate ?? "-") + .themeFont(fontType: .text, fontSize: .small) + .themeColor(foreground: .textPrimary) + .leftAligned() } - .padding(16) - } - .themeColor(background: .layer3) - .cornerRadius(12, corners: .allCorners) - .onTapGesture { [weak self] in - self?.tapAction?() } - return AnyView(view) + VStack(spacing: 8) { + HStack { + Text(DataLocalizer.localize(path: "APP.TRADE.VOLUME")) + + Text(DataLocalizer.localize(path: "APP.GENERAL.TIME_STRINGS.30D")) + .themeColor(foreground: .textTertiary) + } + .themeFont(fontType: .text, fontSize: .smaller) + .leftAligned() + + Text(self.tradingVolume ?? "-") + .themeFont(fontType: .text, fontSize: .small) + .themeColor(foreground: .textPrimary) + .leftAligned() + } } + .wrappedInAnyView() } } diff --git a/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxProfileHistoryView.swift b/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxProfileHistoryView.swift index 40da4a83f..3705044e5 100644 --- a/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxProfileHistoryView.swift +++ b/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxProfileHistoryView.swift @@ -10,7 +10,7 @@ import SwiftUI import PlatformUI import Utilities -public class dydxProfileHistoryViewModel: PlatformViewModel { +public class dydxProfileHistoryViewModel: dydxTitledCardViewModel { public class Item: PlatformViewModel, Equatable { public static func == (lhs: dydxProfileHistoryViewModel.Item, rhs: dydxProfileHistoryViewModel.Item) -> Bool { lhs.action == rhs.action && @@ -43,116 +43,93 @@ public class dydxProfileHistoryViewModel: PlatformViewModel { } @Published public var items: [Item] = [] - @Published public var tapAction: (() -> Void)? - public init() { } + public init() { + super.init(title: DataLocalizer.localize(path: "APP.GENERAL.HISTORY")) + } public static var previewValue: dydxProfileHistoryViewModel { let vm = dydxProfileHistoryViewModel() 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 else { return AnyView(PlatformView.nilView) } - - return AnyView( - VStack(spacing: 0) { + public override func createContent(parentStyle: ThemeStyle = ThemeStyle.defaultStyle, styleKey: String? = nil) -> AnyView? { + VStack(spacing: 0) { + GeometryReader { metrics in + VStack(spacing: 8) { HStack { - Text(DataLocalizer.localize(path: "APP.GENERAL.HISTORY")) - .themeColor(foreground: .textSecondary) - .themeFont(fontSize: .small) - Spacer() - PlatformIconViewModel(type: .system(name: "chevron.right"), - size: CGSize(width: 10, height: 10), - templateColor: .textSecondary) - .createView(parentStyle: style) + Text(DataLocalizer.localize(path: "APP.GENERAL.ACTION")) + .leftAligned() + .frame(width: metrics.size.width / 10 * 3) + Text(DataLocalizer.localize(path: "APP.GENERAL.SIDE")) + .leftAligned() + .frame(width: metrics.size.width / 10 * 2) + Text(DataLocalizer.localize(path: "APP.GENERAL.TYPE")) + .leftAligned() + .frame(width: metrics.size.width / 10 * 2) + Text(DataLocalizer.localize(path: "APP.GENERAL.AMOUNT")) + .frame(width: metrics.size.width / 10 * 3) + .rightAligned() } - .padding() - - DividerModel() - .createView(parentStyle: style) - - GeometryReader { metrics in - VStack(spacing: 8) { - HStack { - Text(DataLocalizer.localize(path: "APP.GENERAL.ACTION")) - .leftAligned() - .frame(width: metrics.size.width / 10 * 3) - Text(DataLocalizer.localize(path: "APP.GENERAL.SIDE")) - .leftAligned() - .frame(width: metrics.size.width / 10 * 2) - Text(DataLocalizer.localize(path: "APP.GENERAL.TYPE")) - .leftAligned() - .frame(width: metrics.size.width / 10 * 2) - Text(DataLocalizer.localize(path: "APP.GENERAL.AMOUNT")) - .frame(width: metrics.size.width / 10 * 3) - .rightAligned() - } - ForEach(self.items, id: \.id ) { item in - HStack { - Group { - switch item.action { - case .fill(let side, let market): - HStack { - side?.createView(parentStyle: style.themeFont(fontSize: .smaller)) - TokenTextViewModel(symbol: market) - .createView(parentStyle: style.themeFont(fontSize: .smallest)) - } - case .string(let value): - Text(value) - .themeColor(foreground: .textSecondary) - case .none: - Text("-") - } + ForEach(self.items, id: \.id ) { item in + HStack { + Group { + switch item.action { + case .fill(let side, let market): + HStack { + side?.createView(parentStyle: parentStyle.themeFont(fontSize: .smaller)) + TokenTextViewModel(symbol: market) + .createView(parentStyle: parentStyle.themeFont(fontSize: .smallest)) } - .themeFont(fontSize: .smaller) + case .string(let value): + Text(value) + .themeColor(foreground: .textSecondary) + case .none: + Text("-") + } + } + .themeFont(fontSize: .smaller) + .leftAligned() + .frame(width: metrics.size.width / 10 * 3) + + item.side?.createView(parentStyle: parentStyle + .themeFont(fontSize: .smaller) + .themeColor(foreground: .textTertiary)) + .leftAligned() + .frame(width: metrics.size.width / 10 * 2) + + if let type = item.type { + switch type { + case .token(let token): + token.createView(parentStyle: parentStyle.themeFont(fontSize: .smallest)) .leftAligned() - .frame(width: metrics.size.width / 10 * 3) - - item.side?.createView(parentStyle: style + .frame(width: metrics.size.width / 10 * 2) + case .string(let value): + Text(value) .themeFont(fontSize: .smaller) - .themeColor(foreground: .textTertiary)) .leftAligned() .frame(width: metrics.size.width / 10 * 2) - - if let type = item.type { - switch type { - case .token(let token): - token.createView(parentStyle: style.themeFont(fontSize: .smallest)) - .leftAligned() - .frame(width: metrics.size.width / 10 * 2) - case .string(let value): - Text(value) - .themeFont(fontSize: .smaller) - .leftAligned() - .frame(width: metrics.size.width / 10 * 2) - } - } - - Text(item.amount ?? "-") - .themeFont(fontSize: .smaller) - .frame(width: metrics.size.width / 10 * 3) - .rightAligned() } } + + Text(item.amount ?? "-") + .themeFont(fontSize: .smaller) + .frame(width: metrics.size.width / 10 * 3) + .rightAligned() } } - .frame(maxWidth: .infinity) - .padding() - .themeFont(fontSize: .smaller) - .themeColor(foreground: .textTertiary) - } - .frame(maxWidth: .infinity) - .frame(minHeight: 210) - .themeColor(background: .layer3) - .cornerRadius(12, corners: .allCorners) - .onTapGesture { [weak self] in - self?.tapAction?() } - ) + } + .frame(maxWidth: .infinity) + .themeFont(fontSize: .smaller) + .themeColor(foreground: .textTertiary) } + .frame(maxWidth: .infinity) + .frame(minHeight: 210) + .themeColor(background: .layer3) + .cornerRadius(12, corners: .allCorners) + .wrappedInAnyView() } } diff --git a/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxProfileRewardsViewModel.swift b/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxProfileRewardsViewModel.swift new file mode 100644 index 000000000..7e696b646 --- /dev/null +++ b/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxProfileRewardsViewModel.swift @@ -0,0 +1,87 @@ +// +// dydxProfileRewardsViewModel.swift +// dydxUI +// +// Created by Rui Huang on 9/18/23. +// Copyright © 2023 dYdX Trading Inc. All rights reserved. +// + +import SwiftUI +import PlatformUI +import Utilities + +public class dydxProfileRewardsViewModel: dydxTitledCardViewModel { + @Published public var last7DaysRewardsAmount: String? + @Published public var allTimeRewardsAmount: String? + + public init() { + super.init(title: DataLocalizer.shared?.localize(path: "APP.GENERAL.TRADING_REWARDS", params: nil) ?? "") + } + + override func createContent(parentStyle: ThemeStyle = ThemeStyle.defaultStyle, styleKey: String? = nil) -> AnyView? { + HStack(spacing: 0) { + VStack(alignment: .leading, spacing: 10) { + titleValueStack(title: DataLocalizer.shared?.localize(path: "APP.PROFILES_PAGE.REWARDS_LAST_7_DAYS", params: nil) ?? "", value: last7DaysRewardsAmount) + titleValueStack(title: DataLocalizer.shared?.localize(path: "APP.PROFILES_PAGE.REWARDS_ALL_TIME", params: nil) ?? "", value: allTimeRewardsAmount) + } + Spacer() + } + .wrappedInAnyView() + } + + private func titleValueStack(title: String, value: String?) -> some View { + VStack(alignment: .leading, spacing: 4) { + Text(title) + .themeColor(foreground: .textTertiary) + .themeFont(fontType: .text, fontSize: .smaller) + HStack(spacing: 6) { + Text(value ?? "-") + .themeColor(foreground: .textSecondary) + .themeFont(fontType: .number, fontSize: .medium) + PlatformIconViewModel(type: .asset(name: "icon_dydx", bundle: .dydxView), clip: .noClip, size: .init(width: 24, height: 24), templateColor: nil) + .createView() + } + } + + } + + public static var previewValue: dydxProfileRewardsViewModel { + let vm = dydxProfileRewardsViewModel() + vm.last7DaysRewardsAmount = "20.00" + vm.allTimeRewardsAmount = "30.00" + return vm + } + +} + +#if DEBUG +struct dydxProfileRewardsViewModel_Previews_Dark: PreviewProvider { + @StateObject static var themeSettings = ThemeSettings.shared + + static var previews: some View { + ThemeSettings.applyDarkTheme() + ThemeSettings.applyStyles() + return dydxProfileRewardsViewModel.previewValue + .createView() + .themeColor(background: .layer0) + .environmentObject(themeSettings) + // .edgesIgnoringSafeArea(.bottom) + .previewLayout(.sizeThatFits) + } +} + +struct dydxProfileRewardsViewModel_Previews_Light: PreviewProvider { + @StateObject static var themeSettings = ThemeSettings.shared + + static var previews: some View { + ThemeSettings.applyLightTheme() + ThemeSettings.applyStyles() + return dydxProfileRewardsViewModel.previewValue + .createView() + .themeColor(background: .layer0) + .environmentObject(themeSettings) + // .edgesIgnoringSafeArea(.bottom) + .previewLayout(.sizeThatFits) + } +} +#endif diff --git a/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxTitledCardView.swift b/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxTitledCardView.swift new file mode 100644 index 000000000..96b2430a7 --- /dev/null +++ b/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxTitledCardView.swift @@ -0,0 +1,90 @@ +// +// dydxTitledCardView.swift +// dydxViews +// +// Created by Michael Maguire on 12/1/23. +// + +import SwiftUI +import PlatformUI +import Utilities + +public class dydxTitledCardViewModel: PlatformViewModel { + + public let title: String + @Published public var tapAction: (() -> Void)? + + public init(title: String) { + self.title = title + super.init() + } + + fileprivate static var previewValue: dydxTitledCardViewModel { + let vm = dydxTitledCardViewModel(title: "TEST") + return vm + } + + func createContent(parentStyle: ThemeStyle = ThemeStyle.defaultStyle, styleKey: String? = nil) -> AnyView? { + PlatformView.nilView?.wrappedInAnyView() + } + + 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) } + + let view = VStack(spacing: 0) { + HStack { + Text(self.title) + .themeFont(fontSize: .small) + Spacer() + PlatformIconViewModel(type: .system(name: "chevron.right"), + size: CGSize(width: 10, height: 10), + templateColor: .textSecondary) + .createView(parentStyle: style) + } + .padding() + + DividerModel() + .createView(parentStyle: style) + self.createContent(parentStyle: style) + .padding(.vertical, 10) + .padding(.horizontal, 18) + } + .themeColor(background: .layer3) + .cornerRadius(12, corners: .allCorners) + .onTapGesture { [weak self] in + self?.tapAction?() + } + + return AnyView(view) + } + } +} + +#if DEBUG +struct dydxTitledCardViewModel_Previews_Dark: PreviewProvider { + @StateObject static var themeSettings = ThemeSettings.shared + + static var previews: some View { + ThemeSettings.applyDarkTheme() + ThemeSettings.applyStyles() + return dydxTitledCardViewModel.previewValue + .createView() + // .edgesIgnoringSafeArea(.bottom) + .previewLayout(.sizeThatFits) + } +} + +struct dydxTitledCardViewModel_Previews_Light: PreviewProvider { + @StateObject static var themeSettings = ThemeSettings.shared + + static var previews: some View { + ThemeSettings.applyLightTheme() + ThemeSettings.applyStyles() + return dydxTitledCardViewModel.previewValue + .createView() + // .edgesIgnoringSafeArea(.bottom) + .previewLayout(.sizeThatFits) + } +} +#endif diff --git a/dydx/dydxViews/dydxViews/_v4/Profile/dydxProfileView.swift b/dydx/dydxViews/dydxViews/_v4/Profile/dydxProfileView.swift index 3b01e98c3..816be4672 100644 --- a/dydx/dydxViews/dydxViews/_v4/Profile/dydxProfileView.swift +++ b/dydx/dydxViews/dydxViews/_v4/Profile/dydxProfileView.swift @@ -16,6 +16,7 @@ public class dydxProfileViewModel: PlatformViewModel { @Published public var settingsHelp = dydxSettingsHelpRowViewModel() @Published public var history: dydxProfileHistoryViewModel? = dydxProfileHistoryViewModel() @Published public var fees: dydxProfileFeesViewModel? = dydxProfileFeesViewModel() + @Published public var balances: dydxProfileBalancesViewModel? = dydxProfileBalancesViewModel() @Published public var rewards: dydxProfileRewardsViewModel? = dydxProfileRewardsViewModel() public init() { } @@ -41,20 +42,19 @@ public class dydxProfileViewModel: PlatformViewModel { .createView(parentStyle: style) .padding(.top, 8) - self.rewards? + self.balances? .createView(parentStyle: style) - self.history? - .createView(parentStyle: style) - - HStack { + HStack(spacing: 14) { self.fees? .createView(parentStyle: style) - .frame(maxWidth: .infinity) - - Text("") - .frame(maxWidth: .infinity) + //TODO, comment in when abacus is ready +// self.rewards? +// .createView(parentStyle: style) } + + self.history? + .createView(parentStyle: style) Spacer(minLength: 100) }