iOS: Make more use of native Swift types
This commit is contained in:
parent
0886af554c
commit
773af9361e
4 changed files with 61 additions and 87 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue