From b19c85350e456b27678ac716439ef6182ebc73f4 Mon Sep 17 00:00:00 2001 From: Shawn Schantz Date: Thu, 3 Sep 2026 10:50:36 -0400 Subject: [PATCH 1/4] feat(mac): remove logging of legacy paths --- mac/KeymanSettings/Sources/Persistence/KeymanPaths.swift | 7 ------- 1 file changed, 7 deletions(-) diff --git a/mac/KeymanSettings/Sources/Persistence/KeymanPaths.swift b/mac/KeymanSettings/Sources/Persistence/KeymanPaths.swift index 96a9cc8780..bc3b9c8c82 100644 --- a/mac/KeymanSettings/Sources/Persistence/KeymanPaths.swift +++ b/mac/KeymanSettings/Sources/Persistence/KeymanPaths.swift @@ -113,13 +113,6 @@ public struct KeymanPaths { } fileprivate func logPaths() { - Logger.setup.debug("documents: \(self.keyman17DocumentsDirectory!.cleanUrlPath())") - Logger.setup.debug("keyman 17 packages: \(self.keyman17PackagesDirectory!.cleanUrlPath())") - - Logger.setup.debug("support directory: \(self.keyman18SupportDirectory!.cleanUrlPath())") - Logger.setup.debug("support keyman directory: \(self.keyman18DataDirectory!.cleanUrlPath())") - Logger.setup.debug("keyman 18 packages: \(self.keyman18PackagesDirectory!.cleanUrlPath())") - Logger.setup.debug("container: \(self.keyman19ContainerDirectory.cleanUrlPath())") Logger.setup.debug("preferences: \(self.keyman19PreferencesDirectory.cleanUrlPath())") Logger.setup.debug("keyman 19 packages: \(self.keyman19PackagesDirectory.cleanUrlPath())") From 4d545000fc1f52c6a5e9fd7e36fb8d4a3d1e8565 Mon Sep 17 00:00:00 2001 From: Shawn Schantz Date: Fri, 4 Sep 2026 05:07:30 -0400 Subject: [PATCH 2/4] feat(mac): track swift package in use --- .../xcshareddata/swiftpm/Package.resolved | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 mac/Keyman.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/mac/Keyman.xcworkspace/xcshareddata/swiftpm/Package.resolved b/mac/Keyman.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000000..581bbf535d --- /dev/null +++ b/mac/Keyman.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,24 @@ +{ + "originHash" : "d6053e837382e5b9950aabdaac059058993d8ef6619f809121310d22cd4216b5", + "pins" : [ + { + "identity" : "sentry-cocoa", + "kind" : "remoteSourceControl", + "location" : "https://github.com/getsentry/sentry-cocoa", + "state" : { + "revision" : "a00a9784fff7193cbb0f9fae509fec8107e07744", + "version" : "9.26.1" + } + }, + { + "identity" : "zipfoundation", + "kind" : "remoteSourceControl", + "location" : "https://github.com/weichsel/ZIPFoundation.git", + "state" : { + "revision" : "22787ffb59de99e5dc1fbfe80b19c97a904ad48d", + "version" : "0.9.20" + } + } + ], + "version" : 3 +} From 51992b96f02604b3d3991637ac3fce15a3a23b13 Mon Sep 17 00:00:00 2001 From: Shawn Schantz Date: Thu, 10 Sep 2026 12:33:28 -0400 Subject: [PATCH 3/4] feat(mac): minscule formatting change --- mac/KeymanSettings/Sources/KeymanSettings/InputMethodUtil.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mac/KeymanSettings/Sources/KeymanSettings/InputMethodUtil.swift b/mac/KeymanSettings/Sources/KeymanSettings/InputMethodUtil.swift index 0f5f51cd55..3d4860094b 100644 --- a/mac/KeymanSettings/Sources/KeymanSettings/InputMethodUtil.swift +++ b/mac/KeymanSettings/Sources/KeymanSettings/InputMethodUtil.swift @@ -316,7 +316,7 @@ public class InputMethodUtil { let targetSource = sources.first else { Logger.setup.error("Could not find the specified input source with bundleID: \(bundleId, privacy: .public)") LogUtil.errorBreadcrumb("Could not find the specified input source with bundleID: \(bundleId)", category: .setup) - return(nil) + return(nil) } return targetSource From 8a206ccb21df5ec1c12bcbb3e1cf22072babcee6 Mon Sep 17 00:00:00 2001 From: Eli Schantz Date: Thu, 10 Sep 2026 22:37:25 -0400 Subject: [PATCH 4/4] feat(mac): Added new about window --- mac/Config/Config.xcodeproj/project.pbxproj | 7 + mac/Config/Config/About/AboutPanelView.swift | 56 ++++++++ mac/Config/Config/ConfigApp.swift | 42 ++++++ mac/Config/Localizable.xcstrings | 20 +++ .../Resources/keyman-for-mac-os-license.html | 123 ++++++++++++++++++ 5 files changed, 248 insertions(+) create mode 100644 mac/Config/Config/About/AboutPanelView.swift create mode 100644 mac/Config/Resources/keyman-for-mac-os-license.html diff --git a/mac/Config/Config.xcodeproj/project.pbxproj b/mac/Config/Config.xcodeproj/project.pbxproj index 1eb4f548bf..9522140b14 100644 --- a/mac/Config/Config.xcodeproj/project.pbxproj +++ b/mac/Config/Config.xcodeproj/project.pbxproj @@ -47,6 +47,11 @@ /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ + 3A589DC630539F2B00E2DD63 /* Resources */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = Resources; + sourceTree = ""; + }; D87D6F492FAF95400083A95E /* Installation */ = { isa = PBXFileSystemSynchronizedRootGroup; path = Installation; @@ -97,6 +102,7 @@ D88F03BD2F50ED5000C02A31 = { isa = PBXGroup; children = ( + 3A589DC630539F2B00E2DD63 /* Resources */, D8F10B613048F12A00C1E597 /* Localizable.xcstrings */, D87D6F492FAF95400083A95E /* Installation */, D88F03C82F50ED5000C02A31 /* Config */, @@ -139,6 +145,7 @@ dependencies = ( ); fileSystemSynchronizedGroups = ( + 3A589DC630539F2B00E2DD63 /* Resources */, D87D6F492FAF95400083A95E /* Installation */, D88F03C82F50ED5000C02A31 /* Config */, ); diff --git a/mac/Config/Config/About/AboutPanelView.swift b/mac/Config/Config/About/AboutPanelView.swift new file mode 100644 index 0000000000..fa28d0dac6 --- /dev/null +++ b/mac/Config/Config/About/AboutPanelView.swift @@ -0,0 +1,56 @@ +/* + * Keyman is copyright (C) SIL Global. MIT License. + * + * Created by Eli Schantz on 2026-07-23 + * + * View shown when About Keyman Configuration is selected from the menu. + */ + +import SwiftUI +import KeymanSettings + +struct AboutPanelView: View { + + var body: some View { + VStack(spacing: 20) { + HStack(alignment: .top, spacing: 28) { + Image(nsImage: NSApp.applicationIconImage) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 104, height: 104) + + VStack(alignment: .leading, spacing: 6) { + Text("Keyman Configuration") + .font(.system(size: 32, weight: .semibold)) + Text("Version \(ConfigAppUtil.configAppVersion())") + .font(.system(size: 13)) + .foregroundStyle(.secondary) + + Spacer(minLength: 14) + + Text("Copyright © SIL Global") + .font(.system(size: 11)) + .foregroundStyle(.secondary) + } + + Spacer(minLength: 0) + } + + HStack { + Spacer() + Button("License Agreement") { + if let url = Bundle.main.url(forResource: "keyman-for-mac-os-license", withExtension: "html") { + NSWorkspace.shared.open(url) + } + } + } + } + .padding(.top, 32) + .padding(.horizontal, 42) + .padding(.bottom, 20) + .frame(width: 570, height: 200) + } +} +#Preview { + AboutPanelView() +} diff --git a/mac/Config/Config/ConfigApp.swift b/mac/Config/Config/ConfigApp.swift index c462b15f60..1e902c9a0c 100644 --- a/mac/Config/Config/ConfigApp.swift +++ b/mac/Config/Config/ConfigApp.swift @@ -7,6 +7,7 @@ */ import SwiftUI +import AppKit import KeymanSettings import OSLog import Sentry @@ -61,6 +62,15 @@ struct ConfigApp: App { } .windowResizability(.contentSize) .defaultSize(width: 600, height: 500) + .commands { + CommandGroup(replacing: .appInfo) { + Button { + AboutPanelPresenter.showAboutPanel() + } label: { + Label("About Keyman Configuration", systemImage: "info.circle") + } + } + } // for testing purposes // Window("Install Test", id: "install-debug") { @@ -69,3 +79,35 @@ struct ConfigApp: App { // } } } + +@MainActor +private enum AboutPanelPresenter { + private static var aboutWindow: NSWindow? + + static func showAboutPanel() { + let contentView = AboutPanelView() + + let window = aboutWindow ?? makeAboutWindow() + window.contentView = NSHostingView(rootView: contentView) + window.center() + window.makeKeyAndOrderFront(nil) + aboutWindow = window + + NSApp.activate(ignoringOtherApps: true) + } + + private static func makeAboutWindow() -> NSWindow { + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 570, height: 200), + styleMask: [.titled, .closable], + backing: .buffered, + defer: false + ) + + window.titleVisibility = .hidden + window.titlebarAppearsTransparent = true + window.isReleasedWhenClosed = false + window.backgroundColor = .windowBackgroundColor + return window + } +} diff --git a/mac/Config/Localizable.xcstrings b/mac/Config/Localizable.xcstrings index e2a2bea6b2..2c2735ae2e 100644 --- a/mac/Config/Localizable.xcstrings +++ b/mac/Config/Localizable.xcstrings @@ -1,6 +1,10 @@ { "sourceLanguage" : "en", "strings" : { + "About Keyman Configuration" : { + "comment" : "A label for the about panel.", + "isCommentAutoGenerated" : true + }, "Access has not been granted." : { }, @@ -30,6 +34,10 @@ }, "Copy link" : { + }, + "Copyright © SIL Global" : { + "comment" : "A copyright notice.", + "isCommentAutoGenerated" : true }, "Copyright:" : { @@ -78,6 +86,14 @@ }, "Keyboards" : { + }, + "Keyman Configuration" : { + "comment" : "The name of the app.", + "isCommentAutoGenerated" : true + }, + "License Agreement" : { + "comment" : "A button that opens a web page with the license agreement for Keyman for macOS.", + "isCommentAutoGenerated" : true }, "Missing Keyman Components" : { @@ -129,6 +145,10 @@ }, "To use Keyman, enable the Keyman input method in System Settings." : { + }, + "Version %@" : { + "comment" : "A description of the app, including its version and copyright.", + "isCommentAutoGenerated" : true }, "Website:" : { diff --git a/mac/Config/Resources/keyman-for-mac-os-license.html b/mac/Config/Resources/keyman-for-mac-os-license.html new file mode 100644 index 0000000000..feb7e7ac7e --- /dev/null +++ b/mac/Config/Resources/keyman-for-mac-os-license.html @@ -0,0 +1,123 @@ + + + + + + + + + + + + +
+ +

Keyman­® for macOS +End User Licence and Services Agreement

+ +

The MIT License

+

Copyright (c) 2017 SIL International

+

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ + + +
+ +

 

+ +
+ +
+ + + +