can now download a lexical model from the cloud

This commit is contained in:
Randy Boring 2019-07-23 12:39:46 -04:00
parent 641f3c271a
commit 0828049385
3 changed files with 272 additions and 25 deletions

View file

@ -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
}
}

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="LanguageLMDetailViewController" customModuleProvider="target">
<connections>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableView opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" bouncesZoom="NO" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="vLr-E1-eTs"/>
<connections>
<outlet property="dataSource" destination="-1" id="Tng-2m-Rnh"/>
<outlet property="delegate" destination="-1" id="9aC-8N-iBw"/>
</connections>
</tableView>
</objects>
</document>

View file

@ -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)
}
}