Give Monero sync its own section and consolidate the wallet buttons
This commit is contained in:
@@ -258,4 +258,53 @@ struct ScreenHeader: View {
|
|||||||
Spacer()
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ struct RootView: View {
|
|||||||
struct HomeView: View {
|
struct HomeView: View {
|
||||||
@EnvironmentObject private var model: AppModel
|
@EnvironmentObject private var model: AppModel
|
||||||
@Binding var route: Route
|
@Binding var route: Route
|
||||||
@State private var showDeleteConfirm = false
|
|
||||||
@State private var selectedTransaction: TransactionRecord?
|
@State private var selectedTransaction: TransactionRecord?
|
||||||
@State private var showSettings = false
|
@State private var showSettings = false
|
||||||
@State private var qrAddress: AddressQR?
|
@State private var qrAddress: AddressQR?
|
||||||
@@ -137,19 +136,6 @@ struct HomeView: View {
|
|||||||
SettingsView()
|
SettingsView()
|
||||||
.environmentObject(model)
|
.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 {
|
private var header: some View {
|
||||||
@@ -189,9 +175,6 @@ struct HomeView: View {
|
|||||||
.font(.system(size: 16, weight: .semibold))
|
.font(.system(size: 16, weight: .semibold))
|
||||||
.foregroundStyle(Theme.text)
|
.foregroundStyle(Theme.text)
|
||||||
Spacer()
|
Spacer()
|
||||||
if model.chain == .xmr, let status = model.syncStatus {
|
|
||||||
SyncBadge(status: status)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if model.chain == .xmr, !model.moneroAccounts.isEmpty {
|
if model.chain == .xmr, !model.moneroAccounts.isEmpty {
|
||||||
@@ -223,25 +206,25 @@ struct HomeView: View {
|
|||||||
AddressRow(address: model.displayAddress)
|
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) {
|
HStack(spacing: 10) {
|
||||||
PrimaryButton(title: "Send") { route = .send }
|
PrimaryButton(title: "Send") { route = .send }
|
||||||
SecondaryButton(title: "Receive") { route = .receive }
|
SecondaryButton(title: "Receive") { route = .receive }
|
||||||
SecondaryButton(title: "Swap") { route = .swap }
|
SecondaryButton(title: "Swap") { route = .swap }
|
||||||
}
|
}
|
||||||
|
|
||||||
if model.chain == .xmr {
|
HStack(spacing: 12) {
|
||||||
HStack(spacing: 10) {
|
IconButton(systemName: "arrow.clockwise") { Task { await model.refresh(force: true) } }
|
||||||
SecondaryButton(title: model.syncStatus?.syncing == true ? "Syncing…" : "Sync now") {
|
if model.chain == .xmr {
|
||||||
Task { await model.startMoneroSync() }
|
IconButton(systemName: "person.2.fill") { route = .accounts }
|
||||||
}
|
|
||||||
SecondaryButton(title: "Addresses") { route = .accounts }
|
|
||||||
}
|
}
|
||||||
|
Spacer()
|
||||||
}
|
}
|
||||||
|
|
||||||
if model.chain == .xrp, model.moneroReady, let status = model.syncStatus, status.syncing {
|
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 {
|
if !model.transactions.isEmpty {
|
||||||
Card {
|
Card {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import SwiftUI
|
|||||||
struct SettingsView: View {
|
struct SettingsView: View {
|
||||||
@EnvironmentObject private var model: AppModel
|
@EnvironmentObject private var model: AppModel
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.dismiss) private var dismiss
|
||||||
|
@State private var showDeleteConfirm = false
|
||||||
|
|
||||||
private let currencies = ["USD", "MYR", "JPY"]
|
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)
|
Spacer(minLength: 0)
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 20)
|
.padding(.horizontal, 20)
|
||||||
.padding(.top, 12)
|
.padding(.top, 12)
|
||||||
}
|
}
|
||||||
.preferredColorScheme(.dark)
|
.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.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user