Format code with SwiftFormat automatically in every build
This commit is contained in:
parent
f167ab7549
commit
7f9f0e43b2
100 changed files with 1124 additions and 1063 deletions
|
|
@ -6,15 +6,14 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import CoreData
|
||||
import SVProgressHUD
|
||||
import passKit
|
||||
import SVProgressHUD
|
||||
import SwiftyUserDefaults
|
||||
import UIKit
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
enum ViewTag: Int {
|
||||
case blur = 100, appicon
|
||||
|
|
@ -25,50 +24,51 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
return presenter
|
||||
}()
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
func application(_: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
SVProgressHUD.setMinimumSize(CGSize(width: 150, height: 100))
|
||||
passcodeLockPresenter.present(windowLevel: UIApplication.shared.windows.last?.windowLevel.rawValue)
|
||||
if let shortcutItem = launchOptions?[UIApplication.LaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem {
|
||||
if shortcutItem.type == Globals.bundleIdentifier + ".search" {
|
||||
self.perform(#selector(postSearchNotification), with: nil, afterDelay: 0.4)
|
||||
perform(#selector(postSearchNotification), with: nil, afterDelay: 0.4)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
|
||||
func application(_: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
|
||||
if let _ = window?.rootViewController as? PasscodeLockViewController {
|
||||
window?.frame = UIScreen.main.bounds
|
||||
}
|
||||
return .all
|
||||
}
|
||||
|
||||
@objc func postSearchNotification() {
|
||||
@objc
|
||||
func postSearchNotification() {
|
||||
NotificationCenter.default.post(name: .passwordSearch, object: nil)
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
|
||||
func application(_: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler _: @escaping (Bool) -> Void) {
|
||||
if shortcutItem.type == Globals.bundleIdentifier + ".search" {
|
||||
let tabBarController = self.window!.rootViewController as! UITabBarController
|
||||
let tabBarController = window!.rootViewController as! UITabBarController
|
||||
tabBarController.selectedIndex = 0
|
||||
let navigationController = tabBarController.selectedViewController as! UINavigationController
|
||||
navigationController.popToRootViewController(animated: false)
|
||||
self.perform(#selector(postSearchNotification), with: nil, afterDelay: 0.4)
|
||||
perform(#selector(postSearchNotification), with: nil, afterDelay: 0.4)
|
||||
}
|
||||
}
|
||||
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
func applicationWillResignActive(_: UIApplication) {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
|
||||
|
||||
// Display a blur effect view
|
||||
let blurEffect = UIBlurEffect(style: UIBlurEffect.Style.light)
|
||||
let blurEffectView = UIVisualEffectView(effect: blurEffect)
|
||||
blurEffectView.frame = (self.window?.frame)!
|
||||
blurEffectView.frame = (window?.frame)!
|
||||
blurEffectView.tag = ViewTag.blur.rawValue
|
||||
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
self.window?.addSubview(blurEffectView)
|
||||
window?.addSubview(blurEffectView)
|
||||
|
||||
// Display the Pass icon in the middle of the screen
|
||||
let iconsDictionary = Bundle.main.infoDictionary?["CFBundleIcons"] as? NSDictionary
|
||||
|
|
@ -78,33 +78,32 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
let appIconView = UIImageView(image: appIcon)
|
||||
appIconView.layer.cornerRadius = (appIcon?.size.height)! / 5
|
||||
appIconView.layer.masksToBounds = true
|
||||
appIconView.center = (self.window?.center)!
|
||||
appIconView.center = (window?.center)!
|
||||
appIconView.tag = ViewTag.appicon.rawValue
|
||||
self.window?.addSubview(appIconView)
|
||||
window?.addSubview(appIconView)
|
||||
}
|
||||
|
||||
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||
func applicationDidEnterBackground(_: UIApplication) {
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
|
||||
}
|
||||
|
||||
func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
func applicationWillEnterForeground(_: UIApplication) {
|
||||
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
|
||||
passcodeLockPresenter.present(windowLevel: UIApplication.shared.windows.last?.windowLevel.rawValue)
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
func applicationDidBecomeActive(_: UIApplication) {
|
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||
|
||||
self.window?.viewWithTag(ViewTag.appicon.rawValue)?.removeFromSuperview()
|
||||
self.window?.viewWithTag(ViewTag.blur.rawValue)?.removeFromSuperview()
|
||||
window?.viewWithTag(ViewTag.appicon.rawValue)?.removeFromSuperview()
|
||||
window?.viewWithTag(ViewTag.blur.rawValue)?.removeFromSuperview()
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
func applicationWillTerminate(_: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
// Saves changes in the application's managed object context before the application terminates.
|
||||
self.saveContext()
|
||||
saveContext()
|
||||
}
|
||||
|
||||
// MARK: - Core Data stack
|
||||
|
|
@ -123,7 +122,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
try! FileManager.default.createDirectory(atPath: Globals.documentPath, withIntermediateDirectories: true, attributes: nil)
|
||||
}
|
||||
container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: URL(fileURLWithPath: Globals.dbPath))]
|
||||
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
|
||||
container.loadPersistentStores(completionHandler: { _, error in
|
||||
if let error = error as NSError? {
|
||||
// Replace this implementation with code to handle the error appropriately.
|
||||
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
||||
|
|
@ -144,7 +143,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
|
||||
// MARK: - Core Data Saving support
|
||||
|
||||
func saveContext () {
|
||||
func saveContext() {
|
||||
let context = persistentContainer.viewContext
|
||||
if context.hasChanges {
|
||||
do {
|
||||
|
|
@ -157,6 +156,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,11 +6,10 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import passKit
|
||||
import UIKit
|
||||
|
||||
class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
||||
|
||||
private static let VALUE_NOT_AVAILABLE = "ValueNotAvailable".localize()
|
||||
|
||||
private var needRefresh = false
|
||||
|
|
@ -18,6 +17,7 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
|||
let indicator = UIActivityIndicatorView(style: .gray)
|
||||
return indicator
|
||||
}()
|
||||
|
||||
private let passwordStore = PasswordStore.shared
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
|
@ -41,10 +41,9 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
|||
}
|
||||
|
||||
private func setTableData() {
|
||||
|
||||
// clear current contents (if any)
|
||||
self.tableData.removeAll(keepingCapacity: true)
|
||||
self.tableView.reloadData()
|
||||
tableData.removeAll(keepingCapacity: true)
|
||||
tableView.reloadData()
|
||||
indicator.startAnimating()
|
||||
|
||||
// reload the table
|
||||
|
|
@ -67,8 +66,7 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
|||
[.style: CellDataStyle.value1, .accessoryType: type, .title: "LocalCommits".localize(), .detailText: localCommits],
|
||||
[.style: CellDataStyle.value1, .accessoryType: type, .title: "LastSynced".localize(), .detailText: lastSynced],
|
||||
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Commits".localize(), .detailText: commits],
|
||||
[.title: "CommitLogs".localize(), .action: "segue", .link: "showCommitLogsSegue"],
|
||||
],
|
||||
[.title: "CommitLogs".localize(), .action: "segue", .link: "showCommitLogsSegue"]],
|
||||
]
|
||||
strongSelf.indicator.stopAnimating()
|
||||
strongSelf.tableView.reloadData()
|
||||
|
|
@ -79,15 +77,15 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
|||
private func numberOfPasswordsString() -> String {
|
||||
let formatter = NumberFormatter()
|
||||
formatter.numberStyle = NumberFormatter.Style.decimal
|
||||
return formatter.string(from: NSNumber(value: self.passwordStore.numberOfPasswords)) ?? ""
|
||||
return formatter.string(from: NSNumber(value: passwordStore.numberOfPasswords)) ?? ""
|
||||
}
|
||||
|
||||
private func sizeOfRepositoryString() -> String {
|
||||
return ByteCountFormatter.string(fromByteCount: Int64(self.passwordStore.sizeOfRepositoryByteCount), countStyle: ByteCountFormatter.CountStyle.file)
|
||||
ByteCountFormatter.string(fromByteCount: Int64(passwordStore.sizeOfRepositoryByteCount), countStyle: ByteCountFormatter.CountStyle.file)
|
||||
}
|
||||
|
||||
private func lastSyncedTimeString() -> String {
|
||||
guard let date = self.passwordStore.lastSyncedTime else {
|
||||
guard let date = passwordStore.lastSyncedTime else {
|
||||
return "SyncAgain?".localize()
|
||||
}
|
||||
let formatter = DateFormatter()
|
||||
|
|
@ -103,7 +101,8 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
|||
return AboutRepositoryTableViewController.VALUE_NOT_AVAILABLE
|
||||
}
|
||||
|
||||
@objc func setNeedRefresh() {
|
||||
@objc
|
||||
func setNeedRefresh() {
|
||||
needRefresh = true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,17 +9,16 @@
|
|||
import UIKit
|
||||
|
||||
class AboutTableViewController: BasicStaticTableViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
tableData = [
|
||||
// section 0
|
||||
[[.title: "Website".localize(), .action: "link", .link: "https://github.com/mssun/pass-ios.git"],
|
||||
[.title: "Help".localize(), .action: "link", .link: "https://github.com/mssun/passforios/wiki"],
|
||||
[.title: "ContactDeveloper".localize(), .action: "link", .link: "mailto:developer@passforios.mssun.me?subject=Pass%20for%20iOS"],],
|
||||
[.title: "ContactDeveloper".localize(), .action: "link", .link: "mailto:developer@passforios.mssun.me?subject=Pass%20for%20iOS"]],
|
||||
|
||||
// section 1,
|
||||
[[.title: "OpenSourceComponents".localize(), .action: "segue", .link: "showOpenSourceComponentsSegue"],
|
||||
[.title: "SpecialThanks".localize(), .action: "segue", .link: "showSpecialThanksSegue"],],
|
||||
[.title: "SpecialThanks".localize(), .action: "segue", .link: "showSpecialThanksSegue"]],
|
||||
]
|
||||
super.viewDidLoad()
|
||||
}
|
||||
|
|
@ -39,11 +38,10 @@ class AboutTableViewController: BasicStaticTableViewController {
|
|||
return nil
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
override func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
if section == 1 {
|
||||
return "Acknowledgements".localize().uppercased()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import passKit
|
||||
import UIKit
|
||||
|
||||
class AddPasswordTableViewController: PasswordEditorTableViewController {
|
||||
var defaultDirPrefix = ""
|
||||
|
|
@ -17,7 +17,7 @@ class AddPasswordTableViewController: PasswordEditorTableViewController {
|
|||
tableData[0][0][PasswordEditorCellKey.content] = defaultDirPrefix
|
||||
}
|
||||
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender _: Any?) -> Bool {
|
||||
if identifier == "saveAddPasswordSegue" {
|
||||
// check PGP key
|
||||
guard PGPAgent.shared.isPrepared else {
|
||||
|
|
|
|||
|
|
@ -6,16 +6,15 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SVProgressHUD
|
||||
import passKit
|
||||
import SVProgressHUD
|
||||
import UIKit
|
||||
|
||||
class AdvancedSettingsTableViewController: UITableViewController {
|
||||
|
||||
@IBOutlet weak var encryptInASCIIArmoredTableViewCell: UITableViewCell!
|
||||
@IBOutlet weak var gitSignatureTableViewCell: UITableViewCell!
|
||||
@IBOutlet weak var eraseDataTableViewCell: UITableViewCell!
|
||||
@IBOutlet weak var discardChangesTableViewCell: UITableViewCell!
|
||||
@IBOutlet var encryptInASCIIArmoredTableViewCell: UITableViewCell!
|
||||
@IBOutlet var gitSignatureTableViewCell: UITableViewCell!
|
||||
@IBOutlet var eraseDataTableViewCell: UITableViewCell!
|
||||
@IBOutlet var discardChangesTableViewCell: UITableViewCell!
|
||||
let passwordStore = PasswordStore.shared
|
||||
|
||||
let encryptInASCIIArmoredSwitch: UISwitch = {
|
||||
|
|
@ -37,10 +36,10 @@ class AdvancedSettingsTableViewController: UITableViewController {
|
|||
private func setGitSignatureText() {
|
||||
let gitSignatureName = passwordStore.gitSignatureForNow?.name ?? ""
|
||||
let gitSignatureEmail = passwordStore.gitSignatureForNow?.email ?? ""
|
||||
self.gitSignatureTableViewCell.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .footnote)
|
||||
self.gitSignatureTableViewCell.detailTextLabel?.text = "\(gitSignatureName) <\(gitSignatureEmail)>"
|
||||
if Defaults.gitSignatureName == nil && Defaults.gitSignatureEmail == nil {
|
||||
self.gitSignatureTableViewCell.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .body)
|
||||
gitSignatureTableViewCell.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .footnote)
|
||||
gitSignatureTableViewCell.detailTextLabel?.text = "\(gitSignatureName) <\(gitSignatureEmail)>"
|
||||
if Defaults.gitSignatureName == nil, Defaults.gitSignatureEmail == nil {
|
||||
gitSignatureTableViewCell.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .body)
|
||||
gitSignatureTableViewCell.detailTextLabel?.text = "NotSet".localize()
|
||||
}
|
||||
}
|
||||
|
|
@ -49,7 +48,7 @@ class AdvancedSettingsTableViewController: UITableViewController {
|
|||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
if tableView.cellForRow(at: indexPath) == eraseDataTableViewCell {
|
||||
let alert = UIAlertController(title: "ErasePasswordStoreData?".localize(), message: "EraseExplanation.".localize(), preferredStyle: UIAlertController.Style.alert)
|
||||
alert.addAction(UIAlertAction(title: "ErasePasswordStoreData".localize(), style: UIAlertAction.Style.destructive, handler: {[unowned self] (action) -> Void in
|
||||
alert.addAction(UIAlertAction(title: "ErasePasswordStoreData".localize(), style: UIAlertAction.Style.destructive, handler: { [unowned self] (_) -> Void in
|
||||
SVProgressHUD.show(withStatus: "Erasing...".localize())
|
||||
self.passwordStore.erase()
|
||||
self.navigationController!.popViewController(animated: true)
|
||||
|
|
@ -57,10 +56,10 @@ class AdvancedSettingsTableViewController: UITableViewController {
|
|||
SVProgressHUD.dismiss(withDelay: 1)
|
||||
}))
|
||||
alert.addAction(UIAlertAction.dismiss())
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
present(alert, animated: true, completion: nil)
|
||||
} else if tableView.cellForRow(at: indexPath) == discardChangesTableViewCell {
|
||||
let alert = UIAlertController(title: "DiscardAllLocalChanges?".localize(), message: "DiscardExplanation.".localize(), preferredStyle: UIAlertController.Style.alert)
|
||||
alert.addAction(UIAlertAction(title: "DiscardAllLocalChanges".localize(), style: UIAlertAction.Style.destructive, handler: {[unowned self] (action) -> Void in
|
||||
alert.addAction(UIAlertAction(title: "DiscardAllLocalChanges".localize(), style: UIAlertAction.Style.destructive, handler: { [unowned self] (_) -> Void in
|
||||
SVProgressHUD.show(withStatus: "Resetting...".localize())
|
||||
do {
|
||||
let numberDiscarded = try self.passwordStore.reset()
|
||||
|
|
@ -73,15 +72,17 @@ class AdvancedSettingsTableViewController: UITableViewController {
|
|||
|
||||
}))
|
||||
alert.addAction(UIAlertAction.dismiss())
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
present(alert, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func encryptInASCIIArmoredAction(_ sender: Any?) {
|
||||
@objc
|
||||
func encryptInASCIIArmoredAction(_: Any?) {
|
||||
Defaults.encryptInArmored = encryptInASCIIArmoredSwitch.isOn
|
||||
}
|
||||
|
||||
@IBAction func saveGitConfigSetting(segue: UIStoryboardSegue) {
|
||||
@IBAction
|
||||
func saveGitConfigSetting(segue: UIStoryboardSegue) {
|
||||
if let controller = segue.source as? GitConfigSettingsTableViewController {
|
||||
if let gitSignatureName = controller.nameTextField.text,
|
||||
let gitSignatureEmail = controller.emailTextField.text {
|
||||
|
|
@ -91,5 +92,4 @@ class AdvancedSettingsTableViewController: UITableViewController {
|
|||
setGitSignatureText()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,10 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SafariServices
|
||||
import MessageUI
|
||||
import passKit
|
||||
|
||||
import SafariServices
|
||||
import UIKit
|
||||
|
||||
enum CellDataType {
|
||||
case link, segue, empty, detail
|
||||
|
|
@ -25,7 +24,7 @@ enum CellDataKey {
|
|||
}
|
||||
|
||||
class BasicStaticTableViewController: UITableViewController, MFMailComposeViewControllerDelegate {
|
||||
var tableData = [[Dictionary<CellDataKey, Any>]]()
|
||||
var tableData = [[[CellDataKey: Any]]]()
|
||||
var navigationItemTitle: String?
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
|
@ -35,12 +34,12 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
|
|||
}
|
||||
}
|
||||
|
||||
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return tableData.count
|
||||
override func numberOfSections(in _: UITableView) -> Int {
|
||||
tableData.count
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return tableData[section].count
|
||||
override func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
tableData[section].count
|
||||
}
|
||||
|
||||
override func didReceiveMemoryWarning() {
|
||||
|
|
@ -48,8 +47,7 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
|
|||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
||||
override func tableView(_: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cellData = tableData[indexPath.section][indexPath.row]
|
||||
let cellDataStyle = cellData[CellDataKey.style] as? CellDataStyle
|
||||
var cell: UITableViewCell?
|
||||
|
|
@ -76,7 +74,7 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
|
|||
return cell ?? UITableViewCell()
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
|
||||
override func tableView(_: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
|
||||
let cellData = tableData[indexPath.section][indexPath.row]
|
||||
let selector = cellData[CellDataKey.detailDisclosureAction] as? Selector
|
||||
perform(selector, with: cellData[CellDataKey.detailDisclosureData])
|
||||
|
|
@ -108,7 +106,7 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
|
|||
}
|
||||
case "http", "https":
|
||||
let svc = SFSafariViewController(url: URL(string: link)!, entersReaderIfAvailable: false)
|
||||
self.present(svc, animated: true, completion: nil)
|
||||
present(svc, animated: true, completion: nil)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
|
@ -123,10 +121,10 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
|
|||
mailVC.setToRecipients(recipients)
|
||||
mailVC.setSubject(subject)
|
||||
mailVC.setMessageBody("", isHTML: false)
|
||||
self.present(mailVC, animated: true, completion: nil)
|
||||
present(mailVC, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
|
||||
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith _: MFMailComposeResult, error _: Error?) {
|
||||
controller.dismiss(animated: true)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import ObjectiveGit
|
||||
import passKit
|
||||
import UIKit
|
||||
|
||||
class CommitLogsTableViewController: UITableViewController {
|
||||
var commits: [GTCommit] = []
|
||||
|
|
@ -18,12 +18,12 @@ class CommitLogsTableViewController: UITableViewController {
|
|||
super.viewDidLoad()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(updateCommitLogs), name: .passwordStoreUpdated, object: nil)
|
||||
commits = getCommitLogs()
|
||||
self.tableView.estimatedRowHeight = 50
|
||||
self.tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.estimatedRowHeight = 50
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return commits.count
|
||||
override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int {
|
||||
commits.count
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
|
@ -42,7 +42,8 @@ class CommitLogsTableViewController: UITableViewController {
|
|||
return cell
|
||||
}
|
||||
|
||||
@objc func updateCommitLogs() {
|
||||
@objc
|
||||
func updateCommitLogs() {
|
||||
commits = getCommitLogs()
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import passKit
|
||||
import UIKit
|
||||
|
||||
class EditPasswordTableViewController: PasswordEditorTableViewController {
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender _: Any?) -> Bool {
|
||||
if identifier == "saveEditPasswordSegue" {
|
||||
// check name
|
||||
guard checkName() else {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import passKit
|
||||
import UIKit
|
||||
|
||||
class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||
let passwordStore = PasswordStore.shared
|
||||
|
|
@ -67,37 +67,35 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
override func viewDidLoad() {
|
||||
tableData = [
|
||||
// section 0
|
||||
[[.title: "AboutRepository".localize(), .action: "segue", .link: "showAboutRepositorySegue"],],
|
||||
[[.title: "AboutRepository".localize(), .action: "segue", .link: "showAboutRepositorySegue"]],
|
||||
|
||||
// section 1
|
||||
[
|
||||
[.title: "RememberPgpKeyPassphrase".localize(), .action: "none",],
|
||||
[.title: "RememberGitCredentialPassphrase".localize(), .action: "none",],
|
||||
[.title: "RememberPgpKeyPassphrase".localize(), .action: "none"],
|
||||
[.title: "RememberGitCredentialPassphrase".localize(), .action: "none"],
|
||||
],
|
||||
|
||||
|
||||
// section 2
|
||||
[
|
||||
[.title: "ShowFolders".localize(), .action: "none",],
|
||||
[.title: "HidePasswordImages".localize(), .action: "none",],
|
||||
[.title: "HideUnknownFields".localize(), .action: "none",],
|
||||
[.title: "HideOtpFields".localize(), .action: "none",],
|
||||
[.title: "ShowFolders".localize(), .action: "none"],
|
||||
[.title: "HidePasswordImages".localize(), .action: "none"],
|
||||
[.title: "HideUnknownFields".localize(), .action: "none"],
|
||||
[.title: "HideOtpFields".localize(), .action: "none"],
|
||||
],
|
||||
|
||||
]
|
||||
super.viewDidLoad()
|
||||
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = super.tableView(tableView, cellForRowAt: indexPath)
|
||||
let cell = super.tableView(tableView, cellForRowAt: indexPath)
|
||||
switch cell.textLabel!.text! {
|
||||
case "HideUnknownFields".localize():
|
||||
cell.accessoryType = .none
|
||||
let detailButton = UIButton(type: .detailDisclosure)
|
||||
hideUnknownSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hideUnknownSwitch.bounds.width, height: hideUnknownSwitch.bounds.height)
|
||||
hideUnknownSwitch.frame = CGRect(x: detailButton.bounds.width + 10, y: 0, width: hideUnknownSwitch.bounds.width, height: hideUnknownSwitch.bounds.height)
|
||||
detailButton.frame = CGRect(x: 0, y: 5, width: detailButton.bounds.width, height: detailButton.bounds.height)
|
||||
detailButton.addTarget(self, action: #selector(GeneralSettingsTableViewController.tapHideUnknownSwitchDetailButton(_:)), for: UIControl.Event.touchDown)
|
||||
let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hideUnknownSwitch.bounds.width+10, height: hideUnknownSwitch.bounds.height))
|
||||
let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hideUnknownSwitch.bounds.width + 10, height: hideUnknownSwitch.bounds.height))
|
||||
accessoryView.addSubview(detailButton)
|
||||
accessoryView.addSubview(hideUnknownSwitch)
|
||||
cell.accessoryView = accessoryView
|
||||
|
|
@ -106,10 +104,10 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
case "HideOtpFields".localize():
|
||||
cell.accessoryType = .none
|
||||
let detailButton = UIButton(type: .detailDisclosure)
|
||||
hideOTPSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hideOTPSwitch.bounds.width, height: hideOTPSwitch.bounds.height)
|
||||
hideOTPSwitch.frame = CGRect(x: detailButton.bounds.width + 10, y: 0, width: hideOTPSwitch.bounds.width, height: hideOTPSwitch.bounds.height)
|
||||
detailButton.frame = CGRect(x: 0, y: 5, width: detailButton.bounds.width, height: detailButton.bounds.height)
|
||||
detailButton.addTarget(self, action: #selector(GeneralSettingsTableViewController.tapHideOTPSwitchDetailButton(_:)), for: UIControl.Event.touchDown)
|
||||
let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hideOTPSwitch.bounds.width+10, height: hideOTPSwitch.bounds.height))
|
||||
let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hideOTPSwitch.bounds.width + 10, height: hideOTPSwitch.bounds.height))
|
||||
accessoryView.addSubview(detailButton)
|
||||
accessoryView.addSubview(hideOTPSwitch)
|
||||
cell.accessoryView = accessoryView
|
||||
|
|
@ -130,10 +128,10 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
case "HidePasswordImages".localize():
|
||||
cell.accessoryType = .none
|
||||
let detailButton = UIButton(type: .detailDisclosure)
|
||||
hidePasswordImagesSwitch.frame = CGRect(x: detailButton.bounds.width+10, y: 0, width: hidePasswordImagesSwitch.bounds.width, height: hidePasswordImagesSwitch.bounds.height)
|
||||
hidePasswordImagesSwitch.frame = CGRect(x: detailButton.bounds.width + 10, y: 0, width: hidePasswordImagesSwitch.bounds.width, height: hidePasswordImagesSwitch.bounds.height)
|
||||
detailButton.frame = CGRect(x: 0, y: 5, width: detailButton.bounds.width, height: detailButton.bounds.height)
|
||||
detailButton.addTarget(self, action: #selector(GeneralSettingsTableViewController.tapHidePasswordImagesSwitchDetailButton(_:)), for: UIControl.Event.touchDown)
|
||||
let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hidePasswordImagesSwitch.bounds.width+10, height: hidePasswordImagesSwitch.bounds.height))
|
||||
let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hidePasswordImagesSwitch.bounds.width + 10, height: hidePasswordImagesSwitch.bounds.height))
|
||||
accessoryView.addSubview(detailButton)
|
||||
accessoryView.addSubview(hidePasswordImagesSwitch)
|
||||
cell.accessoryView = accessoryView
|
||||
|
|
@ -144,43 +142,50 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
return cell
|
||||
}
|
||||
|
||||
@objc func tapHideUnknownSwitchDetailButton(_ sender: Any?) {
|
||||
@objc
|
||||
func tapHideUnknownSwitchDetailButton(_: Any?) {
|
||||
let alertMessage = "HideUnknownFieldsExplanation.".localize()
|
||||
let alertTitle = "HideUnknownFields".localize()
|
||||
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
||||
}
|
||||
|
||||
@objc func tapHideOTPSwitchDetailButton(_ sender: Any?) {
|
||||
@objc
|
||||
func tapHideOTPSwitchDetailButton(_: Any?) {
|
||||
let keywordsString = Constants.OTP_KEYWORDS.joined(separator: ", ")
|
||||
let alertMessage = "HideOtpFieldsExplanation.".localize(keywordsString)
|
||||
let alertTitle = "HideOtpFields".localize()
|
||||
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
||||
}
|
||||
|
||||
@objc func tapHidePasswordImagesSwitchDetailButton(_ sender: Any?) {
|
||||
@objc
|
||||
func tapHidePasswordImagesSwitchDetailButton(_: Any?) {
|
||||
let alertMessage = "HidePasswordImagesExplanation.".localize()
|
||||
let alertTitle = "HidePasswordImages".localize()
|
||||
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
||||
}
|
||||
|
||||
@objc func hideUnknownSwitchAction(_ sender: Any?) {
|
||||
@objc
|
||||
func hideUnknownSwitchAction(_: Any?) {
|
||||
Defaults.isHideUnknownOn = hideUnknownSwitch.isOn
|
||||
NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil)
|
||||
}
|
||||
|
||||
@objc func hideOTPSwitchAction(_ sender: Any?) {
|
||||
@objc
|
||||
func hideOTPSwitchAction(_: Any?) {
|
||||
Defaults.isHideOTPOn = hideOTPSwitch.isOn
|
||||
NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil)
|
||||
}
|
||||
|
||||
@objc func rememberPGPPassphraseSwitchAction(_ sender: Any?) {
|
||||
@objc
|
||||
func rememberPGPPassphraseSwitchAction(_: Any?) {
|
||||
Defaults.isRememberPGPPassphraseOn = rememberPGPPassphraseSwitch.isOn
|
||||
if rememberPGPPassphraseSwitch.isOn == false {
|
||||
AppKeychain.shared.removeAllContent(withPrefix: Globals.pgpKeyPassphrase)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func rememberGitCredentialPassphraseSwitchAction(_ sender: Any?) {
|
||||
@objc
|
||||
func rememberGitCredentialPassphraseSwitchAction(_: Any?) {
|
||||
Defaults.isRememberGitCredentialPassphraseOn = rememberGitCredentialPassphraseSwitch.isOn
|
||||
if rememberGitCredentialPassphraseSwitch.isOn == false {
|
||||
passwordStore.gitSSHPrivateKeyPassphrase = nil
|
||||
|
|
@ -188,14 +193,15 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
}
|
||||
}
|
||||
|
||||
@objc func showFolderSwitchAction(_ sender: Any?) {
|
||||
@objc
|
||||
func showFolderSwitchAction(_: Any?) {
|
||||
Defaults.isShowFolderOn = showFolderSwitch.isOn
|
||||
NotificationCenter.default.post(name: .passwordDisplaySettingChanged, object: nil)
|
||||
}
|
||||
|
||||
@objc func hidePasswordImagesSwitchAction(_ sender: Any?) {
|
||||
@objc
|
||||
func hidePasswordImagesSwitchAction(_: Any?) {
|
||||
Defaults.isHidePasswordImagesOn = hidePasswordImagesSwitch.isOn
|
||||
NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@
|
|||
// Copyright © 2017 Yishi Lin. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import passKit
|
||||
import UIKit
|
||||
|
||||
class GitConfigSettingsTableViewController: UITableViewController {
|
||||
let passwordStore = PasswordStore.shared
|
||||
|
||||
@IBOutlet weak var nameTextField: UITextField!
|
||||
@IBOutlet weak var emailTextField: UITextField!
|
||||
@IBOutlet var nameTextField: UITextField!
|
||||
@IBOutlet var emailTextField: UITextField!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
|
@ -26,7 +26,7 @@ class GitConfigSettingsTableViewController: UITableViewController {
|
|||
emailTextField.text = Defaults.gitSignatureEmail
|
||||
}
|
||||
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender _: Any?) -> Bool {
|
||||
if identifier == "saveGitConfigSettingSegue" {
|
||||
let name = nameTextField.text!.isEmpty ? Globals.gitSignatureDefaultName : nameTextField.text!
|
||||
let email = emailTextField.text!.isEmpty ? Globals.gitSignatureDefaultEmail : nameTextField.text!
|
||||
|
|
@ -38,4 +38,3 @@ class GitConfigSettingsTableViewController: UITableViewController {
|
|||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,21 +6,20 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SVProgressHUD
|
||||
import passKit
|
||||
|
||||
import SVProgressHUD
|
||||
import UIKit
|
||||
|
||||
class GitRepositorySettingsTableViewController: UITableViewController {
|
||||
// MARK: - View Outlet
|
||||
|
||||
@IBOutlet weak var gitURLTextField: UITextField!
|
||||
@IBOutlet weak var usernameTextField: UITextField!
|
||||
@IBOutlet weak var branchNameTextField: UITextField!
|
||||
@IBOutlet weak var authSSHKeyCell: UITableViewCell!
|
||||
@IBOutlet weak var authPasswordCell: UITableViewCell!
|
||||
@IBOutlet weak var gitURLCell: UITableViewCell!
|
||||
@IBOutlet weak var gitRepositoryURLTabelViewCell: UITableViewCell!
|
||||
@IBOutlet var gitURLTextField: UITextField!
|
||||
@IBOutlet var usernameTextField: UITextField!
|
||||
@IBOutlet var branchNameTextField: UITextField!
|
||||
@IBOutlet var authSSHKeyCell: UITableViewCell!
|
||||
@IBOutlet var authPasswordCell: UITableViewCell!
|
||||
@IBOutlet var gitURLCell: UITableViewCell!
|
||||
@IBOutlet var gitRepositoryURLTabelViewCell: UITableViewCell!
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
|
|
@ -33,27 +32,29 @@ class GitRepositorySettingsTableViewController: UITableViewController {
|
|||
updateAuthenticationMethodCheckView(for: newValue)
|
||||
}
|
||||
}
|
||||
|
||||
private var gitUrl: URL {
|
||||
get { Defaults.gitURL }
|
||||
set { Defaults.gitURL = newValue }
|
||||
}
|
||||
|
||||
private var gitBranchName: String {
|
||||
get { Defaults.gitBranchName }
|
||||
set { Defaults.gitBranchName = newValue }
|
||||
}
|
||||
|
||||
private var gitUsername: String {
|
||||
get { Defaults.gitUsername }
|
||||
set { Defaults.gitUsername = newValue }
|
||||
}
|
||||
|
||||
private var gitCredential: GitCredential {
|
||||
get {
|
||||
switch Defaults.gitAuthenticationMethod {
|
||||
case .password:
|
||||
return GitCredential(credential: .http(userName: Defaults.gitUsername))
|
||||
case .key:
|
||||
let privateKey: String = AppKeychain.shared.get(for: SshKey.PRIVATE.getKeychainKey()) ?? ""
|
||||
return GitCredential(credential: .ssh(userName: Defaults.gitUsername, privateKey: privateKey))
|
||||
}
|
||||
switch Defaults.gitAuthenticationMethod {
|
||||
case .password:
|
||||
return GitCredential(credential: .http(userName: Defaults.gitUsername))
|
||||
case .key:
|
||||
let privateKey: String = AppKeychain.shared.get(for: SshKey.PRIVATE.getKeychainKey()) ?? ""
|
||||
return GitCredential(credential: .ssh(userName: Defaults.gitUsername, privateKey: privateKey))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,9 +62,9 @@ class GitRepositorySettingsTableViewController: UITableViewController {
|
|||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
gitURLTextField.text = self.gitUrl.absoluteString
|
||||
usernameTextField.text = self.gitUsername
|
||||
branchNameTextField.text = self.gitBranchName
|
||||
gitURLTextField.text = gitUrl.absoluteString
|
||||
usernameTextField.text = gitUsername
|
||||
branchNameTextField.text = gitBranchName
|
||||
sshLabel = authSSHKeyCell.subviews[0].subviews[0] as? UILabel
|
||||
authSSHKeyCell.accessoryType = .detailButton
|
||||
}
|
||||
|
|
@ -94,7 +95,7 @@ class GitRepositorySettingsTableViewController: UITableViewController {
|
|||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let cell = tableView.cellForRow(at: indexPath)
|
||||
if cell == authPasswordCell {
|
||||
self.gitAuthenticationMethod = .password
|
||||
gitAuthenticationMethod = .password
|
||||
} else if cell == authSSHKeyCell {
|
||||
if !AppKeychain.shared.contains(key: SshKey.PRIVATE.getKeychainKey()) {
|
||||
Utils.alert(title: "CannotSelectSshKey".localize(), message: "PleaseSetupSshKeyFirst.".localize(), controller: self)
|
||||
|
|
@ -108,7 +109,8 @@ class GitRepositorySettingsTableViewController: UITableViewController {
|
|||
|
||||
// MARK: - Segue Handlers
|
||||
|
||||
@IBAction func save(_ sender: Any) {
|
||||
@IBAction
|
||||
func save(_: Any) {
|
||||
guard let gitURLTextFieldText = gitURLTextField.text, let gitURL = URL(string: gitURLTextFieldText.trimmed) else {
|
||||
Utils.alert(title: "CannotSave".localize(), message: "SetGitRepositoryUrl".localize(), controller: self)
|
||||
return
|
||||
|
|
@ -137,9 +139,9 @@ class GitRepositorySettingsTableViewController: UITableViewController {
|
|||
}
|
||||
}
|
||||
|
||||
self.gitUrl = gitURL
|
||||
self.gitBranchName = branchName.trimmed
|
||||
self.gitUsername = (gitURL.user ?? usernameTextField.text ?? "git").trimmed
|
||||
gitUrl = gitURL
|
||||
gitBranchName = branchName.trimmed
|
||||
gitUsername = (gitURL.user ?? usernameTextField.text ?? "git").trimmed
|
||||
|
||||
if passwordStore.repositoryExists() {
|
||||
let overwriteAlert: UIAlertController = {
|
||||
|
|
@ -150,7 +152,7 @@ class GitRepositorySettingsTableViewController: UITableViewController {
|
|||
alert.addAction(UIAlertAction.cancel())
|
||||
return alert
|
||||
}()
|
||||
self.present(overwriteAlert, animated: true)
|
||||
present(overwriteAlert, animated: true)
|
||||
} else {
|
||||
cloneAndSegueIfSuccess()
|
||||
}
|
||||
|
|
@ -159,15 +161,15 @@ class GitRepositorySettingsTableViewController: UITableViewController {
|
|||
private func cloneAndSegueIfSuccess() {
|
||||
// Remember git credential password/passphrase temporarily, ask whether users want this after a successful clone.
|
||||
Defaults.isRememberGitCredentialPassphraseOn = true
|
||||
DispatchQueue.global(qos: .userInitiated).async() {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
do {
|
||||
let transferProgressBlock: (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void = { (git_transfer_progress, _) in
|
||||
let transferProgressBlock: (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void = { git_transfer_progress, _ in
|
||||
let gitTransferProgress = git_transfer_progress.pointee
|
||||
let progress = Float(gitTransferProgress.received_objects) / Float(gitTransferProgress.total_objects)
|
||||
SVProgressHUD.showProgress(progress, status: "Cloning Remote Repository")
|
||||
}
|
||||
|
||||
let checkoutProgressBlock: (String, UInt, UInt) -> Void = { (_, completedSteps, totalSteps) in
|
||||
let checkoutProgressBlock: (String, UInt, UInt) -> Void = { _, completedSteps, totalSteps in
|
||||
let progress = Float(completedSteps) / Float(totalSteps)
|
||||
SVProgressHUD.showProgress(progress, status: "CheckingOutBranch".localize(self.gitBranchName))
|
||||
}
|
||||
|
|
@ -179,7 +181,7 @@ class GitRepositorySettingsTableViewController: UITableViewController {
|
|||
transferProgressBlock: transferProgressBlock,
|
||||
checkoutProgressBlock: checkoutProgressBlock)
|
||||
|
||||
SVProgressHUD.dismiss() {
|
||||
SVProgressHUD.dismiss {
|
||||
let savePassphraseAlert: UIAlertController = {
|
||||
let alert = UIAlertController(title: "Done".localize(), message: "WantToSaveGitCredential?".localize(), preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: "No".localize(), style: .default) { _ in
|
||||
|
|
@ -188,7 +190,7 @@ class GitRepositorySettingsTableViewController: UITableViewController {
|
|||
self.passwordStore.gitSSHPrivateKeyPassphrase = nil
|
||||
self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self)
|
||||
})
|
||||
alert.addAction(UIAlertAction(title: "Yes".localize(), style: .destructive) {_ in
|
||||
alert.addAction(UIAlertAction(title: "Yes".localize(), style: .destructive) { _ in
|
||||
Defaults.isRememberGitCredentialPassphraseOn = true
|
||||
self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self)
|
||||
})
|
||||
|
|
@ -199,7 +201,7 @@ class GitRepositorySettingsTableViewController: UITableViewController {
|
|||
}
|
||||
}
|
||||
} catch {
|
||||
SVProgressHUD.dismiss() {
|
||||
SVProgressHUD.dismiss {
|
||||
let error = error as NSError
|
||||
var message = error.localizedDescription
|
||||
if let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError {
|
||||
|
|
@ -213,7 +215,8 @@ class GitRepositorySettingsTableViewController: UITableViewController {
|
|||
}
|
||||
}
|
||||
|
||||
@IBAction func importSSHKey(segue: UIStoryboardSegue) {
|
||||
@IBAction
|
||||
func importSSHKey(segue: UIStoryboardSegue) {
|
||||
guard let sourceController = segue.source as? KeyImporter, sourceController.isReadyToUse() else {
|
||||
return
|
||||
}
|
||||
|
|
@ -278,7 +281,7 @@ class GitRepositorySettingsTableViewController: UITableViewController {
|
|||
}
|
||||
|
||||
private func requestCredentialPassword(credential: GitCredential.Credential, lastPassword: String?) -> String? {
|
||||
return requestGitCredentialPassword(credential: credential, lastPassword: lastPassword, controller: self)
|
||||
requestGitCredentialPassword(credential: credential, lastPassword: lastPassword, controller: self)
|
||||
}
|
||||
|
||||
private func updateAuthenticationMethodCheckView(for method: GitAuthenticationMethod) {
|
||||
|
|
@ -297,21 +300,20 @@ class GitRepositorySettingsTableViewController: UITableViewController {
|
|||
|
||||
private func showGitURLFormatHelp() {
|
||||
let message = """
|
||||
https://example.com[:port]/project.git
|
||||
ssh://[user@]server[:port]/project.git
|
||||
[user@]server:project.git (no scheme)
|
||||
"""
|
||||
https://example.com[:port]/project.git
|
||||
ssh://[user@]server[:port]/project.git
|
||||
[user@]server:project.git (no scheme)
|
||||
"""
|
||||
Utils.alert(title: "Git URL Format", message: message, controller: self)
|
||||
}
|
||||
}
|
||||
|
||||
extension GitRepositorySettingsTableViewController: KeyImporter {
|
||||
|
||||
static let keySource = KeySource.itunes
|
||||
static let label = "ITunesFileSharing".localize()
|
||||
|
||||
func isReadyToUse() -> Bool {
|
||||
return KeyFileManager.PrivateSsh.doesKeyFileExist()
|
||||
KeyFileManager.PrivateSsh.doesKeyFileExist()
|
||||
}
|
||||
|
||||
func importKeys() throws {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
import passKit
|
||||
|
||||
protocol KeyImporter {
|
||||
|
||||
static var keySource: KeySource { get }
|
||||
|
||||
static var label: String { get }
|
||||
|
|
@ -24,9 +23,8 @@ protocol KeyImporter {
|
|||
}
|
||||
|
||||
extension KeyImporter {
|
||||
|
||||
static var isCurrentKeySource: Bool {
|
||||
return Defaults.gitSSHKeySource == Self.keySource
|
||||
Defaults.gitSSHKeySource == Self.keySource
|
||||
}
|
||||
|
||||
static var menuLabel: String {
|
||||
|
|
|
|||
|
|
@ -6,11 +6,10 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SafariServices
|
||||
import UIKit
|
||||
|
||||
class OpenSourceComponentsTableViewController: BasicStaticTableViewController {
|
||||
|
||||
private static let openSourceComponents = [
|
||||
["FavIcon",
|
||||
"https://github.com/bitserf/FavIcon",
|
||||
|
|
@ -48,12 +47,13 @@ class OpenSourceComponentsTableViewController: BasicStaticTableViewController {
|
|||
.link: item[1],
|
||||
.accessoryType: UITableViewCell.AccessoryType.detailDisclosureButton,
|
||||
.detailDisclosureAction: #selector(actOnDetailDisclosureButton(_:)),
|
||||
.detailDisclosureData: item[2]
|
||||
.detailDisclosureData: item[2],
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
@objc func actOnDetailDisclosureButton(_ sender: Any?) {
|
||||
@objc
|
||||
func actOnDetailDisclosureButton(_ sender: Any?) {
|
||||
if let link = sender as? String, let url = URL(string: link) {
|
||||
let svc = SFSafariViewController(url: url, entersReaderIfAvailable: false)
|
||||
present(svc, animated: true)
|
||||
|
|
|
|||
|
|
@ -6,15 +6,14 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import passKit
|
||||
import UIKit
|
||||
|
||||
class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController, UITextViewDelegate, QRScannerControllerDelegate {
|
||||
|
||||
@IBOutlet weak var armorPublicKeyTextView: UITextView!
|
||||
@IBOutlet weak var armorPrivateKeyTextView: UITextView!
|
||||
@IBOutlet weak var scanPublicKeyCell: UITableViewCell!
|
||||
@IBOutlet weak var scanPrivateKeyCell: UITableViewCell!
|
||||
@IBOutlet var armorPublicKeyTextView: UITextView!
|
||||
@IBOutlet var armorPrivateKeyTextView: UITextView!
|
||||
@IBOutlet var scanPublicKeyCell: UITableViewCell!
|
||||
@IBOutlet var scanPrivateKeyCell: UITableViewCell!
|
||||
|
||||
var armorPublicKey: String?
|
||||
var armorPrivateKey: String?
|
||||
|
|
@ -23,45 +22,47 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
|
|||
enum KeyType {
|
||||
case publicKey, privateKey
|
||||
}
|
||||
|
||||
var keyType = KeyType.publicKey
|
||||
var segments = [String]()
|
||||
var message = ""
|
||||
|
||||
func reset(keytype: KeyType) {
|
||||
self.keyType = keytype
|
||||
self.segments.removeAll()
|
||||
keyType = keytype
|
||||
segments.removeAll()
|
||||
message = "LookingForStartingFrame.".localize()
|
||||
}
|
||||
|
||||
func addSegment(segment: String) -> (accept: Bool, message: String) {
|
||||
let keyTypeStr = self.keyType == .publicKey ? "Public" : "Private"
|
||||
let theOtherKeyTypeStr = self.keyType == .publicKey ? "Private" : "Public"
|
||||
|
||||
let keyTypeStr = keyType == .publicKey ? "Public" : "Private"
|
||||
let theOtherKeyTypeStr = keyType == .publicKey ? "Private" : "Public"
|
||||
|
||||
// Skip duplicated segments.
|
||||
guard segment != self.segments.last else {
|
||||
return (accept: false, message: self.message)
|
||||
guard segment != segments.last else {
|
||||
return (accept: false, message: message)
|
||||
}
|
||||
|
||||
// Check whether we have found the first block.
|
||||
guard !self.segments.isEmpty || segment.contains("-----BEGIN PGP \(keyTypeStr.uppercased()) KEY BLOCK-----") else {
|
||||
guard !segments.isEmpty || segment.contains("-----BEGIN PGP \(keyTypeStr.uppercased()) KEY BLOCK-----") else {
|
||||
// Check whether we are scanning the wrong key type.
|
||||
if segment.contains("-----BEGIN PGP \(theOtherKeyTypeStr.uppercased()) KEY BLOCK-----") {
|
||||
self.message = "Scan\(keyTypeStr)Key.".localize()
|
||||
message = "Scan\(keyTypeStr)Key.".localize()
|
||||
}
|
||||
return (accept: false, message: self.message)
|
||||
return (accept: false, message: message)
|
||||
}
|
||||
|
||||
|
||||
// Update the list of scanned segment and return.
|
||||
self.segments.append(segment)
|
||||
segments.append(segment)
|
||||
if segment.contains("-----END PGP \(keyTypeStr.uppercased()) KEY BLOCK-----") {
|
||||
self.message = "Done".localize()
|
||||
return (accept: true, message: self.message)
|
||||
message = "Done".localize()
|
||||
return (accept: true, message: message)
|
||||
} else {
|
||||
self.message = "ScannedQrCodes(%d)".localize(self.segments.count)
|
||||
return (accept: false, message: self.message)
|
||||
message = "ScannedQrCodes(%d)".localize(segments.count)
|
||||
return (accept: false, message: message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var scanned = ScannedPGPKey()
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
|
@ -76,13 +77,14 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
|
|||
scanPrivateKeyCell?.accessoryType = .disclosureIndicator
|
||||
}
|
||||
|
||||
@IBAction func save(_ sender: Any) {
|
||||
@IBAction
|
||||
func save(_: Any) {
|
||||
armorPublicKey = armorPublicKeyTextView.text
|
||||
armorPrivateKey = armorPrivateKeyTextView.text
|
||||
self.saveImportedKeys()
|
||||
saveImportedKeys()
|
||||
}
|
||||
|
||||
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
|
||||
func textView(_: UITextView, shouldChangeTextIn _: NSRange, replacementText text: String) -> Bool {
|
||||
if text == UIPasteboard.general.string {
|
||||
// user pastes something, do the copy here again and clear the pasteboard in 45s
|
||||
SecurePasteboard.shared.copy(textToCopy: text)
|
||||
|
|
@ -94,21 +96,23 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
|
|||
let selectedCell = tableView.cellForRow(at: indexPath)
|
||||
if selectedCell == scanPublicKeyCell {
|
||||
scanned.reset(keytype: ScannedPGPKey.KeyType.publicKey)
|
||||
self.performSegue(withIdentifier: "showPGPScannerSegue", sender: self)
|
||||
performSegue(withIdentifier: "showPGPScannerSegue", sender: self)
|
||||
} else if selectedCell == scanPrivateKeyCell {
|
||||
scanned.reset(keytype: ScannedPGPKey.KeyType.privateKey)
|
||||
self.performSegue(withIdentifier: "showPGPScannerSegue", sender: self)
|
||||
performSegue(withIdentifier: "showPGPScannerSegue", sender: self)
|
||||
}
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
|
||||
// MARK: - QRScannerControllerDelegate Methods
|
||||
|
||||
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
|
||||
return scanned.addSegment(segment: line)
|
||||
}
|
||||
|
||||
// MARK: - QRScannerControllerDelegate Methods
|
||||
func handleScannedOutput(line: String) {
|
||||
|
||||
func handleScannedOutput(line _: String) {
|
||||
let key = scanned.segments.joined(separator: "")
|
||||
switch scanned.keyType {
|
||||
case .publicKey:
|
||||
|
|
@ -118,7 +122,7 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
|
|||
}
|
||||
}
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
override func prepare(for segue: UIStoryboardSegue, sender _: Any?) {
|
||||
if segue.identifier == "showPGPScannerSegue" {
|
||||
if let navController = segue.destination as? UINavigationController {
|
||||
if let viewController = navController.topViewController as? QRScannerController {
|
||||
|
|
@ -132,7 +136,6 @@ class PGPKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
|
|||
}
|
||||
|
||||
extension PGPKeyArmorImportTableViewController: PGPKeyImporter {
|
||||
|
||||
static let keySource = KeySource.armor
|
||||
static let label = "AsciiArmorEncryptedKey".localize()
|
||||
|
||||
|
|
|
|||
|
|
@ -9,18 +9,18 @@
|
|||
import passKit
|
||||
|
||||
class PGPKeyFileImportTableViewController: AutoCellHeightUITableViewController {
|
||||
@IBOutlet var pgpPublicKeyFile: UITableViewCell!
|
||||
@IBOutlet var pgpPrivateKeyFile: UITableViewCell!
|
||||
|
||||
@IBOutlet weak var pgpPublicKeyFile: UITableViewCell!
|
||||
@IBOutlet weak var pgpPrivateKeyFile: UITableViewCell!
|
||||
|
||||
private var publicKey: String? = nil
|
||||
private var privateKey: String? = nil
|
||||
private var publicKey: String?
|
||||
private var privateKey: String?
|
||||
|
||||
private enum KeyType { case none, `private`, `public` }
|
||||
private var currentlyPicking = KeyType.none
|
||||
|
||||
@IBAction func save(_ sender: Any) {
|
||||
self.saveImportedKeys()
|
||||
@IBAction
|
||||
func save(_: Any) {
|
||||
saveImportedKeys()
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
|
|
@ -43,7 +43,6 @@ class PGPKeyFileImportTableViewController: AutoCellHeightUITableViewController {
|
|||
}
|
||||
|
||||
extension PGPKeyFileImportTableViewController: UIDocumentPickerDelegate {
|
||||
|
||||
func documentPicker(_: UIDocumentPickerViewController, didPickDocumentsAt url: [URL]) {
|
||||
guard let url = url.first else {
|
||||
return
|
||||
|
|
@ -78,12 +77,11 @@ extension PGPKeyFileImportTableViewController: UIDocumentPickerDelegate {
|
|||
}
|
||||
|
||||
extension PGPKeyFileImportTableViewController: PGPKeyImporter {
|
||||
|
||||
static let keySource = KeySource.file
|
||||
static let label = "LoadFromFiles".localize()
|
||||
|
||||
func isReadyToUse() -> Bool {
|
||||
return validate(key: publicKey) && validate(key: privateKey)
|
||||
validate(key: publicKey) && validate(key: privateKey)
|
||||
}
|
||||
|
||||
func importKeys() throws {
|
||||
|
|
|
|||
|
|
@ -9,19 +9,15 @@
|
|||
import passKit
|
||||
|
||||
protocol PGPKeyImporter: KeyImporter {
|
||||
|
||||
func doAfterImport()
|
||||
|
||||
func saveImportedKeys()
|
||||
}
|
||||
|
||||
extension PGPKeyImporter {
|
||||
|
||||
static var isCurrentKeySource: Bool {
|
||||
return Defaults.pgpKeySource == Self.keySource
|
||||
Defaults.pgpKeySource == Self.keySource
|
||||
}
|
||||
|
||||
func doAfterImport() {
|
||||
|
||||
}
|
||||
func doAfterImport() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,12 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import passKit
|
||||
import UIKit
|
||||
|
||||
class PGPKeyUrlImportTableViewController: AutoCellHeightUITableViewController {
|
||||
|
||||
@IBOutlet weak var pgpPublicKeyURLTextField: UITextField!
|
||||
@IBOutlet weak var pgpPrivateKeyURLTextField: UITextField!
|
||||
@IBOutlet var pgpPublicKeyURLTextField: UITextField!
|
||||
@IBOutlet var pgpPrivateKeyURLTextField: UITextField!
|
||||
|
||||
var pgpPrivateKeyURL: URL?
|
||||
var pgpPublicKeyURL: URL?
|
||||
|
|
@ -22,31 +21,31 @@ class PGPKeyUrlImportTableViewController: AutoCellHeightUITableViewController {
|
|||
pgpPublicKeyURLTextField.text = Defaults.pgpPublicKeyURL?.absoluteString
|
||||
pgpPrivateKeyURLTextField.text = Defaults.pgpPrivateKeyURL?.absoluteString
|
||||
}
|
||||
|
||||
@IBAction func save(_ sender: Any) {
|
||||
|
||||
@IBAction
|
||||
func save(_: Any) {
|
||||
guard let publicKeyURLText = pgpPublicKeyURLTextField.text,
|
||||
let publicKeyURL = URL(string: publicKeyURLText),
|
||||
let privateKeyURLText = pgpPrivateKeyURLTextField.text,
|
||||
let privateKeyURL = URL(string: privateKeyURLText) else {
|
||||
Utils.alert(title: "CannotSavePgpKey".localize(), message: "SetPgpKeyUrlsFirst.".localize(), controller: self)
|
||||
return
|
||||
Utils.alert(title: "CannotSavePgpKey".localize(), message: "SetPgpKeyUrlsFirst.".localize(), controller: self)
|
||||
return
|
||||
}
|
||||
if privateKeyURL.scheme?.lowercased() == "http" || publicKeyURL.scheme?.lowercased() == "http" {
|
||||
Utils.alert(title: "HttpNotSecure".localize(), message: "ReallyUseHttp.".localize(), controller: self)
|
||||
}
|
||||
pgpPrivateKeyURL = privateKeyURL
|
||||
pgpPublicKeyURL = publicKeyURL
|
||||
self.saveImportedKeys()
|
||||
saveImportedKeys()
|
||||
}
|
||||
}
|
||||
|
||||
extension PGPKeyUrlImportTableViewController: PGPKeyImporter {
|
||||
|
||||
static let keySource = KeySource.url
|
||||
static let label = "DownloadFromUrl".localize()
|
||||
|
||||
func isReadyToUse() -> Bool {
|
||||
return validate(pgpKeyUrl: pgpPublicKeyURLTextField.text ?? "")
|
||||
validate(pgpKeyUrl: pgpPublicKeyURLTextField.text ?? "")
|
||||
&& validate(pgpKeyUrl: pgpPrivateKeyURLTextField.text ?? "")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,16 +6,16 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import FavIcon
|
||||
import SVProgressHUD
|
||||
import passKit
|
||||
import SVProgressHUD
|
||||
import UIKit
|
||||
|
||||
class PasswordDetailTableViewController: UITableViewController, UIGestureRecognizerDelegate {
|
||||
var passwordEntity: PasswordEntity?
|
||||
private var password: Password?
|
||||
private var passwordImage: UIImage?
|
||||
private var oneTimePasswordIndexPath : IndexPath?
|
||||
private var oneTimePasswordIndexPath: IndexPath?
|
||||
private var shouldPopCurrentView = false
|
||||
private let passwordStore = PasswordStore.shared
|
||||
private let keychain = AppKeychain.shared
|
||||
|
|
@ -52,7 +52,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
tableView.addGestureRecognizer(tapGesture)
|
||||
tapGesture.delegate = self
|
||||
|
||||
tableView.contentInset = UIEdgeInsets.init(top: -36, left: 0, bottom: 44, right: 0);
|
||||
tableView.contentInset = UIEdgeInsets(top: -36, left: 0, bottom: 44, right: 0)
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.estimatedRowHeight = 52
|
||||
|
||||
|
|
@ -66,8 +66,8 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
let image = UIImage(data: imageData as Data)
|
||||
passwordImage = image
|
||||
}
|
||||
self.decryptThenShowPassword()
|
||||
self.setupOneTimePasswordAutoRefresh()
|
||||
decryptThenShowPassword()
|
||||
setupOneTimePasswordAutoRefresh()
|
||||
|
||||
// pop the current view because this password might be "discarded"
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(setShouldPopCurrentView), name: .passwordStoreChangeDiscarded, object: nil)
|
||||
|
|
@ -78,16 +78,17 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
if self.shouldPopCurrentView {
|
||||
if shouldPopCurrentView {
|
||||
let alert = UIAlertController(title: "Notice".localize(), message: "PreviousChangesDiscarded.".localize(), preferredStyle: UIAlertController.Style.alert)
|
||||
alert.addAction(UIAlertAction.okAndPopView(controller: self))
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
present(alert, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func decryptThenShowPassword(keyID: String? = nil) {
|
||||
@objc
|
||||
private func decryptThenShowPassword(keyID: String? = nil) {
|
||||
guard let passwordEntity = passwordEntity else {
|
||||
Utils.alert(title: "CannotShowPassword".localize(), message: "PasswordDoesNotExist".localize(), controller: self, handler: {(UIAlertAction) -> Void in
|
||||
Utils.alert(title: "CannotShowPassword".localize(), message: "PasswordDoesNotExist".localize(), controller: self, handler: { (_) -> Void in
|
||||
self.navigationController!.popViewController(animated: true)
|
||||
})
|
||||
return
|
||||
|
|
@ -98,7 +99,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
let requestPGPKeyPassphrase = Utils.createRequestPGPKeyPassphraseHandler(controller: self)
|
||||
self.password = try self.passwordStore.decrypt(passwordEntity: passwordEntity, keyID: keyID, requestPGPKeyPassphrase: requestPGPKeyPassphrase)
|
||||
self.showPassword()
|
||||
} catch AppError.PgpPrivateKeyNotFound(let key) {
|
||||
} catch let AppError.PgpPrivateKeyNotFound(key) {
|
||||
DispatchQueue.main.async {
|
||||
// alert: cancel or try again
|
||||
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.PgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||
|
|
@ -115,7 +116,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
// alert: cancel or try again
|
||||
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: error.localizedDescription, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
||||
alert.addAction(UIAlertAction(title: "TryAgain".localize(), style: .default) {_ in
|
||||
alert.addAction(UIAlertAction(title: "TryAgain".localize(), style: .default) { _ in
|
||||
self.decryptThenShowPassword()
|
||||
})
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
|
|
@ -141,14 +142,14 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
|
||||
private func setupOneTimePasswordAutoRefresh() {
|
||||
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) {
|
||||
[weak self] timer in
|
||||
[weak self] _ in
|
||||
// bail out of the timer code if the object has been freed
|
||||
guard let strongSelf = self,
|
||||
let otpType = strongSelf.password?.otpType,
|
||||
otpType != .none,
|
||||
let indexPath = strongSelf.oneTimePasswordIndexPath,
|
||||
let cell = strongSelf.tableView.cellForRow(at: indexPath) as? LabelTableViewCell else {
|
||||
return
|
||||
return
|
||||
}
|
||||
switch otpType {
|
||||
case .totp:
|
||||
|
|
@ -163,64 +164,67 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
}
|
||||
}
|
||||
|
||||
@objc private func pressEdit(_ sender: Any?) {
|
||||
@objc
|
||||
private func pressEdit(_: Any?) {
|
||||
performSegue(withIdentifier: "editPasswordSegue", sender: self)
|
||||
}
|
||||
|
||||
@objc private func setShouldPopCurrentView() {
|
||||
self.shouldPopCurrentView = true
|
||||
@objc
|
||||
private func setShouldPopCurrentView() {
|
||||
shouldPopCurrentView = true
|
||||
}
|
||||
|
||||
@IBAction private func cancelEditPassword(segue: UIStoryboardSegue) {
|
||||
@IBAction
|
||||
private func cancelEditPassword(segue _: UIStoryboardSegue) {}
|
||||
|
||||
}
|
||||
|
||||
@IBAction private func saveEditPassword(segue: UIStoryboardSegue) {
|
||||
if self.password!.changed != 0 {
|
||||
self.saveEditPassword(password: self.password!)
|
||||
@IBAction
|
||||
private func saveEditPassword(segue _: UIStoryboardSegue) {
|
||||
if password!.changed != 0 {
|
||||
saveEditPassword(password: password!)
|
||||
}
|
||||
}
|
||||
|
||||
private func saveEditPassword(password: Password, keyID: String? = nil) {
|
||||
SVProgressHUD.show(withStatus: "Saving".localize())
|
||||
do {
|
||||
self.passwordEntity = try self.passwordStore.edit(passwordEntity: self.passwordEntity!, password: password, keyID: keyID)
|
||||
self.setTableData()
|
||||
self.tableView.reloadData()
|
||||
passwordEntity = try passwordStore.edit(passwordEntity: passwordEntity!, password: password, keyID: keyID)
|
||||
setTableData()
|
||||
tableView.reloadData()
|
||||
SVProgressHUD.showSuccess(withStatus: "Success".localize())
|
||||
SVProgressHUD.dismiss(withDelay: 1)
|
||||
} catch AppError.PgpPublicKeyNotFound(let key) {
|
||||
DispatchQueue.main.async {
|
||||
// alert: cancel or select keys
|
||||
SVProgressHUD.dismiss()
|
||||
let alert = UIAlertController(title: "Cannot Edit Password", message: AppError.PgpPublicKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
||||
let selectKey = UIAlertAction.selectKey(controller: self) { action in
|
||||
self.saveEditPassword(password: password, keyID: action.title)
|
||||
}
|
||||
alert.addAction(selectKey)
|
||||
} catch let AppError.PgpPublicKeyNotFound(key) {
|
||||
DispatchQueue.main.async {
|
||||
// alert: cancel or select keys
|
||||
SVProgressHUD.dismiss()
|
||||
let alert = UIAlertController(title: "Cannot Edit Password", message: AppError.PgpPublicKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
|
||||
let selectKey = UIAlertAction.selectKey(controller: self) { action in
|
||||
self.saveEditPassword(password: password, keyID: action.title)
|
||||
}
|
||||
alert.addAction(selectKey)
|
||||
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
return
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||
}
|
||||
}
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
return
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction private func deletePassword(segue: UIStoryboardSegue) {
|
||||
@IBAction
|
||||
private func deletePassword(segue _: UIStoryboardSegue) {
|
||||
do {
|
||||
try passwordStore.delete(passwordEntity: passwordEntity!)
|
||||
} catch {
|
||||
Utils.alert(title: "Error".localize(), message: error.localizedDescription, controller: self, completion: nil)
|
||||
}
|
||||
let _ = navigationController?.popViewController(animated: true)
|
||||
_ = navigationController?.popViewController(animated: true)
|
||||
}
|
||||
|
||||
private func setTableData() {
|
||||
self.tableData = Array<TableSection>()
|
||||
tableData = [TableSection]()
|
||||
|
||||
// name section
|
||||
var section = TableSection(type: .name)
|
||||
|
|
@ -239,7 +243,6 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
section.item.append(Constants.PASSWORD_KEYWORD => password.password)
|
||||
tableData.append(section)
|
||||
|
||||
|
||||
// addition section
|
||||
|
||||
// show one time password
|
||||
|
|
@ -254,7 +257,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
|
||||
// show additional information
|
||||
let filteredAdditionKeys = password.getFilteredAdditions()
|
||||
if filteredAdditionKeys.count > 0 {
|
||||
if !filteredAdditionKeys.isEmpty {
|
||||
section = TableSection(type: .addition, header: "Additions".localize())
|
||||
section.item.append(contentsOf: filteredAdditionKeys)
|
||||
tableData.append(section)
|
||||
|
|
@ -264,10 +267,9 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
section = TableSection(type: .misc)
|
||||
section.item.append(AdditionField(title: "ShowRaw".localize()))
|
||||
tableData.append(section)
|
||||
|
||||
}
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
override func prepare(for segue: UIStoryboardSegue, sender _: Any?) {
|
||||
if segue.identifier == "editPasswordSegue" {
|
||||
if let controller = segue.destination as? UINavigationController {
|
||||
if let editController = controller.viewControllers.first as? EditPasswordTableViewController {
|
||||
|
|
@ -288,9 +290,9 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
if urlString.lowercased().hasPrefix("http://") {
|
||||
// try to replace http url to https url
|
||||
newUrlString = urlString.replacingOccurrences(of: "http://",
|
||||
with: "https://",
|
||||
options: .caseInsensitive,
|
||||
range: urlString.range(of: "http://"))
|
||||
with: "https://",
|
||||
options: .caseInsensitive,
|
||||
range: urlString.range(of: "http://"))
|
||||
} else if urlString.lowercased().hasPrefix("https://") {
|
||||
// do nothing here
|
||||
} else {
|
||||
|
|
@ -311,11 +313,12 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
}
|
||||
}
|
||||
|
||||
@objc private func tapMenu(recognizer: UITapGestureRecognizer) {
|
||||
@objc
|
||||
private func tapMenu(recognizer: UITapGestureRecognizer) {
|
||||
if recognizer.state == UIGestureRecognizer.State.ended {
|
||||
let tapLocation = recognizer.location(in: self.tableView)
|
||||
if let tapIndexPath = self.tableView.indexPathForRow(at: tapLocation) {
|
||||
if let tappedCell = self.tableView.cellForRow(at: tapIndexPath) as? LabelTableViewCell {
|
||||
let tapLocation = recognizer.location(in: tableView)
|
||||
if let tapIndexPath = tableView.indexPathForRow(at: tapLocation) {
|
||||
if let tappedCell = tableView.cellForRow(at: tapIndexPath) as? LabelTableViewCell {
|
||||
tappedCell.becomeFirstResponder()
|
||||
let menuController = UIMenuController.shared
|
||||
let revealItem = UIMenuItem(title: "Reveal".localize(), action: #selector(LabelTableViewCell.revealPassword(_:)))
|
||||
|
|
@ -330,22 +333,22 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
}
|
||||
}
|
||||
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
|
||||
func gestureRecognizer(_: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
|
||||
if touch.view!.isKind(of: UIButton.classForCoder()) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@IBAction func back(segue:UIStoryboardSegue) {
|
||||
}
|
||||
@IBAction
|
||||
func back(segue _: UIStoryboardSegue) {}
|
||||
|
||||
func getNextHOTP() {
|
||||
guard password != nil, passwordEntity != nil, password?.otpType == .hotp else {
|
||||
DispatchQueue.main.async {
|
||||
Utils.alert(title: "Error".localize(), message: "GetNextPasswordOfNonHotp.".localize(), controller: self, completion: nil)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
// copy HOTP to pasteboard (will update counter)
|
||||
|
|
@ -356,7 +359,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
// commit the change of HOTP counter
|
||||
if password!.changed != 0 {
|
||||
do {
|
||||
self.passwordEntity = try self.passwordStore.edit(passwordEntity: self.passwordEntity!, password: self.password!)
|
||||
passwordEntity = try passwordStore.edit(passwordEntity: passwordEntity!, password: password!)
|
||||
SVProgressHUD.showSuccess(withStatus: "PasswordCopied".localize() | "CounterUpdated".localize())
|
||||
SVProgressHUD.dismiss(withDelay: 1)
|
||||
} catch {
|
||||
|
|
@ -384,19 +387,19 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
return from
|
||||
}
|
||||
|
||||
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return tableData.count
|
||||
override func numberOfSections(in _: UITableView) -> Int {
|
||||
tableData.count
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return tableData[section].item.count
|
||||
override func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
tableData[section].item.count
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let sectionIndex = indexPath.section
|
||||
let rowIndex = indexPath.row
|
||||
let tableDataItem = tableData[sectionIndex].item[rowIndex]
|
||||
switch(tableData[sectionIndex].type) {
|
||||
switch tableData[sectionIndex].type {
|
||||
case .name:
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "passwordDetailTitleTableViewCell", for: indexPath) as! PasswordDetailTitleTableViewCell
|
||||
if !Defaults.isHidePasswordImagesOn {
|
||||
|
|
@ -453,8 +456,8 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
detailTextLabel.text = "HiddenFields(%d)".localize(numberOfHiddenFields)
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
return tableData[section].header
|
||||
override func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
tableData[section].header
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
|
||||
|
|
@ -464,7 +467,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
footerLabel.numberOfLines = 0
|
||||
footerLabel.font = UIFont.preferredFont(forTextStyle: .footnote)
|
||||
footerLabel.textColor = UIColor.gray
|
||||
let dateString = self.passwordStore.getLatestUpdateInfo(filename: password!.url.path)
|
||||
let dateString = passwordStore.getLatestUpdateInfo(filename: password!.url.path)
|
||||
footerLabel.text = "LastUpdated".localize(dateString)
|
||||
view.addSubview(footerLabel)
|
||||
return view
|
||||
|
|
@ -472,15 +475,15 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
return nil
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, performAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) {
|
||||
override func tableView(_: UITableView, performAction action: Selector, forRowAt indexPath: IndexPath, withSender _: Any?) {
|
||||
if action == #selector(copy(_:)) {
|
||||
SecurePasteboard.shared.copy(textToCopy: tableData[indexPath.section].item[indexPath.row].content)
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
|
||||
override func tableView(_: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender _: Any?) -> Bool {
|
||||
let section = tableData[indexPath.section]
|
||||
switch(section.type) {
|
||||
switch section.type {
|
||||
case .main, .addition:
|
||||
return action == #selector(UIResponderStandardEditActions.copy(_:))
|
||||
default:
|
||||
|
|
@ -488,8 +491,8 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, shouldShowMenuForRowAt indexPath: IndexPath) -> Bool {
|
||||
return true
|
||||
override func tableView(_: UITableView, shouldShowMenuForRowAt _: IndexPath) -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SafariServices
|
||||
import OneTimePassword
|
||||
import passKit
|
||||
import SafariServices
|
||||
import UIKit
|
||||
|
||||
enum PasswordEditorCellType: Equatable {
|
||||
case nameCell
|
||||
|
|
@ -30,18 +30,16 @@ enum PasswordEditorCellKey {
|
|||
}
|
||||
|
||||
protocol PasswordSettingSliderTableViewCellDelegate {
|
||||
|
||||
func generateAndCopyPassword()
|
||||
}
|
||||
|
||||
class PasswordEditorTableViewController: UITableViewController {
|
||||
|
||||
var tableData = [[Dictionary<PasswordEditorCellKey, Any>]]()
|
||||
var tableData = [[[PasswordEditorCellKey: Any]]]()
|
||||
var password: Password?
|
||||
|
||||
private var navigationItemTitle: String?
|
||||
|
||||
private var sectionHeaderTitles = ["Name".localize(), "Password".localize(), "Additions".localize(),""].map {$0.uppercased()}
|
||||
private var sectionHeaderTitles = ["Name".localize(), "Password".localize(), "Additions".localize(), ""].map { $0.uppercased() }
|
||||
private var sectionFooterTitles = ["", "", "UseKeyValueFormat.".localize(), ""]
|
||||
private let nameSection = 0
|
||||
private let passwordSection = 1
|
||||
|
|
@ -86,7 +84,7 @@ class PasswordEditorTableViewController: UITableViewController {
|
|||
passwordFlavorCell?.textLabel?.text = "PasswordGeneratorFlavor".localize()
|
||||
passwordFlavorCell?.selectionStyle = .none
|
||||
|
||||
let passwordFlavorSelector = UISegmentedControl(items: PasswordGeneratorFlavor.allCases.map { $0.localized })
|
||||
let passwordFlavorSelector = UISegmentedControl(items: PasswordGeneratorFlavor.allCases.map(\.localized))
|
||||
passwordFlavorSelector.selectedSegmentIndex = PasswordGeneratorFlavor.allCases.firstIndex(of: passwordGenerator.flavor)!
|
||||
passwordFlavorSelector.addTarget(self, action: #selector(flavorChanged), for: .valueChanged)
|
||||
passwordFlavorCell?.accessoryView = passwordFlavorSelector
|
||||
|
|
@ -126,11 +124,11 @@ class PasswordEditorTableViewController: UITableViewController {
|
|||
],
|
||||
[
|
||||
[.type: PasswordEditorCellType.scanQRCodeCell],
|
||||
]
|
||||
],
|
||||
]
|
||||
|
||||
if self.password != nil {
|
||||
tableData[additionsSection+1].append([.type: PasswordEditorCellType.deletePasswordCell])
|
||||
|
||||
if password != nil {
|
||||
tableData[additionsSection + 1].append([.type: PasswordEditorCellType.deletePasswordCell])
|
||||
}
|
||||
updateTableData(withRespectTo: passwordGenerator.flavor)
|
||||
}
|
||||
|
|
@ -206,11 +204,11 @@ class PasswordEditorTableViewController: UITableViewController {
|
|||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
return 44
|
||||
override func tableView(_: UITableView, heightForHeaderInSection _: Int) -> CGFloat {
|
||||
44
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
override func tableView(_: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
switch tableData[indexPath.section][indexPath.row][PasswordEditorCellKey.type] as! PasswordEditorCellType {
|
||||
case .passwordLengthCell, .passwordGroupsCell:
|
||||
return 42
|
||||
|
|
@ -221,11 +219,11 @@ class PasswordEditorTableViewController: UITableViewController {
|
|||
}
|
||||
}
|
||||
|
||||
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return tableData.count
|
||||
override func numberOfSections(in _: UITableView) -> Int {
|
||||
tableData.count
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
override func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
if section == passwordSection, hidePasswordSettings {
|
||||
// hide the password section, only the password should be shown
|
||||
return 1
|
||||
|
|
@ -234,27 +232,27 @@ class PasswordEditorTableViewController: UITableViewController {
|
|||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
return sectionHeaderTitles[section]
|
||||
override func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
sectionHeaderTitles[section]
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
|
||||
return sectionFooterTitles[section]
|
||||
override func tableView(_: UITableView, titleForFooterInSection section: Int) -> String? {
|
||||
sectionFooterTitles[section]
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let selectedCell = tableView.cellForRow(at: indexPath)
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
|
||||
|
||||
if selectedCell == deletePasswordCell {
|
||||
let alert = UIAlertController(title: "DeletePassword?".localize(), message: nil, preferredStyle: UIAlertController.Style.alert)
|
||||
alert.addAction(UIAlertAction(title: "Delete".localize(), style: UIAlertAction.Style.destructive, handler: {[unowned self] (action) -> Void in
|
||||
alert.addAction(UIAlertAction(title: "Delete".localize(), style: UIAlertAction.Style.destructive, handler: { [unowned self] (_) -> Void in
|
||||
self.performSegue(withIdentifier: "deletePasswordSegue", sender: self)
|
||||
}))
|
||||
alert.addAction(UIAlertAction.cancel())
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
present(alert, animated: true, completion: nil)
|
||||
} else if selectedCell == scanQRCodeCell {
|
||||
self.performSegue(withIdentifier: "showQRScannerSegue", sender: self)
|
||||
performSegue(withIdentifier: "showQRScannerSegue", sender: self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -276,11 +274,12 @@ class PasswordEditorTableViewController: UITableViewController {
|
|||
}
|
||||
}
|
||||
|
||||
private func isPasswordDelimiterCellData(data: Dictionary<PasswordEditorCellKey, Any>) -> Bool {
|
||||
return (data[.type] as? PasswordEditorCellType) == .some(.passwordGroupsCell)
|
||||
private func isPasswordDelimiterCellData(data: [PasswordEditorCellKey: Any]) -> Bool {
|
||||
(data[.type] as? PasswordEditorCellType) == .some(.passwordGroupsCell)
|
||||
}
|
||||
|
||||
@objc func flavorChanged(_ sender: UISegmentedControl) {
|
||||
@objc
|
||||
func flavorChanged(_ sender: UISegmentedControl) {
|
||||
let flavor = PasswordGeneratorFlavor.allCases[sender.selectedSegmentIndex]
|
||||
guard passwordGenerator.flavor != flavor else {
|
||||
return
|
||||
|
|
@ -327,7 +326,7 @@ class PasswordEditorTableViewController: UITableViewController {
|
|||
additionsCell?.setContent(content: additionsString)
|
||||
}
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
override func prepare(for segue: UIStoryboardSegue, sender _: Any?) {
|
||||
if segue.identifier == "showQRScannerSegue" {
|
||||
if let navController = segue.destination as? UINavigationController {
|
||||
if let viewController = navController.topViewController as? QRScannerController {
|
||||
|
|
@ -362,8 +361,8 @@ class PasswordEditorTableViewController: UITableViewController {
|
|||
// the name field should be a valid url
|
||||
guard let path = name.stringByAddingPercentEncodingForRFC3986(),
|
||||
var passwordURL = URL(string: path) else {
|
||||
Utils.alert(title: "CannotSave".localize(), message: "PasswordNameInvalid.".localize(), controller: self, completion: nil)
|
||||
return false
|
||||
Utils.alert(title: "CannotSave".localize(), message: "PasswordNameInvalid.".localize(), controller: self, completion: nil)
|
||||
return false
|
||||
}
|
||||
|
||||
// check whether we can parse the filename (be consistent with PasswordStore::addPasswordEntities)
|
||||
|
|
@ -382,20 +381,20 @@ class PasswordEditorTableViewController: UITableViewController {
|
|||
}
|
||||
|
||||
// MARK: - FillPasswordTableViewCellDelegate
|
||||
extension PasswordEditorTableViewController: FillPasswordTableViewCellDelegate {
|
||||
|
||||
extension PasswordEditorTableViewController: FillPasswordTableViewCellDelegate {
|
||||
// generate password, copy to pasteboard, and set the cell
|
||||
// check whether the current password looks like an OTP field
|
||||
func generateAndCopyPassword() {
|
||||
if let currentPassword = fillPasswordCell?.getContent(), Constants.isOtpRelated(line: currentPassword) {
|
||||
let alert = UIAlertController(title: "Overwrite?".localize(), message: "OverwriteOtpConfiguration?".localize(), preferredStyle: UIAlertController.Style.alert)
|
||||
alert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertAction.Style.destructive, handler: {_ in
|
||||
alert.addAction(UIAlertAction(title: "Yes".localize(), style: UIAlertAction.Style.destructive, handler: { _ in
|
||||
self.generateAndCopyPasswordNoOtpCheck()
|
||||
}))
|
||||
alert.addAction(UIAlertAction.cancel())
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
present(alert, animated: true, completion: nil)
|
||||
} else {
|
||||
self.generateAndCopyPasswordNoOtpCheck()
|
||||
generateAndCopyPasswordNoOtpCheck()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -407,11 +406,12 @@ extension PasswordEditorTableViewController: FillPasswordTableViewCellDelegate {
|
|||
}
|
||||
|
||||
// MARK: - PasswordSettingSliderTableViewCellDelegate
|
||||
|
||||
extension PasswordEditorTableViewController: PasswordSettingSliderTableViewCellDelegate {}
|
||||
|
||||
// MARK: - QRScannerControllerDelegate
|
||||
extension PasswordEditorTableViewController: QRScannerControllerDelegate {
|
||||
|
||||
extension PasswordEditorTableViewController: QRScannerControllerDelegate {
|
||||
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
|
||||
if let url = URL(string: line), let _ = Token(url: url) {
|
||||
return (accept: true, message: "ValidTokenUrl".localize())
|
||||
|
|
@ -426,31 +426,31 @@ extension PasswordEditorTableViewController: QRScannerControllerDelegate {
|
|||
}
|
||||
|
||||
// MARK: - SFSafariViewControllerDelegate
|
||||
extension PasswordEditorTableViewController: SFSafariViewControllerDelegate {
|
||||
|
||||
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
|
||||
let copiedLinesSplit = UIPasteboard.general.string?.components(separatedBy: CharacterSet.whitespacesAndNewlines).filter({ !$0.isEmpty })
|
||||
extension PasswordEditorTableViewController: SFSafariViewControllerDelegate {
|
||||
func safariViewControllerDidFinish(_: SFSafariViewController) {
|
||||
let copiedLinesSplit = UIPasteboard.general.string?.components(separatedBy: CharacterSet.whitespacesAndNewlines).filter { !$0.isEmpty }
|
||||
if copiedLinesSplit?.count ?? 0 > 0 {
|
||||
let generatedPassword = copiedLinesSplit![0]
|
||||
let alert = UIAlertController(title: "WannaUseIt?".localize(), message: "", preferredStyle: UIAlertController.Style.alert)
|
||||
let message = NSMutableAttributedString(string: "\("SeemsLikeYouHaveCopiedSomething.".localize()) \("FirstStringIs:".localize())\n")
|
||||
message.append(Utils.attributedPassword(plainPassword: generatedPassword))
|
||||
alert.setValue(message, forKey: "attributedMessage")
|
||||
alert.addAction(UIAlertAction(title: "Yes", style: UIAlertAction.Style.default, handler: {[unowned self] (action) -> Void in
|
||||
alert.addAction(UIAlertAction(title: "Yes", style: UIAlertAction.Style.default, handler: { [unowned self] (_) -> Void in
|
||||
// update tableData so to make sure reloadData() works correctly
|
||||
self.tableData[self.passwordSection][0][PasswordEditorCellKey.content] = generatedPassword
|
||||
// update cell manually, no need to call reloadData()
|
||||
self.fillPasswordCell?.setContent(content: generatedPassword)
|
||||
}))
|
||||
alert.addAction(UIAlertAction.cancel())
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
present(alert, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UITextFieldDelegate
|
||||
extension PasswordEditorTableViewController: UITextFieldDelegate {
|
||||
|
||||
extension PasswordEditorTableViewController: UITextFieldDelegate {
|
||||
// update tableData so to make sure reloadData() works correctly
|
||||
func textFieldDidEndEditing(_ textField: UITextField) {
|
||||
if textField == nameCell?.contentTextField {
|
||||
|
|
@ -471,8 +471,8 @@ extension PasswordEditorTableViewController: UITextFieldDelegate {
|
|||
}
|
||||
|
||||
// MARK: - UITextViewDelegate
|
||||
extension PasswordEditorTableViewController: UITextViewDelegate {
|
||||
|
||||
extension PasswordEditorTableViewController: UITextViewDelegate {
|
||||
// update tableData so to make sure reloadData() works correctly
|
||||
func textViewDidEndEditing(_ textView: UITextView) {
|
||||
if textView == additionsCell?.contentTextView {
|
||||
|
|
|
|||
|
|
@ -6,16 +6,16 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SVProgressHUD
|
||||
import passKit
|
||||
import SVProgressHUD
|
||||
import UIKit
|
||||
|
||||
fileprivate let hideSectionHeaderThreshold = 6 // hide section header if passwords count is less than the threshold
|
||||
private let hideSectionHeaderThreshold = 6 // hide section header if passwords count is less than the threshold
|
||||
|
||||
class PasswordsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITabBarControllerDelegate, UISearchBarDelegate {
|
||||
private var passwordsTableEntries: [PasswordTableEntry] = []
|
||||
private var passwordsTableAllEntries: [PasswordTableEntry] = []
|
||||
private var parentPasswordEntity: PasswordEntity? = nil
|
||||
private var parentPasswordEntity: PasswordEntity?
|
||||
private let passwordStore = PasswordStore.shared
|
||||
private let keychain = AppKeychain.shared
|
||||
|
||||
|
|
@ -30,14 +30,12 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
|
||||
private var gitCredential: GitCredential {
|
||||
get {
|
||||
switch Defaults.gitAuthenticationMethod {
|
||||
case .password:
|
||||
return GitCredential(credential: .http(userName: Defaults.gitUsername))
|
||||
case .key:
|
||||
let privateKey: String = AppKeychain.shared.get(for: SshKey.PRIVATE.getKeychainKey()) ?? ""
|
||||
return GitCredential(credential: .ssh(userName: Defaults.gitUsername, privateKey: privateKey))
|
||||
}
|
||||
switch Defaults.gitAuthenticationMethod {
|
||||
case .password:
|
||||
return GitCredential(credential: .http(userName: Defaults.gitUsername))
|
||||
case .key:
|
||||
let privateKey: String = AppKeychain.shared.get(for: SshKey.PRIVATE.getKeychainKey()) ?? ""
|
||||
return GitCredential(credential: .ssh(userName: Defaults.gitUsername, privateKey: privateKey))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -49,11 +47,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
uiSearchController.searchBar.sizeToFit()
|
||||
return uiSearchController
|
||||
}()
|
||||
|
||||
private lazy var syncControl: UIRefreshControl = {
|
||||
let syncControl = UIRefreshControl()
|
||||
syncControl.addTarget(self, action: #selector(handleRefresh(_:)), for: UIControl.Event.valueChanged)
|
||||
return syncControl
|
||||
}()
|
||||
|
||||
private lazy var searchBarView: UIView? = {
|
||||
guard #available(iOS 11, *) else {
|
||||
let uiView = UIView(frame: CGRect(x: 0, y: 64, width: self.view.bounds.width, height: 44))
|
||||
|
|
@ -62,6 +62,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
return nil
|
||||
}()
|
||||
|
||||
private lazy var backUIBarButtonItem: UIBarButtonItem = {
|
||||
let backUIButton = UIButton(type: .system)
|
||||
if #available(iOS 13.0, *) {
|
||||
|
|
@ -116,28 +117,29 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
return transition
|
||||
}()
|
||||
|
||||
@IBOutlet weak var tableView: UITableView!
|
||||
@IBOutlet var tableView: UITableView!
|
||||
|
||||
private func initPasswordsTableEntries(parent: PasswordEntity?) {
|
||||
let passwordAllEntities = self.passwordStore.fetchPasswordEntityCoreData(withDir: false)
|
||||
let passwordAllEntities = passwordStore.fetchPasswordEntityCoreData(withDir: false)
|
||||
passwordsTableAllEntries = passwordAllEntities.compactMap {
|
||||
PasswordTableEntry($0)
|
||||
}
|
||||
|
||||
|
||||
let passwordEntities = Defaults.isShowFolderOn ?
|
||||
self.passwordStore.fetchPasswordEntityCoreData(parent: parent) :
|
||||
passwordStore.fetchPasswordEntityCoreData(parent: parent) :
|
||||
passwordAllEntities
|
||||
passwordsTableEntries = passwordEntities.compactMap {
|
||||
PasswordTableEntry($0)
|
||||
}
|
||||
|
||||
|
||||
parentPasswordEntity = parent
|
||||
}
|
||||
|
||||
@IBAction func cancelAddPassword(segue: UIStoryboardSegue) {
|
||||
@IBAction
|
||||
func cancelAddPassword(segue _: UIStoryboardSegue) {}
|
||||
|
||||
}
|
||||
@IBAction func saveAddPassword(segue: UIStoryboardSegue) {
|
||||
@IBAction
|
||||
func saveAddPassword(segue: UIStoryboardSegue) {
|
||||
if let controller = segue.source as? AddPasswordTableViewController {
|
||||
addPassword(password: controller.password!)
|
||||
}
|
||||
|
|
@ -149,13 +151,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
SVProgressHUD.show(withStatus: "Saving".localize())
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
do {
|
||||
let _ = try self.passwordStore.add(password: password, keyID: keyID)
|
||||
_ = try self.passwordStore.add(password: password, keyID: keyID)
|
||||
DispatchQueue.main.async {
|
||||
// will trigger reloadTableView() by a notification
|
||||
SVProgressHUD.showSuccess(withStatus: "Done".localize())
|
||||
SVProgressHUD.dismiss(withDelay: 1)
|
||||
}
|
||||
} catch AppError.PgpPublicKeyNotFound(let key) {
|
||||
} catch let AppError.PgpPublicKeyNotFound(key) {
|
||||
DispatchQueue.main.async {
|
||||
// alert: cancel or select keys
|
||||
SVProgressHUD.dismiss()
|
||||
|
|
@ -190,15 +192,15 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
|
||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||
do {
|
||||
try self.passwordStore.pullRepository(credential: self.gitCredential, requestCredentialPassword: self.requestCredentialPassword, progressBlock: {(git_transfer_progress, stop) in
|
||||
try self.passwordStore.pullRepository(credential: self.gitCredential, requestCredentialPassword: self.requestCredentialPassword, progressBlock: { git_transfer_progress, _ in
|
||||
DispatchQueue.main.async {
|
||||
SVProgressHUD.showProgress(Float(git_transfer_progress.pointee.received_objects)/Float(git_transfer_progress.pointee.total_objects), status: "PullingFromRemoteRepository".localize())
|
||||
SVProgressHUD.showProgress(Float(git_transfer_progress.pointee.received_objects) / Float(git_transfer_progress.pointee.total_objects), status: "PullingFromRemoteRepository".localize())
|
||||
}
|
||||
})
|
||||
if self.passwordStore.numberOfLocalCommits > 0 {
|
||||
try self.passwordStore.pushRepository(credential: self.gitCredential, requestCredentialPassword: self.requestCredentialPassword, transferProgressBlock: {(current, total, bytes, stop) in
|
||||
try self.passwordStore.pushRepository(credential: self.gitCredential, requestCredentialPassword: self.requestCredentialPassword, transferProgressBlock: { current, total, _, _ in
|
||||
DispatchQueue.main.async {
|
||||
SVProgressHUD.showProgress(Float(current)/Float(total), status: "PushingToRemoteRepository".localize())
|
||||
SVProgressHUD.showProgress(Float(current) / Float(total), status: "PushingToRemoteRepository".localize())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -232,7 +234,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
super.viewDidAppear(animated)
|
||||
|
||||
if Defaults.isShowFolderOn {
|
||||
searchController.searchBar.scopeButtonTitles = SearchBarScope.allCases.map { $0.localizedName }
|
||||
searchController.searchBar.scopeButtonTitles = SearchBarScope.allCases.map(\.localizedName)
|
||||
} else {
|
||||
searchController.searchBar.scopeButtonTitles = nil
|
||||
}
|
||||
|
|
@ -251,7 +253,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
navigationItem.hidesSearchBarWhenScrolling = false
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
tableView.contentInset = UIEdgeInsets.init(top: 44, left: 0, bottom: 0, right: 0)
|
||||
tableView.contentInset = UIEdgeInsets(top: 44, left: 0, bottom: 0, right: 0)
|
||||
view.addSubview(searchBarView!)
|
||||
}
|
||||
navigationItem.title = "PasswordStore".localize()
|
||||
|
|
@ -272,16 +274,17 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
NotificationCenter.default.addObserver(self, selector: #selector(actOnReloadTableViewRelatedNotification), name: UIApplication.willEnterForegroundNotification, object: nil)
|
||||
|
||||
// listen to the swipe back guesture
|
||||
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
|
||||
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(respondToSwipeGesture))
|
||||
swipeRight.direction = UISwipeGestureRecognizer.Direction.right
|
||||
self.view.addGestureRecognizer(swipeRight)
|
||||
view.addGestureRecognizer(swipeRight)
|
||||
}
|
||||
|
||||
@objc func didTapNavigationBar(_ sender: UITapGestureRecognizer) {
|
||||
let location = sender.location(in: self.navigationController?.navigationBar)
|
||||
let hitView = self.navigationController?.navigationBar.hitTest(location, with: nil)
|
||||
@objc
|
||||
func didTapNavigationBar(_ sender: UITapGestureRecognizer) {
|
||||
let location = sender.location(in: navigationController?.navigationBar)
|
||||
let hitView = navigationController?.navigationBar.hitTest(location, with: nil)
|
||||
guard !(hitView is UIControl) else { return }
|
||||
guard (passwordStore.numberOfLocalCommits != 0) else { return }
|
||||
guard passwordStore.numberOfLocalCommits != 0 else { return }
|
||||
|
||||
let ac = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||
let allAction = UIAlertAction(title: "All Passwords", style: .default) { _ in
|
||||
|
|
@ -289,7 +292,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
let unsyncedAction = UIAlertAction(title: "Unsynced Passwords", style: .default) { _ in
|
||||
let filteredPasswordsTableEntries = self.passwordsTableEntries.filter { entry in
|
||||
return !entry.synced
|
||||
!entry.synced
|
||||
}
|
||||
self.reloadTableView(data: filteredPasswordsTableEntries, label: .unsynced)
|
||||
}
|
||||
|
|
@ -299,7 +302,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
ac.addAction(unsyncedAction)
|
||||
ac.addAction(cancelAction)
|
||||
|
||||
self.present(ac, animated: true, completion: nil)
|
||||
present(ac, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
|
|
@ -310,7 +313,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
|
||||
// Add gesture recognizer to the navigation bar when the view is about to appear
|
||||
self.navigationController?.navigationBar.addGestureRecognizer(tapNavigationBarGestureRecognizer)
|
||||
navigationController?.navigationBar.addGestureRecognizer(tapNavigationBarGestureRecognizer)
|
||||
|
||||
// This allows controlls in the navigation bar to continue receiving touches
|
||||
tapNavigationBarGestureRecognizer.cancelsTouchesInView = false
|
||||
|
|
@ -318,9 +321,9 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
tableView.refreshControl = passwordStore.repositoryExists() ? syncControl : nil
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
override func viewWillDisappear(_: Bool) {
|
||||
// Remove gesture recognizer from navigation bar when view is about to disappear
|
||||
self.navigationController?.navigationBar.removeGestureRecognizer(tapNavigationBarGestureRecognizer)
|
||||
navigationController?.navigationBar.removeGestureRecognizer(tapNavigationBarGestureRecognizer)
|
||||
}
|
||||
|
||||
override func viewWillLayoutSubviews() {
|
||||
|
|
@ -332,12 +335,12 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
}
|
||||
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return sections.count
|
||||
func numberOfSections(in _: UITableView) -> Int {
|
||||
sections.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return sections[section].entries.count
|
||||
func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
sections[section].entries.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
|
@ -372,7 +375,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
|
||||
private func getPasswordEntry(by indexPath: IndexPath) -> PasswordTableEntry {
|
||||
return sections[indexPath.section].entries[indexPath.row]
|
||||
sections[indexPath.section].entries[indexPath.row]
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
|
|
@ -390,16 +393,18 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
}
|
||||
|
||||
@objc func respondToSwipeGesture(gesture: UIGestureRecognizer) {
|
||||
@objc
|
||||
func respondToSwipeGesture(gesture: UIGestureRecognizer) {
|
||||
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
|
||||
// swipe right -> swipe back
|
||||
if swipeGesture.direction == .right && parentPasswordEntity != nil {
|
||||
self.backAction(nil)
|
||||
if swipeGesture.direction == .right, parentPasswordEntity != nil {
|
||||
backAction(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func backAction(_ sender: Any?) {
|
||||
@objc
|
||||
func backAction(_: Any?) {
|
||||
guard Defaults.isShowFolderOn else { return }
|
||||
var anim: CATransition? = transitionFromLeft
|
||||
if parentPasswordEntity == nil {
|
||||
|
|
@ -408,13 +413,15 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
reloadTableView(parent: parentPasswordEntity?.parent, anim: anim)
|
||||
}
|
||||
|
||||
@objc func addPasswordAction(_ sender: Any?) {
|
||||
@objc
|
||||
func addPasswordAction(_: Any?) {
|
||||
if shouldPerformSegue(withIdentifier: "addPasswordSegue", sender: self) {
|
||||
performSegue(withIdentifier: "addPasswordSegue", sender: self)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func longPressAction(_ gesture: UILongPressGestureRecognizer) {
|
||||
@objc
|
||||
func longPressAction(_ gesture: UILongPressGestureRecognizer) {
|
||||
if gesture.state == UIGestureRecognizer.State.began {
|
||||
let touchPoint = gesture.location(in: tableView)
|
||||
if let indexPath = tableView.indexPathForRow(at: touchPoint) {
|
||||
|
|
@ -424,31 +431,31 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
|
||||
private func hideSectionHeader() -> Bool {
|
||||
if passwordsTableEntries.count < hideSectionHeaderThreshold || self.searchController.isActive {
|
||||
if passwordsTableEntries.count < hideSectionHeaderThreshold || searchController.isActive {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
if hideSectionHeader() {
|
||||
return nil
|
||||
}
|
||||
return sections[section].title
|
||||
}
|
||||
|
||||
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
|
||||
func sectionIndexTitles(for _: UITableView) -> [String]? {
|
||||
if hideSectionHeader() {
|
||||
return nil
|
||||
}
|
||||
return sections.map { $0.title }
|
||||
return sections.map(\.title)
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
|
||||
return index
|
||||
func tableView(_: UITableView, sectionForSectionIndexTitle _: String, at index: Int) -> Int {
|
||||
index
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
|
||||
func tableView(_: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
|
||||
decryptThenCopyPassword(from: indexPath)
|
||||
}
|
||||
|
||||
|
|
@ -460,7 +467,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
let passwordEntity = getPasswordEntry(by: indexPath).passwordEntity
|
||||
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
|
||||
SVProgressHUD.dismiss()
|
||||
self.decryptPassword(passwordEntity: passwordEntity)
|
||||
decryptPassword(passwordEntity: passwordEntity)
|
||||
}
|
||||
|
||||
private func decryptPassword(passwordEntity: PasswordEntity, keyID: String? = nil) {
|
||||
|
|
@ -476,7 +483,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
SVProgressHUD.showSuccess(withStatus: "PasswordCopiedToPasteboard.".localize())
|
||||
SVProgressHUD.dismiss(withDelay: 0.6)
|
||||
}
|
||||
} catch AppError.PgpPrivateKeyNotFound(let key) {
|
||||
} catch let AppError.PgpPrivateKeyNotFound(key) {
|
||||
DispatchQueue.main.async {
|
||||
// alert: cancel or try again
|
||||
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.PgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
|
||||
|
|
@ -488,7 +495,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
|
||||
self.present(alert, animated: true)
|
||||
}
|
||||
} catch {
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
Utils.alert(title: "CannotCopyPassword".localize(), message: error.localizedDescription, controller: self)
|
||||
}
|
||||
|
|
@ -496,14 +503,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private func generateSections(item: [PasswordTableEntry]) {
|
||||
let collation = UILocalizedIndexedCollation.current()
|
||||
let sectionTitles = collation.sectionIndexTitles
|
||||
var newSections = [(title: String, entries: [PasswordTableEntry])]()
|
||||
|
||||
// initialize all sections
|
||||
for i in 0..<sectionTitles.count {
|
||||
for i in 0 ..< sectionTitles.count {
|
||||
newSections.append((title: sectionTitles[i], entries: [PasswordTableEntry]()))
|
||||
}
|
||||
|
||||
|
|
@ -514,21 +520,21 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
|
||||
// sort each list and set sectionTitles
|
||||
for i in 0..<sectionTitles.count {
|
||||
for i in 0 ..< sectionTitles.count {
|
||||
let entriesToSort = newSections[i].entries
|
||||
let sortedEntries = collation.sortedArray(from: entriesToSort, collationStringSelector: #selector(getter: PasswordTableEntry.title))
|
||||
newSections[i].entries = sortedEntries as! [PasswordTableEntry]
|
||||
}
|
||||
|
||||
// only keep non-empty sections
|
||||
sections = newSections.filter {$0.entries.count > 0}
|
||||
sections = newSections.filter { !$0.entries.isEmpty }
|
||||
}
|
||||
|
||||
@objc func actOnSearchNotification() {
|
||||
@objc
|
||||
func actOnSearchNotification() {
|
||||
searchController.searchBar.becomeFirstResponder()
|
||||
}
|
||||
|
||||
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||
if identifier == "showPasswordDetail" {
|
||||
guard PGPAgent.shared.isPrepared else {
|
||||
|
|
@ -540,7 +546,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
return false
|
||||
}
|
||||
} else if identifier == "addPasswordSegue" {
|
||||
guard PGPAgent.shared.isPrepared && self.passwordStore.storeRepository != nil else {
|
||||
guard PGPAgent.shared.isPrepared && passwordStore.storeRepository != nil else {
|
||||
Utils.alert(title: "CannotAddPassword".localize(), message: "MakeSurePgpAndGitProperlySet.".localize(), controller: self, completion: nil)
|
||||
return false
|
||||
}
|
||||
|
|
@ -551,7 +557,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
if segue.identifier == "showPasswordDetail" {
|
||||
if let viewController = segue.destination as? PasswordDetailTableViewController {
|
||||
let selectedIndexPath = self.tableView.indexPath(for: sender as! UITableViewCell)!
|
||||
let selectedIndexPath = tableView.indexPath(for: sender as! UITableViewCell)!
|
||||
let passwordEntity = getPasswordEntry(by: selectedIndexPath).passwordEntity
|
||||
viewController.passwordEntity = passwordEntity
|
||||
}
|
||||
|
|
@ -568,8 +574,8 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
|
||||
func filterContentForSearchText(searchText: String, scope: SearchBarScope = .all) {
|
||||
var entries: [PasswordTableEntry] = scope == .all ? passwordsTableAllEntries : passwordsTableEntries
|
||||
if searchController.isActive && searchController.searchBar.text != "" {
|
||||
entries = entries.filter {$0.match(searchText)}
|
||||
if searchController.isActive, searchController.searchBar.text != "" {
|
||||
entries = entries.filter { $0.match(searchText) }
|
||||
}
|
||||
reloadTableView(data: entries)
|
||||
}
|
||||
|
|
@ -587,7 +593,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
if #available(iOS 11, *) {
|
||||
navigationController?.navigationBar.prefersLargeTitles = false
|
||||
}
|
||||
self.navigationController?.navigationBar.removeGestureRecognizer(tapNavigationBarGestureRecognizer)
|
||||
navigationController?.navigationBar.removeGestureRecognizer(tapNavigationBarGestureRecognizer)
|
||||
} else {
|
||||
navigationItem.leftBarButtonItem = nil
|
||||
switch label {
|
||||
|
|
@ -599,17 +605,17 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
if #available(iOS 11, *) {
|
||||
navigationController?.navigationBar.prefersLargeTitles = true
|
||||
}
|
||||
self.navigationController?.navigationBar.addGestureRecognizer(tapNavigationBarGestureRecognizer)
|
||||
navigationController?.navigationBar.addGestureRecognizer(tapNavigationBarGestureRecognizer)
|
||||
}
|
||||
navigationItem.rightBarButtonItem = addPasswordUIBarButtonItem
|
||||
|
||||
// set the password table
|
||||
generateSections(item: data)
|
||||
if anim != nil {
|
||||
self.tableView.layer.add(anim!, forKey: "UITableViewReloadDataAnimationKey")
|
||||
tableView.layer.add(anim!, forKey: "UITableViewReloadDataAnimationKey")
|
||||
}
|
||||
tableView.reloadData()
|
||||
self.tableView.layer.removeAnimation(forKey: "UITableViewReloadDataAnimationKey")
|
||||
tableView.layer.removeAnimation(forKey: "UITableViewReloadDataAnimationKey")
|
||||
|
||||
// set the sync control title
|
||||
let atribbutedTitle = "LastSynced".localize() + ": \(lastSyncedTimeString())"
|
||||
|
|
@ -617,7 +623,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
|
||||
private func lastSyncedTimeString() -> String {
|
||||
guard let date = self.passwordStore.lastSyncedTime else {
|
||||
guard let date = passwordStore.lastSyncedTime else {
|
||||
return "SyncAgain?".localize()
|
||||
}
|
||||
let formatter = DateFormatter()
|
||||
|
|
@ -631,7 +637,8 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
reloadTableView(data: passwordsTableEntries, label: label, anim: anim)
|
||||
}
|
||||
|
||||
@objc func actOnReloadTableViewRelatedNotification() {
|
||||
@objc
|
||||
func actOnReloadTableViewRelatedNotification() {
|
||||
DispatchQueue.main.async { [weak weakSelf = self] in
|
||||
guard let strongSelf = weakSelf else { return }
|
||||
// Reset selectedScopeButtonIndex to make sure the correct reloadTableView
|
||||
|
|
@ -641,36 +648,37 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
}
|
||||
|
||||
@objc func handleRefresh(_ syncControl: UIRefreshControl) {
|
||||
@objc
|
||||
func handleRefresh(_: UIRefreshControl) {
|
||||
syncPasswords()
|
||||
}
|
||||
|
||||
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
|
||||
if viewController == self.navigationController {
|
||||
func tabBarController(_: UITabBarController, didSelect viewController: UIViewController) {
|
||||
if viewController == navigationController {
|
||||
let currentTime = Date().timeIntervalSince1970
|
||||
let duration = currentTime - self.tapTabBarTime
|
||||
self.tapTabBarTime = currentTime
|
||||
let duration = currentTime - tapTabBarTime
|
||||
tapTabBarTime = currentTime
|
||||
if duration < 0.35 {
|
||||
let topIndexPath = IndexPath(row: 0, section: 0)
|
||||
if tableView.numberOfSections > 0 {
|
||||
tableView.scrollToRow(at: topIndexPath, at: .bottom, animated: true)
|
||||
}
|
||||
self.tapTabBarTime = 0
|
||||
if tableView.numberOfSections > 0 {
|
||||
tableView.scrollToRow(at: topIndexPath, at: .bottom, animated: true)
|
||||
}
|
||||
tapTabBarTime = 0
|
||||
return
|
||||
}
|
||||
backAction(self)
|
||||
}
|
||||
}
|
||||
|
||||
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
|
||||
func searchBar(_: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
|
||||
// update the default search scope
|
||||
Defaults.searchDefault = SearchBarScope(rawValue: selectedScope)
|
||||
updateSearchResults(for: searchController)
|
||||
}
|
||||
|
||||
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
|
||||
func searchBarShouldBeginEditing(_: UISearchBar) -> Bool {
|
||||
// set the default search scope to "all"
|
||||
if Defaults.isShowFolderOn && Defaults.searchDefault == .all {
|
||||
if Defaults.isShowFolderOn, Defaults.searchDefault == .all {
|
||||
searchController.searchBar.selectedScopeButtonIndex = SearchBarScope.all.rawValue
|
||||
} else {
|
||||
searchController.searchBar.selectedScopeButtonIndex = SearchBarScope.current.rawValue
|
||||
|
|
@ -678,7 +686,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
return true
|
||||
}
|
||||
|
||||
func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool {
|
||||
func searchBarShouldEndEditing(_: UISearchBar) -> Bool {
|
||||
// set the default search scope to "current"
|
||||
searchController.searchBar.selectedScopeButtonIndex = SearchBarScope.current.rawValue
|
||||
updateSearchResults(for: searchController)
|
||||
|
|
@ -686,13 +694,11 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
|
||||
private func requestCredentialPassword(credential: GitCredential.Credential, lastPassword: String?) -> String? {
|
||||
return requestGitCredentialPassword(credential: credential, lastPassword: lastPassword, controller: self)
|
||||
requestGitCredentialPassword(credential: credential, lastPassword: lastPassword, controller: self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension PasswordsViewController: UISearchResultsUpdating {
|
||||
|
||||
func updateSearchResults(for searchController: UISearchController) {
|
||||
let scope = SearchBarScope(rawValue: searchController.searchBar.selectedScopeButtonIndex) ?? .all
|
||||
filterContentForSearchText(searchText: searchController.searchBar.text!, scope: scope)
|
||||
|
|
@ -700,8 +706,7 @@ extension PasswordsViewController: UISearchResultsUpdating {
|
|||
}
|
||||
|
||||
extension PasswordsViewController: CAAnimationDelegate {
|
||||
|
||||
func animationDidStart(_ anim: CAAnimation) {
|
||||
func animationDidStart(_: CAAnimation) {
|
||||
view.window?.backgroundColor = Colors.systemBackground
|
||||
view.layer.backgroundColor = Colors.systemBackground.cgColor
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@
|
|||
// Copyright © 2017 Yishi Lin. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import AVFoundation
|
||||
import OneTimePassword
|
||||
import SVProgressHUD
|
||||
import passKit
|
||||
import SVProgressHUD
|
||||
import UIKit
|
||||
|
||||
protocol QRScannerControllerDelegate {
|
||||
func checkScannedOutput(line: String) -> (accept: Bool, message: String)
|
||||
|
|
@ -18,8 +18,7 @@ protocol QRScannerControllerDelegate {
|
|||
}
|
||||
|
||||
class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
|
||||
|
||||
@IBOutlet weak var scannerOutput: UILabel!
|
||||
@IBOutlet var scannerOutput: UILabel!
|
||||
|
||||
var captureSession: AVCaptureSession?
|
||||
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
|
||||
|
|
@ -93,15 +92,12 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg
|
|||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
|
||||
// MARK: - AVCaptureMetadataOutputObjectsDelegate Methods
|
||||
|
||||
func metadataOutput(_ captureOutput: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
|
||||
|
||||
func metadataOutput(_: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from _: AVCaptureConnection) {
|
||||
if let metadataObj = metadataObjects.first as? AVMetadataMachineReadableCodeObject,
|
||||
supportedCodeTypes.contains(metadataObj.type),
|
||||
let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj) {
|
||||
|
||||
// draw a bounds on the found QR code
|
||||
qrCodeFrameView?.frame = barCodeObject.bounds
|
||||
|
||||
|
|
|
|||
|
|
@ -6,12 +6,11 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import passKit
|
||||
import UIKit
|
||||
|
||||
class RawPasswordViewController: UIViewController {
|
||||
|
||||
@IBOutlet weak var rawPasswordTextView: UITextView!
|
||||
@IBOutlet var rawPasswordTextView: UITextView!
|
||||
var password: Password?
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
|
|
|||
|
|
@ -6,13 +6,12 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import passKit
|
||||
import UIKit
|
||||
|
||||
class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController, UITextViewDelegate, QRScannerControllerDelegate {
|
||||
|
||||
@IBOutlet weak var armorPrivateKeyTextView: UITextView!
|
||||
@IBOutlet weak var scanPrivateKeyCell: UITableViewCell!
|
||||
@IBOutlet var armorPrivateKeyTextView: UITextView!
|
||||
@IBOutlet var scanPrivateKeyCell: UITableViewCell!
|
||||
|
||||
var gitSSHPrivateKeyPassphrase: String?
|
||||
var armorPrivateKey: String?
|
||||
|
|
@ -22,32 +21,33 @@ class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
|
|||
var message = ""
|
||||
|
||||
func reset() {
|
||||
self.segments.removeAll()
|
||||
segments.removeAll()
|
||||
message = "LookingForStartingFrame.".localize()
|
||||
}
|
||||
|
||||
func addSegment(segment: String) -> (accept: Bool, message: String) {
|
||||
// Skip duplicated segments.
|
||||
guard segment != self.segments.last else {
|
||||
return (accept: false, message: self.message)
|
||||
guard segment != segments.last else {
|
||||
return (accept: false, message: message)
|
||||
}
|
||||
|
||||
|
||||
// Check whether we have found the first block.
|
||||
guard !self.segments.isEmpty || segment.contains("-----BEGIN") else {
|
||||
return (accept: false, message: self.message)
|
||||
guard !segments.isEmpty || segment.contains("-----BEGIN") else {
|
||||
return (accept: false, message: message)
|
||||
}
|
||||
|
||||
|
||||
// Update the list of scanned segment and return.
|
||||
self.segments.append(segment)
|
||||
segments.append(segment)
|
||||
if segment.range(of: "-----END.*KEY-----", options: .regularExpression, range: nil, locale: nil) != nil {
|
||||
self.message = "Done".localize()
|
||||
return (accept: true, message: self.message)
|
||||
message = "Done".localize()
|
||||
return (accept: true, message: message)
|
||||
} else {
|
||||
self.message = "ScannedQrCodes(%d)".localize(self.segments.count)
|
||||
return (accept: false, message: self.message)
|
||||
message = "ScannedQrCodes(%d)".localize(segments.count)
|
||||
return (accept: false, message: message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var scanned = ScannedSSHKey()
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
|
@ -59,12 +59,13 @@ class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
|
|||
scanPrivateKeyCell?.accessoryType = .disclosureIndicator
|
||||
}
|
||||
|
||||
@IBAction func doneButtonTapped(_ sender: Any) {
|
||||
@IBAction
|
||||
func doneButtonTapped(_: Any) {
|
||||
armorPrivateKey = armorPrivateKeyTextView.text
|
||||
performSegue(withIdentifier: "importSSHKeySegue", sender: self)
|
||||
}
|
||||
|
||||
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
|
||||
func textView(_: UITextView, shouldChangeTextIn _: NSRange, replacementText text: String) -> Bool {
|
||||
if text == UIPasteboard.general.string {
|
||||
// user pastes something, do the copy here again and clear the pasteboard in 45s
|
||||
SecurePasteboard.shared.copy(textToCopy: text)
|
||||
|
|
@ -76,23 +77,24 @@ class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
|
|||
let selectedCell = tableView.cellForRow(at: indexPath)
|
||||
if selectedCell == scanPrivateKeyCell {
|
||||
scanned.reset()
|
||||
self.performSegue(withIdentifier: "showSSHScannerSegue", sender: self)
|
||||
performSegue(withIdentifier: "showSSHScannerSegue", sender: self)
|
||||
}
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - QRScannerControllerDelegate Methods
|
||||
|
||||
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
|
||||
return scanned.addSegment(segment: line)
|
||||
}
|
||||
|
||||
// MARK: - QRScannerControllerDelegate Methods
|
||||
func handleScannedOutput(line: String) {
|
||||
|
||||
func handleScannedOutput(line _: String) {
|
||||
armorPrivateKeyTextView.text = scanned.segments.joined(separator: "")
|
||||
}
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
override func prepare(for segue: UIStoryboardSegue, sender _: Any?) {
|
||||
if segue.identifier == "showSSHScannerSegue" {
|
||||
if let navController = segue.destination as? UINavigationController {
|
||||
if let viewController = navController.topViewController as? QRScannerController {
|
||||
|
|
@ -104,13 +106,11 @@ class SSHKeyArmorImportTableViewController: AutoCellHeightUITableViewController,
|
|||
}
|
||||
}
|
||||
|
||||
@IBAction private func cancelSSHScanner(segue: UIStoryboardSegue) {
|
||||
|
||||
}
|
||||
@IBAction
|
||||
private func cancelSSHScanner(segue _: UIStoryboardSegue) {}
|
||||
}
|
||||
|
||||
extension SSHKeyArmorImportTableViewController: KeyImporter {
|
||||
|
||||
static let keySource = KeySource.armor
|
||||
static let label = "AsciiArmorEncryptedKey".localize()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ import passKit
|
|||
import SVProgressHUD
|
||||
|
||||
class SSHKeyFileImportTableViewController: AutoCellHeightUITableViewController {
|
||||
@IBOutlet var sshPrivateKeyFile: UITableViewCell!
|
||||
|
||||
@IBOutlet weak var sshPrivateKeyFile: UITableViewCell!
|
||||
private var privateKey: String?
|
||||
|
||||
private var privateKey: String? = nil
|
||||
|
||||
@IBAction func doneButtonTapped(_ sender: Any) {
|
||||
@IBAction
|
||||
func doneButtonTapped(_: Any) {
|
||||
performSegue(withIdentifier: "importSSHKeySegue", sender: self)
|
||||
}
|
||||
|
||||
|
|
@ -35,7 +35,6 @@ class SSHKeyFileImportTableViewController: AutoCellHeightUITableViewController {
|
|||
}
|
||||
|
||||
extension SSHKeyFileImportTableViewController: UIDocumentPickerDelegate {
|
||||
|
||||
func documentPicker(_: UIDocumentPickerViewController, didPickDocumentsAt url: [URL]) {
|
||||
guard let url = url.first else {
|
||||
return
|
||||
|
|
@ -61,7 +60,6 @@ extension SSHKeyFileImportTableViewController: UIDocumentPickerDelegate {
|
|||
}
|
||||
|
||||
extension SSHKeyFileImportTableViewController: KeyImporter {
|
||||
|
||||
static let keySource = KeySource.file
|
||||
static let label = "LoadFromFiles".localize()
|
||||
|
||||
|
|
|
|||
|
|
@ -6,12 +6,11 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import SVProgressHUD
|
||||
import passKit
|
||||
import SVProgressHUD
|
||||
|
||||
class SSHKeyUrlImportTableViewController: AutoCellHeightUITableViewController {
|
||||
|
||||
@IBOutlet weak var privateKeyURLTextField: UITextField!
|
||||
@IBOutlet var privateKeyURLTextField: UITextField!
|
||||
|
||||
var sshPrivateKeyURL: URL?
|
||||
|
||||
|
|
@ -20,11 +19,12 @@ class SSHKeyUrlImportTableViewController: AutoCellHeightUITableViewController {
|
|||
privateKeyURLTextField.text = Defaults.gitSSHPrivateKeyURL?.absoluteString
|
||||
}
|
||||
|
||||
@IBAction func doneButtonTapped(_ sender: UIButton) {
|
||||
@IBAction
|
||||
func doneButtonTapped(_: UIButton) {
|
||||
guard let text = privateKeyURLTextField.text,
|
||||
let privateKeyURL = URL(string: text) else {
|
||||
Utils.alert(title: "CannotSave".localize(), message: "SetPrivateKeyUrl.".localize(), controller: self)
|
||||
return
|
||||
Utils.alert(title: "CannotSave".localize(), message: "SetPrivateKeyUrl.".localize(), controller: self)
|
||||
return
|
||||
}
|
||||
|
||||
if privateKeyURL.scheme?.lowercased() == "http" {
|
||||
|
|
@ -41,7 +41,6 @@ class SSHKeyUrlImportTableViewController: AutoCellHeightUITableViewController {
|
|||
}
|
||||
|
||||
extension SSHKeyUrlImportTableViewController: KeyImporter {
|
||||
|
||||
static let keySource = KeySource.url
|
||||
static let label = "DownloadFromUrl".localize()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,15 +10,16 @@ import UIKit
|
|||
|
||||
class SettingsSplitViewController: UISplitViewController, UISplitViewControllerDelegate {
|
||||
override func viewDidLoad() {
|
||||
self.delegate = self
|
||||
self.preferredDisplayMode = .allVisible
|
||||
delegate = self
|
||||
preferredDisplayMode = .allVisible
|
||||
}
|
||||
|
||||
func splitViewController(
|
||||
_ splitViewController: UISplitViewController,
|
||||
collapseSecondary secondaryViewController: UIViewController,
|
||||
onto primaryViewController: UIViewController) -> Bool {
|
||||
_: UISplitViewController,
|
||||
collapseSecondary _: UIViewController,
|
||||
onto _: UIViewController
|
||||
) -> Bool {
|
||||
// Return true to prevent UIKit from applying its default behavior
|
||||
return true
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,26 +6,27 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SVProgressHUD
|
||||
import CoreData
|
||||
import passKit
|
||||
import SVProgressHUD
|
||||
import UIKit
|
||||
|
||||
class SettingsTableViewController: UITableViewController, UITabBarControllerDelegate {
|
||||
@IBOutlet weak var pgpKeyTableViewCell: UITableViewCell!
|
||||
@IBOutlet weak var passcodeTableViewCell: UITableViewCell!
|
||||
@IBOutlet weak var passwordRepositoryTableViewCell: UITableViewCell!
|
||||
@IBOutlet var pgpKeyTableViewCell: UITableViewCell!
|
||||
@IBOutlet var passcodeTableViewCell: UITableViewCell!
|
||||
@IBOutlet var passwordRepositoryTableViewCell: UITableViewCell!
|
||||
var setPasscodeLockAlert: UIAlertController?
|
||||
|
||||
let passwordStore = PasswordStore.shared
|
||||
let keychain = AppKeychain.shared
|
||||
var passcodeLock = PasscodeLock.shared
|
||||
|
||||
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
|
||||
func tabBarController(_: UITabBarController, didSelect _: UIViewController) {
|
||||
navigationController?.popViewController(animated: true)
|
||||
}
|
||||
|
||||
@IBAction func savePGPKey(segue: UIStoryboardSegue) {
|
||||
@IBAction
|
||||
func savePGPKey(segue: UIStoryboardSegue) {
|
||||
guard let sourceController = segue.source as? PGPKeyImporter, sourceController.isReadyToUse() else {
|
||||
return
|
||||
}
|
||||
|
|
@ -58,19 +59,20 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
}
|
||||
}
|
||||
|
||||
@IBAction func saveGitServerSetting(segue: UIStoryboardSegue) {
|
||||
self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults.gitURL.host
|
||||
@IBAction
|
||||
func saveGitServerSetting(segue _: UIStoryboardSegue) {
|
||||
passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults.gitURL.host
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(SettingsTableViewController.actOnPasswordStoreErasedNotification), name: .passwordStoreErased, object: nil)
|
||||
self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults.gitURL.host
|
||||
passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults.gitURL.host
|
||||
setPGPKeyTableViewCellDetailText()
|
||||
setPasscodeLockCell()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
override func viewWillAppear(_: Bool) {
|
||||
super.viewWillAppear(true)
|
||||
tabBarController!.delegate = self
|
||||
setPasswordRepositoryTableViewCellDetailText()
|
||||
|
|
@ -78,9 +80,9 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
|
||||
private func setPasscodeLockCell() {
|
||||
if passcodeLock.hasPasscode {
|
||||
self.passcodeTableViewCell.detailTextLabel?.text = "On".localize()
|
||||
passcodeTableViewCell.detailTextLabel?.text = "On".localize()
|
||||
} else {
|
||||
self.passcodeTableViewCell.detailTextLabel?.text = "Off".localize()
|
||||
passcodeTableViewCell.detailTextLabel?.text = "Off".localize()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +109,8 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
passwordRepositoryTableViewCell.detailTextLabel?.text = host
|
||||
}
|
||||
|
||||
@objc func actOnPasswordStoreErasedNotification() {
|
||||
@objc
|
||||
func actOnPasswordStoreErasedNotification() {
|
||||
setPGPKeyTableViewCellDetailText()
|
||||
setPasswordRepositoryTableViewCellDetailText()
|
||||
setPasscodeLockCell()
|
||||
|
|
@ -180,9 +183,8 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||
let passcodeRemoveViewController = PasscodeLockViewController()
|
||||
|
||||
|
||||
let removePasscodeAction = UIAlertAction(title: "RemovePasscode".localize(), style: .destructive) { [weak self] _ in
|
||||
passcodeRemoveViewController.successCallback = {
|
||||
passcodeRemoveViewController.successCallback = {
|
||||
self?.passcodeLock.delete()
|
||||
self?.setPasscodeLockCell()
|
||||
}
|
||||
|
|
@ -198,10 +200,11 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
optionMenu.addAction(UIAlertAction.cancel())
|
||||
optionMenu.popoverPresentationController?.sourceView = passcodeTableViewCell
|
||||
optionMenu.popoverPresentationController?.sourceRect = passcodeTableViewCell.bounds
|
||||
self.present(optionMenu, animated: true, completion: nil)
|
||||
present(optionMenu, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@objc func alertTextFieldDidChange(_ sender: UITextField) {
|
||||
@objc
|
||||
func alertTextFieldDidChange(_ sender: UITextField) {
|
||||
// check whether we should enable the Save button in setPasscodeLockAlert
|
||||
if let setPasscodeLockAlert = self.setPasscodeLockAlert,
|
||||
let setPasscodeLockAlertTextFields0 = setPasscodeLockAlert.textFields?[0],
|
||||
|
|
@ -218,25 +221,25 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
func setPasscodeLock() {
|
||||
// prepare the alert for setting the passcode
|
||||
setPasscodeLockAlert = UIAlertController(title: "SetPasscode".localize(), message: "FillInAppPasscode.".localize(), preferredStyle: .alert)
|
||||
setPasscodeLockAlert?.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in
|
||||
setPasscodeLockAlert?.addTextField(configurationHandler: { (_ textField: UITextField) -> Void in
|
||||
textField.placeholder = "Passcode".localize()
|
||||
textField.isSecureTextEntry = true
|
||||
textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged)
|
||||
})
|
||||
setPasscodeLockAlert?.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in
|
||||
setPasscodeLockAlert?.addTextField(configurationHandler: { (_ textField: UITextField) -> Void in
|
||||
textField.placeholder = "PasswordConfirmation".localize()
|
||||
textField.isSecureTextEntry = true
|
||||
textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged)
|
||||
})
|
||||
|
||||
// save action
|
||||
let saveAction = UIAlertAction(title: "Save".localize(), style: .default) { (action:UIAlertAction) -> Void in
|
||||
let saveAction = UIAlertAction(title: "Save".localize(), style: .default) { (_: UIAlertAction) -> Void in
|
||||
let passcode: String = self.setPasscodeLockAlert!.textFields![0].text!
|
||||
self.passcodeLock.save(passcode: passcode)
|
||||
// refresh the passcode lock cell ("On")
|
||||
self.setPasscodeLockCell()
|
||||
}
|
||||
saveAction.isEnabled = false // disable the Save button by default
|
||||
saveAction.isEnabled = false // disable the Save button by default
|
||||
|
||||
// cancel action
|
||||
let cancelAction = UIAlertAction.cancel()
|
||||
|
|
@ -244,17 +247,16 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
// present
|
||||
setPasscodeLockAlert?.addAction(saveAction)
|
||||
setPasscodeLockAlert?.addAction(cancelAction)
|
||||
self.present(setPasscodeLockAlert!, animated: true, completion: nil)
|
||||
present(setPasscodeLockAlert!, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
extension SettingsTableViewController: PGPKeyImporter {
|
||||
|
||||
static let keySource = KeySource.itunes
|
||||
static let label = "ITunesFileSharing".localize()
|
||||
|
||||
func isReadyToUse() -> Bool {
|
||||
return KeyFileManager.PublicPgp.doesKeyFileExist() && KeyFileManager.PrivatePgp.doesKeyFileExist()
|
||||
KeyFileManager.PublicPgp.doesKeyFileExist() && KeyFileManager.PrivatePgp.doesKeyFileExist()
|
||||
}
|
||||
|
||||
func importKeys() throws {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class SpecialThanksTableViewController: BasicStaticTableViewController {
|
|||
"https://icons8.com"],
|
||||
["FlatIcon",
|
||||
"https://www.flaticon.com"],
|
||||
]
|
||||
]
|
||||
|
||||
override func viewDidLoad() {
|
||||
tableData.append([])
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import SVProgressHUD
|
||||
import passKit
|
||||
import SVProgressHUD
|
||||
|
||||
public func requestGitCredentialPassword(credential: GitCredential.Credential,
|
||||
lastPassword: String?,
|
||||
controller: UIViewController) -> String? {
|
||||
lastPassword: String?,
|
||||
controller: UIViewController) -> String? {
|
||||
let sem = DispatchSemaphore(value: 0)
|
||||
var password: String?
|
||||
let message: String = {
|
||||
|
|
@ -27,21 +27,21 @@ public func requestGitCredentialPassword(credential: GitCredential.Credential,
|
|||
DispatchQueue.main.async {
|
||||
SVProgressHUD.dismiss()
|
||||
let alert = UIAlertController(title: "Password".localize(), message: message, preferredStyle: .alert)
|
||||
alert.addTextField() {
|
||||
alert.addTextField {
|
||||
$0.text = lastPassword ?? ""
|
||||
$0.isSecureTextEntry = true
|
||||
}
|
||||
alert.addAction(UIAlertAction.ok() { _ in
|
||||
alert.addAction(UIAlertAction.ok { _ in
|
||||
password = alert.textFields?.first?.text
|
||||
sem.signal()
|
||||
})
|
||||
alert.addAction(UIAlertAction.cancel() { _ in
|
||||
alert.addAction(UIAlertAction.cancel { _ in
|
||||
password = nil
|
||||
sem.signal()
|
||||
})
|
||||
controller.present(alert, animated: true)
|
||||
}
|
||||
|
||||
let _ = sem.wait(timeout: .distantFuture)
|
||||
_ = sem.wait(timeout: .distantFuture)
|
||||
return password
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class SecurePasteboard {
|
|||
// exit the existing background task, if any
|
||||
if backgroundTaskID != UIBackgroundTaskIdentifier.invalid {
|
||||
UIApplication.shared.endBackgroundTask(UIBackgroundTaskIdentifier.invalid)
|
||||
self.backgroundTaskID = UIBackgroundTaskIdentifier.invalid
|
||||
backgroundTaskID = UIBackgroundTaskIdentifier.invalid
|
||||
}
|
||||
|
||||
backgroundTaskID = UIApplication.shared.beginBackgroundTask(expirationHandler: { [weak self] in
|
||||
|
|
@ -40,5 +40,4 @@ class SecurePasteboard {
|
|||
self?.backgroundTaskID = UIBackgroundTaskIdentifier.invalid
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import SVProgressHUD
|
||||
import passKit
|
||||
import SVProgressHUD
|
||||
|
||||
extension Utils {
|
||||
static func alert(title: String, message: String, controller: UIViewController, handler: ((UIAlertAction) -> Void)? = nil, completion: (() -> Void)? = nil) {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import passKit
|
||||
import UIKit
|
||||
|
||||
protocol FillPasswordTableViewCellDelegate {
|
||||
func generateAndCopyPassword()
|
||||
|
|
@ -15,12 +15,11 @@ protocol FillPasswordTableViewCellDelegate {
|
|||
}
|
||||
|
||||
class FillPasswordTableViewCell: UITableViewCell, ContentProvider {
|
||||
|
||||
@IBOutlet weak var contentTextField: UITextField!
|
||||
@IBOutlet var contentTextField: UITextField!
|
||||
var delegate: FillPasswordTableViewCellDelegate?
|
||||
|
||||
@IBOutlet weak var settingButton: UIButton!
|
||||
@IBOutlet weak var generateButton: UIButton!
|
||||
@IBOutlet var settingButton: UIButton!
|
||||
@IBOutlet var generateButton: UIButton!
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
|
|
@ -32,21 +31,24 @@ class FillPasswordTableViewCell: UITableViewCell, ContentProvider {
|
|||
generateButton.imageView?.contentMode = .scaleAspectFit
|
||||
}
|
||||
|
||||
@IBAction func generatePassword(_ sender: UIButton) {
|
||||
self.delegate?.generateAndCopyPassword()
|
||||
@IBAction
|
||||
func generatePassword(_: UIButton) {
|
||||
delegate?.generateAndCopyPassword()
|
||||
}
|
||||
|
||||
@IBAction func showHidePasswordSettings() {
|
||||
self.delegate?.showHidePasswordSettings()
|
||||
@IBAction
|
||||
func showHidePasswordSettings() {
|
||||
delegate?.showHidePasswordSettings()
|
||||
}
|
||||
|
||||
// re-color
|
||||
@IBAction func textFieldDidChange(_ sender: UITextField) {
|
||||
@IBAction
|
||||
func textFieldDidChange(_ sender: UITextField) {
|
||||
contentTextField.attributedText = Utils.attributedPassword(plainPassword: sender.text ?? "")
|
||||
}
|
||||
|
||||
func getContent() -> String? {
|
||||
return contentTextField.attributedText?.string
|
||||
contentTextField.attributedText?.string
|
||||
}
|
||||
|
||||
func setContent(content: String?) {
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SVProgressHUD
|
||||
import passKit
|
||||
import SVProgressHUD
|
||||
import UIKit
|
||||
|
||||
struct LabelTableViewCellData {
|
||||
var title: String
|
||||
|
|
@ -16,9 +16,8 @@ struct LabelTableViewCellData {
|
|||
}
|
||||
|
||||
class LabelTableViewCell: UITableViewCell {
|
||||
|
||||
@IBOutlet weak var contentLabel: UILabel!
|
||||
@IBOutlet weak var titleLabel: UILabel!
|
||||
@IBOutlet var contentLabel: UILabel!
|
||||
@IBOutlet var titleLabel: UILabel!
|
||||
|
||||
private enum CellType {
|
||||
case password, URL, HOTP, other
|
||||
|
|
@ -27,7 +26,7 @@ class LabelTableViewCell: UITableViewCell {
|
|||
private var type = CellType.other
|
||||
private var isReveal = false
|
||||
|
||||
weak var delegatePasswordTableView : PasswordDetailTableViewController?
|
||||
weak var delegatePasswordTableView: PasswordDetailTableViewController?
|
||||
|
||||
private var passwordDisplayButton: UIButton?
|
||||
private var buttons: UIView?
|
||||
|
|
@ -74,12 +73,10 @@ class LabelTableViewCell: UITableViewCell {
|
|||
}
|
||||
|
||||
override var canBecomeFirstResponder: Bool {
|
||||
get {
|
||||
return true
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
|
||||
override func canPerformAction(_ action: Selector, withSender _: Any?) -> Bool {
|
||||
switch type {
|
||||
case .password:
|
||||
if isReveal {
|
||||
|
|
@ -100,11 +97,12 @@ class LabelTableViewCell: UITableViewCell {
|
|||
}
|
||||
}
|
||||
|
||||
override func copy(_ sender: Any?) {
|
||||
override func copy(_: Any?) {
|
||||
SecurePasteboard.shared.copy(textToCopy: cellData?.content)
|
||||
}
|
||||
|
||||
@objc func revealPassword(_ sender: Any?) {
|
||||
@objc
|
||||
func revealPassword(_: Any?) {
|
||||
let plainPassword = cellData?.content ?? ""
|
||||
if type == .password {
|
||||
contentLabel.attributedText = Utils.attributedPassword(plainPassword: plainPassword)
|
||||
|
|
@ -115,7 +113,8 @@ class LabelTableViewCell: UITableViewCell {
|
|||
passwordDisplayButton?.setImage(#imageLiteral(resourceName: "Invisible"), for: .normal)
|
||||
}
|
||||
|
||||
@objc func concealPassword(_ sender: Any?) {
|
||||
@objc
|
||||
func concealPassword(_: Any?) {
|
||||
if type == .password {
|
||||
if cellData?.content.isEmpty == false {
|
||||
contentLabel.text = Globals.passwordDots
|
||||
|
|
@ -130,7 +129,8 @@ class LabelTableViewCell: UITableViewCell {
|
|||
passwordDisplayButton?.setImage(#imageLiteral(resourceName: "Visible"), for: .normal)
|
||||
}
|
||||
|
||||
@objc func reversePasswordDisplay(_ sender: Any?) {
|
||||
@objc
|
||||
func reversePasswordDisplay(_ sender: Any?) {
|
||||
if isReveal {
|
||||
// conceal
|
||||
concealPassword(sender)
|
||||
|
|
@ -140,19 +140,21 @@ class LabelTableViewCell: UITableViewCell {
|
|||
}
|
||||
}
|
||||
|
||||
@objc func openLink(_ sender: Any?) {
|
||||
@objc
|
||||
func openLink(_: Any?) {
|
||||
// if isURLCell, passwordTableView should not be nil
|
||||
delegatePasswordTableView!.openLink(to: cellData?.content)
|
||||
}
|
||||
|
||||
@objc func getNextHOTP(_ sender: Any?) {
|
||||
@objc
|
||||
func getNextHOTP(_: Any?) {
|
||||
// if isHOTPCell, passwordTableView should not be nil
|
||||
delegatePasswordTableView!.getNextHOTP()
|
||||
}
|
||||
|
||||
private func updateButtons() {
|
||||
// total width and height of a button
|
||||
let height = min(self.bounds.height, 36.0)
|
||||
let height = min(bounds.height, 36.0)
|
||||
let width = max(height * 0.8, Globals.tableCellButtonSize)
|
||||
|
||||
// margins (between button boundary and icon)
|
||||
|
|
@ -167,7 +169,7 @@ class LabelTableViewCell: UITableViewCell {
|
|||
passwordDisplayButton!.frame = CGRect(x: 0, y: 0, width: width, height: height)
|
||||
passwordDisplayButton!.setImage(#imageLiteral(resourceName: "Visible"), for: .normal)
|
||||
passwordDisplayButton!.imageView?.contentMode = .scaleAspectFit
|
||||
passwordDisplayButton!.contentEdgeInsets = UIEdgeInsets.init(top: marginY, left: marginX, bottom: marginY, right: marginX)
|
||||
passwordDisplayButton!.contentEdgeInsets = UIEdgeInsets(top: marginY, left: marginX, bottom: marginY, right: marginX)
|
||||
passwordDisplayButton!.addTarget(self, action: #selector(reversePasswordDisplay), for: UIControl.Event.touchUpInside)
|
||||
buttons = passwordDisplayButton
|
||||
}
|
||||
|
|
@ -177,7 +179,7 @@ class LabelTableViewCell: UITableViewCell {
|
|||
nextButton.frame = CGRect(x: 0, y: 0, width: width, height: height)
|
||||
nextButton.setImage(#imageLiteral(resourceName: "Refresh"), for: .normal)
|
||||
nextButton.imageView?.contentMode = .scaleAspectFit
|
||||
nextButton.contentEdgeInsets = UIEdgeInsets.init(top: marginY, left: marginX, bottom: marginY, right: marginX)
|
||||
nextButton.contentEdgeInsets = UIEdgeInsets(top: marginY, left: marginX, bottom: marginY, right: marginX)
|
||||
nextButton.addTarget(self, action: #selector(getNextHOTP), for: UIControl.Event.touchUpInside)
|
||||
|
||||
// password button
|
||||
|
|
@ -186,7 +188,7 @@ class LabelTableViewCell: UITableViewCell {
|
|||
|
||||
passwordDisplayButton!.setImage(#imageLiteral(resourceName: "Visible"), for: .normal)
|
||||
passwordDisplayButton!.imageView?.contentMode = .scaleAspectFit
|
||||
passwordDisplayButton!.contentEdgeInsets = UIEdgeInsets.init(top: marginY, left: marginX, bottom: marginY, right: marginX)
|
||||
passwordDisplayButton!.contentEdgeInsets = UIEdgeInsets(top: marginY, left: marginX, bottom: marginY, right: marginX)
|
||||
passwordDisplayButton!.addTarget(self, action: #selector(reversePasswordDisplay), for: UIControl.Event.touchUpInside)
|
||||
|
||||
buttons = UIView()
|
||||
|
|
@ -197,6 +199,6 @@ class LabelTableViewCell: UITableViewCell {
|
|||
passwordDisplayButton = nil
|
||||
buttons = nil
|
||||
}
|
||||
self.accessoryView = buttons
|
||||
accessoryView = buttons
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,13 +9,12 @@
|
|||
import UIKit
|
||||
|
||||
class PasswordDetailTitleTableViewCell: UITableViewCell {
|
||||
@IBOutlet weak var categoryLabel: UILabel!
|
||||
@IBOutlet weak var nameLabel: UILabel!
|
||||
@IBOutlet weak var passwordImageImageView: UIImageView!
|
||||
@IBOutlet var categoryLabel: UILabel!
|
||||
@IBOutlet var nameLabel: UILabel!
|
||||
@IBOutlet var passwordImageImageView: UIImageView!
|
||||
@IBOutlet var labelImageConstraint: NSLayoutConstraint!
|
||||
@IBOutlet var labelCellConstraint: NSLayoutConstraint!
|
||||
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
}
|
||||
|
|
@ -25,5 +24,4 @@ class PasswordDetailTitleTableViewCell: UITableViewCell {
|
|||
|
||||
// Configure the view for the selected state
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import passKit
|
|||
import UIKit
|
||||
|
||||
class SliderTableViewCell: UITableViewCell {
|
||||
|
||||
@IBOutlet var titleLabel: UILabel!
|
||||
@IBOutlet var valueLabel: UILabel!
|
||||
@IBOutlet var slider: UISlider!
|
||||
|
|
@ -20,7 +19,8 @@ class SliderTableViewCell: UITableViewCell {
|
|||
|
||||
private var delegate: PasswordSettingSliderTableViewCellDelegate!
|
||||
|
||||
@IBAction func handleSliderValueChange(_ sender: UISlider) {
|
||||
@IBAction
|
||||
func handleSliderValueChange(_ sender: UISlider) {
|
||||
let newRoundedValue = Int(sender.value)
|
||||
// Proceed only if the rounded value gets updated.
|
||||
guard checker(newRoundedValue) else {
|
||||
|
|
@ -67,9 +67,8 @@ class SliderTableViewCell: UITableViewCell {
|
|||
}
|
||||
|
||||
extension SliderTableViewCell: ContentProvider {
|
||||
|
||||
func getContent() -> String? {
|
||||
return nil
|
||||
nil
|
||||
}
|
||||
|
||||
func setContent(content _: String?) {}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import passKit
|
|||
import UIKit
|
||||
|
||||
class SwitchTableViewCell: UITableViewCell {
|
||||
|
||||
@IBOutlet var titleLabel: UILabel!
|
||||
@IBOutlet var controlSwitch: UISwitch!
|
||||
|
||||
|
|
@ -18,7 +17,8 @@ class SwitchTableViewCell: UITableViewCell {
|
|||
|
||||
private var delegate: PasswordSettingSliderTableViewCellDelegate!
|
||||
|
||||
@IBAction func switchValueChanged(_: Any) {
|
||||
@IBAction
|
||||
func switchValueChanged(_: Any) {
|
||||
updater(controlSwitch.isOn)
|
||||
delegate.generateAndCopyPassword()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,10 @@
|
|||
import UIKit
|
||||
|
||||
class TextFieldTableViewCell: UITableViewCell, ContentProvider {
|
||||
|
||||
@IBOutlet weak var contentTextField: UITextField!
|
||||
@IBOutlet var contentTextField: UITextField!
|
||||
|
||||
func getContent() -> String? {
|
||||
return contentTextField.text
|
||||
contentTextField.text
|
||||
}
|
||||
|
||||
func setContent(content: String?) {
|
||||
|
|
|
|||
|
|
@ -9,17 +9,16 @@
|
|||
import UIKit
|
||||
|
||||
class TextViewTableViewCell: UITableViewCell, ContentProvider {
|
||||
@IBOutlet var contentTextView: UITextView!
|
||||
|
||||
@IBOutlet weak var contentTextView: UITextView!
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
self.contentTextView.textContainer.lineFragmentPadding = 0
|
||||
self.contentTextView.textContainerInset = .zero
|
||||
contentTextView.textContainer.lineFragmentPadding = 0
|
||||
contentTextView.textContainerInset = .zero
|
||||
}
|
||||
|
||||
func getContent() -> String? {
|
||||
return contentTextView.text
|
||||
contentTextView.text
|
||||
}
|
||||
|
||||
func setContent(content: String?) {
|
||||
|
|
|
|||
|
|
@ -6,11 +6,10 @@
|
|||
Copyright © 2019 Bob Sun. All rights reserved.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
import passKit
|
||||
import UIKit
|
||||
|
||||
class UICodeHighlightingLabel: UILocalizedLabel {
|
||||
|
||||
private static let CODE_ATTRIBUTES: [NSAttributedString.Key: Any] = [.font: UIFont(name: "Menlo-Regular", size: 12)!]
|
||||
private static let ATTRIBUTED_NEWLINE = NSAttributedString(string: "\n")
|
||||
|
||||
|
|
@ -43,4 +42,3 @@ class UICodeHighlightingLabel: UILocalizedLabel {
|
|||
return formattedText
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,11 +6,10 @@
|
|||
Copyright © 2019 Bob Sun. All rights reserved.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
import passKit
|
||||
import UIKit
|
||||
|
||||
class UILocalizedLabel: UILabel {
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
text = text?.localize()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue