import SwiftUI struct AccountsView: View { @EnvironmentObject private var model: AppModel @EnvironmentObject private var drawers: DrawerCoordinator @Binding var route: Route @State private var error: String? @State private var busy = false @State private var showAccountPrompt = false @State private var showSubaddressPrompt = false @State private var pendingLabel = "" @State private var subaddressAccount = 0 var body: some View { VStack(alignment: .leading, spacing: 18) { ScreenHeader(title: "Accounts & addresses", subtitle: "Each address gets its own QR code", onBack: { route = .home }) PrimaryButton(title: busy ? "Working…" : "New account", disabled: busy) { showAccountPrompt = true } if let error { MessageBanner(message: error, isError: true) } ForEach(model.moneroAccounts) { account in accountCard(account) } if model.moneroAccounts.isEmpty { Text("No accounts yet. Accounts and addresses appear after the wallet opens.") .font(.system(size: 12)) .foregroundStyle(Theme.muted) } } .task(id: model.moneroReady) { await model.loadAccounts() } .alert("Account name", isPresented: $showAccountPrompt) { TextField("e.g. Savings", text: $pendingLabel) Button("Create") { createAccount() } Button("Cancel", role: .cancel) { pendingLabel = "" } } .alert("Address label", isPresented: $showSubaddressPrompt) { TextField("e.g. From Alice", text: $pendingLabel) Button("Create") { createSubaddress() } Button("Cancel", role: .cancel) { pendingLabel = "" } } } private func accountCard(_ account: MoneroAccount) -> some View { Card { VStack(alignment: .leading, spacing: 10) { HStack { VStack(alignment: .leading, spacing: 3) { Text(account.title) .font(.system(size: 15, weight: .semibold)) .foregroundStyle(Theme.text) Text("\(account.balance) XMR") .font(.system(size: 12)) .foregroundStyle(Theme.muted) } Spacer() } addressRow(title: "Primary address", address: account.address, isUsed: true) if !account.subaddresses.isEmpty { Divider().overlay(Theme.border) ForEach(account.subaddresses.filter { $0.index != 0 }) { subaddress in addressRow(title: subaddress.label.isEmpty ? "Address \(subaddress.index)" : subaddress.label, address: subaddress.address, isUsed: subaddress.isUsed, balance: subaddress.balance) } } SecondaryButton(title: "New address in this account") { subaddressAccount = account.index pendingLabel = "" showSubaddressPrompt = true } } } } private func addressRow(title: String, address: String, isUsed: Bool, balance: String? = nil) -> some View { Button { drawers.qr = AddressQR(title: title, address: address) } label: { HStack(spacing: 8) { VStack(alignment: .leading, spacing: 2) { Text(title) .font(.system(size: 12, weight: .medium)) .foregroundStyle(Theme.muted) Text(address.isEmpty ? "—" : address) .font(.system(size: 11, design: .monospaced)) .foregroundStyle(Theme.text) .lineLimit(1) .truncationMode(.middle) if let balance { Text("\(balance) XMR\(isUsed ? "" : " · unused")") .font(.system(size: 11)) .foregroundStyle(Theme.muted) } } Spacer(minLength: 6) Image(systemName: "qrcode") .font(.system(size: 14, weight: .semibold)) .foregroundStyle(Theme.accent) .frame(width: 32, height: 32) .background(Theme.surfaceAlt) .clipShape(RoundedRectangle(cornerRadius: 10, style: .continuous)) } .contentShape(Rectangle()) } .buttonStyle(.plain) .disabled(address.isEmpty) } private func createAccount() { busy = true error = nil Task { defer { busy = false } do { try await model.addAccount(label: pendingLabel) pendingLabel = "" } catch { self.error = error.localizedDescription } } } private func createSubaddress() { busy = true error = nil Task { defer { busy = false } do { try await model.addSubaddress(accountIndex: subaddressAccount, label: pendingLabel) pendingLabel = "" } catch { self.error = error.localizedDescription } } } }