feat(view model): 增加自定义调色板
可以自动保存和加载调色板 Signed-off-by: Ching <loooching@gmail.com>
This commit is contained in:
parent
ac3031dd05
commit
ba56e249a0
@ -17,6 +17,7 @@
|
|||||||
248D14F029A230FE00AE4C0D /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248D14EF29A230FE00AE4C0D /* Constants.swift */; };
|
248D14F029A230FE00AE4C0D /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248D14EF29A230FE00AE4C0D /* Constants.swift */; };
|
||||||
248D14F329A2435000AE4C0D /* UtilityViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248D14F129A2435000AE4C0D /* UtilityViews.swift */; };
|
248D14F329A2435000AE4C0D /* UtilityViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248D14F129A2435000AE4C0D /* UtilityViews.swift */; };
|
||||||
248D14F629A243F200AE4C0D /* UtilityExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248D14F529A243F200AE4C0D /* UtilityExtensions.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 */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
@ -32,6 +33,7 @@
|
|||||||
248D14EF29A230FE00AE4C0D /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
248D14EF29A230FE00AE4C0D /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
||||||
248D14F129A2435000AE4C0D /* UtilityViews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UtilityViews.swift; sourceTree = "<group>"; };
|
248D14F129A2435000AE4C0D /* UtilityViews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UtilityViews.swift; sourceTree = "<group>"; };
|
||||||
248D14F529A243F200AE4C0D /* UtilityExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UtilityExtensions.swift; sourceTree = "<group>"; };
|
248D14F529A243F200AE4C0D /* UtilityExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UtilityExtensions.swift; sourceTree = "<group>"; };
|
||||||
|
24E5FE8829A7AB4000794732 /* PaletteStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaletteStore.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -69,6 +71,7 @@
|
|||||||
24145E7D29A1489700ECB9D1 /* EmojiArtDocumentView.swift */,
|
24145E7D29A1489700ECB9D1 /* EmojiArtDocumentView.swift */,
|
||||||
248D14F129A2435000AE4C0D /* UtilityViews.swift */,
|
248D14F129A2435000AE4C0D /* UtilityViews.swift */,
|
||||||
24145E8A29A1498500ECB9D1 /* EmojiArtModel.swift */,
|
24145E8A29A1498500ECB9D1 /* EmojiArtModel.swift */,
|
||||||
|
24E5FE8829A7AB4000794732 /* PaletteStore.swift */,
|
||||||
248D14F529A243F200AE4C0D /* UtilityExtensions.swift */,
|
248D14F529A243F200AE4C0D /* UtilityExtensions.swift */,
|
||||||
248D14EB29A227C700AE4C0D /* EmojiArtDocument.swift */,
|
248D14EB29A227C700AE4C0D /* EmojiArtDocument.swift */,
|
||||||
24145E8C29A225E900ECB9D1 /* EmojiArtModel.Background.swift */,
|
24145E8C29A225E900ECB9D1 /* EmojiArtModel.Background.swift */,
|
||||||
@ -161,6 +164,7 @@
|
|||||||
24145E7C29A1489700ECB9D1 /* EmojiArtApp.swift in Sources */,
|
24145E7C29A1489700ECB9D1 /* EmojiArtApp.swift in Sources */,
|
||||||
248D14EC29A227C700AE4C0D /* EmojiArtDocument.swift in Sources */,
|
248D14EC29A227C700AE4C0D /* EmojiArtDocument.swift in Sources */,
|
||||||
248D14F029A230FE00AE4C0D /* Constants.swift in Sources */,
|
248D14F029A230FE00AE4C0D /* Constants.swift in Sources */,
|
||||||
|
24E5FE8929A7AB4000794732 /* PaletteStore.swift in Sources */,
|
||||||
24145E8B29A1498500ECB9D1 /* EmojiArtModel.swift in Sources */,
|
24145E8B29A1498500ECB9D1 /* EmojiArtModel.swift in Sources */,
|
||||||
24145E8D29A225E900ECB9D1 /* EmojiArtModel.Background.swift in Sources */,
|
24145E8D29A225E900ECB9D1 /* EmojiArtModel.Background.swift in Sources */,
|
||||||
248D14F629A243F200AE4C0D /* UtilityExtensions.swift in Sources */,
|
248D14F629A243F200AE4C0D /* UtilityExtensions.swift in Sources */,
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import SwiftUI
|
|||||||
@main
|
@main
|
||||||
struct EmojiArtApp: App {
|
struct EmojiArtApp: App {
|
||||||
let document = EmojiArtDocument()
|
let document = EmojiArtDocument()
|
||||||
|
let paletteStore = PaletteStore(named: "Default")
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
EmojiArtDocumentView(document: document)
|
EmojiArtDocumentView(document: document)
|
||||||
|
|||||||
79
EmojiArt/PaletteStore.swift
Normal file
79
EmojiArt/PaletteStore.swift
Normal file
@ -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<Palette>.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)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user