mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-06 08:55:34 +00:00
428 lines
16 KiB
Swift
428 lines
16 KiB
Swift
//
|
|
// LanguageSettingsViewController.swift
|
|
// KeymanEngine
|
|
//
|
|
// Created by Randy Boring on 5/29/19.
|
|
// Copyright © 2019 SIL International. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
|
|
private let toolbarButtonTag = 100
|
|
|
|
class LanguageSettingsViewController: UITableViewController {
|
|
let language: Language
|
|
private var settingsArray = [[String: String]]()
|
|
private var keyboardRepository: KeyboardRepository?
|
|
|
|
private var doPredictionsSwitch: UISwitch?
|
|
private var doCorrectionsSwitch: UISwitch?
|
|
private var doCorrectionsLabel: UILabel?
|
|
private var correctionsCell: UITableViewCell?
|
|
|
|
public init(_ keyboardRepository: KeyboardRepository?, _ inLanguage: Language) {
|
|
language = inLanguage
|
|
self.keyboardRepository = keyboardRepository
|
|
super.init(nibName: nil, bundle: nil)
|
|
}
|
|
|
|
required public init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
open override func loadView() {
|
|
super.loadView()
|
|
tableView?.delegate = self
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
title = "\(language.name) Settings"
|
|
log.info("viewDidLoad: LanguageSettingsViewController title: \(title ?? "<empty>")")
|
|
|
|
if Manager.shared.canAddNewKeyboards {
|
|
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self,
|
|
action: #selector(self.addClicked))
|
|
navigationItem.rightBarButtonItem = addButton
|
|
}
|
|
}
|
|
|
|
override func viewDidAppear(_ animated: Bool) {
|
|
super.viewDidAppear(animated)
|
|
|
|
log.info("didAppear: LanguageSettingsViewController")
|
|
}
|
|
|
|
|
|
// MARK: - Table view data source UITableViewDataSource
|
|
|
|
override func numberOfSections(in tableView: UITableView) -> Int {
|
|
return 2
|
|
}
|
|
|
|
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
|
if 0 == section {
|
|
// so far as I know, there is always at least one keyboard or else we won't show
|
|
let kbct = language.keyboards!.count
|
|
return kbct
|
|
} else {
|
|
return 3 // 4 in future when we can manage a user dictionary
|
|
}
|
|
}
|
|
|
|
public func frameAtRightOfCell(cell cellFrame: CGRect, controlSize: CGSize) -> CGRect {
|
|
let rightOffset = cellFrame.size.width
|
|
let switchWidth: CGFloat = 20
|
|
let switchX = rightOffset - switchWidth
|
|
let switchHeight = controlSize.height
|
|
let cellSwitchHeightDiff = cellFrame.size.height - switchHeight
|
|
let switchY = cellFrame.origin.y + 0.5 * cellSwitchHeightDiff
|
|
|
|
let switchFrame = CGRect(x: switchX,
|
|
y: switchY,
|
|
width: switchWidth,
|
|
height: cellFrame.size.height)
|
|
return switchFrame
|
|
}
|
|
|
|
@objc
|
|
func predictionSwitchValueChanged(source: UISwitch) {
|
|
let value = source.isOn;
|
|
let userDefaults = Storage.active.userDefaults
|
|
userDefaults.set(predictSetting: value, forLanguageID: self.language.id)
|
|
|
|
// Reactively set the corrections switch interactivity state.
|
|
self.doCorrectionsSwitch?.isHidden = !value
|
|
self.doCorrectionsLabel?.isEnabled = value
|
|
self.correctionsCell?.isUserInteractionEnabled = value
|
|
|
|
if let lm = Manager.shared.preferredLexicalModel(userDefaults, forLanguage: self.language.id) {
|
|
if Manager.shared.currentKeyboardID?.languageID == self.language.id {
|
|
// re-register the model - that'll enact the settings.
|
|
_ = Manager.shared.registerLexicalModel(lm)
|
|
}
|
|
}
|
|
}
|
|
|
|
@objc
|
|
func correctionSwitchValueChanged(source: UISwitch) {
|
|
let value = source.isOn;
|
|
let userDefaults = Storage.active.userDefaults
|
|
userDefaults.set(correctSetting: value, forLanguageID: self.language.id)
|
|
|
|
if let lm = Manager.shared.preferredLexicalModel(userDefaults, forLanguage: self.language.id) {
|
|
if Manager.shared.currentKeyboardID?.languageID == self.language.id {
|
|
// re-register the model - that'll enact the settings.
|
|
_ = Manager.shared.registerLexicalModel(lm)
|
|
}
|
|
}
|
|
}
|
|
|
|
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
|
let userDefaults = Storage.active.userDefaults
|
|
|
|
let cellIdentifier = 0 == indexPath.section ? "KeyboardInLanguageSettingsCell" : "LanguageSettingsCell"
|
|
|
|
let reusableCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)
|
|
if let cell = reusableCell {
|
|
return cell
|
|
}
|
|
|
|
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: cellIdentifier)
|
|
if 1 == indexPath.section {
|
|
if 0 == indexPath.row {
|
|
cell.accessoryType = .none
|
|
doPredictionsSwitch = UISwitch()
|
|
doPredictionsSwitch!.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
let switchFrame = frameAtRightOfCell(cell: cell.frame, controlSize: doPredictionsSwitch!.frame.size)
|
|
doPredictionsSwitch!.frame = switchFrame
|
|
|
|
doPredictionsSwitch!.isOn = userDefaults.predictSettingForLanguage(languageID: self.language.id)
|
|
doPredictionsSwitch!.addTarget(self, action: #selector(self.predictionSwitchValueChanged), for: .valueChanged)
|
|
cell.addSubview(doPredictionsSwitch!)
|
|
if #available(iOSApplicationExtension 9.0, *) {
|
|
doPredictionsSwitch!.rightAnchor.constraint(equalTo: cell.layoutMarginsGuide.rightAnchor).isActive = true
|
|
doPredictionsSwitch!.centerYAnchor.constraint(equalTo: cell.layoutMarginsGuide.centerYAnchor).isActive = true
|
|
}
|
|
} else if 1 == indexPath.row {
|
|
correctionsCell = cell
|
|
cell.accessoryType = .none
|
|
doCorrectionsSwitch = UISwitch()
|
|
doCorrectionsSwitch!.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
let switchFrame = frameAtRightOfCell(cell: cell.frame, controlSize: doCorrectionsSwitch!.frame.size)
|
|
doCorrectionsSwitch!.frame = switchFrame
|
|
|
|
doCorrectionsSwitch!.isOn = userDefaults.correctSettingForLanguage(languageID: self.language.id)
|
|
doCorrectionsSwitch!.addTarget(self, action: #selector(self.correctionSwitchValueChanged), for: .valueChanged)
|
|
cell.addSubview(doCorrectionsSwitch!)
|
|
if #available(iOSApplicationExtension 9.0, *) {
|
|
doCorrectionsSwitch!.rightAnchor.constraint(equalTo: cell.layoutMarginsGuide.rightAnchor).isActive = true
|
|
doCorrectionsSwitch!.centerYAnchor.constraint(equalTo: cell.layoutMarginsGuide.centerYAnchor).isActive = true
|
|
}
|
|
|
|
// Disable interactivity if the prediction toggle is set to 'off'.
|
|
doCorrectionsSwitch!.isHidden = !userDefaults.predictSettingForLanguage(languageID: self.language.id)
|
|
cell.isUserInteractionEnabled = userDefaults.predictSettingForLanguage(languageID: self.language.id)
|
|
} else { // rows 3 and 4
|
|
cell.accessoryType = .disclosureIndicator
|
|
}
|
|
}
|
|
let selectionColor = UIView()
|
|
selectionColor.backgroundColor = Colors.selectionPrimary
|
|
cell.selectedBackgroundView = selectionColor
|
|
cell.textLabel?.font = cell.textLabel?.font?.withSize(16.0)
|
|
return cell
|
|
}
|
|
|
|
// MARK: - UITableViewDelegate
|
|
|
|
// fixed font style. use custom view (UILabel) if you want something different
|
|
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
|
var title: String
|
|
switch (section) {
|
|
case 0:
|
|
title = "Keyboards"
|
|
case 1:
|
|
title = "Language settings"
|
|
default:
|
|
title = "unknown header"
|
|
}
|
|
return title
|
|
}
|
|
|
|
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
|
|
{
|
|
if (section == 0 || section == 1)
|
|
{
|
|
return 32.0;
|
|
}
|
|
else
|
|
{
|
|
return CGFloat.leastNormalMagnitude;
|
|
}
|
|
}
|
|
|
|
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
|
|
return CGFloat.leastNonzeroMagnitude
|
|
}
|
|
|
|
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
|
|
|
cell.isUserInteractionEnabled = true
|
|
cell.textLabel?.isEnabled = true
|
|
cell.detailTextLabel?.isEnabled = true
|
|
if 0 == indexPath.section { // keyboard list
|
|
guard let keyboard = language.keyboards?[safe: indexPath.row] else {
|
|
return
|
|
}
|
|
cell.textLabel?.text = keyboard.name
|
|
cell.detailTextLabel?.text = keyboard.version + " " + keyboard.id
|
|
|
|
cell.accessoryType = .disclosureIndicator
|
|
} else { // language settings
|
|
cell.accessoryType = .none
|
|
switch indexPath.row {
|
|
case 0:
|
|
cell.textLabel?.text = "Enable predictions"
|
|
case 1:
|
|
doCorrectionsLabel = cell.textLabel
|
|
cell.textLabel?.text = "Enable corrections"
|
|
cell.textLabel?.isEnabled = !(doCorrectionsSwitch?.isHidden ?? false)
|
|
case 2:
|
|
cell.textLabel?.text = "Dictionaries"
|
|
cell.accessoryType = .disclosureIndicator
|
|
if let modelCt = language.lexicalModels?.count {
|
|
switch modelCt {
|
|
case 0:
|
|
cell.detailTextLabel?.text = "no dictionaries installed"
|
|
case 1:
|
|
cell.detailTextLabel?.text = "\(language.lexicalModels![0].name)"
|
|
default:
|
|
cell.detailTextLabel?.text = "\(modelCt) dictionaries installed"
|
|
}
|
|
} else {
|
|
cell.detailTextLabel?.text = "no dictionaries installed"
|
|
}
|
|
case 3: // future
|
|
cell.textLabel?.text = "Manage dictionary"
|
|
cell.accessoryType = .disclosureIndicator
|
|
cell.isUserInteractionEnabled = false
|
|
|
|
default:
|
|
cell.textLabel?.text = "error"
|
|
}
|
|
}
|
|
}
|
|
|
|
override open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
tableView.cellForRow(at: indexPath)?.isSelected = false
|
|
performAction(for: indexPath)
|
|
}
|
|
|
|
override open func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
|
|
performAction(for: indexPath)
|
|
}
|
|
|
|
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
|
|
if !Manager.shared.canRemoveKeyboards {
|
|
return false
|
|
}
|
|
|
|
// No deletion of the settings toggles!
|
|
if indexPath.section != 0 {
|
|
return false
|
|
}
|
|
|
|
// Will we have at least one keyboard left somewhere if this one is deleted? (Even if not same language)
|
|
if Storage.active.userDefaults.userKeyboards?.count ?? 0 > 1 {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle,
|
|
forRowAt indexPath: IndexPath) {
|
|
if editingStyle == .delete {
|
|
if let globalIndex = getKeyboardIndex(kb: (language.keyboards?[safe: indexPath.row])!) {
|
|
if Manager.shared.removeKeyboard(at: globalIndex) {
|
|
// For now, a pop-back will be sufficient.
|
|
navigationController?.popToRootViewController(animated: true)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Do nothing for now.
|
|
}
|
|
|
|
@objc func addClicked(_ sender: Any) {
|
|
showAddLanguageKeyboard()
|
|
}
|
|
|
|
func showAddLanguageKeyboard() {
|
|
let button: UIButton? = (navigationController?.toolbar?.viewWithTag(toolbarButtonTag) as? UIButton)
|
|
button?.isEnabled = false
|
|
let vc = LanguageDetailViewController(keyboardRepository, language: language)
|
|
vc.title = "Add new \(language.name) keyboard"
|
|
navigationController?.pushViewController(vc, animated: true)
|
|
}
|
|
|
|
private func performAction(for indexPath: IndexPath) {
|
|
switch indexPath.section {
|
|
case 0:
|
|
showKeyboardInfoView(kb: (language.keyboards?[safe: indexPath.row])!)
|
|
case 1:
|
|
switch indexPath.row {
|
|
// case 0, 1: the toggles - but a general 'click' not on the toggle itself.
|
|
case 2:
|
|
showLexicalModelsView()
|
|
default:
|
|
break
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
func getKeyboardIndex(kb: Keyboard) -> Int? {
|
|
let matchingFullID = FullKeyboardID(keyboardID: kb.id, languageID: language.id)
|
|
let userData = Storage.active.userDefaults
|
|
|
|
// If user defaults for keyboards list does not exist, do nothing.
|
|
guard let globalUserKeyboards = userData.userKeyboards else {
|
|
log.error("no keyboards in the global keyboards list!")
|
|
return nil
|
|
}
|
|
|
|
if let index = globalUserKeyboards.firstIndex(where: { $0.fullID == matchingFullID }) {
|
|
guard index < globalUserKeyboards.count else {
|
|
return nil
|
|
}
|
|
return index
|
|
} else {
|
|
log.error("this keyboard \(matchingFullID) not found among user's installed keyboards!")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func showKeyboardInfoView(kb: Keyboard) {
|
|
let matchingFullID = FullKeyboardID(keyboardID: kb.id, languageID: language.id)
|
|
|
|
let userData = Storage.active.userDefaults
|
|
|
|
// If user defaults for keyboards list does not exist, do nothing.
|
|
guard let globalUserKeyboards = userData.userKeyboards else {
|
|
log.error("no keyboards in the global keyboards list!")
|
|
return
|
|
}
|
|
|
|
if let index = getKeyboardIndex(kb: kb) {
|
|
guard index < globalUserKeyboards.count else {
|
|
return
|
|
}
|
|
let kbIndex:Int = index
|
|
let thisKb = globalUserKeyboards[kbIndex]
|
|
let infoView = ResourceInfoViewController(for: thisKb)
|
|
infoView.title = thisKb.name
|
|
infoView.keyboardCount = globalUserKeyboards.count
|
|
infoView.keyboardIndex = index
|
|
infoView.isCustomKeyboard = thisKb.isCustom
|
|
navigationController?.pushViewController(infoView, animated: true)
|
|
} else {
|
|
log.error("this keyboard \(matchingFullID) not found among user's installed keyboards!")
|
|
return
|
|
}
|
|
}
|
|
|
|
func showLexicalModelsView() {
|
|
//LanguageLexicalModelPickerViewController? (should show just the models for this language)
|
|
let lmListView = LexicalModelPickerViewController(self.language)
|
|
lmListView.language = self.language
|
|
navigationController?.pushViewController(lmListView, animated: true)
|
|
}
|
|
|
|
func showLexicalModelInfoView() {
|
|
if let lm = language.lexicalModels?[safe: 0] {
|
|
let version = lm.version
|
|
let matchingFullID = FullLexicalModelID(lexicalModelID: lm.id, languageID: language.id)
|
|
|
|
let userData = Storage.active.userDefaults
|
|
|
|
if let globalUserLexicalModels = userData.userLexicalModels {
|
|
if let index = globalUserLexicalModels.firstIndex(where: { $0.fullID == matchingFullID }) {
|
|
guard index < globalUserLexicalModels.count else {
|
|
return
|
|
}
|
|
let lmIndex:Int = index
|
|
let thisLm = globalUserLexicalModels[lmIndex]
|
|
let infoView = LexicalModelInfoViewController()
|
|
infoView.title = thisLm.name
|
|
infoView.lexicalModelCount = globalUserLexicalModels.count
|
|
infoView.lexicalModelIndex = index
|
|
infoView.lexicalModelID = thisLm.id
|
|
infoView.languageID = language.id
|
|
infoView.lexicalModelVersion = version ?? InstallableConstants.defaultVersion
|
|
infoView.isCustomLexicalModel = thisLm.isCustom
|
|
navigationController?.pushViewController(infoView, animated: true)
|
|
} else {
|
|
log.error("this lexical model \(matchingFullID) not found among language's installed lexical model!")
|
|
}
|
|
} else {
|
|
log.error("no lexical models in the global models list!")
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
// MARK: - Navigation
|
|
|
|
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
|
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
|
// Get the new view controller using segue.destination.
|
|
// Pass the selected object to the new view controller.
|
|
}
|
|
*/
|
|
|
|
}
|