Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
b6d1fdf
feat(mac): created new installation views in Configuration app
ejschantz Jul 4, 2026
d7dfa70
feat(mac): rollback test code
ejschantz Jul 17, 2026
645efff
Merge branch 'feat/mac/notify-input-method' into feat/mac/install-window
ejschantz Jul 17, 2026
13cd4f6
feat(mac): Added notification support to installer
ejschantz Jul 21, 2026
16b49b6
Merge branch 'feat/mac/install-notifications' into feat/mac/install-w…
ejschantz Jul 21, 2026
c56532f
Merge branch 'feat/mac/install-notifications' into feat/mac/install-w…
ejschantz Jul 23, 2026
ed44f10
feat(mac): Added input method error screen and restart view
ejschantz Jul 23, 2026
c86a233
feat(mac): Added about window
ejschantz Jul 23, 2026
25a7b7d
feat(mac): Improved functionality of About window
ejschantz Jul 24, 2026
83882f8
Merge branch 'feat/mac/install-notifications' into feat/mac/install-w…
ejschantz Jul 24, 2026
a9f05a2
Merge branch 'feat/mac/install-notifications' into feat/mac/install-w…
ejschantz Jul 24, 2026
2e71a2e
Merge branch 'feat/mac/install-notifications' into feat/mac/install-w…
ejschantz Jul 25, 2026
4a50aa1
feat(mac): First draft of integrated installer
ejschantz Jul 25, 2026
9376ae9
Merge branch 'feat/mac/install-window' into feat/mac/about
ejschantz Jul 25, 2026
d14fe10
feat(mac): Changed label for About button
ejschantz Jul 25, 2026
a73497a
feat(mac): Added procedural file comment to AboutPanelView
ejschantz Aug 17, 2026
e57da47
Merge branch 'epic/mac-config' into feat/mac/about
sgschantz Aug 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions mac/Config/Config.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */

/* Begin PBXFileSystemSynchronizedRootGroup section */
3A8B4F0F301263BC00A18F80 /* Resources */ = {
isa = PBXFileSystemSynchronizedRootGroup;
path = Resources;
sourceTree = "<group>";
};
D87D6F492FAF95400083A95E /* Installation */ = {
isa = PBXFileSystemSynchronizedRootGroup;
path = Installation;
Expand Down Expand Up @@ -101,6 +106,7 @@
D88F03BD2F50ED5000C02A31 = {
isa = PBXGroup;
children = (
3A8B4F0F301263BC00A18F80 /* Resources */,
D87D6F492FAF95400083A95E /* Installation */,
D88F03C82F50ED5000C02A31 /* Config */,
D88F03E02F50ED5100C02A31 /* ConfigUITests */,
Expand Down Expand Up @@ -142,6 +148,7 @@
dependencies = (
);
fileSystemSynchronizedGroups = (
3A8B4F0F301263BC00A18F80 /* Resources */,
D87D6F492FAF95400083A95E /* Installation */,
D88F03C82F50ED5000C02A31 /* Config */,
);
Expand Down
56 changes: 56 additions & 0 deletions mac/Config/Config/About/AboutPanelView.swift
Original file line number Diff line number Diff line change
@@ -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()
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"images" : [
{
"filename" : "AccessibilityPermissionLight.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "AccessibilityPermissionDark.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "AccessibilityPermissionLight 1.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "AccessibilityPermissionDark 1.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "AccessibilityPermissionLight 2.png",
"idiom" : "universal",
"scale" : "3x"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "AccessibilityPermissionDark 2.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"images" : [
{
"filename" : "EnableKeymanLight.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "EnableKeymanDark.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "EnableKeymanLight 2.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "EnableKeymanDark 1.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "EnableKeymanLight 1.png",
"idiom" : "universal",
"scale" : "3x"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "EnableKeymanDark 2.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "InstallerIcon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "InstallerIcon 1.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "InstallerIcon 2.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "Keyman-256.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Keyman-256 1.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Keyman-256 2.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"images" : [
{
"filename" : "keyman logo BIG (2) 3.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "Keyman_Logo_BIG_Dark.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "keyman logo BIG (2) 1.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "Keyman_Logo_BIG_Dark 1.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "keyman logo BIG (2) 2.png",
"idiom" : "universal",
"scale" : "3x"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "Keyman_Logo_BIG_Dark 2.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
51 changes: 51 additions & 0 deletions mac/Config/Config/ConfigApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

import SwiftUI
import AppKit
import KeymanSettings

@main
Expand All @@ -22,11 +23,13 @@ struct ConfigApp: App {
.task {
if !installation.getHasDisplayedInstallationComplete() {
openWindow(id: "install")
openWindow(id: "new install")
}
}
.onReceive(NotificationCenter.default.publisher(for: .installationRepairStarted)) { notification in openWindow(id: "install")
}
}

Window("Installation", id: "install") {
MainInstallView()
.environmentObject(installation)
Expand All @@ -41,5 +44,53 @@ struct ConfigApp: App {
InstallDebugView()
.environmentObject(installation)
}

Window("New Installation", id: "new install") {
ParentInstallView()
.environmentObject(installation)
}
.defaultSize(width: 500, height: 400)
.windowResizability(.contentSize)
.commands {
CommandGroup(replacing: .appInfo) {
Button {
AboutPanelPresenter.showAboutPanel()
} label: {
Label("About Keyman Configuration", systemImage: "info.circle")
}
}
}
}
}

@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
}
}
Loading