Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions DashWallet.xcworkspace/xcshareddata/swiftpm/Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,10 @@ struct UsernameMarketplaceScreen: View {
}
.sheet(item: $registerCandidate) { candidate in
if candidate.isContested {
DashUIKit.BottomSheet(showBackButton: .constant(false)) {
DashUIKit.BottomSheet(
showBackButton: .constant(false),
isDismissalEnabled: .constant(!viewModel.isPerformingAction)
) {
RegisterNameSheet(
label: candidate.label,
isContested: candidate.isContested,
Expand All @@ -490,6 +493,7 @@ struct UsernameMarketplaceScreen: View {
} else {
DashUIKit.BottomSheet.selfSizing(
showBackButton: .constant(false),
isDismissalEnabled: .constant(!viewModel.isPerformingAction),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concrete consequence of the missing 8097d16 on the pinned revision: tapping Register/Request sets isPerformingAction = true, which flips isDismissalEnabled and — at e8d9243 — swaps _ConditionalContent branches, so SwiftUI rebuilds RegisterNameSheet from scratch.

Its @State goes with it: precheck and voteState reset to nil, the .task re-fires contestPrecheck/contestState, and the contest cards blank back to loading exactly while the action is running — then rebuild again when it finishes.

The four transfer sheets take the same rebuild on every start and end of a transfer; this one is just the easiest to observe.

fallback: 340,
cornerRadius: 24
) {
Expand Down Expand Up @@ -1842,7 +1846,6 @@ private struct RegisterNameSheet: View {
}
}
.background(Color.dash.primaryBackground)
.interactiveDismissDisabled(viewModel.isPerformingAction)
.overlay {
if let activity = viewModel.activityMessage {
MarketplaceActivityOverlay(message: activity)
Expand Down
103 changes: 51 additions & 52 deletions DashWallet/Sources/UI/Home/Views/CoinJoinMoveFundsSheet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -182,16 +182,15 @@ struct CoinJoinMoveFundsSheet: View {
}

var body: some View {
VStack(spacing: 0) {
dragHandle
.padding(.top, 8)

Text(NSLocalizedString("Move your mixed coins", comment: "CoinJoin"))
.font(.subheadline)
.fontWeight(.semibold)
.foregroundColor(.dash.primaryText)
.padding(.top, 20)

DashUIKit.BottomSheet(
title: NSLocalizedString("Move your mixed coins", comment: "CoinJoin"),
showBackButton: .constant(false),
isDismissalEnabled: .constant(!viewModel.isInFlight),
// Supplying `onClose` makes the close button live regardless of
// `isDismissalEnabled`, so the in-flight stages have to gate it here.
isCloseButtonEnabled: !viewModel.isInFlight,
onClose: onDismiss

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only migrated sheet whose initial detent is .medium (HomeView.swift:502, [.medium, .large]).

The BottomSheet chrome is 82pt (18pt grabber + 64pt navigation bar) against roughly 51pt for the handle and title it replaces, and choiceBody is a plain non-scrolling VStack — amount, explainer, two destination cards, "Later". The extra ~31pt comes out of the bottom, so on a shorter device the "Later" button can clip, and unlike the .large hosts there is no scroll fallback.

Worth either an explicit detent that accounts for the chrome, or making the body scrollable — b8cf2aa9 in this stack took the scroll route for TransferTimingSheet for the same reason.

) {
switch viewModel.stage {
case .choice:
choiceBody
Expand All @@ -207,49 +206,55 @@ struct CoinJoinMoveFundsSheet: View {
failedBody(message: message, destination: destination)
}
}
.background(Color.dash.primaryBackground)
.interactiveDismissDisabled(viewModel.isInFlight)
}

// MARK: Choice

private var choiceBody: some View {
VStack(spacing: 0) {
DashAmount(
amount: Int64(viewModel.amountDuffs),
font: .largeTitle,
dashSymbolFactor: 0.7,
showDirection: false)
.padding(.top, 14)

Text(NSLocalizedString(
"CoinJoin is no longer supported — choose where to move your mixed coins.",
comment: "CoinJoin"))
.font(.system(size: 14))
.foregroundColor(.dash.secondaryText)
.multilineTextAlignment(.center)
.padding(.horizontal, 24)
.padding(.top, 12)

VStack(spacing: 10) {
destinationCard(
icon: "wallet.pass.fill",
title: NSLocalizedString("Dash Wallet balance", comment: "CoinJoin"),
subtitle: NSLocalizedString(
"Move to your regular spendable balance.", comment: "CoinJoin"),
action: { Task { await viewModel.moveToWallet() } })
destinationCard(
icon: "shield.fill",
title: NSLocalizedString("Shielded balance", comment: "CoinJoin"),
subtitle: NSLocalizedString(
"Keep these coins private. Network and privacy fees apply.",
comment: "CoinJoin"),
action: { Task { await viewModel.moveToShielded() } })
// Scrollable: this is the only migrated sheet whose initial detent is
// `.medium`, and the BottomSheet chrome takes 82pt of it. Letting the
// choices scroll keeps "Later" — the only way out that records the
// deferral — reachable on a short screen or a long translation.
ScrollView {
VStack(spacing: 0) {
DashAmount(
amount: Int64(viewModel.amountDuffs),
font: .largeTitle,
dashSymbolFactor: 0.7,
showDirection: false)
.padding(.top, 14)

Text(NSLocalizedString(
"CoinJoin is no longer supported — choose where to move your mixed coins.",
comment: "CoinJoin"))
.font(.system(size: 14))
.foregroundColor(.dash.secondaryText)
.multilineTextAlignment(.center)
.padding(.horizontal, 24)
.padding(.top, 12)

VStack(spacing: 10) {
destinationCard(
icon: "wallet.pass.fill",
title: NSLocalizedString("Dash Wallet balance", comment: "CoinJoin"),
subtitle: NSLocalizedString(
"Move to your regular spendable balance.", comment: "CoinJoin"),
action: { Task { await viewModel.moveToWallet() } })
destinationCard(
icon: "shield.fill",
title: NSLocalizedString("Shielded balance", comment: "CoinJoin"),
subtitle: NSLocalizedString(
"Keep these coins private. Network and privacy fees apply.",
comment: "CoinJoin"),
action: { Task { await viewModel.moveToShielded() } })
}
.padding(.horizontal, 16)
.padding(.top, 20)
.padding(.bottom, 12)
}
}
.padding(.horizontal, 16)
.padding(.top, 20)

Spacer(minLength: 12)
.scrollBounceBehavior(.basedOnSize)

DashButton(
text: NSLocalizedString("Later", comment: "CoinJoin"),
Expand Down Expand Up @@ -421,10 +426,4 @@ struct CoinJoinMoveFundsSheet: View {

// MARK: Pieces

private var dragHandle: some View {
Rectangle()
.fill(Color.dash.grabberFill)
.frame(width: 36, height: 5)
.cornerRadius(2.5)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -348,19 +348,15 @@ struct EvonodeWithdrawalConfirmSheet: View {
let onUnconfirmedAcknowledged: () -> Void

var body: some View {
VStack(spacing: 0) {
Rectangle()
.fill(Color.dash.grabberFill)
.frame(width: 36, height: 5)
.cornerRadius(2.5)
.padding(.top, 8)

Text(NSLocalizedString("Confirm withdrawal", comment: "Evonode withdrawal"))
.font(.subheadline)
.fontWeight(.semibold)
.foregroundColor(.dash.primaryText)
.padding(.top, 20)

DashUIKit.BottomSheet(
title: NSLocalizedString("Confirm withdrawal", comment: "Evonode withdrawal"),
showBackButton: .constant(false),
isDismissalEnabled: .constant(!(isInFlight || isUnconfirmed)),
// Supplying `onClose` makes the close button live regardless of
// `isDismissalEnabled`, so the protected phases have to gate it here.
isCloseButtonEnabled: !(isInFlight || isUnconfirmed),
onClose: closeAction
) {
switch viewModel.phase {
case let .success(remaining):
successBody(remainingCredits: remaining)
Expand All @@ -370,15 +366,28 @@ struct EvonodeWithdrawalConfirmSheet: View {
detailsBody
}
}
.background(Color.dash.primaryBackground)
.interactiveDismissDisabled(isInFlight || isUnconfirmed)
}

private var isUnconfirmed: Bool {
if case .submittedUnconfirmed = viewModel.phase { return true }
return false
}

/// The close button has to do what the visible button of the current phase
/// does. `onCancel` only closes the sheet, so on success it would skip
/// `onWithdrawn(remaining)` and leave the withdrawal screen showing the
/// stale pre-withdrawal claimable balance.
private var closeAction: () -> Void {
switch viewModel.phase {
case let .success(remaining):
return { onCompleted(remaining) }
case .submittedUnconfirmed:
return onUnconfirmedAcknowledged
default:
return onCancel
}
}

private var isInFlight: Bool {
switch viewModel.phase {
case .authorizing, .submitting: return true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import SwiftDashSDK
/// `ShieldedTransferCoordinator.phase`:
/// - `.idle` → summary card + Cancel/Confirm buttons.
/// - in-flight phases → step checklist (Signing / Locking / Proving /
/// Broadcasting). Drag-dismiss is disabled.
/// Broadcasting). Sheet dismissal is disabled.
/// - `.success` → green check + amount + Done.
/// - `.failed(msg)` → summary card with red error + Try again / Close.
///
Expand Down Expand Up @@ -51,16 +51,15 @@ struct InternalTransferConfirmSheet: View {
@State private var handledPlatformShieldCapacityChange = false

var body: some View {
VStack(spacing: 0) {
dragHandle
.padding(.top, 8)

Text(NSLocalizedString("Confirm", comment: ""))
.font(.subheadline)
.fontWeight(.semibold)
.foregroundColor(.dash.primaryText)
.padding(.top, 20)

DashUIKit.BottomSheet(
title: NSLocalizedString("Confirm", comment: ""),
showBackButton: .constant(false),
isDismissalEnabled: .constant(!isInFlight),
// Supplying `onClose` makes the close button live regardless of
// `isDismissalEnabled`, so the protected phases have to gate it here.
isCloseButtonEnabled: !isInFlight,
onClose: closeAction
) {
switch coordinator.phase {
case .success:
successBody
Expand All @@ -70,8 +69,6 @@ struct InternalTransferConfirmSheet: View {
detailsBody
}
}
.background(Color.dash.primaryBackground)
.interactiveDismissDisabled(isInFlight)
.onChange(of: coordinator.phase) { phase in
handlePlatformShieldCapacityChange(phase)
}
Expand All @@ -86,6 +83,18 @@ struct InternalTransferConfirmSheet: View {
}
}

/// The close button has to do what the visible button of the current phase
/// does. In the terminal phases that is `onCompleted`, which tells the
/// transfer screen the transfer finished; `onCancel` only closes the sheet.
private var closeAction: () -> Void {
switch coordinator.phase {
case .success, .submittedUnconfirmed:
return onCompleted
default:
return onCancel
}
}

// MARK: - Idle / in-flight / failed body

private var detailsBody: some View {
Expand Down Expand Up @@ -192,13 +201,6 @@ struct InternalTransferConfirmSheet: View {

// MARK: - Pieces

private var dragHandle: some View {
Rectangle()
.fill(Color.dash.grabberFill)
.frame(width: 36, height: 5)
.cornerRadius(2.5)
}

private var secondaryLine: some View {
Text(fiatText)
.font(.subheadline)
Expand Down Expand Up @@ -553,16 +555,15 @@ struct ShieldedRecoverySheet: View {
@State private var alreadyComplete = false

var body: some View {
VStack(spacing: 0) {
dragHandle
.padding(.top, 8)

Text(NSLocalizedString("Finish shielded transfer", comment: "InternalTransfer recovery"))
.font(.subheadline)
.fontWeight(.semibold)
.foregroundColor(.dash.primaryText)
.padding(.top, 20)

DashUIKit.BottomSheet(
title: NSLocalizedString("Finish shielded transfer", comment: "InternalTransfer recovery"),
showBackButton: .constant(false),
isDismissalEnabled: .constant(!isInFlight),
// Supplying `onClose` makes the close button live regardless of
// `isDismissalEnabled`, so the protected phases have to gate it here.
isCloseButtonEnabled: !isInFlight,
onClose: onDismiss
) {
switch coordinator.phase {
case .success:
successBody
Expand All @@ -578,8 +579,6 @@ struct ShieldedRecoverySheet: View {
}
}
}
.background(Color.dash.primaryBackground)
.interactiveDismissDisabled(isInFlight)
}

private var isInFlight: Bool {
Expand Down Expand Up @@ -692,13 +691,6 @@ struct ShieldedRecoverySheet: View {

// MARK: - Pieces

private var dragHandle: some View {
Rectangle()
.fill(Color.dash.grabberFill)
.frame(width: 36, height: 5)
.cornerRadius(2.5)
}

private var infoCard: some View {
HStack(alignment: .top, spacing: 12) {
ZStack {
Expand Down
Loading
Loading