iOS: Make more use of native Swift types

This commit is contained in:
Jonathan Schleifer 2019-06-20 01:15:26 +02:00
parent 0886af554c
commit 773af9361e
No known key found for this signature in database
GPG key ID: 79D21189A2D4708D
4 changed files with 61 additions and 87 deletions

View file

@ -62,28 +62,16 @@ class AddSiteController: UITableViewController {
} }
@IBAction func done(_ sender: Any) { @IBAction func done(_ sender: Any) {
guard let name = nameField?.text?.ofObject else { return } guard let name = nameField?.text else { return }
guard let lengthString = lengthField?.text?.ofObject else { return } guard let lengthString = lengthField?.text else { return }
guard name.length > 0 else { guard name.count > 0 else {
showAlert(controller: self, title: "Name missing", showAlert(controller: self, title: "Name missing",
message: "Please enter a name.") message: "Please enter a name.")
return return
} }
var lengthValid = true guard let length = UInt(lengthString), length >= 3, length <= 64 else {
var length: size_t = 0
OFException.try({
length = lengthString.decimalValue
if length < 3 || length > 64 {
lengthValid = false
}
}, catch: { (OFException) in
lengthValid = false
})
guard lengthValid else {
showAlert(controller: self, title: "Invalid length", showAlert(controller: self, title: "Invalid length",
message: "Please enter a number between 3 and 64.") message: "Please enter a number between 3 and 64.")
return return
@ -97,10 +85,9 @@ class AddSiteController: UITableViewController {
return return
} }
let keyFile = self.keyFile?.ofObject
siteStorage.setSite(name, length: length, siteStorage.setSite(name, length: length,
legacy: legacySwitch?.isOn ?? false, isLegacy: legacySwitch?.isOn ?? false,
keyFile: keyFile) keyFile: self.keyFile)
mainViewController?.reset() mainViewController?.reset()
navigationController?.popViewController(animated: true) navigationController?.popViewController(animated: true)
} }

View file

@ -25,7 +25,7 @@ import ObjFW
class MainViewController: UIViewController, UISearchBarDelegate, class MainViewController: UIViewController, UISearchBarDelegate,
UITableViewDelegate, UITableViewDataSource { UITableViewDelegate, UITableViewDataSource {
public var sites = OFArray<OFString>() public var sites: [String] = []
public var siteStorage = SiteStorage() public var siteStorage = SiteStorage()
@IBOutlet var searchBar: UISearchBar? @IBOutlet var searchBar: UISearchBar?
@IBOutlet var tableView: UITableView? @IBOutlet var tableView: UITableView?
@ -51,12 +51,12 @@ class MainViewController: UIViewController, UISearchBarDelegate,
cellForRowAt indexPath: IndexPath) -> UITableViewCell { cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "site") ?? let cell = tableView.dequeueReusableCell(withIdentifier: "site") ??
UITableViewCell(style: .default, reuseIdentifier: "site") UITableViewCell(style: .default, reuseIdentifier: "site")
cell.textLabel?.text = sites[indexPath.row].nsObject cell.textLabel?.text = sites[indexPath.row]
return cell return cell
} }
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
sites = siteStorage.sites(withFilter: searchBar.text?.ofObject) sites = siteStorage.sites(withFilter: searchBar.text)
tableView?.reloadData() tableView?.reloadData()
} }

View file

@ -32,10 +32,10 @@ class ShowDetailsController: UITableViewController, UITextFieldDelegate {
@IBOutlet var passphraseField: UITextField? @IBOutlet var passphraseField: UITextField?
public var mainViewController: MainViewController? public var mainViewController: MainViewController?
private var name: OFString = "".ofObject private var name: String = ""
private var length: size_t = 0 private var length: UInt = 0
private var isLegacy: Bool = false private var isLegacy: Bool = false
private var keyFile: OFString? = nil private var keyFile: String? = nil
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
@ -50,10 +50,10 @@ class ShowDetailsController: UITableViewController, UITextFieldDelegate {
isLegacy = siteStorage.isLegacy(site: name) isLegacy = siteStorage.isLegacy(site: name)
keyFile = siteStorage.keyFile(forSite: name) keyFile = siteStorage.keyFile(forSite: name)
nameField?.text = name.nsObject nameField?.text = name
lengthField?.text = "\(length)" lengthField?.text = "\(length)"
legacySwitch?.isOn = isLegacy legacySwitch?.isOn = isLegacy
keyFileField?.text = keyFile?.nsObject keyFileField?.text = keyFile
tableView.deselectRow(at: indexPath, animated: true) tableView.deselectRow(at: indexPath, animated: true)
} }
@ -134,8 +134,8 @@ class ShowDetailsController: UITableViewController, UITextFieldDelegate {
private func generateWithCallback(_ block: (_: NSMutableString) -> ()) { private func generateWithCallback(_ block: (_: NSMutableString) -> ()) {
let generator: PasswordGenerator = isLegacy ? let generator: PasswordGenerator = isLegacy ?
LegacyPasswordGenerator() : NewPasswordGenerator() LegacyPasswordGenerator() : NewPasswordGenerator()
generator.site = name generator.site = name.ofObject
generator.length = length generator.length = size_t(length)
if let keyFile = keyFile { if let keyFile = keyFile {
guard let documentDirectory = NSSearchPathForDirectoriesInDomains( guard let documentDirectory = NSSearchPathForDirectoriesInDomains(
@ -145,7 +145,8 @@ class ShowDetailsController: UITableViewController, UITextFieldDelegate {
return return
} }
let keyFilePath = documentDirectory.ofObject.appending(keyFile) let keyFilePath =
documentDirectory.ofObject.appending(keyFile.ofObject)
generator.keyFile = OFMutableData(contentsOfFile: keyFilePath) generator.keyFile = OFMutableData(contentsOfFile: keyFilePath)
} }

View file

@ -24,16 +24,13 @@ import ObjFW
import ObjFWBridge import ObjFWBridge
class SiteStorage: OFObject { class SiteStorage: OFObject {
private typealias Storage = private static let lengthField = NSNumber(value: 0)
OFMutableDictionary<OFString, OFDictionary<OFNumber, AnyObject>> private static let legacyField = NSNumber(value: 1)
private static let keyFileField = NSNumber(value: 2)
private static let lengthField = OFNumber(uInt8: 0)
private static let legacyField = OFNumber(uInt8: 1)
private static let keyFileField = OFNumber(uInt8: 2)
private var path: OFString private var path: OFString
private var storage: Storage private var storage: [String: [NSNumber: AnyObject]]
private var sites: OFArray<OFString> private var sites: [String]
override init() { override init() {
let fileManager = OFFileManager.default let fileManager = OFFileManager.default
@ -45,91 +42,80 @@ class SiteStorage: OFObject {
let path = userDataPath.appendingPathComponent( let path = userDataPath.appendingPathComponent(
OFString(utf8String: "sites.msgpack")) OFString(utf8String: "sites.msgpack"))
var storage: Storage? = nil
var storage: [String: [NSNumber: AnyObject]]? = nil
OFException.try({ OFException.try({
storage = OFData(contentsOfFile: path).messagePackValue as? Storage let decoded = (OFData(contentsOfFile: path).messagePackValue)
as? OFDictionary<OFString, OFDictionary<OFNumber, AnyObject>>
storage =
(decoded?.nsObject as? [String: [NSNumber: AnyObject]]) ?? [:]
}, catch: { (OFException) in }, catch: { (OFException) in
storage = OFMutableDictionary() storage = [:]
}) })
self.path = path self.path = path
self.storage = storage! self.storage = storage!
self.sites = self.storage.allKeys.sorted self.sites = self.storage.keys.sorted()
} }
func sites(withFilter filter: OFString?) -> OFArray<OFString> { func sites(withFilter filter: String?) -> [String] {
// FIXME: We need case folding here, but there is no method for it yet. return storage.keys.sorted().filter({ (name) in
let filter = filter?.lowercase if let filter = filter {
return name.localizedCaseInsensitiveContains(filter)
return storage.allKeys.sorted.filteredArray({
(name: Any, index: size_t) -> Bool in
if filter == nil {
return true
} }
return true
let name = name as! OFString
return name.lowercase.contains(filter!)
}) })
} }
func hasSite(_ name: OFString) -> Bool { func hasSite(_ name: String) -> Bool {
return (storage[name] != nil) return (storage[name] != nil)
} }
func length(forSite name: OFString) -> size_t { func length(forSite name: String) -> UInt {
guard let site = storage[name] else { guard let site = storage[name] else {
OFInvalidArgumentException().throw() OFInvalidArgumentException().throw()
} }
return (site[SiteStorage.lengthField] as! OFNumber).sizeValue return (site[SiteStorage.lengthField] as! NSNumber).uintValue
} }
func isLegacy(site name: OFString) -> Bool { func isLegacy(site name: String) -> Bool {
guard let site = storage[name] else { guard let site = storage[name] else { return false }
OFInvalidArgumentException().throw() return (site[SiteStorage.legacyField] as! NSNumber).boolValue
}
return (site[SiteStorage.legacyField] as! OFNumber).boolValue
} }
func keyFile(forSite name: OFString) -> OFString? { func keyFile(forSite name: String) -> String? {
guard let site = storage[name] else { guard let site = storage[name] else { return nil }
OFInvalidArgumentException().throw()
}
let keyFile = site[SiteStorage.keyFileField] guard let keyFile = site[SiteStorage.keyFileField], !(keyFile is NSNull)
if keyFile is OFNull { else {
return nil return nil
} }
return keyFile as? OFString return keyFile as? String
} }
func setSite(_ name: OFString, length: size_t, legacy: Bool, func setSite(_ name: String, length: UInt, isLegacy: Bool,
keyFile: OFString?) { keyFile: String?) {
let siteDictionary = OFMutableDictionary<OFNumber, AnyObject>() var siteDictionary: [NSNumber: AnyObject] = [
SiteStorage.lengthField: NSNumber(value: length),
siteDictionary.setObject(OFNumber(size: length), SiteStorage.legacyField: NSNumber(value: isLegacy),
forKey: SiteStorage.lengthField) ]
siteDictionary.setObject(OFNumber(bool: legacy), siteDictionary[SiteStorage.keyFileField] = keyFile as AnyObject?
forKey: SiteStorage.legacyField)
if keyFile != nil {
siteDictionary.setObject(keyFile!, forKey: SiteStorage.keyFileField)
}
siteDictionary.makeImmutable()
storage.setObject(siteDictionary, forKey: name)
storage[name] = siteDictionary
self.update() self.update()
} }
func removeSite(_ name: OFString) { func removeSite(_ name: String) {
self.storage.removeObject(forKey: name) storage[name] = nil
self.update() self.update()
} }
private func update() { private func update() {
storage.messagePackRepresentation.write(toFile: path) let ofStorage = (storage as NSDictionary).ofObject
sites = storage.allKeys.sorted
ofStorage.messagePackRepresentation.write(toFile: path)
sites = storage.keys.sorted()
} }
} }