diff --git a/RippleChat.xcodeproj/project.pbxproj b/RippleChat.xcodeproj/project.pbxproj index 2f7982a..5b778a9 100644 --- a/RippleChat.xcodeproj/project.pbxproj +++ b/RippleChat.xcodeproj/project.pbxproj @@ -15,6 +15,10 @@ 96454F362A558EBE0040BEBD /* RippleChatUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96454F352A558EBE0040BEBD /* RippleChatUITests.swift */; }; 96454F382A558EBE0040BEBD /* RippleChatUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96454F372A558EBE0040BEBD /* RippleChatUITestsLaunchTests.swift */; }; 96454F452A5593900040BEBD /* .gitignore in Resources */ = {isa = PBXBuildFile; fileRef = 96454F442A5593900040BEBD /* .gitignore */; }; + F5847B622A599BF4009E28D4 /* Body.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5847B612A599BF4009E28D4 /* Body.swift */; }; + F5847B642A599CC3009E28D4 /* LogEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5847B632A599CC3009E28D4 /* LogEntry.swift */; }; + F5847B662A599EA4009E28D4 /* Feed.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5847B652A599EA4009E28D4 /* Feed.swift */; }; + F5847B6A2A59AB24009E28D4 /* FeedStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5847B692A59AB24009E28D4 /* FeedStore.swift */; }; F58EB2D02A5590E800E22DA6 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = F58EB2CF2A5590E800E22DA6 /* README.md */; }; /* End PBXBuildFile section */ @@ -47,6 +51,10 @@ 96454F352A558EBE0040BEBD /* RippleChatUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RippleChatUITests.swift; sourceTree = ""; }; 96454F372A558EBE0040BEBD /* RippleChatUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RippleChatUITestsLaunchTests.swift; sourceTree = ""; }; 96454F442A5593900040BEBD /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = ""; }; + F5847B612A599BF4009E28D4 /* Body.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Body.swift; sourceTree = ""; }; + F5847B632A599CC3009E28D4 /* LogEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogEntry.swift; sourceTree = ""; }; + F5847B652A599EA4009E28D4 /* Feed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Feed.swift; sourceTree = ""; }; + F5847B692A59AB24009E28D4 /* FeedStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedStore.swift; sourceTree = ""; }; F58EB2CF2A5590E800E22DA6 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; /* End PBXFileReference section */ @@ -104,6 +112,10 @@ 96454F1C2A558EBC0040BEBD /* ContentView.swift */, 96454F1E2A558EBD0040BEBD /* Assets.xcassets */, 96454F202A558EBD0040BEBD /* Preview Content */, + F5847B612A599BF4009E28D4 /* Body.swift */, + F5847B632A599CC3009E28D4 /* LogEntry.swift */, + F5847B652A599EA4009E28D4 /* Feed.swift */, + F5847B692A59AB24009E28D4 /* FeedStore.swift */, ); path = RippleChat; sourceTree = ""; @@ -265,6 +277,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F5847B622A599BF4009E28D4 /* Body.swift in Sources */, + F5847B662A599EA4009E28D4 /* Feed.swift in Sources */, + F5847B642A599CC3009E28D4 /* LogEntry.swift in Sources */, + F5847B6A2A59AB24009E28D4 /* FeedStore.swift in Sources */, 96454F1D2A558EBC0040BEBD /* ContentView.swift in Sources */, 96454F1B2A558EBC0040BEBD /* RippleChatApp.swift in Sources */, ); diff --git a/RippleChat/Body.swift b/RippleChat/Body.swift new file mode 100644 index 0000000..c16836c --- /dev/null +++ b/RippleChat/Body.swift @@ -0,0 +1,19 @@ +// +// Body.swift +// RippleChat +// +// Created by Severin Memmishofer on 08.07.23. +// + +import Foundation + +struct Body: Codable { + + let tag: String + let value: String + + init(tag: String, value: String) { + self.tag = tag + self.value = value + } +} diff --git a/RippleChat/Feed.swift b/RippleChat/Feed.swift new file mode 100644 index 0000000..5813b86 --- /dev/null +++ b/RippleChat/Feed.swift @@ -0,0 +1,25 @@ +// +// Feed.swift +// RippleChat +// +// Created by Severin Memmishofer on 08.07.23. +// + +import Foundation + +struct Feed: Codable { + + let feed: [LogEntry] + +} + +extension Feed { + + static let sampleData: [LogEntry] = + [ + LogEntry(feedid: "BOB", sequenceNumber: 1, body: Body(tag: "nam", value: "Bob")), + LogEntry(feedid: "BOB", sequenceNumber: 2, body: Body(tag: "txt", value: "My first post!")), + LogEntry(feedid: "BOB", sequenceNumber: 3, body: Body(tag: "txt", value: "Welcome Alice")) + ] + +} diff --git a/RippleChat/FeedStore.swift b/RippleChat/FeedStore.swift new file mode 100644 index 0000000..7e86781 --- /dev/null +++ b/RippleChat/FeedStore.swift @@ -0,0 +1,44 @@ +// +// FeedStore.swift +// RippleChat +// +// Created by Severin Memmishofer on 08.07.23. +// + +import SwiftUI + +@MainActor +class FeedStore: ObservableObject { + + @Published var feed: [LogEntry] = [] + + private static func fileURL() throws -> URL { + try FileManager.default.url(for: .documentDirectory, + in: .userDomainMask, + appropriateFor: nil, + create: false) + .appendingPathComponent("feed.data") + } + + func load() async throws { + let task = Task<[LogEntry], Error> { + let fileURL = try Self.fileURL() + guard let data = try? Data(contentsOf: fileURL) else { + return [] + } + let logEntries = try JSONDecoder().decode([LogEntry].self, from: data) + return logEntries + } + let feed = try await task.value + self.feed = feed + } + + func save(feed: [LogEntry]) async throws { + let task = Task { + let data = try JSONEncoder().encode(feed) + let outfile = try Self.fileURL() + try data.write(to: outfile) + } + _ = try await task.value + } +} diff --git a/RippleChat/LogEntry.swift b/RippleChat/LogEntry.swift new file mode 100644 index 0000000..09dae68 --- /dev/null +++ b/RippleChat/LogEntry.swift @@ -0,0 +1,22 @@ +// +// LogEntry.swift +// RippleChat +// +// Created by Severin Memmishofer on 08.07.23. +// + +import Foundation + +struct LogEntry: Codable { + + let feedid: String + let sequenceNumber: Int + let body: Body + + init(feedid: String, sequenceNumber: Int, body: Body) { + self.feedid = feedid + self.sequenceNumber = sequenceNumber + self.body = body + } + +}