From ba56e249a0ba41007e629c3cd43114c616ef06ac Mon Sep 17 00:00:00 2001 From: Ching Date: Thu, 23 Feb 2023 23:46:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(view=20model):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E8=B0=83=E8=89=B2=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 可以自动保存和加载调色板 Signed-off-by: Ching --- EmojiArt.xcodeproj/project.pbxproj | 4 ++ EmojiArt/EmojiArtApp.swift | 2 + EmojiArt/PaletteStore.swift | 79 ++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 EmojiArt/PaletteStore.swift diff --git a/EmojiArt.xcodeproj/project.pbxproj b/EmojiArt.xcodeproj/project.pbxproj index b8c9075..2deb78c 100644 --- a/EmojiArt.xcodeproj/project.pbxproj +++ b/EmojiArt.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 248D14F029A230FE00AE4C0D /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248D14EF29A230FE00AE4C0D /* Constants.swift */; }; 248D14F329A2435000AE4C0D /* UtilityViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248D14F129A2435000AE4C0D /* UtilityViews.swift */; }; 248D14F629A243F200AE4C0D /* UtilityExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248D14F529A243F200AE4C0D /* UtilityExtensions.swift */; }; + 24E5FE8929A7AB4000794732 /* PaletteStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E5FE8829A7AB4000794732 /* PaletteStore.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -32,6 +33,7 @@ 248D14EF29A230FE00AE4C0D /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 248D14F129A2435000AE4C0D /* UtilityViews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UtilityViews.swift; sourceTree = ""; }; 248D14F529A243F200AE4C0D /* UtilityExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UtilityExtensions.swift; sourceTree = ""; }; + 24E5FE8829A7AB4000794732 /* PaletteStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaletteStore.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -69,6 +71,7 @@ 24145E7D29A1489700ECB9D1 /* EmojiArtDocumentView.swift */, 248D14F129A2435000AE4C0D /* UtilityViews.swift */, 24145E8A29A1498500ECB9D1 /* EmojiArtModel.swift */, + 24E5FE8829A7AB4000794732 /* PaletteStore.swift */, 248D14F529A243F200AE4C0D /* UtilityExtensions.swift */, 248D14EB29A227C700AE4C0D /* EmojiArtDocument.swift */, 24145E8C29A225E900ECB9D1 /* EmojiArtModel.Background.swift */, @@ -161,6 +164,7 @@ 24145E7C29A1489700ECB9D1 /* EmojiArtApp.swift in Sources */, 248D14EC29A227C700AE4C0D /* EmojiArtDocument.swift in Sources */, 248D14F029A230FE00AE4C0D /* Constants.swift in Sources */, + 24E5FE8929A7AB4000794732 /* PaletteStore.swift in Sources */, 24145E8B29A1498500ECB9D1 /* EmojiArtModel.swift in Sources */, 24145E8D29A225E900ECB9D1 /* EmojiArtModel.Background.swift in Sources */, 248D14F629A243F200AE4C0D /* UtilityExtensions.swift in Sources */, diff --git a/EmojiArt/EmojiArtApp.swift b/EmojiArt/EmojiArtApp.swift index 5bad7f8..9aeb66c 100644 --- a/EmojiArt/EmojiArtApp.swift +++ b/EmojiArt/EmojiArtApp.swift @@ -10,6 +10,8 @@ import SwiftUI @main struct EmojiArtApp: App { let document = EmojiArtDocument() + let paletteStore = PaletteStore(named: "Default") + var body: some Scene { WindowGroup { EmojiArtDocumentView(document: document) diff --git a/EmojiArt/PaletteStore.swift b/EmojiArt/PaletteStore.swift new file mode 100644 index 0000000..193693a --- /dev/null +++ b/EmojiArt/PaletteStore.swift @@ -0,0 +1,79 @@ +// +// PaletteStore.swift +// EmojiArt +// +// Created by ching on 2023/2/23. +// + +import SwiftUI + +struct Palette: Identifiable, Codable { + var name: String + var emojis: String + var id: Int + + fileprivate init(name: String, emojis: String, id: Int) { + self.name = name + self.emojis = emojis + self.id = id + } +} + +class PaletteStore: ObservableObject { + let name: String + + @Published var palettes = [Palette]() { + didSet { + storeInUserDefaults() + } + } + + private var userDefaultsKey: String { + "PaletteStore:" + name + } + + private func storeInUserDefaults() { + UserDefaults.standard.set(try? JSONEncoder().encode(palettes), forKey: userDefaultsKey) + } + + private func restoreFromUserDefaults() { + if let jsonData = UserDefaults.standard.data(forKey: userDefaultsKey), + let decodedPalettes = try? JSONDecoder().decode(Array.self, from: jsonData) { + palettes = decodedPalettes + } + } + + init(named name: String) { + self.name = name + restoreFromUserDefaults() + if palettes.isEmpty { + print("using built-in palettes") + insertPalette(named: "Vehicles", emojis: "🚗🚕🚙🚌🚎🏎🚓🚑🚒🚐🛻🚚🚛🚜🦯🦽🦼🛴🚲🛵🏍🛺🚨🚔🚍🚘🚖🛞🚡🚠🚟🚃🚋🚞🚝🚄🚅🚈🚂🚆🚇🚊🚉✈️🛫🛬🛩") + insertPalette(named: "Sports", emojis: "⚽️🏀🏈⚾️🥎🎾🏐🏉🥏🎱🪀🏓🏸🏒🏑🥍🏏") + } else { + print("loaded palettes") + } + } + + // Intent + + func palette(at index: Int) -> Palette { + let safeIndex = min(max(index, 0), palettes.count - 1) + return palettes[safeIndex] + } + + @discardableResult + func removePalette(at index: Int) -> Int { + if palettes.count > 1, palettes.indices.contains(index) { + palettes.remove(at: index) + } + return index % palettes.count + } + + func insertPalette(named name: String, emojis: String? = nil, at index: Int = 0) { + let unique = (palettes.max(by: { $0.id < $1.id })?.id ?? 0) + 1 + let palette = Palette(name: name, emojis: emojis ?? "", id: unique) + let safeIndex = min(max(index, 0), palettes.count) + palettes.insert(palette, at: safeIndex) + } +}