From b5c6790e190770e8acbdfb3baef74643d7880052 Mon Sep 17 00:00:00 2001 From: pasta Date: Wed, 26 Aug 2026 14:41:14 +0200 Subject: [PATCH 1/5] refactor(explore): use DashUIKit for marketplace sheets --- .../UsernameMarketplaceScreen.swift | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/DashWallet/Sources/UI/Explore Dash/UsernameMarketplaceScreen.swift b/DashWallet/Sources/UI/Explore Dash/UsernameMarketplaceScreen.swift index 46534f7d9..3416fafb1 100644 --- a/DashWallet/Sources/UI/Explore Dash/UsernameMarketplaceScreen.swift +++ b/DashWallet/Sources/UI/Explore Dash/UsernameMarketplaceScreen.swift @@ -475,8 +475,10 @@ struct UsernameMarketplaceScreen: View { .background(Color.dash.primaryBackground.ignoresSafeArea()) .onAppear { viewModel.loadMyNames() } .sheet(item: $selectedLabel) { selected in - MarketplaceNameDetailSheet(selection: selected, viewModel: viewModel) - .presentationDetents([.medium, .large]) + DashUIKit.BottomSheet(showBackButton: .constant(false)) { + MarketplaceNameDetailSheet(selection: selected, viewModel: viewModel) + } + .presentationDetents([.medium, .large]) } .sheet(item: $registerCandidate) { candidate in if candidate.isContested { @@ -1153,12 +1155,16 @@ private struct MarketplaceNameDetailSheet: View { } } .sheet(isPresented: $showingSetPrice) { - SetNamePriceSheet(label: label, viewModel: viewModel, onDone: { dismiss() }) - .presentationDetents([.medium, .large]) + DashUIKit.BottomSheet(showBackButton: .constant(false)) { + SetNamePriceSheet(label: label, viewModel: viewModel, onDone: { dismiss() }) + } + .presentationDetents([.medium, .large]) } .sheet(isPresented: $showingTransfer) { - TransferNameSheet(label: label, viewModel: viewModel, onDone: { dismiss() }) - .presentationDetents([.medium, .large]) + DashUIKit.BottomSheet(showBackButton: .constant(false)) { + TransferNameSheet(label: label, viewModel: viewModel, onDone: { dismiss() }) + } + .presentationDetents([.medium, .large]) } } From 8d2b8a952e5736c463f973e22d910b265cd74187 Mon Sep 17 00:00:00 2001 From: pasta Date: Wed, 26 Aug 2026 15:55:43 +0200 Subject: [PATCH 2/5] refactor(ui): consolidate bottom sheets on DashUIKit --- DashWallet.xcodeproj/project.pbxproj | 12 -- .../Transfer Amount/TransferAmountView.swift | 2 +- .../JoinDashPayInfoDialog.swift | 3 +- .../Info/MerchantTypesDialog.swift | 3 +- .../DashSpend/DashSpendLoginInfoView.swift | 3 +- .../Home/HomeViewController+Shortcuts.swift | 2 +- .../Sources/UI/Home/Views/HomeView.swift | 4 +- .../Shortcuts/ShortcutSelectionView.swift | 2 +- .../Views/Shortcuts/WalletSwitchDialog.swift | 2 +- .../Home/Views/TransactionFilterDialog.swift | 2 +- .../Buy/EnterAmount/BuyEnterAmountView.swift | 2 +- .../UI/Swap/Convert/SwapConvertView.swift | 2 +- .../Components/OrderPreviewFeeRow.swift | 2 +- .../Components/SwapFeeInfoSheet.swift | 4 +- .../UI/SwiftUI Components/BottomSheet.swift | 152 ------------------ .../SwiftUI Components/SelfSizingSheet.swift | 92 ----------- .../Tx/Details/TxDetailViewController.swift | 5 +- 17 files changed, 21 insertions(+), 273 deletions(-) delete mode 100644 DashWallet/Sources/UI/SwiftUI Components/BottomSheet.swift delete mode 100644 DashWallet/Sources/UI/SwiftUI Components/SelfSizingSheet.swift diff --git a/DashWallet.xcodeproj/project.pbxproj b/DashWallet.xcodeproj/project.pbxproj index 33d002060..4ba92cff2 100644 --- a/DashWallet.xcodeproj/project.pbxproj +++ b/DashWallet.xcodeproj/project.pbxproj @@ -118,7 +118,6 @@ 215F9BB0CAADF4D47D95C444 /* DWAvatarUploadClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5E2D975669CB53883D56803 /* DWAvatarUploadClientTests.swift */; }; 2284B63F1C7BD28F0012ECDF /* BRAWKeypad.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22F45A0A1C30EAB700B07A15 /* BRAWKeypad.swift */; }; 22B03841025A55A573432CC9 /* WalletAccountsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 285B961142AB3AFF2442F4EB /* WalletAccountsScreen.swift */; }; - 22E89B6C00B546D294D7F331 /* SelfSizingSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96CB7E093E994D2391D36DEC /* SelfSizingSheet.swift */; }; 2556F3C5C72D70A771C6C61A /* PaymentProtocolWireFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = E66B030D4B574621DA2C5816 /* PaymentProtocolWireFormat.swift */; }; 25C88271468A4CD23F34A6E9 /* SendScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D1F21A7592E99814A800518 /* SendScreen.swift */; }; 279C16F9AF0575C540E312E5 /* SwapConvertCardRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D99130732DE8F2E95F635F6B /* SwapConvertCardRow.swift */; }; @@ -341,7 +340,6 @@ 3705C73F15BCD91AF70940B9 /* PlatformCreditsFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C830DD6D63115525925F75 /* PlatformCreditsFormatter.swift */; }; 371ADBAC635CEB63CA0A4A1E /* SwiftDashSDKWalletRuntime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E9C4B39B015CD9D8AD4741D /* SwiftDashSDKWalletRuntime.swift */; }; FBA8AC3BF5464D0E85240A56 /* WalletLifecycleTransitionState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81F0D6EBA27F471A9FC46E49 /* WalletLifecycleTransitionState.swift */; }; - 39DC037E9CF04CCFA3EFBB53 /* SelfSizingSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96CB7E093E994D2391D36DEC /* SelfSizingSheet.swift */; }; 3A377045AA5C10F3FD63A7C2 /* DWContestedNameStatusService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E950113F9E258B2F1CC0D50C /* DWContestedNameStatusService.swift */; }; 3A958F915CDACC6FE30923BA /* DarkCoinMessageFraming.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C25F44380CDB841AF55D3FF /* DarkCoinMessageFraming.swift */; }; 3B1ECCE5521BAB084D74B5ED /* StorageModelListViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60A762BDA473947F1A7EF199 /* StorageModelListViews.swift */; }; @@ -902,8 +900,6 @@ 75EBAA0D2BB9792F004488E3 /* FeatureTopText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EBAA0B2BB9792F004488E3 /* FeatureTopText.swift */; }; 75EBAA0F2BB99036004488E3 /* TextIntro.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EBAA0E2BB99036004488E3 /* TextIntro.swift */; }; 75EBAA102BB99036004488E3 /* TextIntro.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EBAA0E2BB99036004488E3 /* TextIntro.swift */; }; - 75EBAA122BB99B6B004488E3 /* BottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EBAA112BB99B6B004488E3 /* BottomSheet.swift */; }; - 75EBAA132BB99B6B004488E3 /* BottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EBAA112BB99B6B004488E3 /* BottomSheet.swift */; }; 75EBAA1D2BBA71D9004488E3 /* ZenLedgerInfoSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EBAA1C2BBA71D9004488E3 /* ZenLedgerInfoSheet.swift */; }; 75EBAA222BBA9D3C004488E3 /* ZenLedger-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 75EBAA212BBA9D3C004488E3 /* ZenLedger-Info.plist */; }; 75EBAA232BBA9D3C004488E3 /* ZenLedger-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 75EBAA212BBA9D3C004488E3 /* ZenLedger-Info.plist */; }; @@ -3026,7 +3022,6 @@ 75EBAA082BB9791B004488E3 /* Icon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Icon.swift; sourceTree = ""; }; 75EBAA0B2BB9792F004488E3 /* FeatureTopText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureTopText.swift; sourceTree = ""; }; 75EBAA0E2BB99036004488E3 /* TextIntro.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextIntro.swift; sourceTree = ""; }; - 75EBAA112BB99B6B004488E3 /* BottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomSheet.swift; sourceTree = ""; }; 75EBAA1C2BBA71D9004488E3 /* ZenLedgerInfoSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZenLedgerInfoSheet.swift; sourceTree = ""; }; 75EBAA212BBA9D3C004488E3 /* ZenLedger-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ZenLedger-Info.plist"; sourceTree = ""; }; 75EBAA242BBA9DC2004488E3 /* ZenLedger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZenLedger.swift; sourceTree = ""; }; @@ -3064,7 +3059,6 @@ 8E6FAA6524ACE5F315B57AC3 /* SendViewModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SendViewModel.swift; sourceTree = ""; }; 91F0B8B82F3FAB7C00E713AE /* KeysOverviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeysOverviewView.swift; sourceTree = ""; }; 94606903417F75BE99D4B31C /* BIP70Error.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BIP70Error.swift; sourceTree = ""; }; - 96CB7E093E994D2391D36DEC /* SelfSizingSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelfSizingSheet.swift; sourceTree = ""; }; 97AA6C01B7CED63D37D3652B /* JoinDashPayReadinessScreen.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = JoinDashPayReadinessScreen.swift; sourceTree = ""; }; 97E3D9AE002847AABFDA5537 /* Pods-TodayExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TodayExtension.release.xcconfig"; path = "Target Support Files/Pods-TodayExtension/Pods-TodayExtension.release.xcconfig"; sourceTree = ""; }; 9A461F75E1E170FFE3294337 /* DWAvatarUploadClient.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DWAvatarUploadClient.swift; path = Networking/DWAvatarUploadClient.swift; sourceTree = ""; }; @@ -6922,8 +6916,6 @@ 51DFA7F72FA8A9DF001EDB3A /* DashStepper.swift */, 516983C02FCAEDD600BA91A2 /* Icons */, 7581B19C2CE3509A00714007 /* Dialogs */, - 75EBAA112BB99B6B004488E3 /* BottomSheet.swift */, - 96CB7E093E994D2391D36DEC /* SelfSizingSheet.swift */, AD6615F1246B5935365B05BD /* NavigationBar.swift */, 5E1C0A0100000000000000F1 /* MerchantLogoPlaceholder.swift */, 759ADD562BF3447400767ACD /* Button.swift */, @@ -10058,8 +10050,6 @@ 472CEE012924AA6D00656B48 /* PointOfUseListEmptyResultsView.swift in Sources */, 2A6300452328D07500827825 /* DWLockPinInputView.m in Sources */, 2A0C69AC23125074001B8C90 /* UIView+DWHUD.m in Sources */, - 75EBAA122BB99B6B004488E3 /* BottomSheet.swift in Sources */, - 22E89B6C00B546D294D7F331 /* SelfSizingSheet.swift in Sources */, B453B34B871E4125607DACDC /* NavigationBar.swift in Sources */, 5E1C0A0100000000000000F2 /* MerchantLogoPlaceholder.swift in Sources */, 75CED09E2ACFD0ED0095F10C /* CoinbaseDepositRequest.swift in Sources */, @@ -10592,8 +10582,6 @@ 75FFD6C22BF493A60032879E /* HomeViewController+SecureWalletDelegateImpl.swift in Sources */, C9D2C7062A320AA000D15901 /* DWOnboardingModel.m in Sources */, C9D2C7072A320AA000D15901 /* AmountInputTypeSwitcher.swift in Sources */, - 75EBAA132BB99B6B004488E3 /* BottomSheet.swift in Sources */, - 39DC037E9CF04CCFA3EFBB53 /* SelfSizingSheet.swift in Sources */, EE5F3D5C458E92B69D14BFD8 /* NavigationBar.swift in Sources */, 5E1C0A0100000000000000F3 /* MerchantLogoPlaceholder.swift in Sources */, C9D2C7082A320AA000D15901 /* DWPlaceholderFormCellModel.m in Sources */, diff --git a/DashWallet/Sources/UI/Coinbase/Transfer Amount/TransferAmountView.swift b/DashWallet/Sources/UI/Coinbase/Transfer Amount/TransferAmountView.swift index 12328308a..674b3ef5c 100644 --- a/DashWallet/Sources/UI/Coinbase/Transfer Amount/TransferAmountView.swift +++ b/DashWallet/Sources/UI/Coinbase/Transfer Amount/TransferAmountView.swift @@ -81,7 +81,7 @@ struct TransferAmountView: View { } } .sheet(isPresented: $showLocalCurrency) { - let dialog = BottomSheet(showBackButton: Binding.constant(false)) { + let dialog = DashUIKit.BottomSheet(showBackButton: Binding.constant(false)) { LocalCurrencyView { code in viewModel.selectFiatCurrency(code) showLocalCurrency = false diff --git a/DashWallet/Sources/UI/DashPay/Setup/CreateUsername/JoinDashPayInfoDialog.swift b/DashWallet/Sources/UI/DashPay/Setup/CreateUsername/JoinDashPayInfoDialog.swift index cccc47c1f..4fc2f9b5c 100644 --- a/DashWallet/Sources/UI/DashPay/Setup/CreateUsername/JoinDashPayInfoDialog.swift +++ b/DashWallet/Sources/UI/DashPay/Setup/CreateUsername/JoinDashPayInfoDialog.swift @@ -16,6 +16,7 @@ // import SwiftUI +import DashUIKit public struct JoinDashPayInfoDialog: View { @Environment(\.presentationMode) private var presentationMode @@ -25,7 +26,7 @@ public struct JoinDashPayInfoDialog: View { var onClaimInvitation: (() -> Void)? = nil public var body: some View { - BottomSheet(showBackButton: Binding.constant(false)) { + DashUIKit.BottomSheet(showBackButton: Binding.constant(false)) { JoinDashPayScreen( action: { presentationMode.wrappedValue.dismiss() diff --git a/DashWallet/Sources/UI/Explore Dash/Merchants & ATMs/Info/MerchantTypesDialog.swift b/DashWallet/Sources/UI/Explore Dash/Merchants & ATMs/Info/MerchantTypesDialog.swift index 61ba1c692..ee9431a3a 100644 --- a/DashWallet/Sources/UI/Explore Dash/Merchants & ATMs/Info/MerchantTypesDialog.swift +++ b/DashWallet/Sources/UI/Explore Dash/Merchants & ATMs/Info/MerchantTypesDialog.swift @@ -16,13 +16,14 @@ // import SwiftUI +import DashUIKit public struct MerchantTypesDialog: View { @Environment(\.presentationMode) private var presentationMode var action: (() -> Void)? = nil public var body: some View { - BottomSheet(showBackButton: .constant(false)) { + DashUIKit.BottomSheet(showBackButton: .constant(false)) { TextIntro( icon: .custom("image.merchant"), buttonLabel: NSLocalizedString("Ok", comment: ""), diff --git a/DashWallet/Sources/UI/Explore Dash/Views/DashSpend/DashSpendLoginInfoView.swift b/DashWallet/Sources/UI/Explore Dash/Views/DashSpend/DashSpendLoginInfoView.swift index 7a789f4e1..5dd1104a4 100644 --- a/DashWallet/Sources/UI/Explore Dash/Views/DashSpend/DashSpendLoginInfoView.swift +++ b/DashWallet/Sources/UI/Explore Dash/Views/DashSpend/DashSpendLoginInfoView.swift @@ -16,6 +16,7 @@ // import SwiftUI +import DashUIKit struct DashSpendLoginInfoView: View { let provider: GiftCardProvider @@ -25,7 +26,7 @@ struct DashSpendLoginInfoView: View { @State private var inProgress: Bool = false var body: some View { - BottomSheet(showBackButton: .constant(false)) { + DashUIKit.BottomSheet(showBackButton: .constant(false)) { VStack { TextIntro( icon: .custom(provider.logoName, maxHeight: 60), diff --git a/DashWallet/Sources/UI/Home/HomeViewController+Shortcuts.swift b/DashWallet/Sources/UI/Home/HomeViewController+Shortcuts.swift index e6b908360..cb5d7e24a 100644 --- a/DashWallet/Sources/UI/Home/HomeViewController+Shortcuts.swift +++ b/DashWallet/Sources/UI/Home/HomeViewController+Shortcuts.swift @@ -466,7 +466,7 @@ extension HomeViewController: DWLocalCurrencyViewControllerDelegate { private func shortcutSelectionSheetView(for position: Int) -> AnyView { let usedTypes = Set(HomeViewModel.shared.shortcutItems.map { $0.type }) - let sheet = BottomSheet(title: NSLocalizedString("Select option", comment: ""), + let sheet = DashUIKit.BottomSheet(title: NSLocalizedString("Select option", comment: ""), showBackButton: .constant(false)) { ShortcutSelectionView(usedTypes: usedTypes) { [weak self] selectedType in self?.applyShortcutCustomization(type: selectedType, at: position) diff --git a/DashWallet/Sources/UI/Home/Views/HomeView.swift b/DashWallet/Sources/UI/Home/Views/HomeView.swift index 29a2c67ab..24c621521 100644 --- a/DashWallet/Sources/UI/Home/Views/HomeView.swift +++ b/DashWallet/Sources/UI/Home/Views/HomeView.swift @@ -910,7 +910,7 @@ struct GiftCardDetailsSheet: View { var body: some View { let showsTxDetailRoute = txDetailRoute != nil - let dialog = BottomSheet( + let dialog = DashUIKit.BottomSheet( showBackButton: $showBackButton, onBackButtonPressed: { handleBackNavigation() @@ -1066,7 +1066,7 @@ struct TransactionDetailsSheet: View { var item: TransactionListDataItem var body: some View { - BottomSheet(showBackButton: $showBackButton, onBackButtonPressed: { + DashUIKit.BottomSheet(showBackButton: $showBackButton, onBackButtonPressed: { backNavigationRequested = true }) { TxDetailsDestination(from: item) diff --git a/DashWallet/Sources/UI/Home/Views/Shortcuts/ShortcutSelectionView.swift b/DashWallet/Sources/UI/Home/Views/Shortcuts/ShortcutSelectionView.swift index d0532958d..bd368120c 100644 --- a/DashWallet/Sources/UI/Home/Views/Shortcuts/ShortcutSelectionView.swift +++ b/DashWallet/Sources/UI/Home/Views/Shortcuts/ShortcutSelectionView.swift @@ -75,7 +75,7 @@ struct ShortcutSelectionView: View { VStack { Color.dash.secondaryBackground.ignoresSafeArea() .sheet(isPresented: .constant(true)) { - let sheet = BottomSheet(title: NSLocalizedString("Select option", comment: ""), showBackButton: .constant(false)) { + let sheet = DashUIKit.BottomSheet(title: NSLocalizedString("Select option", comment: ""), showBackButton: .constant(false)) { ShortcutSelectionView(usedTypes: [.receive, .send, .spend]) { _ in } } diff --git a/DashWallet/Sources/UI/Home/Views/Shortcuts/WalletSwitchDialog.swift b/DashWallet/Sources/UI/Home/Views/Shortcuts/WalletSwitchDialog.swift index f7bcce685..df1944412 100644 --- a/DashWallet/Sources/UI/Home/Views/Shortcuts/WalletSwitchDialog.swift +++ b/DashWallet/Sources/UI/Home/Views/Shortcuts/WalletSwitchDialog.swift @@ -23,7 +23,7 @@ struct WalletSwitchDialog: View { } var body: some View { - BottomSheet( + DashUIKit.BottomSheet( title: NSLocalizedString("Switch Wallet", comment: "Wallets"), showBackButton: .constant(false) ) { diff --git a/DashWallet/Sources/UI/Home/Views/TransactionFilterDialog.swift b/DashWallet/Sources/UI/Home/Views/TransactionFilterDialog.swift index bea3360d6..c88913332 100644 --- a/DashWallet/Sources/UI/Home/Views/TransactionFilterDialog.swift +++ b/DashWallet/Sources/UI/Home/Views/TransactionFilterDialog.swift @@ -48,7 +48,7 @@ struct TransactionFilterDialog: View { } var body: some View { - BottomSheet( + DashUIKit.BottomSheet( title: NSLocalizedString("Filter transactions", comment: ""), showBackButton: .constant(false) ) { diff --git a/DashWallet/Sources/UI/Swap/Buy/EnterAmount/BuyEnterAmountView.swift b/DashWallet/Sources/UI/Swap/Buy/EnterAmount/BuyEnterAmountView.swift index 69faa759a..71048d429 100644 --- a/DashWallet/Sources/UI/Swap/Buy/EnterAmount/BuyEnterAmountView.swift +++ b/DashWallet/Sources/UI/Swap/Buy/EnterAmount/BuyEnterAmountView.swift @@ -56,7 +56,7 @@ struct BuyEnterAmountView: View { } .dexOfflineToast(isOnline: viewModel.isOnline) .sheet(isPresented: $showLocalCurrency) { - let dialog = BottomSheet( + let dialog = DashUIKit.BottomSheet( showBackButton: Binding.constant(false) ) { LocalCurrencyView { code in diff --git a/DashWallet/Sources/UI/Swap/Convert/SwapConvertView.swift b/DashWallet/Sources/UI/Swap/Convert/SwapConvertView.swift index e653b2098..0bc954c9d 100644 --- a/DashWallet/Sources/UI/Swap/Convert/SwapConvertView.swift +++ b/DashWallet/Sources/UI/Swap/Convert/SwapConvertView.swift @@ -52,7 +52,7 @@ struct SwapConvertView: View { } .dexOfflineToast(isOnline: viewModel.isOnline) .sheet(isPresented: $showLocalCurrency) { - let dialog = BottomSheet( + let dialog = DashUIKit.BottomSheet( showBackButton: Binding.constant(false) ) { LocalCurrencyView { code in diff --git a/DashWallet/Sources/UI/Swap/OrderPreview/Components/OrderPreviewFeeRow.swift b/DashWallet/Sources/UI/Swap/OrderPreview/Components/OrderPreviewFeeRow.swift index eaec298fe..16d71c67f 100644 --- a/DashWallet/Sources/UI/Swap/OrderPreview/Components/OrderPreviewFeeRow.swift +++ b/DashWallet/Sources/UI/Swap/OrderPreview/Components/OrderPreviewFeeRow.swift @@ -66,7 +66,7 @@ struct OrderPreviewFeeRow: View { .padding(.vertical, rowVPadding) .frame(minHeight: rowMinHeight) .sheet(isPresented: $showInfoSheet) { - BottomSheet(showBackButton: .constant(false), fillsHeight: false) { + DashUIKit.BottomSheet(showBackButton: .constant(false), fillsHeight: false) { SwapFeeInfoSheet( usesGenericFeeInfo: usesGenericFeeInfo, onDismiss: { showInfoSheet = false } diff --git a/DashWallet/Sources/UI/Swap/OrderPreview/Components/SwapFeeInfoSheet.swift b/DashWallet/Sources/UI/Swap/OrderPreview/Components/SwapFeeInfoSheet.swift index a802bc530..58b1528bf 100644 --- a/DashWallet/Sources/UI/Swap/OrderPreview/Components/SwapFeeInfoSheet.swift +++ b/DashWallet/Sources/UI/Swap/OrderPreview/Components/SwapFeeInfoSheet.swift @@ -99,7 +99,7 @@ private struct SwapFeeInfoSheetPreviewHost: View { Color.dash.primaryBackground .ignoresSafeArea() .sheet(isPresented: $isPresented) { -// let sheet = BottomSheet(showBackButton: .constant(false)) { +// let sheet = DashUIKit.BottomSheet(showBackButton: .constant(false)) { // SwapFeeInfoSheet(onDismiss: {}) // } // @@ -109,7 +109,7 @@ private struct SwapFeeInfoSheetPreviewHost: View { // sheet // } - BottomSheet(showBackButton: .constant(false), fillsHeight: false) { + DashUIKit.BottomSheet(showBackButton: .constant(false), fillsHeight: false) { SwapFeeInfoSheet(usesGenericFeeInfo: false, onDismiss: {}) } .selfSizingSheet() diff --git a/DashWallet/Sources/UI/SwiftUI Components/BottomSheet.swift b/DashWallet/Sources/UI/SwiftUI Components/BottomSheet.swift deleted file mode 100644 index 7b77d2eca..000000000 --- a/DashWallet/Sources/UI/SwiftUI Components/BottomSheet.swift +++ /dev/null @@ -1,152 +0,0 @@ -// -// Created by Andrei Ashikhmin -// Copyright © 2024 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 BottomSheet: View { - @Environment(\.presentationMode) private var presentationMode - - var title: String = "" - @Binding var showBackButton: Bool - var onBackButtonPressed: (() -> Void)? = nil - /// `true` (default) — greedy: content fills the sheet (use with an explicit detent or a - /// `.large`/`.medium` detent). `false` — natural height: pair with `.selfSizingSheet()` so - /// the sheet snaps to its content. - var fillsHeight: Bool = true - @ViewBuilder var content: () -> Content - - var body: some View { - let sheet = VStack(spacing: 0) { - grabber - .frame(maxWidth: .infinity, minHeight: 18, maxHeight: 18, alignment: .center) - - header - - contentSection - } - .background(Color.dash.primaryBackground) - - if fillsHeight { - sheet.edgesIgnoringSafeArea(.bottom) - } else { - // Publish the natural content height for `.selfSizingSheet()`. The bottom safe area is - // intentionally NOT ignored here, so the measured height excludes the home-indicator - // inset — `.presentationDetents([.height])` adds that inset itself. - // - // `.fixedSize(vertical:)` is critical: it makes the sheet report its *ideal* height - // independent of the height the sheet currently offers. Without it the measurement is - // coupled to the detent (detent ← measured ← offered height ← detent), so it ping-pongs - // by ~the safe-area inset and the presenting view (HomeView) jitters up/down. - sheet - .fixedSize(horizontal: false, vertical: true) - .background( - GeometryReader { proxy in - Color.clear.preference( - key: BottomSheetHeightPreferenceKey.self, - value: proxy.size.height - ) - } - ) - } - } - - private var grabber: some View { - Rectangle() - .foregroundColor(.clear) - .frame(width: 36, height: 5) - .background(Color.dash.gray300Alpha50) - .cornerRadius(5) - } - - private var header: some View { - // Reuse the shared NavigationBar (absolutely-centered title, own 64pt height + - // horizontal padding). Title styling preserved; back/close use NavigationBarElement. - NavigationBar( - leading: { - if showBackButton { - NavigationBarElement.back.button { onBackButtonPressed?() } - } - }, - central: { - Text(title) - .font(.calloutMedium) - .foregroundColor(.dash.primaryText) - }, - trailing: { - NavigationBarElement.close.button { presentationMode.wrappedValue.dismiss() } - } - ) - } - - @ViewBuilder - private var contentSection: some View { - if fillsHeight { - NavigationView { - content() - .navigationBarHidden(true) - .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(Color.dash.primaryBackground) - } - } else { - // Natural height — no greedy NavigationView / maxHeight so the sheet can self-size. - content() - .frame(maxWidth: .infinity) - .background(Color.dash.primaryBackground) - } - } -} - -// MARK: - Auto-sizing - -/// Bubbles a `BottomSheet`'s measured natural height up to `.selfSizingSheet()`. -struct BottomSheetHeightPreferenceKey: PreferenceKey { - static var defaultValue: CGFloat = 0 - static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { - value = max(value, nextValue()) - } -} - -extension View { - /// Sizes a `BottomSheet` (built with `fillsHeight: false`) to its content's natural height — - /// no hardcoded `.height(...)` needed. On iOS < 16 it is a no-op. - @ViewBuilder - func selfSizingSheet(fallback: CGFloat = 0, maxHeightFraction: CGFloat = 0.95) -> some View { - if #available(iOS 16.0, *) { - modifier(SelfSizingSheetModifier(fallback: fallback, maxHeightFraction: maxHeightFraction)) - } else { - self - } - } -} - -@available(iOS 16.0, *) -private struct SelfSizingSheetModifier: ViewModifier { - let fallback: CGFloat - let maxHeightFraction: CGFloat - @State private var measured: CGFloat = 0 - - func body(content: Content) -> some View { - let cap = UIScreen.main.bounds.height * maxHeightFraction - let resolved = min(measured > 0 ? measured : fallback, cap) - content - .onPreferenceChange(BottomSheetHeightPreferenceKey.self) { measured = $0 } - // Before the first measurement (and when nothing is provided) fall back to .medium so - // the sheet is never given an invalid 0-height detent. - .presentationDetents(resolved > 0 ? [.height(resolved)] : [.medium]) - } -} diff --git a/DashWallet/Sources/UI/SwiftUI Components/SelfSizingSheet.swift b/DashWallet/Sources/UI/SwiftUI Components/SelfSizingSheet.swift deleted file mode 100644 index b92ec7d19..000000000 --- a/DashWallet/Sources/UI/SwiftUI Components/SelfSizingSheet.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 -import DashUIKit - -// Self-sizing sheet: the sheet hugs its content height instead of using a fixed -// detent. Measures the content via GeometryReader and feeds the height into a -// single `.height` presentation detent. -// -// Notes: -// - A single detent (no .large) means the sheet cannot be dragged to full screen, -// and iOS does not show the system drag indicator. -// - Until a real measurement arrives, .medium is used as a placeholder so the -// sheet doesn't collapse (a height of 0 would make iOS fall back to full screen). -// - The measured view must have a finite intrinsic height (no greedy Spacers / -// maxHeight: .infinity), otherwise it expands to fill the offered space and the -// measurement is wrong. See BottomSheet(fillsHeight: false). - -@available(iOS 16.0, *) -private struct SelfSizingSheetModifier: ViewModifier { - @State private var height: CGFloat? - - func body(content: Content) -> some View { - content - .background( - GeometryReader { geo in - Color.clear - .onAppear { update(geo.size.height) } - .onChange(of: geo.size.height) { update($0) } - } - ) - .presentationDetents(detents) - .presentationDragIndicator(.hidden) - } - - private var detents: Set { - guard let height, height > 0 else { return [.medium] } - return [.height(height)] - } - - private func update(_ newHeight: CGFloat) { - guard newHeight > 0, newHeight != height else { return } - height = newHeight - } -} - -extension View { - /// Applies a self-sizing sheet detent so the sheet fits its content automatically. - /// - /// - Parameter cornerRadius: Optional corner radius applied via `presentationCornerRadius` - /// on iOS 16.4..<26 only. Pass `nil` (default) to skip. iOS 26+ uses the system sheet - /// corner styling, so the custom radius is intentionally not applied there. - /// - /// The iOS 16 guard is built-in; callers do NOT need their own `#available` check. - @ViewBuilder - func selfSizingSheet(cornerRadius: CGFloat? = nil) -> some View { - if #available(iOS 16.0, *) { - let modified = modifier(SelfSizingSheetModifier()) - if #available(iOS 16.4, *), let r = cornerRadius { - if #unavailable(iOS 26.0) { - // iOS 16.4..<26: apply the custom corner radius. - modified - .presentationCornerRadius(r) - .presentationBackground(Color.dash.primaryBackground) - } else { - // iOS 26+: keep the system corner styling, skip the custom radius. - modified - .presentationBackground(Color.dash.primaryBackground) - } - } else { - modified - } - } else { - self - } - } -} diff --git a/DashWallet/Sources/UI/Tx/Details/TxDetailViewController.swift b/DashWallet/Sources/UI/Tx/Details/TxDetailViewController.swift index 94fc811d2..041b6d334 100644 --- a/DashWallet/Sources/UI/Tx/Details/TxDetailViewController.swift +++ b/DashWallet/Sources/UI/Tx/Details/TxDetailViewController.swift @@ -17,6 +17,7 @@ import UIKit import SwiftUI +import DashUIKit // MARK: - TxDetailDisplayType @@ -223,7 +224,7 @@ class TXDetailViewController: BaseTxDetailsViewController { extension TXDetailViewController { private func viewInBlockExplorer() { - let swiftUIView = BottomSheet( + let swiftUIView = DashUIKit.BottomSheet( title: NSLocalizedString("Select block explorer", comment: "Block explorer picker"), showBackButton: Binding.constant(false) ) { @@ -259,7 +260,7 @@ extension TXDetailViewController { /// Full consensus-field inspector for this transaction's stored raw bytes. private func viewRawTransaction() { - let sheet = BottomSheet( + let sheet = DashUIKit.BottomSheet( title: NSLocalizedString("Transaction", comment: "Raw transaction inspector"), showBackButton: Binding.constant(false) ) { From da64754531a36be79756f03140380be540056459 Mon Sep 17 00:00:00 2001 From: pasta Date: Wed, 26 Aug 2026 16:08:43 +0200 Subject: [PATCH 3/5] refactor(ui): remove legacy sheet measurement --- .../CrowdNodeBalanceReminderSheet.swift | 3 +-- .../DashSpend/DashSpendConfirmationDialog.swift | 15 ++------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderSheet.swift b/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderSheet.swift index f6568dbcf..6b59d5035 100644 --- a/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderSheet.swift +++ b/DashWallet/Sources/UI/CrowdNode/BalanceReminder/CrowdNodeBalanceReminderSheet.swift @@ -85,8 +85,7 @@ struct CrowdNodeBalanceReminderSheet: View { .ignoresSafeArea() .sheet(isPresented: .constant(true)) { // 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`. + // and (via `cornerRadius`) fills the sheet background + rounds the corners. // `fallback` avoids the `.medium` flash before the first measurement. DashUIKit.BottomSheet.selfSizing( showBackButton: .constant(false), diff --git a/DashWallet/Sources/UI/Explore Dash/Views/DashSpend/DashSpendConfirmationDialog.swift b/DashWallet/Sources/UI/Explore Dash/Views/DashSpend/DashSpendConfirmationDialog.swift index 6dcf646db..8ae8f769e 100644 --- a/DashWallet/Sources/UI/Explore Dash/Views/DashSpend/DashSpendConfirmationDialog.swift +++ b/DashWallet/Sources/UI/Explore Dash/Views/DashSpend/DashSpendConfirmationDialog.swift @@ -163,20 +163,9 @@ struct DashSpendConfirmationDialog: View { .padding(.horizontal, 20) .padding(.bottom, 20) } - // Publish the natural height so `.selfSizingSheet()` (which reads - // `BottomSheetHeightPreferenceKey`) can size the sheet. This dialog is not a `BottomSheet`, - // so without this the modifier never gets a measurement and falls back to `.medium`, which - // is too short and lets the content overflow above the sheet. `.fixedSize(vertical:)` keeps - // the measurement stable (decoupled from the offered height) like the BottomSheet does. + // Keep the natural height independent of the offered detent so DashUIKit's + // `.selfSizingSheet()` can measure a stable intrinsic height. .fixedSize(horizontal: false, vertical: true) - .background( - GeometryReader { proxy in - Color.clear.preference( - key: BottomSheetHeightPreferenceKey.self, - value: proxy.size.height - ) - } - ) } private func detailsRow(title: String, @ViewBuilder value: () -> some View) -> some View { From ab566189742eb386516e9fc4c2d9e940d577a749 Mon Sep 17 00:00:00 2001 From: pasta Date: Thu, 27 Aug 2026 00:43:46 +0200 Subject: [PATCH 4/5] fix(ui): preserve marketplace sheet layouts --- .../UsernameMarketplaceScreen.swift | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/DashWallet/Sources/UI/Explore Dash/UsernameMarketplaceScreen.swift b/DashWallet/Sources/UI/Explore Dash/UsernameMarketplaceScreen.swift index 3416fafb1..46534f7d9 100644 --- a/DashWallet/Sources/UI/Explore Dash/UsernameMarketplaceScreen.swift +++ b/DashWallet/Sources/UI/Explore Dash/UsernameMarketplaceScreen.swift @@ -475,10 +475,8 @@ struct UsernameMarketplaceScreen: View { .background(Color.dash.primaryBackground.ignoresSafeArea()) .onAppear { viewModel.loadMyNames() } .sheet(item: $selectedLabel) { selected in - DashUIKit.BottomSheet(showBackButton: .constant(false)) { - MarketplaceNameDetailSheet(selection: selected, viewModel: viewModel) - } - .presentationDetents([.medium, .large]) + MarketplaceNameDetailSheet(selection: selected, viewModel: viewModel) + .presentationDetents([.medium, .large]) } .sheet(item: $registerCandidate) { candidate in if candidate.isContested { @@ -1155,16 +1153,12 @@ private struct MarketplaceNameDetailSheet: View { } } .sheet(isPresented: $showingSetPrice) { - DashUIKit.BottomSheet(showBackButton: .constant(false)) { - SetNamePriceSheet(label: label, viewModel: viewModel, onDone: { dismiss() }) - } - .presentationDetents([.medium, .large]) + SetNamePriceSheet(label: label, viewModel: viewModel, onDone: { dismiss() }) + .presentationDetents([.medium, .large]) } .sheet(isPresented: $showingTransfer) { - DashUIKit.BottomSheet(showBackButton: .constant(false)) { - TransferNameSheet(label: label, viewModel: viewModel, onDone: { dismiss() }) - } - .presentationDetents([.medium, .large]) + TransferNameSheet(label: label, viewModel: viewModel, onDone: { dismiss() }) + .presentationDetents([.medium, .large]) } } From 3afe61a363ee75b393d6af3084f26e799316c62f Mon Sep 17 00:00:00 2001 From: Roman <51091564+jeanpierreroma@users.noreply.github.com> Date: Thu, 27 Aug 2026 21:07:09 +0300 Subject: [PATCH 5/5] chore(ui): drop the dead commented-out sheet block The block was updated to the new `DashUIKit.BottomSheet` name rather than removed. Keeping commented-out code in sync with live code is carrying cost with no payoff. --- .../OrderPreview/Components/SwapFeeInfoSheet.swift | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/DashWallet/Sources/UI/Swap/OrderPreview/Components/SwapFeeInfoSheet.swift b/DashWallet/Sources/UI/Swap/OrderPreview/Components/SwapFeeInfoSheet.swift index 58b1528bf..033ad4cf1 100644 --- a/DashWallet/Sources/UI/Swap/OrderPreview/Components/SwapFeeInfoSheet.swift +++ b/DashWallet/Sources/UI/Swap/OrderPreview/Components/SwapFeeInfoSheet.swift @@ -99,16 +99,6 @@ private struct SwapFeeInfoSheetPreviewHost: View { Color.dash.primaryBackground .ignoresSafeArea() .sheet(isPresented: $isPresented) { -// let sheet = DashUIKit.BottomSheet(showBackButton: .constant(false)) { -// SwapFeeInfoSheet(onDismiss: {}) -// } -// -// if #available(iOS 16.0, *) { -// sheet.presentationDetents([.height(450)]) -// } else { -// sheet -// } - DashUIKit.BottomSheet(showBackButton: .constant(false), fillsHeight: false) { SwapFeeInfoSheet(usesGenericFeeInfo: false, onDismiss: {}) }