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