From 4c6f31c43a03ecb5a85ffb6a3ea3905a661af0f4 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Tue, 30 Jun 2026 18:24:23 +0800
Subject: [PATCH] Remove non-source materials from source worktree
---
src/Apptag/DataLayer.swift | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 103 insertions(+), 7 deletions(-)
diff --git a/src/Apptag/DataLayer.swift b/src/Apptag/DataLayer.swift
index d05beda..2a23bbd 100644
--- a/src/Apptag/DataLayer.swift
+++ b/src/Apptag/DataLayer.swift
@@ -237,6 +237,52 @@
// MARK: - Tag Color Mapping
+struct TagCustomColor: Codable, Equatable {
+ var red: Double
+ var green: Double
+ var blue: Double
+ var alpha: Double
+
+ init(red: Double, green: Double, blue: Double, alpha: Double = 1.0) {
+ self.red = Self.clamp(red)
+ self.green = Self.clamp(green)
+ self.blue = Self.clamp(blue)
+ self.alpha = Self.clamp(alpha)
+ }
+
+ init(nsColor: NSColor) {
+ let rgbColor = nsColor.usingColorSpace(.sRGB) ?? nsColor
+ self.init(
+ red: Double(rgbColor.redComponent),
+ green: Double(rgbColor.greenComponent),
+ blue: Double(rgbColor.blueComponent),
+ alpha: Double(rgbColor.alphaComponent)
+ )
+ }
+
+ var nsColor: NSColor {
+ NSColor(
+ srgbRed: CGFloat(red),
+ green: CGFloat(green),
+ blue: CGFloat(blue),
+ alpha: CGFloat(alpha)
+ )
+ }
+
+ var signature: String {
+ [
+ String(format: "%.4f", red),
+ String(format: "%.4f", green),
+ String(format: "%.4f", blue),
+ String(format: "%.4f", alpha)
+ ].joined(separator: ":")
+ }
+
+ private static func clamp(_ value: Double) -> Double {
+ min(1.0, max(0.0, value))
+ }
+}
+
enum TagColor {
static func nsColor(for index: Int) -> NSColor {
switch index {
@@ -251,6 +297,20 @@
default: return NSColor.systemGray
}
}
+
+ static func nsColor(for index: Int, customColor: TagCustomColor?) -> NSColor {
+ customColor?.nsColor ?? nsColor(for: index)
+ }
+
+ static func prefersDarkText(for color: NSColor) -> Bool {
+ let rgbColor = color.usingColorSpace(.sRGB) ?? color
+ let red = Double(rgbColor.redComponent)
+ let green = Double(rgbColor.greenComponent)
+ let blue = Double(rgbColor.blueComponent)
+ let luminance = (0.299 * red) + (0.587 * green) + (0.114 * blue)
+ return luminance > 0.62
+ }
+
static let allIndices: [Int] = [1, 2, 3, 4, 5, 6, 7]
}
@@ -963,6 +1023,7 @@
struct TagDef: Codable, Equatable {
var color: Int
var systemCategoryID: SmartCategoryID? = nil
+ var customColor: TagCustomColor? = nil
}
struct Store: Codable {
@@ -1551,12 +1612,14 @@
// MARK: Export / Import
static func exportTo(_ url: URL) throws {
+ try ProEntitlementPolicy.requireUnlocked(.layoutExport)
let store = loadWithEnsuredCategoryScheme()
let data = try JSONEncoder().encode(store)
try data.write(to: url, options: .atomic)
}
static func importFrom(_ url: URL) throws -> Store {
+ try ProEntitlementPolicy.requireUnlocked(.layoutImport)
let previousStore = loadWithEnsuredCategoryScheme()
let data = try Data(contentsOf: url)
var store = try JSONDecoder().decode(Store.self, from: data)
@@ -1753,12 +1816,11 @@
guard !FileManager.default.fileExists(atPath: storeURL.path) else { return }
let starterCategoryIDs: [SmartCategoryID] = [
- .uiPrototyping,
- .ide,
- .writing,
- .game,
+ .design,
+ .development,
+ .office,
.entertainment,
- .system,
+ .systemEnhancement,
.gtd
]
@@ -1808,6 +1870,8 @@
/// Persist the visible app order for one stable container.
static func reorderApps(inContainer containerID: String, orderedPaths: [String]) {
+ guard ProEntitlementPolicy.isUnlocked(.persistentAppSorting) else { return }
+
var store = TagDatabase.load()
_ = TagDatabase.normalizeContainerAppOrder(in: &store)
let previousStore = store
@@ -2137,11 +2201,22 @@
TagDatabase.save(store)
}
- static func setAppNote(_ note: String, for path: String) {
+ @discardableResult
+ static func setAppNote(_ note: String, for path: String) -> ProNoteSaveDecision {
var store = TagDatabase.load()
- let previousStore = store
let trimmed = note.trimmingCharacters(in: .whitespacesAndNewlines)
let limited = String(trimmed.prefix(TagDatabase.maxAppNoteLength))
+ let decision = ProEntitlementPolicy.noteSaveDecision(
+ note: limited,
+ for: path,
+ in: store
+ )
+
+ guard case .allow = decision else {
+ return decision
+ }
+
+ let previousStore = store
if limited.isEmpty {
store.appNotes.removeValue(forKey: path)
store.appNoteMetadata[path] = TagDatabase.AppNoteMetadata(
@@ -2167,6 +2242,7 @@
previous: previousStore,
reason: "edit-app-note"
)
+ return decision
}
static func moveApp(path: String, from sourceTag: String, to targetTag: String, color: Int, copy: Bool) {
@@ -2272,6 +2348,7 @@
let previousStore = store
var tagDef = store.tags[tag] ?? TagDatabase.TagDef(color: color, systemCategoryID: nil)
tagDef.color = color
+ tagDef.customColor = nil
store.tags[tag] = tagDef
TagDatabase.saveUserCategorySchemeMutation(
store,
@@ -2279,4 +2356,23 @@
reason: "set-tag-color"
)
}
+
+ /// Set a Pro custom color for a tag without changing its fallback base color.
+ @discardableResult
+ static func setCustomColor(_ customColor: TagCustomColor, for tag: String) -> Bool {
+ guard ProEntitlementPolicy.isUnlocked(.customTagColors) else {
+ return false
+ }
+ var store = TagDatabase.load()
+ let previousStore = store
+ var tagDef = store.tags[tag] ?? TagDatabase.TagDef(color: 0, systemCategoryID: nil)
+ tagDef.customColor = customColor
+ store.tags[tag] = tagDef
+ TagDatabase.saveUserCategorySchemeMutation(
+ store,
+ previous: previousStore,
+ reason: "set-tag-custom-color"
+ )
+ return true
+ }
}
--
Gitblit v1.9.3