From ba8b8228f958eef567d8bf759d61519e851e032c Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Wed, 17 Jul 2019 19:24:54 -0500 Subject: [PATCH 01/47] done disable Done btn when adding a lesical model --- .../LanguagePicker/LexicalModelPickerViewController.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift index 1e13eab1a3..fd169b54a8 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift @@ -137,7 +137,9 @@ class LexicalModelPickerViewController: UITableViewController, UIAlertViewDelega if Manager.shared.removeLexicalModel(at: globalIndex) { loadUserLexicalModels() } - setIsDoneButtonEnabled(true) + if language == nil { + setIsDoneButtonEnabled(true) + } } override func tableView(_ tableView: UITableView, From 18201f3787f17dd551fc275cd1e90dc753e15f50 Mon Sep 17 00:00:00 2001 From: jahorton Date: Mon, 22 Jul 2019 09:36:19 +0700 Subject: [PATCH 02/47] Comments out hooks for rotation suggestion. --- .../main/java/com/tavultesoft/kmea/KMKeyboard.java | 5 +++-- .../src/main/java/com/tavultesoft/kmea/KMManager.java | 11 +++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java index cb438e3dd8..b547bdfc88 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java @@ -167,10 +167,11 @@ final class KMKeyboard extends WebView { if (subKeysList != null) { showSubKeys(context); return; - } else if(suggestionJSON != null) { + } /* For future implementation + else if(suggestionJSON != null) { showSuggestionLongpress(context); return; - } + }*/ } @Override diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index 45d518c1fc..d569879365 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -1485,17 +1485,19 @@ public final class KMManager { JSONParser parser = new JSONParser(); JSONObject obj = parser.getJSONObjectFromURIString(suggestionJSON); + /* // For future implementation InAppKeyboard.suggestionWindowPos = new double[]{x, y}; InAppKeyboard.suggestionJSON = suggestionJSON; try { Log.v("KMEA", "Suggestion display: " + obj.getString("displayAs")); Log.v("KMEA", "Suggestion's banner coords: " + x + ", " + y + ", " + width + ", " + height); - Log.v("KMEA", "Is a suggestion: " + isCustom); + Log.v("KMEA", "Is a suggestion: " + isCustom); // likely outdated now that tags exist. } catch (JSONException e) { //e.printStackTrace(); Log.v("KMEA", "JSON parsing error: " + e.getMessage()); } + */ } return false; } @@ -1713,14 +1715,19 @@ public final class KMManager { JSONParser parser = new JSONParser(); JSONObject obj = parser.getJSONObjectFromURIString(suggestionJSON); + /* // For future implementation + SystemKeyboard.suggestionWindowPos = new double[]{x, y}; + SystemKeyboard.suggestionJSON = suggestionJSON; + try { Log.v("KMEA", "Suggestion display: " + obj.getString("displayAs")); Log.v("KMEA", "Suggestion's banner coords: " + x + ", " + y + ", " + width + ", " + height); - Log.v("KMEA", "Is a suggestion: " + isCustom); + Log.v("KMEA", "Is a suggestion: " + isCustom); // likely outdated now that tags exist. } catch (JSONException e) { //e.printStackTrace(); Log.v("KMEA", "JSON parsing error: " + e.getMessage()); } + */ } return false; From a654d541d41c3965705e84fdd2bf8b2b369134d2 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Tue, 23 Jul 2019 11:44:27 -0400 Subject: [PATCH 03/47] LexicalModelState is not needed, KeyboardState has all the values we need, note where we need to put a dialog when there are no lexical models for this language --- ios/engine/KMEI/KeymanEngine/Classes/Manager.swift | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift index 8feb400c85..747092c22c 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift @@ -26,15 +26,6 @@ public enum KeyboardState { case none } -// Possible states that a lexical model can be in -public enum LexicalModelState { - case needsDownload - case needsUpdate - case upToDate - case downloading - case none -} - public enum VibrationSupport { case none // Has no vibrator case basic // Has only the basic 0.4 sec long vibration @@ -1074,6 +1065,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat log.info("Failed to fetch lexical model list for "+languageID+". error: "+(error as! String)) self.downloadFailed(forLanguageID: languageID, error: error) //???forKeyboards } else if nil == lexicalModels { + //TODO: put up an alert instead log.info("No lexical models available for language \(languageID) (nil)") } else if 0 == lexicalModels?.count { log.info("No lexical models available for language \(languageID) (empty)") @@ -1274,7 +1266,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat } /// - Returns: The current state for a lexical model - public func stateForLexicalModel(withID lexicalModelID: String) -> LexicalModelState { + public func stateForLexicalModel(withID lexicalModelID: String) -> KeyboardState { if lexicalModelIdForCurrentRequest() == lexicalModelID { return .downloading } From 42fb61cc3ae0ba6f702be160d123afb0a5133637 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Tue, 23 Jul 2019 11:46:10 -0400 Subject: [PATCH 04/47] document installed2API and make available to outside code --- .../Classes/Settings/SettingsViewController.swift | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Settings/SettingsViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/Settings/SettingsViewController.swift index 57da4fea48..a8c2c8388f 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Settings/SettingsViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Settings/SettingsViewController.swift @@ -256,7 +256,13 @@ open class SettingsViewController: UITableViewController { } // MARK: - language access - - private func installed2API(_ installedList: [InstallableLexicalModel]) -> [LexicalModel] { + + /** returns an array of LexicalModel created from an array of InstallableLexicalModel + * @param installedList: The InstallableLexicalModel are probably already installed + * The returned LexicalModels are not complete (usually we go the other way round) + * but sufficient for future API calls + */ + public static func installed2API(_ installedList: [InstallableLexicalModel]) -> [LexicalModel] { var returnList = [LexicalModel]() for ilm in installedList { returnList.append(LexicalModel(id: ilm.id, name: ilm.name, license: "", version: ilm.version, languages: [], authorName: "", fileSize: 0, filename: "no filename", sourcePath: nil, authorEmail: nil, description: nil, packageFileSize: 0, packageFilename: "", packageIncludes: nil, isDefault: false, lastModified: nil, minKeymanVersion: nil)) @@ -283,7 +289,7 @@ open class SettingsViewController: UITableViewController { } let userDefaults : UserDefaults = Storage.active.userDefaults let lmListInstalled: [InstallableLexicalModel] = userDefaults.userLexicalModelsForLanguage(languageID: l) ?? [] - let lmList = installed2API(lmListInstalled) + let lmList = SettingsViewController.installed2API(lmListInstalled) keyboardLanguages[l] = Language(name: k.languageName, id: k.languageID, keyboards: kbds, lexicalModels: lmList, font: nil, oskFont: nil) } // there shouldn't be any lexical models for languages that don't have a keyboard installed From 7b92acc9dfd4f5ed09528296945da4b6ad921089 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Tue, 23 Jul 2019 11:50:31 -0400 Subject: [PATCH 05/47] send the language to the controller showing the lexical models for this language --- .../Classes/Settings/LanguageSettingsViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift index c14188de96..3e4a2e9a63 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift @@ -267,7 +267,7 @@ class LanguageSettingsViewController: UITableViewController { func showLexicalModelsView() { //LanguageLexicalModelPickerViewController? (should show just the models for this language) - let lmListView = LexicalModelPickerViewController() + let lmListView = LexicalModelPickerViewController(self.language) lmListView.language = self.language navigationController?.pushViewController(lmListView, animated: true) } From c6952f7a1065bf70ac6ebfcb22c02b2bb4d899c3 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Tue, 23 Jul 2019 12:30:27 -0400 Subject: [PATCH 06/47] LanguageLMDetailViewController.swift and LanguageLMDetailViewController.xib added InstalledLanguagesViewController and LanguageSpecificViewController changed ids --- .../KeymanEngine.xcodeproj/project.pbxproj | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj b/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj index 9789c00731..9d2af3cb20 100644 --- a/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj +++ b/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj @@ -123,12 +123,12 @@ 9A3B14D3229370B20052A11F /* InstalledLanguagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A3B14D1229370B20052A11F /* InstalledLanguagesViewController.swift */; }; 9A4609972241B39B00B0BFD1 /* LexicalModelInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A4609962241B39B00B0BFD1 /* LexicalModelInfoViewController.swift */; }; 9A4609992242047400B0BFD1 /* LexicalModelAPICall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A4609982242047400B0BFD1 /* LexicalModelAPICall.swift */; }; - 9A60764422893A4E003BCFBA /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A60764322893A4E003BCFBA /* SettingsViewController.swift */; }; - 9A7EEFA222DCF64F00877C22 /* LanguageSpecificViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A7EEFA122DCF64F00877C22 /* LanguageSpecificViewController.swift */; }; 9A5091B122B418140094B99C /* KeyboardCommandStructs.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE67D960228A6F190029F2B5 /* KeyboardCommandStructs.swift */; }; 9A5091B222B418A90094B99C /* KeyboardPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08C62161F67CFB800268D03 /* KeyboardPickerViewController.swift */; }; 9A5091B322B418CA0094B99C /* KeyboardInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08C62141F67C8D500268D03 /* KeyboardInfoViewController.swift */; }; 9A5091B422B419B10094B99C /* LanguageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04C2A6C1F6B7D9A00BA42B6 /* LanguageViewController.swift */; }; + 9A60764422893A4E003BCFBA /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A60764322893A4E003BCFBA /* SettingsViewController.swift */; }; + 9A7EEFA222DCF64F00877C22 /* LanguageSpecificViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A7EEFA122DCF64F00877C22 /* LanguageSpecificViewController.swift */; }; 9A862D2822B429FB005FE26D /* KeyboardNameTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08C62121F67C31100268D03 /* KeyboardNameTableViewCell.swift */; }; 9A862D2922B42A0C005FE26D /* LanguageDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C092D8381F6A70C8005C5485 /* LanguageDetailViewController.swift */; }; 9A9CB08022416E5400231FB9 /* LexicalModelPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A9CB07F22416E5400231FB9 /* LexicalModelPickerViewController.swift */; }; @@ -139,6 +139,11 @@ 9AD4F53D229F85AC007992D3 /* LanguageSettingsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9AD4F53B229F85AC007992D3 /* LanguageSettingsViewController.xib */; }; 9AD4F53E22A8A25B007992D3 /* LanguageSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AD4F53A229F85AC007992D3 /* LanguageSettingsViewController.swift */; }; 9AD4F53F22A8A286007992D3 /* LanguageSettingsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9AD4F53B229F85AC007992D3 /* LanguageSettingsViewController.xib */; }; + 9ADC459A22E186F5004C78C6 /* LanguageSpecificViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A7EEFA122DCF64F00877C22 /* LanguageSpecificViewController.swift */; }; + 9ADC459D22E1895D004C78C6 /* LanguageLMDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9ADC459B22E1895D004C78C6 /* LanguageLMDetailViewController.swift */; }; + 9ADC459E22E1895D004C78C6 /* LanguageLMDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9ADC459B22E1895D004C78C6 /* LanguageLMDetailViewController.swift */; }; + 9ADC459F22E1895D004C78C6 /* LanguageLMDetailViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9ADC459C22E1895D004C78C6 /* LanguageLMDetailViewController.xib */; }; + 9ADC45A022E1895D004C78C6 /* LanguageLMDetailViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9ADC459C22E1895D004C78C6 /* LanguageLMDetailViewController.xib */; }; C007C4651F9F52D8006461B9 /* LanguagesAPICall.swift in Sources */ = {isa = PBXBuildFile; fileRef = C007C4641F9F52D8006461B9 /* LanguagesAPICall.swift */; }; C024C9941FA6EB470060583B /* NotificationName.swift in Sources */ = {isa = PBXBuildFile; fileRef = C024C9931FA6EB470060583B /* NotificationName.swift */; }; C024C9961FA6EC650060583B /* NotificationCenter+Typed.swift in Sources */ = {isa = PBXBuildFile; fileRef = C024C9951FA6EC650060583B /* NotificationCenter+Typed.swift */; }; @@ -335,8 +340,8 @@ 9A079E3F223B602B00581263 /* LexicalModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LexicalModel.swift; sourceTree = ""; }; 9A079E42223B61AE00581263 /* FullLexicalModelID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullLexicalModelID.swift; sourceTree = ""; }; 9A082558227589360051EBB0 /* Formatter+ISODateExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Formatter+ISODateExtension.swift"; sourceTree = ""; }; - 9A3B14D1229370B20052A11F /* InstalledLanguagesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InstalledLanguagesViewController.swift; path = Settings/InstalledLanguagesViewController.swift; sourceTree = ""; }; 9A0FC9FC22D66D9E00D33F86 /* Reachability.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Reachability.framework; path = ../../Carthage/Build/iOS/Reachability.framework; sourceTree = ""; }; + 9A3B14D1229370B20052A11F /* InstalledLanguagesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InstalledLanguagesViewController.swift; path = Settings/InstalledLanguagesViewController.swift; sourceTree = ""; }; 9A4609962241B39B00B0BFD1 /* LexicalModelInfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LexicalModelInfoViewController.swift; sourceTree = ""; }; 9A4609982242047400B0BFD1 /* LexicalModelAPICall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LexicalModelAPICall.swift; sourceTree = ""; }; 9A60763C22892485003BCFBA /* Settings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Settings.storyboard; path = Settings/Settings.storyboard; sourceTree = ""; }; @@ -348,6 +353,8 @@ 9A9CB0852241717C00231FB9 /* LexicalModelRepositoryDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LexicalModelRepositoryDelegate.swift; sourceTree = ""; }; 9AD4F53A229F85AC007992D3 /* LanguageSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LanguageSettingsViewController.swift; path = Settings/LanguageSettingsViewController.swift; sourceTree = ""; }; 9AD4F53B229F85AC007992D3 /* LanguageSettingsViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = LanguageSettingsViewController.xib; path = Settings/LanguageSettingsViewController.xib; sourceTree = ""; }; + 9ADC459B22E1895D004C78C6 /* LanguageLMDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageLMDetailViewController.swift; sourceTree = ""; }; + 9ADC459C22E1895D004C78C6 /* LanguageLMDetailViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LanguageLMDetailViewController.xib; sourceTree = ""; }; C007C4641F9F52D8006461B9 /* LanguagesAPICall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguagesAPICall.swift; sourceTree = ""; }; C024C9931FA6EB470060583B /* NotificationName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationName.swift; sourceTree = ""; }; C024C9951FA6EC650060583B /* NotificationCenter+Typed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NotificationCenter+Typed.swift"; sourceTree = ""; }; @@ -801,6 +808,8 @@ C08C62161F67CFB800268D03 /* KeyboardPickerViewController.swift */, 9A9CB07F22416E5400231FB9 /* LexicalModelPickerViewController.swift */, C092D8381F6A70C8005C5485 /* LanguageDetailViewController.swift */, + 9ADC459B22E1895D004C78C6 /* LanguageLMDetailViewController.swift */, + 9ADC459C22E1895D004C78C6 /* LanguageLMDetailViewController.xib */, C04C2A6C1F6B7D9A00BA42B6 /* LanguageViewController.swift */, 9A7EEFA122DCF64F00877C22 /* LanguageSpecificViewController.swift */, 98C0B11817A22DB5007ECAFC /* PickerButtons */, @@ -1030,6 +1039,7 @@ buildActionMask = 2147483647; files = ( 9AD4F53F22A8A286007992D3 /* LanguageSettingsViewController.xib in Resources */, + 9ADC45A022E1895D004C78C6 /* LanguageLMDetailViewController.xib in Resources */, 9A0FCA0922D7C58B00D33F86 /* Keyman.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1039,6 +1049,7 @@ buildActionMask = 2147483647; files = ( C06D37601F82095200F61AE0 /* Keyman.bundle in Resources */, + 9ADC459F22E1895D004C78C6 /* LanguageLMDetailViewController.xib in Resources */, 9AD4F53D229F85AC007992D3 /* LanguageSettingsViewController.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1145,6 +1156,7 @@ 9A31E2C8224AE87600D9A491 /* RegisteredFont.swift in Sources */, 9A5091B422B419B10094B99C /* LanguageViewController.swift in Sources */, 9A079E352236235700581263 /* Version.swift in Sources */, + 9ADC459E22E1895D004C78C6 /* LanguageLMDetailViewController.swift in Sources */, 9A079DDC2231A11000581263 /* Font.swift in Sources */, 9A079E49223F176100581263 /* String+Helpers.swift in Sources */, 9A079DE82236138800581263 /* HTTPDownloadRequest.swift in Sources */, @@ -1170,7 +1182,7 @@ 9A5091B222B418A90094B99C /* KeyboardPickerViewController.swift in Sources */, 9A31E2C2224AAD9A00D9A491 /* Notifications.swift in Sources */, 9A079DDD2231A11C00581263 /* InstallableKeyboard.swift in Sources */, - 9A7EEFA222DCF64F00877C22 /* LanguageSpecificViewController.swift in Sources */, + 9ADC459A22E186F5004C78C6 /* LanguageSpecificViewController.swift in Sources */, 9A079DD2223194B100581263 /* KeymanEngineTests.swift in Sources */, 9A079E41223B602B00581263 /* LexicalModel.swift in Sources */, 9A3B14C0228F59490052A11F /* SettingsViewController.swift in Sources */, @@ -1241,6 +1253,7 @@ C06D37381F81F5C400F61AE0 /* SubKeysView.swift in Sources */, C0A93A541F8B21240079948B /* Manager.swift in Sources */, C024C9981FA6F2340060583B /* NotificationObserver.swift in Sources */, + 9ADC459D22E1895D004C78C6 /* LanguageLMDetailViewController.swift in Sources */, C06D373E1F81F5C400F61AE0 /* KeyboardInfoViewController.swift in Sources */, C0B901AA1FA1AFC200764EB8 /* UserDefaults+Types.swift in Sources */, 9A079E372238680700581263 /* KMPLexicalModel.swift in Sources */, From d13722e6384352debcb9bd869d3798d2cc003452 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Tue, 23 Jul 2019 12:31:48 -0400 Subject: [PATCH 07/47] Table view data source UITableViewDataSource marked --- .../Classes/LanguagePicker/LanguageDetailViewController.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageDetailViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageDetailViewController.swift index 1aa7ffea90..4e956a9c68 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageDetailViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageDetailViewController.swift @@ -53,6 +53,8 @@ class LanguageDetailViewController: UITableViewController, UIAlertViewDelegate { log.info("didAppear: LanguageDetailViewController (actually willAppear)") } + // MARK: - Table view data source UITableViewDataSource + override func numberOfSections(in tableView: UITableView) -> Int { return language.keyboards!.count } From ca46e6bb14e42fafa0895035cfa45bd8f64682b0 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Tue, 23 Jul 2019 12:32:25 -0400 Subject: [PATCH 08/47] Table view data source UITableViewDataSource marked --- .../Classes/LanguagePicker/LanguageViewController.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageViewController.swift index 812b36d1d0..4ebd5eaeca 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageViewController.swift @@ -101,7 +101,9 @@ class LanguageViewController: UITableViewController, UIAlertViewDelegate { } else { log.info("didAppear: LanguageViewController") } - } + } + + // MARK: - Table view data source UITableViewDataSource override func numberOfSections(in tableView: UITableView) -> Int { return languages.count From f6e66e7e0ec8345673b8d0d942046ebcd2096dcb Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Tue, 23 Jul 2019 12:32:49 -0400 Subject: [PATCH 09/47] default version string is 1.0 --- .../KeymanEngine/Classes/Model/InstallableLexicalModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Model/InstallableLexicalModel.swift b/ios/engine/KMEI/KeymanEngine/Classes/Model/InstallableLexicalModel.swift index 6786d52d1f..aa2f361577 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Model/InstallableLexicalModel.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Model/InstallableLexicalModel.swift @@ -9,7 +9,7 @@ import Foundation struct InstallableConstants { - static let defaultVersion = "0.1.0" + static let defaultVersion = "1.0" } /// Mainly differs from the API `LexicalModel` by having an associated language. From 1e85c4c6cca82f3b82339e573155c20e4f50cfe0 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Tue, 23 Jul 2019 12:33:33 -0400 Subject: [PATCH 10/47] use dictionaray instead of lexical model for user strings show the name of the model installed when there is only one --- .../Settings/LanguageSettingsViewController.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift index 3e4a2e9a63..795a37814a 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift @@ -170,19 +170,19 @@ class LanguageSettingsViewController: UITableViewController { case 1: cell.textLabel?.text = "Enable predictions" case 2: - cell.textLabel?.text = "Model" + cell.textLabel?.text = "Dictionaries" cell.accessoryType = .disclosureIndicator if let modelCt = language.lexicalModels?.count { switch modelCt { case 0: - cell.detailTextLabel?.text = "no models installed" + cell.detailTextLabel?.text = "no dictionaries installed" case 1: - cell.detailTextLabel?.text = "one model installed" + cell.detailTextLabel?.text = "one dictionary installed: \(language.lexicalModels![0].name)" default: - cell.detailTextLabel?.text = "\(modelCt) models installed" + cell.detailTextLabel?.text = "\(modelCt) dictionaries installed" } } else { - cell.detailTextLabel?.text = "no models installed" + cell.detailTextLabel?.text = "no dictionaries installed" } case 3: // future cell.textLabel?.text = "Manage dictionary" From 641f3c271ae3aab15e787865c8306a58c89edfd1 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Tue, 23 Jul 2019 12:37:38 -0400 Subject: [PATCH 11/47] show more of the lm name by removing boilerplate text in front of it --- .../Classes/Settings/LanguageSettingsViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift index 795a37814a..03e4e7df0e 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift @@ -177,7 +177,7 @@ class LanguageSettingsViewController: UITableViewController { case 0: cell.detailTextLabel?.text = "no dictionaries installed" case 1: - cell.detailTextLabel?.text = "one dictionary installed: \(language.lexicalModels![0].name)" + cell.detailTextLabel?.text = "\(language.lexicalModels![0].name)" default: cell.detailTextLabel?.text = "\(modelCt) dictionaries installed" } From 0828049385d694f970c8325359a1eea6d8bb7d6b Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Tue, 23 Jul 2019 12:39:46 -0400 Subject: [PATCH 12/47] can now download a lexical model from the cloud --- .../LanguageLMDetailViewController.swift | 208 ++++++++++++++++++ .../LanguageLMDetailViewController.xib | 26 +++ .../LexicalModelPickerViewController.swift | 63 +++--- 3 files changed, 272 insertions(+), 25 deletions(-) create mode 100644 ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.swift create mode 100644 ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.xib diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.swift new file mode 100644 index 0000000000..2a51dab7c3 --- /dev/null +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.swift @@ -0,0 +1,208 @@ +// +// LanguageLMDetailViewController.swift +// KeymanEngine +// +// Created by Randy Boring on 7/19/19. +// Copyright © 2019 SIL International. All rights reserved. +// + + +import UIKit + +private let toolbarButtonTag = 100 +private let toolbarLabelTag = 101 +private let toolbarActivityIndicatorTag = 102 + +class LanguageLMDetailViewController: UITableViewController, UIAlertViewDelegate { + private var userLexicalModels: [String: InstallableLexicalModel] = [:] + private var isUpdate = false + private let language: Language + public var lexicalModels: [LexicalModel]? = nil + + private var lexicalModelDownloadStartedObserver: NotificationObserver? + private var lexicalModelDownloadFailedObserver: NotificationObserver? + + init(language: Language) { + self.language = language + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + super.loadView() + loadUserLexicalModels() + tableView.dataSource = self + } + + override func viewDidLoad() { + super.viewDidLoad() + lexicalModelDownloadStartedObserver = NotificationCenter.default.addObserver( + forName: Notifications.lexicalModelDownloadStarted, + observer: self, + function: LanguageLMDetailViewController.lexicalModelDownloadStarted) + lexicalModelDownloadFailedObserver = NotificationCenter.default.addObserver( + forName: Notifications.lexicalModelDownloadFailed, + observer: self, + function: LanguageLMDetailViewController.lexicalModelDownloadFailed) + log.info("viewDidLoad: LanguageLMDetailViewController (registered for lexicalModelDownloadStarted)") + } + + override open func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + log.info("didAppear: LanguageLMDetailViewController (actually willAppear)") + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + log.info("didAppear: LanguageLMDetailViewController") + + navigationController?.setToolbarHidden(true, animated: true) + } + + // MARK: - Table view data source UITableViewDataSource + + override func numberOfSections(in tableView: UITableView) -> Int { + return lexicalModels!.count + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cellIdentifier = "Cell" + if let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) { + return cell + } + + let cell = KeyboardNameTableViewCell(style: .subtitle, reuseIdentifier: cellIdentifier) + let selectionColor = UIView() + selectionColor.backgroundColor = UIColor(red: 204.0 / 255.0, green: 136.0 / 255.0, blue: 34.0 / 255.0, alpha: 1.0) + cell.selectedBackgroundView = selectionColor + return cell + } + + override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + let lexicalModel = lexicalModels![indexPath.section] + let cell = cell as! KeyboardNameTableViewCell + cell.indexPath = indexPath + cell.textLabel?.text = lexicalModel.name + if isAdded(languageID: language.id, lexicalModelID: lexicalModel.id) { + cell.accessoryType = .checkmark + cell.isUserInteractionEnabled = false + cell.textLabel?.isEnabled = false + cell.detailTextLabel?.isEnabled = false + } else { + cell.accessoryType = .none + cell.isUserInteractionEnabled = true + cell.textLabel?.isEnabled = true + cell.detailTextLabel?.isEnabled = true + } + + let kbState = Manager.shared.stateForLexicalModel(withID: lexicalModel.id) + cell.setKeyboardState(kbState, selected: false, defaultAccessoryType: cell.accessoryType) + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.cellForRow(at: indexPath)?.isSelected = false + let lexicalModelIndex = indexPath.section + let lexicalModel = lexicalModels![lexicalModelIndex] + + let state = Manager.shared.stateForLexicalModel(withID: lexicalModel.id) + if state != .downloading { + if state == .needsDownload { + isUpdate = false + } else { + isUpdate = true + } + + let alertController = UIAlertController(title: "\(language.name): \(lexicalModel.name)", + message: "Would you like to download this dictionary?", + preferredStyle: UIAlertControllerStyle.alert) + alertController.addAction(UIAlertAction(title: "Cancel", + style: UIAlertActionStyle.cancel, + handler: nil)) + alertController.addAction(UIAlertAction(title: "Download", + style: UIAlertActionStyle.default, + handler: {_ in self.downloadHandler(lexicalModelIndex)} )) + + self.present(alertController, animated: true, completion: nil) + } + } + + func downloadHandler(_ lexicalModelIndex: Int) { +// Manager.shared.downloadLexicalModel(withID: lexicalModels![lexicalModelIndex].id, +// languageID: language.id, isUpdate: isUpdate) + Manager.shared.downloadLexicalModelPackage(string: (lexicalModels?[lexicalModelIndex].packageFilename)!) + /* + if let packageURL = URLComponents(string: (lexicalModels?[lexicalModelIndex].packageFilename)!) { + Manager.shared.downloadLexicalModel(from: packageURL.url!) + } else { + log.error("couldn't make url to download \(lexicalModels?[lexicalModelIndex].packageFilename)") + } + */ + } + + private func lexicalModelDownloadStarted() { + log.info("lexicalModelDownloadStarted: LanguageLMDetailViewController") + view.isUserInteractionEnabled = false + navigationItem.setHidesBackButton(true, animated: true) + + let toolbarFrame = navigationController!.toolbar.frame + let labelFrame = CGRect(origin: toolbarFrame.origin, + size: CGSize(width: toolbarFrame.width * 0.95, height: toolbarFrame.height * 0.7)) + let label = UILabel(frame: labelFrame) + label.backgroundColor = UIColor.clear + label.textColor = UIColor.white + label.textAlignment = .center + label.center = CGPoint(x: toolbarFrame.width * 0.5, y: toolbarFrame.height * 0.5) + label.text = "Downloading\u{2026}" + label.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin, + .flexibleBottomMargin, .flexibleWidth, .flexibleHeight] + label.tag = toolbarLabelTag + + let indicatorView = UIActivityIndicatorView(activityIndicatorStyle: .gray) + indicatorView.center = CGPoint(x: toolbarFrame.width - indicatorView.frame.width, + y: toolbarFrame.height * 0.5) + indicatorView.autoresizingMask = [.flexibleLeftMargin, .flexibleTopMargin, .flexibleBottomMargin] + indicatorView.tag = toolbarActivityIndicatorTag + indicatorView.startAnimating() + + navigationController?.toolbar.viewWithTag(toolbarButtonTag)?.removeFromSuperview() + navigationController?.toolbar.viewWithTag(toolbarLabelTag)?.removeFromSuperview() + navigationController?.toolbar.viewWithTag(toolbarActivityIndicatorTag)?.removeFromSuperview() + navigationController?.toolbar.addSubview(label) + navigationController?.toolbar.addSubview(indicatorView) + navigationController?.setToolbarHidden(false, animated: true) + } + + private func lexicalModelDownloadFailed() { + log.info("lexicalModelDownloadFailed: LanguageLMDetailViewController") + view.isUserInteractionEnabled = true + navigationItem.setHidesBackButton(false, animated: true) + } + + private func loadUserLexicalModels() { + guard let userLmList = Storage.active.userDefaults.userLexicalModels, !userLmList.isEmpty else { + userLexicalModels = [:] + return + } + + userLexicalModels = [:] + for lm in userLmList { + let dictKey = "\(lm.languageID)_\(lm.id)" + userLexicalModels[dictKey] = lm + } + } + + private func isAdded(languageID: String?, lexicalModelID: String?) -> Bool { + guard let languageID = languageID, let lexicalModelID = lexicalModelID else { + return false + } + return userLexicalModels["\(languageID)_\(lexicalModelID)"] != nil + } +} diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.xib b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.xib new file mode 100644 index 0000000000..d379dc8b53 --- /dev/null +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.xib @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift index fd169b54a8..f354001334 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift @@ -15,7 +15,7 @@ private let toolbarActivityIndicatorTag = 102 class LexicalModelPickerViewController: UITableViewController, UIAlertViewDelegate { private var userLexicalModels: [InstallableLexicalModel] = [InstallableLexicalModel]() - public var language: Language? = nil + public var language: Language! private var updateQueue: [InstallableLexicalModel]? private var _isDoneButtonEnabled = false private var isDidUpdateCheck = false @@ -24,17 +24,19 @@ class LexicalModelPickerViewController: UITableViewController, UIAlertViewDelega private var lexicalModelDownloadCompletedObserver: NotificationObserver? private var lexicalModelDownloadFailedObserver: NotificationObserver? + public init(_ language: Language) { + self.language = language + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func viewDidLoad() { super.viewDidLoad() - if let langName = language?.name { - title = "\(langName) Lexical Models" - } else { - title = "Lexical Models" - } - if language == nil { - setIsDoneButtonEnabled(false) - } + title = "\(language.name) Dictionaries" isDidUpdateCheck = false updateQueue = nil if Manager.shared.canAddNewLexicalModels { @@ -137,9 +139,6 @@ class LexicalModelPickerViewController: UITableViewController, UIAlertViewDelega if Manager.shared.removeLexicalModel(at: globalIndex) { loadUserLexicalModels() } - if language == nil { - setIsDoneButtonEnabled(true) - } } override func tableView(_ tableView: UITableView, @@ -148,9 +147,6 @@ class LexicalModelPickerViewController: UITableViewController, UIAlertViewDelega } func showLexicalModelInfoView(with index: Int) { - if language == nil { - setIsDoneButtonEnabled(true) - } let lm = userLexicalModels[index] let version = lm.version @@ -238,14 +234,14 @@ class LexicalModelPickerViewController: UITableViewController, UIAlertViewDelega } updateQueue = nil let label = navigationController?.toolbar?.viewWithTag(toolbarLabelTag) as? UILabel - label?.text = "Lexical models successfully updated!" + label?.text = "Dictionaries successfully updated!" navigationController?.toolbar?.viewWithTag(toolbarActivityIndicatorTag)?.removeFromSuperview() Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(self.hideToolbarDelayed), userInfo: nil, repeats: false) } } else { let label = navigationController?.toolbar?.viewWithTag(toolbarLabelTag) as? UILabel - label?.text = "Lexical model successfully downloaded!" + label?.text = "Dictionary successfully downloaded!" navigationController?.toolbar?.viewWithTag(toolbarActivityIndicatorTag)?.removeFromSuperview() Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(self.hideToolbarDelayed), userInfo: nil, repeats: false) @@ -276,9 +272,9 @@ class LexicalModelPickerViewController: UITableViewController, UIAlertViewDelega let title: String if view == navigationController?.topViewController?.view { updateQueue = nil - title = "Lexical model Update Error" + title = "Dictionary Update Error" } else { - title = "Lexical model Download Error" + title = "Dictionary Download Error" } navigationController?.setToolbarHidden(true, animated: true) @@ -421,13 +417,30 @@ class LexicalModelPickerViewController: UITableViewController, UIAlertViewDelega } func showAddLexicalModel() { - let button: UIButton? = (navigationController?.toolbar?.viewWithTag(toolbarButtonTag) as? UIButton) - button?.isEnabled = false - let vc = LanguageViewController(Manager.shared.apiLexicalModelRepository) //may need to be different for models - navigationController?.pushViewController(vc, animated: true) - if language == nil { - setIsDoneButtonEnabled(true) + //get list of lexical models for this languageID and show it + func listCompletionHandler(lexicalModels: [LexicalModel]?, error: Error?) -> Void { + if let error = error { + log.info("Failed to fetch lexical model list for "+language.id+". error: "+(error as! String)) + self.lexicalModelDownloadFailed(LexicalModelDownloadFailedNotification(lmOrLanguageID: language.id, error: error)) + } else if nil == lexicalModels { + log.info("No lexical models available for language \(language.id) (nil)") + } else if 0 == lexicalModels?.count { + log.info("No lexical models available for language \(language.id) (empty)") + } else { + log.info("Fetched lexical model list for "+language.id+".") + // show the list of lexical models (on the main thread) + DispatchQueue.main.async { + let button: UIButton? = (self.navigationController?.toolbar?.viewWithTag(toolbarButtonTag) as? UIButton) + button?.isEnabled = false + let vc = LanguageLMDetailViewController(language: self.language) + vc.lexicalModels = lexicalModels! + self.navigationController?.pushViewController(vc, animated: true) + } + } } + + Manager.shared.apiLexicalModelRepository.fetchList(languageID: language.id, completionHandler: listCompletionHandler) } + } From af2544eb378f7e1630e5bc5ae2ba36456cc86763 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Tue, 23 Jul 2019 22:28:27 -0400 Subject: [PATCH 13/47] change model or lexical model to dictionary --- .../LanguagePicker/LexicalModelInfoViewController.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelInfoViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelInfoViewController.swift index 67e50e5a1a..3ddeb28165 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelInfoViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelInfoViewController.swift @@ -24,7 +24,7 @@ class LexicalModelInfoViewController: UITableViewController, UIAlertViewDelegate infoArray = [[String: String]]() infoArray.append([ - "title": "Model version", + "title": "Dictionary version", "subtitle": lexicalModelVersion ]) @@ -35,7 +35,7 @@ class LexicalModelInfoViewController: UITableViewController, UIAlertViewDelegate ]) } infoArray.append([ - "title": "Uninstall model", + "title": "Uninstall dictionary", "subtitle": "" ]) } @@ -135,7 +135,7 @@ class LexicalModelInfoViewController: UITableViewController, UIAlertViewDelegate } private func showDeleteLexicalModel() { - let alertController = UIAlertController(title: title ?? "", message: "Would you like to delete this lexical model?", + let alertController = UIAlertController(title: title ?? "", message: "Would you like to delete this dictionary?", preferredStyle: UIAlertControllerStyle.alert) alertController.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, From 90b381a8cf64d444e59eba08757d00a2648aaa99 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Wed, 24 Jul 2019 11:07:02 -0400 Subject: [PATCH 14/47] add missing paren for setBannerHeight JavaScript --- .../KMEI/KeymanEngine/Classes/KeymanWebViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift index 71392db777..56a4ba9457 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift @@ -293,7 +293,7 @@ extension KeymanWebViewController { func setBannerHeight(to height: Int) { // TODO: - webView?.evaluateJavaScript("setBannerHeight(\(height);", completionHandler: nil) + webView?.evaluateJavaScript("setBannerHeight(\(height));", completionHandler: nil) } } From 4d21aa6cd442d1c48d571318ac52c7ac7cefcf40 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Wed, 24 Jul 2019 11:14:58 -0400 Subject: [PATCH 15/47] proper info.log text, removed commented-out code --- .../LanguagePicker/LanguageDetailViewController.swift | 2 +- .../LanguageLMDetailViewController.swift | 11 +---------- .../Classes/Settings/SettingsViewController.swift | 2 +- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageDetailViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageDetailViewController.swift index 4e956a9c68..5244297180 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageDetailViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageDetailViewController.swift @@ -50,7 +50,7 @@ class LanguageDetailViewController: UITableViewController, UIAlertViewDelegate { override open func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - log.info("didAppear: LanguageDetailViewController (actually willAppear)") + log.info("willAppear: LanguageDetailViewController") } // MARK: - Table view data source UITableViewDataSource diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.swift index 2a51dab7c3..adf9c370aa 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.swift @@ -53,7 +53,7 @@ class LanguageLMDetailViewController: UITableViewController, UIAlertViewDelegate override open func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - log.info("didAppear: LanguageLMDetailViewController (actually willAppear)") + log.info("willAppear: LanguageLMDetailViewController") } override func viewDidAppear(_ animated: Bool) { @@ -135,16 +135,7 @@ class LanguageLMDetailViewController: UITableViewController, UIAlertViewDelegate } func downloadHandler(_ lexicalModelIndex: Int) { -// Manager.shared.downloadLexicalModel(withID: lexicalModels![lexicalModelIndex].id, -// languageID: language.id, isUpdate: isUpdate) Manager.shared.downloadLexicalModelPackage(string: (lexicalModels?[lexicalModelIndex].packageFilename)!) - /* - if let packageURL = URLComponents(string: (lexicalModels?[lexicalModelIndex].packageFilename)!) { - Manager.shared.downloadLexicalModel(from: packageURL.url!) - } else { - log.error("couldn't make url to download \(lexicalModels?[lexicalModelIndex].packageFilename)") - } - */ } private func lexicalModelDownloadStarted() { diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Settings/SettingsViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/Settings/SettingsViewController.swift index a8c2c8388f..4377a8bedc 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Settings/SettingsViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Settings/SettingsViewController.swift @@ -16,7 +16,7 @@ open class SettingsViewController: UITableViewController { super.viewWillAppear(animated) loadUserLanguages() - log.info("didAppear: SettingsViewController (actually willAppear)") + log.info("willAppear: SettingsViewController") } override open func viewDidLoad() { From 1750da81000970192732960c1d9a45673fa382f5 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Wed, 24 Jul 2019 11:39:52 -0400 Subject: [PATCH 16/47] use Dictionary instead of Lexical Model for user strings --- .../Classes/Settings/InstalledLanguagesViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift index 0260f10e16..512412735b 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift @@ -336,7 +336,7 @@ class InstalledLanguagesViewController: UITableViewController, UIAlertViewDelega log.info("lexicalModelDownloadFailed: InstalledLanguagesViewController") restoreNavigation() - let title = "Lexical Model Download Error" + let title = "Dicionary Download Error" navigationController?.setToolbarHidden(true, animated: true) let alertController = UIAlertController(title: title, message: "", From a595b8b72d32411f1dd00a00e79008afd167d576 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Wed, 24 Jul 2019 11:40:22 -0400 Subject: [PATCH 17/47] put code that will call UI onto the main thread with DispatchQueue.main.async --- .../LanguagePicker/LexicalModelPickerViewController.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift index f354001334..16df22d07a 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift @@ -421,7 +421,9 @@ class LexicalModelPickerViewController: UITableViewController, UIAlertViewDelega func listCompletionHandler(lexicalModels: [LexicalModel]?, error: Error?) -> Void { if let error = error { log.info("Failed to fetch lexical model list for "+language.id+". error: "+(error as! String)) - self.lexicalModelDownloadFailed(LexicalModelDownloadFailedNotification(lmOrLanguageID: language.id, error: error)) + DispatchQueue.main.async { + self.lexicalModelDownloadFailed(LexicalModelDownloadFailedNotification(lmOrLanguageID: language.id, error: error)) + } } else if nil == lexicalModels { log.info("No lexical models available for language \(language.id) (nil)") } else if 0 == lexicalModels?.count { From b3bdeedaeeac4873f31e49898e7c59e026a065ed Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Wed, 24 Jul 2019 11:41:27 -0400 Subject: [PATCH 18/47] oops, committed before checking that it built without error. Needed "self." --- .../LanguagePicker/LexicalModelPickerViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift index 16df22d07a..7aa16a7c63 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift @@ -422,7 +422,7 @@ class LexicalModelPickerViewController: UITableViewController, UIAlertViewDelega if let error = error { log.info("Failed to fetch lexical model list for "+language.id+". error: "+(error as! String)) DispatchQueue.main.async { - self.lexicalModelDownloadFailed(LexicalModelDownloadFailedNotification(lmOrLanguageID: language.id, error: error)) + self.lexicalModelDownloadFailed(LexicalModelDownloadFailedNotification(lmOrLanguageID: self.language.id, error: error)) } } else if nil == lexicalModels { log.info("No lexical models available for language \(language.id) (nil)") From 3508d4d45c9c82632ee4c3943899e2f21d572a46 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Wed, 24 Jul 2019 13:38:20 -0400 Subject: [PATCH 19/47] rename for clarity, make it possible to view info on selected lexical model --- .../Classes/LanguagePicker/KeyboardNameTableViewCell.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardNameTableViewCell.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardNameTableViewCell.swift index 5b71148716..1f671e2102 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardNameTableViewCell.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardNameTableViewCell.swift @@ -29,9 +29,9 @@ class KeyboardNameTableViewCell: UITableViewCell, UIAlertViewDelegate { } self.accessoryType = accessoryType - let isSelectedView = viewWithTag(cellSelectedTag) + let selectedView = viewWithTag(cellSelectedTag) if isSelected { - if isSelectedView == nil { + if selectedView == nil { let view = UIView(frame: CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height)) view.tag = cellSelectedTag view.backgroundColor = UIColor.green @@ -39,7 +39,7 @@ class KeyboardNameTableViewCell: UITableViewCell, UIAlertViewDelegate { addSubview(view) } } else { - isSelectedView?.removeFromSuperview() + selectedView?.removeFromSuperview() } } } From 69d7a02c5ea783c2116efbbca7eff15b096e1ad4 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Wed, 24 Jul 2019 13:39:43 -0400 Subject: [PATCH 20/47] make possible to view info on the selected lexical model --- .../LanguagePicker/LexicalModelPickerViewController.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift index 7aa16a7c63..129c285b06 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift @@ -176,7 +176,7 @@ class LexicalModelPickerViewController: UITableViewController, UIAlertViewDelega if Manager.shared.currentLexicalModelID == lm.fullID { cell.selectionStyle = .blue cell.isSelected = true - cell.accessoryType = .checkmark + cell.accessoryType = .detailDisclosureButton } else { cell.selectionStyle = .none cell.isSelected = false @@ -388,8 +388,8 @@ class LexicalModelPickerViewController: UITableViewController, UIAlertViewDelega } private func scroll(toSelectedLexicalModel animated: Bool) { - let index = userLexicalModels.index { kb in - return Manager.shared.currentLexicalModelID == kb.fullID + let index = userLexicalModels.index { lm in + return Manager.shared.currentLexicalModelID == lm.fullID } if let index = index { From 3868022438baea9661981f2f7b6549356caac55e Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Wed, 24 Jul 2019 22:04:06 -0400 Subject: [PATCH 21/47] remove unnecessary white space --- .../Classes/LanguagePicker/LanguageViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageViewController.swift index 4ebd5eaeca..1aff71e17d 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageViewController.swift @@ -244,7 +244,7 @@ class LanguageViewController: UITableViewController, UIAlertViewDelegate { func downloadHandler(_ keyboardIndex: Int) { let language = languages[selectedSection] let keyboard = language.keyboards![keyboardIndex] - Manager.shared.downloadKeyboard(withID: keyboard.id, languageID: language.id, isUpdate: isUpdate) + Manager.shared.downloadKeyboard(withID: keyboard.id, languageID: language.id, isUpdate: isUpdate) } private func keyboardDownloadStarted() { From 3221941654ac996c02fa86569acb2c21e63e68b4 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Wed, 24 Jul 2019 22:04:42 -0400 Subject: [PATCH 22/47] document that KeyboardState should be renamed ResourceState now that it is used for lexical models, as well, now --- ios/engine/KMEI/KeymanEngine/Classes/Manager.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift index 747092c22c..ace9b222b4 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift @@ -17,7 +17,7 @@ typealias FetchKeyboardsBlock = ([String: Any]?) -> Void // MARK: - Constants -// Possible states that a keyboard can be in +// Possible states that a keyboard or lexical model can be in public enum KeyboardState { case needsDownload case needsUpdate @@ -1266,6 +1266,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat } /// - Returns: The current state for a lexical model + //TODO: rename KeyboardState to ResourceState? so it can be used with both keybaoards and lexical models without confusion public func stateForLexicalModel(withID lexicalModelID: String) -> KeyboardState { if lexicalModelIdForCurrentRequest() == lexicalModelID { return .downloading From c393616fce95bba77cd72161d20fa48acf4a0af9 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Wed, 24 Jul 2019 22:05:57 -0400 Subject: [PATCH 23/47] remove unreachable code, especially isUpdate class variable pass false for update parameter when downloading a lexical model --- .../InstalledLanguagesViewController.swift | 43 ++----------------- 1 file changed, 3 insertions(+), 40 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift index 512412735b..9bedb7729a 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift @@ -20,7 +20,6 @@ class InstalledLanguagesViewController: UITableViewController, UIAlertViewDelega private var sectionIndexTitles: [String] = [] private var indices: [Int] = [] private var selectedSection = 0 - private var isUpdate = false private var installedLanguages: [String: Language] private var languages: [Language] = [] private let keyboardRepository: KeyboardRepository? @@ -165,49 +164,13 @@ class InstalledLanguagesViewController: UITableViewController, UIAlertViewDelega } cell.textLabel?.text = language.name - - if cell.accessoryType == .disclosureIndicator { - return - } - guard let cell = cell as? KeyboardNameTableViewCell else { - return - } - - let keyboardID = language.keyboards![0].id - - cell.accessoryType = .none - cell.isUserInteractionEnabled = true - cell.textLabel?.isEnabled = true - cell.detailTextLabel?.isEnabled = true - - let kbState = Manager.shared.stateForKeyboard(withID: keyboardID) - cell.setKeyboardState(kbState, selected: false, defaultAccessoryType: cell.accessoryType) } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { selectedSection = indexPath.section tableView.cellForRow(at: indexPath)?.isSelected = false - if tableView.cellForRow(at: indexPath)?.accessoryType == .disclosureIndicator { - let title = tableView.cellForRow(at: indexPath)?.textLabel?.text ?? "" - showLanguageSettingsView(title: title, languageIndex: indexPath.section) - return - } - - let language = languages[indexPath.section] - let keyboardIndex = 0; - let keyboard = language.keyboards![keyboardIndex] - - //TODO: launch real Language Settings controller here - let languageSettingsController = UIAlertController(title: "\(language.name): \(keyboard.name)", - message: "This should be Language Settings", - preferredStyle: UIAlertControllerStyle.alert) - languageSettingsController.addAction(UIAlertAction(title: "Cancel", - style: UIAlertActionStyle.cancel, - handler: nil)) -// languageSettingsController.addAction(UIAlertAction(title: "Download", -// style: UIAlertActionStyle.default, -// handler: {_ in self.downloadHandler(keyboardIndex)} )) - self.present(languageSettingsController, animated: true, completion: nil) + let title = tableView.cellForRow(at: indexPath)?.textLabel?.text ?? "" + showLanguageSettingsView(title: title, languageIndex: indexPath.section) } override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) { @@ -230,7 +193,7 @@ class InstalledLanguagesViewController: UITableViewController, UIAlertViewDelega func downloadHandler(_ keyboardIndex: Int) { let language = languages[selectedSection] let keyboard = language.keyboards![keyboardIndex] - Manager.shared.downloadKeyboard(withID: keyboard.id, languageID: language.id, isUpdate: isUpdate) + Manager.shared.downloadKeyboard(withID: keyboard.id, languageID: language.id, isUpdate: false) } private func restoreNavigation() { From eaa7c89cbf3a17d95dd660a5c0e78b87626a8141 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Thu, 25 Jul 2019 01:06:43 -0400 Subject: [PATCH 24/47] dictionary/ies instead of lexical model for user string on ad hoc install --- .../KeymanEngine/Classes/Model/LexicalModelKeymanPackage.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Model/LexicalModelKeymanPackage.swift b/ios/engine/KMEI/KeymanEngine/Classes/Model/LexicalModelKeymanPackage.swift index e5c117a914..7f4009b88b 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Model/LexicalModelKeymanPackage.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Model/LexicalModelKeymanPackage.swift @@ -12,7 +12,8 @@ public class LexicalModelKeymanPackage : KeymanPackage { public var models : [KMPLexicalModel]! public override func defaultInfoHtml() -> String { - var str = "Found lexical models in package:
" + let count = models.count + var str = "Found "+(count > 1 ? "\(count) dictionaries" : "dictionary")+" in package:
" for model in models { str += model.lexicalModelId! + "
" } From b6748c84afcb6fa613df2fe6dd8b3830ea8ecd72 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Thu, 25 Jul 2019 02:21:29 -0400 Subject: [PATCH 25/47] set the preferred lexical model to the one the user selects --- .../LanguagePicker/LexicalModelPickerViewController.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift index 129c285b06..571f772f4f 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift @@ -289,7 +289,9 @@ class LexicalModelPickerViewController: UITableViewController, UIAlertViewDelega private func switchLexicalModel(_ index: Int) { // Switch lexicalModel and register to user defaults. - if Manager.shared.registerLexicalModel(userLexicalModels[index]) { + let lm = userLexicalModels[index] + if Manager.shared.registerLexicalModel(lm) { + Storage.active.userDefaults.set(preferredLexicalModelID: lm.id, forKey: lm.languageID) tableView.reloadData() } From f47b78e496cc5711da64ebd4c6bc1f0b6ad10023 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Thu, 25 Jul 2019 02:30:28 -0400 Subject: [PATCH 26/47] remove lexical models from preferred lm per language when deleted add lexical model to preferred lm for current language when selected in LexicalModelPickerViewController set the first lexical model of a language, if any, to current when the current one is deleted --- .../KMEI/KeymanEngine/Classes/Manager.swift | 48 ++++++++++++++----- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift index ace9b222b4..1a1799c3bc 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift @@ -302,6 +302,8 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat // If we have a lexical model for the keyboard's language, activate it. if let preferred_model = preferredLexicalModel(userDefaults, forLanguage: kb.languageID) { _ = Manager.shared.registerLexicalModel(preferred_model) + } else if let first_model = userDefaults.userLexicalModels?.first(where: { $0.languageID == kb.languageID }) { + _ = Manager.shared.registerLexicalModel(first_model) } return true @@ -471,30 +473,50 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat } /// Removes the lexical model at index from the lexical models list if it exists. - /// - Returns: The lexical model exists and was removed - public func removeLexicalModel(at index: Int) -> Bool { - let userData = Storage.active.userDefaults - + public func removeLexicalModelFromUserList(userDefs ud: UserDefaults, at index: Int) -> InstallableLexicalModel? { // If user defaults for lexical models list does not exist, do nothing. - guard var userLexicalModels = userData.userLexicalModels else { - return false + guard var userLexicalModels = ud.userLexicalModels else { + return nil } guard index < userLexicalModels.count else { - return false + return nil } let lm = userLexicalModels[index] + log.info("Removing lexical model with ID \(lm.id) and languageID \(lm.languageID) from user list of all models") userLexicalModels.remove(at: index) - userData.userLexicalModels = userLexicalModels - userData.set([Date()], forKey: Key.synchronizeSWLexicalModel) - userData.synchronize() - - log.info("Removing lexical model with ID \(lm.id) and languageID \(lm.languageID)") + ud.userLexicalModels = userLexicalModels + ud.set([Date()], forKey: Key.synchronizeSWLexicalModel) + ud.synchronize() + return lm +} + + /// Removes the lexical model at index from the lexical models list if it exists. + public func removeLexicalModelFromLanguagePreference(userDefs ud: UserDefaults, _ lm: InstallableLexicalModel) { + log.info("Removing lexical model with ID \(lm.id) and languageID \(lm.languageID) from per-language prefs") + ud.set(preferredLexicalModelID: nil, forKey: lm.languageID) + } + + /// Removes the lexical model at index from the lexical models list if it exists. + /// - Returns: The lexical model exists and was removed + public func removeLexicalModel(at index: Int) -> Bool { + let userData = Storage.active.userDefaults + guard let lm = removeLexicalModelFromUserList(userDefs: userData, at: index) else { + return false + } + removeLexicalModelFromLanguagePreference(userDefs: userData, lm) // Set a new lexical model if deleting the current one + let userLexicalModels = userData.userLexicalModels! //removeLexicalModelFromUserList fails above if this is not present + if lm.fullID == currentLexicalModelID { - _ = registerLexicalModel(userLexicalModels[0]) + if let first_lm = userLexicalModels.first(where: {$0.languageID == lm.languageID}) { + _ = registerLexicalModel(first_lm) + } else { + log.info("no more lexical models available for language \(lm.fullID)") + currentLexicalModelID = nil + } } if !userLexicalModels.contains(where: { $0.id == lm.id }) { From c4177aca8a6357b9822cbee036ee3d085ad1129c Mon Sep 17 00:00:00 2001 From: rfaramir <45110266+rfaramir@users.noreply.github.com> Date: Thu, 25 Jul 2019 03:39:27 -0400 Subject: [PATCH 27/47] Update ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift Co-Authored-By: Joshua Horton --- .../Classes/Settings/InstalledLanguagesViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift index 9bedb7729a..81e01bc95e 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift @@ -299,7 +299,7 @@ class InstalledLanguagesViewController: UITableViewController, UIAlertViewDelega log.info("lexicalModelDownloadFailed: InstalledLanguagesViewController") restoreNavigation() - let title = "Dicionary Download Error" + let title = "Dictionary Download Error" navigationController?.setToolbarHidden(true, animated: true) let alertController = UIAlertController(title: title, message: "", From a09e711f4ac2ae06360c41c4fbd4dc91c4f9fe3c Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 26 Jul 2019 06:52:31 +1000 Subject: [PATCH 28/47] [LMLayer] Make license consistent with rest of Keyman --- common/predictive-text/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/predictive-text/package.json b/common/predictive-text/package.json index 83c32f5fe1..4695cf9a46 100644 --- a/common/predictive-text/package.json +++ b/common/predictive-text/package.json @@ -14,7 +14,7 @@ "url": "git+https://github.com/eddieantonio/keyman-lmlayer-prototype.git" }, "author": "Eddie Antonio Santos (http://eddieantonio.ca/)", - "license": "AGPL-3.0", + "license": "MIT", "bugs": { "url": "https://github.com/eddieantonio/keyman-lmlayer-prototype/issues" }, From e413b96a650d679445c08ea3892bd4542d2f4748 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 26 Jul 2019 07:05:57 +1000 Subject: [PATCH 29/47] [LMLayer] Disable Firefox and Edge in unit tests --- .../unit_tests/in_browser/CI.conf.js | 27 ++++++++++--------- .../unit_tests/in_browser/browser-test.sh | 2 +- .../unit_tests/in_browser/manual.conf.js | 3 ++- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/common/predictive-text/unit_tests/in_browser/CI.conf.js b/common/predictive-text/unit_tests/in_browser/CI.conf.js index 4732a552cf..797e93bbe8 100644 --- a/common/predictive-text/unit_tests/in_browser/CI.conf.js +++ b/common/predictive-text/unit_tests/in_browser/CI.conf.js @@ -73,12 +73,14 @@ module.exports = function(config) { }; var CURRENT_WIN_LAUNCHERS = { - bs_firefox_win: { - os: 'Windows', - os_version: '10', - browser: 'firefox', - browser_version: '62.0' - }, + // Currently, Firefox launcher is unstable; see https://github.com/karma-runner/karma-firefox-launcher/issues/93 + // (in particular "not maintained" commentary). + //bs_firefox_win: { + // os: 'Windows', + // os_version: '10', + // browser: 'firefox', + // browser_version: '62.0' + //}, bs_chrome_win: { os: 'Windows', os_version: '10', @@ -91,12 +93,13 @@ module.exports = function(config) { browser: 'ie', browser_version: '11.0' }, - bs_edge_win: { - os: 'Windows', - os_version: '10', - browser: 'edge', - browser_version: '17.0' - } + // On recent versions of Edge, launcher fails to start and/or stop Edge successfully + //bs_edge_win: { + // os: 'Windows', + // os_version: '10', + // browser: 'edge', + // browser_version: '17.0' + //} } var CURRENT_ANDROID_LAUNCHERS = { diff --git a/common/predictive-text/unit_tests/in_browser/browser-test.sh b/common/predictive-text/unit_tests/in_browser/browser-test.sh index 9266d5b12a..e56d3fe56c 100755 --- a/common/predictive-text/unit_tests/in_browser/browser-test.sh +++ b/common/predictive-text/unit_tests/in_browser/browser-test.sh @@ -32,7 +32,7 @@ get_browser_set_for_OS ( ) { if [ $os_id = "mac" ]; then BROWSERS="--browsers Firefox,Chrome,Safari" elif [ $os_id = "win" ]; then - BROWSERS="--browsers Firefox,Chrome,IE,Edge" + BROWSERS="--browsers Chrome,IE" else BROWSERS="--browsers Firefox,Chrome" fi diff --git a/common/predictive-text/unit_tests/in_browser/manual.conf.js b/common/predictive-text/unit_tests/in_browser/manual.conf.js index 417823fb56..6918d4a0e0 100644 --- a/common/predictive-text/unit_tests/in_browser/manual.conf.js +++ b/common/predictive-text/unit_tests/in_browser/manual.conf.js @@ -9,7 +9,8 @@ module.exports = function(config) { // start these browsers // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: ['Firefox', 'IE', 'Chrome', 'Edge'], // Can be specified at run-time instead! + browsers: ['IE', 'Chrome'], // Can be specified at run-time instead! + // Note: disabled Firefox, Edge due to instability // Future note for us: https://www.npmjs.com/package/karma-browserstack-launcher // Concurrency level From 67917d7d95ced91cee89f85432346ff30a69d1b4 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Thu, 25 Jul 2019 20:32:46 -0500 Subject: [PATCH 30/47] added notes and fixed a typo --- .../LanguagePicker/LanguageLMDetailViewController.swift | 4 +++- .../Classes/Settings/InstalledLanguagesViewController.swift | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.swift index adf9c370aa..3d68ab8bf0 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.swift @@ -15,11 +15,13 @@ private let toolbarActivityIndicatorTag = 102 class LanguageLMDetailViewController: UITableViewController, UIAlertViewDelegate { private var userLexicalModels: [String: InstallableLexicalModel] = [:] - private var isUpdate = false + private var isUpdate = false // unused currently, may be used when we switch to HTTPDownloader private let language: Language public var lexicalModels: [LexicalModel]? = nil private var lexicalModelDownloadStartedObserver: NotificationObserver? + //NOTE: there is no need for a CompletedObserver, as our parent LexicalModelPickerViewController + // is registered for that and deals with it by popping us out to root. private var lexicalModelDownloadFailedObserver: NotificationObserver? init(language: Language) { diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift index 9bedb7729a..81e01bc95e 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift @@ -299,7 +299,7 @@ class InstalledLanguagesViewController: UITableViewController, UIAlertViewDelega log.info("lexicalModelDownloadFailed: InstalledLanguagesViewController") restoreNavigation() - let title = "Dicionary Download Error" + let title = "Dictionary Download Error" navigationController?.setToolbarHidden(true, animated: true) let alertController = UIAlertController(title: title, message: "", From 20fc5dee5a356293f733ee0654991c2f76869b1b Mon Sep 17 00:00:00 2001 From: jahorton Date: Fri, 26 Jul 2019 12:52:17 +0700 Subject: [PATCH 31/47] Fixes the in-app banner issue. --- .../KMEI/KeymanEngine/Classes/InputViewController.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift index 918759d2aa..956b33d5fd 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift @@ -179,8 +179,10 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { open override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // Necessary for existing infrastructure to resend info for the keyboard after reloading - // as system keyboard. - Manager.shared.shouldReloadKeyboard = true + // as system keyboard. Do NOT perform if in-app, as this unnecessarily resets the WebView. + if(Manager.shared.isSystemKeyboard) { + Manager.shared.shouldReloadKeyboard = true + } } open override func textDidChange(_ textInput: UITextInput?) { From 5776cd9138d60cdf14af8023d9d39b702ccafd9d Mon Sep 17 00:00:00 2001 From: jahorton Date: Fri, 26 Jul 2019 16:03:12 +0700 Subject: [PATCH 32/47] Documents the methods of WorkerInternalModel --- .../worker/worker-interfaces.ts | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/common/predictive-text/worker/worker-interfaces.ts b/common/predictive-text/worker/worker-interfaces.ts index e813289306..95bc3a3186 100644 --- a/common/predictive-text/worker/worker-interfaces.ts +++ b/common/predictive-text/worker/worker-interfaces.ts @@ -135,8 +135,54 @@ interface LMLayerWorkerState { * The model implementation, within the Worker. */ interface WorkerInternalModel { + /** + * Processes `config` messages, configuring the newly-loaded model based on the host + * platform's capability restrictions. + * + * This allows the model to configure its suggestions according to what the platform + * allows the host to actually perform - for example, if post-caret deletions are not + * supported, no suggestions requiring this feature should be produced by the model. + * + * Returns a `Configuration` object detailing the capabilities the model plans to + * actually utilize, which must be more restrictive than those indicated within + * the provided `Capabilities` object. + * @param capabilities + */ configure(capabilities: Capabilities): Configuration; + + /** + * Generates predictive suggestions corresponding to the state of context resulting from + * applying a potential transform to the current context state. This transform may correspond + * to a 'correction' of a recent keystroke rather than one actually received. + * + * This method should NOT attempt to perform any form of correction; this is modeled within a + * separate component of the LMLayer predictive engine. That is, "th" + "e" should not be + * have "this" for a suggestion ("e" has been 'corrected' to "i"), while "there" would be + * a reasonable prediction. + * + * However, addition of diacritics to characters (which may transform the underlying char code + * when Unicode-normalized) is permitted. For example, "pur" + "e" may reasonably predict + * "purée", where "e" has been transformed to "é" as part of the suggestion. + * + * When both prediction and correction are permitted, said component (the `ModelCompositor`) will + * generally call this method once per 'likely' generated corrected state of the context, + * utilizing the results to compute an overall likelihood across all possible suggestions. + * @param transform A Transform corresponding to a recent input keystroke + * @param context A depiction of the context to which `transform` is applied. + * @returns A probability distribution (`Distribution`) on the resulting `Suggestion` + * space for use in determining the most optimal overall suggestions. + */ predict(transform: Transform, context: Context): Distribution; + + /** + * Performs a wordbreak operation given the current context state, returning whatever word + * or word fragment exists that starts before the caret but after the most recent whitespace + * preceedin the caret. + * + * This function is designed for use in generating display text for 'keep' `Suggestions` + * and display text for reverting any previously-applied `Suggestions`. + * @param context + */ wordbreak(context: Context): USVString; } From 81023b7932f88c1b2dd0f5e424f945dfdfaa4b67 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 29 Jul 2019 08:07:30 +1000 Subject: [PATCH 33/47] [Android] Force KitKat as minimum supported version --- android/KMAPro/kMAPro/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/KMAPro/kMAPro/build.gradle b/android/KMAPro/kMAPro/build.gradle index 033055f46d..0ab3a071d2 100644 --- a/android/KMAPro/kMAPro/build.gradle +++ b/android/KMAPro/kMAPro/build.gradle @@ -9,7 +9,7 @@ android { defaultConfig { applicationId "com.tavultesoft.kmapro" - minSdkVersion 16 + minSdkVersion 19 targetSdkVersion 28 //println "===DUMPING PROPERTIES===" From 269229565ec62a9dc9b6129bd1b6bd34ea6a5338 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 29 Jul 2019 08:08:53 +1000 Subject: [PATCH 34/47] history.md --- android/history.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/android/history.md b/android/history.md index bdee99089a..cb5daa89c1 100644 --- a/android/history.md +++ b/android/history.md @@ -1,10 +1,9 @@ # Keyman for Android -## 12.0 alpha +## 2019-07-29 12.0 beta * Add new "Settings" menu (#1751) -* Update compile and target Android SDK version to 28 (#1654) -* Add feature to install lexical model packages (#1641, 1653) -* Started work on Keyman for Android 12. +* Add predictive text support (#1641, #1653) +* Minimum supported Android version is now 4.4 (KitKat) (#1905) ## 2019-06-28 11.0.2108 stable * Changes: From 7794370eb7aa1276919c788e22a918039ebfcf92 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 29 Jul 2019 08:17:39 +1000 Subject: [PATCH 35/47] beta build number --- android/history.md | 2 +- web/package-lock.json | 46 +++++++++++++++++++++---------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/android/history.md b/android/history.md index cb5daa89c1..f71df1d60e 100644 --- a/android/history.md +++ b/android/history.md @@ -1,6 +1,6 @@ # Keyman for Android -## 2019-07-29 12.0 beta +## 2019-07-29 12.0.2200 beta * Add new "Settings" menu (#1751) * Add predictive text support (#1641, #1653) * Minimum supported Android version is now 4.4 (KitKat) (#1905) diff --git a/web/package-lock.json b/web/package-lock.json index 027a9b9997..20668cdba4 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -73,13 +73,13 @@ "arraybuffer.slice": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU=", "dev": true }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "integrity": "sha1-5gtrDo8wG9l+U3UhW9pAbIURjAs=", "dev": true }, "async": { @@ -94,7 +94,7 @@ "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg=", "dev": true }, "backo2": { @@ -367,7 +367,7 @@ "color-convert": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "integrity": "sha1-wSYRB66y8pTr/+ye2eytUppgl+0=", "dev": true, "requires": { "color-name": "^1.1.1" @@ -424,7 +424,7 @@ "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", "dev": true }, "cookie": { @@ -484,7 +484,7 @@ "deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "integrity": "sha1-38lARACtHI/gI+faHfHBR8S0RN8=", "dev": true, "requires": { "type-detect": "^4.0.0" @@ -872,7 +872,7 @@ "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -1217,7 +1217,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true } } @@ -1242,7 +1242,7 @@ "karma-chrome-launcher": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", - "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", + "integrity": "sha1-zxudBxNswY/iOTJ9JGVMPbw2is8=", "dev": true, "requires": { "fs-access": "^1.0.0", @@ -1252,7 +1252,7 @@ "karma-edge-launcher": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/karma-edge-launcher/-/karma-edge-launcher-0.4.2.tgz", - "integrity": "sha512-YAJZb1fmRcxNhMIWYsjLuxwODBjh2cSHgTW/jkVmdpGguJjLbs9ZgIK/tEJsMQcBLUkO+yO4LBbqYxqgGW2HIw==", + "integrity": "sha1-PZUpsJsTyQnF887uEtAOf5qYmz0=", "dev": true, "requires": { "edge-launcher": "1.2.2" @@ -1261,7 +1261,7 @@ "karma-firefox-launcher": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/karma-firefox-launcher/-/karma-firefox-launcher-1.1.0.tgz", - "integrity": "sha512-LbZ5/XlIXLeQ3cqnCbYLn+rOVhuMIK9aZwlP6eOLGzWdo1UVp7t6CN3DP4SafiRLjexKwHeKHDm0c38Mtd3VxA==", + "integrity": "sha1-LEcDBFLwRTHrfRPU/HZpYwu5Mzk=", "dev": true }, "karma-fixture": { @@ -1328,7 +1328,7 @@ "ansi-styles": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=", "dev": true, "requires": { "color-convert": "^1.9.0" @@ -1374,7 +1374,7 @@ "karma-teamcity-reporter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/karma-teamcity-reporter/-/karma-teamcity-reporter-1.1.0.tgz", - "integrity": "sha512-Ca1uhHGtNqUuzsnW3I+QykNuS/jF9vdxnIrkbLCVJRunCc6yWJq+ai1UobQT13j0e3JVUOf0mKo3QHZ6A6mG9Q==", + "integrity": "sha1-eYD33JHmqwhH4SKt4Ls0x8b0KBY=", "dev": true }, "linkify-it": { @@ -1405,7 +1405,7 @@ "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "integrity": "sha1-V0Dhxdbw39pK2TI7UzIQfva0xAo=", "dev": true, "requires": { "chalk": "^2.0.1" @@ -1414,7 +1414,7 @@ "ansi-styles": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=", "dev": true, "requires": { "color-convert": "^1.9.0" @@ -1548,7 +1548,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -1863,7 +1863,7 @@ "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -1954,7 +1954,7 @@ "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=", "dev": true }, "safer-buffer": { @@ -2198,7 +2198,7 @@ "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -2258,7 +2258,7 @@ "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", "dev": true, "requires": { "os-tmpdir": "~1.0.2" @@ -2328,7 +2328,7 @@ "ultron": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "integrity": "sha1-n+FTahCmZKZSZqHjzPhf02MCvJw=", "dev": true }, "universalify": { @@ -2418,7 +2418,7 @@ "which": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "integrity": "sha1-/wS9/AEO5UfXgL7DjhrBwnd9JTo=", "dev": true, "requires": { "isexe": "^2.0.0" @@ -2482,7 +2482,7 @@ "ws": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "integrity": "sha1-8c+E/i1ekB686U767OeF8YeiKPI=", "dev": true, "requires": { "async-limiter": "~1.0.0", From efbeafa78e2fb109908f593b67220883e66b9f65 Mon Sep 17 00:00:00 2001 From: jahorton Date: Mon, 29 Jul 2019 05:57:14 +0700 Subject: [PATCH 36/47] PR review polish, round 1 --- common/predictive-text/worker/worker-interfaces.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/predictive-text/worker/worker-interfaces.ts b/common/predictive-text/worker/worker-interfaces.ts index 95bc3a3186..a1c1fe13d4 100644 --- a/common/predictive-text/worker/worker-interfaces.ts +++ b/common/predictive-text/worker/worker-interfaces.ts @@ -144,8 +144,8 @@ interface WorkerInternalModel { * supported, no suggestions requiring this feature should be produced by the model. * * Returns a `Configuration` object detailing the capabilities the model plans to - * actually utilize, which must be more restrictive than those indicated within - * the provided `Capabilities` object. + * actually utilize, which must be as restrictive or more restrictive than those + * indicated within the provided `Capabilities` object. * @param capabilities */ configure(capabilities: Capabilities): Configuration; @@ -177,7 +177,7 @@ interface WorkerInternalModel { /** * Performs a wordbreak operation given the current context state, returning whatever word * or word fragment exists that starts before the caret but after the most recent whitespace - * preceedin the caret. + * preceding the caret. If no such text exists, the the empty string is returned. * * This function is designed for use in generating display text for 'keep' `Suggestions` * and display text for reverting any previously-applied `Suggestions`. From 8f374d24fc0af04aa5c028cae0f97b4a0fb050db Mon Sep 17 00:00:00 2001 From: jahorton Date: Mon, 29 Jul 2019 08:11:06 +0700 Subject: [PATCH 37/47] Missed including this edit. --- common/predictive-text/worker/worker-interfaces.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/predictive-text/worker/worker-interfaces.ts b/common/predictive-text/worker/worker-interfaces.ts index a1c1fe13d4..d08885092b 100644 --- a/common/predictive-text/worker/worker-interfaces.ts +++ b/common/predictive-text/worker/worker-interfaces.ts @@ -151,9 +151,9 @@ interface WorkerInternalModel { configure(capabilities: Capabilities): Configuration; /** - * Generates predictive suggestions corresponding to the state of context resulting from - * applying a potential transform to the current context state. This transform may correspond - * to a 'correction' of a recent keystroke rather than one actually received. + * Generates predictive suggestions corresponding to the state of context after the proposed + * transform is applied to it. This transform may correspond to a 'correction' of a recent + * keystroke rather than one actually received. * * This method should NOT attempt to perform any form of correction; this is modeled within a * separate component of the LMLayer predictive engine. That is, "th" + "e" should not be From 897ae3fee220e494aa207aea478ed8d75101de39 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 29 Jul 2019 15:13:09 +1000 Subject: [PATCH 38/47] [Android] If the keyboard view is not ready, calling javascript functions will crash --- .../java/com/tavultesoft/kmea/KMKeyboard.java | 90 +++++++++++++------ .../java/com/tavultesoft/kmea/KMManager.java | 40 +++++---- 2 files changed, 84 insertions(+), 46 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java index b547bdfc88..dd73fbc35c 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java @@ -62,6 +62,8 @@ final class KMKeyboard extends WebView { private String keyboardName; private String keyboardVersion; + protected ArrayList javascriptAfterLoad = new ArrayList(); + private static String currentKeyboard = null; private static String txtFont = ""; private static String oskFont = null; @@ -136,12 +138,16 @@ final class KMKeyboard extends WebView { public boolean onConsoleMessage(ConsoleMessage cm) { if (KMManager.isDebugMode()) { Log.d("KMEA", "Keyman JS Log: Line " + cm.lineNumber() + ", " + cm.sourceId() + ":" + cm.message()); + if (cm.messageLevel() == ConsoleMessage.MessageLevel.ERROR) { + Log.e("KMEA", "Keyman JS Log: ERROR"); + } } // Send console errors to Firebase Analytics. // (Ignoring spurious message "No keyboard stubs exist = ...") // TODO: Analyze if this error warrants reverting to default keyboard // TODO: Fix base error rather than trying to ignore it "No keyboard stubs exist" + if ((cm.messageLevel() == ConsoleMessage.MessageLevel.ERROR) && (!cm.message().startsWith("No keyboard stubs exist"))) { sendKMWError(cm.lineNumber(), cm.sourceId(), cm.message()); Toast.makeText(context, "Fatal Error with " + currentKeyboard + @@ -151,6 +157,7 @@ final class KMKeyboard extends WebView { KMManager.KMDefault_LanguageID, KMManager.KMDefault_KeyboardName, KMManager.KMDefault_LanguageName, KMManager.KMDefault_KeyboardFont, null); } + return true; } }); @@ -188,15 +195,44 @@ final class KMKeyboard extends WebView { setBackgroundColor(0); } + public void loadJavascript(String func) { + this.javascriptAfterLoad.add(func); + + if((keyboardType == KeyboardType.KEYBOARD_TYPE_INAPP && KMManager.InAppKeyboardLoaded) || + (keyboardType == KeyboardType.KEYBOARD_TYPE_SYSTEM && KMManager.SystemKeyboardLoaded)) { + + if(this.javascriptAfterLoad.size() == 1) + callJavascriptAfterLoad(); + } + } + + public void callJavascriptAfterLoad() { + if(this.javascriptAfterLoad.size() > 0) { + Handler handler = new Handler(); + handler.postDelayed(new Runnable() { + @Override + public void run() { + if(javascriptAfterLoad.size() > 0) { + loadUrl("javascript:" + javascriptAfterLoad.get(0)); + javascriptAfterLoad.remove(0); + if (javascriptAfterLoad.size() > 0) { + callJavascriptAfterLoad(); + } + } + } + }, 1); + } + } + public void hideKeyboard() { - String jsString = "javascript:hideKeyboard()"; - loadUrl(jsString); + String jsString = "hideKeyboard()"; + loadJavascript(jsString); } public void executeHardwareKeystroke(int code, int shift, int lstates, int eventModifiers) { - String jsFormat = "javascript:executeHardwareKeystroke(%d,%d, %d, %d)"; + String jsFormat = "executeHardwareKeystroke(%d,%d, %d, %d)"; String jsString = String.format(jsFormat, code, shift, lstates, eventModifiers); - loadUrl(jsString); + loadJavascript(jsString); } @SuppressLint("ClickableViewAccessibility") @@ -226,8 +262,8 @@ final class KMKeyboard extends WebView { DisplayMetrics dms = context.getResources().getDisplayMetrics(); int kbWidth = (int) (dms.widthPixels / dms.density); // Ensure window is loaded for javascript functions - loadUrl(String.format( - "javascript:window.onload = function(){ setOskWidth(\"%d\");"+ + loadJavascript(String.format( + "window.onload = function(){ setOskWidth(\"%d\");"+ "setOskHeight(\"0\"); };", kbWidth)); if (ShouldShowHelpBubble) { ShouldShowHelpBubble = false; @@ -235,7 +271,7 @@ final class KMKeyboard extends WebView { handler.postDelayed(new Runnable() { @Override public void run() { - loadUrl("javascript:showHelpBubble()"); + loadJavascript("showHelpBubble()"); } }, 2000); } @@ -258,15 +294,15 @@ final class KMKeyboard extends WebView { dismissKeyPreview(0); dismissSubKeysWindow(); int bannerHeight = KMManager.getBannerHeight(context); - loadUrl(String.format("javascript:setBannerHeight(%d)", bannerHeight)); - loadUrl(String.format("javascript:setOskWidth(%d)", newConfig.screenWidthDp)); - loadUrl("javascript:setOskHeight(0)"); + loadJavascript(String.format("setBannerHeight(%d)", bannerHeight)); + loadJavascript(String.format("setOskWidth(%d)", newConfig.screenWidthDp)); + loadJavascript("setOskHeight(0)"); if (dismissHelpBubble()) { Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { - loadUrl("javascript:showHelpBubble()"); + loadJavascript("showHelpBubble()"); } }, 2000); } @@ -386,9 +422,9 @@ final class KMKeyboard extends WebView { keyboardName = keyboardName.replaceAll("\'", "\\\\'"); // Double-escaped-backslash b/c regex. languageName = languageName.replaceAll("\'", "\\\\'"); - String jsFormat = "javascript:setKeymanLanguage('%s','%s','%s','%s','%s', %s, %s, '%s')"; + String jsFormat = "setKeymanLanguage('%s','%s','%s','%s','%s', %s, %s, '%s')"; String jsString = String.format(jsFormat, keyboardName, keyboardID, languageName, languageID, keyboardPath, tFont, oFont, packageID); - loadUrl(jsString); + loadJavascript(jsString); this.packageID = packageID; this.keyboardID = keyboardID; @@ -402,7 +438,7 @@ final class KMKeyboard extends WebView { handler.postDelayed(new Runnable() { @Override public void run() { - loadUrl("javascript:showHelpBubble()"); + loadJavascript("showHelpBubble()"); } }, 2000); } @@ -487,9 +523,9 @@ final class KMKeyboard extends WebView { keyboardName = keyboardName.replaceAll("\'", "\\\\'"); // Double-escaped-backslash b/c regex. languageName = languageName.replaceAll("\'", "\\\\'"); - String jsFormat = "javascript:setKeymanLanguage('%s','%s','%s','%s','%s', %s, %s, '%s')"; + String jsFormat = "setKeymanLanguage('%s','%s','%s','%s','%s', %s, %s, '%s')"; String jsString = String.format(jsFormat, keyboardName, keyboardID, languageName, languageID, keyboardPath, tFont, oFont, packageID); - loadUrl(jsString); + loadJavascript(jsString); this.packageID = packageID; this.keyboardID = keyboardID; @@ -503,7 +539,7 @@ final class KMKeyboard extends WebView { handler.postDelayed(new Runnable() { @Override public void run() { - loadUrl("javascript:showHelpBubble()"); + loadJavascript("showHelpBubble()"); } }, 2000); } @@ -713,14 +749,14 @@ final class KMKeyboard extends WebView { public void onDismiss() { suggestionJSON = null; suggestionMenuWindow = null; - String jsString = "javascript:popupVisible(0)"; - loadUrl(jsString); + String jsString = "popupVisible(0)"; + loadJavascript(jsString); } }); suggestionMenuWindow.showAtLocation(KMKeyboard.this, Gravity.TOP | Gravity.LEFT, posX , posY); - String jsString = "javascript:popupVisible(1)"; - loadUrl(jsString); + String jsString = "popupVisible(1)"; + loadJavascript(jsString); return; } @@ -823,9 +859,9 @@ final class KMKeyboard extends WebView { int index = v.getId() - 1; String keyId = subkeyList.get(index).get("keyId"); String keyText = getSubkeyText(keyId, subkeyList.get(index).get("keyText")); - String jsFormat = "javascript:executePopupKey('%s','%s')"; + String jsFormat = "executePopupKey('%s','%s')"; String jsString = String.format(jsFormat, keyId, keyText); - loadUrl(jsString); + loadJavascript(jsString); } }); button.setClickable(false); @@ -910,8 +946,8 @@ final class KMKeyboard extends WebView { public void onDismiss() { subKeysList = null; subKeysWindow = null; - String jsString = "javascript:popupVisible(0)"; - loadUrl(jsString); + String jsString = "popupVisible(0)"; + loadJavascript(jsString); } }); @@ -934,8 +970,8 @@ final class KMKeyboard extends WebView { // And now to actually display it. subKeysWindow.showAtLocation(KMKeyboard.this, Gravity.TOP | Gravity.LEFT, posX, posY); - String jsString = "javascript:popupVisible(1)"; - loadUrl(jsString); + String jsString = "popupVisible(1)"; + loadJavascript(jsString); } // Attempt to get the subkey text. diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index d2f6f924dc..8dc00e68a7 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -718,11 +718,11 @@ public final class KMManager { RelativeLayout.LayoutParams params = getKeyboardLayoutParams(); if (InAppKeyboard != null && InAppKeyboardLoaded && !InAppKeyboardShouldIgnoreTextChange) { InAppKeyboard.setLayoutParams(params); - InAppKeyboard.loadUrl(String.format("javascript:enableSuggestions(%s, %s, %s)", model, mayPredict, mayCorrect)); + InAppKeyboard.loadJavascript(String.format("enableSuggestions(%s, %s, %s)", model, mayPredict, mayCorrect)); } if (SystemKeyboard != null && SystemKeyboardLoaded && !SystemKeyboardShouldIgnoreTextChange) { SystemKeyboard.setLayoutParams(params); - SystemKeyboard.loadUrl(String.format("javascript:enableSuggestions(%s, %s, %s)", model, mayPredict, mayCorrect)); + SystemKeyboard.loadJavascript(String.format("enableSuggestions(%s, %s, %s)", model, mayPredict, mayCorrect)); } return true; } @@ -733,13 +733,13 @@ public final class KMManager { currentLexicalModel = null; } - String url = String.format("javascript:deregisterModel('%s')", modelID); - if (InAppKeyboard != null && InAppKeyboardLoaded) { - InAppKeyboard.loadUrl(url); + String url = String.format("deregisterModel('%s')", modelID); + if (InAppKeyboard != null) { // && InAppKeyboardLoaded) { + InAppKeyboard.loadJavascript(url); } - if (SystemKeyboard != null && SystemKeyboardLoaded) { - SystemKeyboard.loadUrl(url); + if (SystemKeyboard != null) { // && SystemKeyboardLoaded) { + SystemKeyboard.loadJavascript(url); } return true; } @@ -1103,11 +1103,11 @@ public final class KMManager { public static void setNumericLayer(KeyboardType kbType) { if (kbType == KeyboardType.KEYBOARD_TYPE_INAPP) { if (InAppKeyboard != null && InAppKeyboardLoaded && !InAppKeyboardShouldIgnoreTextChange) { - InAppKeyboard.loadUrl("javascript:setNumericLayer()"); + InAppKeyboard.loadJavascript("setNumericLayer()"); } } else if (kbType == KeyboardType.KEYBOARD_TYPE_SYSTEM) { if (SystemKeyboard != null && SystemKeyboardLoaded && !SystemKeyboardShouldIgnoreTextChange) { - SystemKeyboard.loadUrl("javascript:setNumericLayer()"); + SystemKeyboard.loadJavascript("setNumericLayer()"); } } } @@ -1121,14 +1121,14 @@ public final class KMManager { if (kbType == KeyboardType.KEYBOARD_TYPE_INAPP) { if (InAppKeyboard != null && InAppKeyboardLoaded && !InAppKeyboardShouldIgnoreTextChange) { - InAppKeyboard.loadUrl(String.format("javascript:updateKMText('%s')", kmText)); + InAppKeyboard.loadJavascript(String.format("updateKMText('%s')", kmText)); result = true; } InAppKeyboardShouldIgnoreTextChange = false; } else if (kbType == KeyboardType.KEYBOARD_TYPE_SYSTEM) { if (SystemKeyboard != null && SystemKeyboardLoaded && !SystemKeyboardShouldIgnoreTextChange) { - SystemKeyboard.loadUrl(String.format("javascript:updateKMText('%s')", kmText)); + SystemKeyboard.loadJavascript(String.format("updateKMText('%s')", kmText)); result = true; } @@ -1142,7 +1142,7 @@ public final class KMManager { boolean result = false; if (kbType == KeyboardType.KEYBOARD_TYPE_INAPP) { if (InAppKeyboard != null && InAppKeyboardLoaded && !InAppKeyboardShouldIgnoreSelectionChange) { - InAppKeyboard.loadUrl(String.format("javascript:updateKMSelectionRange(%d,%d)", selStart, selEnd)); + InAppKeyboard.loadJavascript(String.format("updateKMSelectionRange(%d,%d)", selStart, selEnd)); result = true; } @@ -1157,7 +1157,7 @@ public final class KMManager { } } - SystemKeyboard.loadUrl(String.format("javascript:updateKMSelectionRange(%d,%d)", selStart, selEnd)); + SystemKeyboard.loadJavascript(String.format("updateKMSelectionRange(%d,%d)", selStart, selEnd)); result = true; } @@ -1170,11 +1170,11 @@ public final class KMManager { public static void resetContext(KeyboardType kbType) { if (kbType == KeyboardType.KEYBOARD_TYPE_INAPP) { if (InAppKeyboard != null && InAppKeyboardLoaded) { - InAppKeyboard.loadUrl("javascript:resetContext()"); + InAppKeyboard.loadJavascript("resetContext()"); } } else if (kbType == KeyboardType.KEYBOARD_TYPE_SYSTEM) { if (SystemKeyboard != null && SystemKeyboardLoaded) { - SystemKeyboard.loadUrl("javascript:resetContext()"); + SystemKeyboard.loadJavascript("resetContext()"); } } } @@ -1301,7 +1301,7 @@ public final class KMManager { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { - if (url.endsWith(KMFilename_KeyboardHtml)) { + if (url.startsWith("file")) { // endsWith(KMFilename_KeyboardHtml)) { InAppKeyboardLoaded = false; } } @@ -1309,7 +1309,7 @@ public final class KMManager { @Override public void onPageFinished(WebView view, String url) { String langId = KMManager.KMKey_LanguageID; - if (url.endsWith(KMFilename_KeyboardHtml)) { + if (url.startsWith("file")) { //endsWith(KMFilename_KeyboardHtml)) { InAppKeyboardLoaded = true; if (!InAppKeyboard.keyboardSet) { @@ -1342,11 +1342,13 @@ public final class KMManager { public void run() { SharedPreferences prefs = context.getSharedPreferences(context.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); if (prefs.getBoolean(KMManager.KMKey_ShouldShowHelpBubble, true)) { - InAppKeyboard.loadUrl("javascript:showHelpBubble()"); + InAppKeyboard.loadJavascript("showHelpBubble()"); } } }, 2000); + InAppKeyboard.callJavascriptAfterLoad(); + KeyboardEventHandler.notifyListeners(KMTextView.kbEventListeners, KeyboardType.KEYBOARD_TYPE_INAPP, EventType.KEYBOARD_LOADED, null); } @@ -1557,7 +1559,7 @@ public final class KMManager { public void run() { SharedPreferences prefs = context.getSharedPreferences(context.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); if (prefs.getBoolean(KMManager.KMKey_ShouldShowHelpBubble, true)) { - SystemKeyboard.loadUrl("javascript:showHelpBubble()"); + SystemKeyboard.loadJavascript("showHelpBubble()"); } } }, 2000); From 96ad12a0feef2ed3381c421e91cf199110c6be4f Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 29 Jul 2019 15:17:08 +1000 Subject: [PATCH 39/47] [Android] Move the loaded flag before the start of the page load --- .../src/main/java/com/tavultesoft/kmea/KMKeyboard.java | 6 ++++++ .../app/src/main/java/com/tavultesoft/kmea/KMManager.java | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java index dd73fbc35c..3a5d26d555 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java @@ -190,6 +190,12 @@ final class KMKeyboard extends WebView { public void loadKeyboard() { keyboardSet = false; + + if(keyboardType == KeyboardType.KEYBOARD_TYPE_INAPP) + KMManager.InAppKeyboardLoaded = false; + else + KMManager.SystemKeyboardLoaded = false; + String htmlPath = "file://" + getContext().getDir("data", Context.MODE_PRIVATE) + "/" + KMManager.KMFilename_KeyboardHtml; loadUrl(htmlPath); setBackgroundColor(0); diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index 8dc00e68a7..dc3996427b 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -1301,9 +1301,9 @@ public final class KMManager { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { - if (url.startsWith("file")) { // endsWith(KMFilename_KeyboardHtml)) { + /*if (url.startsWith("file")) { // endsWith(KMFilename_KeyboardHtml)) { InAppKeyboardLoaded = false; - } + }*/ } @Override @@ -1519,9 +1519,9 @@ public final class KMManager { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { - if (url.endsWith(KMFilename_KeyboardHtml)) { + /*if (url.endsWith(KMFilename_KeyboardHtml)) { SystemKeyboardLoaded = false; - } + }*/ } @Override From 277d849383ef4cfd44768135869b4d68ddb3ddd7 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 29 Jul 2019 19:54:22 +1000 Subject: [PATCH 40/47] [Android] Don't fire finished event until after onload event; guarantees JS is ready --- .../KMEA/app/src/main/assets/keyboard.html | 14 ++++++++- .../java/com/tavultesoft/kmea/KMManager.java | 30 ++++++++++++------- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/android/KMEA/app/src/main/assets/keyboard.html b/android/KMEA/app/src/main/assets/keyboard.html index 8a4e5adf3c..a0eebfa92a 100644 --- a/android/KMEA/app/src/main/assets/keyboard.html +++ b/android/KMEA/app/src/main/assets/keyboard.html @@ -12,6 +12,7 @@ var device = window.jsInterface.getDeviceType(); var oskHeight = window.jsInterface.getKeyboardHeight(); var oskWidth = 0; + var fragmentToggle = 0; window.addEventListener('load', init, false); function init() { @@ -39,6 +40,18 @@ kmw.addEventListener('keyboardloaded', setIsChiral); kmw.addEventListener('keyboardchange', setIsChiral); kmw.addEventListener('mm.modelchange', onModelChange); + + notifyHost('pageLoaded'); + } + + function notifyHost(event, params) { + // TODO: Update all other host notifications to use notifyHost instead of directly setting window.location.hash + window.setTimeout(function() { + // We use a timeout so that the navigation doesn't cause the calling function to abort after the call + fragmentToggle = (fragmentToggle + 1) % 100; + params = params ? '+'+params : ''; + window.location.hash = event+'-'+fragmentToggle+params; + }, 10); } // Update the KMW banner height @@ -211,7 +224,6 @@ kmw['setActiveElement'](ta); } - var fragmentToggle = 0; function oskCreateKeyPreview(x,y,w,h,t) { fragmentToggle = (fragmentToggle + 1) % 100; var div = document.createElement('div'); diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index dc3996427b..ce0a660fd4 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -1308,7 +1308,13 @@ public final class KMManager { @Override public void onPageFinished(WebView view, String url) { + Log.d("KMEA", "onPageFinished: [inapp] " + url); + shouldOverrideUrlLoading(view, url); + } + + private void pageLoaded(WebView view, String url) { String langId = KMManager.KMKey_LanguageID; + Log.d("KMEA", "pageLoaded: [inapp] " + url); if (url.startsWith("file")) { //endsWith(KMFilename_KeyboardHtml)) { InAppKeyboardLoaded = true; @@ -1351,13 +1357,14 @@ public final class KMManager { KeyboardEventHandler.notifyListeners(KMTextView.kbEventListeners, KeyboardType.KEYBOARD_TYPE_INAPP, EventType.KEYBOARD_LOADED, null); } - - shouldOverrideUrlLoading(view, url); } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { - if (url.indexOf("hideKeyboard") >= 0) { + Log.d("KMEA", "shouldOverrideUrlLoading [inapp]: "+url); + if(url.indexOf("pageLoaded") >= 0) { + pageLoaded(view, url); + } else if (url.indexOf("hideKeyboard") >= 0) { if (KMTextView.activeView != null && KMTextView.activeView.getClass() == KMTextView.class) { InAppKeyboard.dismissHelpBubble(); KMTextView textView = (KMTextView) KMTextView.activeView; @@ -1519,15 +1526,18 @@ public final class KMManager { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { - /*if (url.endsWith(KMFilename_KeyboardHtml)) { - SystemKeyboardLoaded = false; - }*/ } @Override public void onPageFinished(WebView view, String url) { + Log.d("KMEA", "onPageFinished: [system] " + url); + shouldOverrideUrlLoading(view, url); + } + + private void pageLoaded(WebView view, String url) { String langId = KMManager.KMKey_LanguageID; - if (url.endsWith(KMFilename_KeyboardHtml)) { + Log.d("KMEA", "pageLoaded: [system] " + url); + if (url.startsWith("file:")) { SystemKeyboardLoaded = true; if (!SystemKeyboard.keyboardSet) { SharedPreferences prefs = context.getSharedPreferences(context.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); @@ -1566,13 +1576,13 @@ public final class KMManager { KeyboardEventHandler.notifyListeners(KMTextView.kbEventListeners, KeyboardType.KEYBOARD_TYPE_SYSTEM, EventType.KEYBOARD_LOADED, null); } - - shouldOverrideUrlLoading(view, url); } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { - if (url.indexOf("hideKeyboard") >= 0) { + if(url.indexOf("pageLoaded") >= 0) { + pageLoaded(view, url); + } else if (url.indexOf("hideKeyboard") >= 0) { SystemKeyboard.dismissHelpBubble(); IMService.requestHideSelf(0); } else if (url.indexOf("globeKeyAction") >= 0) { From eebeb5e8e6d633de2d0d343b568d6c628f771618 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 29 Jul 2019 19:55:35 +1000 Subject: [PATCH 41/47] [Android] javascript after load for system as well as inapp --- .../java/com/tavultesoft/kmea/KMManager.java | 2 + web/package-lock.json | 46 +++++++++---------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index ce0a660fd4..35c95c749b 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -1575,6 +1575,8 @@ public final class KMManager { }, 2000); KeyboardEventHandler.notifyListeners(KMTextView.kbEventListeners, KeyboardType.KEYBOARD_TYPE_SYSTEM, EventType.KEYBOARD_LOADED, null); + + SystemKeyboard.callJavascriptAfterLoad(); } } diff --git a/web/package-lock.json b/web/package-lock.json index 027a9b9997..20668cdba4 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -73,13 +73,13 @@ "arraybuffer.slice": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU=", "dev": true }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "integrity": "sha1-5gtrDo8wG9l+U3UhW9pAbIURjAs=", "dev": true }, "async": { @@ -94,7 +94,7 @@ "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg=", "dev": true }, "backo2": { @@ -367,7 +367,7 @@ "color-convert": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "integrity": "sha1-wSYRB66y8pTr/+ye2eytUppgl+0=", "dev": true, "requires": { "color-name": "^1.1.1" @@ -424,7 +424,7 @@ "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", "dev": true }, "cookie": { @@ -484,7 +484,7 @@ "deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "integrity": "sha1-38lARACtHI/gI+faHfHBR8S0RN8=", "dev": true, "requires": { "type-detect": "^4.0.0" @@ -872,7 +872,7 @@ "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -1217,7 +1217,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true } } @@ -1242,7 +1242,7 @@ "karma-chrome-launcher": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", - "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", + "integrity": "sha1-zxudBxNswY/iOTJ9JGVMPbw2is8=", "dev": true, "requires": { "fs-access": "^1.0.0", @@ -1252,7 +1252,7 @@ "karma-edge-launcher": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/karma-edge-launcher/-/karma-edge-launcher-0.4.2.tgz", - "integrity": "sha512-YAJZb1fmRcxNhMIWYsjLuxwODBjh2cSHgTW/jkVmdpGguJjLbs9ZgIK/tEJsMQcBLUkO+yO4LBbqYxqgGW2HIw==", + "integrity": "sha1-PZUpsJsTyQnF887uEtAOf5qYmz0=", "dev": true, "requires": { "edge-launcher": "1.2.2" @@ -1261,7 +1261,7 @@ "karma-firefox-launcher": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/karma-firefox-launcher/-/karma-firefox-launcher-1.1.0.tgz", - "integrity": "sha512-LbZ5/XlIXLeQ3cqnCbYLn+rOVhuMIK9aZwlP6eOLGzWdo1UVp7t6CN3DP4SafiRLjexKwHeKHDm0c38Mtd3VxA==", + "integrity": "sha1-LEcDBFLwRTHrfRPU/HZpYwu5Mzk=", "dev": true }, "karma-fixture": { @@ -1328,7 +1328,7 @@ "ansi-styles": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=", "dev": true, "requires": { "color-convert": "^1.9.0" @@ -1374,7 +1374,7 @@ "karma-teamcity-reporter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/karma-teamcity-reporter/-/karma-teamcity-reporter-1.1.0.tgz", - "integrity": "sha512-Ca1uhHGtNqUuzsnW3I+QykNuS/jF9vdxnIrkbLCVJRunCc6yWJq+ai1UobQT13j0e3JVUOf0mKo3QHZ6A6mG9Q==", + "integrity": "sha1-eYD33JHmqwhH4SKt4Ls0x8b0KBY=", "dev": true }, "linkify-it": { @@ -1405,7 +1405,7 @@ "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "integrity": "sha1-V0Dhxdbw39pK2TI7UzIQfva0xAo=", "dev": true, "requires": { "chalk": "^2.0.1" @@ -1414,7 +1414,7 @@ "ansi-styles": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=", "dev": true, "requires": { "color-convert": "^1.9.0" @@ -1548,7 +1548,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -1863,7 +1863,7 @@ "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -1954,7 +1954,7 @@ "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=", "dev": true }, "safer-buffer": { @@ -2198,7 +2198,7 @@ "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -2258,7 +2258,7 @@ "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", "dev": true, "requires": { "os-tmpdir": "~1.0.2" @@ -2328,7 +2328,7 @@ "ultron": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "integrity": "sha1-n+FTahCmZKZSZqHjzPhf02MCvJw=", "dev": true }, "universalify": { @@ -2418,7 +2418,7 @@ "which": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "integrity": "sha1-/wS9/AEO5UfXgL7DjhrBwnd9JTo=", "dev": true, "requires": { "isexe": "^2.0.0" @@ -2482,7 +2482,7 @@ "ws": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "integrity": "sha1-8c+E/i1ekB686U767OeF8YeiKPI=", "dev": true, "requires": { "async-limiter": "~1.0.0", From 7d65efcedc45194d8ddbf78c2b2e70a2bdfc62a7 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 29 Jul 2019 20:03:28 +1000 Subject: [PATCH 42/47] [Android] Remove commented code --- .../KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index 35c95c749b..bccc76f973 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -1301,9 +1301,6 @@ public final class KMManager { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { - /*if (url.startsWith("file")) { // endsWith(KMFilename_KeyboardHtml)) { - InAppKeyboardLoaded = false; - }*/ } @Override From 37e1dc34cfb64d759e05dbaafb0fe921de75e767 Mon Sep 17 00:00:00 2001 From: Eddie Antonio Santos Date: Mon, 29 Jul 2019 09:17:39 -0600 Subject: [PATCH 43/47] [Developer] Add build.sh to developer/js. --- developer/js/build.sh | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100755 developer/js/build.sh diff --git a/developer/js/build.sh b/developer/js/build.sh new file mode 100755 index 0000000000..1412aa3809 --- /dev/null +++ b/developer/js/build.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# +# Compiles the developer tools, including the language model compilers. +# + +# Include some helper functions from resources +. ../../resources/shellHelperFunctions.sh +EX_USAGE=64 + + +# Build the worker and the main script. +build () { + npm run build || fail "Could not build top-level JavaScript file." +} + +display_usage ( ) { + echo "Usage: $0 [-test]" + echo " $0 -help" + echo + echo " -help displays this screen and exits" + echo " -test runs unit and integration tests after building" +} + +################################ Main script ################################ + +run_tests=0 + +# Process command-line arguments +while [[ $# -gt 0 ]] ; do + key="$1" + case $key in + -help|-h) + display_usage + exit + ;; + -test) + run_tests=1 + ;; + *) + echo "$0: invalid option: $key" + display_usage + exit $EX_USAGE + esac + shift # past the processed argument +done + +# Check if Node.JS/npm is installed. +type npm >/dev/null ||\ + fail "Build environment setup error detected! Please ensure Node.js is installed!" + +build || fail "Compilation failed." +echo "Typescript compilation successful." + +if (( run_tests )); then + npm test || fail "Tests failed" +fi From 930f4b9eb77bd59f7ffd030bfe37c91559290db1 Mon Sep 17 00:00:00 2001 From: Eddie Antonio Santos Date: Mon, 29 Jul 2019 09:19:49 -0600 Subject: [PATCH 44/47] Correct some comments. --- developer/js/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/developer/js/build.sh b/developer/js/build.sh index 1412aa3809..206b0b17f1 100755 --- a/developer/js/build.sh +++ b/developer/js/build.sh @@ -8,7 +8,7 @@ EX_USAGE=64 -# Build the worker and the main script. +# Build the main script. build () { npm run build || fail "Could not build top-level JavaScript file." } @@ -18,7 +18,7 @@ display_usage ( ) { echo " $0 -help" echo echo " -help displays this screen and exits" - echo " -test runs unit and integration tests after building" + echo " -test runs unit tests after building" } ################################ Main script ################################ From 861f0896320ff9e864e3f7a2d66027391d7a0604 Mon Sep 17 00:00:00 2001 From: Randy Boring Date: Mon, 29 Jul 2019 16:18:15 -0500 Subject: [PATCH 45/47] capitalize the heading for Keyboards and Language settings in LanguageSettingsViewController --- .../Classes/Settings/LanguageSettingsViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift index cc666a8d23..8b7f2d9e91 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift @@ -153,9 +153,9 @@ class LanguageSettingsViewController: UITableViewController { var title: String switch (section) { case 0: - title = "keyboards" + title = "Keyboards" case 1: - title = "language settings" + title = "Language settings" default: title = "unknown header" } From d8cd238e369d814648fbc3217da9ee82ef7a537e Mon Sep 17 00:00:00 2001 From: Joshua Horton Date: Tue, 30 Jul 2019 08:40:00 +0700 Subject: [PATCH 46/47] Update common/predictive-text/worker/worker-interfaces.ts Co-Authored-By: Eddie Antonio Santos --- common/predictive-text/worker/worker-interfaces.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/predictive-text/worker/worker-interfaces.ts b/common/predictive-text/worker/worker-interfaces.ts index d08885092b..69f4d7bcef 100644 --- a/common/predictive-text/worker/worker-interfaces.ts +++ b/common/predictive-text/worker/worker-interfaces.ts @@ -177,7 +177,7 @@ interface WorkerInternalModel { /** * Performs a wordbreak operation given the current context state, returning whatever word * or word fragment exists that starts before the caret but after the most recent whitespace - * preceding the caret. If no such text exists, the the empty string is returned. + * preceding the caret. If no such text exists, the empty string is returned. * * This function is designed for use in generating display text for 'keep' `Suggestions` * and display text for reverting any previously-applied `Suggestions`. From 65136a06e2cb81e3850b65d2a7ed3fe61a81a852 Mon Sep 17 00:00:00 2001 From: Eddie Antonio Santos Date: Tue, 30 Jul 2019 09:21:37 -0600 Subject: [PATCH 47/47] Add set -eu to prevent further mistakes in build.sh. This change is has not been approved by the UK parliament :p --- developer/js/build.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/developer/js/build.sh b/developer/js/build.sh index 206b0b17f1..0308dc00e3 100755 --- a/developer/js/build.sh +++ b/developer/js/build.sh @@ -3,6 +3,9 @@ # Compiles the developer tools, including the language model compilers. # +# Exit on command failure and when using unset variables: +set -eu + # Include some helper functions from resources . ../../resources/shellHelperFunctions.sh EX_USAGE=64