From bcdd7d9f4c858eb22bb0454c8a16a6999f8a3886 Mon Sep 17 00:00:00 2001 From: Roman <51091564+jeanpierreroma@users.noreply.github.com> Date: Mon, 22 Jun 2026 21:09:23 +0300 Subject: [PATCH 1/5] feat(crowdnode): add balance reminder withdrawal flow --- DashWallet.xcodeproj/project.pbxproj | 51 +++++++ .../CrowdNode/CrowdNodeBalanceReminder.swift | 70 ++++++++++ .../CrowdNodeBalanceReminderBanner.swift | 63 +++++++++ .../CrowdNodeBalanceReminderSheet.swift | 106 +++++++++++++++ .../CrowdNodeWithdrawalRouter.swift | 104 ++++++++++++++ .../UI/Explore Dash/ExploreMenuScreen.swift | 17 ++- .../Sources/UI/Home/HomeViewController.swift | 128 +++++++++++++++++- 7 files changed, 531 insertions(+), 8 deletions(-) create mode 100644 DashWallet/Sources/Models/CrowdNode/CrowdNodeBalanceReminder.swift create mode 100644 DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderBanner.swift create mode 100644 DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderSheet.swift create mode 100644 DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeWithdrawalRouter.swift diff --git a/DashWallet.xcodeproj/project.pbxproj b/DashWallet.xcodeproj/project.pbxproj index 48d4c060e..cfacf480a 100644 --- a/DashWallet.xcodeproj/project.pbxproj +++ b/DashWallet.xcodeproj/project.pbxproj @@ -522,6 +522,7 @@ 514AF1C12FB5F02D00F9B54C /* MayaConvertViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514AF1BF2FB5F02D00F9B54C /* MayaConvertViewModel.swift */; }; 514BEA012FB5F02D00F9B54C /* MayaConvertAmount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514BEA002FB5F02D00F9B54C /* MayaConvertAmount.swift */; }; 514BEA022FB5F02D00F9B54C /* MayaConvertAmount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514BEA002FB5F02D00F9B54C /* MayaConvertAmount.swift */; }; + 514518ED2FE936FC00F9AD4C /* DashUIKit in Frameworks */ = {isa = PBXBuildFile; productRef = 514518EC2FE936FC00F9AD4C /* DashUIKit */; }; 5151C8C62F913BF100F0A604 /* Coinbase-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5151C8C22F913BF100F0A604 /* Coinbase-Info.plist */; }; 5151C8C72F913BF100F0A604 /* ZenLedger-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5151C8C52F913BF100F0A604 /* ZenLedger-Info.plist */; }; 5151C8C82F913BF100F0A604 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5151C8C32F913BF100F0A604 /* GoogleService-Info.plist */; }; @@ -1775,6 +1776,14 @@ CC0000202DUMMYID001234567 /* PiggyCardsTokenService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0000102DUMMYID001234567 /* PiggyCardsTokenService.swift */; }; D0D3F0F33D9F162622F0A6E5 /* DashBalanceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF95E0E0B636AFB810D62116 /* DashBalanceView.swift */; }; DA38F1C5CD32A52891D02D0E /* MayaConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7708BBFDD14AFF237FB72D71 /* MayaConstants.swift */; }; + CNR0000012FF100000000001 /* CrowdNodeBalanceReminder.swift in Sources */ = {isa = PBXBuildFile; fileRef = CNR0000072FF100000000001 /* CrowdNodeBalanceReminder.swift */; }; + CNR0000022FF100000000001 /* CrowdNodeBalanceReminder.swift in Sources */ = {isa = PBXBuildFile; fileRef = CNR0000072FF100000000001 /* CrowdNodeBalanceReminder.swift */; }; + CNR0000032FF100000000001 /* CrowdNodeBalanceReminderSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = CNR0000082FF100000000001 /* CrowdNodeBalanceReminderSheet.swift */; }; + CNR0000042FF100000000001 /* CrowdNodeBalanceReminderSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = CNR0000082FF100000000001 /* CrowdNodeBalanceReminderSheet.swift */; }; + CNR0000052FF100000000001 /* CrowdNodeBalanceReminderBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = CNR0000092FF100000000001 /* CrowdNodeBalanceReminderBanner.swift */; }; + CNR0000062FF100000000001 /* CrowdNodeBalanceReminderBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = CNR0000092FF100000000001 /* CrowdNodeBalanceReminderBanner.swift */; }; + CNR0000112FF100000000001 /* CrowdNodeWithdrawalRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CNR0000132FF100000000001 /* CrowdNodeWithdrawalRouter.swift */; }; + CNR0000122FF100000000001 /* CrowdNodeWithdrawalRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CNR0000132FF100000000001 /* CrowdNodeWithdrawalRouter.swift */; }; DE3A167A235B79D705C0A962 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; }; E5767AEAEF7C4921886E915A /* BuySellPortalScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B94B3697D7742BFA991B5CC /* BuySellPortalScreen.swift */; }; E88FE13A3079496C9A5EA8D4 /* MayaCoinIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20554F992205428BA790F6CF /* MayaCoinIconView.swift */; }; @@ -3399,6 +3408,10 @@ CC0000082DUMMYID001234567 /* PiggyCardsEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiggyCardsEndpoint.swift; sourceTree = ""; }; CC0000092DUMMYID001234567 /* PiggyCardsRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiggyCardsRepository.swift; sourceTree = ""; }; CC0000102DUMMYID001234567 /* PiggyCardsTokenService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiggyCardsTokenService.swift; sourceTree = ""; }; + CNR0000072FF100000000001 /* CrowdNodeBalanceReminder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdNodeBalanceReminder.swift; sourceTree = ""; }; + CNR0000082FF100000000001 /* CrowdNodeBalanceReminderSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdNodeBalanceReminderSheet.swift; sourceTree = ""; }; + CNR0000092FF100000000001 /* CrowdNodeBalanceReminderBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdNodeBalanceReminderBanner.swift; sourceTree = ""; }; + CNR0000132FF100000000001 /* CrowdNodeWithdrawalRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdNodeWithdrawalRouter.swift; sourceTree = ""; }; D53435DCAF024BC82E0247F3 /* ImportPrivateKeySheet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ImportPrivateKeySheet.swift; sourceTree = ""; }; D99130732DE8F2E95F635F6B /* MayaConvertCardRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MayaConvertCardRow.swift; sourceTree = ""; }; E2A832899A499C24C7A43E47 /* Pods-WatchApp Extension.testnet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WatchApp Extension.testnet.xcconfig"; path = "Target Support Files/Pods-WatchApp Extension/Pods-WatchApp Extension.testnet.xcconfig"; sourceTree = ""; }; @@ -3508,6 +3521,7 @@ 0FC75A8F28F03E22000E4858 /* libDashSync.a in Frameworks */, 2A5279BC23D994BC00F856D3 /* CoreNFC.framework in Frameworks */, FB3E9F60236125F600C09C5C /* BackgroundTasks.framework in Frameworks */, + 514518ED2FE936FC00F9AD4C /* DashUIKit in Frameworks */, 2AD1CE9922DE63FB00C99324 /* GameplayKit.framework in Frameworks */, FB4FA9C322505DD70060B017 /* AudioToolbox.framework in Frameworks */, 2AA08534237D6CF500797F95 /* CloudKit.framework in Frameworks */, @@ -3854,6 +3868,7 @@ 11BD738028E7356100A34022 /* CrowdNode.swift */, 11E47BAC28EB3A7D0097CFA0 /* CrowdNode+Constants.swift */, 111C3C51296D620D00788E18 /* CrowdNode+UserDefaults.swift */, + CNR0000072FF100000000001 /* CrowdNodeBalanceReminder.swift */, ); path = CrowdNode; sourceTree = ""; @@ -3863,6 +3878,7 @@ children = ( 47083B392989488D0010AF71 /* Tx Details */, 47083B3329893E260010AF71 /* Views */, + CNR0000102FF100000000001 /* BalanceReminder */, 110C679629227895006B580C /* Extensions */, 117ECC7C29742A30003D798E /* Online */, 1141E4C3291FDC3B00ACDA9E /* Getting Started */, @@ -8211,6 +8227,16 @@ path = "Sync View"; sourceTree = ""; }; + CNR0000102FF100000000001 /* BalanceReminder */ = { + isa = PBXGroup; + children = ( + CNR0000082FF100000000001 /* CrowdNodeBalanceReminderSheet.swift */, + CNR0000092FF100000000001 /* CrowdNodeBalanceReminderBanner.swift */, + CNR0000132FF100000000001 /* CrowdNodeWithdrawalRouter.swift */, + ); + path = BalanceReminder; + sourceTree = ""; + }; DD0000012DUMMYID001234567 /* PiggyCards */ = { isa = PBXGroup; children = ( @@ -8482,6 +8508,9 @@ uk, ); mainGroup = 75D5F3B5191EC270004AB296; + packageReferences = ( + 514518EB2FE936FC00F9AD4C /* XCLocalSwiftPackageReference "../Packages/DashUIKit" */, + ); productRefGroup = 75D5F3BF191EC270004AB296 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -9153,6 +9182,10 @@ 4751136C28D9A3DB00223B77 /* BuySellPortalViewController.swift in Sources */, AA00000128D9A3DB00223B77 /* BuySellPortalView.swift in Sources */, 8DF3D24EE3B247B79AE9CAB5 /* BuySellPortalScreen.swift in Sources */, + CNR0000012FF100000000001 /* CrowdNodeBalanceReminder.swift in Sources */, + CNR0000032FF100000000001 /* CrowdNodeBalanceReminderSheet.swift in Sources */, + CNR0000052FF100000000001 /* CrowdNodeBalanceReminderBanner.swift in Sources */, + CNR0000112FF100000000001 /* CrowdNodeWithdrawalRouter.swift in Sources */, 514AEA0F2FB31BD800F9B54C /* AddressFieldView.swift in Sources */, 2A7A7BD62348CB6600451078 /* SettingsScreen.swift in Sources */, 2A0C69DA2314727F001B8C90 /* UISpringTimingParameters+DWInit.m in Sources */, @@ -9905,6 +9938,10 @@ C9D2C6AF2A320AA000D15901 /* BuySellPortalViewController.swift in Sources */, AA00000228D9A3DB00223B77 /* BuySellPortalView.swift in Sources */, E5767AEAEF7C4921886E915A /* BuySellPortalScreen.swift in Sources */, + CNR0000022FF100000000001 /* CrowdNodeBalanceReminder.swift in Sources */, + CNR0000042FF100000000001 /* CrowdNodeBalanceReminderSheet.swift in Sources */, + CNR0000062FF100000000001 /* CrowdNodeBalanceReminderBanner.swift in Sources */, + CNR0000122FF100000000001 /* CrowdNodeWithdrawalRouter.swift in Sources */, C9D2C6B02A320AA000D15901 /* SettingsScreen.swift in Sources */, 751B61C52ADFFD0700D1C2EF /* IntegrationViewController+Uphold.swift in Sources */, C943B5022A40A54600AF23C5 /* DWDPGenericStatusItemView.m in Sources */, @@ -12952,6 +12989,20 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 514518EB2FE936FC00F9AD4C /* XCLocalSwiftPackageReference "../Packages/DashUIKit" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = ../Packages/DashUIKit; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 514518EC2FE936FC00F9AD4C /* DashUIKit */ = { + isa = XCSwiftPackageProductDependency; + productName = DashUIKit; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 75D5F3B6191EC270004AB296 /* Project object */; } diff --git a/DashWallet/Sources/Models/CrowdNode/CrowdNodeBalanceReminder.swift b/DashWallet/Sources/Models/CrowdNode/CrowdNodeBalanceReminder.swift new file mode 100644 index 000000000..a8a1469e2 --- /dev/null +++ b/DashWallet/Sources/Models/CrowdNode/CrowdNodeBalanceReminder.swift @@ -0,0 +1,70 @@ +// +// Created by OpenAI Codex +// Copyright © 2026 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Combine +import Foundation + +@MainActor +final class CrowdNodeBalanceReminder: ObservableObject { + static let shared = CrowdNodeBalanceReminder() + + @Published private(set) var hasBalance: Bool + @Published private(set) var balance: UInt64 + @Published private(set) var activeScreenReminderDismissed: Bool = false + + private let crowdNode: CrowdNode + private var cancellableBag = Set() + + var formattedBalance: String { + balance.formattedDashAmount + } + + var shouldShowOnActiveScreen: Bool { + hasBalance && !activeScreenReminderDismissed + } + + var shouldShowOnExplore: Bool { + hasBalance + } + + private init(crowdNode: CrowdNode = .shared) { + self.crowdNode = crowdNode + self.balance = crowdNode.balance + self.hasBalance = crowdNode.balance > 0 + + crowdNode.$balance + .receive(on: DispatchQueue.main) + .sink { [weak self] balance in + self?.update(balance: balance) + } + .store(in: &cancellableBag) + } + + func dismissActiveScreenReminder() { + // TODO(product): persist dismissal per account if this should survive app restarts. + activeScreenReminderDismissed = true + } + + private func update(balance: UInt64) { + self.balance = balance + hasBalance = balance > 0 + + if balance == 0 { + activeScreenReminderDismissed = false + } + } +} diff --git a/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderBanner.swift b/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderBanner.swift new file mode 100644 index 000000000..0d9eb6332 --- /dev/null +++ b/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderBanner.swift @@ -0,0 +1,63 @@ +// +// Created by OpenAI Codex +// Copyright © 2026 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import SwiftUI +import DashUIKit + +struct CrowdNodeBalanceReminderBanner: View { + var onWithdraw: () -> Void + + var body: some View { + HStack(alignment: .top, spacing: 10) { + Image(dash: .custom("warning_triangle", bundle: .dashUIKit)) + .resizable() + .scaledToFit() + .frame(width: 30, height: 30) + + VStack(alignment: .leading, spacing: 20) { + VStack(alignment: .leading, spacing: 1) { + Text(NSLocalizedString("You have a balance on CrowdNode", comment: "CrowdNode")) + .font(Font.dash.subheadMedium) + .foregroundColor(Color.dash.primaryText) + + Text(NSLocalizedString("These funds should be withdrawn from CrowdNode. You can transfer these funds to this wallet or via your online account on some other device.", comment: "CrowdNode")) + .font(Font.dash.subhead) + .foregroundColor(Color.dash.secondaryText) + .multilineTextAlignment(.leading) + } + + DashUIKit.DashButton( + text: NSLocalizedString("Withdraw funds", comment: "CrowdNode"), + size: .small, + style: .filledBlue, + action: onWithdraw + ) + } + .padding(.trailing, 20) + .padding(.top, 5) + } + .padding(16) + .background(Color.dash.gray300Alpha10) + .clipShape(.rect(cornerRadius: 20)) + } +} + +#Preview { + CrowdNodeBalanceReminderBanner(onWithdraw: {}) + .padding(20) + .background(Color.primaryBackground) +} diff --git a/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderSheet.swift b/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderSheet.swift new file mode 100644 index 000000000..b8278b6e7 --- /dev/null +++ b/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderSheet.swift @@ -0,0 +1,106 @@ +// +// Created by OpenAI Codex +// Copyright © 2026 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import SwiftUI +import DashUIKit + +struct CrowdNodeBalanceReminderSheet: View { + var onWithdraw: () -> Void + var onDismiss: () -> Void + + var body: some View { + VStack(alignment: .leading, spacing: 0) { + Image(dash: .custom("crowdnode.warning", bundle: .dashUIKit)) + .resizable() + .scaledToFit() + .frame(width: 90, height: 90) + .padding(.top, 20) + .padding(.bottom, 10) + .frame(maxWidth: .infinity, alignment: .center) + + + VStack(alignment: .leading, spacing: 6) { + Text(NSLocalizedString("You have a balance on CrowdNode", comment: "CrowdNode")) + .font(Font.dash.title1) + .foregroundStyle(Color.dash.primaryText) + .multilineTextAlignment(.leading) + + Text(NSLocalizedString("These funds should be withdrawn from CrowdNode. You can transfer these funds to this wallet or via your online account on some other device.", comment: "CrowdNode")) + .font(Font.dash.subhead) + .foregroundStyle(Color.dash.secondaryText) + .multilineTextAlignment(.leading) + } + .padding(.horizontal, 40 + 20) + .padding(.top, 20) + .padding(.bottom, 32) + + + VStack(alignment: .center, spacing: 16) { + DashUIKit.DashButton( + text: NSLocalizedString("Withdraw funds", comment: "CrowdNode"), + fillsWidth: true, + size: .large, + style: .filledBlue, + action: onWithdraw + ) + + DashUIKit.DashButton( + text: NSLocalizedString("Close", comment: "CrowdNode"), + fillsWidth: true, + size: .large, + style: .tintedGray, + action: onDismiss + ) + } + .padding(.horizontal, 60) + .padding(.vertical, 20) + } + } +} + +#Preview { + CrowdNodeBalanceReminderSheet( + onWithdraw: {}, + onDismiss: {} + ) + .background(Color.primaryBackground) +} + +#Preview { + Color.dash.primaryBackground + .ignoresSafeArea() + .sheet(isPresented: .constant(true)) { + // Qualify the type: the project also defines a `BottomSheet`, so use the lib's one. + // `fillsHeight: false` + `.selfSizingSheet()` snaps the sheet to its content height. + let sheet = DashUIKit.BottomSheet(showBackButton: .constant(false), fillsHeight: false) { + CrowdNodeBalanceReminderSheet( + onWithdraw: {}, + onDismiss: {} + ) + } + .selfSizingSheet() + + if #available(iOS 16.4, *) { + sheet + .presentationBackground(Color.dash.primaryBackground) // fills the bottom safe-area strip too + .presentationCornerRadius(32) + .presentationDragIndicator(.hidden) // hide native grabber — lib draws its own + } else { + sheet + } + } +} diff --git a/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeWithdrawalRouter.swift b/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeWithdrawalRouter.swift new file mode 100644 index 000000000..27f8137c7 --- /dev/null +++ b/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeWithdrawalRouter.swift @@ -0,0 +1,104 @@ +// +// Created by OpenAI Codex +// Copyright © 2026 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import UIKit + +@MainActor +enum CrowdNodeWithdrawalRouter { + /// Returns true when navigation was started. Returns false when the flow was blocked + /// and the user was shown an explanatory alert instead. + @discardableResult + static func openWithdrawal(from presenter: UIViewController) -> Bool { + guard SyncingActivityMonitor.shared.state == .syncDone else { + presentSyncingAlert(from: presenter) + return false + } + + CrowdNode.shared.restoreState() + let state = CrowdNode.shared.signUpState + + guard state == .finished || state == .linkedOnline else { + let rootViewController = CrowdNodeModelObjcWrapper.getRootVC() + presentInNavigationController(rootViewController, from: presenter) + return true + } + + guard CrowdNodeModel.shared.canWithdraw else { + presentMinimumBalanceError(from: presenter) + return false + } + + let portal = CrowdNodePortalController.controller() + let navigationController = BaseNavigationController(rootViewController: portal) + presenter.present(navigationController, animated: true) { + navigationController.pushViewController( + CrowdNodeTransferController.controller(mode: .withdraw), + animated: false + ) + } + return true + } + + private static func presentInNavigationController(_ rootViewController: UIViewController, from presenter: UIViewController) { + let navigationController = BaseNavigationController(rootViewController: rootViewController) + presenter.present(navigationController, animated: true) + } + + private static func presentSyncingAlert(from presenter: UIViewController) { + let title = NSLocalizedString("The chain is syncing…", comment: "") + let message = NSLocalizedString("Wait until the chain is fully synced, so we can review your transaction history. Visit CrowdNode website to log in or sign up.", comment: "") + let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) + + let websiteAction = UIAlertAction( + title: NSLocalizedString("Go to CrowdNode website", comment: ""), + style: .default + ) { _ in + UIApplication.shared.open(CrowdNodeObjcWrapper.crowdNodeWebsiteUrl(), options: [:], completionHandler: nil) + } + alert.addAction(websiteAction) + + let closeAction = UIAlertAction( + title: NSLocalizedString("Close", comment: ""), + style: .cancel + ) + alert.addAction(closeAction) + presenter.present(alert, animated: true) + } + + private static func presentMinimumBalanceError(from presenter: UIViewController) { + let controller = BasicInfoController() + controller.icon = "image.crowdnode.error" + controller.headerText = NSLocalizedString("You should have a positive balance on Dash Wallet", comment: "CrowdNode") + controller.descriptionText = String.localizedStringWithFormat( + NSLocalizedString("Deposit at least %@ Dash on your Dash Wallet to complete a withdrawal", comment: "CrowdNode"), + CrowdNode.minimumLeftoverBalance.formattedDashAmountWithoutCurrencySymbol + ) + controller.actionButtonText = CrowdNodeModel.shared.buyDashButtonText + + let navigationController = BaseNavigationController(rootViewController: controller) + controller.mainAction = { + Task { + if await CrowdNodeModel.shared.authenticate() { + let buySellController = BuySellPortalViewController.controller() + navigationController.pushViewController(buySellController, animated: true) + } + } + } + + presenter.present(navigationController, animated: true) + } +} diff --git a/DashWallet/Sources/UI/Explore Dash/ExploreMenuScreen.swift b/DashWallet/Sources/UI/Explore Dash/ExploreMenuScreen.swift index 78990e7c0..efbdf93f5 100644 --- a/DashWallet/Sources/UI/Explore Dash/ExploreMenuScreen.swift +++ b/DashWallet/Sources/UI/Explore Dash/ExploreMenuScreen.swift @@ -25,6 +25,7 @@ struct ExploreMenuScreen: View { private let onShowReceivePayment: () -> Void private let onShowGiftCard: (Data) -> Void + @ObservedObject private var balanceReminder = CrowdNodeBalanceReminder.shared @State private var showSyncingAlert = false private var isTestnet: Bool { @@ -60,10 +61,14 @@ struct ExploreMenuScreen: View { title: NSLocalizedString("Explore Dash", comment: ""), subtitle: NSLocalizedString("Find merchants that accept Dash, where to buy it and how to earn income with it.", comment: "") ) - .padding(.leading, 20) - .padding(.trailing, 60) - .padding(.top, 10) - .padding(.bottom, 20) + + if balanceReminder.shouldShowOnExplore { + CrowdNodeBalanceReminderBanner { + showCrowdNodeWithdrawal() + } + .padding(.horizontal, 20) + .padding(.bottom, 16) + } // Menu list VStack(spacing: 2) { @@ -189,6 +194,10 @@ struct ExploreMenuScreen: View { showSyncingAlert = true } } + + private func showCrowdNodeWithdrawal() { + CrowdNodeWithdrawalRouter.openWithdrawal(from: vc) + } } struct CrowdNodeAPYBadge: View { diff --git a/DashWallet/Sources/UI/Home/HomeViewController.swift b/DashWallet/Sources/UI/Home/HomeViewController.swift index eaf7cf718..ad04b8a83 100644 --- a/DashWallet/Sources/UI/Home/HomeViewController.swift +++ b/DashWallet/Sources/UI/Home/HomeViewController.swift @@ -26,6 +26,10 @@ protocol HomeViewControllerDelegate: AnyObject { class HomeViewController: DWBasePayViewController, NavigationBarDisplayable { private var cancellableBag = Set() + private var isSyncObserverRegistered = false + private var pendingCrowdNodeReminder = false + private var isCrowdNodeReminderRetryScheduled = false + private weak var crowdNodeBalanceReminderController: UIViewController? var model: DWHomeProtocol! var viewModel: HomeViewModel! private var homeView: HomeView! @@ -50,6 +54,9 @@ class HomeViewController: DWBasePayViewController, NavigationBarDisplayable { } deinit { + if isSyncObserverRegistered { + SyncingActivityMonitor.shared.remove(observer: self) + } print("☠️ \(String(describing: self))") } @@ -66,6 +73,7 @@ class HomeViewController: DWBasePayViewController, NavigationBarDisplayable { assert(model != nil) + registerSyncObserverIfNeeded() setupView() performJailbreakCheck() configureObservers() @@ -92,6 +100,7 @@ class HomeViewController: DWBasePayViewController, NavigationBarDisplayable { model.registerForPushNotifications() model.checkCrowdNodeState() + presentCrowdNodeBalanceReminderIfNeeded() } #if DASHPAY @@ -109,7 +118,6 @@ class HomeViewController: DWBasePayViewController, NavigationBarDisplayable { state.invitation = url state.chosenUsername = definedUsername invitationSetup = state - SyncingActivityMonitor.shared.add(observer: self) return } @@ -267,6 +275,107 @@ class HomeViewController: DWBasePayViewController, NavigationBarDisplayable { self?.viewModel.reclassifyTransactionShown(isShown: true) } .store(in: &cancellableBag) + + CrowdNodeBalanceReminder.shared.$hasBalance + .removeDuplicates() + .receive(on: DispatchQueue.main) + .sink { [weak self] hasBalance in + guard let self = self else { return } + + if hasBalance { + self.presentCrowdNodeBalanceReminderIfNeeded() + } else { + self.pendingCrowdNodeReminder = false + self.dismissCrowdNodeBalanceReminder(markDismissed: false, animated: true) + } + } + .store(in: &cancellableBag) + } + + private func registerSyncObserverIfNeeded() { + guard !isSyncObserverRegistered else { return } + + SyncingActivityMonitor.shared.add(observer: self) + isSyncObserverRegistered = true + } + + private func presentCrowdNodeBalanceReminderIfNeeded() { + guard isViewLoaded, view.window != nil else { return } + guard SyncingActivityMonitor.shared.state == .syncDone else { return } + guard CrowdNodeBalanceReminder.shared.shouldShowOnActiveScreen else { + pendingCrowdNodeReminder = false + return + } + guard crowdNodeBalanceReminderController == nil else { + pendingCrowdNodeReminder = false + return + } + guard presentedViewController == nil else { + pendingCrowdNodeReminder = true + scheduleCrowdNodeReminderRetryIfNeeded() + return + } + + let sheet = CrowdNodeBalanceReminderSheet( + onWithdraw: { [weak self] in + self?.openCrowdNodeWithdrawalFromReminder() + }, + onDismiss: { [weak self] in + self?.dismissCrowdNodeBalanceReminder(markDismissed: true, animated: true) + } + ) + .background(Color.primaryBackground) + + let hostingController = UIHostingController(rootView: sheet) + hostingController.modalPresentationStyle = .pageSheet + hostingController.presentationController?.delegate = self + + if let sheet = hostingController.sheetPresentationController { + sheet.detents = [.medium()] + sheet.preferredCornerRadius = 24 + sheet.prefersGrabberVisible = true + } + + pendingCrowdNodeReminder = false + crowdNodeBalanceReminderController = hostingController + present(hostingController, animated: true) + } + + private func dismissCrowdNodeBalanceReminder(markDismissed: Bool, animated: Bool, completion: (() -> Void)? = nil) { + pendingCrowdNodeReminder = false + + if markDismissed { + CrowdNodeBalanceReminder.shared.dismissActiveScreenReminder() + } + + guard let controller = crowdNodeBalanceReminderController else { + completion?() + return + } + + crowdNodeBalanceReminderController = nil + controller.dismiss(animated: animated, completion: completion) + } + + private func openCrowdNodeWithdrawalFromReminder() { + dismissCrowdNodeBalanceReminder(markDismissed: false, animated: true) { [weak self] in + guard let self = self else { return } + CrowdNodeWithdrawalRouter.openWithdrawal(from: self) + } + } + + private func scheduleCrowdNodeReminderRetryIfNeeded() { + guard pendingCrowdNodeReminder, !isCrowdNodeReminderRetryScheduled else { return } + + isCrowdNodeReminderRetryScheduled = true + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in + guard let self = self else { return } + + self.isCrowdNodeReminderRetryScheduled = false + guard self.pendingCrowdNodeReminder else { return } + + self.presentCrowdNodeBalanceReminderIfNeeded() + } } private func showTimeSkewDialog(diffSeconds: Int64, coinjoin: Bool) { @@ -382,14 +491,25 @@ extension HomeViewController: SyncingActivityMonitorObserver { } func syncingActivityMonitorStateDidChange(previousState: SyncingActivityMonitor.State, state: SyncingActivityMonitor.State) { - #if DASHPAY if state == .syncDone { + #if DASHPAY if let invitationSetup = invitationSetup { handleDeeplink(invitationSetup.invitation!, definedUsername: invitationSetup.chosenUsername) self.invitationSetup = nil + return } - SyncingActivityMonitor.shared.remove(observer: self) + #endif + + presentCrowdNodeBalanceReminderIfNeeded() } - #endif + } +} + +extension HomeViewController: UIAdaptivePresentationControllerDelegate { + func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { + guard presentationController.presentedViewController === crowdNodeBalanceReminderController else { return } + + crowdNodeBalanceReminderController = nil + CrowdNodeBalanceReminder.shared.dismissActiveScreenReminder() } } From efba637a29e30b67f77a50a0bbfd46a0402c203a Mon Sep 17 00:00:00 2001 From: Roman <51091564+jeanpierreroma@users.noreply.github.com> Date: Mon, 22 Jun 2026 21:10:56 +0300 Subject: [PATCH 2/5] fix(crowdnode): present balance reminder on active screen --- .../CrowdNode/CrowdNodeBalanceReminder.swift | 11 ++- .../CrowdNodeBalanceReminderSheet.swift | 22 +++--- .../Sources/UI/Home/HomeViewController.swift | 72 ++++++++++++++----- .../SwiftUI Components/SelfSizingSheet.swift | 1 + 4 files changed, 73 insertions(+), 33 deletions(-) diff --git a/DashWallet/Sources/Models/CrowdNode/CrowdNodeBalanceReminder.swift b/DashWallet/Sources/Models/CrowdNode/CrowdNodeBalanceReminder.swift index a8a1469e2..dbcdb09f8 100644 --- a/DashWallet/Sources/Models/CrowdNode/CrowdNodeBalanceReminder.swift +++ b/DashWallet/Sources/Models/CrowdNode/CrowdNodeBalanceReminder.swift @@ -25,6 +25,10 @@ final class CrowdNodeBalanceReminder: ObservableObject { @Published private(set) var hasBalance: Bool @Published private(set) var balance: UInt64 @Published private(set) var activeScreenReminderDismissed: Bool = false + /// Set once the active-screen reminder has been shown this session. Never reset, so the + /// reminder sheet appears at most once per app launch (unlike the dismissed flag, which + /// resets when the balance clears). + @Published private(set) var didShowActiveScreenReminder: Bool = false private let crowdNode: CrowdNode private var cancellableBag = Set() @@ -34,7 +38,7 @@ final class CrowdNodeBalanceReminder: ObservableObject { } var shouldShowOnActiveScreen: Bool { - hasBalance && !activeScreenReminderDismissed + hasBalance && !activeScreenReminderDismissed && !didShowActiveScreenReminder } var shouldShowOnExplore: Bool { @@ -59,6 +63,11 @@ final class CrowdNodeBalanceReminder: ObservableObject { activeScreenReminderDismissed = true } + /// Mark the active-screen reminder as shown so it isn't presented again this session. + func markActiveScreenReminderShown() { + didShowActiveScreenReminder = true + } + private func update(balance: UInt64) { self.balance = balance hasBalance = balance > 0 diff --git a/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderSheet.swift b/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderSheet.swift index b8278b6e7..5462ba7a5 100644 --- a/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderSheet.swift +++ b/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderSheet.swift @@ -84,23 +84,19 @@ struct CrowdNodeBalanceReminderSheet: View { Color.dash.primaryBackground .ignoresSafeArea() .sheet(isPresented: .constant(true)) { - // Qualify the type: the project also defines a `BottomSheet`, so use the lib's one. - // `fillsHeight: false` + `.selfSizingSheet()` snaps the sheet to its content height. - let sheet = DashUIKit.BottomSheet(showBackButton: .constant(false), fillsHeight: false) { + // Use the lib's qualified factory: it sets `fillsHeight: false`, self-sizes to content, + // and (via `cornerRadius`) fills the sheet background + rounds the corners. Being fully + // qualified by type, it also avoids the ambiguity with the project's `selfSizingSheet`. + // `fallback` avoids the `.medium` flash before the first measurement. + DashUIKit.BottomSheet.selfSizing( + showBackButton: .constant(false), + fallback: 540, + cornerRadius: 24 + ) { CrowdNodeBalanceReminderSheet( onWithdraw: {}, onDismiss: {} ) } - .selfSizingSheet() - - if #available(iOS 16.4, *) { - sheet - .presentationBackground(Color.dash.primaryBackground) // fills the bottom safe-area strip too - .presentationCornerRadius(32) - .presentationDragIndicator(.hidden) // hide native grabber — lib draws its own - } else { - sheet - } } } diff --git a/DashWallet/Sources/UI/Home/HomeViewController.swift b/DashWallet/Sources/UI/Home/HomeViewController.swift index ad04b8a83..c0cc5439b 100644 --- a/DashWallet/Sources/UI/Home/HomeViewController.swift +++ b/DashWallet/Sources/UI/Home/HomeViewController.swift @@ -18,6 +18,7 @@ import UIKit import SwiftUI import Combine +import DashUIKit @objc(DWHomeViewControllerDelegate) protocol HomeViewControllerDelegate: AnyObject { @@ -300,7 +301,7 @@ class HomeViewController: DWBasePayViewController, NavigationBarDisplayable { } private func presentCrowdNodeBalanceReminderIfNeeded() { - guard isViewLoaded, view.window != nil else { return } + guard isViewLoaded else { return } guard SyncingActivityMonitor.shared.state == .syncDone else { return } guard CrowdNodeBalanceReminder.shared.shouldShowOnActiveScreen else { pendingCrowdNodeReminder = false @@ -310,35 +311,68 @@ class HomeViewController: DWBasePayViewController, NavigationBarDisplayable { pendingCrowdNodeReminder = false return } - guard presentedViewController == nil else { + // Present on whatever view is currently active (any tab / pushed screen), not just Home. + // The sync observer fires even when Home isn't the visible tab, so `self` may be off-screen. + guard let presenter = activeTopViewController(), + presenter.presentedViewController == nil, + !(presenter is UIAlertController) else { pendingCrowdNodeReminder = true scheduleCrowdNodeReminderRetryIfNeeded() return } - let sheet = CrowdNodeBalanceReminderSheet( - onWithdraw: { [weak self] in - self?.openCrowdNodeWithdrawalFromReminder() - }, - onDismiss: { [weak self] in - self?.dismissCrowdNodeBalanceReminder(markDismissed: true, animated: true) - } - ) - .background(Color.primaryBackground) + let bottomSheet = DashUIKit.BottomSheet(showBackButton: .constant(false), fillsHeight: false) { + CrowdNodeBalanceReminderSheet( + onWithdraw: { [weak self] in + self?.openCrowdNodeWithdrawalFromReminder() + }, + onDismiss: { [weak self] in + self?.dismissCrowdNodeBalanceReminder(markDismissed: true, animated: true) + } + ) + } - let hostingController = UIHostingController(rootView: sheet) + let hostingController = UIHostingController(rootView: bottomSheet) hostingController.modalPresentationStyle = .pageSheet hostingController.presentationController?.delegate = self + // Fill the whole sheet (incl. the bottom safe-area strip) with the sheet background. + hostingController.view.backgroundColor = UIColor(Color.dash.primaryBackground) + + if let sheetPC = hostingController.sheetPresentationController { + sheetPC.prefersGrabberVisible = false + // Custom corner radius only below iOS 26; iOS 26+ keeps the native sheet styling. + if #unavailable(iOS 26.0) { + sheetPC.preferredCornerRadius = 24 + } - if let sheet = hostingController.sheetPresentationController { - sheet.detents = [.medium()] - sheet.preferredCornerRadius = 24 - sheet.prefersGrabberVisible = true + // SwiftUI's `.presentationDetents` (used by `.selfSizingSheet()`) does NOT bridge to a + // UIHostingController presented via UIKit `present()` — UIKit would fall back to `.large`. + // So size the sheet to its content here with a custom UIKit detent. + if #available(iOS 16.0, *) { + let width = presenter.view.bounds.width + let bottomInset = presenter.view.window?.safeAreaInsets.bottom ?? 0 + let contentHeight = hostingController + .sizeThatFits(in: CGSize(width: width, height: .greatestFiniteMagnitude)) + .height + sheetPC.detents = [.custom { context in + min(contentHeight + bottomInset, context.maximumDetentValue) + }] + } else { + sheetPC.detents = [.medium()] + } } pendingCrowdNodeReminder = false crowdNodeBalanceReminderController = hostingController - present(hostingController, animated: true) + // Show at most once per session — don't re-present on subsequent HomeView appearances. + CrowdNodeBalanceReminder.shared.markActiveScreenReminderShown() + presenter.present(hostingController, animated: true) + } + + /// The active tab's top-most controller. Resolves via the tab-bar ancestor, which stays + /// reachable even when Home isn't the selected tab (so the reminder can appear anywhere). + private func activeTopViewController() -> UIViewController? { + (tabBarController ?? view.window?.rootViewController)?.topController() } private func dismissCrowdNodeBalanceReminder(markDismissed: Bool, animated: Bool, completion: (() -> Void)? = nil) { @@ -359,8 +393,8 @@ class HomeViewController: DWBasePayViewController, NavigationBarDisplayable { private func openCrowdNodeWithdrawalFromReminder() { dismissCrowdNodeBalanceReminder(markDismissed: false, animated: true) { [weak self] in - guard let self = self else { return } - CrowdNodeWithdrawalRouter.openWithdrawal(from: self) + guard let self = self, let presenter = self.activeTopViewController() else { return } + CrowdNodeWithdrawalRouter.openWithdrawal(from: presenter) } } diff --git a/DashWallet/Sources/UI/SwiftUI Components/SelfSizingSheet.swift b/DashWallet/Sources/UI/SwiftUI Components/SelfSizingSheet.swift index aff78ced1..656c7516e 100644 --- a/DashWallet/Sources/UI/SwiftUI Components/SelfSizingSheet.swift +++ b/DashWallet/Sources/UI/SwiftUI Components/SelfSizingSheet.swift @@ -49,6 +49,7 @@ private struct SelfSizingSheetModifier: ViewModifier { private var detents: Set { guard let height, height > 0 else { return [.medium] } + print("\(height)") return [.height(height)] } From 6a9fc0674f322007c5ad0e60f0b13f5359b4aeff Mon Sep 17 00:00:00 2001 From: Roman <51091564+jeanpierreroma@users.noreply.github.com> Date: Mon, 22 Jun 2026 21:46:55 +0300 Subject: [PATCH 3/5] fix(crowdnode): refine balance reminder presentation --- .../CrowdNodeWithdrawalRouter.swift | 4 +- .../UI/Explore Dash/ExploreMenuScreen.swift | 60 +++++++------------ .../Sources/UI/Home/HomeViewController.swift | 4 +- .../SwiftUI Components/SelfSizingSheet.swift | 1 - 4 files changed, 24 insertions(+), 45 deletions(-) diff --git a/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeWithdrawalRouter.swift b/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeWithdrawalRouter.swift index 27f8137c7..d622fb0cf 100644 --- a/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeWithdrawalRouter.swift +++ b/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeWithdrawalRouter.swift @@ -90,11 +90,11 @@ enum CrowdNodeWithdrawalRouter { controller.actionButtonText = CrowdNodeModel.shared.buyDashButtonText let navigationController = BaseNavigationController(rootViewController: controller) - controller.mainAction = { + controller.mainAction = { [weak navigationController] in Task { if await CrowdNodeModel.shared.authenticate() { let buySellController = BuySellPortalViewController.controller() - navigationController.pushViewController(buySellController, animated: true) + navigationController?.pushViewController(buySellController, animated: true) } } } diff --git a/DashWallet/Sources/UI/Explore Dash/ExploreMenuScreen.swift b/DashWallet/Sources/UI/Explore Dash/ExploreMenuScreen.swift index efbdf93f5..ee99a5554 100644 --- a/DashWallet/Sources/UI/Explore Dash/ExploreMenuScreen.swift +++ b/DashWallet/Sources/UI/Explore Dash/ExploreMenuScreen.swift @@ -59,16 +59,12 @@ struct ExploreMenuScreen: View { TopIntro( title: NSLocalizedString("Explore Dash", comment: ""), - subtitle: NSLocalizedString("Find merchants that accept Dash, where to buy it and how to earn income with it.", comment: "") + subtitle: NSLocalizedString("Find merchants who accept Dash and where to buy it.", comment: "") ) - - if balanceReminder.shouldShowOnExplore { - CrowdNodeBalanceReminderBanner { - showCrowdNodeWithdrawal() - } - .padding(.horizontal, 20) - .padding(.bottom, 16) - } + .padding(.leading, 20) + .padding(.trailing, 60) + .padding(.top, 10) + .padding(.bottom, 20) // Menu list VStack(spacing: 2) { @@ -101,7 +97,13 @@ struct ExploreMenuScreen: View { if hasCrowdNodeAccount { MenuItem( title: NSLocalizedString("Staking", comment: ""), - subtitleView: AnyView(StakingSubtitle()), + subtitleView: AnyView( + Text(NSLocalizedString("Easily stake Dash and earn passive income with a few simple clicks", comment: "")) + .font(.footnote) + .foregroundColor(.tertiaryText) + .multilineTextAlignment(.leading) + .frame(maxWidth: .infinity, alignment: .leading) + ), icon: .custom("image-menu-staking", maxHeight: 30), iconAlignment: .top, action: { showStaking() } @@ -115,6 +117,14 @@ struct ExploreMenuScreen: View { .shadow(color: Color.shadow, radius: 20, x: 0, y: 5) .padding(.horizontal, 20) + if balanceReminder.shouldShowOnExplore { + CrowdNodeBalanceReminderBanner { + showCrowdNodeWithdrawal() + } + .padding(.horizontal, 20) + .padding(.top, 20) + } + Spacer() } .background(Color.primaryBackground) @@ -137,10 +147,6 @@ struct ExploreMenuScreen: View { .foregroundColor(.tertiaryText) .multilineTextAlignment(.leading) .frame(maxWidth: .infinity, alignment: .leading) - - CrowdNodeAPYBadge() - .frame(height: 24) - .fixedSize(horizontal: true, vertical: false) } .padding(.top, 2) .frame(maxWidth: .infinity, alignment: .leading) @@ -199,29 +205,3 @@ struct ExploreMenuScreen: View { CrowdNodeWithdrawalRouter.openWithdrawal(from: vc) } } - -struct CrowdNodeAPYBadge: View { - private static let systemGreen = Color(red: 98 / 255, green: 182 / 255, blue: 125 / 255) - - private var apy: String { - let apyValue = CrowdNode.shared.crowdnodeAPY - let numberFormatter = NumberFormatter() - numberFormatter.numberStyle = .percent - numberFormatter.minimumFractionDigits = 0 - numberFormatter.maximumFractionDigits = 2 - numberFormatter.multiplier = 1 - return numberFormatter.string(from: NSNumber(value: apyValue)) ?? "" - } - - var body: some View { - HStack(spacing: 4) { - Text(String.localizedStringWithFormat(NSLocalizedString("Current APY = %@", comment: "CrowdNode"), apy)) - .font(.system(size: 11, weight: .semibold)) - .foregroundColor(Self.systemGreen) - } - .padding(.horizontal, 8) - .frame(height: 24) - .background(Self.systemGreen.opacity(0.1)) - .clipShape(RoundedRectangle(cornerRadius: 6)) - } -} diff --git a/DashWallet/Sources/UI/Home/HomeViewController.swift b/DashWallet/Sources/UI/Home/HomeViewController.swift index c0cc5439b..79a39ea1a 100644 --- a/DashWallet/Sources/UI/Home/HomeViewController.swift +++ b/DashWallet/Sources/UI/Home/HomeViewController.swift @@ -527,8 +527,8 @@ extension HomeViewController: SyncingActivityMonitorObserver { func syncingActivityMonitorStateDidChange(previousState: SyncingActivityMonitor.State, state: SyncingActivityMonitor.State) { if state == .syncDone { #if DASHPAY - if let invitationSetup = invitationSetup { - handleDeeplink(invitationSetup.invitation!, definedUsername: invitationSetup.chosenUsername) + if let invitationSetup = invitationSetup, let invitation = invitationSetup.invitation { + handleDeeplink(invitation, definedUsername: invitationSetup.chosenUsername) self.invitationSetup = nil return } diff --git a/DashWallet/Sources/UI/SwiftUI Components/SelfSizingSheet.swift b/DashWallet/Sources/UI/SwiftUI Components/SelfSizingSheet.swift index 656c7516e..aff78ced1 100644 --- a/DashWallet/Sources/UI/SwiftUI Components/SelfSizingSheet.swift +++ b/DashWallet/Sources/UI/SwiftUI Components/SelfSizingSheet.swift @@ -49,7 +49,6 @@ private struct SelfSizingSheetModifier: ViewModifier { private var detents: Set { guard let height, height > 0 else { return [.medium] } - print("\(height)") return [.height(height)] } From b9e0c2fde895fed692814d90ea1107d1ead874b0 Mon Sep 17 00:00:00 2001 From: Roman <51091564+jeanpierreroma@users.noreply.github.com> Date: Fri, 26 Jun 2026 15:34:08 +0300 Subject: [PATCH 4/5] feat(cn-balance): improve balance message display for CrowdNode Update balance reminder messaging and UI components for better clarity: - Improve CrowdNodeBalanceReminderBanner and CrowdNodeBalanceReminderSheet messaging - Update CrowdNode.swift balance calculation logic - Enhance MayaAmountView formatting - Improve LocalCurrencyView display - Remove unused geometry reader utilities (FrameReader, LocationReader, ScaleToFitWidth) - Remove unused ScrollViewWithOnScrollChanged component - Update project configuration --- DashWallet.xcodeproj/project.pbxproj | 427 +++++++++--------- .../Sources/Models/CrowdNode/CrowdNode.swift | 6 + .../CrowdNodeBalanceReminderBanner.swift | 2 +- .../CrowdNodeBalanceReminderSheet.swift | 2 +- .../Convert/Components/MayaAmountView.swift | 1 + .../LocalCurrency/LocalCurrencyView.swift | 1 + .../Geometry Readers/FrameReader.swift | 96 ---- .../Geometry Readers/LocationReader.swift | 92 ---- .../Geometry Readers/ScaleToFitWidth.swift | 77 ---- .../ScrollViewWithOnScrollChanged.swift | 79 ---- 10 files changed, 220 insertions(+), 563 deletions(-) delete mode 100644 DashWallet/Sources/UI/SwiftUI Components/Geometry Readers/FrameReader.swift delete mode 100644 DashWallet/Sources/UI/SwiftUI Components/Geometry Readers/LocationReader.swift delete mode 100644 DashWallet/Sources/UI/SwiftUI Components/Geometry Readers/ScaleToFitWidth.swift delete mode 100644 DashWallet/Sources/UI/SwiftUI Components/ScrollViews/ScrollViewWithOnScrollChanged.swift diff --git a/DashWallet.xcodeproj/project.pbxproj b/DashWallet.xcodeproj/project.pbxproj index cfacf480a..7c3fe22ad 100644 --- a/DashWallet.xcodeproj/project.pbxproj +++ b/DashWallet.xcodeproj/project.pbxproj @@ -80,11 +80,10 @@ 11BD738128E7356100A34022 /* CrowdNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11BD738028E7356100A34022 /* CrowdNode.swift */; }; 11E47BA828EAE7AD0097CFA0 /* CrowdNodeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E47BA728EAE7AD0097CFA0 /* CrowdNodeModel.swift */; }; 11E47BAB28EB38510097CFA0 /* SendCoinsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E47BAA28EB38510097CFA0 /* SendCoinsService.swift */; }; - FE5CA1E0000000000000A002 /* ScaleToFitWidth.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE5CA1E0000000000000A001 /* ScaleToFitWidth.swift */; }; - 51BA2EA02F0B2E0100A1B201 /* MayaSwapPendingGate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51BA2E9F2F0B2E0100A1B201 /* MayaSwapPendingGate.swift */; }; 11E47BAD28EB3A7D0097CFA0 /* CrowdNode+Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E47BAC28EB3A7D0097CFA0 /* CrowdNode+Constants.swift */; }; 11ED906B29681773003784F9 /* StakingInfoDialogController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11ED906A29681773003784F9 /* StakingInfoDialogController.swift */; }; - 19BF3F10240A082811AAC1EB /* BuildFile in Frameworks */ = {isa = PBXBuildFile; }; + 153C3E3D30BB4DB2A63DAD87 /* DashUIKit in Frameworks */ = {isa = PBXBuildFile; productRef = 64C58B73936B4EE69F73994F /* DashUIKit */; }; + 19BF3F10240A082811AAC1EB /* (null) in Frameworks */ = {isa = PBXBuildFile; }; 1AF81D8C73A81CB927C3AE0E /* libPods-DashWalletScreenshotsUITests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B56B94951BA51EAC9E0A6E1 /* libPods-DashWalletScreenshotsUITests.a */; }; 1DD7BE9CD62998F12672140D /* RadioButtonRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708B9F2B4B1E4C31B5010CDF /* RadioButtonRow.swift */; }; 1F3FF21B0295D5A326F08B74 /* OrderPreviewFeeRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D1A08496F925D17031493E /* OrderPreviewFeeRow.swift */; }; @@ -500,6 +499,7 @@ 47FA3AFF29350929008D58DC /* SyncingActivityMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FA3AFE29350929008D58DC /* SyncingActivityMonitor.swift */; }; 47FA3B0229364991008D58DC /* HTTPClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FA3B0129364991008D58DC /* HTTPClient.swift */; }; 4A36341D70A94778AF408757 /* MayaCoinIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20554F992205428BA790F6CF /* MayaCoinIconView.swift */; }; + 514518ED2FE936FC00F9AD4C /* DashUIKit in Frameworks */ = {isa = PBXBuildFile; productRef = 514518EC2FE936FC00F9AD4C /* DashUIKit */; }; 514AE85E2FB1F9DB00F9B54C /* DashSwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514AE85D2FB1F9DB00F9B54C /* DashSwitch.swift */; }; 514AE85F2FB1F9DB00F9B54C /* DashSwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514AE85D2FB1F9DB00F9B54C /* DashSwitch.swift */; }; 514AE9F32FB2F4C500F9B54C /* HaltedToast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514AE9F22FB2F4C500F9B54C /* HaltedToast.swift */; }; @@ -522,7 +522,6 @@ 514AF1C12FB5F02D00F9B54C /* MayaConvertViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514AF1BF2FB5F02D00F9B54C /* MayaConvertViewModel.swift */; }; 514BEA012FB5F02D00F9B54C /* MayaConvertAmount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514BEA002FB5F02D00F9B54C /* MayaConvertAmount.swift */; }; 514BEA022FB5F02D00F9B54C /* MayaConvertAmount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514BEA002FB5F02D00F9B54C /* MayaConvertAmount.swift */; }; - 514518ED2FE936FC00F9AD4C /* DashUIKit in Frameworks */ = {isa = PBXBuildFile; productRef = 514518EC2FE936FC00F9AD4C /* DashUIKit */; }; 5151C8C62F913BF100F0A604 /* Coinbase-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5151C8C22F913BF100F0A604 /* Coinbase-Info.plist */; }; 5151C8C72F913BF100F0A604 /* ZenLedger-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5151C8C52F913BF100F0A604 /* ZenLedger-Info.plist */; }; 5151C8C82F913BF100F0A604 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5151C8C32F913BF100F0A604 /* GoogleService-Info.plist */; }; @@ -549,6 +548,20 @@ 516983B22FCAEDEB00BA91A2 /* LoadingIllustration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 516983B02FCAEDEB00BA91A2 /* LoadingIllustration.swift */; }; 516983C22FCAEDEB00BA91A2 /* XmarkIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 516983C12FCAEDEB00BA91A2 /* XmarkIcon.swift */; }; 516983C32FCAEDEB00BA91A2 /* XmarkIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 516983C12FCAEDEB00BA91A2 /* XmarkIcon.swift */; }; + 5185FF482FEE6D64001BA37E /* GiftCardDetailsInfoCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C0B001D6C0B001D6C0B001 /* GiftCardDetailsInfoCard.swift */; }; + 5185FF492FEE6D64001BA37E /* GiftCardDetailsMerchantHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C0B002D6C0B002D6C0B002 /* GiftCardDetailsMerchantHeader.swift */; }; + 5185FF4A2FEE6D64001BA37E /* GiftCardPurchaseSelectionSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C0B003D6C0B003D6C0B003 /* GiftCardPurchaseSelectionSheet.swift */; }; + 5185FF4B2FEE6D64001BA37E /* GiftCardDetailsPoweredBySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C0B004D6C0B004D6C0B004 /* GiftCardDetailsPoweredBySection.swift */; }; + 5185FF4C2FEE6D64001BA37E /* GiftCardDetailsHowToUseSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C0B005D6C0B005D6C0B005 /* GiftCardDetailsHowToUseSection.swift */; }; + 5185FF4D2FEE6D64001BA37E /* DashSpendFixedContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B003D5A0B003D5A0B003 /* DashSpendFixedContent.swift */; }; + 5185FF4E2FEE6D64001BA37E /* DashSpendFlexibleContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B004D5A0B004D5A0B004 /* DashSpendFlexibleContent.swift */; }; + 5185FF4F2FEE6D64001BA37E /* DashSpendAmountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B001D5A0B001D5A0B001 /* DashSpendAmountView.swift */; }; + 5185FF502FEE6D64001BA37E /* DashSpendDenominationRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B002D5A0B002D5A0B002 /* DashSpendDenominationRow.swift */; }; + 5185FF512FEE6D64001BA37E /* DashSpendMultiplePanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B005D5A0B005D5A0B005 /* DashSpendMultiplePanel.swift */; }; + 5185FF522FEE6D64001BA37E /* DashSpendPayIntro.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B006D5A0B006D5A0B006 /* DashSpendPayIntro.swift */; }; + 5185FF532FEE6D64001BA37E /* DashSpendSinglePanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B007D5A0B007D5A0B007 /* DashSpendSinglePanel.swift */; }; + 5185FF542FEE6D64001BA37E /* DashStepper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DFA10175DFA10175DFA101 /* DashStepper.swift */; }; + 5185FF552FEE6D64001BA37E /* SegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DFA10275DFA10275DFA102 /* SegmentedControl.swift */; }; 51A577482FBB3A6000FB4097 /* OrderPreviewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A577472FBB3A6000FB4097 /* OrderPreviewViewModel.swift */; }; 51A577492FBB3A6000FB4097 /* OrderPreviewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A577472FBB3A6000FB4097 /* OrderPreviewViewModel.swift */; }; 51A5774B2FBB3A6E00FB4097 /* OrderPreviewHostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A5774A2FBB3A6E00FB4097 /* OrderPreviewHostingController.swift */; }; @@ -563,6 +576,8 @@ 51A57C072FBB5A0000FB4097 /* MayaTransactionFailureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A57C032FBB5A0000FB4097 /* MayaTransactionFailureView.swift */; }; 51A57C092FBB5A0000FB4097 /* MayaTransactionPendingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A57C082FBB5A0000FB4097 /* MayaTransactionPendingView.swift */; }; 51A57C0A2FBB5A0000FB4097 /* MayaTransactionPendingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A57C082FBB5A0000FB4097 /* MayaTransactionPendingView.swift */; }; + 51BA2EA02F0B2E0100A1B201 /* MayaSwapPendingGate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51BA2E9F2F0B2E0100A1B201 /* MayaSwapPendingGate.swift */; }; + 51BA2EA12F0B2E0100A1B201 /* MayaSwapPendingGate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51BA2E9F2F0B2E0100A1B201 /* MayaSwapPendingGate.swift */; }; 51F0D10130BF97A900B27E11 /* ExclamationIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F0D10030BF97A900B27E11 /* ExclamationIcon.swift */; }; 51F0D10230BF97A900B27E11 /* ExclamationIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F0D10030BF97A900B27E11 /* ExclamationIcon.swift */; }; 51F0D10430BF98BA00B27E11 /* ArrowDownIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F0D10330BF98BA00B27E11 /* ArrowDownIcon.swift */; }; @@ -647,16 +662,16 @@ 754119E01CDA93FF0042DC51 /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BAE12BE61B2DEE7F00895CC5 /* NotificationCenter.framework */; }; 754495DD2AE91B6300492817 /* GroupedRequestCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754495DC2AE91B6300492817 /* GroupedRequestCell.swift */; }; 754495DF2AE91D3500492817 /* UsernameRequestCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754495DE2AE91D3500492817 /* UsernameRequestCell.swift */; }; - 754565C82DAA52A000DA4E8E /* CTXSpendAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754565C42DAA52A000DA4E8E /* CTXSpendAPI.swift */; }; - 754565CA2DAA52A000DA4E8E /* CTXSpendRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754565C72DAA52A000DA4E8E /* CTXSpendRepository.swift */; }; - 754565CB2DAA52A000DA4E8E /* CTXSpendEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754565C52DAA52A000DA4E8E /* CTXSpendEndpoint.swift */; }; - 754565CC2DAA52A000DA4E8E /* CTXSpendAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754565C42DAA52A000DA4E8E /* CTXSpendAPI.swift */; }; - 754565CE2DAA52A000DA4E8E /* CTXSpendRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754565C72DAA52A000DA4E8E /* CTXSpendRepository.swift */; }; - 754565CF2DAA52A000DA4E8E /* CTXSpendEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754565C52DAA52A000DA4E8E /* CTXSpendEndpoint.swift */; }; + 754565C82DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754565C42DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendAPI.swift */; }; + 754565CA2DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754565C72DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendRepository.swift */; }; + 754565CB2DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754565C52DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendEndpoint.swift */; }; + 754565CC2DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754565C42DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendAPI.swift */; }; + 754565CE2DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754565C72DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendRepository.swift */; }; + 754565CF2DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754565C52DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendEndpoint.swift */; }; 754565D12DABA5F300DA4E8E /* MerchantTypesDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754565D02DABA5EB00DA4E8E /* MerchantTypesDialog.swift */; }; 754565D22DABA5F300DA4E8E /* MerchantTypesDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754565D02DABA5EB00DA4E8E /* MerchantTypesDialog.swift */; }; - 7545ED532DA91A2F0075F45C /* CTXConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7545ED522DA91A2F0075F45C /* CTXConstants.swift */; }; - 7545ED542DA91A2F0075F45C /* CTXConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7545ED522DA91A2F0075F45C /* CTXConstants.swift */; }; + 7545ED532DA91A2F0075F45C /* DashSpend/CTXConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7545ED522DA91A2F0075F45C /* DashSpend/CTXConstants.swift */; }; + 7545ED542DA91A2F0075F45C /* DashSpend/CTXConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7545ED522DA91A2F0075F45C /* DashSpend/CTXConstants.swift */; }; 7545ED572DA91AF10075F45C /* DashSpendUserAuthViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7545ED562DA91AEA0075F45C /* DashSpendUserAuthViewModel.swift */; }; 7545ED582DA91AF10075F45C /* DashSpendUserAuthViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7545ED562DA91AEA0075F45C /* DashSpendUserAuthViewModel.swift */; }; 7545ED5D2DA91F590075F45C /* DashSpendTermsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7545ED5C2DA91F590075F45C /* DashSpendTermsScreen.swift */; }; @@ -759,17 +774,8 @@ 759C8FA02B593589004B1305 /* CrowdNodeAPYView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 759C8F9E2B593589004B1305 /* CrowdNodeAPYView.swift */; }; 75A0A3F32CA7DBCF003ED48B /* TimeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75A0A3F22CA7DBCF003ED48B /* TimeUtils.swift */; }; 75A0A3F42CA7DBCF003ED48B /* TimeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75A0A3F22CA7DBCF003ED48B /* TimeUtils.swift */; }; - 75DFA00175DFA00175DFA001 /* DashStepper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DFA10175DFA10175DFA101 /* DashStepper.swift */; }; - 75DFA00275DFA00275DFA002 /* SegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DFA10275DFA10275DFA102 /* SegmentedControl.swift */; }; - 75A2F3032DE48C860046BE17 /* CTXSpendTokenService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75A2F3022DE48C860046BE17 /* CTXSpendTokenService.swift */; }; - 75A2F3042DE48C860046BE17 /* CTXSpendTokenService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75A2F3022DE48C860046BE17 /* CTXSpendTokenService.swift */; }; - D5A0C001D5A0C001D5A0C001 /* DashSpendAmountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B001D5A0B001D5A0B001 /* DashSpendAmountView.swift */; }; - D5A0C002D5A0C002D5A0C002 /* DashSpendDenominationRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B002D5A0B002D5A0B002 /* DashSpendDenominationRow.swift */; }; - D5A0C003D5A0C003D5A0C003 /* DashSpendFixedContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B003D5A0B003D5A0B003 /* DashSpendFixedContent.swift */; }; - D5A0C004D5A0C004D5A0C004 /* DashSpendFlexibleContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B004D5A0B004D5A0B004 /* DashSpendFlexibleContent.swift */; }; - D5A0C005D5A0C005D5A0C005 /* DashSpendMultiplePanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B005D5A0B005D5A0B005 /* DashSpendMultiplePanel.swift */; }; - D5A0C006D5A0C006D5A0C006 /* DashSpendPayIntro.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B006D5A0B006D5A0B006 /* DashSpendPayIntro.swift */; }; - D5A0C007D5A0C007D5A0C007 /* DashSpendSinglePanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B007D5A0B007D5A0B007 /* DashSpendSinglePanel.swift */; }; + 75A2F3032DE48C860046BE17 /* DashSpend/CTX/CTXSpendTokenService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75A2F3022DE48C860046BE17 /* DashSpend/CTX/CTXSpendTokenService.swift */; }; + 75A2F3042DE48C860046BE17 /* DashSpend/CTX/CTXSpendTokenService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75A2F3022DE48C860046BE17 /* DashSpend/CTX/CTXSpendTokenService.swift */; }; 75A8C1652AE5726B0042256E /* UsernameRequestsDAO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75A8C1632AE5725C0042256E /* UsernameRequestsDAO.swift */; }; 75A8C1672AE5734A0042256E /* UsernameRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75A8C1662AE5734A0042256E /* UsernameRequest.swift */; }; 75A8C1692AE6A1AC0042256E /* VotingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75A8C1682AE6A1AC0042256E /* VotingViewModel.swift */; }; @@ -826,11 +832,8 @@ 75D9EBC72DE5CE14009416A2 /* GiftCardDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75D9EBC42DE5CE14009416A2 /* GiftCardDetailsView.swift */; }; 75D9EBC82DE5CE14009416A2 /* GiftCardDetailsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75D9EBC52DE5CE14009416A2 /* GiftCardDetailsViewModel.swift */; }; 75D9EBC92DE5CE14009416A2 /* GiftCardDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75D9EBC42DE5CE14009416A2 /* GiftCardDetailsView.swift */; }; - D6C0C001D6C0C001D6C0C001 /* GiftCardDetailsInfoCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C0B001D6C0B001D6C0B001 /* GiftCardDetailsInfoCard.swift */; }; - D6C0C002D6C0C002D6C0C002 /* GiftCardDetailsMerchantHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C0B002D6C0B002D6C0B002 /* GiftCardDetailsMerchantHeader.swift */; }; - D6C0C003D6C0C003D6C0C003 /* GiftCardPurchaseSelectionSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C0B003D6C0B003D6C0B003 /* GiftCardPurchaseSelectionSheet.swift */; }; - D6C0C004D6C0C004D6C0C004 /* GiftCardDetailsPoweredBySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C0B004D6C0B004D6C0B004 /* GiftCardDetailsPoweredBySection.swift */; }; - D6C0C005D6C0C005D6C0C005 /* GiftCardDetailsHowToUseSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C0B005D6C0B005D6C0B005 /* GiftCardDetailsHowToUseSection.swift */; }; + 75DFA00175DFA00175DFA001 /* DashStepper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DFA10175DFA10175DFA101 /* DashStepper.swift */; }; + 75DFA00275DFA00275DFA002 /* SegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DFA10275DFA10275DFA102 /* SegmentedControl.swift */; }; 75DFAF2E2CF7066600CCA68B /* VoteButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DFAF2D2CF7066200CCA68B /* VoteButton.swift */; }; 75E2F3C82AA4CF1900C3B458 /* Topper-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 75E2F3C72AA4CF1900C3B458 /* Topper-Info.plist */; }; 75E2F3CA2AA4D1B900C3B458 /* Topper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75E2F3C92AA4D1B900C3B458 /* Topper.swift */; }; @@ -891,8 +894,8 @@ AA0000012DUMMYID001234567 /* AddProviderToGiftCardsTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0000032DUMMYID001234567 /* AddProviderToGiftCardsTable.swift */; }; AA00000228D9A3DB00223B77 /* BuySellPortalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA00000028D9A3DB00223B77 /* BuySellPortalView.swift */; }; AA0000022DUMMYID001234567 /* AddProviderToGiftCardsTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0000032DUMMYID001234567 /* AddProviderToGiftCardsTable.swift */; }; - AA0000042DUMMYID001234567 /* GiftCardProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0000062DUMMYID001234567 /* GiftCardProvider.swift */; }; - AA0000052DUMMYID001234567 /* GiftCardProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0000062DUMMYID001234567 /* GiftCardProvider.swift */; }; + AA0000042DUMMYID001234567 /* DashSpend/GiftCardProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0000062DUMMYID001234567 /* DashSpend/GiftCardProvider.swift */; }; + AA0000052DUMMYID001234567 /* DashSpend/GiftCardProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0000062DUMMYID001234567 /* DashSpend/GiftCardProvider.swift */; }; AA0001022AA9F58E00A1B201 /* MayaPortalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0001012AA9F58E00A1B201 /* MayaPortalView.swift */; }; AA0001032AA9F58E00A1B201 /* MayaPortalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0001012AA9F58E00A1B201 /* MayaPortalView.swift */; }; AA0001052AA9F58E00A1B202 /* MayaPortalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0001042AA9F58E00A1B202 /* MayaPortalViewController.swift */; }; @@ -936,7 +939,7 @@ AA0020012FA0000000000015 /* SwapExecutionData.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0020012FA0000000000013 /* SwapExecutionData.swift */; }; AA29B7041CF55787428E1A04 /* libPods-WatchApp Extension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B9BF7550EF8D4BA009CB1EB5 /* libPods-WatchApp Extension.a */; }; ABA7230759067F4D4EB39AE9 /* MayaTransactionStatusHostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B5469F5588395FA0668C4B /* MayaTransactionStatusHostingController.swift */; }; - AEAE60406265A73AFD573FD1 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; }; + AEAE60406265A73AFD573FD1 /* (null) in Frameworks */ = {isa = PBXBuildFile; }; B059B6E200A57A699E6EED84 /* libPods-DashWalletTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1940CA64E8FD6DDD0CFC14A2 /* libPods-DashWalletTests.a */; }; B3A1F2C4D5E6078901234568 /* ExtendedPublicKeySheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3A1F2C4D5E6078901234567 /* ExtendedPublicKeySheet.swift */; }; B3A1F2C4D5E6078901234569 /* ExtendedPublicKeySheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3A1F2C4D5E6078901234567 /* ExtendedPublicKeySheet.swift */; }; @@ -957,12 +960,12 @@ BAA6E3F11BD5CA5900773205 /* BRAWReceiveMoneyInterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAA6E3F01BD5CA5900773205 /* BRAWReceiveMoneyInterfaceController.swift */; }; BAE12BF21B2DEE7F00895CC5 /* TodayExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = BAE12BE51B2DEE7F00895CC5 /* TodayExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; BAE12C061B2DEEF700895CC5 /* DWTodayViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BAE12C051B2DEEF700895CC5 /* DWTodayViewController.m */; }; - BB0000012DUMMYID001234567 /* DashSpendError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB0000072DUMMYID001234567 /* DashSpendError.swift */; }; - BB0000022DUMMYID001234567 /* DashSpendError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB0000072DUMMYID001234567 /* DashSpendError.swift */; }; - BB0000032DUMMYID001234567 /* DashSpendRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB0000082DUMMYID001234567 /* DashSpendRepository.swift */; }; - BB0000042DUMMYID001234567 /* DashSpendRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB0000082DUMMYID001234567 /* DashSpendRepository.swift */; }; - BB0000052DUMMYID001234567 /* DashSpendRepositoryFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB0000092DUMMYID001234567 /* DashSpendRepositoryFactory.swift */; }; - BB0000062DUMMYID001234567 /* DashSpendRepositoryFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB0000092DUMMYID001234567 /* DashSpendRepositoryFactory.swift */; }; + BB0000012DUMMYID001234567 /* DashSpend/DashSpendError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB0000072DUMMYID001234567 /* DashSpend/DashSpendError.swift */; }; + BB0000022DUMMYID001234567 /* DashSpend/DashSpendError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB0000072DUMMYID001234567 /* DashSpend/DashSpendError.swift */; }; + BB0000032DUMMYID001234567 /* DashSpend/DashSpendRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB0000082DUMMYID001234567 /* DashSpend/DashSpendRepository.swift */; }; + BB0000042DUMMYID001234567 /* DashSpend/DashSpendRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB0000082DUMMYID001234567 /* DashSpend/DashSpendRepository.swift */; }; + BB0000052DUMMYID001234567 /* DashSpend/DashSpendRepositoryFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB0000092DUMMYID001234567 /* DashSpend/DashSpendRepositoryFactory.swift */; }; + BB0000062DUMMYID001234567 /* DashSpend/DashSpendRepositoryFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB0000092DUMMYID001234567 /* DashSpend/DashSpendRepositoryFactory.swift */; }; C049F721C394463EB97CA8FF /* DSAccount+SpentInputCheck.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BC16BFBFFFA4E488C09164D /* DSAccount+SpentInputCheck.m */; }; C124DF94278D4238FAE0975D /* OrderPreviewFeeRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D1A08496F925D17031493E /* OrderPreviewFeeRow.swift */; }; C1A0B2C3D4E5F60718293A02 /* ShortcutsBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A0B2C3D4E5F60718293A01 /* ShortcutsBarView.swift */; }; @@ -1301,7 +1304,7 @@ C9D2C70C2A320AA000D15901 /* DWUpholdLogoutTutorialViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A9FFE652230FF4600956D5F /* DWUpholdLogoutTutorialViewController.m */; }; C9D2C70D2A320AA000D15901 /* CBAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47CF46A429654E190067B6EE /* CBAccount.swift */; }; C9D2C70E2A320AA000D15901 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47AF180429070B720025803E /* Types.swift */; }; - C9D2C70F2A320AA000D15901 /* BuildFile in Sources */ = {isa = PBXBuildFile; }; + C9D2C70F2A320AA000D15901 /* (null) in Sources */ = {isa = PBXBuildFile; }; C9D2C7112A320AA000D15901 /* Coinbase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4774DCDA28F3FA9C008CF87D /* Coinbase.swift */; }; C9D2C7122A320AA000D15901 /* SyncModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F452072A11F28600825057 /* SyncModel.swift */; }; C9D2C7132A320AA000D15901 /* ReceiveContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F42FAA29DC1098001BC549 /* ReceiveContentView.swift */; }; @@ -1321,7 +1324,7 @@ C9D2C7242A320AA000D15901 /* WKWebView+CrowdNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110D1780298BA9AF005BEB30 /* WKWebView+CrowdNode.swift */; }; C9D2C7252A320AA000D15901 /* SyncingActivityMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FA3AFE29350929008D58DC /* SyncingActivityMonitor.swift */; }; C9D2C7262A320AA000D15901 /* EmptyUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F42FAF29DC27F4001BC549 /* EmptyUIView.swift */; }; - C9D2C7272A320AA000D15901 /* BuildFile in Sources */ = {isa = PBXBuildFile; }; + C9D2C7272A320AA000D15901 /* (null) in Sources */ = {isa = PBXBuildFile; }; C9D2C7282A320AA000D15901 /* DWQRScanModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AC92C891FEB0B8B008CAEE0 /* DWQRScanModel.m */; }; C9D2C72A2A320AA000D15901 /* SyncView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F451F62A0CAE1300825057 /* SyncView.swift */; }; C9D2C72B2A320AA000D15901 /* SuccessfulOperationStatusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47522F4F2927CB9000EE143E /* SuccessfulOperationStatusViewController.swift */; }; @@ -1352,7 +1355,7 @@ C9D2C7492A320AA000D15901 /* DWCurrencyObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AA87CF926E5681100F0CEA6 /* DWCurrencyObject.m */; }; C9D2C74A2A320AA000D15901 /* ShortcutsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94F5E8F29D4060A0034FD57 /* ShortcutsView.swift */; }; C9D2C74B2A320AA000D15901 /* DWFormSectionModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A9FFE3E2230FF4600956D5F /* DWFormSectionModel.m */; }; - C9D2C74C2A320AA000D15901 /* BuildFile in Sources */ = {isa = PBXBuildFile; }; + C9D2C74C2A320AA000D15901 /* (null) in Sources */ = {isa = PBXBuildFile; }; C9D2C74D2A320AA000D15901 /* CoinbasePlaceBuyOrderResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F6EDFA628C896BC000427E7 /* CoinbasePlaceBuyOrderResponse.swift */; }; C9D2C74E2A320AA000D15901 /* ExploreMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47AE8BDC28C1305E00490F5E /* ExploreMapView.swift */; }; C9D2C74F2A320AA000D15901 /* DWSeedPhraseRow.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AD1CE9322DD078600C99324 /* DWSeedPhraseRow.m */; }; @@ -1376,7 +1379,7 @@ C9D2C7642A320AA000D15901 /* BasePageSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F2C67C28602D4F00C2B774 /* BasePageSheetViewController.swift */; }; C9D2C7662A320AA000D15901 /* CrowdNodeRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 119E8D0329051F9900D406C1 /* CrowdNodeRequest.swift */; }; C9D2C7672A320AA000D15901 /* CoinbaseExchangeRateResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F6EDFAF28C896BC000427E7 /* CoinbaseExchangeRateResponse.swift */; }; - C9D2C7692A320AA000D15901 /* BuildFile in Sources */ = {isa = PBXBuildFile; }; + C9D2C7692A320AA000D15901 /* (null) in Sources */ = {isa = PBXBuildFile; }; C9D2C76A2A320AA000D15901 /* CrowdNodePortalItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 117728A2297A7D24006F1553 /* CrowdNodePortalItem.swift */; }; C9D2C76B2A320AA000D15901 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C661B528FE75A700028A8D /* BaseViewController.swift */; }; C9D2C76C2A320AA000D15901 /* AccountListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4751CABF296EFD2900F63AC4 /* AccountListController.swift */; }; @@ -1426,12 +1429,12 @@ C9D2C7A52A320AA000D15901 /* DWModalPresentationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A0C69C523142AA4001B8C90 /* DWModalPresentationController.m */; }; C9D2C7A72A320AA000D15901 /* ActionButtonViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C661B328FDCF7800028A8D /* ActionButtonViewController.swift */; }; C9D2C7A82A320AA000D15901 /* BuySellServiceItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4774DCE428F4668B008CF87D /* BuySellServiceItemCell.swift */; }; - C9D2C7AA2A320AA000D15901 /* BuildFile in Sources */ = {isa = PBXBuildFile; }; + C9D2C7AA2A320AA000D15901 /* (null) in Sources */ = {isa = PBXBuildFile; }; C9D2C7AB2A320AA000D15901 /* DWBaseFormTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A7A7BC82347E0D700451078 /* DWBaseFormTableViewCell.m */; }; C9D2C7AC2A320AA000D15901 /* AccountCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4751CAC6296FAEBB00F63AC4 /* AccountCell.swift */; }; C9D2C7AD2A320AA000D15901 /* DWTransactionListDataProviderStub.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A913EA723A79AD2006A2A59 /* DWTransactionListDataProviderStub.m */; }; C9D2C7B12A320AA000D15901 /* CoinbaseBaseIDForCurrencyResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F6EDFA028C896BC000427E7 /* CoinbaseBaseIDForCurrencyResponse.swift */; }; - C9D2C7B22A320AA000D15901 /* BuildFile in Sources */ = {isa = PBXBuildFile; }; + C9D2C7B22A320AA000D15901 /* (null) in Sources */ = {isa = PBXBuildFile; }; C9D2C7B32A320AA000D15901 /* SpecifyAmountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47AC8412297822E000BD1B49 /* SpecifyAmountViewController.swift */; }; C9D2C7B42A320AA000D15901 /* DWUpholdTransactionObject+DWView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AFCB9C323BE76EC00FF59A6 /* DWUpholdTransactionObject+DWView.m */; }; C9D2C7B62A320AA000D15901 /* CrowdNodeDepositTx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 114CFECF296469D9005F421B /* CrowdNodeDepositTx.swift */; }; @@ -1442,14 +1445,14 @@ C9D2C7BD2A320AA000D15901 /* DWSharedUIConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A8B9E2822FB1C5D00FF8653 /* DWSharedUIConstants.m */; }; C9D2C7BE2A320AA000D15901 /* BRAppleWatchTransactionData.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A858A0E237EE89B0097A7B5 /* BRAppleWatchTransactionData.m */; }; C9D2C7C02A320AA000D15901 /* HomeHeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F4520A2A1209D100825057 /* HomeHeaderModel.swift */; }; - C9D2C7C22A320AA000D15901 /* BuildFile in Sources */ = {isa = PBXBuildFile; }; + C9D2C7C22A320AA000D15901 /* (null) in Sources */ = {isa = PBXBuildFile; }; C9D2C7C32A320AA000D15901 /* DWDPRegistrationStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AFF01DA243F4559003718DC /* DWDPRegistrationStatus.m */; }; C9D2C7C42A320AA000D15901 /* CurrencyExchanger_Objc.m in Sources */ = {isa = PBXBuildFile; fileRef = 472D13EC299E6579006903F1 /* CurrencyExchanger_Objc.m */; }; C9D2C7C62A320AA000D15901 /* Tools.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471DD1B7290A92CD00E030C8 /* Tools.swift */; }; C9D2C7C72A320AA000D15901 /* BuySellPortalModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 478A2C7028DC554200AD1420 /* BuySellPortalModel.swift */; }; C9D2C7C92A320AA000D15901 /* BuyDashViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 478C98252942DC2700FAA0F0 /* BuyDashViewController.swift */; }; C9D2C7CA2A320AA000D15901 /* DWModalDismissalAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A0C69CF23143435001B8C90 /* DWModalDismissalAnimation.m */; }; - C9D2C7CB2A320AA000D15901 /* BuildFile in Sources */ = {isa = PBXBuildFile; }; + C9D2C7CB2A320AA000D15901 /* (null) in Sources */ = {isa = PBXBuildFile; }; C9D2C7CD2A320AA000D15901 /* UIViewController+DashWallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47CDEECD294A3CF2008AE06D /* UIViewController+DashWallet.swift */; }; C9D2C7CE2A320AA000D15901 /* CrowdNodeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 470617D5299A671900DCC667 /* CrowdNodeCell.swift */; }; C9D2C7CF2A320AA000D15901 /* MerchantListLocationOffCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47AE8BD128C1305E00490F5E /* MerchantListLocationOffCell.swift */; }; @@ -1543,7 +1546,7 @@ C9D2C8472A320AA000D15901 /* DWBaseTransactionListDataProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A913EAD23A7AC86006A2A59 /* DWBaseTransactionListDataProvider.m */; }; C9D2C8482A320AA000D15901 /* CoinbaseTransactionsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F6EDFA828C896BC000427E7 /* CoinbaseTransactionsRequest.swift */; }; C9D2C8492A320AA000D15901 /* DWAppRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A9CEBAC22E1DA4000A50237 /* DWAppRootViewController.m */; }; - C9D2C84A2A320AA000D15901 /* BuildFile in Sources */ = {isa = PBXBuildFile; }; + C9D2C84A2A320AA000D15901 /* (null) in Sources */ = {isa = PBXBuildFile; }; C9D2C84B2A320AA000D15901 /* UITableView+DashWallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F005FE297164600029EB10 /* UITableView+DashWallet.swift */; }; C9D2C84C2A320AA000D15901 /* TransferAmountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C661B128FDC72700028A8D /* TransferAmountViewController.swift */; }; C9D2C84D2A320AA000D15901 /* ShortcutCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94F5E8D29D404850034FD57 /* ShortcutCell.swift */; }; @@ -1566,7 +1569,7 @@ C9D2C8622A320AA000D15901 /* BackupInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F42FB129DD5141001BC549 /* BackupInfoViewController.swift */; }; C9D2C8652A320AA000D15901 /* DWCaptureSessionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A7A7BAD234770C900451078 /* DWCaptureSessionManager.m */; }; C9D2C8662A320AA000D15901 /* DWDataMigrationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A11F59E2194BD6200E7B563 /* DWDataMigrationManager.m */; }; - C9D2C86A2A320AA000D15901 /* BuildFile in Sources */ = {isa = PBXBuildFile; }; + C9D2C86A2A320AA000D15901 /* (null) in Sources */ = {isa = PBXBuildFile; }; C9D2C86B2A320AA000D15901 /* AmountPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472D13E5299E3C81006903F1 /* AmountPreviewView.swift */; }; C9D2C86C2A320AA000D15901 /* ModalNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4759D513292FEFFB002F20DC /* ModalNavigationController.swift */; }; C9D2C86E2A320AA000D15901 /* TransferAmountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47A50F3A2913BC0900C70123 /* TransferAmountModel.swift */; }; @@ -1599,14 +1602,12 @@ C9D2C8952A320AA000D15901 /* ConvertCryptoOrderPreviewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4751CACF2970224D00F63AC4 /* ConvertCryptoOrderPreviewModel.swift */; }; C9D2C8972A320AA000D15901 /* RatesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47A2E3A82972B15F0032A63B /* RatesProvider.swift */; }; C9D2C8982A320AA000D15901 /* CBAuth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47A2A2E8293E612900938DB7 /* CBAuth.swift */; }; - C9D2C8992A320AA000D15901 /* BuildFile in Sources */ = {isa = PBXBuildFile; }; + C9D2C8992A320AA000D15901 /* (null) in Sources */ = {isa = PBXBuildFile; }; C9D2C89A2A320AA000D15901 /* CoinbaseCreateAddressesRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F6EDFAE28C896BC000427E7 /* CoinbaseCreateAddressesRequest.swift */; }; C9D2C89B2A320AA000D15901 /* DWImportWalletInfoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A10EB342358996700C38B61 /* DWImportWalletInfoViewController.m */; }; C9D2C89D2A320AA000D15901 /* SyncingAlertContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F451ED2A0BF1F500825057 /* SyncingAlertContentView.swift */; }; C9D2C89E2A320AA000D15901 /* AddressUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471A2604289ACD5C0056B7B2 /* AddressUserInfo.swift */; }; C9D2C8A02A320AA000D15901 /* SendCoinsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E47BAA28EB38510097CFA0 /* SendCoinsService.swift */; }; - FE5CA1E0000000000000A003 /* ScaleToFitWidth.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE5CA1E0000000000000A001 /* ScaleToFitWidth.swift */; }; - 51BA2EA12F0B2E0100A1B201 /* MayaSwapPendingGate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51BA2E9F2F0B2E0100A1B201 /* MayaSwapPendingGate.swift */; }; C9D2C8A12A320AA000D15901 /* ShortcutAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94F5E8929D3FCCF0034FD57 /* ShortcutAction.swift */; }; C9D2C8A22A320AA000D15901 /* DWModalChevronView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A0C69DF231556D6001B8C90 /* DWModalChevronView.m */; }; C9D2C8A32A320AA000D15901 /* DWBaseLegacyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A58815821A5906C00FD4D2C /* DWBaseLegacyViewController.m */; }; @@ -1652,7 +1653,7 @@ C9D2C8DD2A320AA000D15901 /* AtmDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47AE8BD528C1305E00490F5E /* AtmDataProvider.swift */; }; C9D2C8DE2A320AA000D15901 /* GettingStartedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110C67942921147F006B580C /* GettingStartedViewController.swift */; }; C9D2C8DF2A320AA000D15901 /* NetworkUnavailableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 477A963D292CD27D0013605B /* NetworkUnavailableView.swift */; }; - C9D2C8E02A320AA000D15901 /* BuildFile in Sources */ = {isa = PBXBuildFile; }; + C9D2C8E02A320AA000D15901 /* (null) in Sources */ = {isa = PBXBuildFile; }; C9D2C8E12A320AA000D15901 /* DWLockScreenViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A63004D2328F37C00827825 /* DWLockScreenViewController.m */; }; C9D2C8E22A320AA000D15901 /* UpholdTransferViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4789D2302981069700BAFEFA /* UpholdTransferViewController.swift */; }; C9D2C8E32A320AA000D15901 /* DWVerifySeedPhraseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AD1CE8322DC9B5D00C99324 /* DWVerifySeedPhraseViewController.m */; }; @@ -1711,7 +1712,7 @@ C9D2C9272A320AA000D15901 /* SyncView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2A4E531922EA382B00E5168A /* SyncView.xib */; }; C9D2C9292A320AA000D15901 /* BackupInfoItemView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C9F42FB529DD8702001BC549 /* BackupInfoItemView.xib */; }; C9D2C92A2A320AA000D15901 /* explore.db in Resources */ = {isa = PBXBuildFile; fileRef = 47AE8BAF28BFF28400490F5E /* explore.db */; }; - C9D2C92B2A320AA000D15901 /* BuildFile in Resources */ = {isa = PBXBuildFile; }; + C9D2C92B2A320AA000D15901 /* (null) in Resources */ = {isa = PBXBuildFile; }; C9D2C92C2A320AA000D15901 /* Coinbase.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0F3693812919A70B007F4E91 /* Coinbase.storyboard */; }; C9D2C92E2A320AA000D15901 /* ImportWalletInfo.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2A10EB3D2358BDA500C38B61 /* ImportWalletInfo.storyboard */; }; C9D2C92F2A320AA000D15901 /* ReceiveContentView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C9F42FAC29DC115A001BC549 /* ReceiveContentView.xib */; }; @@ -1774,8 +1775,6 @@ CC0000182DUMMYID001234567 /* PiggyCardsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0000092DUMMYID001234567 /* PiggyCardsRepository.swift */; }; CC0000192DUMMYID001234567 /* PiggyCardsTokenService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0000102DUMMYID001234567 /* PiggyCardsTokenService.swift */; }; CC0000202DUMMYID001234567 /* PiggyCardsTokenService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0000102DUMMYID001234567 /* PiggyCardsTokenService.swift */; }; - D0D3F0F33D9F162622F0A6E5 /* DashBalanceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF95E0E0B636AFB810D62116 /* DashBalanceView.swift */; }; - DA38F1C5CD32A52891D02D0E /* MayaConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7708BBFDD14AFF237FB72D71 /* MayaConstants.swift */; }; CNR0000012FF100000000001 /* CrowdNodeBalanceReminder.swift in Sources */ = {isa = PBXBuildFile; fileRef = CNR0000072FF100000000001 /* CrowdNodeBalanceReminder.swift */; }; CNR0000022FF100000000001 /* CrowdNodeBalanceReminder.swift in Sources */ = {isa = PBXBuildFile; fileRef = CNR0000072FF100000000001 /* CrowdNodeBalanceReminder.swift */; }; CNR0000032FF100000000001 /* CrowdNodeBalanceReminderSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = CNR0000082FF100000000001 /* CrowdNodeBalanceReminderSheet.swift */; }; @@ -1784,7 +1783,21 @@ CNR0000062FF100000000001 /* CrowdNodeBalanceReminderBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = CNR0000092FF100000000001 /* CrowdNodeBalanceReminderBanner.swift */; }; CNR0000112FF100000000001 /* CrowdNodeWithdrawalRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CNR0000132FF100000000001 /* CrowdNodeWithdrawalRouter.swift */; }; CNR0000122FF100000000001 /* CrowdNodeWithdrawalRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CNR0000132FF100000000001 /* CrowdNodeWithdrawalRouter.swift */; }; - DE3A167A235B79D705C0A962 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; }; + D0D3F0F33D9F162622F0A6E5 /* DashBalanceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF95E0E0B636AFB810D62116 /* DashBalanceView.swift */; }; + D5A0C001D5A0C001D5A0C001 /* DashSpendAmountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B001D5A0B001D5A0B001 /* DashSpendAmountView.swift */; }; + D5A0C002D5A0C002D5A0C002 /* DashSpendDenominationRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B002D5A0B002D5A0B002 /* DashSpendDenominationRow.swift */; }; + D5A0C003D5A0C003D5A0C003 /* DashSpendFixedContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B003D5A0B003D5A0B003 /* DashSpendFixedContent.swift */; }; + D5A0C004D5A0C004D5A0C004 /* DashSpendFlexibleContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B004D5A0B004D5A0B004 /* DashSpendFlexibleContent.swift */; }; + D5A0C005D5A0C005D5A0C005 /* DashSpendMultiplePanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B005D5A0B005D5A0B005 /* DashSpendMultiplePanel.swift */; }; + D5A0C006D5A0C006D5A0C006 /* DashSpendPayIntro.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B006D5A0B006D5A0B006 /* DashSpendPayIntro.swift */; }; + D5A0C007D5A0C007D5A0C007 /* DashSpendSinglePanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0B007D5A0B007D5A0B007 /* DashSpendSinglePanel.swift */; }; + D6C0C001D6C0C001D6C0C001 /* GiftCardDetailsInfoCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C0B001D6C0B001D6C0B001 /* GiftCardDetailsInfoCard.swift */; }; + D6C0C002D6C0C002D6C0C002 /* GiftCardDetailsMerchantHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C0B002D6C0B002D6C0B002 /* GiftCardDetailsMerchantHeader.swift */; }; + D6C0C003D6C0C003D6C0C003 /* GiftCardPurchaseSelectionSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C0B003D6C0B003D6C0B003 /* GiftCardPurchaseSelectionSheet.swift */; }; + D6C0C004D6C0C004D6C0C004 /* GiftCardDetailsPoweredBySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C0B004D6C0B004D6C0B004 /* GiftCardDetailsPoweredBySection.swift */; }; + D6C0C005D6C0C005D6C0C005 /* GiftCardDetailsHowToUseSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C0B005D6C0B005D6C0B005 /* GiftCardDetailsHowToUseSection.swift */; }; + DA38F1C5CD32A52891D02D0E /* MayaConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7708BBFDD14AFF237FB72D71 /* MayaConstants.swift */; }; + DE3A167A235B79D705C0A962 /* (null) in Frameworks */ = {isa = PBXBuildFile; }; E5767AEAEF7C4921886E915A /* BuySellPortalScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B94B3697D7742BFA991B5CC /* BuySellPortalScreen.swift */; }; E88FE13A3079496C9A5EA8D4 /* MayaCoinIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20554F992205428BA790F6CF /* MayaCoinIconView.swift */; }; EC26E6EBECE04736903F77A2 /* DSAccount+SpentInputCheck.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BC16BFBFFFA4E488C09164D /* DSAccount+SpentInputCheck.m */; }; @@ -1809,8 +1822,8 @@ FBF3F42D1E42B00C00C7248E /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBF3F42C1E42B00C00C7248E /* UIKit.framework */; }; FBF3F42F1E42B01E00C7248E /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBF3F42E1E42B01E00C7248E /* CoreGraphics.framework */; }; FBF3F4311E42B02800C7248E /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBF3F4301E42B02800C7248E /* ImageIO.framework */; }; - FF0000012DUMMYID001234567 /* PiggyCardsConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF0000042DUMMYID001234567 /* PiggyCardsConstants.swift */; }; - FF0000022DUMMYID001234567 /* PiggyCardsConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF0000042DUMMYID001234567 /* PiggyCardsConstants.swift */; }; + FF0000012DUMMYID001234567 /* DashSpend/PiggyCardsConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF0000042DUMMYID001234567 /* DashSpend/PiggyCardsConstants.swift */; }; + FF0000022DUMMYID001234567 /* DashSpend/PiggyCardsConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF0000042DUMMYID001234567 /* DashSpend/PiggyCardsConstants.swift */; }; FF0000052DUMMYID001234567 /* PiggyCardsModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF0000062DUMMYID001234567 /* PiggyCardsModels.swift */; }; FF0000072DUMMYID001234567 /* PiggyCardsModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF0000062DUMMYID001234567 /* PiggyCardsModels.swift */; }; FF0000082DUMMYID001234567 /* BarcodeScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF0000092DUMMYID001234567 /* BarcodeScanner.swift */; }; @@ -1977,9 +1990,7 @@ 11BD738028E7356100A34022 /* CrowdNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdNode.swift; sourceTree = ""; }; 11E47BA728EAE7AD0097CFA0 /* CrowdNodeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdNodeModel.swift; sourceTree = ""; }; 11E47BAA28EB38510097CFA0 /* SendCoinsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendCoinsService.swift; sourceTree = ""; }; - FE5CA1E0000000000000A001 /* ScaleToFitWidth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScaleToFitWidth.swift; path = "DashWallet/Sources/UI/SwiftUI Components/Geometry Readers/ScaleToFitWidth.swift"; sourceTree = SOURCE_ROOT; }; 11E47BAC28EB3A7D0097CFA0 /* CrowdNode+Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CrowdNode+Constants.swift"; sourceTree = ""; }; - 51BA2E9F2F0B2E0100A1B201 /* MayaSwapPendingGate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MayaSwapPendingGate.swift; sourceTree = ""; }; 11ED906A29681773003784F9 /* StakingInfoDialogController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingInfoDialogController.swift; sourceTree = ""; }; 180C7A2E60359C7F8FB7B918 /* Pods-DashWalletScreenshotsUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DashWalletScreenshotsUITests.release.xcconfig"; path = "Target Support Files/Pods-DashWalletScreenshotsUITests/Pods-DashWalletScreenshotsUITests.release.xcconfig"; sourceTree = ""; }; 1940CA64E8FD6DDD0CFC14A2 /* libPods-DashWalletTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-DashWalletTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2668,11 +2679,10 @@ 51A57C022FBB5A0000FB4097 /* MayaTransactionSuccessView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MayaTransactionSuccessView.swift; sourceTree = ""; }; 51A57C032FBB5A0000FB4097 /* MayaTransactionFailureView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MayaTransactionFailureView.swift; sourceTree = ""; }; 51A57C082FBB5A0000FB4097 /* MayaTransactionPendingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MayaTransactionPendingView.swift; sourceTree = ""; }; + 51BA2E9F2F0B2E0100A1B201 /* MayaSwapPendingGate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MayaSwapPendingGate.swift; sourceTree = ""; }; 51F0D10030BF97A900B27E11 /* ExclamationIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExclamationIcon.swift; sourceTree = ""; }; 51F0D10330BF98BA00B27E11 /* ArrowDownIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrowDownIcon.swift; sourceTree = ""; }; 52B5469F5588395FA0668C4B /* MayaTransactionStatusHostingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MayaTransactionStatusHostingController.swift; sourceTree = ""; }; - 75DFA10175DFA10175DFA101 /* DashStepper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashStepper.swift; sourceTree = ""; }; - 75DFA10275DFA10275DFA102 /* SegmentedControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegmentedControl.swift; sourceTree = ""; }; 5CBC0F417B9E8DE631F9DE2A /* Pods-DashWalletTests.testnet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DashWalletTests.testnet.xcconfig"; path = "Target Support Files/Pods-DashWalletTests/Pods-DashWalletTests.testnet.xcconfig"; sourceTree = ""; }; 62613C0D937CA301FBBF2356 /* Pods-dashpay.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dashpay.debug.xcconfig"; path = "Target Support Files/Pods-dashpay/Pods-dashpay.debug.xcconfig"; sourceTree = ""; }; 708B9F2B4B1E4C31B5010CDF /* RadioButtonRow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RadioButtonRow.swift; path = "DashWallet/Sources/UI/SwiftUI Components/RadioButtonRow.swift"; sourceTree = ""; }; @@ -2730,11 +2740,11 @@ 753FDBED2AECF52B0005EEC3 /* UsernameVoting.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = UsernameVoting.storyboard; sourceTree = ""; }; 754495DC2AE91B6300492817 /* GroupedRequestCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupedRequestCell.swift; sourceTree = ""; }; 754495DE2AE91D3500492817 /* UsernameRequestCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsernameRequestCell.swift; sourceTree = ""; }; - 754565C42DAA52A000DA4E8E /* CTXSpendAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/CTX/CTXSpendAPI.swift; sourceTree = ""; }; - 754565C52DAA52A000DA4E8E /* CTXSpendEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/CTX/CTXSpendEndpoint.swift; sourceTree = ""; }; - 754565C72DAA52A000DA4E8E /* CTXSpendRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/CTX/CTXSpendRepository.swift; sourceTree = ""; }; + 754565C42DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/CTX/CTXSpendAPI.swift; sourceTree = ""; }; + 754565C52DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/CTX/CTXSpendEndpoint.swift; sourceTree = ""; }; + 754565C72DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/CTX/CTXSpendRepository.swift; sourceTree = ""; }; 754565D02DABA5EB00DA4E8E /* MerchantTypesDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MerchantTypesDialog.swift; sourceTree = ""; }; - 7545ED522DA91A2F0075F45C /* CTXConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/CTXConstants.swift; sourceTree = ""; }; + 7545ED522DA91A2F0075F45C /* DashSpend/CTXConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/CTXConstants.swift; sourceTree = ""; }; 7545ED562DA91AEA0075F45C /* DashSpendUserAuthViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpendUserAuthViewModel.swift; sourceTree = ""; }; 7545ED5C2DA91F590075F45C /* DashSpendTermsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpendTermsScreen.swift; sourceTree = ""; }; 7545ED5F2DA91FC60075F45C /* NumericKeyboardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumericKeyboardView.swift; sourceTree = ""; }; @@ -2801,7 +2811,7 @@ 759AFDE22CC67E89007072D2 /* VotingInfoScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VotingInfoScreen.swift; sourceTree = ""; }; 759C8F9E2B593589004B1305 /* CrowdNodeAPYView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdNodeAPYView.swift; sourceTree = ""; }; 75A0A3F22CA7DBCF003ED48B /* TimeUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeUtils.swift; sourceTree = ""; }; - 75A2F3022DE48C860046BE17 /* CTXSpendTokenService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/CTX/CTXSpendTokenService.swift; sourceTree = ""; }; + 75A2F3022DE48C860046BE17 /* DashSpend/CTX/CTXSpendTokenService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/CTX/CTXSpendTokenService.swift; sourceTree = ""; }; 75A8C1632AE5725C0042256E /* UsernameRequestsDAO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsernameRequestsDAO.swift; sourceTree = ""; }; 75A8C1662AE5734A0042256E /* UsernameRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsernameRequest.swift; sourceTree = ""; }; 75A8C1682AE6A1AC0042256E /* VotingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VotingViewModel.swift; sourceTree = ""; }; @@ -2840,15 +2850,12 @@ 75D9EBC12DE5CD9C009416A2 /* GiftCardsDAO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiftCardsDAO.swift; sourceTree = ""; }; 75D9EBC42DE5CE14009416A2 /* GiftCardDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiftCardDetailsView.swift; sourceTree = ""; }; 75D9EBC52DE5CE14009416A2 /* GiftCardDetailsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiftCardDetailsViewModel.swift; sourceTree = ""; }; - D6C0B001D6C0B001D6C0B001 /* GiftCardDetailsInfoCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiftCardDetailsInfoCard.swift; sourceTree = ""; }; - D6C0B002D6C0B002D6C0B002 /* GiftCardDetailsMerchantHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiftCardDetailsMerchantHeader.swift; sourceTree = ""; }; - D6C0B003D6C0B003D6C0B003 /* GiftCardPurchaseSelectionSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiftCardPurchaseSelectionSheet.swift; sourceTree = ""; }; - D6C0B004D6C0B004D6C0B004 /* GiftCardDetailsPoweredBySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiftCardDetailsPoweredBySection.swift; sourceTree = ""; }; - D6C0B005D6C0B005D6C0B005 /* GiftCardDetailsHowToUseSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiftCardDetailsHowToUseSection.swift; sourceTree = ""; }; 75DE02411B0EB79A0027FF08 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; 75DE02491B0EB7C80027FF08 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; 75DE024D1B0EB7FC0027FF08 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; 75DE02511B0EB8030027FF08 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; lineEnding = 0; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; + 75DFA10175DFA10175DFA101 /* DashStepper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashStepper.swift; sourceTree = ""; }; + 75DFA10275DFA10275DFA102 /* SegmentedControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegmentedControl.swift; sourceTree = ""; }; 75DFAF2D2CF7066200CCA68B /* VoteButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoteButton.swift; sourceTree = ""; }; 75E2F3C72AA4CF1900C3B458 /* Topper-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Topper-Info.plist"; sourceTree = ""; }; 75E2F3C92AA4D1B900C3B458 /* Topper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Topper.swift; sourceTree = ""; }; @@ -2890,7 +2897,7 @@ 9EC1F4DB87C442BEABDF0DB2 /* DerivationPathKeysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DerivationPathKeysView.swift; sourceTree = ""; }; AA00000028D9A3DB00223B77 /* BuySellPortalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuySellPortalView.swift; sourceTree = ""; }; AA0000032DUMMYID001234567 /* AddProviderToGiftCardsTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddProviderToGiftCardsTable.swift; sourceTree = ""; }; - AA0000062DUMMYID001234567 /* GiftCardProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/GiftCardProvider.swift; sourceTree = ""; }; + AA0000062DUMMYID001234567 /* DashSpend/GiftCardProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/GiftCardProvider.swift; sourceTree = ""; }; AA0001012AA9F58E00A1B201 /* MayaPortalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MayaPortalView.swift; sourceTree = ""; }; AA0001042AA9F58E00A1B202 /* MayaPortalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MayaPortalViewController.swift; sourceTree = ""; }; AA0002012BA0F58E00A1B301 /* MayaCryptoCurrency.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MayaCryptoCurrency.swift; sourceTree = ""; }; @@ -2941,9 +2948,9 @@ BAE12BE61B2DEE7F00895CC5 /* NotificationCenter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NotificationCenter.framework; path = System/Library/Frameworks/NotificationCenter.framework; sourceTree = SDKROOT; }; BAE12BEA1B2DEE7F00895CC5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; BAE12C051B2DEEF700895CC5 /* DWTodayViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DWTodayViewController.m; sourceTree = ""; }; - BB0000072DUMMYID001234567 /* DashSpendError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/DashSpendError.swift; sourceTree = ""; }; - BB0000082DUMMYID001234567 /* DashSpendRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/DashSpendRepository.swift; sourceTree = ""; }; - BB0000092DUMMYID001234567 /* DashSpendRepositoryFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/DashSpendRepositoryFactory.swift; sourceTree = ""; }; + BB0000072DUMMYID001234567 /* DashSpend/DashSpendError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/DashSpendError.swift; sourceTree = ""; }; + BB0000082DUMMYID001234567 /* DashSpend/DashSpendRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/DashSpendRepository.swift; sourceTree = ""; }; + BB0000092DUMMYID001234567 /* DashSpend/DashSpendRepositoryFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/DashSpendRepositoryFactory.swift; sourceTree = ""; }; C0D1A08496F925D17031493E /* OrderPreviewFeeRow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = OrderPreviewFeeRow.swift; sourceTree = ""; }; C1A0B2C3D4E5F60718293A01 /* ShortcutsBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsBarView.swift; sourceTree = ""; }; C3DAD266246AA6F10001624F /* DWScreenshotWarningViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DWScreenshotWarningViewController.h; sourceTree = ""; }; @@ -3394,13 +3401,6 @@ C9F452002A0CE6C900825057 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; C9F452072A11F28600825057 /* SyncModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncModel.swift; sourceTree = ""; }; C9F4520A2A1209D100825057 /* HomeHeaderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeHeaderModel.swift; sourceTree = ""; }; - D5A0B001D5A0B001D5A0B001 /* DashSpendAmountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpendAmountView.swift; sourceTree = ""; }; - D5A0B002D5A0B002D5A0B002 /* DashSpendDenominationRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpendDenominationRow.swift; sourceTree = ""; }; - D5A0B003D5A0B003D5A0B003 /* DashSpendFixedContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpendFixedContent.swift; sourceTree = ""; }; - D5A0B004D5A0B004D5A0B004 /* DashSpendFlexibleContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpendFlexibleContent.swift; sourceTree = ""; }; - D5A0B005D5A0B005D5A0B005 /* DashSpendMultiplePanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpendMultiplePanel.swift; sourceTree = ""; }; - D5A0B006D5A0B006D5A0B006 /* DashSpendPayIntro.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpendPayIntro.swift; sourceTree = ""; }; - D5A0B007D5A0B007D5A0B007 /* DashSpendSinglePanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpendSinglePanel.swift; sourceTree = ""; }; C9FAABB42AB793CE00878224 /* BuySellPortal.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = BuySellPortal.storyboard; sourceTree = ""; }; C9FAABB62AB799AE00878224 /* UpholdPortalModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpholdPortalModel.swift; sourceTree = ""; }; CC0000062DUMMYID001234567 /* PiggyCardsAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiggyCardsAPI.swift; sourceTree = ""; }; @@ -3413,6 +3413,18 @@ CNR0000092FF100000000001 /* CrowdNodeBalanceReminderBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdNodeBalanceReminderBanner.swift; sourceTree = ""; }; CNR0000132FF100000000001 /* CrowdNodeWithdrawalRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdNodeWithdrawalRouter.swift; sourceTree = ""; }; D53435DCAF024BC82E0247F3 /* ImportPrivateKeySheet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ImportPrivateKeySheet.swift; sourceTree = ""; }; + D5A0B001D5A0B001D5A0B001 /* DashSpendAmountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpendAmountView.swift; sourceTree = ""; }; + D5A0B002D5A0B002D5A0B002 /* DashSpendDenominationRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpendDenominationRow.swift; sourceTree = ""; }; + D5A0B003D5A0B003D5A0B003 /* DashSpendFixedContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpendFixedContent.swift; sourceTree = ""; }; + D5A0B004D5A0B004D5A0B004 /* DashSpendFlexibleContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpendFlexibleContent.swift; sourceTree = ""; }; + D5A0B005D5A0B005D5A0B005 /* DashSpendMultiplePanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpendMultiplePanel.swift; sourceTree = ""; }; + D5A0B006D5A0B006D5A0B006 /* DashSpendPayIntro.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpendPayIntro.swift; sourceTree = ""; }; + D5A0B007D5A0B007D5A0B007 /* DashSpendSinglePanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpendSinglePanel.swift; sourceTree = ""; }; + D6C0B001D6C0B001D6C0B001 /* GiftCardDetailsInfoCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiftCardDetailsInfoCard.swift; sourceTree = ""; }; + D6C0B002D6C0B002D6C0B002 /* GiftCardDetailsMerchantHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiftCardDetailsMerchantHeader.swift; sourceTree = ""; }; + D6C0B003D6C0B003D6C0B003 /* GiftCardPurchaseSelectionSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiftCardPurchaseSelectionSheet.swift; sourceTree = ""; }; + D6C0B004D6C0B004D6C0B004 /* GiftCardDetailsPoweredBySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiftCardDetailsPoweredBySection.swift; sourceTree = ""; }; + D6C0B005D6C0B005D6C0B005 /* GiftCardDetailsHowToUseSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiftCardDetailsHowToUseSection.swift; sourceTree = ""; }; D99130732DE8F2E95F635F6B /* MayaConvertCardRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MayaConvertCardRow.swift; sourceTree = ""; }; E2A832899A499C24C7A43E47 /* Pods-WatchApp Extension.testnet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WatchApp Extension.testnet.xcconfig"; path = "Target Support Files/Pods-WatchApp Extension/Pods-WatchApp Extension.testnet.xcconfig"; sourceTree = ""; }; E83D8CEAFF69B6D666C02116 /* Pods-WatchApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WatchApp.release.xcconfig"; path = "Target Support Files/Pods-WatchApp/Pods-WatchApp.release.xcconfig"; sourceTree = ""; }; @@ -3460,7 +3472,7 @@ FBF3F42C1E42B00C00C7248E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; FBF3F42E1E42B01E00C7248E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; FBF3F4301E42B02800C7248E /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; }; - FF0000042DUMMYID001234567 /* PiggyCardsConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/PiggyCardsConstants.swift; sourceTree = ""; }; + FF0000042DUMMYID001234567 /* DashSpend/PiggyCardsConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashSpend/PiggyCardsConstants.swift; sourceTree = ""; }; FF0000062DUMMYID001234567 /* PiggyCardsModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiggyCardsModels.swift; sourceTree = ""; }; FF0000092DUMMYID001234567 /* BarcodeScanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarcodeScanner.swift; sourceTree = ""; }; GG0000032DUMMYID001234567 /* GeoRestrictionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoRestrictionService.swift; sourceTree = ""; }; @@ -3470,39 +3482,9 @@ /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ - 5151CDF22F929C2300F0A604 /* Geometry Readers */ = { - isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - ); - explicitFileTypes = { - }; - explicitFolders = ( - ); - path = "Geometry Readers"; - sourceTree = ""; - }; - 5151CDF62F929D3F00F0A604 /* ScrollViews */ = { - isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - ); - explicitFileTypes = { - }; - explicitFolders = ( - ); - path = ScrollViews; - sourceTree = ""; - }; - 51DFA7FB2FA8EAF2001EDB3A /* Components */ = { - isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - ); - explicitFileTypes = { - }; - explicitFolders = ( - ); - path = Components; - sourceTree = ""; - }; + 5151CDF22F929C2300F0A604 /* Geometry Readers */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = "Geometry Readers"; sourceTree = ""; }; + 5151CDF62F929D3F00F0A604 /* ScrollViews */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = ScrollViews; sourceTree = ""; }; + 51DFA7FB2FA8EAF2001EDB3A /* Components */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Components; sourceTree = ""; }; /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ @@ -3538,8 +3520,8 @@ 222E7F561C46E9B8009AB45D /* Security.framework in Frameworks */, 222040C61C1A1940005CE1C3 /* WebKit.framework in Frameworks */, 22B6A4481C0E963900673913 /* libbz2.tbd in Frameworks */, - DE3A167A235B79D705C0A962 /* BuildFile in Frameworks */, - AEAE60406265A73AFD573FD1 /* BuildFile in Frameworks */, + DE3A167A235B79D705C0A962 /* (null) in Frameworks */, + AEAE60406265A73AFD573FD1 /* (null) in Frameworks */, 39A9FD561F6418568F3FC109 /* libPods-dashwallet.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3548,7 +3530,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 19BF3F10240A082811AAC1EB /* BuildFile in Frameworks */, + 19BF3F10240A082811AAC1EB /* (null) in Frameworks */, B059B6E200A57A699E6EED84 /* libPods-DashWalletTests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3582,6 +3564,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 153C3E3D30BB4DB2A63DAD87 /* DashUIKit in Frameworks */, C9D2C8F62A320AA000D15901 /* libDashSync.a in Frameworks */, C9D2C8F72A320AA000D15901 /* CoreNFC.framework in Frameworks */, C9D2C8F82A320AA000D15901 /* BackgroundTasks.framework in Frameworks */, @@ -5480,7 +5463,6 @@ 472D13E2299E23B7006903F1 /* BalanceNotifier.swift */, 51BA2E9F2F0B2E0100A1B201 /* MayaSwapPendingGate.swift */, 11E47BAA28EB38510097CFA0 /* SendCoinsService.swift */, - FE5CA1E0000000000000A001 /* ScaleToFitWidth.swift */, 09950CBE38F14286AC06BB78 /* DSAccount+SpentInputCheck.h */, 7BC16BFBFFFA4E488C09164D /* DSAccount+SpentInputCheck.m */, ); @@ -5993,9 +5975,9 @@ 47AE8B9628BFACE800490F5E /* Model */ = { isa = PBXGroup; children = ( - 7545ED522DA91A2F0075F45C /* CTXConstants.swift */, - AA0000062DUMMYID001234567 /* GiftCardProvider.swift */, - FF0000042DUMMYID001234567 /* PiggyCardsConstants.swift */, + 7545ED522DA91A2F0075F45C /* DashSpend/CTXConstants.swift */, + AA0000062DUMMYID001234567 /* DashSpend/GiftCardProvider.swift */, + FF0000042DUMMYID001234567 /* DashSpend/PiggyCardsConstants.swift */, 47AE8B9A28BFAD2000490F5E /* Entites */, 47AE8B9928BFAD0B00490F5E /* DAO */, ); @@ -6015,15 +5997,15 @@ isa = PBXGroup; children = ( FF0000092DUMMYID001234567 /* BarcodeScanner.swift */, - 75A2F3022DE48C860046BE17 /* CTXSpendTokenService.swift */, - 754565C42DAA52A000DA4E8E /* CTXSpendAPI.swift */, - 754565C52DAA52A000DA4E8E /* CTXSpendEndpoint.swift */, - 754565C72DAA52A000DA4E8E /* CTXSpendRepository.swift */, - BB0000072DUMMYID001234567 /* DashSpendError.swift */, - BB0000082DUMMYID001234567 /* DashSpendRepository.swift */, - BB0000092DUMMYID001234567 /* DashSpendRepositoryFactory.swift */, + 75A2F3022DE48C860046BE17 /* DashSpend/CTX/CTXSpendTokenService.swift */, + 754565C42DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendAPI.swift */, + 754565C52DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendEndpoint.swift */, + 754565C72DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendRepository.swift */, + BB0000072DUMMYID001234567 /* DashSpend/DashSpendError.swift */, + BB0000082DUMMYID001234567 /* DashSpend/DashSpendRepository.swift */, + BB0000092DUMMYID001234567 /* DashSpend/DashSpendRepositoryFactory.swift */, GG0000032DUMMYID001234567 /* GeoRestrictionService.swift */, - DD0000012DUMMYID001234567 /* PiggyCards */, + DD0000012DUMMYID001234567 /* DashSpend/PiggyCards */, 47AE8BAC28BFAE6700490F5E /* DWLocationManager.swift */, 47AE8BA828BFAE5800490F5E /* ExploreDatabaseSyncManager.swift */, ); @@ -6452,6 +6434,14 @@ path = Icons; sourceTree = ""; }; + 5185FF562FEE6D64001BA37E /* Recovered References */ = { + isa = PBXGroup; + children = ( + 51DFA7FB2FA8EAF2001EDB3A /* Components */, + ); + name = "Recovered References"; + sourceTree = ""; + }; 51A5774D2FBB3A7100FB4097 /* Components */ = { isa = PBXGroup; children = ( @@ -6540,42 +6530,6 @@ path = DashSpend; sourceTree = ""; }; - D5A0D000D5A0D000D5A0D000 /* Components */ = { - isa = PBXGroup; - children = ( - D5A0B001D5A0B001D5A0B001 /* DashSpendAmountView.swift */, - D5A0B002D5A0B002D5A0B002 /* DashSpendDenominationRow.swift */, - D5A0B003D5A0B003D5A0B003 /* DashSpendFixedContent.swift */, - D5A0B004D5A0B004D5A0B004 /* DashSpendFlexibleContent.swift */, - D5A0B005D5A0B005D5A0B005 /* DashSpendMultiplePanel.swift */, - D5A0B006D5A0B006D5A0B006 /* DashSpendPayIntro.swift */, - D5A0B007D5A0B007D5A0B007 /* DashSpendSinglePanel.swift */, - ); - path = Components; - sourceTree = ""; - }; - D6C0D000D6C0D000D6C0D000 /* GiftCardDetails */ = { - isa = PBXGroup; - children = ( - 75D9EBC42DE5CE14009416A2 /* GiftCardDetailsView.swift */, - 75D9EBC52DE5CE14009416A2 /* GiftCardDetailsViewModel.swift */, - D6C0D001D6C0D001D6C0D001 /* Components */, - ); - path = GiftCardDetails; - sourceTree = ""; - }; - D6C0D001D6C0D001D6C0D001 /* Components */ = { - isa = PBXGroup; - children = ( - D6C0B001D6C0B001D6C0B001 /* GiftCardDetailsInfoCard.swift */, - D6C0B002D6C0B002D6C0B002 /* GiftCardDetailsMerchantHeader.swift */, - D6C0B003D6C0B003D6C0B003 /* GiftCardPurchaseSelectionSheet.swift */, - D6C0B004D6C0B004D6C0B004 /* GiftCardDetailsPoweredBySection.swift */, - D6C0B005D6C0B005D6C0B005 /* GiftCardDetailsHowToUseSection.swift */, - ); - path = Components; - sourceTree = ""; - }; 7549BE552DEAECA5004F0BAF /* Tx Metadata */ = { isa = PBXGroup; children = ( @@ -6753,6 +6707,7 @@ 75D5F3BF191EC270004AB296 /* Products */, 708B9F2B4B1E4C31B5010CDF /* RadioButtonRow.swift */, 8AE9CD5705796B04FF0033B6 /* Pods */, + 5185FF562FEE6D64001BA37E /* Recovered References */, ); sourceTree = ""; wrapsLines = 0; @@ -8237,7 +8192,43 @@ path = BalanceReminder; sourceTree = ""; }; - DD0000012DUMMYID001234567 /* PiggyCards */ = { + D5A0D000D5A0D000D5A0D000 /* Components */ = { + isa = PBXGroup; + children = ( + D5A0B001D5A0B001D5A0B001 /* DashSpendAmountView.swift */, + D5A0B002D5A0B002D5A0B002 /* DashSpendDenominationRow.swift */, + D5A0B003D5A0B003D5A0B003 /* DashSpendFixedContent.swift */, + D5A0B004D5A0B004D5A0B004 /* DashSpendFlexibleContent.swift */, + D5A0B005D5A0B005D5A0B005 /* DashSpendMultiplePanel.swift */, + D5A0B006D5A0B006D5A0B006 /* DashSpendPayIntro.swift */, + D5A0B007D5A0B007D5A0B007 /* DashSpendSinglePanel.swift */, + ); + path = Components; + sourceTree = ""; + }; + D6C0D000D6C0D000D6C0D000 /* GiftCardDetails */ = { + isa = PBXGroup; + children = ( + 75D9EBC42DE5CE14009416A2 /* GiftCardDetailsView.swift */, + 75D9EBC52DE5CE14009416A2 /* GiftCardDetailsViewModel.swift */, + D6C0D001D6C0D001D6C0D001 /* Components */, + ); + path = GiftCardDetails; + sourceTree = ""; + }; + D6C0D001D6C0D001D6C0D001 /* Components */ = { + isa = PBXGroup; + children = ( + D6C0B001D6C0B001D6C0B001 /* GiftCardDetailsInfoCard.swift */, + D6C0B002D6C0B002D6C0B002 /* GiftCardDetailsMerchantHeader.swift */, + D6C0B003D6C0B003D6C0B003 /* GiftCardPurchaseSelectionSheet.swift */, + D6C0B004D6C0B004D6C0B004 /* GiftCardDetailsPoweredBySection.swift */, + D6C0B005D6C0B005D6C0B005 /* GiftCardDetailsHowToUseSection.swift */, + ); + path = Components; + sourceTree = ""; + }; + DD0000012DUMMYID001234567 /* DashSpend/PiggyCards */ = { isa = PBXGroup; children = ( CC0000062DUMMYID001234567 /* PiggyCardsAPI.swift */, @@ -8670,7 +8661,7 @@ C9D2C9272A320AA000D15901 /* SyncView.xib in Resources */, C9D2C9292A320AA000D15901 /* BackupInfoItemView.xib in Resources */, C9D2C92A2A320AA000D15901 /* explore.db in Resources */, - C9D2C92B2A320AA000D15901 /* BuildFile in Resources */, + C9D2C92B2A320AA000D15901 /* (null) in Resources */, C9D2C92C2A320AA000D15901 /* Coinbase.storyboard in Resources */, 5151C8C62F913BF100F0A604 /* Coinbase-Info.plist in Resources */, 5151C8C72F913BF100F0A604 /* ZenLedger-Info.plist in Resources */, @@ -9171,7 +9162,7 @@ C9F451EB2A0BF10B00825057 /* SyncingAlertViewController.swift in Sources */, 11B8449628F5B9F80082770C /* CrowdNodeResponse.swift in Sources */, 47AE8BB228BFF61A00490F5E /* FileManager+DashWallet.swift in Sources */, - 7545ED532DA91A2F0075F45C /* CTXConstants.swift in Sources */, + 7545ED532DA91A2F0075F45C /* DashSpend/CTXConstants.swift in Sources */, 47AE8BF228C1306000490F5E /* PointOfUseItemCell.swift in Sources */, 47083B3229892D770010AF71 /* DSTransaction+DashWallet.swift in Sources */, 751B61C82AE0EDD000D1C2EF /* CoinJoinLevelsViewController.swift in Sources */, @@ -9193,7 +9184,7 @@ 11AE3DD82997C599000856EE /* IsDefaultEmail.swift in Sources */, 516983A62FCAEF1300BA91A2 /* ErrorIllustration.swift in Sources */, 2A9FFF2A2233E60F00956D5F /* DWUpholdAccountObject.m in Sources */, - 75A2F3042DE48C860046BE17 /* CTXSpendTokenService.swift in Sources */, + 75A2F3042DE48C860046BE17 /* DashSpend/CTX/CTXSpendTokenService.swift in Sources */, 2A9FFE812230FF4700956D5F /* DWFormTableViewController.m in Sources */, C909614D29EFF7D600002D82 /* WalletKeysOverviewModel.swift in Sources */, 4751137528DAF28800223B77 /* UIAssembly.swift in Sources */, @@ -9524,10 +9515,10 @@ 7549BE582DEAECB8004F0BAF /* CustomIconMetadataProvider.swift in Sources */, 7549BE602DEAF628004F0BAF /* AddIconBitmapsTable.swift in Sources */, AA0000012DUMMYID001234567 /* AddProviderToGiftCardsTable.swift in Sources */, - AA0000042DUMMYID001234567 /* GiftCardProvider.swift in Sources */, - BB0000012DUMMYID001234567 /* DashSpendError.swift in Sources */, - BB0000032DUMMYID001234567 /* DashSpendRepository.swift in Sources */, - BB0000052DUMMYID001234567 /* DashSpendRepositoryFactory.swift in Sources */, + AA0000042DUMMYID001234567 /* DashSpend/GiftCardProvider.swift in Sources */, + BB0000012DUMMYID001234567 /* DashSpend/DashSpendError.swift in Sources */, + BB0000032DUMMYID001234567 /* DashSpend/DashSpendRepository.swift in Sources */, + BB0000052DUMMYID001234567 /* DashSpend/DashSpendRepositoryFactory.swift in Sources */, GG0000012DUMMYID001234567 /* GeoRestrictionService.swift in Sources */, CC0000112DUMMYID001234567 /* PiggyCardsAPI.swift in Sources */, CC0000132DUMMYID001234567 /* PiggyCardsCache.swift in Sources */, @@ -9537,7 +9528,7 @@ EE0000012DUMMYID001234567 /* POIDetailsViewModel.swift in Sources */, 51A577482FBB3A6000FB4097 /* OrderPreviewViewModel.swift in Sources */, EE0000042DUMMYID001234567 /* PercentageFormatter.swift in Sources */, - FF0000012DUMMYID001234567 /* PiggyCardsConstants.swift in Sources */, + FF0000012DUMMYID001234567 /* DashSpend/PiggyCardsConstants.swift in Sources */, FF0000052DUMMYID001234567 /* PiggyCardsModels.swift in Sources */, FF0000082DUMMYID001234567 /* BarcodeScanner.swift in Sources */, 2A8B9E6F2302A9C200FF8653 /* DWPasteboardAddressExtractor.m in Sources */, @@ -9555,14 +9546,14 @@ 2AD1CE8022DC92BF00C99324 /* NSString+DWTextSize.m in Sources */, 47AE8C0528C1F74A00490F5E /* PointOfUseListFiltersCell.swift in Sources */, 47AE8C1A28C6A21A00490F5E /* AllMerchantLocationsDataProvider.swift in Sources */, - 754565CC2DAA52A000DA4E8E /* CTXSpendAPI.swift in Sources */, + 754565CC2DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendAPI.swift in Sources */, 516983A32FCAEDEB00BA91A2 /* SuccessIllustration.swift in Sources */, 516983B12FCAEDEB00BA91A2 /* LoadingIllustration.swift in Sources */, 51F0D10430BF98BA00B27E11 /* ArrowDownIcon.swift in Sources */, 516983C22FCAEDEB00BA91A2 /* XmarkIcon.swift in Sources */, 51F0D10130BF97A900B27E11 /* ExclamationIcon.swift in Sources */, - 754565CE2DAA52A000DA4E8E /* CTXSpendRepository.swift in Sources */, - 754565CF2DAA52A000DA4E8E /* CTXSpendEndpoint.swift in Sources */, + 754565CE2DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendRepository.swift in Sources */, + 754565CF2DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendEndpoint.swift in Sources */, C9F451E52A0B986E00825057 /* MainTabbarController.swift in Sources */, 7545ED612DA91FC60075F45C /* NumericKeyboardView.swift in Sources */, 47B30D78290BFCA60080C326 /* NumberFormatter+DashWallet.swift in Sources */, @@ -9733,7 +9724,6 @@ 471A2605289ACD5C0056B7B2 /* AddressUserInfo.swift in Sources */, 51BA2EA02F0B2E0100A1B201 /* MayaSwapPendingGate.swift in Sources */, 11E47BAB28EB38510097CFA0 /* SendCoinsService.swift in Sources */, - FE5CA1E0000000000000A002 /* ScaleToFitWidth.swift in Sources */, EC26E6EBECE04736903F77A2 /* DSAccount+SpentInputCheck.m in Sources */, C94F5E8A29D3FCCF0034FD57 /* ShortcutAction.swift in Sources */, 2A0C69E0231556D6001B8C90 /* DWModalChevronView.m in Sources */, @@ -10036,7 +10026,7 @@ C943B31D2A408CED00AF23C5 /* DWUserProfileContainerView.m in Sources */, C9D2C6F02A320AA000D15901 /* UIImage+Utils.m in Sources */, C943B4BE2A40A54600AF23C5 /* DWGlobalMatchFailedHeaderView.m in Sources */, - 75A2F3032DE48C860046BE17 /* CTXSpendTokenService.swift in Sources */, + 75A2F3032DE48C860046BE17 /* DashSpend/CTX/CTXSpendTokenService.swift in Sources */, C943B4C22A40A54600AF23C5 /* BaseCollectionReusableView.m in Sources */, C9D2C6F22A320AA000D15901 /* DWSetupViewController.m in Sources */, C9D2C6F32A320AA000D15901 /* ExploreDatabaseConnection.swift in Sources */, @@ -10099,7 +10089,7 @@ 75A8C1672AE5734A0042256E /* UsernameRequest.swift in Sources */, C9D2C70D2A320AA000D15901 /* CBAccount.swift in Sources */, C9D2C70E2A320AA000D15901 /* Types.swift in Sources */, - C9D2C70F2A320AA000D15901 /* BuildFile in Sources */, + C9D2C70F2A320AA000D15901 /* (null) in Sources */, C943B33B2A408CED00AF23C5 /* DWUploadAvatarChildView.m in Sources */, C9D2C7112A320AA000D15901 /* Coinbase.swift in Sources */, C9D2C7122A320AA000D15901 /* SyncModel.swift in Sources */, @@ -10133,7 +10123,7 @@ C9D2C7252A320AA000D15901 /* SyncingActivityMonitor.swift in Sources */, 75EE38D82CBFE52E00845FFF /* ContactsPlaceholderViewController.swift in Sources */, C9D2C7262A320AA000D15901 /* EmptyUIView.swift in Sources */, - C9D2C7272A320AA000D15901 /* BuildFile in Sources */, + C9D2C7272A320AA000D15901 /* (null) in Sources */, C9D2C7282A320AA000D15901 /* DWQRScanModel.m in Sources */, C943B3292A408CED00AF23C5 /* DWExternalSourceViewController.m in Sources */, C9D2C72A2A320AA000D15901 /* SyncView.swift in Sources */, @@ -10156,20 +10146,20 @@ C9D2C7382A320AA000D15901 /* CoinbasePlaceBuyOrderRequest.swift in Sources */, C943B5262A40A54600AF23C5 /* DWDashPayAnimationView.m in Sources */, 753F75342DD0D42300D40DFE /* DashSpendPayScreen.swift in Sources */, - D6C0C001D6C0C001D6C0C001 /* GiftCardDetailsInfoCard.swift in Sources */, - D6C0C002D6C0C002D6C0C002 /* GiftCardDetailsMerchantHeader.swift in Sources */, - D6C0C003D6C0C003D6C0C003 /* GiftCardPurchaseSelectionSheet.swift in Sources */, - D6C0C004D6C0C004D6C0C004 /* GiftCardDetailsPoweredBySection.swift in Sources */, - D6C0C005D6C0C005D6C0C005 /* GiftCardDetailsHowToUseSection.swift in Sources */, - D5A0C003D5A0C003D5A0C003 /* DashSpendFixedContent.swift in Sources */, - D5A0C004D5A0C004D5A0C004 /* DashSpendFlexibleContent.swift in Sources */, - D5A0C001D5A0C001D5A0C001 /* DashSpendAmountView.swift in Sources */, - D5A0C002D5A0C002D5A0C002 /* DashSpendDenominationRow.swift in Sources */, - D5A0C005D5A0C005D5A0C005 /* DashSpendMultiplePanel.swift in Sources */, - D5A0C006D5A0C006D5A0C006 /* DashSpendPayIntro.swift in Sources */, - D5A0C007D5A0C007D5A0C007 /* DashSpendSinglePanel.swift in Sources */, - 75DFA00175DFA00175DFA001 /* DashStepper.swift in Sources */, - 75DFA00275DFA00275DFA002 /* SegmentedControl.swift in Sources */, + 5185FF482FEE6D64001BA37E /* GiftCardDetailsInfoCard.swift in Sources */, + 5185FF492FEE6D64001BA37E /* GiftCardDetailsMerchantHeader.swift in Sources */, + 5185FF4A2FEE6D64001BA37E /* GiftCardPurchaseSelectionSheet.swift in Sources */, + 5185FF4B2FEE6D64001BA37E /* GiftCardDetailsPoweredBySection.swift in Sources */, + 5185FF4C2FEE6D64001BA37E /* GiftCardDetailsHowToUseSection.swift in Sources */, + 5185FF4D2FEE6D64001BA37E /* DashSpendFixedContent.swift in Sources */, + 5185FF4E2FEE6D64001BA37E /* DashSpendFlexibleContent.swift in Sources */, + 5185FF4F2FEE6D64001BA37E /* DashSpendAmountView.swift in Sources */, + 5185FF502FEE6D64001BA37E /* DashSpendDenominationRow.swift in Sources */, + 5185FF512FEE6D64001BA37E /* DashSpendMultiplePanel.swift in Sources */, + 5185FF522FEE6D64001BA37E /* DashSpendPayIntro.swift in Sources */, + 5185FF532FEE6D64001BA37E /* DashSpendSinglePanel.swift in Sources */, + 5185FF542FEE6D64001BA37E /* DashStepper.swift in Sources */, + 5185FF552FEE6D64001BA37E /* SegmentedControl.swift in Sources */, C943B4EF2A40A54600AF23C5 /* DWUserProfileHeaderView.m in Sources */, C9D2C7392A320AA000D15901 /* CoinbaseAmount.swift in Sources */, C9D2C73B2A320AA000D15901 /* SendAmountModel.swift in Sources */, @@ -10211,7 +10201,7 @@ C9D2C74A2A320AA000D15901 /* ShortcutsView.swift in Sources */, C9D2C74B2A320AA000D15901 /* DWFormSectionModel.m in Sources */, 754C27CF2CC3C7AF00BA7B9F /* MixDashDialog.swift in Sources */, - C9D2C74C2A320AA000D15901 /* BuildFile in Sources */, + C9D2C74C2A320AA000D15901 /* (null) in Sources */, C9D2C74D2A320AA000D15901 /* CoinbasePlaceBuyOrderResponse.swift in Sources */, C9D2C74E2A320AA000D15901 /* ExploreMapView.swift in Sources */, D0D3F0F33D9F162622F0A6E5 /* DashBalanceView.swift in Sources */, @@ -10236,7 +10226,7 @@ C9D2C7552A320AA000D15901 /* DWPaymentInput.m in Sources */, C9D2C7572A320AA000D15901 /* OnlineAccountDetailsController.swift in Sources */, C9D2C7582A320AA000D15901 /* UIApplication+DashWallet.swift in Sources */, - 7545ED542DA91A2F0075F45C /* CTXConstants.swift in Sources */, + 7545ED542DA91A2F0075F45C /* DashSpend/CTXConstants.swift in Sources */, C9D2C7592A320AA000D15901 /* OnlineAccountInfoController.swift in Sources */, C9D2C75A2A320AA000D15901 /* PaymentController.swift in Sources */, C9D2C75B2A320AA000D15901 /* CALayer+MBAnimationPersistence.m in Sources */, @@ -10265,7 +10255,7 @@ 75EBAA0A2BB9791B004488E3 /* Icon.swift in Sources */, 754C27C72CC3C0B900BA7B9F /* UsernamePrefs.swift in Sources */, C9D2C7672A320AA000D15901 /* CoinbaseExchangeRateResponse.swift in Sources */, - C9D2C7692A320AA000D15901 /* BuildFile in Sources */, + C9D2C7692A320AA000D15901 /* (null) in Sources */, C9D2C76A2A320AA000D15901 /* CrowdNodePortalItem.swift in Sources */, C943B4C82A40A54600AF23C5 /* DWSearchStateViewController.m in Sources */, C9D2C76B2A320AA000D15901 /* BaseViewController.swift in Sources */, @@ -10352,7 +10342,7 @@ C9D2C7A72A320AA000D15901 /* ActionButtonViewController.swift in Sources */, C9D2C7A82A320AA000D15901 /* BuySellServiceItemCell.swift in Sources */, C956AF122A5B5949002FAB75 /* PasteboardContentView.swift in Sources */, - C9D2C7AA2A320AA000D15901 /* BuildFile in Sources */, + C9D2C7AA2A320AA000D15901 /* (null) in Sources */, C943B5002A40A54600AF23C5 /* DWDPTxItemView.m in Sources */, C9D2C7AB2A320AA000D15901 /* DWBaseFormTableViewCell.m in Sources */, C9D2C7AC2A320AA000D15901 /* AccountCell.swift in Sources */, @@ -10363,7 +10353,7 @@ C943B3392A408CED00AF23C5 /* DWUploadAvatarViewController.m in Sources */, 759609242C455B2000F3BF04 /* SendIntro.swift in Sources */, C9D2C7B12A320AA000D15901 /* CoinbaseBaseIDForCurrencyResponse.swift in Sources */, - C9D2C7B22A320AA000D15901 /* BuildFile in Sources */, + C9D2C7B22A320AA000D15901 /* (null) in Sources */, C9D2C7B32A320AA000D15901 /* SpecifyAmountViewController.swift in Sources */, C943B4EA2A40A54600AF23C5 /* DWUserProfileViewController.m in Sources */, 756557B62CE84FFA0060348D /* FeeInfo.swift in Sources */, @@ -10384,7 +10374,7 @@ C956AF212A5C33E5002FAB75 /* DWButton.m in Sources */, C9D2C7C02A320AA000D15901 /* HomeHeaderModel.swift in Sources */, C943B5942A40ED7B00AF23C5 /* DWPlanetarySystemView.m in Sources */, - C9D2C7C22A320AA000D15901 /* BuildFile in Sources */, + C9D2C7C22A320AA000D15901 /* (null) in Sources */, C9D2C7C32A320AA000D15901 /* DWDPRegistrationStatus.m in Sources */, C9D2C7C42A320AA000D15901 /* CurrencyExchanger_Objc.m in Sources */, 752F81982E30F55E00ADA76D /* SecurityMenuScreen.swift in Sources */, @@ -10398,7 +10388,7 @@ C9D2C7C92A320AA000D15901 /* BuyDashViewController.swift in Sources */, C956AF0D2A5B592E002FAB75 /* TappableLabel.swift in Sources */, C9D2C7CA2A320AA000D15901 /* DWModalDismissalAnimation.m in Sources */, - C9D2C7CB2A320AA000D15901 /* BuildFile in Sources */, + C9D2C7CB2A320AA000D15901 /* (null) in Sources */, C9D2C7CD2A320AA000D15901 /* UIViewController+DashWallet.swift in Sources */, 75D5D5332CC928630049ED7B /* UIHostingController+DashWallet.swift in Sources */, C9D2C7CE2A320AA000D15901 /* CrowdNodeCell.swift in Sources */, @@ -10429,10 +10419,10 @@ C9D2C7E22A320AA000D15901 /* CrowdNodeWithdrawalReceivedTx.swift in Sources */, 7549BE612DEAF628004F0BAF /* AddIconBitmapsTable.swift in Sources */, AA0000022DUMMYID001234567 /* AddProviderToGiftCardsTable.swift in Sources */, - AA0000052DUMMYID001234567 /* GiftCardProvider.swift in Sources */, - BB0000022DUMMYID001234567 /* DashSpendError.swift in Sources */, - BB0000042DUMMYID001234567 /* DashSpendRepository.swift in Sources */, - BB0000062DUMMYID001234567 /* DashSpendRepositoryFactory.swift in Sources */, + AA0000052DUMMYID001234567 /* DashSpend/GiftCardProvider.swift in Sources */, + BB0000022DUMMYID001234567 /* DashSpend/DashSpendError.swift in Sources */, + BB0000042DUMMYID001234567 /* DashSpend/DashSpendRepository.swift in Sources */, + BB0000062DUMMYID001234567 /* DashSpend/DashSpendRepositoryFactory.swift in Sources */, GG0000022DUMMYID001234567 /* GeoRestrictionService.swift in Sources */, CC0000122DUMMYID001234567 /* PiggyCardsAPI.swift in Sources */, CC0000142DUMMYID001234567 /* PiggyCardsCache.swift in Sources */, @@ -10441,7 +10431,7 @@ CC0000202DUMMYID001234567 /* PiggyCardsTokenService.swift in Sources */, EE0000022DUMMYID001234567 /* POIDetailsViewModel.swift in Sources */, EE0000062DUMMYID001234567 /* PercentageFormatter.swift in Sources */, - FF0000022DUMMYID001234567 /* PiggyCardsConstants.swift in Sources */, + FF0000022DUMMYID001234567 /* DashSpend/PiggyCardsConstants.swift in Sources */, FF0000072DUMMYID001234567 /* PiggyCardsModels.swift in Sources */, FF0000102DUMMYID001234567 /* BarcodeScanner.swift in Sources */, C943B4B62A40A54600AF23C5 /* DWFetchedResultsDataSource.m in Sources */, @@ -10575,7 +10565,7 @@ C9D2C8482A320AA000D15901 /* CoinbaseTransactionsRequest.swift in Sources */, C943B3372A408CED00AF23C5 /* DWEditProfileTextFieldCell.m in Sources */, C9D2C8492A320AA000D15901 /* DWAppRootViewController.m in Sources */, - C9D2C84A2A320AA000D15901 /* BuildFile in Sources */, + C9D2C84A2A320AA000D15901 /* (null) in Sources */, 7513DA882AB175E0005D55F6 /* TopperViewModel.swift in Sources */, C9D2C84B2A320AA000D15901 /* UITableView+DashWallet.swift in Sources */, C9D2C84C2A320AA000D15901 /* TransferAmountViewController.swift in Sources */, @@ -10614,7 +10604,7 @@ C9D2C8652A320AA000D15901 /* DWCaptureSessionManager.m in Sources */, C9D2C8662A320AA000D15901 /* DWDataMigrationManager.m in Sources */, 7502A4872AE401EF00ACDDD3 /* UsernameVotingViewController.swift in Sources */, - C9D2C86A2A320AA000D15901 /* BuildFile in Sources */, + C9D2C86A2A320AA000D15901 /* (null) in Sources */, C943B51F2A40A54600AF23C5 /* DWSuccessInvitationView.m in Sources */, C9D2C86B2A320AA000D15901 /* AmountPreviewView.swift in Sources */, 75CDD7812C0898E400F433D2 /* Shape.swift in Sources */, @@ -10673,7 +10663,7 @@ C9D2C8972A320AA000D15901 /* RatesProvider.swift in Sources */, C9D2C8982A320AA000D15901 /* CBAuth.swift in Sources */, C943B51C2A40A54600AF23C5 /* SuccessInvitationViewController.swift in Sources */, - C9D2C8992A320AA000D15901 /* BuildFile in Sources */, + C9D2C8992A320AA000D15901 /* (null) in Sources */, C9D2C89A2A320AA000D15901 /* CoinbaseCreateAddressesRequest.swift in Sources */, C943B3382A408CED00AF23C5 /* DWEditProfileAvatarView.m in Sources */, C943B5582A40DA3700AF23C5 /* DWFullScreenModalControllerViewController.m in Sources */, @@ -10684,7 +10674,6 @@ C943B5062A40A54600AF23C5 /* UICollectionView+DWDPItemDequeue.m in Sources */, 51BA2EA12F0B2E0100A1B201 /* MayaSwapPendingGate.swift in Sources */, C9D2C8A02A320AA000D15901 /* SendCoinsService.swift in Sources */, - FE5CA1E0000000000000A003 /* ScaleToFitWidth.swift in Sources */, C049F721C394463EB97CA8FF /* DSAccount+SpentInputCheck.m in Sources */, C9D2C8A12A320AA000D15901 /* ShortcutAction.swift in Sources */, C956AF112A5B592E002FAB75 /* UIButton+Dash.swift in Sources */, @@ -10712,9 +10701,9 @@ 757422222DF87B5200CB0175 /* MerchantFiltersView.swift in Sources */, C943B5382A40A65B00AF23C5 /* DWScrollingViewController.m in Sources */, C9D2C8B22A320AA000D15901 /* CoinbaseAccountAddress.swift in Sources */, - 754565C82DAA52A000DA4E8E /* CTXSpendAPI.swift in Sources */, - 754565CA2DAA52A000DA4E8E /* CTXSpendRepository.swift in Sources */, - 754565CB2DAA52A000DA4E8E /* CTXSpendEndpoint.swift in Sources */, + 754565C82DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendAPI.swift in Sources */, + 754565CA2DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendRepository.swift in Sources */, + 754565CB2DAA52A000DA4E8E /* DashSpend/CTX/CTXSpendEndpoint.swift in Sources */, C930784E2A6AD59E00906E4B /* ConfirmPaymentModel.swift in Sources */, C9D2C8B42A320AA000D15901 /* CrowdNodeTransferViewController.swift in Sources */, C9D2C8B62A320AA000D15901 /* CBAuthInterop.swift in Sources */, @@ -10765,7 +10754,7 @@ C943B50E2A40A54600AF23C5 /* DWConfirmInvitationContentView.m in Sources */, C9D2C8DE2A320AA000D15901 /* GettingStartedViewController.swift in Sources */, C9D2C8DF2A320AA000D15901 /* NetworkUnavailableView.swift in Sources */, - C9D2C8E02A320AA000D15901 /* BuildFile in Sources */, + C9D2C8E02A320AA000D15901 /* (null) in Sources */, 751B61C32ADFF9AE00D1C2EF /* UpholdPortalModel.swift in Sources */, C943B4FC2A40A54600AF23C5 /* DWDPEstablishedContactNotificationObject.m in Sources */, C9D2C8E12A320AA000D15901 /* DWLockScreenViewController.m in Sources */, @@ -13002,6 +12991,10 @@ isa = XCSwiftPackageProductDependency; productName = DashUIKit; }; + 64C58B73936B4EE69F73994F /* DashUIKit */ = { + isa = XCSwiftPackageProductDependency; + productName = DashUIKit; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 75D5F3B6191EC270004AB296 /* Project object */; diff --git a/DashWallet/Sources/Models/CrowdNode/CrowdNode.swift b/DashWallet/Sources/Models/CrowdNode/CrowdNode.swift index 82d4b2d35..4cf893f9a 100644 --- a/DashWallet/Sources/Models/CrowdNode/CrowdNode.swift +++ b/DashWallet/Sources/Models/CrowdNode/CrowdNode.swift @@ -213,6 +213,12 @@ extension CrowdNode { do { try tryRestoreLinkedOnlineAccount(state: onlineState, address: address) refreshWithdrawalLimits() + // Linked online accounts don't go through `setFinished`, so their balance was + // never fetched at restore — only when the user opened the CrowdNode portal. + // Refresh it proactively so the balance reminder (banner/sheet) can appear after + // sync without requiring the user to enter CrowdNode. `refreshBalance` self-guards + // on `signUpState`, so it no-ops for accounts that aren't linked yet. + refreshBalance() } catch { DSLogger.log("Failure while restoring linked CrowdNode account: \(error.localizedDescription)") } diff --git a/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderBanner.swift b/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderBanner.swift index 0d9eb6332..5f8e01dd6 100644 --- a/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderBanner.swift +++ b/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderBanner.swift @@ -59,5 +59,5 @@ struct CrowdNodeBalanceReminderBanner: View { #Preview { CrowdNodeBalanceReminderBanner(onWithdraw: {}) .padding(20) - .background(Color.primaryBackground) + .background(Color.dash.primaryBackground) } diff --git a/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderSheet.swift b/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderSheet.swift index 5462ba7a5..f6568dbcf 100644 --- a/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderSheet.swift +++ b/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderSheet.swift @@ -77,7 +77,7 @@ struct CrowdNodeBalanceReminderSheet: View { onWithdraw: {}, onDismiss: {} ) - .background(Color.primaryBackground) + .background(Color.dash.primaryBackground) } #Preview { diff --git a/DashWallet/Sources/UI/Maya/Convert/Components/MayaAmountView.swift b/DashWallet/Sources/UI/Maya/Convert/Components/MayaAmountView.swift index d54640815..99397064c 100644 --- a/DashWallet/Sources/UI/Maya/Convert/Components/MayaAmountView.swift +++ b/DashWallet/Sources/UI/Maya/Convert/Components/MayaAmountView.swift @@ -15,6 +15,7 @@ // limitations under the License. // +import DashUIKit import SwiftUI // MARK: - MayaAmountView diff --git a/DashWallet/Sources/UI/Menu/Settings/LocalCurrency/LocalCurrencyView.swift b/DashWallet/Sources/UI/Menu/Settings/LocalCurrency/LocalCurrencyView.swift index 9d27584e1..eb1efc3b9 100644 --- a/DashWallet/Sources/UI/Menu/Settings/LocalCurrency/LocalCurrencyView.swift +++ b/DashWallet/Sources/UI/Menu/Settings/LocalCurrency/LocalCurrencyView.swift @@ -15,6 +15,7 @@ // limitations under the License. // +import DashUIKit import SwiftUI // MARK: - LocalCurrencyView diff --git a/DashWallet/Sources/UI/SwiftUI Components/Geometry Readers/FrameReader.swift b/DashWallet/Sources/UI/SwiftUI Components/Geometry Readers/FrameReader.swift deleted file mode 100644 index 2a8265152..000000000 --- a/DashWallet/Sources/UI/SwiftUI Components/Geometry Readers/FrameReader.swift +++ /dev/null @@ -1,96 +0,0 @@ -// -// Created by Roman Chornyi -// Copyright © 2026 Dash Core Group. All rights reserved. -// -// Licensed under the MIT License (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import SwiftUI - -@available(iOS 14, *) -/// Adds a transparent View and read it's frame. -/// -/// Adds a GeometryReader with infinity frame. -public struct FrameReader: View { - - let coordinateSpace: CoordinateSpace - let onChange: (_ frame: CGRect) -> Void - - public init(coordinateSpace: CoordinateSpace, onChange: @escaping (_ frame: CGRect) -> Void) { - self.coordinateSpace = coordinateSpace - self.onChange = onChange - } - - public var body: some View { - GeometryReader { geo in - Text("") - .frame(maxWidth: .infinity, maxHeight: .infinity) - .onAppear(perform: { - onChange(geo.frame(in: coordinateSpace)) - }) - .onChange(of: geo.frame(in: coordinateSpace), perform: onChange) - } - .frame(maxWidth: .infinity, maxHeight: .infinity) - } -} - -@available(iOS 14, *) -public extension View { - - /// Get the frame of the View - /// - /// Adds a GeometryReader to the background of a View. - func readingFrame(coordinateSpace: CoordinateSpace = .global, onChange: @escaping (_ frame: CGRect) -> ()) -> some View { - background(FrameReader(coordinateSpace: coordinateSpace, onChange: onChange)) - } -} - -@available(iOS 14, *) -struct FrameReader_Previews: PreviewProvider { - - struct PreviewView: View { - - @State private var yOffset: CGFloat = 0 - - var body: some View { - ScrollView(.vertical) { - VStack { - Text("") - .frame(maxWidth: .infinity) - .frame(height: 200) - .cornerRadius(10) - .background(Color.green) - .padding() - .readingFrame { frame in - yOffset = frame.minY - } - - ForEach(0..<30) { x in - Text("") - .frame(maxWidth: .infinity) - .frame(height: 200) - .cornerRadius(10) - .background(Color.green) - .padding() - } - } - } - .coordinateSpace(name: "test") - .overlay(Text("Offset: \(yOffset)")) - } - } - - static var previews: some View { - PreviewView() - } -} diff --git a/DashWallet/Sources/UI/SwiftUI Components/Geometry Readers/LocationReader.swift b/DashWallet/Sources/UI/SwiftUI Components/Geometry Readers/LocationReader.swift deleted file mode 100644 index d788347d5..000000000 --- a/DashWallet/Sources/UI/SwiftUI Components/Geometry Readers/LocationReader.swift +++ /dev/null @@ -1,92 +0,0 @@ -// -// Created by Roman Chornyi -// Copyright © 2026 Dash Core Group. All rights reserved. -// -// Licensed under the MIT License (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import SwiftUI - -@available(iOS 14, *) -/// Adds a transparent View and read it's center point. -/// -/// Adds a GeometryReader with 0px by 0px frame. -public struct LocationReader: View { - - let coordinateSpace: CoordinateSpace - let onChange: (_ location: CGPoint) -> Void - - public init(coordinateSpace: CoordinateSpace, onChange: @escaping (_ location: CGPoint) -> Void) { - self.coordinateSpace = coordinateSpace - self.onChange = onChange - } - - public var body: some View { - FrameReader(coordinateSpace: coordinateSpace) { frame in - onChange(CGPoint(x: frame.midX, y: frame.midY)) - } - .frame(width: 0, height: 0, alignment: .center) - } -} - -@available(iOS 14, *) -public extension View { - - /// Get the center point of the View - /// - /// Adds a 0px GeometryReader to the background of a View. - func readingLocation(coordinateSpace: CoordinateSpace = .global, onChange: @escaping (_ location: CGPoint) -> ()) -> some View { - background(LocationReader(coordinateSpace: coordinateSpace, onChange: onChange)) - } - -} - -@available(iOS 14, *) -struct LocationReader_Previews: PreviewProvider { - - struct PreviewView: View { - - @State private var yOffset: CGFloat = 0 - - var body: some View { - ScrollView(.vertical) { - VStack { - Text("Hello, world!") - .frame(maxWidth: .infinity) - .frame(height: 200) - .cornerRadius(10) - .background(Color.green) - .padding() - .readingLocation { location in - yOffset = location.y - } - - ForEach(0..<30) { x in - Text("") - .frame(maxWidth: .infinity) - .frame(height: 200) - .cornerRadius(10) - .background(Color.green) - .padding() - } - } - } - .coordinateSpace(name: "test") - .overlay(Text("Offset: \(yOffset)")) - } - } - - static var previews: some View { - PreviewView() - } -} diff --git a/DashWallet/Sources/UI/SwiftUI Components/Geometry Readers/ScaleToFitWidth.swift b/DashWallet/Sources/UI/SwiftUI Components/Geometry Readers/ScaleToFitWidth.swift deleted file mode 100644 index 0153c6c86..000000000 --- a/DashWallet/Sources/UI/SwiftUI Components/Geometry Readers/ScaleToFitWidth.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// Created by Roman Chornyi -// Copyright © 2026 Dash Core Group. All rights reserved. -// -// Licensed under the MIT License (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import SwiftUI - -// MARK: - ScaleToFitWidth - -private struct ScaleToFitContentSizeKey: PreferenceKey { - static var defaultValue: CGSize = .zero - static func reduce(value: inout CGSize, nextValue: () -> CGSize) { - let next = nextValue() - if next.width > 0 { value = next } - } -} - -/// Scales its content uniformly to fit the available width on a single line, shrinking the WHOLE -/// group (e.g. currency symbol + amount + logo) together — unlike `minimumScaleFactor`, which only -/// shrinks each `Text` independently. Content renders at full size when it fits and never scales -/// below `minScale`. -/// -/// The modifier reserves the content's natural single-line height (constant) so it keeps the -/// surrounding vertical layout stable while only the horizontal scale changes. -struct ScaleToFitWidth: ViewModifier { - var minScale: CGFloat = 0.35 - - @State private var naturalSize: CGSize = .zero - - func body(content: Content) -> some View { - GeometryReader { proxy in - content - .fixedSize() // natural, single-line size — the unit we scale - .scaleEffect(scale(forAvailableWidth: proxy.size.width), anchor: .center) - .frame(width: proxy.size.width, height: proxy.size.height, alignment: .center) - } - .frame(maxWidth: .infinity) - // Collapse the greedy GeometryReader to one content line so vertical layout is unaffected. - .frame(height: naturalSize.height == 0 ? nil : naturalSize.height) - .background( - // Measure the content's natural (unconstrained) size off-screen. - content - .fixedSize() - .hidden() - .background( - GeometryReader { proxy in - Color.clear.preference(key: ScaleToFitContentSizeKey.self, value: proxy.size) - } - ) - ) - .onPreferenceChange(ScaleToFitContentSizeKey.self) { naturalSize = $0 } - } - - private func scale(forAvailableWidth available: CGFloat) -> CGFloat { - guard naturalSize.width > 0, available > 0, available < naturalSize.width else { return 1 } - return max(minScale, available / naturalSize.width) - } -} - -extension View { - /// Scales the view uniformly to fit the available width on one line, down to `minScale`. - func scaleToFitWidth(minScale: CGFloat = 0.35) -> some View { - modifier(ScaleToFitWidth(minScale: minScale)) - } -} diff --git a/DashWallet/Sources/UI/SwiftUI Components/ScrollViews/ScrollViewWithOnScrollChanged.swift b/DashWallet/Sources/UI/SwiftUI Components/ScrollViews/ScrollViewWithOnScrollChanged.swift deleted file mode 100644 index 282dc8f63..000000000 --- a/DashWallet/Sources/UI/SwiftUI Components/ScrollViews/ScrollViewWithOnScrollChanged.swift +++ /dev/null @@ -1,79 +0,0 @@ -// -// Created by Roman Chornyi -// Copyright © 2026 Dash Core Group. All rights reserved. -// -// Licensed under the MIT License (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import SwiftUI - -@available(iOS 14, *) -public struct ScrollViewWithOnScrollChanged: View { - - let axes: Axis.Set - let showsIndicators: Bool - let content: Content - let onScrollChanged: (_ origin: CGPoint) -> () - @State private var coordinateSpaceID: String = UUID().uuidString - - public init( - _ axes: Axis.Set = .vertical, - showsIndicators: Bool = false, - @ViewBuilder content: () -> Content, - onScrollChanged: @escaping (_ origin: CGPoint) -> ()) { - self.axes = axes - self.showsIndicators = showsIndicators - self.content = content() - self.onScrollChanged = onScrollChanged - } - - public var body: some View { - ScrollView(axes, showsIndicators: showsIndicators) { - LocationReader(coordinateSpace: .named(coordinateSpaceID), onChange: onScrollChanged) - content - } - .coordinateSpace(name: coordinateSpaceID) - } -} - -@available(iOS 14, *) -struct ScrollViewWithOnScrollChanged_Previews: PreviewProvider { - - struct PreviewView: View { - - @State private var yPosition: CGFloat = 0 - - var body: some View { - ScrollViewWithOnScrollChanged { - VStack { - ForEach(0..<30) { x in - Text("x: \(x)") - .frame(maxWidth: .infinity) - .frame(height: 200) - .cornerRadius(10) - .background(Color.red) - .padding() - .id(x) - } - } - } onScrollChanged: { origin in - yPosition = origin.y - } - .overlay(Text("Offset: \(yPosition)")) - } - } - - static var previews: some View { - PreviewView() - } -} From c6b41f053567637aa81686f07bfd55ecffb2ba4f Mon Sep 17 00:00:00 2001 From: Roman <51091564+jeanpierreroma@users.noreply.github.com> Date: Fri, 26 Jun 2026 15:57:40 +0300 Subject: [PATCH 5/5] chore: bump version to 8.6.1 (build 9) --- DashWallet.xcodeproj/project.pbxproj | 96 +++++++++---------- .../Sources/Models/CrowdNode/CrowdNode.swift | 21 +++- 2 files changed, 66 insertions(+), 51 deletions(-) diff --git a/DashWallet.xcodeproj/project.pbxproj b/DashWallet.xcodeproj/project.pbxproj index 7c3fe22ad..ec069d208 100644 --- a/DashWallet.xcodeproj/project.pbxproj +++ b/DashWallet.xcodeproj/project.pbxproj @@ -10946,7 +10946,7 @@ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10983,7 +10983,7 @@ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -11019,7 +11019,7 @@ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -11055,7 +11055,7 @@ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -11216,7 +11216,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = dashwallet/dashwallet.entitlements; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; @@ -11245,7 +11245,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -11347,7 +11347,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = dashwallet/dashwallet.entitlements; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -11385,7 +11385,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -11484,7 +11484,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/dashwallet.app/dashwallet"; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -11519,7 +11519,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/dashwallet.app/dashwallet"; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -11554,12 +11554,12 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; IBSC_MODULE = WatchApp_Extension; INFOPLIST_FILE = WatchApp/Info.plist; - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; @@ -11576,12 +11576,12 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; IBSC_MODULE = WatchApp_Extension; INFOPLIST_FILE = WatchApp/Info.plist; - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; @@ -11596,7 +11596,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 3BA20785E162F1AF2F455D9C /* Pods-WatchApp Extension.debug.xcconfig */; buildSettings = { - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; ENABLE_BITCODE = NO; EXCLUDED_ARCHS = ""; @@ -11606,7 +11606,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.watchkitapp.watchkitextension; PRODUCT_NAME = "${TARGET_NAME}"; SDKROOT = watchos; @@ -11623,7 +11623,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 4457C976B1DB0CF402FF3C5F /* Pods-WatchApp Extension.release.xcconfig */; buildSettings = { - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; ENABLE_BITCODE = NO; EXCLUDED_ARCHS = ""; @@ -11633,7 +11633,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.watchkitapp.watchkitextension; PRODUCT_NAME = "${TARGET_NAME}"; SDKROOT = watchos; @@ -11651,7 +11651,7 @@ baseConfigurationReference = 3B0E86557754B86DD3A389CC /* Pods-TodayExtension.debug.xcconfig */; buildSettings = { CODE_SIGN_ENTITLEMENTS = dashwallet/dashwalletTodayExtension.entitlements; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; @@ -11665,7 +11665,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.TodayExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -11680,7 +11680,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = dashwallet/dashwalletTodayExtension.entitlements; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; @@ -11694,7 +11694,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.TodayExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -11714,7 +11714,7 @@ CLIENT_ID = 0c38beb67db0c68191326be347d7ec0abd7d77adb02a79db1abeba343f16a0f7; CLIENT_SECRET = cc980185754f905e24250f877792817c03540b3d0e0959721df291c816797e59; CODE_SIGN_ENTITLEMENTS = dashwallet/dashwallet.entitlements; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; @@ -11744,7 +11744,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -11850,7 +11850,7 @@ CLIENT_ID = 0c38beb67db0c68191326be347d7ec0abd7d77adb02a79db1abeba343f16a0f7; CLIENT_SECRET = cc980185754f905e24250f877792817c03540b3d0e0959721df291c816797e59; CODE_SIGN_ENTITLEMENTS = dashwallet/dashwallet.entitlements; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -11879,7 +11879,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -11984,7 +11984,7 @@ CLIENT_ID = 0c38beb67db0c68191326be347d7ec0abd7d77adb02a79db1abeba343f16a0f7; CLIENT_SECRET = cc980185754f905e24250f877792817c03540b3d0e0959721df291c816797e59; CODE_SIGN_ENTITLEMENTS = dashwallet/dashwallet.entitlements; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -12024,7 +12024,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -12128,7 +12128,7 @@ CLIENT_ID = 0c38beb67db0c68191326be347d7ec0abd7d77adb02a79db1abeba343f16a0f7; CLIENT_SECRET = cc980185754f905e24250f877792817c03540b3d0e0959721df291c816797e59; CODE_SIGN_ENTITLEMENTS = dashwallet/dashwallet.entitlements; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -12167,7 +12167,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -12332,7 +12332,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = dashwallet/dashwallet.entitlements; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -12370,7 +12370,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -12469,7 +12469,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = dashwallet/dashwalletTodayExtension.entitlements; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; @@ -12483,7 +12483,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.TodayExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -12499,7 +12499,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/dashwallet.app/dashwallet"; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -12534,12 +12534,12 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; IBSC_MODULE = WatchApp_Extension; INFOPLIST_FILE = WatchApp/Info.plist; - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; @@ -12554,7 +12554,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = EE15E7C0EEFF1E6930A90DA6 /* Pods-WatchApp Extension.testflight.xcconfig */; buildSettings = { - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; ENABLE_BITCODE = NO; EXCLUDED_ARCHS = ""; @@ -12564,7 +12564,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.watchkitapp.watchkitextension; PRODUCT_NAME = "${TARGET_NAME}"; SDKROOT = watchos; @@ -12653,7 +12653,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = dashwallet/dashwallet.entitlements; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -12681,7 +12681,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -12779,7 +12779,7 @@ baseConfigurationReference = AA29A8515217AC4232F794C2 /* Pods-TodayExtension.testnet.xcconfig */; buildSettings = { CODE_SIGN_ENTITLEMENTS = dashwallet/dashwalletTodayExtension.entitlements; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; @@ -12793,7 +12793,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.TodayExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -12808,7 +12808,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/dashwallet.app/dashwallet"; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -12843,12 +12843,12 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; IBSC_MODULE = WatchApp_Extension; INFOPLIST_FILE = WatchApp/Info.plist; - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; @@ -12863,7 +12863,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = E2A832899A499C24C7A43E47 /* Pods-WatchApp Extension.testnet.xcconfig */; buildSettings = { - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 44RJ69WHFF; ENABLE_BITCODE = NO; EXCLUDED_ARCHS = ""; @@ -12873,7 +12873,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 8.6.0; + MARKETING_VERSION = 8.6.1; PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.watchkitapp.watchkitextension; PRODUCT_NAME = "${TARGET_NAME}"; SDKROOT = watchos; diff --git a/DashWallet/Sources/Models/CrowdNode/CrowdNode.swift b/DashWallet/Sources/Models/CrowdNode/CrowdNode.swift index 4cf893f9a..36cd9f806 100644 --- a/DashWallet/Sources/Models/CrowdNode/CrowdNode.swift +++ b/DashWallet/Sources/Models/CrowdNode/CrowdNode.swift @@ -218,7 +218,10 @@ extension CrowdNode { // Refresh it proactively so the balance reminder (banner/sheet) can appear after // sync without requiring the user to enter CrowdNode. `refreshBalance` self-guards // on `signUpState`, so it no-ops for accounts that aren't linked yet. - refreshBalance() + // Don't seed from cache: a stale positive `lastKnownBalance` would otherwise drive + // the balance reminder before the first fresh fetch, surfacing/consuming it even + // when the server returns 0. + refreshBalance(seedFromCache: false) } catch { DSLogger.log("Failure while restoring linked CrowdNode account: \(error.localizedDescription)") } @@ -535,13 +538,20 @@ extension CrowdNode { // MARK: Balance extension CrowdNode { - func refreshBalance(retries: Int = 3, afterWithdrawal: Bool = false) { + /// - Parameter seedFromCache: When `true` (default) the cached `lastKnownBalance` is published + /// immediately so UI (e.g. the CrowdNode portal) shows a value while the fetch is in flight. + /// Pass `false` for silent/background refreshes (e.g. restore) where a stale positive cache + /// must not drive balance-derived UI such as `CrowdNodeBalanceReminder` before the first + /// fresh fetch completes. + func refreshBalance(retries: Int = 3, afterWithdrawal: Bool = false, seedFromCache: Bool = true) { guard !accountAddress.isEmpty && signUpState != .notStarted else { return } Task { let lastBalance = prefs.lastKnownBalance var currentBalance = lastBalance - balance = currentBalance + if seedFromCache { + balance = currentBalance + } isBalanceLoading = true do { @@ -557,6 +567,11 @@ extension CrowdNode { let plainAmount = dashNumber * duffsNumber currentBalance = NSDecimalNumber(decimal: plainAmount).uint64Value prefs.lastKnownBalance = currentBalance + // Publish the fresh value as soon as it arrives. The loop keeps polling (with + // escalating backoff) until the balance *changes* vs. the cached baseline, which + // can take minutes; without this, a non-seeded refresh (e.g. restore) wouldn't + // surface the real balance — and the balance reminder — until the loop ends. + balance = currentBalance var breakDifference: UInt64 = 0