From 9c317d89a39d0871f15f8282aec6c7f3dde7768c Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Fri, 26 Jun 2026 22:42:44 +0800
Subject: [PATCH] Polish Pro status UI and app grid layout
---
src/Apptag/ApptagApp.swift | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 56 insertions(+), 0 deletions(-)
diff --git a/src/Apptag/ApptagApp.swift b/src/Apptag/ApptagApp.swift
index c5b38a3..bb6b32b 100644
--- a/src/Apptag/ApptagApp.swift
+++ b/src/Apptag/ApptagApp.swift
@@ -34,6 +34,7 @@
private static let statusItemButtonIdentifier = NSUserInterfaceItemIdentifier("TagLauncherStatusItemButton")
private static let statusItemAccessibilityLabel = AppIdentity.displayName
private static let showAppListMenuItemIdentifier = NSUserInterfaceItemIdentifier("TagLauncherShowAppListMenuItem")
+ private static let proStatusMenuItemIdentifier = NSUserInterfaceItemIdentifier("TagLauncherProStatusMenuItem")
private static let helpMenuItemIdentifier = NSUserInterfaceItemIdentifier("TagLauncherHelpMenu")
private static let downloadHelpMenuItemIdentifier = NSUserInterfaceItemIdentifier("TagLauncherDownloadHelpMenuItem")
private static let externalActivationNotification = Notification.Name("TagLauncherExternalActivationRequested")
@@ -661,6 +662,9 @@
versionItem.isEnabled = false
menu.addItem(versionItem)
+ let proStatusItem = makeProStatusMenuItem()
+ menu.addItem(proStatusItem)
+
menu.addItem(.separator())
let prefsItem = NSMenuItem(
title: tr("menu.preferences"),
@@ -697,6 +701,7 @@
}
func menuWillOpen(_ menu: NSMenu) {
+ configureProStatusMenuItem(in: menu)
statusMenuScreenForNextOverlay = overlayController.screenContainingCurrentPointer()
?? statusItem?.button?.window?.screen
?? NSScreen.main
@@ -766,6 +771,53 @@
image.isTemplate = true
image.accessibilityDescription = "TagLauncher"
+ return image
+ }
+
+ private func makeProStatusMenuItem() -> NSMenuItem {
+ let item = NSMenuItem(
+ title: "",
+ action: #selector(openProStatusFromStatusMenu(_:)),
+ keyEquivalent: ""
+ )
+ item.identifier = Self.proStatusMenuItemIdentifier
+ item.target = self
+ configureProStatusMenuItem(item)
+ return item
+ }
+
+ private func configureProStatusMenuItem(in menu: NSMenu) {
+ guard let item = menu.items.first(where: { $0.identifier == Self.proStatusMenuItemIdentifier }) else {
+ return
+ }
+ configureProStatusMenuItem(item)
+ }
+
+ private func configureProStatusMenuItem(_ item: NSMenuItem) {
+ let isUnlocked = ProEntitlementPolicy.accessState().isUnlocked
+ item.title = tr(isUnlocked ? "menu.proStatus.unlocked" : "menu.proStatus.free")
+ item.action = #selector(openProStatusFromStatusMenu(_:))
+ item.target = self
+ item.isEnabled = true
+ item.image = isUnlocked ? makeProStatusMenuIcon() : nil
+ }
+
+ private func makeProStatusMenuIcon() -> NSImage? {
+ guard let symbol = NSImage(systemSymbolName: "crown.fill", accessibilityDescription: "Pro") else {
+ return nil
+ }
+ let configuration = NSImage.SymbolConfiguration(pointSize: 13, weight: .semibold)
+ let configuredSymbol = symbol.withSymbolConfiguration(configuration) ?? symbol
+ let image = NSImage(size: NSSize(width: 16, height: 16))
+ image.lockFocus()
+ NSColor(red: 0.96, green: 0.63, blue: 0.10, alpha: 1.0).set()
+ let iconRect = NSRect(x: 1.5, y: 1.5, width: 13, height: 13)
+ configuredSymbol.draw(in: iconRect, from: .zero, operation: .sourceOver, fraction: 1.0)
+ NSColor(red: 0.96, green: 0.63, blue: 0.10, alpha: 1.0).set()
+ iconRect.fill(using: .sourceAtop)
+ image.unlockFocus()
+ image.isTemplate = false
+ image.accessibilityDescription = "Pro"
return image
}
@@ -1700,6 +1752,10 @@
openPreferences(targetTab: nil)
}
+ @objc private func openProStatusFromStatusMenu(_ sender: NSMenuItem) {
+ openPreferences(targetTab: SettingsTabTarget.about)
+ }
+
private func openPreferences(targetTab: String?) {
dismissQuickSearchIfNeeded()
TagDatabase.flushPendingCategorySchemeBackupBatch()
--
Gitblit v1.9.3