From 70a1cc2e63d2c49a135bd89cec3ffb1d427d90ee Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Tue, 30 Jun 2026 16:21:47 +0800
Subject: [PATCH] Freeze prep TagLauncher 8.2.9 Pro status UI
---
src/Apptag/TagEditorView.swift | 97 +++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 95 insertions(+), 2 deletions(-)
diff --git a/src/Apptag/TagEditorView.swift b/src/Apptag/TagEditorView.swift
index 775170a..1d2963b 100644
--- a/src/Apptag/TagEditorView.swift
+++ b/src/Apptag/TagEditorView.swift
@@ -1,3 +1,4 @@
+import AppKit
import SwiftUI
// MARK: - Reusable Tag Editor (overlay edit mode + Preferences)
@@ -6,7 +7,11 @@
/// All changes (rename, delete, setColor) are saved to the local tag database.
struct TagEditorView: View {
@Binding var tagColors: [String: Int]
+ @Binding var tagCustomColors: [String: TagCustomColor]
let excludedTagNames: Set<String>
+ let isCustomColorUnlocked: Bool
+ let onLockedCustomColor: () -> Void
+ var topLeadingAccessory: AnyView? = nil
var onRefresh: (() -> Void)?
@State private var editingTagName: String? = nil
@@ -30,7 +35,13 @@
VStack(spacing: 0) {
// "New Tag" button at top
HStack {
- Spacer()
+ if let topLeadingAccessory {
+ topLeadingAccessory
+ .frame(maxWidth: .infinity, alignment: .leading)
+ } else {
+ Spacer()
+ }
+
Button {
addingNewTag = true
newTagNameText = ""
@@ -85,16 +96,20 @@
private func tagEditRow(_ tagName: String) -> some View {
let colorIndex = tagColors[tagName] ?? 0
+ let hasCustomColor = tagCustomColors[tagName] != nil
return HStack(spacing: 10) {
HStack(spacing: 4) {
ForEach(TagColor.allIndices, id: \.self) { idx in
- ColorSwatch(index: idx, isSelected: idx == colorIndex) {
+ ColorSwatch(index: idx, isSelected: !hasCustomColor && idx == colorIndex) {
TagEditor.setColor(idx, for: tagName)
tagColors[tagName] = idx
+ tagCustomColors.removeValue(forKey: tagName)
onRefresh?()
}
}
}
+
+ customColorControl(tagName: tagName, colorIndex: colorIndex)
if editingTagName == tagName {
MacTextField(
@@ -167,6 +182,8 @@
TagEditor.renameTag(from: oldName, to: newName)
tagColors[newName] = tagColors[oldName]
tagColors.removeValue(forKey: oldName)
+ tagCustomColors[newName] = tagCustomColors[oldName]
+ tagCustomColors.removeValue(forKey: oldName)
editingTagName = nil
onRefresh?()
}
@@ -184,6 +201,82 @@
private func deleteTag(_ name: String) {
TagEditor.deleteTagCompletely(name)
tagColors.removeValue(forKey: name)
+ tagCustomColors.removeValue(forKey: name)
onRefresh?()
}
+
+ @ViewBuilder
+ private func customColorControl(tagName: String, colorIndex: Int) -> some View {
+ let isSelected = tagCustomColors[tagName] != nil
+ if isCustomColorUnlocked {
+ ColorPicker(
+ "",
+ selection: customColorBinding(tagName: tagName, colorIndex: colorIndex),
+ supportsOpacity: false
+ )
+ .labelsHidden()
+ .opacity(0.02)
+ .frame(width: 64, height: 24)
+ .overlay(
+ customColorSwatch(tagName: tagName, colorIndex: colorIndex, isSelected: isSelected)
+ .allowsHitTesting(false)
+ )
+ .frame(width: 72, alignment: .leading)
+ .help(tr("tag.customColor"))
+ } else {
+ Button(action: onLockedCustomColor) {
+ customColorSwatch(tagName: tagName, colorIndex: colorIndex, isSelected: isSelected)
+ }
+ .buttonStyle(.plain)
+ .frame(width: 72, alignment: .leading)
+ .help(tr("pro.prompt.customTagColors"))
+ }
+ }
+
+ private func customColorSwatch(tagName: String, colorIndex: Int, isSelected: Bool) -> some View {
+ let fill = Color(nsColor: TagColor.nsColor(for: colorIndex, customColor: tagCustomColors[tagName]))
+ return ZStack {
+ RoundedRectangle(cornerRadius: 10, style: .continuous)
+ .fill(fill)
+ .frame(width: 58, height: 18)
+ .overlay(
+ RoundedRectangle(cornerRadius: 10, style: .continuous)
+ .stroke(Color.secondary.opacity(0.18), lineWidth: 1)
+ )
+ .padding(3)
+ .overlay(
+ RoundedRectangle(cornerRadius: 13, style: .continuous)
+ .stroke(isSelected ? Color.white : Color.clear, lineWidth: 2)
+ )
+ .shadow(color: .black.opacity(0.15), radius: 2, y: 1)
+
+ Image(systemName: "crown")
+ .font(.system(size: 10, weight: .semibold))
+ .symbolRenderingMode(.monochrome)
+ .foregroundStyle(Color.white)
+ .shadow(color: .black.opacity(0.28), radius: 1, y: 0.5)
+ }
+ }
+
+ private func customColorBinding(tagName: String, colorIndex: Int) -> Binding<Color> {
+ Binding(
+ get: {
+ Color(nsColor: TagColor.nsColor(for: colorIndex, customColor: tagCustomColors[tagName]))
+ },
+ set: { color in
+ guard isCustomColorUnlocked else {
+ onLockedCustomColor()
+ return
+ }
+ let nsColor = NSColor(color)
+ let customColor = TagCustomColor(nsColor: nsColor)
+ guard TagEditor.setCustomColor(customColor, for: tagName) else {
+ onLockedCustomColor()
+ return
+ }
+ tagCustomColors[tagName] = customColor
+ onRefresh?()
+ }
+ )
+ }
}
--
Gitblit v1.9.3