mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-24 00:27:40 +00:00
[iOS] FV app code cleanup, refactor, and implement upgrade
This commit is contained in:
parent
0ac9545fb8
commit
b0429ed1aa
9 changed files with 316 additions and 238 deletions
|
|
@ -9,15 +9,37 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
let FVGroupID: String = "group.FVKeyboards"
|
||||
let kFVLoadedKeyboardList: String = "FVLoadedKeyboardList"
|
||||
struct FVConstants {
|
||||
static let groupID: String = "group.FVKeyboards"
|
||||
static let kFVLoadedKeyboardList: String = "FVLoadedKeyboardList"
|
||||
|
||||
// Legacy keys
|
||||
static let legacy_kFVKeyboardList = "FVKeyboardList"
|
||||
static let legacy_kKeyboardsFileLastModDateKey = "KeyboardsFileLastModDate"
|
||||
|
||||
static let legacy_kFVKeyboardCheckStateKey = "FVKeyboardCheckState"
|
||||
static let legacy_kFVKeyboardFilenameKey = "FVKeyboardFilename"
|
||||
|
||||
// Keyboard files and paths
|
||||
static let keyboardsPath = "Keyboards/files"
|
||||
static let keyboardsCSVPath = "Keyboards"
|
||||
static let keyboardsCSVName = "keyboards"
|
||||
static let keyboardsCSVType = "csv"
|
||||
static let keyboardInfoType = "keyboard_info"
|
||||
static let keyboardType = "js"
|
||||
|
||||
// Instructions web page
|
||||
static let instructionsName = "setup"
|
||||
static let instructionsType = "html"
|
||||
static let instructionsPath = "Instructions"
|
||||
}
|
||||
|
||||
class FVShared {
|
||||
|
||||
class func userDefaults() -> UserDefaults {
|
||||
var _userDefaults: UserDefaults? = nil
|
||||
if UserDefaults.standard.responds(to: #selector(UserDefaults.init(suiteName:))) {
|
||||
_userDefaults = UserDefaults(suiteName: FVGroupID)
|
||||
_userDefaults = UserDefaults(suiteName: FVConstants.groupID)
|
||||
}
|
||||
if _userDefaults == nil {
|
||||
_userDefaults = UserDefaults.standard
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
37C183B922932AD2009F9EFD /* FVKeyboardList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C183B822932AD2009F9EFD /* FVKeyboardList.swift */; };
|
||||
37C183BD2293321C009F9EFD /* Instructions in Resources */ = {isa = PBXBuildFile; fileRef = 37C183BC2293321C009F9EFD /* Instructions */; };
|
||||
37EA1F1E228A180A003E710C /* KeymanEngine.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 37EA1F1D228A1809003E710C /* KeymanEngine.framework */; };
|
||||
37EA1F1F228A1823003E710C /* KeymanEngine.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 37EA1F1D228A1809003E710C /* KeymanEngine.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
37EA1F20228A183E003E710C /* KeymanEngine.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 37EA1F1D228A1809003E710C /* KeymanEngine.framework */; };
|
||||
|
|
@ -38,12 +40,9 @@
|
|||
98395E361C1E61AF007CD675 /* 739-question.png in Resources */ = {isa = PBXBuildFile; fileRef = 98395E301C1E61AF007CD675 /* 739-question.png */; };
|
||||
98395E371C1E61AF007CD675 /* 739-question@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 98395E311C1E61AF007CD675 /* 739-question@2x.png */; };
|
||||
98395E381C1E61AF007CD675 /* 739-question@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 98395E321C1E61AF007CD675 /* 739-question@3x.png */; };
|
||||
984471A61C1F796D00D3C9DA /* languagegeek.png in Resources */ = {isa = PBXBuildFile; fileRef = 984471A51C1F796D00D3C9DA /* languagegeek.png */; };
|
||||
9889E8C41BFA9CEC00019560 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9889E8C21BFA9CEC00019560 /* Main.storyboard */; };
|
||||
9889E8C61BFA9CEC00019560 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9889E8C51BFA9CEC00019560 /* Assets.xcassets */; };
|
||||
9889E8C91BFA9CEC00019560 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9889E8C71BFA9CEC00019560 /* LaunchScreen.storyboard */; };
|
||||
989618CA1C194AD90012E3EB /* fpcc.svg in Resources */ = {isa = PBXBuildFile; fileRef = 989618C81C194AD90012E3EB /* fpcc.svg */; };
|
||||
989618CB1C194AD90012E3EB /* nrt.svg in Resources */ = {isa = PBXBuildFile; fileRef = 989618C91C194AD90012E3EB /* nrt.svg */; };
|
||||
98C7F7F51BFD4649007F17B7 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98C9A9E71BFC0974009E9A4F /* AudioToolbox.framework */; };
|
||||
98C7F7F61BFD464F007F17B7 /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98C9A9ED1BFC098F009E9A4F /* CoreText.framework */; };
|
||||
98C7F7F71BFD4655007F17B7 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98C9A9F71BFC09ED009E9A4F /* CoreGraphics.framework */; };
|
||||
|
|
@ -74,21 +73,6 @@
|
|||
98C9A9F41BFC09C5009E9A4F /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98C9A9F31BFC09C5009E9A4F /* MobileCoreServices.framework */; };
|
||||
98C9A9F61BFC09DE009E9A4F /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98C9A9F51BFC09DE009E9A4F /* UIKit.framework */; };
|
||||
98C9A9F81BFC09ED009E9A4F /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98C9A9F71BFC09ED009E9A4F /* CoreGraphics.framework */; };
|
||||
98FAB7FD1C0E775500C31263 /* globe.svg in Resources */ = {isa = PBXBuildFile; fileRef = 98FAB7EA1C0E775500C31263 /* globe.svg */; };
|
||||
98FAB7FE1C0E775500C31263 /* ios-instructions.css in Resources */ = {isa = PBXBuildFile; fileRef = 98FAB7EB1C0E775500C31263 /* ios-instructions.css */; };
|
||||
98FAB7FF1C0E775500C31263 /* keyman.svg in Resources */ = {isa = PBXBuildFile; fileRef = 98FAB7EC1C0E775500C31263 /* keyman.svg */; };
|
||||
98FAB8011C0E775500C31263 /* nunito-regular-webfont.eot in Resources */ = {isa = PBXBuildFile; fileRef = 98FAB7EE1C0E775500C31263 /* nunito-regular-webfont.eot */; };
|
||||
98FAB8021C0E775500C31263 /* nunito-regular-webfont.svg in Resources */ = {isa = PBXBuildFile; fileRef = 98FAB7EF1C0E775500C31263 /* nunito-regular-webfont.svg */; };
|
||||
98FAB8031C0E775500C31263 /* nunito-regular-webfont.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 98FAB7F01C0E775500C31263 /* nunito-regular-webfont.ttf */; };
|
||||
98FAB8041C0E775500C31263 /* nunito-regular-webfont.woff in Resources */ = {isa = PBXBuildFile; fileRef = 98FAB7F11C0E775500C31263 /* nunito-regular-webfont.woff */; };
|
||||
98FAB8051C0E775500C31263 /* nunito-regular-webfont.woff2 in Resources */ = {isa = PBXBuildFile; fileRef = 98FAB7F21C0E775500C31263 /* nunito-regular-webfont.woff2 */; };
|
||||
98FAB8061C0E775500C31263 /* opensans-regular-webfont.eot in Resources */ = {isa = PBXBuildFile; fileRef = 98FAB7F31C0E775500C31263 /* opensans-regular-webfont.eot */; };
|
||||
98FAB8071C0E775500C31263 /* opensans-regular-webfont.svg in Resources */ = {isa = PBXBuildFile; fileRef = 98FAB7F41C0E775500C31263 /* opensans-regular-webfont.svg */; };
|
||||
98FAB8081C0E775500C31263 /* opensans-regular-webfont.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 98FAB7F51C0E775500C31263 /* opensans-regular-webfont.ttf */; };
|
||||
98FAB8091C0E775500C31263 /* opensans-regular-webfont.woff in Resources */ = {isa = PBXBuildFile; fileRef = 98FAB7F61C0E775500C31263 /* opensans-regular-webfont.woff */; };
|
||||
98FAB80A1C0E775500C31263 /* opensans-regular-webfont.woff2 in Resources */ = {isa = PBXBuildFile; fileRef = 98FAB7F71C0E775500C31263 /* opensans-regular-webfont.woff2 */; };
|
||||
98FAB80B1C0E775500C31263 /* setup.html in Resources */ = {isa = PBXBuildFile; fileRef = 98FAB7F81C0E775500C31263 /* setup.html */; };
|
||||
98FAB80D1C0E799100C31263 /* firstvoices-logo.gif in Resources */ = {isa = PBXBuildFile; fileRef = 98FAB80C1C0E799100C31263 /* firstvoices-logo.gif */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
|
@ -131,15 +115,15 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
37C183B822932AD2009F9EFD /* FVKeyboardList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FVKeyboardList.swift; sourceTree = "<group>"; };
|
||||
37C183BC2293321C009F9EFD /* Instructions */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Instructions; path = FirstVoices/Instructions; sourceTree = "<group>"; };
|
||||
37EA1F1D228A1809003E710C /* KeymanEngine.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = KeymanEngine.framework; sourceTree = "<group>"; };
|
||||
37EA1F21228A1F57003E710C /* SWKeyboard-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SWKeyboard-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
37EA1F22228A1F57003E710C /* FVInputViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FVInputViewController.swift; sourceTree = "<group>"; };
|
||||
37EA1F25228B5D6E003E710C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
37EA1F27228B5E2B003E710C /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
37EA1F29228B69AF003E710C /* KeyboardsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardsViewController.swift; sourceTree = "<group>"; };
|
||||
37EA1F2E228B7458003E710C /* CheckBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CheckBox.swift; path = Checkbox/CheckBox.swift; sourceTree = "<group>"; };
|
||||
37EA1F30228B7661003E710C /* FVShared.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FVShared.swift; path = FVShared/FVShared.swift; sourceTree = "<group>"; };
|
||||
37EA1F33228BCDF8003E710C /* FirstVoices-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FirstVoices-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
37EA1F34228CA3BD003E710C /* ObjcExceptionBridging.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjcExceptionBridging.framework; path = ../../../ios/Carthage/Build/iOS/ObjcExceptionBridging.framework; sourceTree = "<group>"; };
|
||||
37EA1F36228CA3D2003E710C /* XCGLogger.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCGLogger.framework; path = ../../../ios/Carthage/Build/iOS/XCGLogger.framework; sourceTree = "<group>"; };
|
||||
37EA1F38228CA3E4003E710C /* Zip.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Zip.framework; path = ../../../ios/Carthage/Build/iOS/Zip.framework; sourceTree = "<group>"; };
|
||||
|
|
@ -153,14 +137,11 @@
|
|||
98395E301C1E61AF007CD675 /* 739-question.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "739-question.png"; sourceTree = "<group>"; };
|
||||
98395E311C1E61AF007CD675 /* 739-question@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "739-question@2x.png"; sourceTree = "<group>"; };
|
||||
98395E321C1E61AF007CD675 /* 739-question@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "739-question@3x.png"; sourceTree = "<group>"; };
|
||||
984471A51C1F796D00D3C9DA /* languagegeek.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = languagegeek.png; sourceTree = "<group>"; };
|
||||
9889E8B61BFA9CEC00019560 /* FirstVoices.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FirstVoices.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9889E8C31BFA9CEC00019560 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
9889E8C51BFA9CEC00019560 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
9889E8C81BFA9CEC00019560 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
9889E8CA1BFA9CEC00019560 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
989618C81C194AD90012E3EB /* fpcc.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = fpcc.svg; sourceTree = "<group>"; };
|
||||
989618C91C194AD90012E3EB /* nrt.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = nrt.svg; sourceTree = "<group>"; };
|
||||
98C9A8BC1BFBF23C009E9A4F /* SWKeyboard.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SWKeyboard.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
98C9A8C11BFBF23C009E9A4F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
98C9A8DD1BFBF6C1009E9A4F /* banner-Landscape-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "banner-Landscape-568h@2x.png"; sourceTree = "<group>"; };
|
||||
|
|
@ -185,21 +166,6 @@
|
|||
98C9A9F71BFC09ED009E9A4F /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
||||
98C9A9F91BFC10D2009E9A4F /* FirstVoices.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = FirstVoices.entitlements; sourceTree = "<group>"; };
|
||||
98C9A9FA1BFC1111009E9A4F /* SWKeyboard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = SWKeyboard.entitlements; sourceTree = "<group>"; };
|
||||
98FAB7EA1C0E775500C31263 /* globe.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = globe.svg; sourceTree = "<group>"; };
|
||||
98FAB7EB1C0E775500C31263 /* ios-instructions.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = "ios-instructions.css"; sourceTree = "<group>"; };
|
||||
98FAB7EC1C0E775500C31263 /* keyman.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = keyman.svg; sourceTree = "<group>"; };
|
||||
98FAB7EE1C0E775500C31263 /* nunito-regular-webfont.eot */ = {isa = PBXFileReference; lastKnownFileType = file; path = "nunito-regular-webfont.eot"; sourceTree = "<group>"; };
|
||||
98FAB7EF1C0E775500C31263 /* nunito-regular-webfont.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = "nunito-regular-webfont.svg"; sourceTree = "<group>"; };
|
||||
98FAB7F01C0E775500C31263 /* nunito-regular-webfont.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "nunito-regular-webfont.ttf"; sourceTree = "<group>"; };
|
||||
98FAB7F11C0E775500C31263 /* nunito-regular-webfont.woff */ = {isa = PBXFileReference; lastKnownFileType = file; path = "nunito-regular-webfont.woff"; sourceTree = "<group>"; };
|
||||
98FAB7F21C0E775500C31263 /* nunito-regular-webfont.woff2 */ = {isa = PBXFileReference; lastKnownFileType = file; path = "nunito-regular-webfont.woff2"; sourceTree = "<group>"; };
|
||||
98FAB7F31C0E775500C31263 /* opensans-regular-webfont.eot */ = {isa = PBXFileReference; lastKnownFileType = file; path = "opensans-regular-webfont.eot"; sourceTree = "<group>"; };
|
||||
98FAB7F41C0E775500C31263 /* opensans-regular-webfont.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = "opensans-regular-webfont.svg"; sourceTree = "<group>"; };
|
||||
98FAB7F51C0E775500C31263 /* opensans-regular-webfont.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "opensans-regular-webfont.ttf"; sourceTree = "<group>"; };
|
||||
98FAB7F61C0E775500C31263 /* opensans-regular-webfont.woff */ = {isa = PBXFileReference; lastKnownFileType = file; path = "opensans-regular-webfont.woff"; sourceTree = "<group>"; };
|
||||
98FAB7F71C0E775500C31263 /* opensans-regular-webfont.woff2 */ = {isa = PBXFileReference; lastKnownFileType = file; path = "opensans-regular-webfont.woff2"; sourceTree = "<group>"; };
|
||||
98FAB7F81C0E775500C31263 /* setup.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = setup.html; sourceTree = "<group>"; };
|
||||
98FAB80C1C0E799100C31263 /* firstvoices-logo.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "firstvoices-logo.gif"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
|
@ -264,6 +230,7 @@
|
|||
9889E8AD1BFA9CEC00019560 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
37C183BC2293321C009F9EFD /* Instructions */,
|
||||
37EA1F472292238E003E710C /* Keyboards */,
|
||||
9889E8B81BFA9CEC00019560 /* FirstVoices */,
|
||||
98C9A9FB1BFC19ED009E9A4F /* Frameworks */,
|
||||
|
|
@ -287,16 +254,15 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
98C9A9F91BFC10D2009E9A4F /* FirstVoices.entitlements */,
|
||||
37EA1F33228BCDF8003E710C /* FirstVoices-Bridging-Header.h */,
|
||||
9889E8CA1BFA9CEC00019560 /* Info.plist */,
|
||||
37EA1F25228B5D6E003E710C /* AppDelegate.swift */,
|
||||
37EA1F2E228B7458003E710C /* CheckBox.swift */,
|
||||
37C183B822932AD2009F9EFD /* FVKeyboardList.swift */,
|
||||
37EA1F4522921BAD003E710C /* KeyboardInfo.swift */,
|
||||
37EA1F29228B69AF003E710C /* KeyboardsViewController.swift */,
|
||||
37EA1F27228B5E2B003E710C /* ViewController.swift */,
|
||||
9889E8C51BFA9CEC00019560 /* Assets.xcassets */,
|
||||
98395E2C1C1E61AF007CD675 /* Icons */,
|
||||
98FAB7E51C0E775500C31263 /* Instructions */,
|
||||
9889E8C71BFA9CEC00019560 /* LaunchScreen.storyboard */,
|
||||
9889E8C21BFA9CEC00019560 /* Main.storyboard */,
|
||||
9889E8B91BFA9CEC00019560 /* Supporting Files */,
|
||||
|
|
@ -326,7 +292,6 @@
|
|||
98C9A8DC1BFBF6C1009E9A4F /* Images */,
|
||||
37EA1F22228A1F57003E710C /* FVInputViewController.swift */,
|
||||
98C9A8C11BFBF23C009E9A4F /* Info.plist */,
|
||||
37EA1F21228A1F57003E710C /* SWKeyboard-Bridging-Header.h */,
|
||||
);
|
||||
path = SWKeyboard;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -370,31 +335,6 @@
|
|||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
98FAB7E51C0E775500C31263 /* Instructions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
98FAB80C1C0E799100C31263 /* firstvoices-logo.gif */,
|
||||
989618C81C194AD90012E3EB /* fpcc.svg */,
|
||||
98FAB7EA1C0E775500C31263 /* globe.svg */,
|
||||
98FAB7EB1C0E775500C31263 /* ios-instructions.css */,
|
||||
98FAB7EC1C0E775500C31263 /* keyman.svg */,
|
||||
984471A51C1F796D00D3C9DA /* languagegeek.png */,
|
||||
989618C91C194AD90012E3EB /* nrt.svg */,
|
||||
98FAB7EE1C0E775500C31263 /* nunito-regular-webfont.eot */,
|
||||
98FAB7EF1C0E775500C31263 /* nunito-regular-webfont.svg */,
|
||||
98FAB7F01C0E775500C31263 /* nunito-regular-webfont.ttf */,
|
||||
98FAB7F11C0E775500C31263 /* nunito-regular-webfont.woff */,
|
||||
98FAB7F21C0E775500C31263 /* nunito-regular-webfont.woff2 */,
|
||||
98FAB7F31C0E775500C31263 /* opensans-regular-webfont.eot */,
|
||||
98FAB7F41C0E775500C31263 /* opensans-regular-webfont.svg */,
|
||||
98FAB7F51C0E775500C31263 /* opensans-regular-webfont.ttf */,
|
||||
98FAB7F61C0E775500C31263 /* opensans-regular-webfont.woff */,
|
||||
98FAB7F71C0E775500C31263 /* opensans-regular-webfont.woff2 */,
|
||||
98FAB7F81C0E775500C31263 /* setup.html */,
|
||||
);
|
||||
path = Instructions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
|
|
@ -493,35 +433,18 @@
|
|||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
98FAB7FD1C0E775500C31263 /* globe.svg in Resources */,
|
||||
9889E8C91BFA9CEC00019560 /* LaunchScreen.storyboard in Resources */,
|
||||
37C183BD2293321C009F9EFD /* Instructions in Resources */,
|
||||
9800EC5C1C029F2200BF0FB5 /* Settings.bundle in Resources */,
|
||||
98FAB8021C0E775500C31263 /* nunito-regular-webfont.svg in Resources */,
|
||||
989618CA1C194AD90012E3EB /* fpcc.svg in Resources */,
|
||||
98FAB8061C0E775500C31263 /* opensans-regular-webfont.eot in Resources */,
|
||||
98FAB80B1C0E775500C31263 /* setup.html in Resources */,
|
||||
98FAB8071C0E775500C31263 /* opensans-regular-webfont.svg in Resources */,
|
||||
9889E8C61BFA9CEC00019560 /* Assets.xcassets in Resources */,
|
||||
98FAB7FF1C0E775500C31263 /* keyman.svg in Resources */,
|
||||
98395E331C1E61AF007CD675 /* 739-question-selected.png in Resources */,
|
||||
37EA1F482292238F003E710C /* Keyboards in Resources */,
|
||||
98FAB8041C0E775500C31263 /* nunito-regular-webfont.woff in Resources */,
|
||||
98FAB8091C0E775500C31263 /* opensans-regular-webfont.woff in Resources */,
|
||||
989618CB1C194AD90012E3EB /* nrt.svg in Resources */,
|
||||
984471A61C1F796D00D3C9DA /* languagegeek.png in Resources */,
|
||||
98395E371C1E61AF007CD675 /* 739-question@2x.png in Resources */,
|
||||
9889E8C41BFA9CEC00019560 /* Main.storyboard in Resources */,
|
||||
98FAB7FE1C0E775500C31263 /* ios-instructions.css in Resources */,
|
||||
98395E341C1E61AF007CD675 /* 739-question-selected@2x.png in Resources */,
|
||||
98FAB8051C0E775500C31263 /* nunito-regular-webfont.woff2 in Resources */,
|
||||
98FAB8081C0E775500C31263 /* opensans-regular-webfont.ttf in Resources */,
|
||||
98FAB80A1C0E775500C31263 /* opensans-regular-webfont.woff2 in Resources */,
|
||||
98FAB8011C0E775500C31263 /* nunito-regular-webfont.eot in Resources */,
|
||||
98395E361C1E61AF007CD675 /* 739-question.png in Resources */,
|
||||
98FAB80D1C0E799100C31263 /* firstvoices-logo.gif in Resources */,
|
||||
98395E381C1E61AF007CD675 /* 739-question@3x.png in Resources */,
|
||||
98395E351C1E61AF007CD675 /* 739-question-selected@3x.png in Resources */,
|
||||
98FAB8031C0E775500C31263 /* nunito-regular-webfont.ttf in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
@ -572,6 +495,7 @@
|
|||
37EA1F2F228B7458003E710C /* CheckBox.swift in Sources */,
|
||||
37EA1F31228B7661003E710C /* FVShared.swift in Sources */,
|
||||
37EA1F28228B5E2B003E710C /* ViewController.swift in Sources */,
|
||||
37C183B922932AD2009F9EFD /* FVKeyboardList.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
func application(_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
|
||||
|
||||
#warning("TODO: we need to upgrade existing installations, which involves mapping the horrific old data structure plus keyboard file renames")
|
||||
FVRegionStorage.upgrade()
|
||||
|
||||
//#if DEBUG
|
||||
KeymanEngine.log.outputLevel = .debug
|
||||
|
|
@ -27,7 +27,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
//#endif
|
||||
|
||||
// Replace with your application group id
|
||||
Manager.applicationGroupIdentifier = "group.FVKeyboards"
|
||||
Manager.applicationGroupIdentifier = FVConstants.groupID
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
245
oem/firstvoices/ios/FirstVoices/FVKeyboardList.swift
Normal file
245
oem/firstvoices/ios/FirstVoices/FVKeyboardList.swift
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
//
|
||||
// FVKeyboardList.swift
|
||||
// FirstVoices app
|
||||
//
|
||||
// License: MIT
|
||||
//
|
||||
// Copyright © 2019 FirstVoices.
|
||||
//
|
||||
// Created by Marc Durdin on 21/05/2019.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import KeymanEngine
|
||||
|
||||
/// A single keyboard in the list of available keyboards
|
||||
class FVKeyboard {
|
||||
let id, name, legacyId: String
|
||||
init(id: String, name: String, legacyId: String) {
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.legacyId = legacyId
|
||||
}
|
||||
}
|
||||
|
||||
typealias FVKeyboardList = [FVKeyboard]
|
||||
|
||||
/// A region with a list of keyboards
|
||||
class FVRegion {
|
||||
let name: String
|
||||
var keyboards: FVKeyboardList = []
|
||||
init(name: String) {
|
||||
self.name = name
|
||||
}
|
||||
}
|
||||
typealias FVRegionList = [FVRegion]
|
||||
|
||||
class FVRegionStorage {
|
||||
|
||||
/// Loads the available keyboards from keyboards.csv to present
|
||||
/// in the user interface. This keyboards.csv file is maintained
|
||||
/// manually but the keyboards listed within are imported into the
|
||||
/// app during build (into the Keyboards/files directory) from the
|
||||
/// keymanapp/keyboards repository. This means that a rebuild of the
|
||||
/// app always gets the latest version of the keyboards. Adding a new
|
||||
/// keyboard to the app is as simple as updating keyboards.csv and
|
||||
/// rebuilding.
|
||||
///
|
||||
/// The keyboards.csv file has 5 columns:
|
||||
/// - shortname - the keyboards repository shortname (e.g. fv)
|
||||
/// - id - the identifier of the keyboard
|
||||
/// - name - the name of the keyboard to be shown in UI in app
|
||||
/// (sometimes may differ from the compiled keyboard)
|
||||
/// - regionName - the name of the region to group the keyboard under
|
||||
/// - legacyId - the legacy filename of the keyboard, used only
|
||||
/// during upgrades
|
||||
/// The file is sorted according to how the keyboards should be
|
||||
/// displayed in the Keyboard Selection UI.
|
||||
class func load() -> FVRegionList {
|
||||
var regionList = FVRegionList()
|
||||
do {
|
||||
let keyboardsFile: String = Bundle.main.path(forResource: FVConstants.keyboardsCSVName,
|
||||
ofType: FVConstants.keyboardsCSVType,
|
||||
inDirectory: FVConstants.keyboardsCSVPath)!
|
||||
|
||||
let fileContents: String = try String(contentsOfFile: keyboardsFile, encoding: .utf8).replacingOccurrences(of: "\r", with: "")
|
||||
let lines: [String] = fileContents.components(separatedBy: "\n")
|
||||
for i in 1..<lines.count { // skip first line; it is a header row
|
||||
let line: String = lines[i]
|
||||
if line.count == 0 {
|
||||
continue
|
||||
}
|
||||
let values: [String] = line.components(separatedBy: ",")
|
||||
if values.count > 0 {
|
||||
// Columns: shortname,id,name,region,legacyid
|
||||
let kbId: String = values[1]
|
||||
let kbName: String = values[2]
|
||||
let regionName: String = values[3]
|
||||
let legacyId: String = values[4]
|
||||
|
||||
var region = regionList.first(where: { $0.name == regionName })
|
||||
if region == nil {
|
||||
region = FVRegion(name: regionName)
|
||||
regionList.append(region!)
|
||||
}
|
||||
|
||||
let kb = FVKeyboard(id: kbId, name: kbName, legacyId: legacyId)
|
||||
region!.keyboards.append(kb)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
print("Unexpected error loading keyboards.csv: \(error).")
|
||||
}
|
||||
return regionList
|
||||
}
|
||||
|
||||
/// Load shared user data from earlier versions of the app and
|
||||
/// convert into the desired format, then unload the old keyboards
|
||||
/// and load the new ones corresponding. If a keyboard is not available
|
||||
/// in the new version, it will be uninstalled.
|
||||
class func upgrade() {
|
||||
|
||||
let sharedData: UserDefaults = FVShared.userDefaults()
|
||||
let list = sharedData.array(forKey: FVConstants.legacy_kFVKeyboardList)
|
||||
if(list == nil) {
|
||||
// No legacy data to upgrade
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
// The legacy format is a bit messy. It mixes static data and configuration.
|
||||
// Fortunately, we only need the checkstatekey value (and corresponding
|
||||
// keyboard name) in order to transfer state to the new app.
|
||||
// array(
|
||||
// 0: region_name
|
||||
// 1: array(
|
||||
// dictionary(
|
||||
// checkstatekey
|
||||
// filenamekey
|
||||
// ...
|
||||
// )
|
||||
// )
|
||||
// ...
|
||||
// )
|
||||
//
|
||||
|
||||
let regions = self.load()
|
||||
var loadedKeyboards: [String] = []
|
||||
|
||||
var i = 1
|
||||
while i < list!.count {
|
||||
let keyboards = list![i] as? [[String:String]]
|
||||
if let keyboards = keyboards {
|
||||
for keyboard in keyboards {
|
||||
|
||||
if keyboard[FVConstants.legacy_kFVKeyboardCheckStateKey] == "YES" {
|
||||
|
||||
let legacyId = keyboard[FVConstants.legacy_kFVKeyboardFilenameKey]
|
||||
print("Legacy keyboard \(legacyId!) is installed")
|
||||
|
||||
for region in regions {
|
||||
for rk in region.keyboards {
|
||||
if rk.legacyId == legacyId {
|
||||
print("Found corresponding keyboard \(rk.id)")
|
||||
loadedKeyboards.append(rk.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Some intermediate debug builds had different formats
|
||||
// so we just abandon data from those
|
||||
print("Unable to load corrupted data")
|
||||
break
|
||||
}
|
||||
i += 2
|
||||
}
|
||||
|
||||
// Save the new configuration (which could be empty), and update Keyman Engine
|
||||
self.saveKeyboardListToUserDefaults(loadedKeyboards: loadedKeyboards)
|
||||
self.updateActiveKeyboardsList(keyboardList: regions, loadedKeyboards: loadedKeyboards)
|
||||
|
||||
// Finally, remove the legacy data
|
||||
sharedData.removeObject(forKey: FVConstants.legacy_kFVKeyboardList)
|
||||
sharedData.removeObject(forKey: FVConstants.legacy_kKeyboardsFileLastModDateKey)
|
||||
}
|
||||
|
||||
/// Loads the list of keyboards that the user has selected; in theory we could
|
||||
/// collect these from Keyman Engine but at present there is no API to iterate
|
||||
/// over the installed keyboards.
|
||||
class func loadKeyboardListFromUserDefaults() -> [String] {
|
||||
let sharedData: UserDefaults = FVShared.userDefaults()
|
||||
let keyboards = sharedData.array(forKey: FVConstants.kFVLoadedKeyboardList)
|
||||
if keyboards != nil {
|
||||
return keyboards as! [String]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/// Saves the list of keyboards to shared data
|
||||
class func saveKeyboardListToUserDefaults(loadedKeyboards: [String]) {
|
||||
let sharedData: UserDefaults = FVShared.userDefaults()
|
||||
sharedData.set(loadedKeyboards, forKey: FVConstants.kFVLoadedKeyboardList)
|
||||
sharedData.synchronize()
|
||||
}
|
||||
|
||||
/// Updates Keyman Engine with the list of installed keyboards. Removes all
|
||||
/// the keyboards and reinstalls them to maintain a clean configuration.
|
||||
class func updateActiveKeyboardsList(keyboardList: FVRegionList, loadedKeyboards: [String]) {
|
||||
|
||||
// Remove all installed keyboards first -- we'll re-add them below
|
||||
|
||||
while Manager.shared.removeKeyboard(at: 0) {
|
||||
}
|
||||
|
||||
// Iterate through the available keyboards
|
||||
|
||||
for region in keyboardList {
|
||||
let keyboards = region.keyboards
|
||||
for kb in keyboards {
|
||||
if loadedKeyboards.contains(kb.id) {
|
||||
|
||||
// Load the .keyboard_info file and find its first language code
|
||||
|
||||
var keyboardInfo: KeyboardInfo
|
||||
do {
|
||||
let kbinfoFilename: String = Bundle.main.path(forResource: kb.id, ofType: FVConstants.keyboardInfoType, inDirectory: FVConstants.keyboardsPath)!
|
||||
keyboardInfo = try KeyboardInfoParser.decode(file: kbinfoFilename)
|
||||
} catch {
|
||||
print("Failed to load keyboard info for " + kb.id+": " + error.localizedDescription)
|
||||
continue
|
||||
}
|
||||
|
||||
// Preload the keyboard
|
||||
|
||||
do {
|
||||
let kbPath: String = Bundle.main.path(forResource: kb.id,
|
||||
ofType: FVConstants.keyboardType,
|
||||
inDirectory: FVConstants.keyboardsPath)!
|
||||
let pathUrl = URL(fileURLWithPath: kbPath)
|
||||
try Manager.shared.preloadFiles(forKeyboardID: kb.id, at: [pathUrl], shouldOverwrite: true)
|
||||
} catch {
|
||||
print("Failed to load preload "+kb.id+": " + error.localizedDescription)
|
||||
continue
|
||||
}
|
||||
|
||||
// Install the keyboard into Keyman Engine
|
||||
|
||||
let keyboard: InstallableKeyboard = InstallableKeyboard.init(id: kb.id,
|
||||
name: kb.name,
|
||||
languageID: keyboardInfo.languages.keys[keyboardInfo.languages.startIndex],
|
||||
languageName: kb.name,
|
||||
version: keyboardInfo.version,
|
||||
isRTL: false,
|
||||
font: nil,
|
||||
oskFont: nil,
|
||||
isCustom: true)
|
||||
Manager.shared.addKeyboard(keyboard)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
//
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
|
||||
|
|
@ -14,28 +14,26 @@ let helpLink: String = "https://help.keyman.com/keyboard/"
|
|||
let tHelpButtonTag: NSInteger = 1000
|
||||
let tCheckBoxTag: NSInteger = 2000
|
||||
|
||||
class FVKeyboard {
|
||||
let id, name: String
|
||||
init(id: String, name: String) {
|
||||
self.id = id
|
||||
self.name = name
|
||||
}
|
||||
}
|
||||
typealias FVKeyboardList = [FVKeyboard]
|
||||
class FVRegion {
|
||||
var name: String = ""
|
||||
var keyboards: FVKeyboardList = []
|
||||
}
|
||||
typealias FVRegionList = [FVRegion]
|
||||
|
||||
class KeyboardsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
|
||||
|
||||
@IBOutlet var tableView: UITableView!
|
||||
var _keyboardList: FVRegionList = []
|
||||
var _loadedKeyboards: [String] = []
|
||||
|
||||
private var _keyboardList: FVRegionList!
|
||||
|
||||
private var keyboardList: FVRegionList {
|
||||
get {
|
||||
if _keyboardList == nil {
|
||||
_keyboardList = FVRegionStorage.load()
|
||||
}
|
||||
return _keyboardList!
|
||||
}
|
||||
}
|
||||
|
||||
private var _loadedKeyboards: [String] = []
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
loadKeyboardListFromUserDefaults()
|
||||
_loadedKeyboards = FVRegionStorage.loadKeyboardListFromUserDefaults()
|
||||
super.viewDidLoad()
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
}
|
||||
|
|
@ -52,11 +50,11 @@ class KeyboardsViewController: UIViewController, UITableViewDelegate, UITableVie
|
|||
|
||||
// MARK: - Table view data source
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return self.keyboardList().count
|
||||
return self.keyboardList.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
let kbArray = self.keyboardList()[section].keyboards
|
||||
let kbArray = self.keyboardList[section].keyboards
|
||||
return kbArray.count
|
||||
}
|
||||
|
||||
|
|
@ -98,14 +96,14 @@ class KeyboardsViewController: UIViewController, UITableViewDelegate, UITableVie
|
|||
|
||||
func tableView(_ tableView: UITableView,
|
||||
titleForHeaderInSection section: Int) -> String? {
|
||||
return self.keyboardList()[section].name
|
||||
return self.keyboardList[section].name
|
||||
}
|
||||
|
||||
// MARK: - Table view delegate
|
||||
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
||||
cell.selectionStyle = .none
|
||||
cell.accessoryType = .none
|
||||
let keyboards = (self.keyboardList()[indexPath.section]).keyboards
|
||||
let keyboards = (self.keyboardList[indexPath.section]).keyboards
|
||||
let kb = keyboards[indexPath.row]
|
||||
cell.textLabel!.text = kb.name
|
||||
let checkbox: CheckBox = (cell.accessoryView!.viewWithTag(tCheckBoxTag) as! CheckBox)
|
||||
|
|
@ -116,52 +114,13 @@ class KeyboardsViewController: UIViewController, UITableViewDelegate, UITableVie
|
|||
//
|
||||
}
|
||||
|
||||
func keyboardList() -> FVRegionList {
|
||||
if _keyboardList.count == 0 {
|
||||
do {
|
||||
#warning("TODO: refactor the .csv load + related struct/class types into a separate module")
|
||||
let keyboardsFile: String = Bundle.main.path(forResource: "keyboards", ofType: "csv", inDirectory: "Keyboards")!
|
||||
|
||||
let fileContents: String = try String(contentsOfFile: keyboardsFile, encoding: .utf8).replacingOccurrences(of: "\r", with: "")
|
||||
let lines: [String] = fileContents.components(separatedBy: "\n")
|
||||
for i in 1..<lines.count { // skip first line; it is a header row
|
||||
let line: String = lines[i]
|
||||
if line.count == 0 {
|
||||
continue
|
||||
}
|
||||
let values: [String] = line.components(separatedBy: ",")
|
||||
if values.count > 0 {
|
||||
// Columns: shortname,id,name,region,legacyid
|
||||
let kbId: String = values[1]
|
||||
let kbName: String = values[2]
|
||||
let regionName: String = values[3]
|
||||
// TODO: let legacyId: String = values[3]
|
||||
#warning("TODO: deal with legacy ids")
|
||||
var region = _keyboardList.first(where: { $0.name == regionName })
|
||||
if region == nil {
|
||||
region = FVRegion.init()
|
||||
region!.name = regionName
|
||||
_keyboardList.append(region!)
|
||||
}
|
||||
|
||||
let kb = FVKeyboard(id: kbId, name: kbName)
|
||||
region!.keyboards.append(kb)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
NSLog("Unexpected error: \(error).")
|
||||
}
|
||||
}
|
||||
return _keyboardList
|
||||
}
|
||||
|
||||
@objc func helpButtonTapped(_ sender: Any, forEvent event: UIEvent) {
|
||||
let touches: Set<UITouch>? = event.allTouches
|
||||
let touch: UITouch = touches!.first!
|
||||
let currentTouchPosition: CGPoint = touch.location(in: self.tableView)
|
||||
let indexPath: IndexPath? = self.tableView!.indexPathForRow(at: currentTouchPosition)
|
||||
if indexPath != nil {
|
||||
let kbArray: FVKeyboardList = self.keyboardList()[indexPath!.section].keyboards
|
||||
let kbArray: FVKeyboardList = self.keyboardList[indexPath!.section].keyboards
|
||||
let kbDict: FVKeyboard = kbArray[indexPath!.row]
|
||||
let helpUrl: URL = URL.init(string: "\(helpLink)\(kbDict.id)")!
|
||||
UIApplication.shared.openURL(helpUrl)
|
||||
|
|
@ -175,33 +134,19 @@ class KeyboardsViewController: UIViewController, UITableViewDelegate, UITableVie
|
|||
let indexPath: IndexPath? = self.tableView!.indexPathForRow(at: currentTouchPosition)
|
||||
if indexPath != nil {
|
||||
// Update the checkState with the new checked state
|
||||
let keyboards = self.keyboardList()[indexPath!.section].keyboards
|
||||
let keyboards = self.keyboardList[indexPath!.section].keyboards
|
||||
let kb = keyboards[indexPath!.row]
|
||||
|
||||
_loadedKeyboards = _loadedKeyboards.filter { $0 != kb.id }
|
||||
if (sender as! CheckBox).isChecked {
|
||||
_loadedKeyboards += [kb.id]
|
||||
}
|
||||
self.saveKeyboardListToUserDefaults()
|
||||
self.updateActiveKeyboardsList()
|
||||
FVRegionStorage.saveKeyboardListToUserDefaults(loadedKeyboards: self._loadedKeyboards)
|
||||
FVRegionStorage.updateActiveKeyboardsList(keyboardList: self.keyboardList,
|
||||
loadedKeyboards: self._loadedKeyboards)
|
||||
}
|
||||
}
|
||||
|
||||
func loadKeyboardListFromUserDefaults() {
|
||||
let sharedData: UserDefaults = FVShared.userDefaults()
|
||||
let keyboards = sharedData.array(forKey: kFVLoadedKeyboardList)
|
||||
if keyboards != nil {
|
||||
_loadedKeyboards = keyboards as! [String]
|
||||
} else {
|
||||
_loadedKeyboards = []
|
||||
}
|
||||
}
|
||||
|
||||
func saveKeyboardListToUserDefaults() {
|
||||
let sharedData: UserDefaults = FVShared.userDefaults()
|
||||
sharedData.set(_loadedKeyboards, forKey: kFVLoadedKeyboardList)
|
||||
sharedData.synchronize()
|
||||
}
|
||||
|
||||
func reportFatalError(message: String) {
|
||||
let alertController = UIAlertController(title: title, message: message,
|
||||
|
|
@ -216,58 +161,5 @@ class KeyboardsViewController: UIViewController, UITableViewDelegate, UITableVie
|
|||
// some reporting mechanism
|
||||
}
|
||||
|
||||
func updateActiveKeyboardsList() {
|
||||
|
||||
// Remove all installed keyboards first -- we'll re-add them below
|
||||
|
||||
while Manager.shared.removeKeyboard(at: 0) {
|
||||
}
|
||||
|
||||
// Iterate through the available keyboards
|
||||
|
||||
let kbList = self.keyboardList()
|
||||
for i in 0...kbList.count-1 {
|
||||
let keyboards = kbList[i].keyboards
|
||||
for kb in keyboards {
|
||||
if _loadedKeyboards.contains(kb.id) {
|
||||
|
||||
// Load the .keyboard_info file and find its first language code
|
||||
|
||||
var keyboardInfo: KeyboardInfo
|
||||
do {
|
||||
let kbinfoFilename: String = Bundle.main.path(forResource: kb.id, ofType: "keyboard_info", inDirectory: "Keyboards/files")!
|
||||
keyboardInfo = try KeyboardInfoParser.decode(file: kbinfoFilename)
|
||||
} catch {
|
||||
reportFatalError(message: "Failed to load keyboard info for " + kb.id+": " + error.localizedDescription)
|
||||
continue
|
||||
}
|
||||
|
||||
// Preload the keyboard
|
||||
|
||||
do {
|
||||
let kbPath: String = Bundle.main.path(forResource: kb.id, ofType: "js", inDirectory: "Keyboards/files")!
|
||||
let pathUrl = URL(fileURLWithPath: kbPath)
|
||||
try Manager.shared.preloadFiles(forKeyboardID: kb.id, at: [pathUrl], shouldOverwrite: true)
|
||||
} catch {
|
||||
reportFatalError(message: "Failed to load preload "+kb.id+": " + error.localizedDescription)
|
||||
continue
|
||||
}
|
||||
|
||||
// Install the keyboard into Keyman Engine
|
||||
|
||||
let keyboard: InstallableKeyboard = InstallableKeyboard.init(id: kb.id,
|
||||
name: kb.name,
|
||||
languageID: keyboardInfo.languages.keys[keyboardInfo.languages.startIndex],
|
||||
languageName: kb.name,
|
||||
version: keyboardInfo.version,
|
||||
isRTL: false,
|
||||
font: nil,
|
||||
oskFont: nil,
|
||||
isCustom: true)
|
||||
Manager.shared.addKeyboard(keyboard)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,10 +18,11 @@ class ViewController: UIViewController, UIWebViewDelegate {
|
|||
super.viewDidLoad()
|
||||
|
||||
//
|
||||
// Preload all the .js files, including their file versions
|
||||
// Install all the .js files into Keyman Engine (doesn't show them in the keyboard list)
|
||||
//
|
||||
|
||||
let kbPaths: [String] = Bundle.main.paths(forResourcesOfType:"js", inDirectory: "Keyboards/files")
|
||||
let kbPaths: [String] = Bundle.main.paths(forResourcesOfType: FVConstants.keyboardType,
|
||||
inDirectory: FVConstants.keyboardsPath)
|
||||
for kbPath in kbPaths {
|
||||
let pathUrl = URL(fileURLWithPath: kbPath)
|
||||
let id = pathUrl.deletingPathExtension().lastPathComponent
|
||||
|
|
@ -31,8 +32,15 @@ class ViewController: UIViewController, UIWebViewDelegate {
|
|||
print("Failed to preload "+id+": "+error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Show Instructions page
|
||||
//
|
||||
|
||||
self.webView!.delegate = self
|
||||
let filePath: String? = Bundle.main.path(forResource: "setup", ofType: "html", inDirectory: nil)
|
||||
let filePath: String? = Bundle.main.path(forResource: FVConstants.instructionsName,
|
||||
ofType: FVConstants.instructionsType,
|
||||
inDirectory: FVConstants.instructionsPath)
|
||||
self.webView!.loadRequest(URLRequest.init(url: URL.init(fileURLWithPath: filePath!)))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,14 +20,9 @@ class FVInputViewController: InputViewController {
|
|||
// KeymanEngine.log.outputLevel = .warning
|
||||
//#endif
|
||||
|
||||
print("FVIVC: Starting app")
|
||||
Manager.applicationGroupIdentifier = "group.FVKeyboards"
|
||||
//[self setGlobeKeyTapBehaviour:GKTapSwitchToNextKeyboard];
|
||||
//[self setMenuBehaviour:MenuShowAlways];
|
||||
//[self setMenuCloseButtonTitle:@"Switch to other keyboard"];
|
||||
Manager.applicationGroupIdentifier = FVConstants.groupID
|
||||
|
||||
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
|
||||
print("FVIVC: After super.init")
|
||||
|
||||
self.globeKeyTapBehaviour = .switchToNextKeyboard
|
||||
self.menuBehaviour = .showAlways
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
//
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
|
||||
Loading…
Add table
Reference in a new issue