Add automatic language mode and localized help menu
| | |
| | | private static let statusItemButtonIdentifier = NSUserInterfaceItemIdentifier("TagLauncherStatusItemButton") |
| | | private static let statusItemAccessibilityLabel = AppIdentity.displayName |
| | | private static let showAppListMenuItemIdentifier = NSUserInterfaceItemIdentifier("TagLauncherShowAppListMenuItem") |
| | | private static let helpMenuItemIdentifier = NSUserInterfaceItemIdentifier("TagLauncherHelpMenu") |
| | | private static let downloadHelpMenuItemIdentifier = NSUserInterfaceItemIdentifier("TagLauncherDownloadHelpMenuItem") |
| | | private static let externalActivationNotification = Notification.Name("TagLauncherExternalActivationRequested") |
| | | private static let externalActivationObject = AppIdentity.bundleIdentifier |
| | | private static let launcherOverlayLevel = NSWindow.Level(rawValue: NSWindow.Level.mainMenu.rawValue - 1) |
| | |
| | | } |
| | | |
| | | self.configureApplicationMenu() |
| | | self.removeHelpMenu() |
| | | self.configureHelpMenu() |
| | | if retries > 0 && self.applicationMenuNeedsCleanup() { |
| | | self.configureApplicationMenuWhenAvailable(retries: retries - 1) |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | private func removeHelpMenu() { |
| | | private func configureHelpMenu() { |
| | | guard let mainMenu = NSApp.mainMenu else { return } |
| | | NSApp.helpMenu = nil |
| | | |
| | | for item in mainMenu.items.reversed() { |
| | | let isHelpMenu = item.submenu === NSApp.helpMenu |
| | | let isHelpMenu = item.identifier == Self.helpMenuItemIdentifier |
| | | || item.title.localizedCaseInsensitiveContains("help") |
| | | || item.title == tr("menu.help") |
| | | || item.submenu?.title.localizedCaseInsensitiveContains("help") == true |
| | |
| | | mainMenu.removeItem(item) |
| | | } |
| | | } |
| | | |
| | | let menuItem = NSMenuItem(title: tr("menu.help"), action: nil, keyEquivalent: "") |
| | | let helpMenu = NSMenu(title: tr("menu.help")) |
| | | menuItem.identifier = Self.helpMenuItemIdentifier |
| | | menuItem.submenu = helpMenu |
| | | |
| | | let downloadItem = NSMenuItem() |
| | | downloadItem.identifier = Self.downloadHelpMenuItemIdentifier |
| | | downloadItem.title = tr("help.downloadPDF") |
| | | downloadItem.action = #selector(openLocalizedHelp(_:)) |
| | | downloadItem.target = self |
| | | downloadItem.keyEquivalent = "" |
| | | downloadItem.keyEquivalentModifierMask = [] |
| | | downloadItem.isEnabled = true |
| | | helpMenu.addItem(downloadItem) |
| | | mainMenu.addItem(menuItem) |
| | | } |
| | | |
| | | @objc private func openLocalizedHelp(_ sender: Any? = nil) { |
| | | NSWorkspace.shared.open(HelpDocument.currentURL) |
| | | } |
| | | |
| | | private func removeMenuBarItem() { |
| | |
| | | return |
| | | } |
| | | |
| | | if self.isMenuTrackingWindow(keyWindow) { |
| | | return |
| | | } |
| | | |
| | | if self.isAppOwnedDocumentWindow(keyWindow) { |
| | | self.prepareSettingsWindow(keyWindow) |
| | | return |
| | | } |
| | | |
| | | if NSApp.windows.contains(keyWindow) { |
| | | return |
| | | } |
| | | |
| | |
| | | && window != overlayWindow |
| | | && window.isVisible |
| | | && !(window is NSPanel) |
| | | && !isMenuTrackingWindow(window) |
| | | && window.styleMask.contains(.titled) |
| | | } |
| | | |
| | | private func isMenuTrackingWindow(_ window: NSWindow) -> Bool { |
| | | let className = NSStringFromClass(type(of: window)) |
| | | return className.localizedCaseInsensitiveContains("Menu") |
| | | || className.localizedCaseInsensitiveContains("Popup") |
| | | } |
| | | |
| | | private func settingsWindowTitleCandidates() -> Set<String> { |
| | |
| | | } |
| | | |
| | | enum L10n { |
| | | static let automaticCode = "auto" |
| | | static var current: [String: String] = [:] |
| | | private(set) static var currentCode = "en" |
| | | |
| | |
| | | ("sv", "Svenska"), |
| | | ] |
| | | |
| | | static var selectedLanguageCode: String { |
| | | UserDefaults.standard.string(forKey: "appLanguage") ?? automaticCode |
| | | } |
| | | |
| | | static var isAutomatic: Bool { |
| | | UserDefaults.standard.string(forKey: "appLanguage") == nil |
| | | } |
| | | |
| | | static func switchSelection(to code: String) { |
| | | if code == automaticCode { |
| | | switchToAutomatic() |
| | | } else { |
| | | switchTo(code) |
| | | } |
| | | } |
| | | |
| | | static func switchToAutomatic() { |
| | | let code = fallbackCode() |
| | | let previousCode = currentCode |
| | | load(code) |
| | | UserDefaults.standard.removeObject(forKey: "appLanguage") |
| | | let relocalizedTags = previousCode != currentCode |
| | | ? TagDatabase.relocalizeSystemTagsForCurrentLanguage() |
| | | : false |
| | | NotificationCenter.default.post( |
| | | name: .appLanguageDidChange, |
| | | object: nil, |
| | | userInfo: ["code": automaticCode, "effectiveCode": currentCode] |
| | | ) |
| | | if relocalizedTags { |
| | | NotificationCenter.default.post(name: .tagLauncherDataDidChange, object: nil) |
| | | } |
| | | } |
| | | |
| | | static func switchTo(_ code: String) { |
| | | guard supported.contains(where: { $0.code == code }) else { return } |
| | | guard code != currentCode else { return } |
| | | let previousSelection = selectedLanguageCode |
| | | guard code != currentCode || previousSelection == automaticCode else { return } |
| | | load(code) |
| | | let relocalizedTags = TagDatabase.relocalizeSystemTagsForCurrentLanguage() |
| | | UserDefaults.standard.set(code, forKey: "appLanguage") |
| | | NotificationCenter.default.post(name: .appLanguageDidChange, object: nil, userInfo: ["code": currentCode]) |
| | | NotificationCenter.default.post( |
| | | name: .appLanguageDidChange, |
| | | object: nil, |
| | | userInfo: ["code": currentCode, "effectiveCode": currentCode] |
| | | ) |
| | | if relocalizedTags { |
| | | NotificationCenter.default.post(name: .tagLauncherDataDidChange, object: nil) |
| | | } |
| | |
| | | currentCode = code |
| | | } |
| | | |
| | | private static func fallbackCode() -> String { |
| | | static func fallbackCode() -> String { |
| | | let lang = Locale.preferredLanguages.first ?? "en" |
| | | if lang.hasPrefix("zh-Hant") || lang.hasPrefix("zh-HK") || lang.hasPrefix("zh-TW") { return "zh-Hant" } |
| | | if lang.hasPrefix("zh") { return "zh-Hans" } |
| | |
| | | func tr(_ key: String) -> String { |
| | | L10n.current[key] ?? key |
| | | } |
| | | |
| | | enum HelpDocument { |
| | | private static let baseURL = "https://github.com/shanghai3168/taglauncher/releases/download/v7.6.0" |
| | | |
| | | static var currentURL: URL { |
| | | URL(string: "\(baseURL)/Taglauncher-help-\(languageCode(for: L10n.currentCode)).pdf")! |
| | | } |
| | | |
| | | private static func languageCode(for appLanguageCode: String) -> String { |
| | | switch appLanguageCode { |
| | | case "zh-Hans": return "zh" |
| | | case "zh-Hant": return "zh-Hant" |
| | | case "en", "ar", "ar-Najdi", "cs", "da", "de", "es", "fr", "id", |
| | | "it", "ja", "ko", "ms", "nb", "nl", "nn", "no", "pl", "pt-BR", |
| | | "ro", "ru", "sr-Cyrl", "sv", "th", "tr", "uk", "vi": |
| | | return appLanguageCode |
| | | default: |
| | | return "en" |
| | | } |
| | | } |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "تلقائي", |
| | | "help.downloadPDF": "تنزيل ملف المساعدة PDF" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "تلقائي", |
| | | "help.downloadPDF": "تنزيل ملف المساعدة PDF" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Automaticky", |
| | | "help.downloadPDF": "Stáhnout PDF nápovědy" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Automatisk", |
| | | "help.downloadPDF": "Download hjælp-PDF" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Hilfe-PDF öffnen", |
| | | "help.copyLink": "Link zum Hilfe-PDF kopieren", |
| | | "help.currentLanguage": "Öffnet das Online-PDF für die aktuelle App-Sprache." |
| | | "help.currentLanguage": "Öffnet das Online-PDF für die aktuelle App-Sprache.", |
| | | "settings.language.auto": "Automatisch", |
| | | "help.downloadPDF": "Hilfe-PDF herunterladen" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Automatic", |
| | | "help.downloadPDF": "Download Help PDF" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Abrir PDF de ayuda", |
| | | "help.copyLink": "Copiar enlace del PDF de ayuda", |
| | | "help.currentLanguage": "Abre el PDF en línea para el idioma actual de la app." |
| | | "help.currentLanguage": "Abre el PDF en línea para el idioma actual de la app.", |
| | | "settings.language.auto": "Automático", |
| | | "help.downloadPDF": "Descargar PDF de ayuda" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Ouvrir le PDF d’aide", |
| | | "help.copyLink": "Copier le lien du PDF d’aide", |
| | | "help.currentLanguage": "Ouvre le PDF en ligne correspondant à la langue actuelle de l’app." |
| | | "help.currentLanguage": "Ouvre le PDF en ligne correspondant à la langue actuelle de l’app.", |
| | | "settings.language.auto": "Automatique", |
| | | "help.downloadPDF": "Télécharger le PDF d’aide" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Otomatis", |
| | | "help.downloadPDF": "Unduh PDF bantuan" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Apri PDF di aiuto", |
| | | "help.copyLink": "Copia link del PDF di aiuto", |
| | | "help.currentLanguage": "Apre il PDF online per la lingua attuale dell’app." |
| | | "help.currentLanguage": "Apre il PDF online per la lingua attuale dell’app.", |
| | | "settings.language.auto": "Automatico", |
| | | "help.downloadPDF": "Scarica PDF di aiuto" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "ヘルプPDFを開く", |
| | | "help.copyLink": "ヘルプPDFのリンクをコピー", |
| | | "help.currentLanguage": "現在のアプリ言語に対応するオンラインPDFを開きます。" |
| | | "help.currentLanguage": "現在のアプリ言語に対応するオンラインPDFを開きます。", |
| | | "settings.language.auto": "自動", |
| | | "help.downloadPDF": "ヘルプPDFをダウンロード" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "도움말 PDF 열기", |
| | | "help.copyLink": "도움말 PDF 링크 복사", |
| | | "help.currentLanguage": "현재 앱 언어에 맞는 온라인 PDF를 엽니다." |
| | | "help.currentLanguage": "현재 앱 언어에 맞는 온라인 PDF를 엽니다.", |
| | | "settings.language.auto": "자동", |
| | | "help.downloadPDF": "도움말 PDF 다운로드" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Automatik", |
| | | "help.downloadPDF": "Muat turun PDF bantuan" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Automatisk", |
| | | "help.downloadPDF": "Last ned hjelp-PDF" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Automatisch", |
| | | "help.downloadPDF": "Help-PDF downloaden" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Automatisk", |
| | | "help.downloadPDF": "Last ned hjelp-PDF" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Automatisk", |
| | | "help.downloadPDF": "Last ned hjelp-PDF" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Automatycznie", |
| | | "help.downloadPDF": "Pobierz PDF pomocy" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Automático", |
| | | "help.downloadPDF": "Baixar PDF de ajuda" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Automat", |
| | | "help.downloadPDF": "Descarcă PDF-ul de ajutor" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Открыть PDF справки", |
| | | "help.copyLink": "Скопировать ссылку на PDF справки", |
| | | "help.currentLanguage": "Открывает онлайн-PDF для текущего языка приложения." |
| | | "help.currentLanguage": "Открывает онлайн-PDF для текущего языка приложения.", |
| | | "settings.language.auto": "Автоматически", |
| | | "help.downloadPDF": "Скачать PDF справки" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Аутоматски", |
| | | "help.downloadPDF": "Преузми PDF помоћи" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Automatiskt", |
| | | "help.downloadPDF": "Ladda ner hjälp-PDF" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "อัตโนมัติ", |
| | | "help.downloadPDF": "ดาวน์โหลด PDF วิธีใช้" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Otomatik", |
| | | "help.downloadPDF": "Yardım PDF’sini indir" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Автоматично", |
| | | "help.downloadPDF": "Завантажити PDF довідки" |
| | | } |
| | |
| | | "smart.category.network-tools": "Network Tools", |
| | | "help.openPDF": "Open Help PDF", |
| | | "help.copyLink": "Copy Help PDF link", |
| | | "help.currentLanguage": "Opens the online PDF for the current app language." |
| | | "help.currentLanguage": "Opens the online PDF for the current app language.", |
| | | "settings.language.auto": "Tự động", |
| | | "help.downloadPDF": "Tải PDF trợ giúp" |
| | | } |
| | |
| | | "smart.category.network-tools": "网络工具", |
| | | "help.openPDF": "打开帮助文档", |
| | | "help.copyLink": "复制帮助文档链接", |
| | | "help.currentLanguage": "将按当前应用语言打开对应版本的在线 PDF。" |
| | | "help.currentLanguage": "将按当前应用语言打开对应版本的在线 PDF。", |
| | | "settings.language.auto": "自动", |
| | | "help.downloadPDF": "下载帮助文档" |
| | | } |
| | |
| | | "smart.category.network-tools": "網路工具", |
| | | "help.openPDF": "打開說明文件", |
| | | "help.copyLink": "複製說明文件連結", |
| | | "help.currentLanguage": "將依目前應用程式語言開啟對應版本的線上 PDF。" |
| | | "help.currentLanguage": "將依目前應用程式語言開啟對應版本的線上 PDF。", |
| | | "settings.language.auto": "自動", |
| | | "help.downloadPDF": "下載說明文件" |
| | | } |
| | |
| | | @AppStorage("showUncommonAppBubbles") private var showUncommonAppBubbles = AppDefaults.showUncommonAppBubbles |
| | | @AppStorage("mainHotkeyRegistrationState") private var mainHotkeyRegistrationState = LauncherHotkeyRegistrationState.active.rawValue |
| | | @AppStorage("quickSearchHotkeyRegistrationState") private var quickSearchHotkeyRegistrationState = LauncherHotkeyRegistrationState.active.rawValue |
| | | @State private var selectedLanguage = L10n.currentCode |
| | | @State private var selectedLanguage = L10n.selectedLanguageCode |
| | | @State private var isRefreshingLanguage = false |
| | | @State private var allApps: [AppInfo] = [] |
| | | @State private var tagColors: [String: Int] = [:] |
| | |
| | | } |
| | | |
| | | private func syncSelectedLanguage() { |
| | | let code = L10n.currentCode |
| | | let code = L10n.selectedLanguageCode |
| | | guard selectedLanguage != code else { return } |
| | | selectedLanguage = code |
| | | } |
| | |
| | | private var buildVersion: String { |
| | | Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "?" |
| | | } |
| | | private var helpPDFLanguageCode: String { |
| | | switch L10n.currentCode { |
| | | case "zh-Hans": return "zh" |
| | | case "zh-Hant": return "zh-Hant" |
| | | case "en", "ar", "ar-Najdi", "cs", "da", "de", "es", "fr", "id", |
| | | "it", "ja", "ko", "ms", "nb", "nl", "nn", "no", "pl", "pt-BR", |
| | | "ro", "ru", "sr-Cyrl", "sv", "th", "tr", "uk", "vi": |
| | | return L10n.currentCode |
| | | default: |
| | | return "en" |
| | | } |
| | | } |
| | | private var helpPDFURL: URL { |
| | | URL(string: "https://github.com/shanghai3168/taglauncher/releases/download/v7.6.0/Taglauncher-help-\(helpPDFLanguageCode).pdf")! |
| | | HelpDocument.currentURL |
| | | } |
| | | private var languageColumns: [GridItem] { |
| | | [ |
| | |
| | | |
| | | ScrollView { |
| | | LazyVGrid(columns: languageColumns, alignment: .leading, spacing: 6) { |
| | | Button { |
| | | selectedLanguage = L10n.automaticCode |
| | | } label: { |
| | | HStack(spacing: 8) { |
| | | Image(systemName: selectedLanguage == L10n.automaticCode ? "checkmark" : "circle") |
| | | .font(.system(size: 12, weight: .semibold)) |
| | | .foregroundStyle(selectedLanguage == L10n.automaticCode ? Color.accentColor : Color.secondary.opacity(0.28)) |
| | | .frame(width: 16) |
| | | Text(tr("settings.language.auto")) |
| | | .foregroundStyle(.primary) |
| | | .lineLimit(1) |
| | | Text("(\(L10n.supported.first(where: { $0.code == L10n.currentCode })?.name ?? "English"))") |
| | | .font(.caption) |
| | | .foregroundStyle(.secondary) |
| | | .lineLimit(1) |
| | | Spacer(minLength: 0) |
| | | } |
| | | .padding(.horizontal, 8) |
| | | .padding(.vertical, 5) |
| | | .contentShape(Rectangle()) |
| | | } |
| | | .buttonStyle(.plain) |
| | | .accessibilityLabel("\(tr("settings.languagePicker")) \(tr("settings.language.auto"))") |
| | | |
| | | ForEach(L10n.supported, id: \.code) { language in |
| | | Button { |
| | | selectedLanguage = language.code |
| | |
| | | .padding() |
| | | } |
| | | .onChange(of: selectedLanguage) { _, code in |
| | | L10n.switchTo(code) |
| | | L10n.switchSelection(to: code) |
| | | } |
| | | .onReceive(NotificationCenter.default.publisher(for: .appLanguageDidChange)) { notification in |
| | | if let code = notification.userInfo?["code"] as? String { |
| | |
| | | |
| | | cat >"$assert_swift" <<'SWIFT' |
| | | import AppKit |
| | | import AppKit |
| | | import CoreGraphics |
| | | import Foundation |
| | | |
| | |
| | | SWIFT |
| | | |
| | | cat >"$coords_swift" <<'SWIFT' |
| | | import AppKit |
| | | import CoreGraphics |
| | | import Foundation |
| | | |
| | | let raw = CGWindowListCopyWindowInfo([.optionOnScreenOnly, .excludeDesktopElements], kCGNullWindowID) as? [[String: Any]] ?? [] |
| | | let tag = raw.filter { ($0[kCGWindowOwnerName as String] as? String) == "TagLauncher" } |
| | | let mode = CommandLine.arguments.dropFirst().first ?? "" |
| | | |
| | | func dimension(_ bounds: NSDictionary, _ key: String) -> CGFloat { |
| | | if let value = bounds[key] as? CGFloat { |
| | | return value |
| | | } |
| | | if let value = bounds[key] as? NSNumber { |
| | | return CGFloat(truncating: value) |
| | | } |
| | | return 0 |
| | | } |
| | | |
| | | switch mode { |
| | | case "data-tab": |
| | | guard let settings = tag.first(where: { (($0[kCGWindowName as String] as? String) ?? "").isEmpty == false }), |
| | |
| | | } |
| | | print("\(Int(round(x + 375))) \(Int(round(y + 331)))") |
| | | case "overlay-outside": |
| | | guard let overlay = tag.first(where: { (($0[kCGWindowName as String] as? String) ?? "").isEmpty }), |
| | | let overlayBounds = overlay[kCGWindowBounds as String] as? NSDictionary, |
| | | let overlayX = overlayBounds["X"] as? CGFloat, |
| | | let overlayY = overlayBounds["Y"] as? CGFloat else { |
| | | fputs("FAIL: could not find overlay window bounds\n", stderr) |
| | | exit(1) |
| | | guard let overlay = tag.max(by: { lhs, rhs in |
| | | let lhsBounds = lhs[kCGWindowBounds as String] as? NSDictionary ?? [:] |
| | | let rhsBounds = rhs[kCGWindowBounds as String] as? NSDictionary ?? [:] |
| | | let lhsArea = dimension(lhsBounds, "Width") * dimension(lhsBounds, "Height") |
| | | let rhsArea = dimension(rhsBounds, "Width") * dimension(rhsBounds, "Height") |
| | | return lhsArea < rhsArea |
| | | }), let overlayBounds = overlay[kCGWindowBounds as String] as? NSDictionary else { |
| | | let screen = NSScreen.screens.first?.frame ?? CGRect(x: 0, y: 0, width: 1200, height: 800) |
| | | print("\(Int(round(screen.minX + 120))) \(160)") |
| | | exit(0) |
| | | } |
| | | let overlayX = dimension(overlayBounds, "X") |
| | | let overlayY = dimension(overlayBounds, "Y") |
| | | print("\(Int(round(overlayX + 120))) \(Int(round(overlayY + 160)))") |
| | | default: |
| | | fputs("FAIL: unknown coords mode \(mode)\n", stderr) |