Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
48b1648
feat(mac): drag and drop .kmp with debug window
sgschantz Aug 10, 2026
d970506
feat(mac): handled drag and drop errors
sgschantz Aug 12, 2026
8276645
feat(mac): added function to clean up package on failed drop install
sgschantz Aug 12, 2026
652c6f7
feat(mac): drag and drop .kmp with debug window
sgschantz Aug 10, 2026
6a996ae
feat(mac): handled drag and drop errors
sgschantz Aug 12, 2026
e7c3539
feat(mac): added function to clean up package on failed drop install
sgschantz Aug 12, 2026
5c5dd6f
feat(mac): move drag and drop code to main config view
sgschantz Aug 16, 2026
a18c740
rename PackageDownload to PackageInstallHelper
sgschantz Aug 18, 2026
f194a15
feat(mac): enforce minimum keyman version for package
sgschantz Aug 18, 2026
52d41e7
feat(mac): used shared webview for help and readme
sgschantz Aug 20, 2026
38e3c45
Merge branch 'feat/mac/config-ui' into feat/mac/drag-kmp
sgschantz Aug 20, 2026
504e867
feat(mac): classified four different package installation types
sgschantz Aug 21, 2026
751dc0b
feat(mac): package download and drag and drop use common code
sgschantz Aug 21, 2026
f942bdb
feat(mac): tidied PackageConfirmationView
sgschantz Aug 21, 2026
6b92bd8
feat(mac): renaming for clarity
sgschantz Aug 21, 2026
a58f6f9
feat(mac): strip obsolete code
sgschantz Aug 21, 2026
3064a3d
feat(mac): added error handling for failed downloads
sgschantz Aug 21, 2026
69b4344
feat(mac): added progress indicator for downloads
sgschantz Aug 22, 2026
dc1e8a5
Merge branch 'feat/mac/config-ui' into feat/mac/drag-kmp
sgschantz Aug 22, 2026
7c5bc21
feat(mac): added internalError for debugging
sgschantz Aug 22, 2026
95ae54e
feat(mac): added font validation and installation
sgschantz Aug 24, 2026
bb26133
feat(mac): improve font installation error handling
sgschantz Aug 24, 2026
dd04926
feat(mac): comment revision
sgschantz Aug 25, 2026
f006f05
feat(mac): remove dependence on name of .kmp file
sgschantz Aug 25, 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
21 changes: 0 additions & 21 deletions mac/Config/Config.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,6 @@
D88F03DD2F50ED5100C02A31 /* ConfigUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ConfigUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */

/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
375D21122FF2F21800FCD24A /* Exceptions for "Config" folder in "Config" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
ConfigTests/ConfigTests.swift,
);
target = D88F03C52F50ED5000C02A31 /* Config */;
};
375D21132FF2F21800FCD24A /* Exceptions for "Config" folder in "ConfigTests" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
ConfigTests/ConfigTests.swift,
);
target = D88F03D22F50ED5100C02A31 /* ConfigTests */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */

/* Begin PBXFileSystemSynchronizedRootGroup section */
D87D6F492FAF95400083A95E /* Installation */ = {
isa = PBXFileSystemSynchronizedRootGroup;
Expand All @@ -58,10 +41,6 @@
};
D88F03C82F50ED5000C02A31 /* Config */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
375D21122FF2F21800FCD24A /* Exceptions for "Config" folder in "Config" target */,
375D21132FF2F21800FCD24A /* Exceptions for "Config" folder in "ConfigTests" target */,
);
path = Config;
sourceTree = "<group>";
};
Expand Down
108 changes: 108 additions & 0 deletions mac/Config/Config/AddKeyboardView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Keyman is copyright (C) SIL Global. MIT License.
*
* Created by Shawn Schantz on 2026-06-16
*
* Contains webview to search for keyboards and injects
* DownloadCoordinator to bridge back to SwiftUI
*/

import SwiftUI
import KeymanSettings

struct VisualEffectBlur: NSViewRepresentable {
func makeNSView(context: Context) -> NSVisualEffectView {
let view = NSVisualEffectView()
view.material = .hudWindow // Matches native dark/light HUD styling
view.blendingMode = .withinWindow
view.state = .active
return view
}

func updateNSView(_ nsView: NSVisualEffectView, context: Context) {}
}

struct AddKeyboardView: View {
@EnvironmentObject var settings: SettingsContainer
@Environment(\.dismiss) private var dismissAddKeyboardView
@StateObject private var downloadCoordinator = DownloadCoordinator()

var body: some View {
ZStack {
KeyboardSearchView(coordinator: downloadCoordinator)
.environmentObject(settings)
.padding()

if downloadCoordinator.isDownloading {
// Dim the background slightly to focus on the progress panel
Color.black.opacity(0.2)
.transition(.opacity)

VStack(spacing: 16) {
Text("Downloading File...")
.font(.headline)

// Native progress bar bound to the coordinator's value (0.0 to 1.0)
ProgressView(value: downloadCoordinator.downloadProgress, total: 1.0)
.progressViewStyle(.linear)
.frame(width: 250)

Text("\(Int(downloadCoordinator.downloadProgress * 100))%")
.font(.body)
.foregroundColor(.secondary)
}
.padding(24)
// translucent macOS look
.background(VisualEffectBlur())
.cornerRadius(12)
.shadow(radius: 10)
.transition(.scale.combined(with: .opacity))
}
}
.animation(.default, value: downloadCoordinator.isDownloading)
.toolbar {
// Placement determines where on the bar it sits
ToolbarItem(placement: .cancellationAction) {
Button("Close") {
print("close button clicked")
dismissAddKeyboardView()
if settings.isInstallationInProgress() {
settings.userCanceledPackageInstallation()
}
}
}
}
.onDisappear {
print("AddKeyboardView onDisappear")
downloadCoordinator.cancelActiveDownload()
}
.alert("Package Installation Failed", isPresented: $downloadCoordinator.loadPackageFailed) {
Button("OK", role: .cancel) { }
} message: {
if let message = downloadCoordinator.loadFailureMessage {
Text(message)
}
}
.sheet(isPresented: $downloadCoordinator.showConfirmPackageSheet) {
if let helper = downloadCoordinator.installHelper {
PackageConfirmationView(installHelper: helper) { accepted in
if accepted {
print("installing validated package: \(helper.packageName ?? "unknown package")")
do {
try settings.installPackage()
} catch {
print("failed to install package: \(helper.packageName ?? "unknown package") with error: \(error.localizedDescription)")
}
} else {
settings.userCanceledPackageInstallation()
}

// close sheet
downloadCoordinator.showConfirmPackageSheet = false
// close
dismissAddKeyboardView()
}
}
}
}
}
13 changes: 9 additions & 4 deletions mac/Config/Config/ConfigApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ struct ConfigApp: App {
var body: some Scene {
Window("Configuration", id: "main-config") {
MainConfigView()
// .background(Color(.underPageBackgroundColor))
.frame(
minWidth: 600, maxWidth: 1000,
minHeight: 400, maxHeight: .infinity
)
.environmentObject(settings)
.task {
if !installation.getHasDisplayedInstallationComplete() {
Expand All @@ -27,16 +32,16 @@ struct ConfigApp: App {
.onReceive(NotificationCenter.default.publisher(for: .installationRepairStarted)) { notification in openWindow(id: "install")
}
}
// the size of the window when first opened
// .defaultSize(width: 1024, height: 768)
.defaultSize(width: 800, height: 600)
.windowResizability(.contentSize)
Window("Installation", id: "install") {
MainInstallView()
.environmentObject(installation)
}
.windowResizability(.contentSize)
.defaultSize(width: 600, height: 500)
Window("Config Test", id: "config-debug") {
ConfigDebugView()
.environmentObject(settings)
}
Window("Install Test", id: "install-debug") {
InstallDebugView()
.environmentObject(installation)
Expand Down
85 changes: 0 additions & 85 deletions mac/Config/Config/ConfigDebugView.swift

This file was deleted.

18 changes: 0 additions & 18 deletions mac/Config/Config/ConfigTests/ConfigTests.swift

This file was deleted.

Loading