spiegel-keyman/mac/KeymanSettings/Sources/Model/Keyboard.swift
Shawn Schantz 895151d89a
Some checks are pending
Keyman Build Summary / Summarize build status checks (push) Waiting to run
feat(mac): refactor to allow package removal after install
When installed, packages keep a reference to their
location on disk so that they can delete their
associated files if removed. However, installation
from the internet now happens via a temp directory.
The directory must be updated when moved to the
install directory and there can be no trace of the
temp directory path anywhere when loading other
data from the package.

The cleanest way to accomplish this was to use
computed properties for the locations of all the
data like welcome.htm and the graphic image. These
properties are based on the single package
directory URL, and this URL is updated when the
package is moved.
2026-08-13 21:08:03 -04:00

93 lines
3 KiB
Swift

/*
* Keyman is copyright (C) SIL Global. MIT License.
*
* Created by Shawn Schantz on 2026-02-24
*
* Object that represents a Keyman keyboard
* Each keyboard can be marked as enabled/disabled
*
*/
import Foundation
import AppKit
public class Keyboard: Identifiable, Hashable, Equatable {
public var id = UUID()
public var enabled: Bool
public var name: String
public let oskFont: String?
public let displayFont: String?
public var keyboardId: String
// a key to uniquely identify the keyboard
// in the UserDefaults this key is used for the selected Keyboard and enabled keyboards properties
// the key is in the form "/[package directory]/[package name].kmx"
// for example, "/khmer_angkor/khmer_angkor.kmx"
public let keyboardKey: String
public init(keyboardSource: KeyboardSource, packageDirectoryName: String) {
self.enabled = true
self.name = keyboardSource.name
self.oskFont = keyboardSource.oskFont
self.displayFont = keyboardSource.displayFont
self.keyboardId = keyboardSource.id
self.keyboardKey = Keyboard.deriveKeyboardSettingsKey(from: packageDirectoryName, keyboardId: self.keyboardId)
}
/**
* initializer that does not rely on package source -- provided to create unit test data
*/
public init(name: String, oskFont: String? = nil, displayFont: String? = nil, keyboardId: String, packageDirectoryName: String, enabled: Bool) {
self.name = name
self.oskFont = oskFont
self.displayFont = displayFont
self.keyboardId = keyboardId
self.enabled = enabled
self.keyboardKey = Keyboard.deriveKeyboardSettingsKey(from: packageDirectoryName, keyboardId: self.keyboardId)
}
/**
* provided for Equatable conformance
*/
public static func == (lhs: Keyboard, rhs: Keyboard) -> Bool {
return lhs.keyboardId == rhs.keyboardId && lhs.enabled == rhs.enabled
}
/**
* provided for Hashable conformance
*/
public func hash(into hasher: inout Hasher) {
hasher.combine(keyboardId)
}
/**
* generate the url for the keyboard's kmx file
*/
func deriveKmxFileUrl(from keyboardDirectory: URL) -> URL {
return keyboardDirectory.appendingPathComponent("\(keyboardId).kmx")
}
/**
* generate the keyboard's key
* see the above comment for `keyboardKey` for a description of the format of the key
*/
static func deriveKeyboardSettingsKey(from packageDirectoryName: String, keyboardId: String) -> String {
// get filename from keyboardId
let kmxFilename = "\(keyboardId).kmx"
let settingsKey = "/\(packageDirectoryName)/\(kmxFilename)"
return settingsKey
}
/**
* validate whether a corresponding kmx file exists for this keyboard
*/
public func validateKmxFile(in packageDirectory: URL) throws {
let kmxFilePath = self.deriveKmxFileUrl(from: packageDirectory).path
if !FileManager.default.fileExists(atPath: kmxFilePath) {
print("** error: could not find kmx file \(kmxFilePath)")
throw LoadPackageError.missingKmxFile
}
}
}