Give Monero sync its own section and consolidate the wallet buttons

This commit is contained in:
2026-10-10 20:18:41 +08:00
parent 7e739e1b77
commit c9679e35c4
3 changed files with 95 additions and 31 deletions
+50 -1
View File
@@ -258,4 +258,53 @@ struct ScreenHeader: View {
Spacer()
}
}
}
}
/// Monero's chain sync as its own section, rather than buried in the wallet card.
struct SyncCard: View {
@EnvironmentObject private var model: AppModel
var body: some View {
Card {
VStack(alignment: .leading, spacing: 12) {
HStack {
Text("Sync")
.font(.system(size: 13, weight: .semibold))
.foregroundStyle(Theme.muted)
Spacer()
if let status = model.syncStatus { SyncBadge(status: status) }
}
if let status = model.syncStatus {
SyncProgress(status: status, eta: model.syncEta)
} else {
Text("Sync status is not available yet.")
.font(.system(size: 11))
.foregroundStyle(Theme.muted)
}
SecondaryButton(title: model.syncStatus?.syncing == true ? "Syncing…" : "Sync now") {
Task { await model.startMoneroSync() }
}
}
}
}
}
/// A small circular icon button for utility actions (refresh, delete, …).
struct IconButton: View {
var systemName: String
var destructive = false
var action: () -> Void
var body: some View {
Button(action: action) {
Image(systemName: systemName)
.font(.system(size: 14, weight: .semibold))
.foregroundStyle(destructive ? Theme.danger : Theme.muted)
.frame(width: 42, height: 42)
.background(Theme.surface)
.overlay(Circle().stroke(Theme.border))
.clipShape(Circle())
}
}
}
+9 -30
View File
@@ -91,7 +91,6 @@ struct RootView: View {
struct HomeView: View {
@EnvironmentObject private var model: AppModel
@Binding var route: Route
@State private var showDeleteConfirm = false
@State private var selectedTransaction: TransactionRecord?
@State private var showSettings = false
@State private var qrAddress: AddressQR?
@@ -137,19 +136,6 @@ struct HomeView: View {
SettingsView()
.environmentObject(model)
}
.confirmationDialog("Delete this wallet?",
isPresented: $showDeleteConfirm,
titleVisibility: .visible) {
Button("Delete wallet", role: .destructive) {
Task {
await model.deleteWallet()
route = .home
}
}
Button("Cancel", role: .cancel) {}
} message: {
Text("The keys stored on this device are removed. Make sure your recovery seed is backed up.")
}
}
private var header: some View {
@@ -189,9 +175,6 @@ struct HomeView: View {
.font(.system(size: 16, weight: .semibold))
.foregroundStyle(Theme.text)
Spacer()
if model.chain == .xmr, let status = model.syncStatus {
SyncBadge(status: status)
}
}
if model.chain == .xmr, !model.moneroAccounts.isEmpty {
@@ -223,25 +206,25 @@ struct HomeView: View {
AddressRow(address: model.displayAddress)
}
if model.chain == .xmr, let status = model.syncStatus {
SyncProgress(status: status, eta: model.syncEta)
}
}
}
if model.chain == .xmr {
SyncCard()
}
HStack(spacing: 10) {
PrimaryButton(title: "Send") { route = .send }
SecondaryButton(title: "Receive") { route = .receive }
SecondaryButton(title: "Swap") { route = .swap }
}
if model.chain == .xmr {
HStack(spacing: 10) {
SecondaryButton(title: model.syncStatus?.syncing == true ? "Syncing…" : "Sync now") {
Task { await model.startMoneroSync() }
}
SecondaryButton(title: "Addresses") { route = .accounts }
HStack(spacing: 12) {
IconButton(systemName: "arrow.clockwise") { Task { await model.refresh(force: true) } }
if model.chain == .xmr {
IconButton(systemName: "person.2.fill") { route = .accounts }
}
Spacer()
}
if model.chain == .xrp, model.moneroReady, let status = model.syncStatus, status.syncing {
@@ -264,10 +247,6 @@ struct HomeView: View {
}
}
HStack(spacing: 10) {
SecondaryButton(title: "Refresh") { Task { await model.refresh(force: true) } }
SecondaryButton(title: "Delete") { showDeleteConfirm = true }
}
if !model.transactions.isEmpty {
Card {
+36
View File
@@ -3,6 +3,7 @@ import SwiftUI
struct SettingsView: View {
@EnvironmentObject private var model: AppModel
@Environment(\.dismiss) private var dismiss
@State private var showDeleteConfirm = false
private let currencies = ["USD", "MYR", "JPY"]
@@ -63,11 +64,46 @@ struct SettingsView: View {
}
}
Card {
VStack(alignment: .leading, spacing: 10) {
Text("Danger zone")
.font(.system(size: 13, weight: .semibold))
.foregroundStyle(Theme.muted)
Button {
showDeleteConfirm = true
} label: {
Text("Delete this wallet")
.font(.system(size: 15, weight: .semibold))
.foregroundStyle(Theme.danger)
.frame(maxWidth: .infinity)
.padding(.vertical, 14)
.background(Theme.danger.opacity(0.12))
.clipShape(RoundedRectangle(cornerRadius: 14, style: .continuous))
}
Text("Removes the wallet from this device. Your recovery phrase is the only way to get it back.")
.font(.system(size: 11))
.foregroundStyle(Theme.muted)
}
}
Spacer(minLength: 0)
}
.padding(.horizontal, 20)
.padding(.top, 12)
}
.preferredColorScheme(.dark)
.confirmationDialog("Delete this wallet?",
isPresented: $showDeleteConfirm,
titleVisibility: .visible) {
Button("Delete wallet", role: .destructive) {
Task {
await model.deleteWallet()
dismiss()
}
}
Button("Cancel", role: .cancel) {}
} message: {
Text("The keys stored on this device are removed. Make sure your recovery phrase is backed up.")
}
}
}