Ariver
2026-05-06 08ff53cae4f4d65d4ed211f9211ac4920e36b626
Apptag/ApptagApp.swift
@@ -1,6 +1,7 @@
import SwiftUI
import AppKit
import Carbon
import ServiceManagement
// MARK: - Application Entry Point
@@ -25,16 +26,46 @@
    func applicationDidFinishLaunching(_ notification: Notification) {
        L10n.setup()
        NSApp.setActivationPolicy(.accessory)
        let showDock = UserDefaults.standard.bool(forKey: "showDockIcon")
        NSApp.setActivationPolicy(showDock ? .regular : .accessory)
        setupMenuBar()
        registerHotkey()
        observeOtherWindows()
        observeEditMode()
        observeDockSetting()
        setupLaunchAtLogin()
    }
    /// Observe Show in Dock changes so it takes effect immediately.
    private func observeDockSetting() {
        NotificationCenter.default.addObserver(
            forName: UserDefaults.didChangeNotification,
            object: nil, queue: .main
        ) { _ in
            let show = UserDefaults.standard.bool(forKey: "showDockIcon")
            NSApp.setActivationPolicy(show ? .regular : .accessory)
        }
    }
    /// Enable launch at login by default; prompt user if disabled.
    private func setupLaunchAtLogin() {
        let key = "launchAtLogin"
        if UserDefaults.standard.object(forKey: key) == nil {
            // First launch: enable by default
            UserDefaults.standard.set(true, forKey: key)
            try? SMAppService.mainApp.register()
        } else if UserDefaults.standard.bool(forKey: key) {
            try? SMAppService.mainApp.register()
        }
    }
    // MARK: - Menu Bar
    private func setupMenuBar() {
        // Remove old status item if re-creating (language switch, etc.)
        if let existing = statusItem {
            NSStatusBar.system.removeStatusItem(existing)
        }
        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
        if let button = statusItem.button {
@@ -80,7 +111,7 @@
        // Language submenu
        let langMenu = NSMenu()
        let currentLang = UserDefaults.standard.string(forKey: "appLanguage") ?? "en"
        let currentLang = L10n.currentCode
        for (code, name) in L10n.supported {
            let item = NSMenuItem(title: name, action: #selector(switchLanguage(_:)), keyEquivalent: "")
            item.representedObject = code
@@ -343,6 +374,8 @@
    @AppStorage("defaultGroupName") private var defaultGroupName = "Other"
    @AppStorage("displayMode") private var displayMode = "flat"
    @AppStorage("hideAppNames") private var hideAppNames = false
    @AppStorage("showDockIcon") private var showDockIcon = false
    @AppStorage("launchAtLogin") private var launchAtLogin = true
    @State private var allApps: [AppInfo] = []
    @State private var tagColors: [String: Int] = [:]
@@ -409,6 +442,21 @@
            // Tab 1: General
            Form {
                Section {
                    HStack(spacing: 20) {
                        Toggle("Launch at login", isOn: $launchAtLogin)
                            .onChange(of: launchAtLogin) { _, enabled in
                                if enabled {
                                    try? SMAppService.mainApp.register()
                                } else {
                                    try? SMAppService.mainApp.unregister()
                                }
                            }
                        Toggle("Show in Dock", isOn: $showDockIcon)
                        Toggle("Hide app names", isOn: $hideAppNames)
                    }
                }
                Section {
                    LabeledContent("App list style:") {
                        Picker("", selection: $displayMode) {
                            Text("Flat").tag("flat")
@@ -466,10 +514,6 @@
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
                Section {
                    Toggle("Hide app names", isOn: $hideAppNames)
                }
            }
            .tabItem { Label("General", systemImage: "gearshape") }
            .padding()
@@ -487,21 +531,6 @@
            // Tab 3: Data
            Form {
                Section {
                    HStack {
                        Button("Re-index Now") {
                            NotificationCenter.default.post(name: .apptagReindex, object: nil)
                        }
                        .buttonStyle(.borderedProminent)
                        Text("Re-scan all app directories and refresh the tag database.")
                            .font(.caption)
                            .foregroundStyle(.secondary)
                    }
                } header: {
                    Text("Index Management")
                }
                Section {
                    HStack(spacing: 12) {
                        Button("Export Tags…") { exportTags() }