diff --git a/PlatformUI/PlatformUI/DesignSystem/Theme/ThemeViewModifiers.swift b/PlatformUI/PlatformUI/DesignSystem/Theme/ThemeViewModifiers.swift index cc87aa241..d556e3748 100644 --- a/PlatformUI/PlatformUI/DesignSystem/Theme/ThemeViewModifiers.swift +++ b/PlatformUI/PlatformUI/DesignSystem/Theme/ThemeViewModifiers.swift @@ -17,7 +17,7 @@ public extension View { } func themeColor(background: ThemeColor.SemanticColor) -> some View { - modifier(SemanticColorModifier(layerColor: background)) + modifier(BackgroundColorModifier(layerColor: background)) } func themeGradient(background: ThemeColor.SemanticColor, gradientColor: Color) -> some View { @@ -31,7 +31,7 @@ public extension Text { } } -struct TextColorModifier: ViewModifier { +private struct TextColorModifier: ViewModifier { @EnvironmentObject var themeSettings: ThemeSettings let textColor: ThemeColor.SemanticColor @@ -42,7 +42,7 @@ struct TextColorModifier: ViewModifier { } } -struct SemanticColorModifier: ViewModifier { +private struct BackgroundColorModifier: ViewModifier { @EnvironmentObject var themeSettings: ThemeSettings let layerColor: ThemeColor.SemanticColor @@ -53,7 +53,7 @@ struct SemanticColorModifier: ViewModifier { } } -struct GradientColorModifier: ViewModifier { +private struct GradientColorModifier: ViewModifier { @EnvironmentObject var themeSettings: ThemeSettings let layerColor: ThemeColor.SemanticColor @@ -268,8 +268,43 @@ public extension View { func border(borderWidth: CGFloat = 1, cornerRadius: CGFloat = 0, borderColor: Color? = ThemeColor.SemanticColor.layer5.color) -> some View { modifier(BorderModifier(cornerRadius: cornerRadius, borderWidth: borderWidth, borderColor: borderColor)) } + + func borderAndClip(style: BorderAndClipStyle, borderColor: ThemeColor.SemanticColor, lineWidth: CGFloat) -> some View { + modifier(BorderAndClipModifier(style: style, borderColor: borderColor, lineWidth: lineWidth)) + } +} + +/// The clip shape/style +public enum BorderAndClipStyle { + /// A rectangular shape with rounded corners with specified corner radius, aligned inside the frame of the view containing it. + case cornerRadius(CGFloat) + /// A capsule shape is equivalent to a rounded rectangle where the corner radius is chosen as half the length of the rectangle’s smallest edge. + case capsule +} + +private struct BorderAndClipModifier: ViewModifier { + let style: BorderAndClipStyle + let borderColor: ThemeColor.SemanticColor + let lineWidth: CGFloat + + func body(content: Content) -> some View { + switch style { + case .cornerRadius(let cornerRadius): + content + .clipShape(RoundedRectangle(cornerSize: .init(width: cornerRadius, height: cornerRadius))) + .overlay(RoundedRectangle(cornerRadius: cornerRadius) + .strokeBorder(borderColor.color, lineWidth: lineWidth)) + + case .capsule: + content + .clipShape(Capsule()) + .overlay(Capsule() + .strokeBorder(borderColor.color, lineWidth: lineWidth)) + } + } } + private struct BorderModifier: ViewModifier { var cornerRadius: CGFloat = .infinity var borderWidth: CGFloat = 1 diff --git a/dydx/dydxPresenters/dydxPresenters.xcodeproj/project.pbxproj b/dydx/dydxPresenters/dydxPresenters.xcodeproj/project.pbxproj index 440c61eac..d4af7aebc 100644 --- a/dydx/dydxPresenters/dydxPresenters.xcodeproj/project.pbxproj +++ b/dydx/dydxPresenters/dydxPresenters.xcodeproj/project.pbxproj @@ -77,7 +77,6 @@ 02860A9F29C15E760079E644 /* dydxOnboardScanViewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02860A9329C15E760079E644 /* dydxOnboardScanViewBuilder.swift */; }; 028AC6A42A5E564B00FE0891 /* dydxTransferAlertsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 028AC6A32A5E564B00FE0891 /* dydxTransferAlertsProvider.swift */; }; 028DB3402A05893D0090BE58 /* dydxProfileHeaderViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 028DB33F2A05893D0090BE58 /* dydxProfileHeaderViewPresenter.swift */; }; - 028DB3562A05BF630090BE58 /* dydxAddressDetailsViewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 028DB3552A05BF630090BE58 /* dydxAddressDetailsViewBuilder.swift */; }; 028FB3EC2AD642B30013136C /* dydxTokenConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 028FB3EB2AD642B30013136C /* dydxTokenConstants.swift */; }; 0295392329FB256E009026E3 /* dydxThemeViewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0295392229FB256E009026E3 /* dydxThemeViewBuilder.swift */; }; 0295392729FB28B7009026E3 /* settings_theme.json in Resources */ = {isa = PBXBuildFile; fileRef = 0295392629FB28B7009026E3 /* settings_theme.json */; }; @@ -131,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 */; }; + 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 */; }; 6448800B2AA248340068DD87 /* dydxAlertsWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64487FFE2AA248340068DD87 /* dydxAlertsWorker.swift */; }; @@ -415,7 +415,6 @@ 02860A9329C15E760079E644 /* dydxOnboardScanViewBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = dydxOnboardScanViewBuilder.swift; sourceTree = ""; }; 028AC6A32A5E564B00FE0891 /* dydxTransferAlertsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxTransferAlertsProvider.swift; sourceTree = ""; }; 028DB33F2A05893D0090BE58 /* dydxProfileHeaderViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxProfileHeaderViewPresenter.swift; sourceTree = ""; }; - 028DB3552A05BF630090BE58 /* dydxAddressDetailsViewBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxAddressDetailsViewBuilder.swift; sourceTree = ""; }; 028FB3EB2AD642B30013136C /* dydxTokenConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxTokenConstants.swift; sourceTree = ""; }; 0295392229FB256E009026E3 /* dydxThemeViewBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxThemeViewBuilder.swift; sourceTree = ""; }; 0295392629FB28B7009026E3 /* settings_theme.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = settings_theme.json; sourceTree = ""; }; @@ -469,6 +468,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 = ""; }; + 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 = ""; }; 645299E22AE86FB1000810E6 /* dydxUpdateViewPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = dydxUpdateViewPresenter.swift; sourceTree = ""; }; @@ -852,7 +852,6 @@ 023848C32A9E6BCD00B1A673 /* SystemStatus */, 2741E3712A689702000FA190 /* DirectionColorPreference */, 02F958152A1BDEEF00828F9A /* KeyExport */, - 028DB34D2A05BE650090BE58 /* AddressDetails */, 02E90C4C29D62702004E2311 /* FeatureFlags */, 02FAFA4E29D4E079001A0903 /* Debug */, 027E1EEA29CA27B00098666F /* Settings */, @@ -873,6 +872,7 @@ 028DB33F2A05893D0090BE58 /* dydxProfileHeaderViewPresenter.swift */, 02F95A8D2A1D6AAD00828F9A /* dydxProfileHistoryViewPresenter.swift */, 02F6E71E2A8293270018F00C /* dydxProfileFeesViewPresenter.swift */, + 27C027522AFD761300E92CCB /* dydxSettingsHelpRowViewPresenter.swift */, ); path = Components; sourceTree = ""; @@ -1009,14 +1009,6 @@ path = Scan; sourceTree = ""; }; - 028DB34D2A05BE650090BE58 /* AddressDetails */ = { - isa = PBXGroup; - children = ( - 028DB3552A05BF630090BE58 /* dydxAddressDetailsViewBuilder.swift */, - ); - path = AddressDetails; - sourceTree = ""; - }; 0295391529FB254C009026E3 /* Theme */ = { isa = PBXGroup; children = ( @@ -1755,10 +1747,10 @@ 0230376F28C11BE600412B72 /* dydxMarketsViewBuilder.swift in Sources */, 270BA8F32A6F278F009212EA /* dydxDebugThemeViewerBuilder.swift in Sources */, 02669B952AD87A9D00A756AA /* dydxGlobalWorkers.swift in Sources */, - 028DB3562A05BF630090BE58 /* dydxAddressDetailsViewBuilder.swift in Sources */, 027CB28729EEFF910069781A /* dydxTransferStatusViewBuilder.swift in Sources */, 0257C78E2A00485500F6160B /* SparklineDataPoint.swift in Sources */, 028DB3402A05893D0090BE58 /* dydxProfileHeaderViewPresenter.swift in Sources */, + 27C027532AFD761300E92CCB /* dydxSettingsHelpRowViewPresenter.swift in Sources */, 02EF485629F732C600C97746 /* dydxFavoriteStore.swift in Sources */, 0208627C28F4DAC000C9D3A0 /* dydxMarketInfoPagingViewPresenter.swift in Sources */, 0238FECB2970D681002E1C1A /* SharedAccountPresenter.swift in Sources */, diff --git a/dydx/dydxPresenters/dydxPresenters/_Features/routing_swiftui.json b/dydx/dydxPresenters/dydxPresenters/_Features/routing_swiftui.json index 9d57d5602..e8053c750 100644 --- a/dydx/dydxPresenters/dydxPresenters/_Features/routing_swiftui.json +++ b/dydx/dydxPresenters/dydxPresenters/_Features/routing_swiftui.json @@ -152,10 +152,6 @@ "/my-profile":{ "destination":"dydxPresenters.dydxProfileViewBuilder" }, - "/my-profile/address":{ - "destination":"dydxPresenters.dydxAddressDetailsViewBuilder", - "presentation":"push" - }, "/my-profile/keyexport":{ "destination":"dydxPresenters.dydxKeyExportViewBuilder", "presentation":"prompt" diff --git a/dydx/dydxPresenters/dydxPresenters/_v4/Profile/AddressDetails/dydxAddressDetailsViewBuilder.swift b/dydx/dydxPresenters/dydxPresenters/_v4/Profile/AddressDetails/dydxAddressDetailsViewBuilder.swift deleted file mode 100644 index e7c19527d..000000000 --- a/dydx/dydxPresenters/dydxPresenters/_v4/Profile/AddressDetails/dydxAddressDetailsViewBuilder.swift +++ /dev/null @@ -1,89 +0,0 @@ -// -// dydxAddressDetailsViewBuilder.swift -// dydxPresenters -// -// Created by Rui Huang on 5/5/23. -// - -import Utilities -import dydxViews -import PlatformParticles -import RoutingKit -import ParticlesKit -import PlatformUI -import Abacus -import dydxStateManager -import Cartera - -public class dydxAddressDetailsViewBuilder: NSObject, ObjectBuilderProtocol { - public func build() -> T? { - let presenter = dydxAddressDetailsViewPresenter() - let view = presenter.viewModel?.createView() ?? PlatformViewModel().createView() - return dydxAddressDetailsViewController(presenter: presenter, view: view, configuration: .default) as? T - } -} - -private class dydxAddressDetailsViewController: HostingViewController { - override public func arrive(to request: RoutingRequest?, animated: Bool) -> Bool { - if request?.path == "/my-profile/address" { - return true - } - return false - } -} - -private protocol dydxAddressDetailsViewPresenterProtocol: HostedViewPresenterProtocol { - var viewModel: dydxAddressDetailsViewModel? { get } -} - -private class dydxAddressDetailsViewPresenter: HostedViewPresenter, dydxAddressDetailsViewPresenterProtocol { - override init() { - super.init() - - viewModel = dydxAddressDetailsViewModel() - if let chainLogo = AbacusStateManager.shared.environment?.chainLogo { - viewModel?.dydxChainLogoUrl = URL(string: chainLogo) - } - } - - override func start() { - super.start() - - AbacusStateManager.shared.state.walletState - .sink { [weak self] walletState in - self?.viewModel?.dydxAddress = walletState.currentWallet?.cosmoAddress - self?.viewModel?.sourceAddress = walletState.currentWallet?.ethereumAddress - - self?.viewModel?.sourceWalletImageUrl = walletState.currentWallet?.imageUrl - - self?.viewModel?.copyAddressAction = { - guard let cosmoAddress = walletState.currentWallet?.cosmoAddress else { - return - } - let pasteboard = UIPasteboard.general - pasteboard.string = cosmoAddress - - ErrorInfo.shared?.info(title: nil, - message: DataLocalizer.localize(path: "APP.V4.DYDX_ADDRESS_COPIED"), - type: .success, - error: nil, time: 3) - } - - self?.viewModel?.etherscanAction = { - guard let ethereumAddress = walletState.currentWallet?.ethereumAddress else { - return - } - - let urlString = "https://etherscan.io/address/\(ethereumAddress)" - if let url = URL(string: urlString), URLHandler.shared?.canOpenURL(url) ?? false { - URLHandler.shared?.open(url, completionHandler: nil) - } - } - - self?.viewModel?.keyExportAction = { - Router.shared?.navigate(to: RoutingRequest(url: "/my-profile/keyexport"), animated: true, completion: nil) - } - } - .store(in: &subscriptions) - } -} diff --git a/dydx/dydxPresenters/dydxPresenters/_v4/Profile/Components/dydxProfileButtonsViewPresenter.swift b/dydx/dydxPresenters/dydxPresenters/_v4/Profile/Components/dydxProfileButtonsViewPresenter.swift index b1fee8da4..d1184a8b3 100644 --- a/dydx/dydxPresenters/dydxPresenters/_v4/Profile/Components/dydxProfileButtonsViewPresenter.swift +++ b/dydx/dydxPresenters/dydxPresenters/_v4/Profile/Components/dydxProfileButtonsViewPresenter.swift @@ -23,29 +23,16 @@ class dydxProfileButtonsViewPresenter: HostedViewPresenter 0 { - Router.shared?.navigate(to: RoutingRequest(path: "/wallets"), animated: true, completion: nil) - } else { - Router.shared?.navigate(to: RoutingRequest(path: "/onboard/wallets"), animated: true, completion: nil) - } - } - .store(in: &self.subscriptions) + viewModel.transferAction = { + Router.shared?.navigate(to: RoutingRequest(path: "/transfer", params: ["section": TransferSection.transferOut.rawValue]), animated: true, completion: nil) } viewModel.signOutAction = { [weak self] in @@ -76,11 +63,5 @@ class dydxProfileButtonsViewPresenter: HostedViewPresenter 0 { + Router.shared?.navigate(to: RoutingRequest(path: "/wallets"), animated: true, completion: nil) + } else { + Router.shared?.navigate(to: RoutingRequest(path: "/onboard/wallets"), animated: true, completion: nil) + } + } + .store(in: &self.subscriptions) } } @@ -34,6 +47,24 @@ class dydxProfileHeaderViewPresenter: HostedViewPresenter, dydxSettingsHelpRowViewPresenterProtocol { + init(viewModel: dydxSettingsHelpRowViewModel) { + super.init() + + self.viewModel = viewModel + + viewModel.settingsAction = { + Router.shared?.navigate(to: RoutingRequest(path: "/settings"), animated: true, completion: nil) + } + + viewModel.helpAction = { + Router.shared?.navigate(to: RoutingRequest(path: "/help"), animated: true, completion: nil) + } + } +} diff --git a/dydx/dydxPresenters/dydxPresenters/_v4/Profile/dydxProfileViewBuilder.swift b/dydx/dydxPresenters/dydxPresenters/_v4/Profile/dydxProfileViewBuilder.swift index d1d522398..b8b76f6c3 100644 --- a/dydx/dydxPresenters/dydxPresenters/_v4/Profile/dydxProfileViewBuilder.swift +++ b/dydx/dydxPresenters/dydxPresenters/_v4/Profile/dydxProfileViewBuilder.swift @@ -35,6 +35,7 @@ private protocol dydxProfileViewPresenterProtocol: HostedViewPresenterProtocol { private class dydxProfileViewPresenter: HostedViewPresenter, dydxProfileViewPresenterProtocol { private let buttonsPresenter: dydxProfileButtonsViewPresenter + private let settingsHelpRowPresenter: dydxSettingsHelpRowViewPresenter private let headerPresenter: dydxProfileHeaderViewPresenter private let historyPresenter: dydxProfileHistoryViewPresenter private let feesPresenter: dydxProfileFeesViewPresenter @@ -42,6 +43,7 @@ private class dydxProfileViewPresenter: HostedViewPresenter Bool { let size = parser.asDecimal(transferInput.size?.size)?.doubleValue ?? 0 let usdcSize = parser.asDecimal(transferInput.size?.usdcSize)?.doubleValue ?? 0 diff --git a/dydx/dydxPresenters/dydxPresenters/_v4/Transfer/dydxTransferViewBuilder.swift b/dydx/dydxPresenters/dydxPresenters/_v4/Transfer/dydxTransferViewBuilder.swift index becee073a..cf314074c 100644 --- a/dydx/dydxPresenters/dydxPresenters/_v4/Transfer/dydxTransferViewBuilder.swift +++ b/dydx/dydxPresenters/dydxPresenters/_v4/Transfer/dydxTransferViewBuilder.swift @@ -38,7 +38,7 @@ private class dydxTransferViewController: HostingViewController { } } + viewModel.openInEtherscanTapped = { + let ethereumAddress = wallet.ethereumAddress + let urlString = "https://etherscan.io/address/\(ethereumAddress)" + if let url = URL(string: urlString), URLHandler.shared?.canOpenURL(url) ?? false { + URLHandler.shared?.open(url, completionHandler: nil) + } + } + + viewModel.exportSecretPhraseTapped = { + Router.shared?.navigate(to: RoutingRequest(url: "/my-profile/keyexport"), animated: true, completion: nil) + } + viewModel.walletImageUrl = wallet.imageUrl // TODO: diff --git a/dydx/dydxStateManager/dydxStateManager/AbacusStateManager.swift b/dydx/dydxStateManager/dydxStateManager/AbacusStateManager.swift index 3aec0e971..3ad55278b 100644 --- a/dydx/dydxStateManager/dydxStateManager/AbacusStateManager.swift +++ b/dydx/dydxStateManager/dydxStateManager/AbacusStateManager.swift @@ -14,7 +14,10 @@ import dydxFormatter public final class AbacusStateManager: NSObject { public static let shared = AbacusStateManager() - public let deploymentUri = dydxStringFeatureFlag.deployment_url.string ?? (CredientialConfig.shared.key(for: "webAppUrl"))! + public let deploymentUri = { + let url = dydxStringFeatureFlag.deployment_url.string ?? (CredientialConfig.shared.key(for: "webAppUrl"))! + return url.last == "/" ? url : url + "/" + }() public var isMainNet: Bool { asyncStateManager.environment?.isMainNet ?? false diff --git a/dydx/dydxViews/dydxViews.xcodeproj/project.pbxproj b/dydx/dydxViews/dydxViews.xcodeproj/project.pbxproj index 032ed7068..e76cdfe4a 100644 --- a/dydx/dydxViews/dydxViews.xcodeproj/project.pbxproj +++ b/dydx/dydxViews/dydxViews.xcodeproj/project.pbxproj @@ -105,7 +105,6 @@ 0284201629AD71B600C0E7CC /* Enums.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0284201529AD71B600C0E7CC /* Enums.swift */; }; 02860A9129C15E670079E644 /* dydxOnboardScanView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02860A8429C15E670079E644 /* dydxOnboardScanView.swift */; }; 028DB33E2A0589270090BE58 /* dydxProfileHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 028DB33D2A0589270090BE58 /* dydxProfileHeaderView.swift */; }; - 028DB3542A05BF530090BE58 /* dydxAddressDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 028DB3532A05BF530090BE58 /* dydxAddressDetailsView.swift */; }; 02934CE5290067F1005DB99C /* SideChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02934CE4290067F1005DB99C /* SideChange.swift */; }; 0297A0F72A6109E500619181 /* ProgressStepView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0297A0F62A6109E500619181 /* ProgressStepView.swift */; }; 029CBE6C28F5F3F600259C1D /* dydxMarketFundingChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 029CBE6B28F5F3F600259C1D /* dydxMarketFundingChartView.swift */; }; @@ -161,6 +160,7 @@ 277442982AD88C4900C91357 /* Satoshi-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 277442962AD88C4900C91357 /* Satoshi-Regular.otf */; }; 27A799B92A66EC2D007C3D04 /* ThemeClassicDark.json in Resources */ = {isa = PBXBuildFile; fileRef = 27A799B82A66EC2D007C3D04 /* ThemeClassicDark.json */; }; 27AAA9862ACE34C800AF3C56 /* SwiftMessages+Banner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27AAA9852ACE34C800AF3C56 /* SwiftMessages+Banner.swift */; }; + 27C027452AFD734800E92CCB /* dydxSettingsHelpRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27C027442AFD734800E92CCB /* dydxSettingsHelpRowView.swift */; }; 27ED340C2AD47CB100C159F5 /* dydxBannerErrorAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27ED340B2AD47CB100C159F5 /* dydxBannerErrorAlert.swift */; }; 27ED365C2AD735A800C159F5 /* dydxSecurityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27ED365B2AD735A800C159F5 /* dydxSecurityView.swift */; }; 645299F22AE86FC3000810E6 /* dydxUpdateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 645299F12AE86FC3000810E6 /* dydxUpdateView.swift */; }; @@ -439,7 +439,6 @@ 0284201529AD71B600C0E7CC /* Enums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Enums.swift; sourceTree = ""; }; 02860A8429C15E670079E644 /* dydxOnboardScanView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = dydxOnboardScanView.swift; sourceTree = ""; }; 028DB33D2A0589270090BE58 /* dydxProfileHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxProfileHeaderView.swift; sourceTree = ""; }; - 028DB3532A05BF530090BE58 /* dydxAddressDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxAddressDetailsView.swift; sourceTree = ""; }; 02934CE4290067F1005DB99C /* SideChange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideChange.swift; sourceTree = ""; }; 0297A0F62A6109E500619181 /* ProgressStepView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressStepView.swift; sourceTree = ""; }; 029CBE6B28F5F3F600259C1D /* dydxMarketFundingChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxMarketFundingChartView.swift; sourceTree = ""; }; @@ -495,6 +494,7 @@ 277442962AD88C4900C91357 /* Satoshi-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Satoshi-Regular.otf"; sourceTree = ""; }; 27A799B82A66EC2D007C3D04 /* ThemeClassicDark.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ThemeClassicDark.json; sourceTree = ""; }; 27AAA9852ACE34C800AF3C56 /* SwiftMessages+Banner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SwiftMessages+Banner.swift"; sourceTree = ""; }; + 27C027442AFD734800E92CCB /* dydxSettingsHelpRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSettingsHelpRowView.swift; sourceTree = ""; }; 27ED340B2AD47CB100C159F5 /* dydxBannerErrorAlert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = dydxBannerErrorAlert.swift; sourceTree = ""; }; 27ED365B2AD735A800C159F5 /* dydxSecurityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSecurityView.swift; sourceTree = ""; }; 4FF528D5C65F7B79E5D5812D /* Pods-iOS-dydxViews.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-dydxViews.debug.xcconfig"; path = "Target Support Files/Pods-iOS-dydxViews/Pods-iOS-dydxViews.debug.xcconfig"; sourceTree = ""; }; @@ -1002,7 +1002,6 @@ 024FEB622ACB75C00087A55E /* FeesStructure */, 270BA8C12A6F145B009212EA /* Settings */, 02F958062A1BDED300828F9A /* KeyExport */, - 028DB3502A05BEA30090BE58 /* AddressDetails */, 0253177C29C126C800D6CC9B /* TradingNetwork */, 0258BA2429929D050098E1BE /* Components */, 0258BA1C2992949D0098E1BE /* dydxProfileView.swift */, @@ -1018,6 +1017,7 @@ 028DB33D2A0589270090BE58 /* dydxProfileHeaderView.swift */, 02F95A8B2A1D6A9200828F9A /* dydxProfileHistoryView.swift */, 02F6E7102A8292FC0018F00C /* dydxProfileFeesView.swift */, + 27C027442AFD734800E92CCB /* dydxSettingsHelpRowView.swift */, ); path = Components; sourceTree = ""; @@ -1128,14 +1128,6 @@ path = Components; sourceTree = ""; }; - 028DB3502A05BEA30090BE58 /* AddressDetails */ = { - isa = PBXGroup; - children = ( - 028DB3532A05BF530090BE58 /* dydxAddressDetailsView.swift */, - ); - path = AddressDetails; - sourceTree = ""; - }; 029CBE5E28F5F3C800259C1D /* Funding */ = { isa = PBXGroup; children = ( @@ -1811,6 +1803,7 @@ 270BA8CF2A6F1470009212EA /* dydxDebugThemeViewerView.swift in Sources */, 0273A1382ACCC49C001B89F5 /* dydxHistoryView.swift in Sources */, 0246DE5E28B984C700A7FF1F /* Wallets2View.swift in Sources */, + 27C027452AFD734800E92CCB /* dydxSettingsHelpRowView.swift in Sources */, 0253155129BFA62700D6CC9B /* dydxOnboardScanInstructionsView.swift in Sources */, 024B7B5C28B7F90100F7C386 /* dydxViewBundleClass.swift in Sources */, 02A9B60C29005A3F00AE1516 /* AmountChange.swift in Sources */, @@ -1890,7 +1883,6 @@ 02678F5B2965DEAD00EE346B /* dydxPortfolioSectionsView.swift in Sources */, 64A4DB762966276B008D8E20 /* dydxTradeInputTriggerPriceView.swift in Sources */, 0238FEBF2970CBEF002E1C1A /* dydxMarketAccountView.swift in Sources */, - 028DB3542A05BF530090BE58 /* dydxAddressDetailsView.swift in Sources */, 02E5996128FF46B500F62F28 /* MarginUsageChange.swift in Sources */, 6453A7BB299C26DE0041A0C4 /* dydxClosePositionInputView.swift in Sources */, 02D1379D28EE452200B46941 /* UIView+SwiftUI.swift in Sources */, diff --git a/dydx/dydxViews/dydxViews/Media.xcassets/icon_copy.imageset/Contents.json b/dydx/dydxViews/dydxViews/Media.xcassets/icon_copy.imageset/Contents.json new file mode 100644 index 000000000..b1a870b84 --- /dev/null +++ b/dydx/dydxViews/dydxViews/Media.xcassets/icon_copy.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "icon_copy.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/dydx/dydxViews/dydxViews/Media.xcassets/icon_copy.imageset/icon_copy.pdf b/dydx/dydxViews/dydxViews/Media.xcassets/icon_copy.imageset/icon_copy.pdf new file mode 100644 index 000000000..268e1002f Binary files /dev/null and b/dydx/dydxViews/dydxViews/Media.xcassets/icon_copy.imageset/icon_copy.pdf differ diff --git a/dydx/dydxViews/dydxViews/Media.xcassets/icon_wallet_connect.imageset/Contents.json b/dydx/dydxViews/dydxViews/Media.xcassets/icon_wallet_connect.imageset/Contents.json index a208b71f3..8d141198b 100644 --- a/dydx/dydxViews/dydxViews/Media.xcassets/icon_wallet_connect.imageset/Contents.json +++ b/dydx/dydxViews/dydxViews/Media.xcassets/icon_wallet_connect.imageset/Contents.json @@ -1,16 +1,12 @@ { "images" : [ { - "filename" : "Polygon 2.pdf", + "filename" : "icon_wallet_connect.pdf", "idiom" : "universal" } ], "info" : { "author" : "xcode", "version" : 1 - }, - "properties" : { - "preserves-vector-representation" : true, - "template-rendering-intent" : "template" } } diff --git a/dydx/dydxViews/dydxViews/Media.xcassets/icon_wallet_connect.imageset/Polygon 2.pdf b/dydx/dydxViews/dydxViews/Media.xcassets/icon_wallet_connect.imageset/Polygon 2.pdf deleted file mode 100644 index 6430d0d04..000000000 Binary files a/dydx/dydxViews/dydxViews/Media.xcassets/icon_wallet_connect.imageset/Polygon 2.pdf and /dev/null differ diff --git a/dydx/dydxViews/dydxViews/Media.xcassets/icon_wallet_connect.imageset/icon_wallet_connect.pdf b/dydx/dydxViews/dydxViews/Media.xcassets/icon_wallet_connect.imageset/icon_wallet_connect.pdf new file mode 100644 index 000000000..ced82b440 Binary files /dev/null and b/dydx/dydxViews/dydxViews/Media.xcassets/icon_wallet_connect.imageset/icon_wallet_connect.pdf differ diff --git a/dydx/dydxViews/dydxViews/_v4/Profile/AddressDetails/dydxAddressDetailsView.swift b/dydx/dydxViews/dydxViews/_v4/Profile/AddressDetails/dydxAddressDetailsView.swift deleted file mode 100644 index c667abe11..000000000 --- a/dydx/dydxViews/dydxViews/_v4/Profile/AddressDetails/dydxAddressDetailsView.swift +++ /dev/null @@ -1,184 +0,0 @@ -// -// dydxAddressDetailsView.swift -// dydxUI -// -// Created by Rui Huang on 5/5/23. -// Copyright © 2023 dYdX Trading Inc. All rights reserved. -// - -import SwiftUI -import PlatformUI -import Utilities -import RoutingKit - -public class dydxAddressDetailsViewModel: PlatformViewModel { - @Published public var text: String? - @Published public var dydxChainLogoUrl: URL? - @Published public var dydxAddress: String? - @Published public var sourceAddress: String? - @Published public var sourceWalletImageUrl: URL? - @Published public var copyAddressAction: (() -> Void)? - @Published public var etherscanAction: (() -> Void)? - @Published public var keyExportAction: (() -> Void)? - - public init() { } - - public static var previewValue: dydxAddressDetailsViewModel { - let vm = dydxAddressDetailsViewModel() - vm.text = "Test String" - 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(alignment: .leading, spacing: 12) { - self.createHeader(parentStyle: style) - .frame(height: 48) - .padding([.leading, .trailing]) - - self.createDydxAddressView(parentStyle: style) - - /* - TODO: source address should be different than dydx address. This if condition should evntually be removed before production launch. - When this comment was made, the "sync with desktop" flow would not bring over the source address from web app. This will have to change - before this if can be removed. - */ - if self.sourceAddress != self.dydxAddress { - self.createSourceAddressView(parentStyle: style) - } - - DividerModel().createView(parentStyle: style) - - self.createEtherscanView(parentStyle: style) - - DividerModel().createView(parentStyle: style) - - self.createKeyExportView(parentStyle: style) - - DividerModel().createView(parentStyle: style) - - Spacer() - } - .themeColor(background: .layer2) - .animation(.default) - ) - } - } - - private func createHeader(parentStyle: ThemeStyle) -> some View { - HStack { - PlatformButtonViewModel(content: PlatformIconViewModel(type: .system(name: "chevron.left"), size: CGSize(width: 16, height: 16)), type: .iconType) { - Router.shared?.navigate(to: RoutingRequest(url: "/action/dismiss"), animated: true, completion: nil) - } - .createView(parentStyle: parentStyle) - - Text(DataLocalizer.localize(path: "APP.GENERAL.PROFILE", params: nil)) - .themeFont(fontType: .bold, fontSize: .largest) - - Spacer() - } - } - - private func createDydxAddressView(parentStyle: ThemeStyle) -> some View { - let icon = PlatformIconViewModel(type: .url(url: dydxChainLogoUrl), - size: CGSize(width: 64, height: 64)) - let main = VStack(alignment: .leading, spacing: 4) { - Text(DataLocalizer.localize(path: "APP.V4.DYDX_ADDRESS")) - .themeFont(fontSize: .small) - - Text(self.dydxAddress ?? "-") - .themeColor(foreground: .textPrimary) - .lineLimit(1) - .truncationMode(.middle) - } - let copyText = Text(DataLocalizer.localize(path: "APP.GENERAL.COPY")) - .themeFont(fontSize: .small) - let trailing = PlatformButtonViewModel(content: copyText.wrappedViewModel, type: .pill, state: .secondary) { [weak self] in - self?.copyAddressAction?() - } - return PlatformTableViewCellViewModel(leading: icon, - main: main.wrappedViewModel, - trailing: trailing) - .createView(parentStyle: parentStyle) - } - - private func createSourceAddressView(parentStyle: ThemeStyle) -> some View { - let icon: PlatformViewModel - if let sourceWalletImageUrl = sourceWalletImageUrl { - icon = PlatformIconViewModel(type: .url(url: sourceWalletImageUrl), - clip: .circle(background: .layer4, spacing: 0), - size: CGSize(width: 64, height: 64)) - } else { - icon = PlatformIconViewModel(type: .system(name: "folder"), - clip: .circle(background: .layer4, spacing: 32), - size: CGSize(width: 64, height: 64)) - } - let main = VStack(alignment: .leading, spacing: 4) { - Text(DataLocalizer.localize(path: "APP.V4.SOURCE_ADDRESS")) - .themeFont(fontSize: .small) - - Text(self.sourceAddress ?? "-") - .themeColor(foreground: .textPrimary) - .lineLimit(1) - .truncationMode(.middle) - } - let trailing = PlatformView.nilViewModel - return PlatformTableViewCellViewModel(leading: icon, - main: main.wrappedViewModel, - trailing: trailing) - .createView(parentStyle: parentStyle) - } - - private func createEtherscanView(parentStyle: ThemeStyle) -> some View { - let main = Text(DataLocalizer.localize(path: "APP.HEADER.OPEN_IN_ETHERSCAN")) - let trailing = PlatformIconViewModel(type: .system(name: "chevron.right"), size: CGSize(width: 16, height: 16)) - return PlatformTableViewCellViewModel(main: main.wrappedViewModel, - trailing: trailing) - .createView(parentStyle: parentStyle) - .onTapGesture { [weak self] in - self?.etherscanAction?() - } - } - - private func createKeyExportView(parentStyle: ThemeStyle) -> some View { - let main = Text(DataLocalizer.localize(path: "APP.MNEMONIC_EXPORT.EXPORT_SECRET_PHRASE")) - let trailing = PlatformIconViewModel(type: .system(name: "chevron.right"), size: CGSize(width: 16, height: 16)) - return PlatformTableViewCellViewModel(main: main.wrappedViewModel, - trailing: trailing) - .createView(parentStyle: parentStyle) - .onTapGesture { [weak self] in - self?.keyExportAction?() - } - } -} - -#if DEBUG -struct dydxAddressDetailsView_Previews_Dark: PreviewProvider { - @StateObject static var themeSettings = ThemeSettings.shared - - static var previews: some View { - ThemeSettings.applyDarkTheme() - ThemeSettings.applyStyles() - return dydxAddressDetailsViewModel.previewValue - .createView() - // .edgesIgnoringSafeArea(.bottom) - .previewLayout(.sizeThatFits) - } -} - -struct dydxAddressDetailsView_Previews_Light: PreviewProvider { - @StateObject static var themeSettings = ThemeSettings.shared - - static var previews: some View { - ThemeSettings.applyLightTheme() - ThemeSettings.applyStyles() - return dydxAddressDetailsViewModel.previewValue - .createView() - // .edgesIgnoringSafeArea(.bottom) - .previewLayout(.sizeThatFits) - } -} -#endif diff --git a/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxProfileButtonsView.swift b/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxProfileButtonsView.swift index d0057282c..58b0cd0f9 100644 --- a/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxProfileButtonsView.swift +++ b/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxProfileButtonsView.swift @@ -9,15 +9,13 @@ import SwiftUI import PlatformUI import Utilities -import SDWebImageSwiftUI public class dydxProfileButtonsViewModel: PlatformViewModel { - @Published public var settingsAction: (() -> Void)? - @Published public var helpAction: (() -> Void)? - @Published public var walletAction: (() -> Void)? + @Published public var depositAction: (() -> Void)? + @Published public var withdrawAction: (() -> Void)? + @Published public var transferAction: (() -> Void)? @Published public var signOutAction: (() -> Void)? @Published public var onboardAction: (() -> Void)? - @Published public var walletImageUrl: URL? @Published public var onboarded: Bool = false public init() { } @@ -34,37 +32,32 @@ public class dydxProfileButtonsViewModel: PlatformViewModel { return AnyView( HStack { self.createButton(parentStyle: style, - imageName: "icon_settings", - title: DataLocalizer.localize(path: "APP.EMAIL_NOTIFICATIONS.SETTINGS"), - action: self.settingsAction) + imageName: "icon_transfer_deposit", + title: DataLocalizer.localize(path: "APP.GENERAL.DEPOSIT"), + action: self.depositAction) self.createButton(parentStyle: style, - imageName: "icon_info", - title: DataLocalizer.localize(path: "APP.HEADER.HELP"), - action: self.helpAction) + imageName: "icon_transfer_withdrawal", + title: DataLocalizer.localize(path: "APP.GENERAL.WITHDRAW"), + action: self.withdrawAction) - if let walletImageUrl = self.walletImageUrl { - self.createButton(parentStyle: style, - imageUrl: walletImageUrl, - title: DataLocalizer.localize(path: "APP.GENERAL.WALLETS"), - action: self.walletAction) - } else { - self.createButton(parentStyle: style, - imageName: "icon_wallet", - title: DataLocalizer.localize(path: "APP.GENERAL.WALLETS"), - action: self.walletAction) - } + self.createButton(parentStyle: style, + imageName: "icon_transfer_dydx", + title: DataLocalizer.localize(path: "APP.GENERAL.TRANSFER"), + action: self.transferAction) if self.onboarded { self.createButton(parentStyle: style, imageName: "settings_signout", title: DataLocalizer.localize(path: "APP.GENERAL.SIGN_OUT"), - applyTemplateColor: false, + templateColor: nil, action: self.signOutAction) } else { self.createButton(parentStyle: style, imageName: "icon_wallet_connect", title: DataLocalizer.localize(path: "APP.GENERAL.CONNECT"), + backgroundColor: .colorPurple, + templateColor: .colorWhite, action: self.onboardAction) } } @@ -72,21 +65,11 @@ public class dydxProfileButtonsViewModel: PlatformViewModel { } } - private func createButton(parentStyle: ThemeStyle, imageName: String, title: String, applyTemplateColor: Bool = true, action: (() -> Void)?) -> some View { + private func createButton(parentStyle: ThemeStyle, imageName: String, title: String, styleKey: String? = nil, backgroundColor: ThemeColor.SemanticColor = .layer3, templateColor: ThemeColor.SemanticColor? = .textSecondary, action: (() -> Void)?) -> some View { let icon = PlatformIconViewModel(type: .asset(name: imageName, bundle: Bundle.dydxView), - clip: .circle(background: .layer3, spacing: 24, borderColor: .layer6), + clip: .circle(background: backgroundColor, spacing: 24, borderColor: .layer6), size: CGSize(width: 48, height: 48), - templateColor: applyTemplateColor ? .textSecondary : nil) - return createButton(parentStyle: parentStyle, icon: icon, title: title, action: action) - } - - private func createButton(parentStyle: ThemeStyle, imageUrl: URL, title: String, action: (() -> Void)?) -> some View { - let image = PlatformIconViewModel(type: .url(url: imageUrl), - clip: .circle(background: .layer3, spacing: 0), - size: CGSize(width: 32, height: 32)) - let icon = PlatformIconViewModel(type: .any(viewModel: image), - clip: .circle(background: .layer3, spacing: 16, borderColor: .layer6), - size: CGSize(width: 48, height: 48)) + templateColor: templateColor) return createButton(parentStyle: parentStyle, icon: icon, title: title, action: action) } diff --git a/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxProfileHeaderView.swift b/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxProfileHeaderView.swift index f7d13dd92..43a0d7c11 100644 --- a/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxProfileHeaderView.swift +++ b/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxProfileHeaderView.swift @@ -13,7 +13,10 @@ import Utilities public class dydxProfileHeaderViewModel: PlatformViewModel { @Published public var dydxChainLogoUrl: URL? @Published public var dydxAddress: String? - @Published public var onTapAction: (() -> Void)? + @Published public var sourceAddress: String? + @Published public var copyAction: (() -> Void)? + @Published public var openInEtherscanAction: (() -> Void)? + @Published public var manageWalletAction: (() -> Void)? public init() { } @@ -24,32 +27,106 @@ public class dydxProfileHeaderViewModel: PlatformViewModel { } public override func createView(parentStyle: ThemeStyle = ThemeStyle.defaultStyle, styleKey: String? = nil) -> PlatformView { - PlatformView(viewModel: self, parentStyle: parentStyle, styleKey: styleKey) { [weak self] style in + PlatformView(viewModel: self, parentStyle: parentStyle, styleKey: styleKey) { [weak self] _ in guard let self = self else { return AnyView(PlatformView.nilView) } - let icon = PlatformIconViewModel(type: self.dydxAddress != nil ? .url(url: self.dydxChainLogoUrl) : .asset(name: "hedgie_placeholder", bundle: Bundle.dydxView), + let chainIcon = PlatformIconViewModel(type: self.dydxAddress != nil ? .url(url: self.dydxChainLogoUrl) : .asset(name: "hedgie_placeholder", bundle: Bundle.dydxView), size: CGSize(width: 64, height: 64)) - let main = VStack(alignment: .leading, spacing: 4) { + let dropDownIcon = PlatformIconViewModel(type: .asset(name: "icon_dropdown", bundle: Bundle.dydxView), + clip: .noClip, + size: .init(width: 14, height: 8), + templateColor: .textTertiary) + let manageWalletButton = HStack(spacing: 9) { + Text(DataLocalizer.localize(path: "APP.GENERAL.MANAGE_WALLET")) + .themeFont(fontSize: .small) + .themeColor(foreground: .textTertiary) + dropDownIcon.createView(parentStyle: parentStyle) + } + .onTapGesture { [weak self] in + self?.manageWalletAction?() + } + + let addressInfoView = VStack(alignment: .leading, spacing: 4) { Text(DataLocalizer.localize(path: "APP.V4.DYDX_ADDRESS")) .themeFont(fontSize: .small) + .themeColor(foreground: .textTertiary) Text(self.dydxAddress ?? "-") .themeColor(foreground: .textPrimary) .lineLimit(1) .truncationMode(.middle) } - let trailing = self.dydxAddress != nil ? PlatformIconViewModel(type: .system(name: "chevron.right"), size: CGSize(width: 16, height: 16)) : PlatformView.nilViewModel - return AnyView( - PlatformTableViewCellViewModel(leading: icon, - main: main.wrappedViewModel, - trailing: trailing) - .createView(parentStyle: style) - .onTapGesture { [weak self] in - if self?.dydxAddress != nil { - self?.onTapAction?() + + let iconDim: CGFloat = 40 + let iconSpacing: CGFloat = 18 + + let copyButton: Button? = copyAction == nil ? nil : Button { [weak self] in + if let copyAction = self?.copyAction { + copyAction() + ErrorInfo.shared?.info(title: nil, + message: DataLocalizer.localize(path: "APP.V4.DYDX_ADDRESS_COPIED"), + type: .info, + error: nil, time: 3) + } + } label: { + PlatformIconViewModel(type: .asset(name: "icon_copy", bundle: .dydxView), + clip: .circle(background: .layer4, spacing: iconSpacing, borderColor: .layer6), + size: CGSize(width: iconDim, height: iconDim), + templateColor: .textSecondary) + .createView() + } + + let openInEtherscanAction: Button? = openInEtherscanAction == nil ? nil : Button { [weak self] in + self?.openInEtherscanAction?() + } label: { + PlatformIconViewModel(type: .asset(name: "icon_external_link", bundle: .dydxView), + clip: .circle(background: .layer4, spacing: iconSpacing, borderColor: .layer6), + size: CGSize(width: iconDim, height: iconDim), + templateColor: .textSecondary) + .createView() + } + + let content = VStack(spacing: 0) { + VStack(spacing: 16) { + HStack(alignment: .top) { + chainIcon + .createView(parentStyle: parentStyle) + Spacer() + if self.dydxAddress?.isEmpty == false { + manageWalletButton + } } + HStack(spacing: 0) { + addressInfoView + Spacer(minLength: 12) + HStack(spacing: 12) { + copyButton + openInEtherscanAction + } + } + } + .padding(.all, 20) + .themeColor(background: .layer4) + .cornerRadius(12, corners: .allCorners) + if let sourceAddress = self.sourceAddress { + HStack(spacing: 0) { + Text(DataLocalizer.shared?.localize(path: "APP.GENERAL.SOURCE_ADDRESS", params: nil) ?? "") + .themeFont(fontType: .text, fontSize: .small) + .themeColor(foreground: .textTertiary) + Spacer(minLength: 64) + Text(sourceAddress) + .truncationMode(.middle) + .lineLimit(1) + .themeFont(fontType: .text, fontSize: .small) + .themeColor(foreground: .textSecondary) + } + .padding(.horizontal, 20) + .padding(.vertical, 12) } - ) + } + .themeColor(background: .layer1) + .cornerRadius(12, corners: .allCorners) + return AnyView(content) } } } diff --git a/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxSettingsHelpRowView.swift b/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxSettingsHelpRowView.swift new file mode 100644 index 000000000..cfe537298 --- /dev/null +++ b/dydx/dydxViews/dydxViews/_v4/Profile/Components/dydxSettingsHelpRowView.swift @@ -0,0 +1,94 @@ +// +// dydxSettingsHelpRowView.swift +// dydxViews +// +// Created by Michael Maguire on 11/9/23. +// + +import SwiftUI +import PlatformUI +import Utilities + +public class dydxSettingsHelpRowViewModel: PlatformViewModel { + @Published public var settingsAction: (() -> Void)? + @Published public var helpAction: (() -> Void)? + + public init() { } + + public static var previewValue: dydxSettingsHelpRowViewModel { + let vm = dydxSettingsHelpRowViewModel() + return vm + } + + public override func createView(parentStyle: ThemeStyle = ThemeStyle.defaultStyle, styleKey: String? = nil) -> PlatformUI.PlatformView { + PlatformView(viewModel: self, parentStyle: parentStyle, styleKey: styleKey) { [weak self] style in + guard let self = self else { return AnyView(PlatformView.nilView) } + + return AnyView( + HStack(spacing: 16) { + self.createButton(parentStyle: style, + imageName: "icon_settings", + title: DataLocalizer.localize(path: "APP.EMAIL_NOTIFICATIONS.SETTINGS"), + action: self.settingsAction) + + self.createButton(parentStyle: style, + imageName: "icon_tutorial", + title: DataLocalizer.localize(path: "APP.HEADER.HELP"), + action: self.helpAction) + } + ) + } + } + + private func createButton(parentStyle: ThemeStyle, imageName: String, title: String, action: (() -> Void)?) -> some View { + HStack(spacing: 8) { + PlatformIconViewModel(type: .asset(name: imageName, bundle: Bundle.dydxView), + clip: .noClip, + size: CGSize(width: 24, height: 24), + templateColor: .textTertiary) + .createView(parentStyle: parentStyle) + + Text(title) + .themeFont(fontSize: .medium) + .themeColor(foreground: .textPrimary) + .lineLimit(1) + Spacer() + } + .padding(.horizontal, 16) + .padding(.vertical, 22) + .themeColor(background: .layer4) + .cornerRadius(12, corners: .allCorners) + .frame(maxWidth: .infinity) + .onTapGesture { + action?() + } + } +} + +#if DEBUG +struct dydxSettingsHelpRowView_Previews_Dark: PreviewProvider { + @StateObject static var themeSettings = ThemeSettings.shared + + static var previews: some View { + ThemeSettings.applyDarkTheme() + ThemeSettings.applyStyles() + return dydxSettingsHelpRowViewModel.previewValue + .createView() + // .edgesIgnoringSafeArea(.bottom) + .previewLayout(.sizeThatFits) + } +} + +struct dydxSettingsHelpRowView_Previews_Light: PreviewProvider { + @StateObject static var themeSettings = ThemeSettings.shared + + static var previews: some View { + ThemeSettings.applyLightTheme() + ThemeSettings.applyStyles() + return dydxSettingsHelpRowViewModel.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 c726327ed..3b01e98c3 100644 --- a/dydx/dydxViews/dydxViews/_v4/Profile/dydxProfileView.swift +++ b/dydx/dydxViews/dydxViews/_v4/Profile/dydxProfileView.swift @@ -13,6 +13,7 @@ import Utilities public class dydxProfileViewModel: PlatformViewModel { @Published public var header = dydxProfileHeaderViewModel() @Published public var buttons = dydxProfileButtonsViewModel() + @Published public var settingsHelp = dydxSettingsHelpRowViewModel() @Published public var history: dydxProfileHistoryViewModel? = dydxProfileHistoryViewModel() @Published public var fees: dydxProfileFeesViewModel? = dydxProfileFeesViewModel() @Published public var rewards: dydxProfileRewardsViewModel? = dydxProfileRewardsViewModel() @@ -36,10 +37,13 @@ public class dydxProfileViewModel: PlatformViewModel { self.buttons .createView(parentStyle: style) - self.rewards? + self.settingsHelp .createView(parentStyle: style) .padding(.top, 8) + self.rewards? + .createView(parentStyle: style) + self.history? .createView(parentStyle: style) diff --git a/dydx/dydxViews/dydxViews/_v4/Wallet/WalletConnectionView.swift b/dydx/dydxViews/dydxViews/_v4/Wallet/WalletConnectionView.swift index 000d4ea84..48ce66863 100644 --- a/dydx/dydxViews/dydxViews/_v4/Wallet/WalletConnectionView.swift +++ b/dydx/dydxViews/dydxViews/_v4/Wallet/WalletConnectionView.swift @@ -18,6 +18,8 @@ public class WalletConnectionViewModel: PlatformViewModel { @Published public var walletImageUrl: URL? @Published public var pnl24hPercent: SignedAmountViewModel? @Published public var onTap: (() -> Void)? + @Published public var openInEtherscanTapped: (() -> Void)? + @Published public var exportSecretPhraseTapped: (() -> Void)? public init() {} @@ -35,45 +37,76 @@ public class WalletConnectionViewModel: PlatformViewModel { PlatformView(viewModel: self, parentStyle: parentStyle, styleKey: styleKey) { [weak self] style in AnyView( Group { - let icon = PlatformIconViewModel(type: .url(url: self?.walletImageUrl), clip: .defaultCircle) + let buttonBorderWidth = 1.5 + let buttonContentVerticalPadding: CGFloat = 8 + let buttonContentHorizontalPadding: CGFloat = 12 + + let icon = self?.walletImageUrl == nil ? nil : PlatformIconViewModel(type: .url(url: self?.walletImageUrl), clip: .defaultCircle) .createView(parentStyle: style) let status = PlatformIconViewModel(type: .asset(name: "status_filled", bundle: Bundle.dydxView), - size: CGSize(width: 8, height: 8), - templateColor: self?.templateColor ?? .textTertiary) + size: CGSize(width: 8, height: 8), + templateColor: self?.templateColor ?? .textTertiary) .createView(parentStyle: style) - let main = - Text(self?.walletAddress ?? "") + let addressText = Text(self?.walletAddress ?? "") + .lineLimit(1) + .truncationMode(.middle) + .themeFont(fontSize: .medium) + .themeColor(foreground: .textPrimary) + + let blockExplorerButton = Button(action: { + self?.openInEtherscanTapped?() + }, label: { + HStack(spacing: 4) { + Text(DataLocalizer.shared?.localize(path: "APP.GENERAL.BLOCK_EXPLORER", params: nil) ?? "") + .lineLimit(1) + .themeFont(fontSize: .medium) + .themeColor(foreground: .textTertiary) + PlatformIconViewModel(type: .asset(name: "icon_external_link", + bundle: .dydxView), + clip: .noClip, + size: .init(width: 20, height: 20), + templateColor: .textTertiary) + .createView(parentStyle: style) + } + .fixedSize() + .padding(.horizontal, buttonContentHorizontalPadding) + .padding(.vertical, buttonContentVerticalPadding) + .themeColor(background: .layer3) + }) + .borderAndClip(style: .capsule, borderColor: .layer6, lineWidth: buttonBorderWidth) + + let exportPhraseButton = Button(action: { + self?.exportSecretPhraseTapped?() + }, label: { + Text(DataLocalizer.shared?.localize(path: "APP.MNEMONIC_EXPORT.EXPORT_PHRASE", params: nil) ?? "") .lineLimit(1) - .truncationMode(.middle) .themeFont(fontSize: .medium) - .themeColor(foreground: .textPrimary) - - let trailing = - VStack(alignment: .trailing, spacing: 2) { - Text(self?.equity ?? "") - .themeFont(fontType: .number, fontSize: .small) - if let pnl24hPercent = self?.pnl24hPercent { - HStack { - Text(DataLocalizer.localize(path: "APP.GENERAL.TIME_STRINGS.24H", params: nil)) - .themeFont(fontSize: .smaller) - pnl24hPercent.createView(parentStyle: style - .themeColor(foreground: .textTertiary) - .themeFont(fontType: .number, fontSize: .smaller)) - } + .themeColor(foreground: .colorRed) + .padding(.horizontal, buttonContentHorizontalPadding) + .padding(.vertical, buttonContentVerticalPadding) + }) + .themeColor(background: .colorFadedRed) + .borderAndClip(style: .capsule, borderColor: .borderDestructive, lineWidth: buttonBorderWidth) + + let main = VStack(alignment: .leading) { + addressText + if self?.selected == true { + HStack(spacing: 10) { + blockExplorerButton + exportPhraseButton } } - - Group { - PlatformTableViewCellViewModel(leading: status.wrappedViewModel, - logo: icon.wrappedViewModel, - main: main.wrappedViewModel, - trailing: trailing.wrappedViewModel) - .createView(parentStyle: style) } - .frame(width: UIScreen.main.bounds.width - 32, height: 64) - .themeColor(background: .layer5) - .cornerRadius(16) + .padding(.vertical, 16) + + PlatformTableViewCellViewModel(leading: status.wrappedViewModel, + logo: icon?.wrappedViewModel, + main: main.wrappedViewModel) + .createView(parentStyle: style) + .frame(width: UIScreen.main.bounds.width - 32) + .themeColor(background: self?.selected == true ? .layer1 : .layer3) + .borderAndClip(style: .cornerRadius(10), borderColor: .borderDefault, lineWidth: 1) .onTapGesture { self?.onTap?() } diff --git a/dydx/dydxViews/dydxViews/_v4/Wallet/Wallets2View.swift b/dydx/dydxViews/dydxViews/_v4/Wallet/Wallets2View.swift index 0fc5d155d..6a6353d72 100644 --- a/dydx/dydxViews/dydxViews/_v4/Wallet/Wallets2View.swift +++ b/dydx/dydxViews/dydxViews/_v4/Wallet/Wallets2View.swift @@ -29,7 +29,7 @@ public class Wallets2ViewModel: PlatformViewModel { guard let self = self else { return AnyView(PlatformView.nilView) } let view = VStack(alignment: .leading, spacing: 16) { - Text(DataLocalizer.localize(path: "APP.GENERAL.SWITCH_WALLET", params: nil)) + Text(DataLocalizer.localize(path: "APP.GENERAL.MANAGE_WALLET", params: nil)) .themeFont(fontType: .bold, fontSize: .largest) .padding(.top, 40)