mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-09 18:35:32 +00:00
97 lines
3.3 KiB
Swift
97 lines
3.3 KiB
Swift
//
|
|
// APILexicalModelRepository.swift
|
|
// KeymanEngine
|
|
//
|
|
// Created by Randy Boring on 3/19/19.
|
|
// Copyright © 2019 SIL International. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import UIKit // for UIDevice
|
|
|
|
public enum APILexicalModelFetchError: Error {
|
|
case networkError(Error)
|
|
case noData
|
|
case parsingError(Error)
|
|
}
|
|
|
|
public class APILexicalModelRepository: LexicalModelRepository {
|
|
private let modelsAPIURL = URLComponents(string: "https://api.keyman.com/model")! //?q=bcp47:en
|
|
|
|
public weak var delegate: LexicalModelRepositoryDelegate?
|
|
public private(set) var languages: [String: Language]?
|
|
public private(set) var lexicalModels: [String: LexicalModel]?
|
|
|
|
public func fetch(completionHandler: CompletionHandler?) {
|
|
let deviceType = UIDevice.current.userInterfaceIdiom == .phone ? "iphone" : "ipad"
|
|
let keymanVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
|
|
var urlComponents = modelsAPIURL
|
|
urlComponents.queryItems = [
|
|
URLQueryItem(name: "q", value: "bcp47:en") //+languages?[0]
|
|
]
|
|
log.info("Connecting to Keyman cloud: \(urlComponents.url!).")
|
|
let task = URLSession.shared.dataTask(with: urlComponents.url!) { (data, response, error) in
|
|
self.apiCompletionHandler(data: data, response: response, error: error,
|
|
fetchCompletionHandler: completionHandler)
|
|
}
|
|
task.resume()
|
|
}
|
|
|
|
private func apiCompletionHandler(data: Data?,
|
|
response: URLResponse?,
|
|
error: Error?,
|
|
fetchCompletionHandler: CompletionHandler?) {
|
|
let errorHandler = { (error: Error) -> Void in
|
|
DispatchQueue.main.async {
|
|
self.delegate?.lexicalModelRepository(self, didFailFetch: error)
|
|
fetchCompletionHandler?(error)
|
|
}
|
|
}
|
|
|
|
if let error = error {
|
|
log.error("Network error fetching languages: \(error)")
|
|
errorHandler(APILexicalModelFetchError.networkError(error))
|
|
return
|
|
}
|
|
guard let data = data else {
|
|
log.error("Language API did not return data")
|
|
errorHandler(APILexicalModelFetchError.noData)
|
|
return
|
|
}
|
|
|
|
let decoder = JSONDecoder()
|
|
decoder.dateDecodingStrategy = .secondsSince1970
|
|
let result: LanguagesAPICall
|
|
do {
|
|
result = try decoder.decode(LanguagesAPICall.self, from: data)
|
|
} catch {
|
|
log.error("Failed parsing API languages: \(error)")
|
|
errorHandler(APILexicalModelFetchError.parsingError(error))
|
|
return
|
|
}
|
|
|
|
languages = Dictionary(uniqueKeysWithValues: result.languages.map { ($0.id, $0) })
|
|
|
|
let lexicalModelsWithID = result.languages.flatMap { language in
|
|
language.lexicalModels?.map { lm in (lm.id, lm) } ?? []
|
|
}
|
|
lexicalModels = Dictionary(lexicalModelsWithID) { old, new in
|
|
var lm = old
|
|
if old.languages == nil {
|
|
lm.languages = new.languages
|
|
return lm
|
|
}
|
|
if let newLanguages = new.languages {
|
|
let oldLanguageIDs = Set(old.languages!.map { $0 })
|
|
lm.languages!.append(contentsOf: newLanguages.filter { !oldLanguageIDs.contains($0) })
|
|
}
|
|
return lm
|
|
}
|
|
|
|
log.info("Request completed -- \(result.languages.count) languages.")
|
|
DispatchQueue.main.async {
|
|
self.delegate?.lexicalModelRepositoryDidFetch(self)
|
|
fetchCompletionHandler?(nil)
|
|
}
|
|
}
|
|
}
|