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 {
@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())
}
}

View File

@ -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<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,9 +9,32 @@ 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)
}
}
}
}

View File

@ -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)
}

View File

@ -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 = ""
}
}) {

View File

@ -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()