From 1e805949ae762b49f8d96dc340f916b59174d4f2 Mon Sep 17 00:00:00 2001 From: sgschantz Date: Fri, 9 Aug 2024 14:49:37 +0700 Subject: [PATCH 1/6] change(mac): store partial path in UserDefaults --- .../Keyman4MacIM/KMDataRepository.h | 1 + .../Keyman4MacIM/KMDataRepository.m | 7 ++- .../Keyman4MacIM/KMSettingsRepository.m | 44 ++++++++++++++----- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMDataRepository.h b/mac/Keyman4MacIM/Keyman4MacIM/KMDataRepository.h index a5af2ccb88..766e9c10e9 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMDataRepository.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMDataRepository.h @@ -20,6 +20,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)createDataDirectoryIfNecessary; - (void)createKeyboardsDirectoryIfNecessary; - (BOOL)migrateData; +- (NSString*)buildFullPathWith:(NSString *)partialPath; @end NS_ASSUME_NONNULL_END diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMDataRepository.m b/mac/Keyman4MacIM/Keyman4MacIM/KMDataRepository.m index 24495007bd..0b3b8023e6 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMDataRepository.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMDataRepository.m @@ -164,7 +164,7 @@ NSString *const kKeymanSubdirectoryName = @"keyman.inputmethod.Keyman"; BOOL didMoveData = NO; NSFileManager *fileManager = [NSFileManager defaultManager]; BOOL dataExistsInOldLocation = [self keyboardsExistInObsoleteDirectory]; - os_log([KMLogs dataLog], "obsolete keyman keyboards directory exists: %@", dataExistsInOldLocation?@"YES":@"NO"); + os_log_debug([KMLogs dataLog], "obsolete keyman keyboards directory exists: %@", dataExistsInOldLocation?@"YES":@"NO"); // only move data if there is something to move if (dataExistsInOldLocation) { @@ -182,4 +182,9 @@ NSString *const kKeymanSubdirectoryName = @"keyman.inputmethod.Keyman"; return didMoveData; } +- (NSString*)buildFullPathWith:(NSString *)partialPath { + NSString *fullPath = [self.keymanKeyboardsDirectory.path stringByAppendingString:partialPath]; + os_log_debug([KMLogs dataLog], "createFullPathWith: '%{public}@' with partialPath '%{public}@'", self.keymanKeyboardsDirectory.path, partialPath); + return fullPath; +} @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m index 489c4e63dc..3109770067 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m @@ -12,12 +12,14 @@ #import "KMSettingsRepository.h" #import "KMLogs.h" +#import "KMDataRepository.h" NSString *const kActiveKeyboardsKey = @"KMActiveKeyboardsKey"; NSString *const kSelectedKeyboardKey = @"KMSelectedKeyboardKey"; NSString *const kPersistedOptionsKey = @"KMPersistedOptionsKey"; -NSString *const kObsoletePathComponent = @"/Documents/"; +//NSString *const kObsoletePathComponent = @"/Documents/"; +NSString *const kObsoletePathComponent = @"/Documents/Keyman-Keyboards"; NSString *const kNewPathComponent = @"/Library/Application Support/keyman.inputmethod.Keyman/"; /** @@ -53,7 +55,7 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; */ - (BOOL)settingsExist { - return [[NSUserDefaults standardUserDefaults] objectForKey:kSelectedKeyboardKey] != nil; + return ([[NSUserDefaults standardUserDefaults] objectForKey:kSelectedKeyboardKey] != nil); } /** @@ -122,13 +124,13 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; - (void)convertSelectedKeyboardPathForMigration { NSString *selectedKeyboardPath = [self selectedKeyboard]; - if (selectedKeyboardPath != nil) { - NSString *newPathString = [self convertOldKeyboardPath:selectedKeyboardPath]; + NSString *newPathString = [self trimObsoleteKeyboardPath:selectedKeyboardPath]; if ([selectedKeyboardPath isNotEqualTo:newPathString]) { [self saveSelectedKeyboard:newPathString]; - os_log([KMLogs dataLog], "converted selected keyboard setting from '%{public}@' to '%{public}@'", selectedKeyboardPath, newPathString); + os_log_debug([KMLogs dataLog], "converted selected keyboard setting from '%{public}@' to '%{public}@'", selectedKeyboardPath, newPathString); + os_log_debug([KMLogs dataLog], "full path of selected keyboard from buildFullPathWith = '%{public}@'", [KMDataRepository.shared buildFullPathWith:newPathString]); } } } @@ -137,7 +139,7 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; * Convert the path of the keyboard designating the Documents folder to its new location * in the Application Support folder */ - +/* - (NSString *)convertOldKeyboardPath:(NSString *)oldPath { NSString *newPathString = @""; if(oldPath != nil) { @@ -145,18 +147,36 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; } return newPathString; } +*/ + +/** + * To convert the keyboard path for the new location, just trim the parent directory from the path + * No need to repeatedly store the parent directory with the path of each keyboard + * If the old directory is not found in the string, then return the string unchanged + */ +- (NSString *)trimObsoleteKeyboardPath:(NSString *)oldPath { + NSString *newPath = oldPath; + if(oldPath != nil) { + NSRange range = [oldPath rangeOfString:kObsoletePathComponent]; + if (range.length > 0) { + newPath = [oldPath substringFromIndex:range.location + range.length]; + os_log_debug([KMLogs dataLog], "trimmed keyboard path from '%{public}@' to '%{public}@'", oldPath, newPath); + } + } + return newPath; +} - (void)convertActiveKeyboardArrayForMigration { NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - NSMutableArray *activeKeyboards = [self activeKeyboards]; + NSMutableArray *keyboards = [self activeKeyboards]; NSMutableArray *convertedActiveKeyboards = [[NSMutableArray alloc] initWithCapacity:0]; BOOL didConvert = NO; - for (NSString *oldPath in activeKeyboards) { - NSString *newPath = [self convertOldKeyboardPath:oldPath]; + for (NSString *oldPath in keyboards) { + NSString *newPath = [self trimObsoleteKeyboardPath:oldPath]; if ([oldPath isNotEqualTo:newPath]) { [convertedActiveKeyboards addObject:newPath]; - os_log([KMLogs dataLog], "converted active keyboard from old path '%{public}@' to '%{public}@'", oldPath, newPath); + os_log_debug([KMLogs dataLog], "converted active keyboard from old path '%{public}@' to '%{public}@'", oldPath, newPath); // if we have adjusted at least one path, set flag didConvert = YES; } else { @@ -183,7 +203,7 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; os_log_info([KMLogs configLog], "persisted options found in UserDefaults with key = %{public}@", key); } for (NSString *key in optionsMap) { - NSString *newPathString = [self convertOldKeyboardPath:key]; + NSString *newPathString = [self trimObsoleteKeyboardPath:key]; NSDictionary *optionsValue = [optionsMap objectForKey:key]; if ([key isNotEqualTo:newPathString]) { @@ -191,7 +211,7 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; // insert options into new map with newly converted path as key [mutableOptionsMap setObject:optionsValue forKey:newPathString]; - os_log([KMLogs dataLog], "converted option key from '%{public}@' to '%{public}@'", key, newPathString); + os_log_debug([KMLogs dataLog], "converted option key from '%{public}@' to '%{public}@'", key, newPathString); } else { // retain options that did not need converting [mutableOptionsMap setObject:optionsValue forKey:key]; From b1685f5865e5be975843c92748ad56fdb73e2af5 Mon Sep 17 00:00:00 2001 From: sgschantz Date: Thu, 15 Aug 2024 15:41:38 +0700 Subject: [PATCH 2/6] change(mac): use partial paths in settings converts partial paths to full paths as needed and vice-versa when moving between file system access and referencing keyboards in UserDefaults --- .../KMConfigurationWindowController.m | 25 +++-- .../Keyman4MacIM/KMDataRepository.h | 4 +- .../Keyman4MacIM/KMDataRepository.m | 32 +++++- .../Keyman4MacIM/KMInputMethodAppDelegate.m | 100 +++++++++++------- .../Keyman4MacIM/KMSettingsRepository.m | 1 - 5 files changed, 111 insertions(+), 51 deletions(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m index 3e2ffe2410..efafbed11a 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m @@ -8,6 +8,7 @@ #import "KMConfigurationWindowController.h" #import "KMDownloadKBWindowController.h" +#import "KMDataRepository.h" #import "KMLogs.h" @interface KMConfigurationWindowController () @@ -134,8 +135,10 @@ NSArray *pArray = (NSArray *)obj; NSString *packageFolder = [self packageFolderFromPath:[pArray objectAtIndex:0]]; NSString *packageName = [self.AppDelegate packageNameFromPackageInfo:packageFolder]; + os_log_debug([KMLogs uiLog], "tableContents, packageFolder: %{public}@, packageName: %{public}@", packageFolder, packageName); [_tableContents addObject:[NSDictionary dictionaryWithObjectsAndKeys:packageName, @"HeaderTitle", nil]]; for (NSString *path in pArray) { + os_log_debug([KMLogs uiLog], "tableContents, path = '%{public}@'", path); NSDictionary *info = [KMXFile keyboardInfoFromKmxFile:path]; if (!info) { info = [[NSDictionary alloc] initWithObjectsAndKeys: @@ -150,6 +153,7 @@ } else { NSString *path = (NSString *)obj; + os_log_debug([KMLogs uiLog], "tableContents, path = '%{public}@'", path); NSDictionary *info = [KMXFile keyboardInfoFromKmxFile:path]; if (!info) { info = [[NSDictionary alloc] initWithObjectsAndKeys: @@ -241,22 +245,27 @@ BOOL isHeader = (headerTitle != nil); BOOL isOthers = NO; NSString *kmxFilePath = [self kmxFilePathAtIndex:row]; - if (kmxFilePath != nil) + if (kmxFilePath != nil) { isOthers = [[self packageFolderFromPath:kmxFilePath] isEqualToString:@"Others"]; - else if (isHeader && [headerTitle isEqualToString:@"Others"]) + } + else if (isHeader && [headerTitle isEqualToString:@"Others"]) { isOthers = YES; - + } if ([identifier isEqualToString:@"Column1"]) { KMConfigColumn1CellView *cellView = [tableView makeViewWithIdentifier:identifier owner:self]; - if (isHeader) + if (isHeader) { [cellView setHidden:YES]; + } else { [cellView setHidden:NO]; cellView.imageView.objectValue = [info objectForKey:kKMKeyboardIconKey]; [cellView.checkBox setTag:row]; [cellView.checkBox setAction:@selector(checkBoxAction:)]; - [cellView.checkBox setState:([self.activeKeyboards containsObject:[self kmxFilePathAtIndex:row]])?NSOnState:NSOffState]; + NSString *kmxFilePath = [self kmxFilePathAtIndex:row]; + NSString *partialPath = [KMDataRepository.shared trimToPartialPath:kmxFilePath]; + os_log_debug([KMLogs uiLog], "tableView:viewForTableColumn, kmxFilePath = %{public}@ for row %li, partialPath = %{public}@", kmxFilePath, (long)row, partialPath); + [cellView.checkBox setState:([self.activeKeyboards containsObject:partialPath])?NSOnState:NSOffState]; } return cellView; @@ -357,14 +366,16 @@ - (void)checkBoxAction:(id)sender { NSButton *checkBox = (NSButton *)sender; NSString *kmxFilePath = [self kmxFilePathAtIndex:checkBox.tag]; + NSString *partialPath = [KMDataRepository.shared trimToPartialPath:kmxFilePath]; + os_log_debug([KMLogs uiLog], "checkBoxAction, kmxFilePath = %{public}@ for checkBox.tag %li, partialPath = %{public}@", kmxFilePath, checkBox.tag, partialPath); if (checkBox.state == NSOnState) { os_log_debug([KMLogs uiLog], "Adding active keyboard: %{public}@", kmxFilePath); - [self.activeKeyboards addObject:kmxFilePath]; + [self.activeKeyboards addObject:partialPath]; [self saveActiveKeyboards]; } else if (checkBox.state == NSOffState) { os_log_debug([KMLogs uiLog], "Disabling active keyboard: %{public}@", kmxFilePath); - [self.activeKeyboards removeObject:kmxFilePath]; + [self.activeKeyboards removeObject:partialPath]; [self saveActiveKeyboards]; } } diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMDataRepository.h b/mac/Keyman4MacIM/Keyman4MacIM/KMDataRepository.h index 766e9c10e9..8f38c282fa 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMDataRepository.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMDataRepository.h @@ -20,7 +20,9 @@ NS_ASSUME_NONNULL_BEGIN - (void)createDataDirectoryIfNecessary; - (void)createKeyboardsDirectoryIfNecessary; - (BOOL)migrateData; -- (NSString*)buildFullPathWith:(NSString *)partialPath; +- (NSString*)buildFullPath:(NSString *)fromPartialPath; +- (NSString*)trimToPartialPath:(NSString *)fromFullPath; +- (NSString *)buildPartialPathFrom:(NSString *)keyboardSubdirectory keyboardFile:(NSString *)kmxFilename; @end NS_ASSUME_NONNULL_END diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMDataRepository.m b/mac/Keyman4MacIM/Keyman4MacIM/KMDataRepository.m index 0b3b8023e6..59bac96bb4 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMDataRepository.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMDataRepository.m @@ -182,9 +182,35 @@ NSString *const kKeymanSubdirectoryName = @"keyman.inputmethod.Keyman"; return didMoveData; } -- (NSString*)buildFullPathWith:(NSString *)partialPath { - NSString *fullPath = [self.keymanKeyboardsDirectory.path stringByAppendingString:partialPath]; - os_log_debug([KMLogs dataLog], "createFullPathWith: '%{public}@' with partialPath '%{public}@'", self.keymanKeyboardsDirectory.path, partialPath); +- (NSString*)buildFullPath:(NSString *)fromPartialPath { + NSString *fullPath = [self.keymanKeyboardsDirectory.path stringByAppendingString:fromPartialPath]; + os_log_debug([KMLogs dataLog], "buildFullPath: '%{public}@' fromPartialPath '%{public}@'", + fullPath, fromPartialPath); return fullPath; } + +- (NSString *)trimToPartialPath:(NSString *)fromFullPath { + NSString *partialPath = fromFullPath; + if(fromFullPath != nil) { + NSRange range = [fromFullPath rangeOfString:kKeyboardsDirectoryName]; + if (range.length > 0) { + partialPath = [fromFullPath substringFromIndex:range.location + range.length]; + os_log_debug([KMLogs dataLog], "trimToPartialPath: fromFullPath: '%{public}@' to partialPath: '%{public}@'", fromFullPath, partialPath); + } + } + return partialPath; +} + +- (NSString *)buildPartialPathFrom:(NSString *)keyboardSubdirectory keyboardFile:(NSString *)kmxFilename { + NSMutableArray *pathComponents = [[NSMutableArray alloc] initWithCapacity:0]; + [pathComponents addObject:@"/"]; + [pathComponents addObject:keyboardSubdirectory]; + [pathComponents addObject:kmxFilename]; + NSString *keyboardPartialPath = [NSString pathWithComponents:pathComponents]; + os_log_debug([KMLogs keyboardLog], "buildPartialPathFrom, keyboardSubdirectory: %{public}@, kmxFileName: %{public}@, keyboardPartialPath : %{public}@", + keyboardSubdirectory, kmxFilename, keyboardPartialPath); + return keyboardPartialPath; +} + + @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m index 845e1f2140..947bb803f1 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m @@ -169,12 +169,9 @@ id _lastServerWithOSKShowing = nil; [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"NSApplicationCrashOnExceptions": @YES }]; [KMLogs reportLogStatus]; - [self startSentry]; - [self setDefaultKeymanMenuItems]; [self updateKeyboardMenuItems]; - [self setPostLaunchKeymanSentryTags]; // [SentrySDK captureMessage:@"Starting Keyman [test message]"]; } @@ -544,12 +541,13 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } - (NSArray *)kmxFileList { - os_log_debug([KMLogs dataLog], "kmxFileList"); if (_kmxFileList == nil) { - NSArray *kmxFiles = [self KMXFiles]; + os_log_debug([KMLogs dataLog], "creating kmxFileList"); + NSArray *kmxFiles = [self getKmxFilesInKeyboardsDirectory]; _kmxFileList = [[NSMutableArray alloc] initWithCapacity:0]; NSMutableArray *others = nil; for (NSString *filePath in kmxFiles) { + os_log_debug([KMLogs dataLog], "kmxFileList, filePath: %{public}@", filePath); NSString *packageFolder = [self packageFolderFromPath:filePath]; NSInteger index = [self indexForPackageFolder:packageFolder]; if ([packageFolder isEqualToString:@"Others"]) { @@ -666,7 +664,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef - (NSArray *)keyboardNamesFromFolder:(NSString *)packageFolder { os_log_debug([KMLogs dataLog], "keyboardNamesFromFolder, folder = %{public}@", packageFolder); NSMutableArray *kbNames = [[NSMutableArray alloc] initWithCapacity:0];; - for (NSString *kmxFile in [self KMXFilesAtPath:packageFolder]) { + for (NSString *kmxFile in [self getKmxFilesAtPath:packageFolder]) { NSDictionary * infoDict = [KMXFile keyboardInfoFromKmxFile:kmxFile]; if (infoDict != nil) { NSString *name = [infoDict objectForKey:kKMKeyboardNameKey]; @@ -684,7 +682,8 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; _selectedKeyboard = [userData objectForKey:kKMSelectedKeyboardKey]; } - + os_log_debug([KMLogs dataLog], "selectedKeyboard = %{public}@", _selectedKeyboard); + return _selectedKeyboard; } @@ -697,16 +696,20 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef - (NSMutableArray *)activeKeyboards { if (!_activeKeyboards) { + os_log_debug([KMLogs dataLog], "initializing activeKeyboards"); NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; _activeKeyboards = [[userData arrayForKey:kKMActiveKeyboardsKey] mutableCopy]; - if (!_activeKeyboards) - _activeKeyboards = [[NSMutableArray alloc] initWithCapacity:0]; + if (!_activeKeyboards) { + os_log_debug([KMLogs dataLog], "KMActiveKeyboardsKey key not found in NSUserDefualts"); + _activeKeyboards = [[NSMutableArray alloc] initWithCapacity:0]; + } } - + return _activeKeyboards; } - (void)saveActiveKeyboards { + os_log_debug([KMLogs dataLog], "saveActiveKeyboards, entering"); NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; [userData setObject:_activeKeyboards forKey:kKMActiveKeyboardsKey]; [userData synchronize]; @@ -725,8 +728,12 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef // Remove entries with missing files NSMutableArray *pathsToRemove = [[NSMutableArray alloc] initWithCapacity:0]; for (NSString *path in self.activeKeyboards) { - if (![[NSFileManager defaultManager] fileExistsAtPath:path]) + NSString *fullPath = [KMDataRepository.shared buildFullPath:path]; + os_log_debug([KMLogs dataLog], "resetActiveKeyboards, checking fullPath: '%{public}@' for path: '%{public}@'", fullPath, path); + if (![[NSFileManager defaultManager] fileExistsAtPath:fullPath]) { + os_log_debug([KMLogs dataLog], "resetActiveKeyboards, need to remove non-existent path: %{public}@", fullPath); [pathsToRemove addObject:path]; + } } BOOL found = FALSE; @@ -814,6 +821,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } - (int)calculateNumberOfKeyboardMenuItems { + os_log_debug([KMLogs uiLog], "calculateNumberOfKeyboardMenuItems, entered"); if (self.activeKeyboards.count == 0) { // if there are no active keyboards, then we will insert one placeholder menu item 'No Active Keyboards' return 1; @@ -835,6 +843,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } - (void)addDynamicKeyboardMenuItems { + os_log_debug([KMLogs startupLog], "addDynamicKeyboardMenuItems, entered"); BOOL didSetSelectedKeyboard = NO; NSInteger itag = KEYMAN_FIRST_KEYBOARD_MENUITEM_TAG; NSString *keyboardMenuName = @""; @@ -846,7 +855,9 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef // loop through the active keyboards list and add them to the menu for (NSString *path in self.activeKeyboards) { - NSDictionary *infoDict = [KMXFile keyboardInfoFromKmxFile:path]; + NSString *fullPath = [KMDataRepository.shared buildFullPath:path]; + os_log_debug([KMLogs dataLog], "addDynamicKeyboardMenuItems, path = '%{public}@', full path = '%{public}@'", path, fullPath); + NSDictionary *infoDict = [KMXFile keyboardInfoFromKmxFile:fullPath]; if (!infoDict) { continue; } @@ -876,10 +887,12 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef - (void) setSelectedKeyboard:(NSString*)keyboardName inMenuItem:(NSMenuItem*) menuItem { KVKFile *kvk = nil; + NSString *fullPath = [KMDataRepository.shared buildFullPath:keyboardName]; + os_log_debug([KMLogs dataLog], "setSelectedKeyboard, keyboardName = '%{public}@', full path = '%{public}@'", keyboardName, fullPath); [menuItem setState:NSOnState]; - KMXFile *kmx = [[KMXFile alloc] initWithFilePath:keyboardName]; + KMXFile *kmx = [[KMXFile alloc] initWithFilePath:fullPath]; [self setKmx:kmx]; - NSDictionary *kmxInfo = [KMXFile keyboardInfoFromKmxFile:keyboardName]; + NSDictionary *kmxInfo = [KMXFile keyboardInfoFromKmxFile:fullPath]; NSString *kvkFilename = [kmxInfo objectForKey:kKMVisualKeyboardKey]; if (kvkFilename != nil) { NSString *kvkFilePath = [self kvkFilePathFromFilename:kvkFilename]; @@ -931,10 +944,13 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } NSString *path = [self.activeKeyboards objectAtIndex:tag-KEYMAN_FIRST_KEYBOARD_MENUITEM_TAG]; - KMXFile *kmx = [[KMXFile alloc] initWithFilePath:path]; + NSString *fullPath = [KMDataRepository.shared buildFullPath:path]; + os_log_debug([KMLogs dataLog], "setSelectedKeyboard, keyboardName = '%{public}@', full path = '%{public}@'", path, fullPath); + + KMXFile *kmx = [[KMXFile alloc] initWithFilePath:fullPath]; [self setKmx:kmx]; KVKFile *kvk = nil; - NSDictionary *kmxInfo = [KMXFile keyboardInfoFromKmxFile:path]; + NSDictionary *kmxInfo = [KMXFile keyboardInfoFromKmxFile:fullPath]; NSString *kvkFilename = [kmxInfo objectForKey:kKMVisualKeyboardKey]; if (kvkFilename != nil) { NSString *kvkFilePath = [self kvkFilePathFromFilename:kvkFilename]; @@ -953,12 +969,12 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef [self showOSK]; } -- (NSArray *)KMXFiles { - return [self KMXFilesAtPath:self.keyboardsPath]; +- (NSArray *)getKmxFilesInKeyboardsDirectory { + return [self getKmxFilesAtPath:self.keyboardsPath]; } -- (NSArray *)KMXFilesAtPath:(NSString *)path { - os_log_debug([KMLogs dataLog], "Reading KMXFiles at path %{public}@", path); +- (NSArray *)getKmxFilesAtPath:(NSString *)path { + os_log_debug([KMLogs dataLog], "getKmxFilesAtPath, path: '%{public}@'", path); NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:path]; NSMutableArray *kmxFiles = [[NSMutableArray alloc] initWithCapacity:0]; NSString *filePath; @@ -973,23 +989,23 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef return kmxFiles; } -- (NSArray *)KVKFiles { +- (NSArray *)getKvkFilesArray { NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:self.keyboardsPath]; - NSMutableArray *kvkFiles = [[NSMutableArray alloc] initWithCapacity:0]; + NSMutableArray *kvkFilesArray = [[NSMutableArray alloc] initWithCapacity:0]; NSString *filePath; while (filePath = (NSString *)[dirEnum nextObject]) { NSString *extension = [[filePath pathExtension] lowercaseString]; if ([extension isEqualToString:@"kvk"]) - [kvkFiles addObject:[self.keyboardsPath stringByAppendingPathComponent:filePath]]; + [kvkFilesArray addObject:[self.keyboardsPath stringByAppendingPathComponent:filePath]]; } - return kvkFiles; + return kvkFilesArray; } - (NSString *)kvkFilePathFromFilename:(NSString *)kvkFilename { NSString *kvkFilePath = nil; - NSArray *kvkFiles = [self KVKFiles]; - for (NSString *filePath in kvkFiles) { + NSArray *kvkFilesArray = [self getKvkFilesArray]; + for (NSString *filePath in kvkFilesArray) { if ([[filePath lastPathComponent] isEqualToString:kvkFilename]) { kvkFilePath = filePath; break; @@ -1338,7 +1354,8 @@ extern const CGKeyCode kProcessPendingBuffer; NSError *error = nil; NSString *fileName = filePath.lastPathComponent; NSString *folderName = [fileName stringByDeletingPathExtension]; - + os_log_debug([KMLogs keyboardLog], "unzipFile, folderName: %{public}@, fileName: %{public}@", folderName, fileName); + // First we unzip into a temp folder, and check kmp.json for the fileVersion // before we continue installation. We don't want to overwrite existing // package if it is there if the files are not compatible with the installed @@ -1349,9 +1366,9 @@ extern const CGKeyCode kProcessPendingBuffer; ZipArchive *za = [[ZipArchive alloc] init]; if ([za UnzipOpenFile:filePath]) { - os_log_debug([KMLogs keyboardLog], "Unzipping %{public}@ to %{public}@", filePath, tempDestFolder); + os_log_debug([KMLogs keyboardLog], "unzipFile, Unzipping %{public}@ to %{public}@", filePath, tempDestFolder); if ([[NSFileManager defaultManager] fileExistsAtPath:tempDestFolder]) { - os_log_debug([KMLogs keyboardLog], "The temp destination folder already exists. Overwriting..."); + os_log_debug([KMLogs keyboardLog], "unzipFile, The temp destination folder already exists. Overwriting..."); } didUnzip = [za UnzipFileTo:tempDestFolder overWrite:YES]; @@ -1359,11 +1376,11 @@ extern const CGKeyCode kProcessPendingBuffer; } if (!didUnzip) { - os_log_error([KMLogs keyboardLog], "Failed to unzip file: %{public}@", filePath); + os_log_error([KMLogs keyboardLog], "unzipFile, Failed to unzip file: %{public}@", filePath); return NO; } - os_log_debug([KMLogs keyboardLog], "Unzipped file: %{public}@", filePath); + os_log_debug([KMLogs keyboardLog], "unzipFile, Unzipped file: %{public}@", filePath); BOOL didInstall = [self verifyPackageVersionInTempFolder:tempDestFolder filePath:filePath]; @@ -1371,10 +1388,10 @@ extern const CGKeyCode kProcessPendingBuffer; // Remove existing package if it exists if (didInstall && [[NSFileManager defaultManager] fileExistsAtPath:destFolder]) { - os_log_debug([KMLogs keyboardLog], "The destination folder already exists. Overwriting..."); + os_log_debug([KMLogs keyboardLog], "unzipFile, The destination folder already exists. Overwriting..."); [[NSFileManager defaultManager] removeItemAtPath:destFolder error:&error]; if (error != nil) { - os_log_error([KMLogs keyboardLog], "Unable to remove destination folder %{public}@", destFolder); + os_log_error([KMLogs keyboardLog], "unzipFile, Unable to remove destination folder %{public}@", destFolder); didInstall = NO; } } @@ -1387,7 +1404,7 @@ extern const CGKeyCode kProcessPendingBuffer; if(didInstall) { [[NSFileManager defaultManager] moveItemAtPath:tempDestFolder toPath:destFolder error:&error]; if (error != nil) { - os_log_error([KMLogs keyboardLog], "Unable to move temp folder %{public}@ to dest folder %{public}@", tempDestFolder, destFolder); + os_log_error([KMLogs keyboardLog], "unzipFile, Unable to move temp folder %{public}@ to dest folder %{public}@", tempDestFolder, destFolder); didInstall = NO; } } @@ -1395,7 +1412,7 @@ extern const CGKeyCode kProcessPendingBuffer; if(!didInstall) { [[NSFileManager defaultManager] removeItemAtPath:tempDestFolder error:&error]; if (error != nil) { - os_log_error([KMLogs keyboardLog], "Unable to remove temp folder %{public}@", tempDestFolder); + os_log_error([KMLogs keyboardLog], "unzipFile, Unable to remove temp folder %{public}@", tempDestFolder); } return NO; @@ -1404,11 +1421,16 @@ extern const CGKeyCode kProcessPendingBuffer; // Package has installed, now scan for keyboards and fonts // TODO: we need to be reading the kmp.json data to determine keyboards to install NSString * keyboardFolderPath = [self.keyboardsPath stringByAppendingPathComponent:folderName]; + os_log_debug([KMLogs keyboardLog], "unzipFile, folderName: %{public}@, keyboardFolderPath: %{public}@", folderName, keyboardFolderPath); [self installFontsAtPath:keyboardFolderPath]; - for (NSString *kmxFile in [self KMXFilesAtPath:keyboardFolderPath]) { - os_log_debug([KMLogs keyboardLog], "Adding keyboard to list of active keyboards: %{public}@", kmxFile); - if (![self.activeKeyboards containsObject:kmxFile]) - [self.activeKeyboards addObject:kmxFile]; + + for (NSString *kmxFile in [self getKmxFilesAtPath:keyboardFolderPath]) { + NSString *partialPath = [KMDataRepository.shared buildPartialPathFrom:folderName keyboardFile:[kmxFile lastPathComponent]]; + // TODO: encapsulate this in KMSettingsRepository, insertIfNotExists + if (![self.activeKeyboards containsObject:partialPath]) { + os_log_debug([KMLogs keyboardLog], "unzipFile, adding keyboard to list of active keyboards: %{public}@", partialPath); + [self.activeKeyboards addObject:partialPath]; + } } [self saveActiveKeyboards]; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m index 3109770067..54c779c00d 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m @@ -130,7 +130,6 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; if ([selectedKeyboardPath isNotEqualTo:newPathString]) { [self saveSelectedKeyboard:newPathString]; os_log_debug([KMLogs dataLog], "converted selected keyboard setting from '%{public}@' to '%{public}@'", selectedKeyboardPath, newPathString); - os_log_debug([KMLogs dataLog], "full path of selected keyboard from buildFullPathWith = '%{public}@'", [KMDataRepository.shared buildFullPathWith:newPathString]); } } } From 5364a741dadd7a75bb5137c08110bd9664113753 Mon Sep 17 00:00:00 2001 From: sgschantz Date: Fri, 16 Aug 2024 16:34:19 +0700 Subject: [PATCH 3/6] change(mac): some refactoring Mostly taking advantage of KMSettingsRepository so that more of the UserDefaults changes happen through it Still some refactoring remains for active keyboards list --- .../Keyman4MacIM/KMInputMethodAppDelegate.h | 3 +- .../Keyman4MacIM/KMInputMethodAppDelegate.m | 98 +++------------ .../Keyman4MacIM/KMInputMethodEventHandler.m | 2 +- .../Keyman4MacIM/KMPackageReader.h | 2 - .../Keyman4MacIM/KMPackageReader.m | 3 - .../Keyman4MacIM/KMSettingsRepository.h | 8 ++ .../Keyman4MacIM/KMSettingsRepository.m | 115 ++++++++++++++---- 7 files changed, 114 insertions(+), 117 deletions(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h index 7eddf31cb5..376e531f7f 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h @@ -23,7 +23,6 @@ typedef void(^PostEventCallback)(CGEventRef eventToPost); -extern NSString *const kKMSelectedKeyboardKey; extern NSString *const kKMActiveKeyboardsKey; extern NSString *const kKeymanKeyboardDownloadCompletedNotification; @@ -99,7 +98,7 @@ static const int KEYMAN_FIRST_KEYBOARD_MENUITEM_INDEX = 0; - (NSMenu *)menu; - (void)saveActiveKeyboards; -- (void)readPersistedOptions; +- (void)applyPersistedOptions; - (void)writePersistedOptions:(NSString *)storeKey withValue:(NSString* )value; - (void)showAboutWindow; - (void)showOSK; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m index 947bb803f1..fddecc55fa 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m @@ -6,15 +6,6 @@ // Copyright (c) 2017 SIL International. All rights reserved. // -// *** TO INVESTIGATE *** -// Keyman4MacIM[6245]: IMK Stall detected, *please Report* your user scenario in - (activateServerWithReply:) block performed very slowly (0.00 secs) -// Keyman4MacIM[6245]: IMK Stall detected, *please Report* your user scenario in - (deactivateServerWithReply:) block performed very slowly (0.00 secs) -// Keyman4MacIM[6245]: IMK Stall detected, *please Report* your user scenario in - (menusDictionaryWithClientAsync:reply:) block performed very slowly (0.00 secs) -// Keyman4MacIM[6245]: IMK Stall detected, *please Report* your user scenario in - (modesWithClientAsync:reply:) block performed very slowly (0.00 secs) -// Keyman4MacIM[6245]: IMK Stall detected, *please Report* your user scenario in - (commitCompositionWithReply:) block performed very slowly (0.00 secs) -// Keyman4MacIM[6245]: IMK Stall detected, *please Report* your user scenario in - (hidePalettes) block performed very slowly (0.00 secs) -// Keyman4MacIM[6245]: IMK Stall detected, *please Report* your user scenario in - (sessionFinished) block performed very slowly (0.00 secs) - #import "KMInputMethodAppDelegate.h" #import "KMSettingsRepository.h" #import "KMDataRepository.h" @@ -28,20 +19,9 @@ #import "KMLogs.h" @import Sentry; +// TODO: move Active Keyboards UserDefaults code to KMSettingsRepository /** NSUserDefaults keys */ -NSString *const kKMSelectedKeyboardKey = @"KMSelectedKeyboardKey"; NSString *const kKMActiveKeyboardsKey = @"KMActiveKeyboardsKey"; -/** - The following constant "KMSavedStoresKey" is left here for documentation - though we have abandoned stores written to UserDefaults with this key because - they used a less-reliable numeric key prior to integration with Keyman Core. - It is replaced by the renamed "KMPersistedOptionsKey" which directly - represents what it is saving. - */ -NSString *const kKMDeprecatedPersistedOptionsKey = @"KMSavedStoresKey"; -NSString *const kKMPersistedOptionsKey = @"KMPersistedOptionsKey"; -NSString *const kKMAlwaysShowOSKKey = @"KMAlwaysShowOSKKey"; -NSString *const kKMUseVerboseLogging = @"KMUseVerboseLogging"; NSString *const kKeymanKeyboardDownloadCompletedNotification = @"kKeymanKeyboardDownloadCompletedNotification"; @@ -409,7 +389,6 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef - (KMPackageReader *)packageReader { if (_packageReader == nil) { _packageReader = [[KMPackageReader alloc] init]; - [_packageReader setDebugMode:self.debugMode]; } return _packageReader; @@ -440,55 +419,17 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef [_oskWindow.window setTitle:self.oskWindowTitle]; } -- (void)readPersistedOptions { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - NSDictionary *allPersistedOptions = [userData dictionaryForKey:kKMPersistedOptionsKey]; - if (!allPersistedOptions) { - return; - } - NSDictionary *persistedOptionsForSelectedKeyboard = [allPersistedOptions objectForKey:_selectedKeyboard]; - if (!persistedOptionsForSelectedKeyboard) { - os_log_info([KMLogs configLog], "no persisted options found in UserDefaults for keyboard %{public}@ ", _selectedKeyboard); - return; - } +- (void)applyPersistedOptions { + NSDictionary *selectedPersistedOptions = [[KMSettingsRepository shared] readOptionsForSelectedKeyboard]; // TODO: pass array instead of making repeated calls - for (NSString *key in persistedOptionsForSelectedKeyboard) { - NSString *value = [persistedOptionsForSelectedKeyboard objectForKey:key]; + for (NSString *key in selectedPersistedOptions) { + NSString *value = [selectedPersistedOptions objectForKey:key]; os_log_info([KMLogs configLog], "persisted options found in UserDefaults for keyboard %{public}@, key: %{public}@, value: %{public}@", _selectedKeyboard, key, value); [self.kme setCoreOptions:key withValue:value]; } } -- (void)writePersistedOptions:(NSString *)storeKey withValue:(NSString* )value { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - NSDictionary *allPersistedOptions = [userData dictionaryForKey:kKMPersistedOptionsKey]; - NSDictionary *persistedOptionsForSelectedKeyboard; - - if (allPersistedOptions) { - persistedOptionsForSelectedKeyboard = [allPersistedOptions objectForKey:_selectedKeyboard]; - } - - if (persistedOptionsForSelectedKeyboard) { - NSMutableDictionary *newSavedStores = [persistedOptionsForSelectedKeyboard mutableCopy]; - [newSavedStores setObject:value forKey:storeKey]; - persistedOptionsForSelectedKeyboard = newSavedStores; - } else { - persistedOptionsForSelectedKeyboard = [[NSDictionary alloc] initWithObjectsAndKeys:value, storeKey, nil]; - } - - if (allPersistedOptions) { - NSMutableDictionary *newAllSavedStores = [allPersistedOptions mutableCopy]; - [newAllSavedStores setObject:persistedOptionsForSelectedKeyboard forKey:_selectedKeyboard]; - allPersistedOptions = newAllSavedStores; - } else { - allPersistedOptions = [[NSDictionary alloc] initWithObjectsAndKeys:persistedOptionsForSelectedKeyboard, _selectedKeyboard, nil]; - } - - [userData setObject:allPersistedOptions forKey:kKMPersistedOptionsKey]; - [userData synchronize]; -} - - (NSString *)oskWindowTitle { if (_keyboardName == nil || !_keyboardName.length) return [NSString stringWithFormat:@"Keyman"]; @@ -498,9 +439,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef - (void)setAlwaysShowOSK:(BOOL)alwaysShowOSK { _alwaysShowOSK = alwaysShowOSK; - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - [userData setBool:alwaysShowOSK forKey:kKMAlwaysShowOSKKey]; - [userData synchronize]; + [[KMSettingsRepository shared] writeAlwaysShowOsk:alwaysShowOSK]; } - (void)setUseVerboseLogging:(BOOL)useVerboseLogging { @@ -508,23 +447,17 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef _debugMode = useVerboseLogging; if (_kme != nil) [_kme setUseVerboseLogging:useVerboseLogging]; - if (_packageReader != nil) { - [_packageReader setDebugMode:useVerboseLogging]; - } - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - [userData setBool:useVerboseLogging forKey:kKMUseVerboseLogging]; - [userData synchronize]; + + [[KMSettingsRepository shared] writeUseVerboseLogging:useVerboseLogging]; } - (BOOL)alwaysShowOSK { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - _alwaysShowOSK = [userData boolForKey:kKMAlwaysShowOSKKey]; + _alwaysShowOSK = [[KMSettingsRepository shared] readAlwaysShowOsk]; return _alwaysShowOSK; } - (BOOL)useVerboseLogging { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - return [userData boolForKey:kKMUseVerboseLogging]; + return [[KMSettingsRepository shared] readUseVerboseLogging]; } #pragma mark - Keyman Data @@ -679,8 +612,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef - (NSString *)selectedKeyboard { if (_selectedKeyboard == nil) { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - _selectedKeyboard = [userData objectForKey:kKMSelectedKeyboardKey]; + _selectedKeyboard = [[KMSettingsRepository shared] readSelectedKeyboard]; } os_log_debug([KMLogs dataLog], "selectedKeyboard = %{public}@", _selectedKeyboard); @@ -688,10 +620,8 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } - (void)setSelectedKeyboard:(NSString *)selectedKeyboard { + [[KMSettingsRepository shared] writeSelectedKeyboard:selectedKeyboard]; _selectedKeyboard = selectedKeyboard; - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - [userData setObject:_selectedKeyboard forKey:kKMSelectedKeyboardKey]; - [userData synchronize]; } - (NSMutableArray *)activeKeyboards { @@ -903,7 +833,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef [self setKvk:kvk]; [self setKeyboardName:[kmxInfo objectForKey:kKMKeyboardNameKey]]; [self setKeyboardIcon:[kmxInfo objectForKey:kKMKeyboardIconKey]]; - [self readPersistedOptions]; + [self applyPersistedOptions]; } // defaults to the whatever keyboard happens to be first in the list @@ -964,7 +894,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef [self setKeyboardIcon:[kmxInfo objectForKey:kKMKeyboardIconKey]]; [self setContextBuffer:nil]; [self setSelectedKeyboard:path]; - [self readPersistedOptions]; + [self applyPersistedOptions]; if (kvk != nil && self.alwaysShowOSK) [self showOSK]; } diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m index efe628c43a..da1a319223 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m @@ -429,7 +429,7 @@ NSString* const kEasterEggKmxName = @"EnglishSpanish.kmx"; NSString *value = [options objectForKey:key]; if(key && value) { os_log_debug([KMLogs keyLog], "persistOptions, key: %{public}@, value: %{public}@", key, value); - [self.appDelegate writePersistedOptions:key withValue:value]; + [[KMSettingsRepository shared] writeOptionForSelectedKeyboard:key withValue:value]; } else { os_log_debug([KMLogs keyLog], "invalid values in persistOptions, not writing to UserDefaults, key: %{public}@, value: %{public}@", key, value); diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.h b/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.h index 2c138d8215..008f0c025e 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.h @@ -19,8 +19,6 @@ NS_ASSUME_NONNULL_BEGIN @interface KMPackageReader : NSObject -@property (assign, nonatomic) BOOL debugMode; - - (instancetype)init; - (KMPackageInfo *)loadPackageInfo:(NSString *)path; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.m b/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.m index 186ec8ab5a..e2cf1757a8 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.m @@ -44,9 +44,6 @@ typedef enum { - (instancetype)init { self = [super init]; - if (self) { - _debugMode = NO; - } return self; } diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.h b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.h index e6fe4dca38..8b74ce23d2 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.h @@ -17,6 +17,14 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)dataMigrationNeeded; - (void)convertSettingsForMigration; - (void)setDataModelVersionIfNecessary; +- (NSString *)readSelectedKeyboard; +- (void)writeSelectedKeyboard:(NSString *)selectedKeyboard; +- (NSDictionary *)readOptionsForSelectedKeyboard; +- (void)writeOptionForSelectedKeyboard:(NSString *)key withValue:(NSString*)value; +- (BOOL)readAlwaysShowOsk; +- (void)writeAlwaysShowOsk:(BOOL)alwaysShowOsk; +- (BOOL)readUseVerboseLogging; +- (void)writeUseVerboseLogging:(BOOL)verboseLogging; @end NS_ASSUME_NONNULL_END diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m index 54c779c00d..83b16a7e8b 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m @@ -17,6 +17,17 @@ NSString *const kActiveKeyboardsKey = @"KMActiveKeyboardsKey"; NSString *const kSelectedKeyboardKey = @"KMSelectedKeyboardKey"; NSString *const kPersistedOptionsKey = @"KMPersistedOptionsKey"; +NSString *const kAlwaysShowOSKKey = @"KMAlwaysShowOSKKey"; +NSString *const kUseVerboseLogging = @"KMUseVerboseLogging"; + +/** + The following constant "KMSavedStoresKey" is left here for documentation + though we have abandoned stores written to UserDefaults with this key because + they used a less-reliable numeric key prior to integration with Keyman Core. + It is replaced by the renamed "KMPersistedOptionsKey" which directly + represents what it is saving. + */ +NSString *const kKMDeprecatedPersistedOptionsKey = @"KMSavedStoresKey"; //NSString *const kObsoletePathComponent = @"/Documents/"; NSString *const kObsoletePathComponent = @"/Documents/Keyman-Keyboards"; @@ -58,6 +69,32 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; return ([[NSUserDefaults standardUserDefaults] objectForKey:kSelectedKeyboardKey] != nil); } +- (void)writeOptionForSelectedKeyboard:(NSString *)key withValue:(NSString*)value { + NSDictionary *optionsMap = [self readOptionsForSelectedKeyboard]; + NSDictionary *newOptionsMap = nil; + // if we can read an existing options map, then add the specified key-value pair + if (optionsMap != nil) { + NSMutableDictionary *mutableOptionsMap = [optionsMap mutableCopy]; + [mutableOptionsMap setObject:value forKey:key]; + os_log_info([KMLogs dataLog], "writeOptionsForSelectedKeyboard, setting key: %{public}@, value %{public}@", key, value); + newOptionsMap = mutableOptionsMap; + } else { + newOptionsMap = [[NSDictionary alloc] initWithObjectsAndKeys:value, key, nil]; + } + + // write the fully built dictionary to the dictionary of options + NSString *selectedKeyboard = [self readSelectedKeyboard]; + [self writeKeyboardOptionsMap: selectedKeyboard withOptions:newOptionsMap]; +} + +- (void)writeKeyboardOptionsMap:(NSString *)keyboardName withOptions:(NSDictionary*) optionsMap { + NSDictionary *fullOptionsMap = [self readOptions]; + NSMutableDictionary *newFullOptionsMap = [fullOptionsMap mutableCopy]; + + [newFullOptionsMap setObject:optionsMap forKey:keyboardName]; + [self writeOptions:newFullOptionsMap]; +} + /** * For the first numbered version of the data model, the app stores the keyboards under the /Library directory * For versions before version 1, the keyboards were stored under the /Documents directory. @@ -83,11 +120,11 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; return !(keymanSettingsExist && dataInLibrary); } -- (NSString *)selectedKeyboard { +- (NSString *)readSelectedKeyboard { return [[NSUserDefaults standardUserDefaults] objectForKey:kSelectedKeyboardKey]; } -- (void)saveSelectedKeyboard:(NSString *)selectedKeyboard { +- (void)writeSelectedKeyboard:(NSString *)selectedKeyboard { NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; [userData setObject:selectedKeyboard forKey:kSelectedKeyboardKey]; } @@ -101,53 +138,61 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; return activeKeyboards; } -- (NSDictionary *)persistedOptions { +/* + * returns dictionary of persisted options for the single selected keyboard + */ +- (NSDictionary *)readOptionsForSelectedKeyboard { + NSDictionary *optionsMap = [self readOptions]; + NSString *selectedKeyboard = [self readSelectedKeyboard]; + NSDictionary *selectedOptionsMap = [optionsMap objectForKey: selectedKeyboard]; + if (selectedOptionsMap == nil) { + os_log_info([KMLogs dataLog], "no persisted options found in UserDefaults for keyboard %{public}@ ", selectedKeyboard); + } else { + for (NSString *key in optionsMap) { + NSString *value = [optionsMap objectForKey:key]; + os_log_info([KMLogs dataLog], "option for keyboard %{public}@ key: %{public}@, value %{public}@", selectedKeyboard, key, value); + } + } + return selectedOptionsMap; +} + +/* + * returns dictionary of all persisted options for all keyboards + */ +- (NSDictionary *)readOptions { NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; return [userData dictionaryForKey:kPersistedOptionsKey]; } -- (void)savePersistedOptions:(NSDictionary *) optionsDictionary { +- (void)writeOptions:(NSDictionary *) optionsDictionary { NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; [userData setObject:optionsDictionary forKey:kPersistedOptionsKey]; } -- (void)removePersistedOptions { +- (void)removeAllOptions { NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; return [userData removeObjectForKey:kPersistedOptionsKey]; } - (void)convertSettingsForMigration { + os_log_debug([KMLogs dataLog], "converting settings in UserDefaults for migration"); [self convertSelectedKeyboardPathForMigration]; [self convertActiveKeyboardArrayForMigration]; - [self convertPersistedOptionsPathsForMigration]; + [self convertOptionsPathsForMigration]; } - (void)convertSelectedKeyboardPathForMigration { - NSString *selectedKeyboardPath = [self selectedKeyboard]; + NSString *selectedKeyboardPath = [self readSelectedKeyboard]; if (selectedKeyboardPath != nil) { NSString *newPathString = [self trimObsoleteKeyboardPath:selectedKeyboardPath]; if ([selectedKeyboardPath isNotEqualTo:newPathString]) { - [self saveSelectedKeyboard:newPathString]; + [self writeSelectedKeyboard:newPathString]; os_log_debug([KMLogs dataLog], "converted selected keyboard setting from '%{public}@' to '%{public}@'", selectedKeyboardPath, newPathString); } } } -/** - * Convert the path of the keyboard designating the Documents folder to its new location - * in the Application Support folder - */ -/* -- (NSString *)convertOldKeyboardPath:(NSString *)oldPath { - NSString *newPathString = @""; - if(oldPath != nil) { - newPathString = [oldPath stringByReplacingOccurrencesOfString:kObsoletePathComponent withString:kNewPathComponent]; - } - return newPathString; -} -*/ - /** * To convert the keyboard path for the new location, just trim the parent directory from the path * No need to repeatedly store the parent directory with the path of each keyboard @@ -190,8 +235,8 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; } } -- (void)convertPersistedOptionsPathsForMigration { - NSDictionary * optionsMap = [self persistedOptions]; +- (void)convertOptionsPathsForMigration { + NSDictionary * optionsMap = [self readOptions]; NSMutableDictionary *mutableOptionsMap = nil; BOOL optionsChanged = NO; @@ -217,9 +262,29 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; } } if (optionsChanged) { - [self savePersistedOptions:mutableOptionsMap]; + [self writeOptions:mutableOptionsMap]; } } } +- (BOOL)readAlwaysShowOsk { + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + return [userData boolForKey:kAlwaysShowOSKKey]; +} + +- (void)writeAlwaysShowOsk:(BOOL)alwaysShowOsk { + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + [userData setBool:alwaysShowOsk forKey:kAlwaysShowOSKKey]; +} + +- (BOOL)readUseVerboseLogging { + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + return [userData boolForKey:kUseVerboseLogging]; +} + +- (void)writeUseVerboseLogging:(BOOL)verboseLogging { + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + [userData setBool:verboseLogging forKey:kUseVerboseLogging]; +} + @end From 49bfd08fb3617386dbf3b7d93dbc52811cedac93 Mon Sep 17 00:00:00 2001 From: sgschantz Date: Mon, 19 Aug 2024 12:49:46 +0700 Subject: [PATCH 4/6] change(mac): persist options fix when dictionary exists testing showed that when an option already existed, it would be deleted when attempting to update it to a new value --- .../Keyman4MacIM/KMSettingsRepository.m | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m index 83b16a7e8b..752ea86b66 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m @@ -72,27 +72,38 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; - (void)writeOptionForSelectedKeyboard:(NSString *)key withValue:(NSString*)value { NSDictionary *optionsMap = [self readOptionsForSelectedKeyboard]; NSDictionary *newOptionsMap = nil; + // if we can read an existing options map, then add the specified key-value pair if (optionsMap != nil) { NSMutableDictionary *mutableOptionsMap = [optionsMap mutableCopy]; [mutableOptionsMap setObject:value forKey:key]; - os_log_info([KMLogs dataLog], "writeOptionsForSelectedKeyboard, setting key: %{public}@, value %{public}@", key, value); newOptionsMap = mutableOptionsMap; } else { + // if no options map exists, create a new one add the specified key-value pair newOptionsMap = [[NSDictionary alloc] initWithObjectsAndKeys:value, key, nil]; } - // write the fully built dictionary to the dictionary of options + // write the options map for the selected keyboard to the dictionary of options NSString *selectedKeyboard = [self readSelectedKeyboard]; + os_log_info([KMLogs dataLog], "writeOptionForSelectedKeyboard, adding options map: %{public}@, to keyboard %{public}@", newOptionsMap, selectedKeyboard); [self writeKeyboardOptionsMap: selectedKeyboard withOptions:newOptionsMap]; } - (void)writeKeyboardOptionsMap:(NSString *)keyboardName withOptions:(NSDictionary*) optionsMap { - NSDictionary *fullOptionsMap = [self readOptions]; - NSMutableDictionary *newFullOptionsMap = [fullOptionsMap mutableCopy]; - - [newFullOptionsMap setObject:optionsMap forKey:keyboardName]; - [self writeOptions:newFullOptionsMap]; + NSMutableDictionary *newFullOptionsMap = nil; + os_log_debug([KMLogs dataLog], "writeKeyboardOptionsMap, adding options map: %{public}@, to keyboard %{public}@", optionsMap, keyboardName); + + NSDictionary *fullOptionsMap = [self readFullOptionsMap]; + // if we can read the existing full options map, then add for the specified keyboard + if (fullOptionsMap != nil) { + newFullOptionsMap = [fullOptionsMap mutableCopy]; + [newFullOptionsMap setObject:optionsMap forKey:keyboardName]; + } else { + // otherwise, create the full options map and add for the specified keyboard + newFullOptionsMap = [[NSMutableDictionary alloc] initWithObjectsAndKeys:optionsMap, keyboardName, nil]; + } + + [self writeFullOptionsMap:newFullOptionsMap]; } /** @@ -142,14 +153,14 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; * returns dictionary of persisted options for the single selected keyboard */ - (NSDictionary *)readOptionsForSelectedKeyboard { - NSDictionary *optionsMap = [self readOptions]; + NSDictionary *optionsMap = [self readFullOptionsMap]; NSString *selectedKeyboard = [self readSelectedKeyboard]; NSDictionary *selectedOptionsMap = [optionsMap objectForKey: selectedKeyboard]; if (selectedOptionsMap == nil) { os_log_info([KMLogs dataLog], "no persisted options found in UserDefaults for keyboard %{public}@ ", selectedKeyboard); } else { - for (NSString *key in optionsMap) { - NSString *value = [optionsMap objectForKey:key]; + for (NSString *key in selectedOptionsMap) { + NSString *value = [selectedOptionsMap objectForKey:key]; os_log_info([KMLogs dataLog], "option for keyboard %{public}@ key: %{public}@, value %{public}@", selectedKeyboard, key, value); } } @@ -158,15 +169,16 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; /* * returns dictionary of all persisted options for all keyboards + * (options are stored in UserDefaults as a map of maps) */ -- (NSDictionary *)readOptions { +- (NSDictionary *)readFullOptionsMap { NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; return [userData dictionaryForKey:kPersistedOptionsKey]; } -- (void)writeOptions:(NSDictionary *) optionsDictionary { +- (void)writeFullOptionsMap:(NSDictionary *) fullOptionsMap { NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - [userData setObject:optionsDictionary forKey:kPersistedOptionsKey]; + [userData setObject:fullOptionsMap forKey:kPersistedOptionsKey]; } - (void)removeAllOptions { @@ -236,7 +248,7 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; } - (void)convertOptionsPathsForMigration { - NSDictionary * optionsMap = [self readOptions]; + NSDictionary * optionsMap = [self readFullOptionsMap]; NSMutableDictionary *mutableOptionsMap = nil; BOOL optionsChanged = NO; @@ -262,7 +274,7 @@ NSInteger const kVersionStoreDataInLibraryDirectory = 1; } } if (optionsChanged) { - [self writeOptions:mutableOptionsMap]; + [self writeFullOptionsMap:mutableOptionsMap]; } } } From 24daed27f7bf4fe964f8178c7b69a77f08834e93 Mon Sep 17 00:00:00 2001 From: sgschantz Date: Wed, 28 Aug 2024 12:54:42 +0700 Subject: [PATCH 5/6] change(mac): minor comment cleanup Fixes: #2542 --- .../Keyman4MacIM/KMSettingsRepository.m | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m index c4001b5acd..c7d655593a 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m @@ -18,15 +18,14 @@ NSString *const kAlwaysShowOSKKey = @"KMAlwaysShowOSKKey"; NSString *const kUseVerboseLogging = @"KMUseVerboseLogging"; /** - The following constant "KMSavedStoresKey" is left here for documentation - though we have abandoned stores written to UserDefaults with this key because - they used a less-reliable numeric key prior to integration with Keyman Core. - It is replaced by the renamed "KMPersistedOptionsKey" which directly - represents what it is saving. + * The following constant "KMSavedStoresKey" is left here for documentation + * though we have abandoned stores written to UserDefaults with this key because + * they used a less-reliable numeric key prior to integration with Keyman Core. + * It is replaced by the renamed "KMPersistedOptionsKey" which directly + * represents what it is saving. */ NSString *const kKMDeprecatedPersistedOptionsKey = @"KMSavedStoresKey"; -//NSString *const kObsoletePathComponent = @"/Documents/"; NSString *const kObsoletePathComponent = @"/Documents/Keyman-Keyboards"; NSString *const kNewPathComponent = @"/Library/Application Support/keyman.inputmethod.Keyman/"; @@ -152,7 +151,7 @@ NSInteger const kCurrentDataModelVersionNumber = kVersionStoreDataInLibraryDirec return activeKeyboards; } -/* +/** * returns dictionary of persisted options for the single selected keyboard */ - (NSDictionary *)readOptionsForSelectedKeyboard { @@ -170,7 +169,7 @@ NSInteger const kCurrentDataModelVersionNumber = kVersionStoreDataInLibraryDirec return selectedOptionsMap; } -/* +/** * returns dictionary of all persisted options for all keyboards * (options are stored in UserDefaults as a map of maps) */ From 9ddb7ba3292412920c6085c93c0c66f4822dd11f Mon Sep 17 00:00:00 2001 From: sgschantz Date: Fri, 30 Aug 2024 09:38:58 +0700 Subject: [PATCH 6/6] change(mac): encapsulate active keyboards access in KMSettingsRepository --- .../Keyman4MacIM/KMInputMethodAppDelegate.h | 2 - .../Keyman4MacIM/KMInputMethodAppDelegate.m | 38 +++++++------------ .../Keyman4MacIM/KMSettingsRepository.h | 3 ++ .../Keyman4MacIM/KMSettingsRepository.m | 26 +++++++++++++ 4 files changed, 42 insertions(+), 27 deletions(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h index 376e531f7f..ce70724c3a 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.h @@ -23,7 +23,6 @@ typedef void(^PostEventCallback)(CGEventRef eventToPost); -extern NSString *const kKMActiveKeyboardsKey; extern NSString *const kKeymanKeyboardDownloadCompletedNotification; typedef struct { @@ -99,7 +98,6 @@ static const int KEYMAN_FIRST_KEYBOARD_MENUITEM_INDEX = 0; - (NSMenu *)menu; - (void)saveActiveKeyboards; - (void)applyPersistedOptions; -- (void)writePersistedOptions:(NSString *)storeKey withValue:(NSString* )value; - (void)showAboutWindow; - (void)showOSK; - (void)showConfigurationWindow; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m index fddecc55fa..26ecc717ef 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m @@ -19,10 +19,6 @@ #import "KMLogs.h" @import Sentry; -// TODO: move Active Keyboards UserDefaults code to KMSettingsRepository -/** NSUserDefaults keys */ -NSString *const kKMActiveKeyboardsKey = @"KMActiveKeyboardsKey"; - NSString *const kKeymanKeyboardDownloadCompletedNotification = @"kKeymanKeyboardDownloadCompletedNotification"; @implementation NSString (VersionNumbers) @@ -627,33 +623,31 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef - (NSMutableArray *)activeKeyboards { if (!_activeKeyboards) { os_log_debug([KMLogs dataLog], "initializing activeKeyboards"); - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - _activeKeyboards = [[userData arrayForKey:kKMActiveKeyboardsKey] mutableCopy]; - if (!_activeKeyboards) { - os_log_debug([KMLogs dataLog], "KMActiveKeyboardsKey key not found in NSUserDefualts"); - _activeKeyboards = [[NSMutableArray alloc] initWithCapacity:0]; - } + _activeKeyboards = [[KMSettingsRepository.shared readActiveKeyboards] mutableCopy]; } return _activeKeyboards; } - (void)saveActiveKeyboards { - os_log_debug([KMLogs dataLog], "saveActiveKeyboards, entering"); - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - [userData setObject:_activeKeyboards forKey:kKMActiveKeyboardsKey]; - [userData synchronize]; + os_log_debug([KMLogs dataLog], "saveActiveKeyboards"); + [KMSettingsRepository.shared writeActiveKeyboards:_activeKeyboards]; [self resetActiveKeyboards]; [self updateKeyboardMenuItems]; } - (void)clearActiveKeyboards { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - [userData setObject:nil forKey:kKMActiveKeyboardsKey]; - [userData synchronize]; + [KMSettingsRepository.shared clearActiveKeyboards]; [self updateKeyboardMenuItems]; } +- (void)addActiveKeyboard:(NSString *) partialPath { + if (![self.activeKeyboards containsObject:partialPath]) { + os_log_debug([KMLogs keyboardLog], "addActiveKeyboard, adding '%{public}@' to list of active keyboards: ", partialPath); + [self.activeKeyboards addObject:partialPath]; + } +} + - (void)resetActiveKeyboards { // Remove entries with missing files NSMutableArray *pathsToRemove = [[NSMutableArray alloc] initWithCapacity:0]; @@ -686,9 +680,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } if (found) { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - [userData setObject:_activeKeyboards forKey:kKMActiveKeyboardsKey]; - [userData synchronize]; + [KMSettingsRepository.shared writeActiveKeyboards:_activeKeyboards]; } } @@ -1356,11 +1348,7 @@ extern const CGKeyCode kProcessPendingBuffer; for (NSString *kmxFile in [self getKmxFilesAtPath:keyboardFolderPath]) { NSString *partialPath = [KMDataRepository.shared buildPartialPathFrom:folderName keyboardFile:[kmxFile lastPathComponent]]; - // TODO: encapsulate this in KMSettingsRepository, insertIfNotExists - if (![self.activeKeyboards containsObject:partialPath]) { - os_log_debug([KMLogs keyboardLog], "unzipFile, adding keyboard to list of active keyboards: %{public}@", partialPath); - [self.activeKeyboards addObject:partialPath]; - } + [self addActiveKeyboard:partialPath]; } [self saveActiveKeyboards]; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.h b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.h index 8b74ce23d2..5a7f920c9f 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.h @@ -19,6 +19,9 @@ NS_ASSUME_NONNULL_BEGIN - (void)setDataModelVersionIfNecessary; - (NSString *)readSelectedKeyboard; - (void)writeSelectedKeyboard:(NSString *)selectedKeyboard; +- (NSArray *)readActiveKeyboards; +- (void)writeActiveKeyboards: (NSArray *) keyboards; +- (void)clearActiveKeyboards; - (NSDictionary *)readOptionsForSelectedKeyboard; - (void)writeOptionForSelectedKeyboard:(NSString *)key withValue:(NSString*)value; - (BOOL)readAlwaysShowOsk; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m index c7d655593a..d8cca25f94 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m @@ -151,6 +151,32 @@ NSInteger const kCurrentDataModelVersionNumber = kVersionStoreDataInLibraryDirec return activeKeyboards; } +- (NSArray *)readActiveKeyboards { + os_log_debug([KMLogs dataLog], "KMSettingsRepository readActiveKeyboards"); + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + NSArray *keyboardsArray = [userData arrayForKey:kActiveKeyboardsKey]; + + // if the kActiveKeyboardsKey does not exist, then create an empty array + if (!keyboardsArray) { + os_log_debug([KMLogs dataLog], "KMActiveKeyboardsKey key not found in NSUserDefualts"); + keyboardsArray = [[NSArray alloc] init]; + } + return keyboardsArray; +} + +- (void)writeActiveKeyboards: (NSArray *) keyboards { + os_log_debug([KMLogs dataLog], "KMSettingsRepository writeActiveKeyboards"); + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + [userData setObject:keyboards forKey:kActiveKeyboardsKey]; +} + +- (void)clearActiveKeyboards { + os_log_debug([KMLogs dataLog], "KMSettingsRepository clearActiveKeyboards"); + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + [userData setObject:nil forKey:kActiveKeyboardsKey]; +} + + /** * returns dictionary of persisted options for the single selected keyboard */