spiegel-keyman/ios/engine/KMEI/KeymanEngine/Classes/KeyboardRepository/APIKeyboardRepository.swift

81 lines
2.8 KiB
Swift

//
// APIKeyboardRepository.swift
// KeymanEngine
//
// Created by Gabriel Wong on 2017-12-01.
// Copyright © 2017 SIL International. All rights reserved.
//
import Foundation
public enum APIKeyboardFetchError: Error {
case networkError(Error)
case noData
case parsingError(Error)
}
public class APIKeyboardRepository: KeyboardRepository {
private let languagesAPIURL = URLComponents(string: "https://r.keymanweb.com/api/4.0/languages")!
public weak var delegate: KeyboardRepositoryDelegate?
public private(set) var languages: [String: Language]?
public private(set) var keyboards: [String: Keyboard]?
public private(set) var options: Options?
public func fetch() {
let deviceType = UIDevice.current.userInterfaceIdiom == .phone ? "iphone" : "ipad"
var urlComponents = languagesAPIURL
urlComponents.queryItems = [
URLQueryItem(name: "dateformat", value: "seconds"),
URLQueryItem(name: "device", value: deviceType)
]
let task = URLSession.shared.dataTask(with: urlComponents.url!, completionHandler: apiCompletionHandler)
task.resume()
}
private func apiCompletionHandler(_ data: Data?, _ response: URLResponse?, _ error: Error?) {
if let error = error {
Manager.shared.kmLog("Network error fetching languages: \(error)", checkDebugPrinting: false)
delegate?.keyboardRepository(self, didFailFetch: APIKeyboardFetchError.networkError(error))
return
}
guard let data = data else {
Manager.shared.kmLog("Language API did not return data", checkDebugPrinting: false)
delegate?.keyboardRepository(self, didFailFetch: APIKeyboardFetchError.noData)
return
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970
let result: LanguagesAPICall
do {
result = try decoder.decode(LanguagesAPICall.self, from: data)
} catch {
Manager.shared.kmLog("Failed parsing API languages: \(error)", checkDebugPrinting: false)
delegate?.keyboardRepository(self, didFailFetch: APIKeyboardFetchError.parsingError(error))
return
}
options = result.options
languages = Dictionary(uniqueKeysWithValues: result.languages.map { ($0.id, $0) })
let keyboardsWithID = result.languages.flatMap { language in
language.keyboards?.map { kb in (kb.id, kb) } ?? []
}
keyboards = Dictionary(keyboardsWithID) { old, new in
var kb = old
if old.languages == nil {
kb.languages = new.languages
return kb
}
if let newLanguages = new.languages {
let oldLanguageIDs = Set(old.languages!.map { $0.id })
kb.languages!.append(contentsOf: newLanguages.filter { !oldLanguageIDs.contains($0.id) })
}
return kb
}
Manager.shared.kmLog("Request completed -- \(result.languages.count) languages.", checkDebugPrinting: true)
delegate?.keyboardRepositoryDidFetch(self)
}
}