| | |
| | | static let theme = "theme" |
| | | static let tags = "tags" |
| | | static let data = "data" |
| | | static let pro = "pro" |
| | | static let about = "about" |
| | | } |
| | | |
| | |
| | | struct TagPill: View { |
| | | let name: String |
| | | let colorIndex: Int |
| | | var customColor: TagCustomColor? = nil |
| | | var dragModeActive: Bool = false |
| | | var isDragging: Bool = false |
| | | let action: () -> Void |
| | | |
| | | private var resolvedNSColor: NSColor { |
| | | TagColor.nsColor(for: colorIndex, customColor: customColor) |
| | | } |
| | | |
| | | private var bgColor: Color { |
| | | Color(nsColor: TagColor.nsColor(for: colorIndex)) |
| | | Color(nsColor: resolvedNSColor) |
| | | } |
| | | |
| | | private var textColor: Color { |
| | | if colorIndex == 0 || colorIndex == 5 { |
| | | return .primary |
| | | } |
| | | return .white |
| | | TagColor.prefersDarkText(for: resolvedNSColor) ? .primary : .white |
| | | } |
| | | |
| | | var body: some View { |
| | |
| | | struct SideTagPill: View { |
| | | let name: String |
| | | let colorIndex: Int |
| | | var customColor: TagCustomColor? = nil |
| | | var dragModeActive: Bool = false |
| | | var isDragging: Bool = false |
| | | let action: () -> Void |
| | | |
| | | private var bgColor: Color { |
| | | Color(nsColor: TagColor.nsColor(for: colorIndex)) |
| | | private var resolvedNSColor: NSColor { |
| | | TagColor.nsColor(for: colorIndex, customColor: customColor) |
| | | } |
| | | |
| | | private var bgColor: Color { |
| | | Color(nsColor: resolvedNSColor) |
| | | } |
| | | |
| | | private var textColor: Color { |
| | | colorIndex == 0 || colorIndex == 5 ? .primary : .white |
| | | TagColor.prefersDarkText(for: resolvedNSColor) ? .primary : .white |
| | | } |
| | | |
| | | var body: some View { |
| | |
| | | @State private var allApps: [AppInfo] = [] |
| | | @State private var displayGroups: [TagGroup] = [] |
| | | @State private var tagColors: [String: Int] = [:] |
| | | @State private var tagCustomColors: [String: TagCustomColor] = [:] |
| | | @State private var tagDefinitions: [String: TagDatabase.TagDef] = [:] |
| | | @State private var containerAppOrder: [String: [String]] = [:] |
| | | @State private var groupLayoutVersion = 0 |
| | |
| | | ) |
| | | } |
| | | |
| | | private var renderedDisplayMode: String { |
| | | ProEntitlementPolicy.effectiveDisplayMode(for: displayMode) |
| | | } |
| | | |
| | | private func storedThemeTuning(for theme: AppGridTheme) -> Double? { |
| | | switch theme { |
| | | case .deepBlue: |
| | |
| | | } |
| | | |
| | | private var isColorlessContainerMode: Bool { |
| | | displayMode == "container" || displayMode == "gridContainer" |
| | | renderedDisplayMode == "container" || renderedDisplayMode == "gridContainer" |
| | | } |
| | | |
| | | private var shouldShowUsageTips: Bool { |
| | |
| | | // Always sync tag list from database when entering edit mode |
| | | let store = TagDatabase.load() |
| | | tagColors = store.tags.mapValues { $0.color } |
| | | tagCustomColors = store.tags.compactMapValues { $0.customColor } |
| | | tagDefinitions = store.tags |
| | | draggedTagNames = TagEditor.orderedTagNames() |
| | | } |
| | | editPhase = phase |
| | |
| | | HStack(spacing: 8) { |
| | | ForEach(tagLabels) { tag in |
| | | TagPill(name: tag.name, colorIndex: tag.colorIndex, |
| | | customColor: tag.customColor, |
| | | dragModeActive: tagNavDragModeActive && canReorderTag(tag.name), |
| | | isDragging: tagNavDragItem == tag.name, |
| | | action: { |
| | |
| | | VStack(spacing: 6) { |
| | | ForEach(tagLabels) { tag in |
| | | SideTagPill(name: tag.name, colorIndex: tag.colorIndex, |
| | | customColor: tag.customColor, |
| | | dragModeActive: tagNavDragModeActive && canReorderTag(tag.name), |
| | | isDragging: tagNavDragItem == tag.name, |
| | | action: { |
| | |
| | | AppGridCollectionView( |
| | | groups: displayGroups, |
| | | tagColors: tagColors, |
| | | displayMode: displayMode, |
| | | tagCustomColors: tagCustomColors, |
| | | displayMode: renderedDisplayMode, |
| | | iconSize: iconSize, |
| | | showNames: !hideAppNames, |
| | | appGridTheme: renderedAppGridTheme, |
| | |
| | | |
| | | TagEditorView( |
| | | tagColors: $tagColors, |
| | | tagCustomColors: $tagCustomColors, |
| | | excludedTagNames: ["Mac自带", defaultGroupName], |
| | | isCustomColorUnlocked: proEntitlement.isUnlocked, |
| | | onLockedCustomColor: { presentProPrompt(for: .customTagColors) }, |
| | | onRefresh: { refreshApps() } |
| | | ) |
| | | } |
| | |
| | | } |
| | | |
| | | private var tagLabels: [TagNavigationItem] { |
| | | displayGroups.map { TagNavigationItem(name: $0.name, colorIndex: tagColors[$0.name] ?? 0) } |
| | | displayGroups.map { |
| | | TagNavigationItem( |
| | | name: $0.name, |
| | | colorIndex: tagColors[$0.name] ?? 0, |
| | | customColor: tagCustomColors[$0.name] |
| | | ) |
| | | } |
| | | } |
| | | |
| | | private var editGroups: [TagGroup] { |
| | |
| | | if let preview = proEntitlement.themePreviewState { |
| | | appGridThemeID = preview.theme.rawValue |
| | | proEntitlement.stopThemePreview() |
| | | } |
| | | if let preview = proEntitlement.displayModePreviewState { |
| | | displayMode = preview.displayMode |
| | | proEntitlement.stopDisplayModePreview() |
| | | } |
| | | |
| | | let hadPrompt = appGridInteraction.proPrompt != nil |
| | |
| | | quickSearchDocuments = snapshot.quickSearchDocuments |
| | | tagColors = snapshot.tagColors |
| | | tagDefinitions = snapshot.tagDefinitions |
| | | tagCustomColors = snapshot.tagDefinitions.compactMapValues { $0.customColor } |
| | | containerAppOrder = snapshot.containerAppOrder |
| | | draggedTagNames = snapshot.tagOrder |
| | | rebuildDisplayGroups(apps: snapshot.apps, tagOrder: snapshot.tagOrder) |