mirror of
https://github.com/keymanapp/keyman.git
synced 2026-10-18 11:57:38 +00:00
feat(mac): display packages and keyboard list view
Some checks failed
Keyman Build Summary / Summarize build status checks (push) Has been cancelled
Some checks failed
Keyman Build Summary / Summarize build status checks (push) Has been cancelled
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
This commit is contained in:
parent
45ac789c95
commit
bb816a1335
8 changed files with 394 additions and 69 deletions
|
|
@ -11,17 +11,61 @@ import KeymanSettings
|
|||
|
||||
struct ConfigView: View {
|
||||
@EnvironmentObject var settings: SettingsContainer
|
||||
// selectedItem cannot be used with .enumerated
|
||||
//@State private var selectedItem: KeymanPackage?
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Image(systemName: "keyboard")
|
||||
.imageScale(.large)
|
||||
.foregroundColor(.accentColor)
|
||||
Text(settings.settingName)
|
||||
Text("keyboard count = \(settings.keyboardPackages.count)")
|
||||
Button("Update settings") {settings.settingName = "Settings changed!"}
|
||||
Button("Remove last keyboard") {if !settings.keyboardPackages.isEmpty {
|
||||
settings.keyboardPackages.removeLast()}
|
||||
HStack {
|
||||
Image(systemName: "keyboard")
|
||||
.imageScale(.large)
|
||||
.foregroundColor(.accentColor)
|
||||
Text("keyboard count = \(settings.installedKeyboardPackages.count)")
|
||||
Button("debug") {
|
||||
settings.debug()
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
|
||||
// ScrollView(showsIndicators: false) {
|
||||
// List {
|
||||
// // Use $ to get binding to the published array
|
||||
// ForEach($settings.installedKeyboardPackages) { $package in
|
||||
// Section(header: Text("Section")) {
|
||||
// // Use $ to get binding to the nested array
|
||||
// ForEach($package.keyboards) { $keyboard in
|
||||
// Toggle(keyboard.keyboardId, isOn: $keyboard.enabled) // Binding here
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .padding()
|
||||
// }
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
ForEach(Array(settings.installedKeyboardPackages.enumerated()), id: \.offset) { index, package in
|
||||
VStack {
|
||||
HStack(alignment: .center, spacing: 10) {
|
||||
Text(package.packageName)
|
||||
.font(.headline)
|
||||
Text(package.packageVersion)
|
||||
.font(.subheadline)
|
||||
// Example of Icon-Only Button
|
||||
Spacer()
|
||||
Button(action: {
|
||||
settings.installedKeyboardPackages.remove(at: index)
|
||||
}) {
|
||||
Label("remove", systemImage: "trash.fill")
|
||||
}
|
||||
.labelStyle(.iconOnly)
|
||||
.buttonStyle(.borderless)
|
||||
}
|
||||
KeyboardListView(packageId: package.id, keyboards: package.keyboards)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.trailing, 25) // allow space for scroll bar
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
|
|
@ -29,7 +73,7 @@ struct ConfigView: View {
|
|||
}
|
||||
|
||||
#Preview {
|
||||
let configuration = Configuration()
|
||||
let settings = SettingsContainer()
|
||||
ConfigView()
|
||||
.environmentObject(configuration)
|
||||
.environmentObject(settings)
|
||||
}
|
||||
|
|
|
|||
34
mac/Config/Config/KeyboardListView.swift
Normal file
34
mac/Config/Config/KeyboardListView.swift
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*
|
||||
* Created by Shawn Schantz on 2026-04-02
|
||||
*
|
||||
* Subview to display list of keyboards for a package
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
import KeymanSettings
|
||||
import Combine
|
||||
|
||||
struct KeyboardListView: View {
|
||||
@EnvironmentObject var settings: SettingsContainer
|
||||
@State var packageId: UUID
|
||||
@State var keyboards: [Keyboard]
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
ForEach($keyboards) { $keyboard in
|
||||
HStack {
|
||||
Toggle("", isOn: Binding(
|
||||
get: { settings.isKeyboardEnabled(packageId: packageId, keyboardId: keyboard.keyboardId) },
|
||||
set: { newValue in settings.setKeyboardEnabled(packageId: packageId, keyboardId: keyboard.keyboardId, enabled: newValue)
|
||||
settings.objectWillChange.send() }
|
||||
))
|
||||
Text(keyboard.keyboardId)
|
||||
.padding(.leading, 5)
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +1,89 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*
|
||||
* Created by Shawn Schantz on 2026-04-02
|
||||
*
|
||||
* Class that exposes all settings information to the Config app
|
||||
* Provides a place for the Config app can bind directly to the settings
|
||||
* and update when changes are made
|
||||
*
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
public class SettingsContainer : ObservableObject {
|
||||
|
||||
@Published public var settingName: String
|
||||
@Published public var keyboardPackages: [KeymanPackage]
|
||||
@Published public var activeKeyboards: Set<String>
|
||||
@Published public var currentKeyboard: String
|
||||
|
||||
fileprivate let dataRepository: PackageRepository
|
||||
// keyboard packages are defined on disk
|
||||
@Published public var installedKeyboardPackages: [KeymanPackage]
|
||||
|
||||
fileprivate let packageRepository: PackageRepository
|
||||
fileprivate let settingsRepository: SettingsRepository
|
||||
|
||||
|
||||
// active keyboards and selected keyboard are stored in the UserDefaults
|
||||
fileprivate var activeKeyboards: Set<String>
|
||||
fileprivate var currentKeyboard: String
|
||||
|
||||
public init() {
|
||||
settingName = "uninitialized"
|
||||
self.dataRepository = PackageRepository()
|
||||
self.settingsRepository = SettingsRepository(suiteName: KeymanPaths.groupId)
|
||||
self.packageRepository = PackageRepository()
|
||||
|
||||
do {
|
||||
try self.settingsRepository = SettingsRepository(suiteName: KeymanPaths.groupId)
|
||||
print("Found group container")
|
||||
} catch UserDefaultsError.unknownSuite {
|
||||
fatalError("Group container not found.")
|
||||
} catch {
|
||||
fatalError("Unable to access settings in group container.")
|
||||
}
|
||||
|
||||
self.activeKeyboards = self.settingsRepository.readActiveKeyboards()
|
||||
self.currentKeyboard = self.settingsRepository.readSelectedKeyboard()
|
||||
|
||||
self.keyboardPackages = []
|
||||
self.installedKeyboardPackages = []
|
||||
self.loadPackages()
|
||||
self.synchronizeSettings()
|
||||
self.applySettings()
|
||||
}
|
||||
|
||||
// TODO: delete test code
|
||||
public func debug() {
|
||||
self.installedKeyboardPackages .forEach { package in
|
||||
package.keyboards.forEach { keyboard in
|
||||
print("\(keyboard.keyboardId) enabled: \(keyboard.enabled)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: extract method for keyboard search
|
||||
// TODO: throw error for keyboard not found or log and fail silently (should never happen)
|
||||
public func isKeyboardEnabled(packageId: UUID, keyboardId: String) -> Bool {
|
||||
var enabled = false;
|
||||
|
||||
guard let package = self.installedKeyboardPackages.first(where: { $0.id == packageId }) else {
|
||||
print ("ERROR: setKeyboardEnabled could not find package with ID: \(packageId)")
|
||||
return enabled
|
||||
}
|
||||
|
||||
enabled = package.isKeyboardEnabled(keyboardId: keyboardId)
|
||||
print ("isEnabled for \(keyboardId) returning with \(enabled)")
|
||||
|
||||
return enabled
|
||||
}
|
||||
|
||||
public func setKeyboardEnabled(packageId: UUID, keyboardId: String, enabled: Bool) {
|
||||
let package = self.installedKeyboardPackages.first(where: { $0.id == packageId })
|
||||
if (package == nil) {
|
||||
print ("ERROR: setKeyboardEnabled could not find package with ID: \(packageId)")
|
||||
} else {
|
||||
package!.enableKeyboard(keyboardId: keyboardId, enabled: enabled)
|
||||
print ("setKeyboardEnabled for \(keyboardId) setting to \(enabled)")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read the Keyman packages from the group container directory and store in the keyboardPackages array
|
||||
*/
|
||||
func loadPackages() {
|
||||
// TODO: create keyboards directory if it doesn't exist
|
||||
// if let keyboardsUrl = self.pathUtil.keymanKeyboardsDirectory {
|
||||
//
|
||||
// if FileManager.default.fileExists(atPath: keyboardsUrl.path) {
|
||||
|
|
@ -28,21 +92,50 @@ public class SettingsContainer : ObservableObject {
|
|||
// print("non-existent directory: \(keyboardsUrl.absoluteString)")
|
||||
// }
|
||||
// }
|
||||
|
||||
// load keyboards from disk
|
||||
if (self.dataRepository.keyman19SharedDataDirectoryExists()) {
|
||||
// TODO: remove test code
|
||||
self.dataRepository.writeSomethingToContainer()
|
||||
|
||||
let packageSourceArray = self.dataRepository.readKeymanPackagesForKeyman19()
|
||||
// load keyboards from disk
|
||||
if (self.packageRepository.keyman19SharedDataDirectoryExists()) {
|
||||
// TODO: remove test code
|
||||
self.packageRepository.writeSomethingToContainer()
|
||||
|
||||
// create a KeymanPackage object for each PackageSource object and insert it in the array
|
||||
for source in packageSourceArray {
|
||||
let package = KeymanPackage(packageSource: source)
|
||||
self.keyboardPackages.append(package)
|
||||
}
|
||||
self.installedKeyboardPackages = self.packageRepository.loadPackages()
|
||||
} else {
|
||||
self.dataRepository.createKeyman19SharedDataDirectories()
|
||||
self.packageRepository.createKeyman19SharedDataDirectories()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns set containing the keyboards settings keys for the keyboards of every installed package
|
||||
*/
|
||||
func getAllKeyboardSettingsKeys() -> Set<String> {
|
||||
var settingsKeys = Set<String>()
|
||||
|
||||
// loop through all the installed packages and for each of the package's keyboards,
|
||||
// insert the settings key for the keyboard
|
||||
self.installedKeyboardPackages.forEach { $0.keyboards.forEach
|
||||
{settingsKeys.insert($0.keyboardSettingsKey)}
|
||||
}
|
||||
|
||||
return settingsKeys
|
||||
}
|
||||
|
||||
/**
|
||||
* remove any settings (UserDefaults) for which we have no installed package
|
||||
*/
|
||||
func synchronizeSettings() {
|
||||
let installedPackageKeys = self.getAllKeyboardSettingsKeys()
|
||||
let activeKeyboardKeys = self.settingsRepository.readActiveKeyboards()
|
||||
let commonKeyboardKeys = installedPackageKeys.intersection(activeKeyboardKeys)
|
||||
|
||||
// TODO: replace the active keyboards list with the intersection of the current
|
||||
// active keyboards list and the installed packages list
|
||||
}
|
||||
|
||||
/**
|
||||
* apply the current settings to the installed packages
|
||||
*/
|
||||
func applySettings() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
*
|
||||
* Created by Shawn Schantz on 2026-02-24
|
||||
*
|
||||
* Wrapper bject that represents a Keyman keyboard as loaded from a .KMP file
|
||||
* Can be loaded but disabled
|
||||
* Wrapper object that represents a Keyman keyboard as loaded from a .KMP file
|
||||
* Mostly immutable, but can be marked as enabled/disabled
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -12,19 +12,86 @@
|
|||
import Foundation
|
||||
import AppKit
|
||||
|
||||
public struct Keyboard: Identifiable, Hashable, Equatable {
|
||||
public class Keyboard: Identifiable, Hashable, Equatable {
|
||||
|
||||
public var id = UUID()
|
||||
public var enabled: Bool
|
||||
public var name: String
|
||||
public var keyboardId: String
|
||||
|
||||
public init(keyboardSource: KeyboardSource) {
|
||||
// the directory we are reading the keyboard from
|
||||
public var keyboardDirectoryUrl: URL
|
||||
// the URL of the .kmx file for the package
|
||||
public let kmxFileUrl: URL
|
||||
// the UserDefaults key for this package, used for the selected Keyboard and active keyboards
|
||||
// the key is in the form "/[package directory]/[package name].kmx"
|
||||
// for example, "/khmer_angkor/khmer_angkor.kmx"
|
||||
public let keyboardSettingsKey: String
|
||||
|
||||
public init(keyboardSource: KeyboardSource, directoryUrl: URL) {
|
||||
self.enabled = true
|
||||
self.name = keyboardSource.name
|
||||
self.keyboardId = keyboardSource.id
|
||||
|
||||
self.keyboardDirectoryUrl = directoryUrl
|
||||
self.kmxFileUrl = Keyboard.deriveKmxFileUrl(from: self.keyboardDirectoryUrl, keyboardId: self.keyboardId)
|
||||
self.keyboardSettingsKey = Keyboard.deriveKeyboardSettingsKey(from: self.keyboardDirectoryUrl, keyboardId: self.keyboardId)
|
||||
|
||||
// ConfigLogger.shared.testLogger.debug("keyboard created for: \(keyboardSource.id)")
|
||||
print("keyboard created for: \(keyboardSource.id)")
|
||||
print("keyboard created for: \(keyboardSource.id) \r with kmxFileUrl: \(self.kmxFileUrl) \r and settingsKey: \(self.keyboardSettingsKey)")
|
||||
}
|
||||
|
||||
public static func == (lhs: Keyboard, rhs: Keyboard) -> Bool {
|
||||
return lhs.keyboardId == rhs.keyboardId && lhs.enabled == rhs.enabled
|
||||
}
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(keyboardId)
|
||||
}
|
||||
|
||||
static func deriveKmxFileUrl(from keyboardDirectory: URL, keyboardId: String) -> URL {
|
||||
return keyboardDirectory.appendingPathComponent("\(keyboardId).kmx")
|
||||
}
|
||||
|
||||
static func deriveKeyboardSettingsKey(from keyboardDirectory: URL, keyboardId: String) -> String {
|
||||
// get parent directory
|
||||
let parentDirectoryName = keyboardDirectory.lastPathComponent
|
||||
|
||||
// get filename from keyboardId
|
||||
let kmxFilename = "\(keyboardId).kmx"
|
||||
|
||||
let settingsKey = "/\(parentDirectoryName)/\(kmxFilename)"
|
||||
print("settingsKey: \(settingsKey)")
|
||||
|
||||
return settingsKey
|
||||
}
|
||||
|
||||
// TODO: throw/handle error if no kmx file found in directory
|
||||
public func validateKmxFile() -> Bool {
|
||||
let fileManager = FileManager.default
|
||||
if fileManager.fileExists(atPath: self.kmxFileUrl.path) {
|
||||
return true
|
||||
} else {
|
||||
print(" *** Error: could not find kmx file \(self.kmxFileUrl.path)")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public func findKmxFile(in keyboardDirectoryUrl: URL) -> URL? {
|
||||
var kmxFileUrl: URL? = nil
|
||||
let fileManager = FileManager.default
|
||||
|
||||
do {
|
||||
let fileURLs = try fileManager.contentsOfDirectory(at: keyboardDirectoryUrl, includingPropertiesForKeys: nil)
|
||||
let filteredFiles = fileURLs.filter { $0.pathExtension == "kmx" }
|
||||
|
||||
if (!filteredFiles.isEmpty) {
|
||||
kmxFileUrl = filteredFiles.first!
|
||||
}
|
||||
} catch {
|
||||
print("Error reading directory: \(error)")
|
||||
}
|
||||
|
||||
return kmxFileUrl;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* Created by Shawn Schantz on 2026-02-24
|
||||
*
|
||||
* Wrapper object that represents a Keyman package as loaded from a .KMP file
|
||||
* Can be loaded but disabled
|
||||
* Mostly immutable, but can be marked as enabled/disabled
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ import Foundation
|
|||
import AppKit
|
||||
|
||||
// MARK: - Root
|
||||
public struct KeymanPackage: Identifiable, Hashable, Equatable {
|
||||
public class KeymanPackage: Identifiable, Hashable, Equatable {
|
||||
static let defaultImage: NSImage? = {
|
||||
var image: NSImage? = nil
|
||||
if let imageUrl = Bundle.main.url(forResource: "SideImage", withExtension: "bmp") {
|
||||
|
|
@ -22,11 +22,12 @@ public struct KeymanPackage: Identifiable, Hashable, Equatable {
|
|||
}()
|
||||
|
||||
public var id = UUID()
|
||||
public var enabled: Bool
|
||||
let source: PackageSource
|
||||
public let keyboards: [Keyboard]
|
||||
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?
|
||||
|
|
@ -48,7 +49,6 @@ public struct KeymanPackage: Identifiable, Hashable, Equatable {
|
|||
}
|
||||
|
||||
init(packageSource: PackageSource) {
|
||||
self.enabled = true
|
||||
self.source = packageSource
|
||||
self.sourceDirectoryUrl = packageSource.directoryUrl!
|
||||
self.jsonFileUrl = packageSource.jsonFileUrl!
|
||||
|
|
@ -67,7 +67,7 @@ public struct KeymanPackage: Identifiable, Hashable, Equatable {
|
|||
|
||||
if let keyboards = source.keyboards {
|
||||
for keyboardSource in keyboards {
|
||||
let keyboard = Keyboard(keyboardSource: keyboardSource)
|
||||
let keyboard = Keyboard(keyboardSource: keyboardSource, directoryUrl: self.sourceDirectoryUrl)
|
||||
keyboardsArray.append(keyboard)
|
||||
}
|
||||
}
|
||||
|
|
@ -77,6 +77,34 @@ public struct KeymanPackage: Identifiable, Hashable, Equatable {
|
|||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,23 @@ public struct PackageRepository {
|
|||
self.pathUtil = KeymanPaths()
|
||||
}
|
||||
|
||||
func loadPackages() -> [KeymanPackage] {
|
||||
var installedPackages: [KeymanPackage] = []
|
||||
let packageSourceArray = self.readKeymanPackagesForKeyman19()
|
||||
|
||||
// create a KeymanPackage object for each PackageSource object and insert it in the array if it is valid
|
||||
for source in packageSourceArray {
|
||||
let package = KeymanPackage(packageSource: source)
|
||||
if (package.validate()) {
|
||||
installedPackages.append(package)
|
||||
} else {
|
||||
print("package '\(source.packageName)' is not valid")
|
||||
}
|
||||
}
|
||||
|
||||
return installedPackages
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the directory tree where keyboards are stored under the standard 'Group Containers' directory
|
||||
*/
|
||||
|
|
@ -44,6 +61,9 @@ public struct PackageRepository {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* for group container testing purposes to check directory access
|
||||
*/
|
||||
public func writeSomethingToContainer() {
|
||||
if let keyboardDirectory = self.pathUtil.keyman19KeyboardsDirectory {
|
||||
print("About to write to: \(keyboardDirectory.path)")
|
||||
|
|
@ -74,6 +94,9 @@ public struct PackageRepository {
|
|||
return self.directoryExistsAtPath(directoryUrl: keyboardsUrl)
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if a directory exists at the specified URL
|
||||
*/
|
||||
func directoryExistsAtPath(directoryUrl: URL) -> Bool {
|
||||
var isDirectory: ObjCBool = false
|
||||
let exists = FileManager.default.fileExists(atPath: directoryUrl.path, isDirectory: &isDirectory)
|
||||
|
|
@ -110,7 +133,7 @@ public struct PackageRepository {
|
|||
)
|
||||
|
||||
for itemUrl in directoryContents {
|
||||
// if the item is a directory, then attempt to read it as a keyboard
|
||||
// if the item is a directory, then attempt to read it as a keyboard package
|
||||
if (itemUrl.hasDirectoryPath) {
|
||||
if let packageSource = readKeyboardPackageFromDirectory(keyboardDirectoryUrl: itemUrl) {
|
||||
packages.append(packageSource)
|
||||
|
|
@ -124,27 +147,27 @@ public struct PackageRepository {
|
|||
print("\(packages.count) packages read")
|
||||
return packages
|
||||
}
|
||||
|
||||
|
||||
func readKeyboardPackageFromDirectory(keyboardDirectoryUrl: URL) -> PackageSource? {
|
||||
var packageSource: PackageSource?
|
||||
|
||||
let lastPathComponent = keyboardDirectoryUrl.lastPathComponent
|
||||
let kmpFileUrl = keyboardDirectoryUrl.appendingPathComponent(packageFileName)
|
||||
|
||||
if FileManager.default.fileExists(atPath: kmpFileUrl.path) {
|
||||
if let source = readKeyboardPackage(kmpFileUrl) {
|
||||
packageSource = source
|
||||
// save the keyboard directory and path of the kmp.json for this keyboard
|
||||
packageSource?.directoryUrl = keyboardDirectoryUrl
|
||||
packageSource?.jsonFileUrl = kmpFileUrl
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ConfigLogger.shared.testLogger.debug(" ** \(lastPathComponent) DOES NOT contain the file 'kmp.json')")
|
||||
// ConfigLogger.shared.testLogger.debug(" ** \(lastPathComponent) DOES NOT contain the file 'kmp.json')")
|
||||
print(" ** \(lastPathComponent) DOES NOT contain the file 'kmp.json')")
|
||||
}
|
||||
|
||||
return packageSource
|
||||
}
|
||||
|
||||
|
||||
public func readKeyboardPackage(_ kmpFileUrl: URL) -> PackageSource? {
|
||||
var packageSource: PackageSource?
|
||||
do {
|
||||
|
|
|
|||
|
|
@ -8,9 +8,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum UserDefaultsError: Error {
|
||||
case unknownSuite
|
||||
}
|
||||
|
||||
public struct SettingsRepository {
|
||||
fileprivate let pathUtil: KeymanPaths
|
||||
let defaultsSuiteName: String
|
||||
|
|
@ -19,7 +22,8 @@ public struct SettingsRepository {
|
|||
let kActiveKeyboardsKey = "KMActiveKeyboardsKey"
|
||||
let kSelectedKeyboardKey = "KMSelectedKeyboardKey"
|
||||
let kPersistedOptionsKey = "KMPersistedOptionsKey"
|
||||
let kShowOskOnActivate = "KMShowOskOnActivate"
|
||||
let kDataModelVersionKey = "KMDataModelVersionKey"
|
||||
let kShowOskOnActivateKey = "KMShowOskOnActivate"
|
||||
let kForceSentryError = "KMForceSentryError"
|
||||
|
||||
// public init() {
|
||||
|
|
@ -27,10 +31,16 @@ public struct SettingsRepository {
|
|||
// self.defaultsSuiteName = KeymanPaths.groupId
|
||||
// }
|
||||
//
|
||||
public init(suiteName: String) {
|
||||
public init(suiteName: String) throws(Error) {
|
||||
self.pathUtil = KeymanPaths()
|
||||
self.defaultsSuiteName = suiteName
|
||||
self.defaults = UserDefaults(suiteName: suiteName)
|
||||
|
||||
let userDefaults = UserDefaults(suiteName: suiteName)
|
||||
if userDefaults == nil {
|
||||
throw(UserDefaultsError.unknownSuite)
|
||||
} else {
|
||||
self.defaults = userDefaults
|
||||
}
|
||||
}
|
||||
|
||||
public func readActiveKeyboards() -> Set<String> {
|
||||
|
|
@ -46,13 +56,16 @@ public struct SettingsRepository {
|
|||
}
|
||||
|
||||
public func readSelectedKeyboard() -> String {
|
||||
guard let sharedDefaults = self.defaults else {
|
||||
print("Group container UserDefaults not found.")
|
||||
if let sharedDefaults = self.defaults {
|
||||
return sharedDefaults.value(forKey: kSelectedKeyboardKey) as? String ?? ""
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
|
||||
let selectedKeyboard = sharedDefaults.value(forKey: kSelectedKeyboardKey) as? String ?? ""
|
||||
|
||||
return selectedKeyboard
|
||||
}
|
||||
|
||||
public func writeSelectedKeyboard(keyboardName: String) {
|
||||
if let sharedDefaults = self.defaults {
|
||||
sharedDefaults.set(keyboardName, forKey: kSelectedKeyboardKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,8 +50,36 @@ import Foundation
|
|||
}
|
||||
}
|
||||
|
||||
// defaults read test.suite.name
|
||||
|
||||
@Suite("Load KMP data") struct KeymanDataRepositoryTests {
|
||||
@Suite("Settings check") struct KeymanSettingsRepositoryTests {
|
||||
var settingsRepo: SettingsRepository
|
||||
|
||||
fileprivate init() async throws {
|
||||
print("init Settings")
|
||||
do {
|
||||
try self.settingsRepo = SettingsRepository(suiteName: "test.suite.name")
|
||||
print("Found group container")
|
||||
} catch UserDefaultsError.unknownSuite {
|
||||
fatalError("Group container not found.")
|
||||
} catch {
|
||||
fatalError("Unable to access settings in group container.")
|
||||
}
|
||||
|
||||
self.settingsRepo.writeSelectedKeyboard(keyboardName: "keyboardtest")
|
||||
}
|
||||
|
||||
@Test("Write selected keyboard") func writeSelectedKeyboard() async throws {
|
||||
settingsRepo.writeSelectedKeyboard(keyboardName: "testing")
|
||||
#expect(settingsRepo.readSelectedKeyboard() == "testing")
|
||||
}
|
||||
|
||||
@Test("Read selected keyboard") func readSelectedKeyboard() async throws {
|
||||
#expect(settingsRepo.readSelectedKeyboard() == "keyboardtest")
|
||||
}
|
||||
}
|
||||
|
||||
@Suite("Load KMP data") struct KeymanPackageRepositoryTests {
|
||||
var testKmpUrl: URL? = nil
|
||||
|
||||
fileprivate init() async throws {
|
||||
|
|
@ -62,11 +90,6 @@ import Foundation
|
|||
return Bundle.module.url(forResource: "amharic.kmp", withExtension: "json")
|
||||
}
|
||||
|
||||
@Test("Find amharic .kmp file") func locateKmpTestData() async throws {
|
||||
let kmpUrl = try #require(self.getAmharicKmpUrl())
|
||||
#expect(kmpUrl.isFileURL)
|
||||
}
|
||||
|
||||
@Test("Read package") func loadPackageSource() async throws {
|
||||
let dataRepo = PackageRepository()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue