feat(view, model): 增加自动保存功能

增加自动保存功能

Signed-off-by: Ching <loooching@gmail.com>
This commit is contained in:
Ching 2023-02-23 21:59:16 +08:00
parent 89d38faea4
commit ac3031dd05
4 changed files with 87 additions and 9 deletions

View File

@ -11,4 +11,5 @@ import SwiftUI
struct const { struct const {
static let defaultEmojiFontSize: CGFloat = 40 static let defaultEmojiFontSize: CGFloat = 40
static let coalescingInterval = 5.0
} }

View File

@ -10,15 +10,56 @@ import SwiftUI
class EmojiArtDocument: ObservableObject { class EmojiArtDocument: ObservableObject {
@Published private(set) var emojiArt: EmojiArtModel { @Published private(set) var emojiArt: EmojiArtModel {
didSet { didSet {
scheduleAutosave()
if emojiArt.background != oldValue.background { if emojiArt.background != oldValue.background {
fetchBackgoundImageDataIfNecessary() fetchBackgoundImageDataIfNecessary()
} }
} }
} }
private var autosaveTimer: Timer?
private func scheduleAutosave() {
autosaveTimer?.invalidate()
autosaveTimer = Timer.scheduledTimer(withTimeInterval: const.coalescingInterval, repeats: false) { _ in
self.autoSave()
}
}
private enum Autosave {
static let filename = "Autosaved.emojiart"
static var url: URL? {
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
return documentDirectory?.appendingPathComponent(filename)
}
}
private func autoSave() {
if let url = Autosave.url {
save(to: url)
}
}
private func save(to url: URL) {
let thisFunction = "\(String(describing: self)).\(#function)"
do {
let data: Data = try emojiArt.json()
print("\(thisFunction) json = \(String(data: data, encoding: .utf8) ?? "nil")")
try data.write(to: url)
print("\(thisFunction) success")
} catch {
print("\(thisFunction) error = \(error)")
}
}
init() { init() {
if let url = Autosave.url, let autosavedEmojiArt = try? EmojiArtModel(url: url) {
emojiArt = autosavedEmojiArt
fetchBackgoundImageDataIfNecessary()
} else {
emojiArt = EmojiArtModel() emojiArt = EmojiArtModel()
} }
}
var emojis: [EmojiArtModel.Emoji] { emojiArt.emojis } var emojis: [EmojiArtModel.Emoji] { emojiArt.emojis }
var background: EmojiArtModel.Background { emojiArt.background } var background: EmojiArtModel.Background { emojiArt.background }

View File

@ -8,11 +8,36 @@
import Foundation import Foundation
extension EmojiArtModel { extension EmojiArtModel {
enum Background: Equatable { enum Background: Equatable, Codable {
case blank case blank
case url(URL) case url(URL)
case imageData(Data) case imageData(Data)
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let url = try? container.decode(URL.self, forKey: .url) {
self = .url(url)
} else if let imageData = try? container.decode(Data.self, forKey: .imageData) {
self = .imageData(imageData)
} else {
self = .blank
}
}
enum CodingKeys: String, CodingKey {
case url = "theURL"
case imageData
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .url(let url): try container.encode(url, forKey: .url)
case .imageData(let data): try container.encode(data, forKey: .imageData)
case .blank: break
}
}
var url: URL? { var url: URL? {
switch self { switch self {
case .url(let url): return url case .url(let url): return url

View File

@ -7,11 +7,11 @@
import Foundation import Foundation
struct EmojiArtModel { struct EmojiArtModel: Codable {
var background: Background = EmojiArtModel.Background.blank var background: Background = EmojiArtModel.Background.blank
var emojis = [Emoji]() var emojis = [Emoji]()
struct Emoji: Identifiable { struct Emoji: Identifiable, Hashable, Codable {
let text: String let text: String
var x: Int var x: Int
var y: Int var y: Int
@ -27,14 +27,25 @@ struct EmojiArtModel {
} }
} }
init() { func json() throws -> Data {
return try JSONEncoder().encode(self)
} }
init(json: Data) throws {
self = try JSONDecoder().decode(EmojiArtModel.self, from: json)
}
init(url: URL) throws {
let data = try Data(contentsOf: url)
self = try EmojiArtModel.init(json: data)
}
init() {}
private var uniqueEmojiId = 0 private var uniqueEmojiId = 0
mutating func addEmoji(_ text: String, at location: (x: Int, y: Int), size: Int) { mutating func addEmoji(_ text: String, at location: (x: Int, y: Int), size: Int) {
uniqueEmojiId += 1 uniqueEmojiId += 1
emojis.append(Emoji(text: text, x: location.x, y: location.y, size: size, id: uniqueEmojiId)) emojis.append(Emoji(text: text, x: location.x, y: location.y, size: size, id: uniqueEmojiId))
} }
} }