Add persistent storage

This commit is contained in:
Sebastian Lenzlinger 2023-07-12 14:55:45 +02:00
parent 232d007686
commit d218e9b600
6 changed files with 135 additions and 23 deletions

View File

@ -10,7 +10,9 @@ import CoreBluetooth
struct ContentView: View { struct ContentView: View {
@State var currentView = 0 @State var currentView = 0
@StateObject var dataStore = DataStore() @EnvironmentObject var dataStore: DataStore
@Environment(\.scenePhase) private var scenePhase
let saveAction: ()->Void
var body: some View { var body: some View {
VStack { VStack {
@ -61,14 +63,16 @@ struct ContentView: View {
} }
.frame(height: UIScreen.main.bounds.height * 0.05) .frame(height: UIScreen.main.bounds.height * 0.05)
} }
.onChange(of: scenePhase) { phase in
if phase == .inactive { saveAction() }
}
} }
} }
struct ContentView_Previews: PreviewProvider { struct ContentView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
ContentView() ContentView(saveAction: {})
.environmentObject(DataStore()) .environmentObject(DataStore())
} }
} }

View File

@ -8,16 +8,93 @@
import SwiftUI import SwiftUI
import Foundation import Foundation
@MainActor
class DataStore: ObservableObject { class DataStore: ObservableObject {
@Published var personalID: String @Published var personalID: String
@Published var friends: [String] @Published var friends: [String:Int]
@Published var feeds: [Feed] @Published var feedStores: [FeedStore]
init(personalID: String = "", friends: [String] = [], feeds: [Feed] = []) { init(personalID: String = "", friends: [String:Int] = [:], feedStores: [FeedStore] = []) {
self.personalID = personalID self.personalID = personalID
self.friends = friends 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<String, Error> {
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)])
} }

View File

@ -9,10 +9,33 @@ import SwiftUI
@main @main
struct RippleChatApp: App { struct RippleChatApp: App {
@StateObject private var dataStore = DataStore()
var body: some Scene { var body: some Scene {
WindowGroup { 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)
}
}
} }
} }
} }

View File

@ -22,9 +22,9 @@ struct FeedListView: View {
Button("Save Feed") { Button("Save Feed") {
Task { Task {
do { do {
for feed in feedStores { try await DataStore.sampleDataStore.saveFriends()
try await feed.save(feed: feed.feed) try await DataStore.sampleDataStore.savePersonalID()
} try await DataStore.sampleDataStore.saveFeedStores()
} catch { } catch {
fatalError(error.localizedDescription) fatalError(error.localizedDescription)
} }

View File

@ -20,18 +20,24 @@ struct SettingsEditView: View {
} }
} }
Section(header: Text("Friends")) { Section(header: Text("Friends")) {
ForEach(dataStore.friends) { friend in ForEach(dataStore.friends.keys.sorted(), id: \.self) { friend in
Label(friend, systemImage: "person") 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 { HStack {
TextField("New Feed", text: $newFeedID) TextField("New Feed", text: $newFeedID)
Button(action: { Button(action: {
withAnimation { withAnimation {
let feedid = newFeedID dataStore.friends[newFeedID] = 0
dataStore.friends.append(feedid)
newFeedID = "" newFeedID = ""
} }
}) { }) {

View File

@ -22,8 +22,10 @@ struct SettingsView: View {
Label(dataStore.personalID, systemImage: "person.crop.circle") Label(dataStore.personalID, systemImage: "person.crop.circle")
} }
Section(header: Text("Friends")) { Section(header: Text("Friends")) {
ForEach(dataStore.friends) { friend in ForEach(dataStore.friends.keys.sorted(), id: \.self) { friend in
Label(friend, systemImage: "person") if let seq = dataStore.friends[friend] {
Label("\(friend) - SEQ: \(seq)", systemImage: "person")
}
} }
} }
} }
@ -62,9 +64,9 @@ struct SettingsView: View {
struct SettingsView_Previews: PreviewProvider { struct SettingsView_Previews: PreviewProvider {
static var friends = [ static var friends = [
"BOS", "BOS":1,
"ALI", "ALI":2,
"CYN" "CYN":3
] ]
static var previews: some View { static var previews: some View {
SettingsView() SettingsView()