Require Face ID to open the app and to send

This commit is contained in:
2026-09-27 23:35:26 +08:00
parent b989b0f791
commit 78e1cefad4
8 changed files with 172 additions and 7 deletions
+35 -7
View File
@@ -59,6 +59,13 @@ struct RootView: View {
.scrollDismissesKeyboard(.interactively)
}
.preferredColorScheme(.dark)
.overlay {
if model.locked, model.faceIDEnabled {
LockScreen {
Task { await model.authenticate() }
}
}
}
.task { await model.bootstrap() }
.sheet(item: $seedBox) { box in
SeedRevealView(seed: box.seed, symbol: box.symbol) { seedBox = nil }
@@ -67,6 +74,9 @@ struct RootView: View {
if route == .dashboard { route = .home }
}
.onChange(of: scenePhase) { phase in
if phase == .background, model.faceIDEnabled, Biometrics.isAvailable {
model.locked = true
}
if phase != .active {
Task { await model.persistWallet() }
}
@@ -79,6 +89,7 @@ struct HomeView: View {
@Binding var route: Route
@State private var showDeleteConfirm = false
@State private var selectedTransaction: TransactionRecord?
@State private var showSettings = false
var body: some View {
VStack(spacing: 18) {
@@ -104,6 +115,10 @@ struct HomeView: View {
symbol: model.symbol,
chain: model.chain) { selectedTransaction = nil }
}
.sheet(isPresented: $showSettings) {
SettingsView()
.environmentObject(model)
}
.confirmationDialog("Delete this wallet?",
isPresented: $showDeleteConfirm,
titleVisibility: .visible) {
@@ -120,13 +135,26 @@ struct HomeView: View {
}
private var header: some View {
VStack(alignment: .leading, spacing: 4) {
Text("Koins")
.font(.system(size: 30, weight: .heavy))
.foregroundStyle(Theme.text)
Text("Monero and XRP wallet")
.font(.system(size: 13))
.foregroundStyle(Theme.muted)
HStack(alignment: .firstTextBaseline) {
VStack(alignment: .leading, spacing: 4) {
Text("Koins")
.font(.system(size: 30, weight: .heavy))
.foregroundStyle(Theme.text)
Text("Monero and XRP wallet")
.font(.system(size: 13))
.foregroundStyle(Theme.muted)
}
Spacer()
Button {
showSettings = true
} label: {
Image(systemName: "gearshape")
.font(.system(size: 17, weight: .medium))
.foregroundStyle(Theme.muted)
.frame(width: 36, height: 36)
.background(Theme.surface)
.clipShape(Circle())
}
}
.frame(maxWidth: .infinity, alignment: .leading)
}