diff --git a/RippleChat/ContentView.swift b/RippleChat/ContentView.swift index 2f33fa7..0eed3ba 100644 --- a/RippleChat/ContentView.swift +++ b/RippleChat/ContentView.swift @@ -10,7 +10,9 @@ import CoreBluetooth struct ContentView: View { @State var currentView = 0 - @StateObject var dataStore = DataStore() + @EnvironmentObject var dataStore: DataStore + @Environment(\.scenePhase) private var scenePhase + let saveAction: ()->Void var body: some View { VStack { @@ -61,14 +63,16 @@ struct ContentView: View { } .frame(height: UIScreen.main.bounds.height * 0.05) } + .onChange(of: scenePhase) { phase in + if phase == .inactive { saveAction() } + } - } } struct ContentView_Previews: PreviewProvider { static var previews: some View { - ContentView() + ContentView(saveAction: {}) .environmentObject(DataStore()) } } diff --git a/RippleChat/DataStore.swift b/RippleChat/DataStore.swift index eed3e22..f1b6b3c 100644 --- a/RippleChat/DataStore.swift +++ b/RippleChat/DataStore.swift @@ -8,16 +8,93 @@ import SwiftUI import Foundation +@MainActor class DataStore: ObservableObject { @Published var personalID: String - @Published var friends: [String] - @Published var feeds: [Feed] + @Published var friends: [String:Int] + @Published var feedStores: [FeedStore] - init(personalID: String = "", friends: [String] = [], feeds: [Feed] = []) { + init(personalID: String = "", friends: [String:Int] = [:], feedStores: [FeedStore] = []) { self.personalID = personalID self.friends = friends - self.feeds = feeds + self.feedStores = feedStores + } + + private func fileURL(for filename: String) throws -> URL { + try FileManager.default.url(for: .documentDirectory, + in: .userDomainMask, + appropriateFor: nil, + create: false) + .appendingPathComponent("\(filename).json") + } + + func savePersonalID() async throws { + let task = Task { + let data = try JSONEncoder().encode(personalID) + let outfile = try fileURL(for: "personalID") + try data.write(to: outfile) + } + _ = try await task.value + } + + func saveFriends() async throws { + let task = Task { + let data = try JSONEncoder().encode(friends) + let outfile = try fileURL(for: "friends") + try data.write(to: outfile) + } + _ = try await task.value + } + + func loadPersonalID() async throws { + let task = Task { + let fileURL = try self.fileURL(for: "personalID") + let data = try Data(contentsOf: fileURL) + let personalID = try JSONDecoder().decode(String.self, from: data) + return personalID + } + let personalID = try await task.value + self.personalID = personalID + } + + func loadFriends() async throws { + let task = Task<[String:Int], Error> { + let fileURL = try self.fileURL(for: "friends") + let data = try Data(contentsOf: fileURL) + let friends = try JSONDecoder().decode([String:Int].self, from: data) + return friends + } + let friends = try await task.value + self.friends = friends + } + + func loadFeedStores() async throws { + let task = Task<[FeedStore], Error> { + var feedStores: [FeedStore] = [] + for feedStore in self.feedStores { + try await feedStore.load() + feedStores.append(feedStore) + } + return feedStores + } + let feedStores = try await task.value + self.feedStores = feedStores + } + + func saveFeedStores() async throws { + let task = Task { + for feedStore in self.feedStores { + try await feedStore.save(feed: feedStore.feed) + } + } + _ = try await task.value } + +} + + +extension DataStore { + static let sampleDataStore = DataStore(personalID: "BOB", friends: SettingsView_Previews.friends, feedStores: [FeedStore(feed: Feed.sampleFeed), FeedStore(feed: Feed.sampleFeed2)]) } diff --git a/RippleChat/RippleChatApp.swift b/RippleChat/RippleChatApp.swift index d4a8766..df4264f 100644 --- a/RippleChat/RippleChatApp.swift +++ b/RippleChat/RippleChatApp.swift @@ -9,10 +9,33 @@ import SwiftUI @main struct RippleChatApp: App { + @StateObject private var dataStore = DataStore() var body: some Scene { WindowGroup { - ContentView() - + ContentView() { + Task { + do { + try await dataStore.savePersonalID() + try await dataStore.saveFriends() + try await dataStore.saveFeedStores() + } catch { + fatalError(error.localizedDescription) + } + } + } + .environmentObject(dataStore) + .task { + do { + try await dataStore.loadPersonalID() + try await dataStore.loadFriends() + try await dataStore.loadFeedStores() + } catch { + // Handle the error + print("Error loading data: \(error)") + fatalError(error.localizedDescription) + } + } + } } } diff --git a/RippleChat/Views/FeedListView.swift b/RippleChat/Views/FeedListView.swift index beeb971..174919a 100644 --- a/RippleChat/Views/FeedListView.swift +++ b/RippleChat/Views/FeedListView.swift @@ -22,9 +22,9 @@ struct FeedListView: View { Button("Save Feed") { Task { do { - for feed in feedStores { - try await feed.save(feed: feed.feed) - } + try await DataStore.sampleDataStore.saveFriends() + try await DataStore.sampleDataStore.savePersonalID() + try await DataStore.sampleDataStore.saveFeedStores() } catch { fatalError(error.localizedDescription) } diff --git a/RippleChat/Views/SettingsEditView.swift b/RippleChat/Views/SettingsEditView.swift index ba2f29b..314f9e4 100644 --- a/RippleChat/Views/SettingsEditView.swift +++ b/RippleChat/Views/SettingsEditView.swift @@ -20,18 +20,24 @@ struct SettingsEditView: View { } } Section(header: Text("Friends")) { - ForEach(dataStore.friends) { friend in - Label(friend, systemImage: "person") + ForEach(dataStore.friends.keys.sorted(), id: \.self) { friend in + if let seq = dataStore.friends[friend] { + Label("\(friend) - SEQ: \(seq)", systemImage: "person") + } + } + .onDelete { indexSet in do { + indexSet.forEach { index in + let key = dataStore.friends.keys.sorted()[index] + dataStore.friends.removeValue(forKey: key) + } + } - .onDelete {indices in - dataStore.friends.remove(atOffsets: indices) } HStack { TextField("New Feed", text: $newFeedID) Button(action: { withAnimation { - let feedid = newFeedID - dataStore.friends.append(feedid) + dataStore.friends[newFeedID] = 0 newFeedID = "" } }) { diff --git a/RippleChat/Views/SettingsView.swift b/RippleChat/Views/SettingsView.swift index cef546f..88f4ee4 100644 --- a/RippleChat/Views/SettingsView.swift +++ b/RippleChat/Views/SettingsView.swift @@ -22,8 +22,10 @@ struct SettingsView: View { Label(dataStore.personalID, systemImage: "person.crop.circle") } Section(header: Text("Friends")) { - ForEach(dataStore.friends) { friend in - Label(friend, systemImage: "person") + ForEach(dataStore.friends.keys.sorted(), id: \.self) { friend in + if let seq = dataStore.friends[friend] { + Label("\(friend) - SEQ: \(seq)", systemImage: "person") + } } } } @@ -62,9 +64,9 @@ struct SettingsView: View { struct SettingsView_Previews: PreviewProvider { static var friends = [ - "BOS", - "ALI", - "CYN" + "BOS":1, + "ALI":2, + "CYN":3 ] static var previews: some View { SettingsView()