this repo has no description
1//
2// ContentView.swift
3// AtProtoBackup
4//
5// Created by Corey Alexander on 8/25/25.
6//
7
8import SwiftUI
9import SwiftData
10
11struct ContentView: View {
12 @Environment(\.modelContext) private var modelContext
13 @Query private var items: [Account]
14 @State private var showingAlert = false
15 @State private var inputText = ""
16 @State private var isLoading = false
17 @State private var errorMessage: String?
18 @State private var selectedAccount: PersistentIdentifier?
19
20 var body: some View {
21 NavigationSplitView {
22 List(selection: $selectedAccount) {
23 ForEach(items) { item in
24 AccountListItemView(account: item)
25 .tag(item.id)
26 }
27 .onDelete(perform: deleteItems)
28 }
29#if os(macOS)
30 .navigationSplitViewColumnWidth(min: 180, ideal: 200)
31#endif
32 .toolbar {
33#if os(iOS)
34 ToolbarItem(placement: .navigationBarTrailing) {
35 EditButton()
36 }
37#endif
38 ToolbarItem {
39 Button(action: addItem) {
40 Label("Add Account", systemImage: "plus")
41 }
42 }
43 }
44 } detail: {
45 if let selectedId = selectedAccount,
46 let account = items.first(where: { $0.id == selectedId }) {
47 AccountDetailView(account: account)
48 } else {
49 Text("Select an item")
50 }
51 }
52 .onAppear {
53 discoverAndAddBackedUpAccounts()
54 }
55 .alert("Add AT Protocol Account", isPresented: $showingAlert) {
56 TextField("Enter handle (e.g., user.bsky.social)", text: $inputText)
57 Button("Add") {
58 print("[ContentView] Add button in alert pressed")
59 Task {
60 await lookupAndAddAccount()
61 }
62 }
63 Button("Cancel", role: .cancel) {
64 inputText = ""
65 errorMessage = nil
66 }
67 } message: {
68 if let errorMessage = errorMessage {
69 Text(errorMessage)
70 } else if isLoading {
71 Text("Looking up DID...")
72 } else {
73 Text("Enter your AT Protocol handle")
74 }
75 }
76 }
77
78
79 private func addItem() {
80 print("[ContentView] Add button clicked")
81 inputText = ""
82 errorMessage = nil
83 showingAlert = true
84 }
85
86 private func lookupAndAddAccount() async {
87 print("[ContentView] lookupAndAddAccount called with handle: '\(inputText)'")
88 isLoading = true
89 errorMessage = nil
90
91 do {
92 print("[ContentView] Starting API lookup...")
93 let (parsed, jsonData) = try await ATProtocolService.shared.lookupDID(for: inputText.lowercased())
94 print("[ContentView] API lookup successful - DID: \(parsed.did)")
95
96 await MainActor.run {
97 print("[ContentView] Creating and inserting Account object")
98 withAnimation {
99 let account = Account(did: parsed.did, handle: inputText, pds: parsed.pds, jsonResponse: jsonData)
100 modelContext.insert(account)
101 print("[ContentView] Account inserted into modelContext")
102
103 // Auto-select the newly added account
104 selectedAccount = account.id
105 print("[ContentView] Auto-selected new account: \(account.id)")
106 }
107 showingAlert = false
108 inputText = ""
109 isLoading = false
110 print("[ContentView] Alert dismissed, operation complete")
111 }
112 } catch {
113 print("[ContentView] Error during lookup: \(error)")
114 await MainActor.run {
115 errorMessage = "Error: \(error.localizedDescription)"
116 isLoading = false
117 }
118 }
119 }
120
121 private func deleteItems(offsets: IndexSet) {
122 withAnimation {
123 for index in offsets {
124 modelContext.delete(items[index])
125 }
126 }
127 }
128
129 private func discoverAndAddBackedUpAccounts() {
130 Task {
131 do {
132 let discovered = try BackupDiscovery.discoverBackedUpAccounts()
133 print("[ContentView] Discovered \(discovered.count) backed up accounts")
134
135 await MainActor.run {
136 for discoveredAccount in discovered {
137 // Check if account already exists
138 let exists = items.contains { $0.did == discoveredAccount.did }
139
140 if !exists {
141 print("[ContentView] Adding discovered account: \(discoveredAccount.handle ?? discoveredAccount.did)")
142
143 // Create account with discovered information from backup metadata
144 let account = Account(
145 did: discoveredAccount.did,
146 handle: discoveredAccount.handle ?? discoveredAccount.did,
147 pds: discoveredAccount.pds ?? "https://bsky.network",
148 jsonResponse: nil
149 )
150
151 modelContext.insert(account)
152 }
153 }
154 }
155 } catch {
156 print("[ContentView] Error discovering backed up accounts: \(error)")
157 }
158 }
159 }
160}
161
162#Preview {
163 ContentView()
164 .modelContainer(for: Account.self, inMemory: false)
165}