spiegel-keyman/mac/KeymanSettings/Sources/Model/KeymanPackage.swift
Shawn Schantz bb816a1335
Some checks failed
Keyman Build Summary / Summarize build status checks (push) Has been cancelled
feat(mac): display packages and keyboard list view
added buttons for removal of packages
and toggle for disabling of keyboard
not remotely final but mostly for ensuring that
we can bind to the data model and respond to updates
2026-04-02 14:01:11 -04:00

138 lines
3.9 KiB
Swift

/*
* Keyman is copyright (C) SIL Global. MIT License.
*
* Created by Shawn Schantz on 2026-02-24
*
* Wrapper object that represents a Keyman package as loaded from a .KMP file
* Mostly immutable, but can be marked as enabled/disabled
*
*/
import Foundation
import AppKit
// MARK: - Root
public class KeymanPackage: Identifiable, Hashable, Equatable {
static let defaultImage: NSImage? = {
var image: NSImage? = nil
if let imageUrl = Bundle.main.url(forResource: "SideImage", withExtension: "bmp") {
image = NSImage(contentsOf: imageUrl)
}
return image
}()
public var id = UUID()
let source: PackageSource
public var keyboards: [Keyboard]
// the URL of the directory in which the package is contained
public let sourceDirectoryUrl: URL
// the URL of the kmp.json file for the package
public let jsonFileUrl: URL
public let readmeFileUrl: URL?
public let graphicFileUrl: URL?
public let graphicImage: NSImage?
// computed properties for convenience
public var packageName: String {
return source.info.name.description
}
public var packageVersion: String {
return source.info.version.description
}
public var copyright: String? {
if let copy = source.info.copyright?.description {
return copy
} else {
return nil
}
}
init(packageSource: PackageSource) {
self.source = packageSource
self.sourceDirectoryUrl = packageSource.directoryUrl!
self.jsonFileUrl = packageSource.jsonFileUrl!
if let readmeFilename = packageSource.readmeFilename {
let fileUrl = sourceDirectoryUrl.appendingPathComponent(readmeFilename)
self.readmeFileUrl = fileUrl
} else {
self.readmeFileUrl = nil
}
self.graphicFileUrl = KeymanPackage.buildGraphicFileUrl(source: packageSource)
self.graphicImage = KeymanPackage.loadImage(imageUrl: self.graphicFileUrl)
var keyboardsArray = [Keyboard]()
if let keyboards = source.keyboards {
for keyboardSource in keyboards {
let keyboard = Keyboard(keyboardSource: keyboardSource, directoryUrl: self.sourceDirectoryUrl)
keyboardsArray.append(keyboard)
}
}
self.keyboards = keyboardsArray
// ConfigLogger.shared.testLogger.debug("package created for: \(packageSource.packageName)")
print("package created for: \(packageSource.packageName)")
}
public func isKeyboardEnabled(keyboardId: String) -> Bool {
var enabled = false
if let keyboard = self.keyboards.first(where: { $0.keyboardId == keyboardId }) {
enabled = keyboard.enabled
}
return enabled
}
public func enableKeyboard(keyboardId: String, enabled: Bool) {
let keyboard = self.keyboards.first(where: { $0.keyboardId == keyboardId })
if (keyboard != nil) {
keyboard!.enabled = enabled
}
}
public func validate() -> Bool {
var validKeyboards = self.keyboards.isEmpty == false
self.keyboards.forEach { keyboard in
if (validKeyboards && !keyboard.validateKmxFile()) {
validKeyboards = false
}
}
return validKeyboards
}
static func buildGraphicFileUrl(source: PackageSource) -> URL? {
var fileUrl: URL? = nil
if let graphicFilename = source.graphicFilename {
fileUrl = source.directoryUrl!.appendingPathComponent(graphicFilename)
}
return fileUrl
}
static func loadImage(imageUrl: URL?) -> NSImage? {
var packageImage: NSImage? = nil;
if let fileUrl = imageUrl, let image = NSImage(contentsOf: fileUrl) {
packageImage = image
} else {
packageImage = KeymanPackage.defaultImage
}
return packageImage
}
public func hash(into hasher: inout Hasher) {
hasher.combine(id) // only combine the unique ID
}
// Custom Equatable conformance (required by Hashable)
public static func == (lhs: KeymanPackage, rhs: KeymanPackage) -> Bool {
return lhs.id == rhs.id // only compare unique IDs
}
}