lint: delete trailing whitespaces
This commit is contained in:
parent
2ba6917710
commit
ed387069a4
59 changed files with 624 additions and 623 deletions
|
|
@ -10,7 +10,7 @@ import UIKit
|
|||
import passKit
|
||||
|
||||
class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
||||
|
||||
|
||||
private var needRefresh = false
|
||||
private var indicator: UIActivityIndicatorView = {
|
||||
let indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
|
||||
|
|
@ -23,13 +23,13 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
|||
|
||||
indicator.center = CGPoint(x: view.bounds.midX, y: view.bounds.height * 0.382)
|
||||
tableView.addSubview(indicator)
|
||||
|
||||
|
||||
setTableData()
|
||||
|
||||
|
||||
// all password store updates (including erase, discard) will trigger the refresh
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(setNeedRefresh), name: .passwordStoreUpdated, object: nil)
|
||||
}
|
||||
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
if needRefresh {
|
||||
|
|
@ -37,14 +37,14 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
|||
needRefresh = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func setTableData() {
|
||||
|
||||
|
||||
// clear current contents (if any)
|
||||
self.tableData.removeAll(keepingCapacity: true)
|
||||
self.tableView.reloadData()
|
||||
indicator.startAnimating()
|
||||
|
||||
|
||||
// reload the table
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
let passwords = self.numberOfPasswordsString()
|
||||
|
|
@ -52,7 +52,7 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
|||
let localCommits = self.numberOfLocalCommitsString()
|
||||
let lastSynced = self.lastSyncedTimeString()
|
||||
let commits = self.numberOfPasswordsString()
|
||||
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
|
|
@ -97,7 +97,7 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
|||
formatter.timeStyle = .short
|
||||
return formatter.string(from: date)
|
||||
}
|
||||
|
||||
|
||||
@objc func setNeedRefresh() {
|
||||
needRefresh = true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,21 +9,21 @@
|
|||
import UIKit
|
||||
|
||||
class AboutTableViewController: BasicStaticTableViewController {
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
tableData = [
|
||||
// section 0
|
||||
[[.title: "Website", .action: "link", .link: "https://github.com/mssun/pass-ios.git"],
|
||||
[.title: "Help", .action: "link", .link: "https://github.com/mssun/passforios/wiki"],
|
||||
[.title: "Contact Developer", .action: "link", .link: "mailto:developer@passforios.mssun.me?subject=Pass%20for%20iOS"],],
|
||||
|
||||
|
||||
// section 1,
|
||||
[[.title: "Open Source Components", .action: "segue", .link: "showOpenSourceComponentsSegue"],
|
||||
[.title: "Special Thanks", .action: "segue", .link: "showSpecialThanksSegue"],],
|
||||
]
|
||||
super.viewDidLoad()
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
|
||||
if section == tableData.count - 1 {
|
||||
let view = UIView()
|
||||
|
|
@ -38,7 +38,7 @@ class AboutTableViewController: BasicStaticTableViewController {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
if section == 1 {
|
||||
return "Acknowledgements".uppercased()
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class AddPasswordTableViewController: PasswordEditorTableViewController {
|
|||
tableData[0][0][PasswordEditorCellKey.content] = defaultDirPrefix
|
||||
super.viewDidLoad()
|
||||
}
|
||||
|
||||
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||
if identifier == "saveAddPasswordSegue" {
|
||||
// check PGP key
|
||||
|
|
@ -37,7 +37,7 @@ class AddPasswordTableViewController: PasswordEditorTableViewController {
|
|||
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
// check name
|
||||
guard checkName() == true else {
|
||||
return false
|
||||
|
|
@ -45,7 +45,7 @@ class AddPasswordTableViewController: PasswordEditorTableViewController {
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
super.prepare(for: segue, sender: sender)
|
||||
if segue.identifier == "saveAddPasswordSegue" {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class AdvancedSettingsTableViewController: UITableViewController {
|
|||
@IBOutlet weak var eraseDataTableViewCell: UITableViewCell!
|
||||
@IBOutlet weak var discardChangesTableViewCell: UITableViewCell!
|
||||
let passwordStore = PasswordStore.shared
|
||||
|
||||
|
||||
let encryptInASCIIArmoredSwitch: UISwitch = {
|
||||
let uiSwitch = UISwitch()
|
||||
uiSwitch.onTintColor = Globals.blue
|
||||
|
|
@ -33,7 +33,7 @@ class AdvancedSettingsTableViewController: UITableViewController {
|
|||
encryptInASCIIArmoredTableViewCell.selectionStyle = .none
|
||||
setGitSignatureText()
|
||||
}
|
||||
|
||||
|
||||
private func setGitSignatureText() {
|
||||
let gitSignatureName = passwordStore.gitSignatureForNow.name!
|
||||
let gitSignatureEmail = passwordStore.gitSignatureForNow.email!
|
||||
|
|
@ -77,17 +77,17 @@ class AdvancedSettingsTableViewController: UITableViewController {
|
|||
} catch {
|
||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
}))
|
||||
alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.cancel, handler:nil))
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func encryptInASCIIArmoredAction(_ sender: Any?) {
|
||||
SharedDefaults[.encryptInArmored] = encryptInASCIIArmoredSwitch.isOn
|
||||
}
|
||||
|
||||
|
||||
@IBAction func saveGitConfigSetting(segue: UIStoryboardSegue) {
|
||||
if let controller = segue.source as? GitConfigSettingTableViewController {
|
||||
if let gitSignatureName = controller.nameTextField.text,
|
||||
|
|
|
|||
|
|
@ -27,18 +27,18 @@ enum CellDataKey {
|
|||
class BasicStaticTableViewController: UITableViewController, MFMailComposeViewControllerDelegate {
|
||||
var tableData = [[Dictionary<CellDataKey, Any>]]()
|
||||
var navigationItemTitle: String?
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
if navigationItemTitle != nil {
|
||||
navigationItem.title = navigationItemTitle
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return tableData.count
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return tableData[section].count
|
||||
}
|
||||
|
|
@ -47,13 +47,13 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
|
|||
super.didReceiveMemoryWarning()
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
||||
|
||||
let cellData = tableData[indexPath.section][indexPath.row]
|
||||
let cellDataStyle = cellData[CellDataKey.style] as? CellDataStyle
|
||||
var cell: UITableViewCell?
|
||||
|
||||
|
||||
switch cellDataStyle ?? .defaultStyle {
|
||||
case .value1:
|
||||
cell = UITableViewCell(style: .value1, reuseIdentifier: "value1 cell")
|
||||
|
|
@ -61,7 +61,7 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
|
|||
default:
|
||||
cell = UITableViewCell(style: .default, reuseIdentifier: "default cell")
|
||||
}
|
||||
|
||||
|
||||
if let detailText = cellData[CellDataKey.detailText] as? String {
|
||||
cell?.detailTextLabel?.text = detailText
|
||||
}
|
||||
|
|
@ -71,17 +71,17 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
|
|||
cell?.accessoryType = .disclosureIndicator
|
||||
cell?.selectionStyle = .default
|
||||
}
|
||||
|
||||
|
||||
cell?.textLabel?.text = cellData[CellDataKey.title] as? String
|
||||
return cell ?? UITableViewCell()
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ 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])
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
let cellData = tableData[indexPath.section][indexPath.row]
|
||||
|
|
@ -116,7 +116,7 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
|
|||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func sendEmail(toRecipients recipients: [String], subject: String) {
|
||||
let mailVC = MFMailComposeViewController()
|
||||
mailVC.mailComposeDelegate = self
|
||||
|
|
@ -125,7 +125,7 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
|
|||
mailVC.setMessageBody("", isHTML: false)
|
||||
self.present(mailVC, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
|
||||
controller.dismiss(animated: true)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import passKit
|
|||
class CommitLogsTableViewController: UITableViewController {
|
||||
var commits: [GTCommit] = []
|
||||
let passwordStore = PasswordStore.shared
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(updateCommitLogs), name: .passwordStoreUpdated, object: nil)
|
||||
|
|
@ -25,14 +25,14 @@ class CommitLogsTableViewController: UITableViewController {
|
|||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return commits.count
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "commitLogCell", for: indexPath)
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = DateFormatter.Style.medium
|
||||
formatter.timeStyle = .medium
|
||||
let dateString = formatter.string(from: commits[indexPath.row].commitDate)
|
||||
|
||||
|
||||
let author = cell.contentView.viewWithTag(200) as? UILabel
|
||||
let dateLabel = cell.contentView.viewWithTag(201) as? UILabel
|
||||
let messageLabel = cell.contentView.viewWithTag(202) as? UILabel
|
||||
|
|
@ -41,12 +41,12 @@ class CommitLogsTableViewController: UITableViewController {
|
|||
messageLabel?.text = commits[indexPath.row].message?.trimmed
|
||||
return cell
|
||||
}
|
||||
|
||||
|
||||
@objc func updateCommitLogs() {
|
||||
commits = getCommitLogs()
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
|
||||
private func getCommitLogs() -> [GTCommit] {
|
||||
do {
|
||||
return try passwordStore.getRecentCommits(count: 20)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class EditPasswordTableViewController: PasswordEditorTableViewController {
|
|||
tableData[1].append([.type: PasswordEditorCellType.memorablePasswordGeneratorCell])
|
||||
super.viewDidLoad()
|
||||
}
|
||||
|
||||
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||
if identifier == "saveEditPasswordSegue" {
|
||||
// check name
|
||||
|
|
@ -34,7 +34,7 @@ class EditPasswordTableViewController: PasswordEditorTableViewController {
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
super.prepare(for: segue, sender: sender)
|
||||
if segue.identifier == "saveEditPasswordSegue" {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
uiSwitch.addTarget(self, action: #selector(hideUnknownSwitchAction(_:)), for: UIControlEvents.valueChanged)
|
||||
return uiSwitch
|
||||
}()
|
||||
|
||||
|
||||
let hideOTPSwitch: UISwitch = {
|
||||
let uiSwitch = UISwitch()
|
||||
uiSwitch.onTintColor = Globals.blue
|
||||
|
|
@ -27,7 +27,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
uiSwitch.addTarget(self, action: #selector(hideOTPSwitchAction(_:)), for: UIControlEvents.valueChanged)
|
||||
return uiSwitch
|
||||
}()
|
||||
|
||||
|
||||
let rememberPGPPassphraseSwitch: UISwitch = {
|
||||
let uiSwitch = UISwitch()
|
||||
uiSwitch.onTintColor = Globals.blue
|
||||
|
|
@ -36,7 +36,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
uiSwitch.isOn = SharedDefaults[.isRememberPGPPassphraseOn]
|
||||
return uiSwitch
|
||||
}()
|
||||
|
||||
|
||||
let rememberGitCredentialPassphraseSwitch: UISwitch = {
|
||||
let uiSwitch = UISwitch()
|
||||
uiSwitch.onTintColor = Globals.blue
|
||||
|
|
@ -45,7 +45,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
uiSwitch.isOn = SharedDefaults[.isRememberGitCredentialPassphraseOn]
|
||||
return uiSwitch
|
||||
}()
|
||||
|
||||
|
||||
let showFolderSwitch: UISwitch = {
|
||||
let uiSwitch = UISwitch()
|
||||
uiSwitch.onTintColor = Globals.blue
|
||||
|
|
@ -59,12 +59,12 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
tableData = [
|
||||
// section 0
|
||||
[[.title: "About Repository", .action: "segue", .link: "showAboutRepositorySegue"],],
|
||||
|
||||
|
||||
// section 1
|
||||
[
|
||||
[.title: "Password Generator Flavor", .action: "none", .style: CellDataStyle.value1],
|
||||
],
|
||||
|
||||
|
||||
// section 2
|
||||
[
|
||||
[.title: "Remember PGP Key Passphrase", .action: "none",],
|
||||
|
|
@ -78,9 +78,9 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
|
||||
]
|
||||
super.viewDidLoad()
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = super.tableView(tableView, cellForRowAt: indexPath)
|
||||
switch cell.textLabel!.text! {
|
||||
|
|
@ -127,7 +127,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
}
|
||||
return cell
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
super.tableView(tableView, didSelectRowAt: indexPath)
|
||||
let cell = tableView.cellForRow(at: indexPath)!
|
||||
|
|
@ -136,7 +136,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
showPasswordGeneratorFlavorActionSheet(sourceCell: cell)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func showPasswordGeneratorFlavorActionSheet(sourceCell: UITableViewCell) {
|
||||
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||
var randomFlavorActionTitle = ""
|
||||
|
|
@ -152,12 +152,12 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
SharedDefaults[.passwordGeneratorFlavor] = "Random"
|
||||
sourceCell.detailTextLabel?.text = "Random"
|
||||
}
|
||||
|
||||
|
||||
let appleFlavorAction = UIAlertAction(title: appleFlavorActionTitle, style: .default) { _ in
|
||||
SharedDefaults[.passwordGeneratorFlavor] = "Apple"
|
||||
sourceCell.detailTextLabel?.text = "Apple"
|
||||
}
|
||||
|
||||
|
||||
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
|
||||
optionMenu.addAction(randomFlavorAction)
|
||||
optionMenu.addAction(appleFlavorAction)
|
||||
|
|
@ -166,37 +166,37 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
optionMenu.popoverPresentationController?.sourceRect = sourceCell.bounds
|
||||
self.present(optionMenu, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
@objc func tapHideUnknownSwitchDetailButton(_ sender: Any?) {
|
||||
let alertMessage = "Only \"key: value\" format in additional fields is supported. Unsupported fields will be given \"unknown\" keys. Turn on this switch to hide unsupported fields."
|
||||
let alertTitle = "Hide Unknown Fields"
|
||||
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
@objc func tapHideOTPSwitchDetailButton(_ sender: Any?) {
|
||||
let keywordsString = Constants.OTP_KEYWORDS.joined(separator: ",")
|
||||
let alertMessage = "Turn on this switch to hide the fields related to one time passwords (i.e., \(keywordsString))."
|
||||
let alertTitle = "Hide One Time Password Fields"
|
||||
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
@objc func hideUnknownSwitchAction(_ sender: Any?) {
|
||||
SharedDefaults[.isHideUnknownOn] = hideUnknownSwitch.isOn
|
||||
NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil)
|
||||
}
|
||||
|
||||
|
||||
@objc func hideOTPSwitchAction(_ sender: Any?) {
|
||||
SharedDefaults[.isHideOTPOn] = hideOTPSwitch.isOn
|
||||
NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil)
|
||||
}
|
||||
|
||||
|
||||
@objc func rememberPGPPassphraseSwitchAction(_ sender: Any?) {
|
||||
SharedDefaults[.isRememberPGPPassphraseOn] = rememberPGPPassphraseSwitch.isOn
|
||||
if rememberPGPPassphraseSwitch.isOn == false {
|
||||
passwordStore.pgpKeyPassphrase = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func rememberGitCredentialPassphraseSwitchAction(_ sender: Any?) {
|
||||
SharedDefaults[.isRememberGitCredentialPassphraseOn] = rememberGitCredentialPassphraseSwitch.isOn
|
||||
if rememberGitCredentialPassphraseSwitch.isOn == false {
|
||||
|
|
@ -204,10 +204,10 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
passwordStore.gitPassword = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func showFolderSwitchAction(_ sender: Any?) {
|
||||
SharedDefaults[.isShowFolderOn] = showFolderSwitch.isOn
|
||||
NotificationCenter.default.post(name: .passwordDisplaySettingChanged, object: nil)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,21 +12,21 @@ import passKit
|
|||
|
||||
class GitConfigSettingTableViewController: UITableViewController {
|
||||
let passwordStore = PasswordStore.shared
|
||||
|
||||
|
||||
@IBOutlet weak var nameTextField: UITextField!
|
||||
@IBOutlet weak var emailTextField: UITextField!
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
tableView.rowHeight = UITableViewAutomaticDimension
|
||||
|
||||
|
||||
let signature = passwordStore.gitSignatureForNow
|
||||
nameTextField.placeholder = signature.name
|
||||
emailTextField.placeholder = signature.email
|
||||
nameTextField.text = SharedDefaults[.gitSignatureName]
|
||||
emailTextField.text = SharedDefaults[.gitSignatureEmail]
|
||||
}
|
||||
|
||||
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||
if identifier == "saveGitConfigSettingSegue" {
|
||||
let name = nameTextField.text!.isEmpty ? Globals.gitSignatureDefaultName : nameTextField.text!
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ import passKit
|
|||
class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextViewDelegate, QRScannerControllerDelegate {
|
||||
@IBOutlet weak var armorPrivateKeyTextView: UITextView!
|
||||
@IBOutlet weak var scanPrivateKeyCell: UITableViewCell!
|
||||
|
||||
|
||||
var gitSSHPrivateKeyPassphrase: String?
|
||||
let passwordStore = PasswordStore.shared
|
||||
|
||||
|
||||
class ScannedSSHKey {
|
||||
static let maxNumberOfGif = 100
|
||||
var numberOfSegments = 0
|
||||
|
|
@ -24,7 +24,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
|||
var message = ""
|
||||
var hasStarted = false
|
||||
var isDone = false
|
||||
|
||||
|
||||
func reset() {
|
||||
numberOfSegments = 0
|
||||
previousSegment = ""
|
||||
|
|
@ -33,14 +33,14 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
|||
hasStarted = false
|
||||
isDone = false
|
||||
}
|
||||
|
||||
|
||||
func addSegment(segment: String) {
|
||||
// skip duplicated segments
|
||||
guard segment != previousSegment else {
|
||||
return
|
||||
}
|
||||
previousSegment = segment
|
||||
|
||||
|
||||
// check whether we have found the first block
|
||||
if hasStarted == false {
|
||||
hasStarted = segment.contains("-----BEGIN")
|
||||
|
|
@ -48,38 +48,38 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
|||
guard hasStarted == true else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// check the number of segments
|
||||
numberOfSegments = numberOfSegments + 1
|
||||
guard numberOfSegments <= ScannedSSHKey.maxNumberOfGif else {
|
||||
key = "Too many QR codes"
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// update full text and check whether we are done
|
||||
key.append(segment)
|
||||
if let index1 = key.range(of: "-----END")?.lowerBound,
|
||||
let _ = key.suffix(from: index1).range(of: "KEY-----")?.lowerBound {
|
||||
isDone = true
|
||||
}
|
||||
|
||||
|
||||
// update message
|
||||
message = "\(numberOfSegments) scanned QR codes."
|
||||
}
|
||||
}
|
||||
var scanned = ScannedSSHKey()
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
armorPrivateKeyTextView.text = SharedDefaults[.gitSSHPrivateKeyArmor]
|
||||
armorPrivateKeyTextView.delegate = self
|
||||
|
||||
|
||||
scanPrivateKeyCell?.textLabel?.text = "Scan Private Key QR Codes"
|
||||
scanPrivateKeyCell?.textLabel?.textColor = Globals.blue
|
||||
scanPrivateKeyCell?.selectionStyle = .default
|
||||
scanPrivateKeyCell?.accessoryType = .disclosureIndicator
|
||||
}
|
||||
|
||||
|
||||
@IBAction func doneButtonTapped(_ sender: Any) {
|
||||
SharedDefaults[.gitSSHPrivateKeyArmor] = armorPrivateKeyTextView.text
|
||||
do {
|
||||
|
|
@ -90,7 +90,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
|||
SharedDefaults[.gitSSHKeySource] = "armor"
|
||||
self.navigationController!.popViewController(animated: true)
|
||||
}
|
||||
|
||||
|
||||
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
|
||||
if text == UIPasteboard.general.string {
|
||||
// user pastes something, do the copy here again and clear the pasteboard in 45s
|
||||
|
|
@ -98,7 +98,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let selectedCell = tableView.cellForRow(at: indexPath)
|
||||
if selectedCell == scanPrivateKeyCell {
|
||||
|
|
@ -107,8 +107,8 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
|||
}
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// MARK: - QRScannerControllerDelegate Methods
|
||||
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
|
||||
scanned.addSegment(segment: line)
|
||||
|
|
@ -118,12 +118,12 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
|||
return (accept: false, message: scanned.message)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - QRScannerControllerDelegate Methods
|
||||
func handleScannedOutput(line: String) {
|
||||
armorPrivateKeyTextView.text = scanned.key
|
||||
}
|
||||
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
if segue.identifier == "showSSHScannerSegue" {
|
||||
if let navController = segue.destination as? UINavigationController {
|
||||
|
|
@ -135,9 +135,9 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@IBAction private func cancelSSHScanner(segue: UIStoryboardSegue) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
sshKeyCheckView.isHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
// Grey out ssh option if ssh_key is not present
|
||||
|
|
@ -55,30 +55,30 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
checkAuthenticationMethod(method: authenticationMethod)
|
||||
authSSHKeyCell.accessoryType = .detailButton
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
|
||||
let cell = tableView.cellForRow(at: indexPath)
|
||||
if cell == authSSHKeyCell {
|
||||
showSSHKeyActionSheet()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
view.endEditing(true)
|
||||
}
|
||||
|
||||
|
||||
private func cloneAndSegueIfSuccess() {
|
||||
// try to clone
|
||||
let gitRepostiroyURL = gitURLTextField.text!.trimmed
|
||||
let username = usernameTextField.text!
|
||||
let auth = authenticationMethod
|
||||
|
||||
|
||||
SVProgressHUD.setDefaultMaskType(.black)
|
||||
SVProgressHUD.setDefaultStyle(.light)
|
||||
SVProgressHUD.show(withStatus: "Prepare Repository")
|
||||
|
|
@ -160,15 +160,15 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
checkAuthenticationMethod(method: authenticationMethod)
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
|
||||
|
||||
@IBAction func save(_ sender: Any) {
|
||||
|
||||
|
||||
// some sanity checks
|
||||
guard let gitURL = URL(string: gitURLTextField.text!) else {
|
||||
Utils.alert(title: "Cannot Save", message: "Please set the Git repository URL.", controller: self, completion: nil)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
switch gitURL.scheme {
|
||||
case let val where val == "https":
|
||||
break
|
||||
|
|
@ -188,7 +188,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
Utils.alert(title: "Cannot Save", message: "Please specify the scheme of the Git repository URL (https or ssh).", controller: self, completion: nil)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if passwordStore.repositoryExisted() {
|
||||
let alert = UIAlertController(title: "Overwrite?", message: "This operation will overwrite your current password store data (repository). Data on your remote server will not be affected.", preferredStyle: UIAlertControllerStyle.alert)
|
||||
alert.addAction(UIAlertAction(title: "Overwrite", style: UIAlertActionStyle.destructive, handler: { _ in
|
||||
|
|
@ -202,13 +202,13 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
cloneAndSegueIfSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func showSSHKeyActionSheet() {
|
||||
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||
var urlActionTitle = "Download from URL"
|
||||
var armorActionTitle = "ASCII-Armor Encrypted Key"
|
||||
var fileActionTitle = "iTunes File Sharing"
|
||||
|
||||
|
||||
if SharedDefaults[.gitSSHKeySource] == "url" {
|
||||
urlActionTitle = "✓ \(urlActionTitle)"
|
||||
} else if SharedDefaults[.gitSSHKeySource] == "armor" {
|
||||
|
|
@ -225,7 +225,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
|
||||
optionMenu.addAction(urlAction)
|
||||
optionMenu.addAction(armorAction)
|
||||
|
||||
|
||||
if passwordStore.gitSSHKeyExists(inFileSharing: true) {
|
||||
// might keys updated via iTunes, or downloaded/pasted inside the app
|
||||
fileActionTitle.append(" (Import)")
|
||||
|
|
@ -249,7 +249,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
}
|
||||
optionMenu.addAction(fileAction)
|
||||
}
|
||||
|
||||
|
||||
if SharedDefaults[.gitSSHKeySource] != nil {
|
||||
let deleteAction = UIAlertAction(title: "Remove Git SSH Keys", style: .destructive) { _ in
|
||||
self.passwordStore.removeGitSSHKeys()
|
||||
|
|
@ -266,7 +266,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
optionMenu.popoverPresentationController?.sourceRect = authSSHKeyCell.bounds
|
||||
self.present(optionMenu, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
private func requestGitPassword(credential: GitCredential.Credential, lastPassword: String?) -> String? {
|
||||
let sem = DispatchSemaphore(value: 0)
|
||||
var password: String?
|
||||
|
|
@ -277,7 +277,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
case .ssh:
|
||||
message = "Please fill in the passphrase of your SSH key."
|
||||
}
|
||||
|
||||
|
||||
DispatchQueue.main.async {
|
||||
SVProgressHUD.dismiss()
|
||||
let alert = UIAlertController(title: "Password", message: message, preferredStyle: UIAlertControllerStyle.alert)
|
||||
|
|
@ -295,7 +295,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
})
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
let _ = sem.wait(timeout: .distantFuture)
|
||||
return password
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class OpenSourceComponentsTableViewController: BasicStaticTableViewController {
|
|||
"https://github.com/SVProgressHUD/SVProgressHUD",
|
||||
"https://github.com/SVProgressHUD/SVProgressHUD/blob/master/LICENSE.txt"],
|
||||
]
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
tableData.append([])
|
||||
for item in openSourceComponents {
|
||||
|
|
@ -43,7 +43,7 @@ class OpenSourceComponentsTableViewController: BasicStaticTableViewController {
|
|||
}
|
||||
super.viewDidLoad()
|
||||
}
|
||||
|
||||
|
||||
@objc func actOnDetailDisclosureButton(_ sender: Any?) {
|
||||
if let link = sender as? String {
|
||||
let svc = SFSafariViewController(url: URL(string: link)!, entersReaderIfAvailable: false)
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
|||
@IBOutlet weak var armorPrivateKeyTextView: UITextView!
|
||||
@IBOutlet weak var scanPublicKeyCell: UITableViewCell!
|
||||
@IBOutlet weak var scanPrivateKeyCell: UITableViewCell!
|
||||
|
||||
|
||||
var pgpPassphrase: String?
|
||||
let passwordStore = PasswordStore.shared
|
||||
|
||||
|
||||
class ScannedPGPKey {
|
||||
static let maxNumberOfGif = 100
|
||||
enum KeyType {
|
||||
|
|
@ -30,7 +30,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
|||
var message = ""
|
||||
var hasStarted = false
|
||||
var isDone = false
|
||||
|
||||
|
||||
func reset(keytype: KeyType) {
|
||||
self.keyType = keytype
|
||||
numberOfSegments = 0
|
||||
|
|
@ -40,14 +40,14 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
|||
hasStarted = false
|
||||
isDone = false
|
||||
}
|
||||
|
||||
|
||||
func addSegment(segment: String) {
|
||||
// skip duplicated segments
|
||||
guard segment != previousSegment else {
|
||||
return
|
||||
}
|
||||
previousSegment = segment
|
||||
|
||||
|
||||
// check whether we have found the first block
|
||||
if hasStarted == false {
|
||||
let findPublic = segment.contains("-----BEGIN PGP PUBLIC KEY BLOCK-----")
|
||||
|
|
@ -68,32 +68,32 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
|||
guard hasStarted == true else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// check the number of segments
|
||||
numberOfSegments = numberOfSegments + 1
|
||||
guard numberOfSegments <= ScannedPGPKey.maxNumberOfGif else {
|
||||
key = "Too many QR codes"
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// update full text and check whether we are done
|
||||
key.append(segment)
|
||||
if key.contains("-----END PGP PUBLIC KEY BLOCK-----") || key.contains("-----END PGP PRIVATE KEY BLOCK-----") {
|
||||
isDone = true
|
||||
}
|
||||
|
||||
|
||||
// update message
|
||||
message = "\(numberOfSegments) scanned QR codes."
|
||||
}
|
||||
}
|
||||
var scanned = ScannedPGPKey()
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
armorPublicKeyTextView.text = SharedDefaults[.pgpPublicKeyArmor]
|
||||
armorPrivateKeyTextView.text = SharedDefaults[.pgpPrivateKeyArmor]
|
||||
pgpPassphrase = passwordStore.pgpKeyPassphrase
|
||||
|
||||
|
||||
scanPublicKeyCell?.textLabel?.text = "Scan Public Key QR Codes"
|
||||
scanPublicKeyCell?.textLabel?.textColor = Globals.blue
|
||||
scanPublicKeyCell?.selectionStyle = .default
|
||||
|
|
@ -104,7 +104,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
|||
scanPrivateKeyCell?.selectionStyle = .default
|
||||
scanPrivateKeyCell?.accessoryType = .disclosureIndicator
|
||||
}
|
||||
|
||||
|
||||
@IBAction func save(_ sender: Any) {
|
||||
guard armorPublicKeyTextView.text.isEmpty == false else {
|
||||
Utils.alert(title: "Cannot Save", message: "Please set public key first.", controller: self, completion: nil)
|
||||
|
|
@ -138,7 +138,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
|||
})
|
||||
self.present(savePassphraseAlert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
|
||||
if text == UIPasteboard.general.string {
|
||||
// user pastes something, do the copy here again and clear the pasteboard in 45s
|
||||
|
|
@ -146,7 +146,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let selectedCell = tableView.cellForRow(at: indexPath)
|
||||
if selectedCell == scanPublicKeyCell {
|
||||
|
|
@ -158,7 +158,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
|||
}
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - QRScannerControllerDelegate Methods
|
||||
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
|
||||
scanned.addSegment(segment: line)
|
||||
|
|
@ -168,7 +168,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
|||
return (accept: false, message: scanned.message)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - QRScannerControllerDelegate Methods
|
||||
func handleScannedOutput(line: String) {
|
||||
switch scanned.keyType {
|
||||
|
|
@ -178,7 +178,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
|||
armorPrivateKeyTextView.text = scanned.key
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
if segue.identifier == "showPGPScannerSegue" {
|
||||
if let navController = segue.destination as? UINavigationController {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class PGPKeySettingTableViewController: UITableViewController {
|
|||
@IBOutlet weak var pgpPrivateKeyURLTextField: UITextField!
|
||||
var pgpPassphrase: String?
|
||||
let passwordStore = PasswordStore.shared
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
tableView.rowHeight = UITableViewAutomaticDimension
|
||||
|
|
@ -23,7 +23,7 @@ class PGPKeySettingTableViewController: UITableViewController {
|
|||
pgpPrivateKeyURLTextField.text = SharedDefaults[.pgpPrivateKeyURL]?.absoluteString
|
||||
pgpPassphrase = passwordStore.pgpKeyPassphrase
|
||||
}
|
||||
|
||||
|
||||
private func validatePGPKeyURL(input: String?) -> Bool {
|
||||
guard let path = input, let url = URL(string: path) else {
|
||||
Utils.alert(title: "Cannot Save PGP Key", message: "Please set PGP Key URL first.", controller: self, completion: nil)
|
||||
|
|
@ -35,7 +35,7 @@ class PGPKeySettingTableViewController: UITableViewController {
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@IBAction func save(_ sender: Any) {
|
||||
guard validatePGPKeyURL(input: pgpPublicKeyURLTextField.text) == true,
|
||||
validatePGPKeyURL(input: pgpPrivateKeyURLTextField.text) == true else {
|
||||
|
|
@ -65,6 +65,6 @@ class PGPKeySettingTableViewController: UITableViewController {
|
|||
})
|
||||
self.present(savePassphraseAlert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
private var oneTimePasswordIndexPath : IndexPath?
|
||||
private var shouldPopCurrentView = false
|
||||
private let passwordStore = PasswordStore.shared
|
||||
|
||||
|
||||
private lazy var editUIBarButtonItem: UIBarButtonItem = {
|
||||
let uiBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(pressEdit(_:)))
|
||||
return uiBarButtonItem
|
||||
|
|
@ -31,18 +31,18 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
title = ""
|
||||
content = ""
|
||||
}
|
||||
|
||||
|
||||
init(title: String) {
|
||||
self.title = title
|
||||
self.content = ""
|
||||
}
|
||||
|
||||
|
||||
init(title: String, content: String) {
|
||||
self.title = title
|
||||
self.content = content
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private struct TableSection {
|
||||
var type: PasswordDetailTableViewControllerSectionType
|
||||
var header: String?
|
||||
|
|
@ -52,56 +52,56 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
header = nil
|
||||
item = [TableCell]()
|
||||
}
|
||||
|
||||
|
||||
init(type: PasswordDetailTableViewControllerSectionType, header: String) {
|
||||
self.init(type: type)
|
||||
self.header = header
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private var tableData = Array<TableSection>()
|
||||
|
||||
|
||||
private enum PasswordDetailTableViewControllerSectionType {
|
||||
case name, main, addition, misc
|
||||
}
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
tableView.register(UINib(nibName: "LabelTableViewCell", bundle: nil), forCellReuseIdentifier: "labelCell")
|
||||
tableView.register(UINib(nibName: "PasswordDetailTitleTableViewCell", bundle: nil), forCellReuseIdentifier: "passwordDetailTitleTableViewCell")
|
||||
|
||||
|
||||
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(PasswordDetailTableViewController.tapMenu(recognizer:)))
|
||||
tapGesture.cancelsTouchesInView = false
|
||||
tableView.addGestureRecognizer(tapGesture)
|
||||
tapGesture.delegate = self
|
||||
|
||||
|
||||
tableView.contentInset = UIEdgeInsetsMake(-36, 0, 44, 0);
|
||||
tableView.rowHeight = UITableViewAutomaticDimension
|
||||
tableView.estimatedRowHeight = 52
|
||||
|
||||
|
||||
editUIBarButtonItem.isEnabled = false
|
||||
navigationItem.rightBarButtonItem = editUIBarButtonItem
|
||||
if #available(iOS 11.0, *) {
|
||||
navigationItem.largeTitleDisplayMode = .never
|
||||
}
|
||||
|
||||
|
||||
if let imageData = passwordEntity?.getImage() {
|
||||
let image = UIImage(data: imageData as Data)
|
||||
passwordImage = image
|
||||
}
|
||||
self.decryptThenShowPassword()
|
||||
self.setupOneTimePasswordAutoRefresh()
|
||||
|
||||
|
||||
// pop the current view because this password might be "discarded"
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(setShouldPopCurrentView), name: .passwordStoreChangeDiscarded, object: nil)
|
||||
|
||||
|
||||
// reset the data table if some password (maybe another one) has been updated
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(decryptThenShowPassword), name: .passwordStoreUpdated, object: nil)
|
||||
|
||||
|
||||
// reset the data table if the disaply settings have been changed
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(decryptThenShowPassword), name: .passwordDetailDisplaySettingChanged, object: nil)
|
||||
}
|
||||
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
if self.shouldPopCurrentView {
|
||||
|
|
@ -112,7 +112,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func requestPGPKeyPassphrase() -> String {
|
||||
let sem = DispatchSemaphore(value: 0)
|
||||
var passphrase = ""
|
||||
|
|
@ -134,7 +134,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
}
|
||||
return passphrase
|
||||
}
|
||||
|
||||
|
||||
@objc private func decryptThenShowPassword() {
|
||||
guard let passwordEntity = passwordEntity else {
|
||||
Utils.alert(title: "Cannot Show Password", message: "The password does not exist.", controller: self, handler: {(UIAlertAction) -> Void in
|
||||
|
|
@ -166,7 +166,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
self.showPassword()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func showPassword() {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.setTableData()
|
||||
|
|
@ -179,7 +179,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func setupOneTimePasswordAutoRefresh() {
|
||||
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) {
|
||||
[weak self] timer in
|
||||
|
|
@ -204,19 +204,19 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc private func pressEdit(_ sender: Any?) {
|
||||
performSegue(withIdentifier: "editPasswordSegue", sender: self)
|
||||
}
|
||||
|
||||
|
||||
@objc private func setShouldPopCurrentView() {
|
||||
self.shouldPopCurrentView = true
|
||||
}
|
||||
|
||||
|
||||
@IBAction private func cancelEditPassword(segue: UIStoryboardSegue) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@IBAction private func saveEditPassword(segue: UIStoryboardSegue) {
|
||||
if self.password!.changed != 0 {
|
||||
SVProgressHUD.show(withStatus: "Saving")
|
||||
|
|
@ -231,7 +231,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
SVProgressHUD.dismiss(withDelay: 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@IBAction private func deletePassword(segue: UIStoryboardSegue) {
|
||||
do {
|
||||
try passwordStore.delete(passwordEntity: passwordEntity!)
|
||||
|
|
@ -243,7 +243,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
|
||||
private func setTableData() {
|
||||
self.tableData = Array<TableSection>()
|
||||
|
||||
|
||||
// name section
|
||||
var section = TableSection(type: .name)
|
||||
section.item.append(TableCell())
|
||||
|
|
@ -261,9 +261,9 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
section.item.append(TableCell(title: "password", content: password.password))
|
||||
tableData.append(section)
|
||||
|
||||
|
||||
|
||||
// addition section
|
||||
|
||||
|
||||
// show one time password
|
||||
if password.otpType != .none {
|
||||
if let (title, otp) = self.password?.getOtpStrings() {
|
||||
|
|
@ -273,7 +273,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
oneTimePasswordIndexPath = IndexPath(row: 0, section: tableData.count - 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// show additional information
|
||||
let filteredAdditionKeys = password.getFilteredAdditions()
|
||||
if filteredAdditionKeys.count > 0 {
|
||||
|
|
@ -283,14 +283,14 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
})
|
||||
tableData.append(section)
|
||||
}
|
||||
|
||||
|
||||
// misc section
|
||||
section = TableSection(type: .misc)
|
||||
section.item.append(TableCell(title: "Show Raw"))
|
||||
tableData.append(section)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
if segue.identifier == "editPasswordSegue" {
|
||||
if let controller = segue.destination as? UINavigationController {
|
||||
|
|
@ -306,7 +306,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func updatePasswordImage(urlString: String) {
|
||||
var newUrlString = urlString
|
||||
if urlString.lowercased().hasPrefix("http://") {
|
||||
|
|
@ -321,7 +321,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
// if a url does not start with http or https, try to add https
|
||||
newUrlString = "https://\(urlString)"
|
||||
}
|
||||
|
||||
|
||||
try? FavIcon.downloadPreferred(newUrlString) { [weak self] result in
|
||||
if case let .success(image) = result {
|
||||
let indexPath = IndexPath(row: 0, section: 0)
|
||||
|
|
@ -334,7 +334,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc private func tapMenu(recognizer: UITapGestureRecognizer) {
|
||||
if recognizer.state == UIGestureRecognizerState.ended {
|
||||
let tapLocation = recognizer.location(in: self.tableView)
|
||||
|
|
@ -353,17 +353,17 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
|
||||
if touch.view!.isKind(of: UIButton.classForCoder()) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@IBAction func back(segue:UIStoryboardSegue) {
|
||||
}
|
||||
|
||||
|
||||
func getNextHOTP() {
|
||||
guard password != nil, passwordEntity != nil, password?.otpType == .hotp else {
|
||||
DispatchQueue.main.async {
|
||||
|
|
@ -371,12 +371,12 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// copy HOTP to pasteboard (will update counter)
|
||||
if let plainPassword = password!.getNextHotp() {
|
||||
SecurePasteboard.shared.copy(textToCopy: plainPassword)
|
||||
}
|
||||
|
||||
|
||||
// commit the change of HOTP counter
|
||||
if password!.changed != 0 {
|
||||
do {
|
||||
|
|
@ -465,11 +465,11 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
detailTextLabel.textColor = .gray
|
||||
detailTextLabel.text = "\(numberOfHiddenFields) hidden field\(numberOfHiddenFields > 1 ? "s" : "")"
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
return tableData[section].header
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
|
||||
if section == tableData.count - 1 {
|
||||
let view = UIView()
|
||||
|
|
@ -484,13 +484,13 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, performAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: 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 {
|
||||
let section = tableData[indexPath.section]
|
||||
switch(section.type) {
|
||||
|
|
@ -500,11 +500,11 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, shouldShowMenuForRowAt indexPath: IndexPath) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let section = tableData[indexPath.section]
|
||||
if section.type == .misc {
|
||||
|
|
|
|||
|
|
@ -20,21 +20,21 @@ enum PasswordEditorCellKey {
|
|||
}
|
||||
|
||||
class PasswordEditorTableViewController: UITableViewController, FillPasswordTableViewCellDelegate, PasswordSettingSliderTableViewCellDelegate, QRScannerControllerDelegate, UITextFieldDelegate, UITextViewDelegate, SFSafariViewControllerDelegate {
|
||||
|
||||
|
||||
var tableData = [
|
||||
[Dictionary<PasswordEditorCellKey, Any>]
|
||||
]()
|
||||
var password: Password?
|
||||
|
||||
|
||||
private var navigationItemTitle: String?
|
||||
|
||||
|
||||
private var sectionHeaderTitles = ["name", "password", "additions",""].map {$0.uppercased()}
|
||||
private var sectionFooterTitles = ["", "", "Use \"key: value\" format for additional fields.", ""]
|
||||
private let nameSection = 0
|
||||
private let passwordSection = 1
|
||||
private let additionsSection = 2
|
||||
private var hidePasswordSettings = true
|
||||
|
||||
|
||||
var nameCell: TextFieldTableViewCell?
|
||||
var fillPasswordCell: FillPasswordTableViewCell?
|
||||
private var passwordLengthCell: SliderTableViewCell?
|
||||
|
|
@ -42,39 +42,39 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
|||
private var deletePasswordCell: UITableViewCell?
|
||||
private var scanQRCodeCell: UITableViewCell?
|
||||
private var memorablePasswordGeneratorCell: UITableViewCell?
|
||||
|
||||
|
||||
override func loadView() {
|
||||
super.loadView()
|
||||
|
||||
|
||||
deletePasswordCell = UITableViewCell(style: .default, reuseIdentifier: "default")
|
||||
deletePasswordCell!.textLabel?.text = "Delete Password"
|
||||
deletePasswordCell!.textLabel?.textColor = Globals.red
|
||||
deletePasswordCell?.selectionStyle = .default
|
||||
|
||||
|
||||
scanQRCodeCell = UITableViewCell(style: .default, reuseIdentifier: "default")
|
||||
scanQRCodeCell?.textLabel?.text = "Add One-Time Password"
|
||||
scanQRCodeCell?.textLabel?.textColor = Globals.blue
|
||||
scanQRCodeCell?.selectionStyle = .default
|
||||
scanQRCodeCell?.accessoryType = .disclosureIndicator
|
||||
|
||||
|
||||
memorablePasswordGeneratorCell = UITableViewCell(style: .default, reuseIdentifier: "default")
|
||||
memorablePasswordGeneratorCell?.textLabel?.text = "Get a Memorable One: xkpasswd"
|
||||
memorablePasswordGeneratorCell?.textLabel?.textColor = Globals.blue
|
||||
memorablePasswordGeneratorCell?.selectionStyle = .default
|
||||
memorablePasswordGeneratorCell?.accessoryType = .disclosureIndicator
|
||||
}
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
if navigationItemTitle != nil {
|
||||
navigationItem.title = navigationItemTitle
|
||||
}
|
||||
|
||||
|
||||
tableView.register(UINib(nibName: "TextFieldTableViewCell", bundle: nil), forCellReuseIdentifier: "textFieldCell")
|
||||
tableView.register(UINib(nibName: "TextViewTableViewCell", bundle: nil), forCellReuseIdentifier: "textViewCell")
|
||||
tableView.register(UINib(nibName: "FillPasswordTableViewCell", bundle: nil), forCellReuseIdentifier: "fillPasswordCell")
|
||||
tableView.register(UINib(nibName: "SliderTableViewCell", bundle: nil), forCellReuseIdentifier: "passwordLengthCell")
|
||||
|
||||
|
||||
tableView.rowHeight = UITableViewAutomaticDimension
|
||||
tableView.estimatedRowHeight = 48
|
||||
self.tableView.sectionFooterHeight = UITableViewAutomaticDimension;
|
||||
|
|
@ -83,10 +83,10 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
|||
override func viewDidLayoutSubviews() {
|
||||
additionsCell?.contentTextView.setContentOffset(.zero, animated: false)
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cellData = tableData[indexPath.section][indexPath.row]
|
||||
|
||||
|
||||
switch cellData[PasswordEditorCellKey.type] as! PasswordEditorCellType {
|
||||
case .nameCell:
|
||||
nameCell = tableView.dequeueReusableCell(withIdentifier: "textFieldCell", for: indexPath) as? TextFieldTableViewCell
|
||||
|
|
@ -132,7 +132,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
|||
return scanQRCodeCell!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
return 44
|
||||
}
|
||||
|
|
@ -153,11 +153,11 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
|||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
return sectionHeaderTitles[section]
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
|
||||
return sectionFooterTitles[section]
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let selectedCell = tableView.cellForRow(at: indexPath)
|
||||
if selectedCell == deletePasswordCell {
|
||||
|
|
@ -175,12 +175,12 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
|||
let vc = SFSafariViewController(url: url, entersReaderIfAvailable: false)
|
||||
vc.delegate = self
|
||||
present(vc, animated: true)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
|
||||
|
||||
// generate password, copy to pasteboard, and set the cell
|
||||
// check whether the current password looks like an OTP field
|
||||
func generateAndCopyPassword() {
|
||||
|
|
@ -195,23 +195,23 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
|||
self.generateAndCopyPasswordNoOtpCheck()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// generate the password, don't care whether the original line is otp
|
||||
func generateAndCopyPasswordNoOtpCheck() {
|
||||
// show password settings (e.g., the length slider)
|
||||
showPasswordSettings()
|
||||
|
||||
|
||||
let length = passwordLengthCell?.roundedValue ?? 0
|
||||
let plainPassword = PasswordGeneratorFlavour.from(SharedDefaults[.passwordGeneratorFlavor]).generatePassword(length: length)
|
||||
SecurePasteboard.shared.copy(textToCopy: plainPassword)
|
||||
|
||||
|
||||
// update tableData so to make sure reloadData() works correctly
|
||||
tableData[passwordSection][0][PasswordEditorCellKey.content] = plainPassword
|
||||
|
||||
|
||||
// update cell manually, no need to call reloadData()
|
||||
fillPasswordCell?.setContent(content: plainPassword)
|
||||
}
|
||||
|
||||
|
||||
// show password settings (e.g., the length slider)
|
||||
func showPasswordSettings() {
|
||||
if hidePasswordSettings == true {
|
||||
|
|
@ -219,13 +219,13 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
|||
tableView.reloadSections([passwordSection], with: .fade)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// show/hide password settings (e.g., the length slider)
|
||||
func showHidePasswordSettings() {
|
||||
hidePasswordSettings = !hidePasswordSettings
|
||||
tableView.reloadSections([passwordSection], with: .fade)
|
||||
}
|
||||
|
||||
|
||||
func insertScannedOTPFields(_ otpauth: String) {
|
||||
// update tableData
|
||||
var additionsString = ""
|
||||
|
|
@ -235,11 +235,11 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
|||
additionsString = otpauth
|
||||
}
|
||||
tableData[additionsSection][0][PasswordEditorCellKey.content] = additionsString
|
||||
|
||||
|
||||
// reload the additions cell
|
||||
additionsCell?.setContent(content: additionsString)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - QRScannerControllerDelegate Methods
|
||||
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
|
||||
if let url = URL(string: line), let _ = Token(url: url) {
|
||||
|
|
@ -248,12 +248,12 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
|||
return (accept: false, message: "Invalid token URL")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - QRScannerControllerDelegate Methods
|
||||
func handleScannedOutput(line: String) {
|
||||
insertScannedOTPFields(line)
|
||||
}
|
||||
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
if segue.identifier == "showQRScannerSegue" {
|
||||
if let navController = segue.destination as? UINavigationController {
|
||||
|
|
@ -265,7 +265,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// update tableData so to make sure reloadData() works correctly
|
||||
func textFieldDidEndEditing(_ textField: UITextField) {
|
||||
if textField == nameCell?.contentTextField {
|
||||
|
|
@ -277,48 +277,48 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// update tableData so to make sure reloadData() works correctly
|
||||
func textViewDidEndEditing(_ textView: UITextView) {
|
||||
if textView == additionsCell?.contentTextView {
|
||||
tableData[additionsSection][0][PasswordEditorCellKey.content] = additionsCell?.getContent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||
if textField == fillPasswordCell?.contentTextField {
|
||||
// show password generation settings automatically
|
||||
showPasswordSettings()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func getNameURL() -> (String, URL) {
|
||||
let encodedName = (nameCell?.getContent()?.stringByAddingPercentEncodingForRFC3986())!
|
||||
let name = URL(string: encodedName)!.lastPathComponent
|
||||
let url = URL(string: encodedName)!.appendingPathExtension("gpg")
|
||||
return (name, url)
|
||||
}
|
||||
|
||||
|
||||
func checkName() -> Bool {
|
||||
// the name field should not be empty
|
||||
guard let name = nameCell?.getContent(), name.isEmpty == false else {
|
||||
Utils.alert(title: "Cannot Save", message: "Please fill in the name.", controller: self, completion: nil)
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
// the name should not start with /
|
||||
guard name.hasPrefix("/") == false else {
|
||||
Utils.alert(title: "Cannot Save", message: "Please remove the prefix \"/\" from your password name.", controller: self, completion: nil)
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
// the name field should be a valid url
|
||||
guard let path = name.stringByAddingPercentEncodingForRFC3986(),
|
||||
var passwordURL = URL(string: path) else {
|
||||
Utils.alert(title: "Cannot Save", message: "Password name is invalid.", controller: self, completion: nil)
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
// check whether we can parse the filename (be consistent with PasswordStore::addPasswordEntities)
|
||||
var previousPathLength = Int.max
|
||||
while passwordURL.path != "." {
|
||||
|
|
@ -329,10 +329,10 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
|||
}
|
||||
previousPathLength = passwordURL.path.count
|
||||
}
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
|
||||
let copiedLinesSplit = UIPasteboard.general.string?.components(separatedBy: CharacterSet.whitespacesAndNewlines).filter({ !$0.isEmpty })
|
||||
if copiedLinesSplit?.count ?? 0 > 0 {
|
||||
|
|
@ -353,5 +353,5 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
|||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,13 +27,13 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
private var filteredPasswordsTableEntries: [PasswordsTableEntry] = []
|
||||
private var parentPasswordEntity: PasswordEntity? = nil
|
||||
private let passwordStore = PasswordStore.shared
|
||||
|
||||
|
||||
private var tapTabBarTime: TimeInterval = 0
|
||||
|
||||
private var sections = [(title: String, entries: [PasswordsTableEntry])]()
|
||||
|
||||
|
||||
private var searchActive : Bool = false
|
||||
|
||||
|
||||
private lazy var searchController: UISearchController = {
|
||||
let uiSearchController = UISearchController(searchResultsController: nil)
|
||||
uiSearchController.searchResultsUpdater = self
|
||||
|
|
@ -59,7 +59,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
let backUIBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(self.backAction(_:)))
|
||||
return backUIBarButtonItem
|
||||
}()
|
||||
|
||||
|
||||
private lazy var transitionFromRight: CATransition = {
|
||||
let transition = CATransition()
|
||||
transition.type = kCATransitionPush
|
||||
|
|
@ -69,7 +69,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
transition.subtype = kCATransitionFromRight
|
||||
return transition
|
||||
}()
|
||||
|
||||
|
||||
private lazy var transitionFromLeft: CATransition = {
|
||||
let transition = CATransition()
|
||||
transition.type = kCATransitionPush
|
||||
|
|
@ -81,7 +81,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}()
|
||||
|
||||
@IBOutlet weak var tableView: UITableView!
|
||||
|
||||
|
||||
private func initPasswordsTableEntries(parent: PasswordEntity?) {
|
||||
passwordsTableEntries.removeAll()
|
||||
passwordsTableAllEntries.removeAll()
|
||||
|
|
@ -102,9 +102,9 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
parentPasswordEntity = parent
|
||||
}
|
||||
|
||||
|
||||
@IBAction func cancelAddPassword(segue: UIStoryboardSegue) {
|
||||
|
||||
|
||||
}
|
||||
@IBAction func saveAddPassword(segue: UIStoryboardSegue) {
|
||||
if let controller = segue.source as? AddPasswordTableViewController {
|
||||
|
|
@ -127,7 +127,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func syncPasswords() {
|
||||
guard passwordStore.repositoryExisted() else {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(800)) {
|
||||
|
|
@ -190,17 +190,17 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
|
||||
if SharedDefaults[.isShowFolderOn] {
|
||||
searchController.searchBar.scopeButtonTitles = ["Current", "All"]
|
||||
} else {
|
||||
searchController.searchBar.scopeButtonTitles = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
searchController.searchBar.delegate = self
|
||||
|
|
@ -220,22 +220,22 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
tableView.refreshControl = syncControl
|
||||
SVProgressHUD.setDefaultMaskType(.black)
|
||||
tableView.register(UINib(nibName: "PasswordWithFolderTableViewCell", bundle: nil), forCellReuseIdentifier: "passwordWithFolderTableViewCell")
|
||||
|
||||
|
||||
// initialize the password table
|
||||
reloadTableView(parent: nil)
|
||||
|
||||
|
||||
// reset the data table if some password (maybe another one) has been updated
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(actOnReloadTableViewRelatedNotification), name: .passwordStoreUpdated, object: nil)
|
||||
// reset the data table if the disaply settings have been changed
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(actOnReloadTableViewRelatedNotification), name: .passwordDisplaySettingChanged, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(actOnSearchNotification), name: .passwordSearch, object: nil)
|
||||
|
||||
|
||||
// listen to the swipe back guesture
|
||||
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
|
||||
swipeRight.direction = UISwipeGestureRecognizerDirection.right
|
||||
self.view.addGestureRecognizer(swipeRight)
|
||||
}
|
||||
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
tabBarController!.delegate = self
|
||||
|
|
@ -243,7 +243,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
tableView.deselectRow(at: path, animated: false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func viewWillLayoutSubviews() {
|
||||
super.viewWillLayoutSubviews()
|
||||
guard #available(iOS 11, *) else {
|
||||
|
|
@ -252,21 +252,21 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return sections.count
|
||||
}
|
||||
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return sections[section].entries.count
|
||||
}
|
||||
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressAction(_:)))
|
||||
longPressGestureRecognizer.minimumPressDuration = 0.6
|
||||
if SharedDefaults[.isShowFolderOn] && searchController.searchBar.selectedScopeButtonIndex == 0{
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "passwordTableViewCell", for: indexPath)
|
||||
|
||||
|
||||
let entry = getPasswordEntry(by: indexPath)
|
||||
if entry.passwordEntity!.synced {
|
||||
cell.textLabel?.text = entry.title
|
||||
|
|
@ -299,11 +299,11 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private func getPasswordEntry(by indexPath: IndexPath) -> PasswordsTableEntry {
|
||||
return sections[indexPath.section].entries[indexPath.row]
|
||||
}
|
||||
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let entry = getPasswordEntry(by: indexPath)
|
||||
if !entry.isDir {
|
||||
|
|
@ -318,7 +318,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
reloadTableView(parent: entry.passwordEntity, anim: transitionFromRight)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func respondToSwipeGesture(gesture: UIGestureRecognizer) {
|
||||
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
|
||||
// swipe right -> swipe back
|
||||
|
|
@ -327,7 +327,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func backAction(_ sender: Any?) {
|
||||
guard SharedDefaults[.isShowFolderOn] else { return }
|
||||
var anim: CATransition? = transitionFromLeft
|
||||
|
|
@ -336,7 +336,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
reloadTableView(parent: parentPasswordEntity?.parent, anim: anim)
|
||||
}
|
||||
|
||||
|
||||
@objc func longPressAction(_ gesture: UILongPressGestureRecognizer) {
|
||||
if gesture.state == UIGestureRecognizerState.began {
|
||||
let touchPoint = gesture.location(in: tableView)
|
||||
|
|
@ -345,7 +345,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
return sections[section].title
|
||||
}
|
||||
|
|
@ -357,11 +357,11 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
|
||||
return index
|
||||
}
|
||||
|
||||
|
||||
func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
|
||||
decryptThenCopyPassword(from: indexPath)
|
||||
}
|
||||
|
||||
|
||||
private func requestPGPKeyPassphrase() -> String {
|
||||
let sem = DispatchSemaphore(value: 0)
|
||||
var passphrase = ""
|
||||
|
|
@ -389,7 +389,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
return passphrase
|
||||
}
|
||||
|
||||
|
||||
private func decryptThenCopyPassword(from indexPath: IndexPath) {
|
||||
guard self.passwordStore.privateKey != nil else {
|
||||
Utils.alert(title: "Cannot Copy Password", message: "PGP Key is not set. Please set your PGP Key first.", controller: self, completion: nil)
|
||||
|
|
@ -418,39 +418,39 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func generateSections(item: [PasswordsTableEntry]) {
|
||||
let collation = UILocalizedIndexedCollation.current()
|
||||
let sectionTitles = collation.sectionIndexTitles
|
||||
var newSections = [(title: String, entries: [PasswordsTableEntry])]()
|
||||
|
||||
|
||||
// initialize all sections
|
||||
for i in 0..<sectionTitles.count {
|
||||
newSections.append((title: sectionTitles[i], entries: [PasswordsTableEntry]()))
|
||||
}
|
||||
|
||||
|
||||
// put entries into sections
|
||||
for entry in item {
|
||||
let sectionNumber = collation.section(for: entry, collationStringSelector: #selector(getter: PasswordsTableEntry.title))
|
||||
newSections[sectionNumber].entries.append(entry)
|
||||
}
|
||||
|
||||
|
||||
// sort each list and set sectionTitles
|
||||
for i in 0..<sectionTitles.count {
|
||||
let entriesToSort = newSections[i].entries
|
||||
let sortedEntries = collation.sortedArray(from: entriesToSort, collationStringSelector: #selector(getter: PasswordsTableEntry.title))
|
||||
newSections[i].entries = sortedEntries as! [PasswordsTableEntry]
|
||||
}
|
||||
|
||||
|
||||
// only keep non-empty sections
|
||||
sections = newSections.filter {$0.entries.count > 0}
|
||||
}
|
||||
|
||||
|
||||
@objc func actOnSearchNotification() {
|
||||
searchController.searchBar.becomeFirstResponder()
|
||||
}
|
||||
|
||||
|
||||
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||
if identifier == "showPasswordDetail" {
|
||||
guard self.passwordStore.privateKey != nil else {
|
||||
|
|
@ -487,7 +487,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func filterContentForSearchText(searchText: String, scope: String = "All") {
|
||||
switch scope {
|
||||
case "All":
|
||||
|
|
@ -512,10 +512,10 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
default:
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private func reloadTableView(data: [PasswordsTableEntry], anim: CAAnimation? = nil) {
|
||||
// set navigation item
|
||||
let numberOfLocalCommits = self.passwordStore.numberOfLocalCommits
|
||||
|
|
@ -529,7 +529,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
} else {
|
||||
navigationItem.leftBarButtonItem = nil
|
||||
}
|
||||
|
||||
|
||||
// set the password table
|
||||
generateSections(item: data)
|
||||
if anim != nil {
|
||||
|
|
@ -537,7 +537,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
tableView.reloadData()
|
||||
self.tableView.layer.removeAnimation(forKey: "UITableViewReloadDataAnimationKey")
|
||||
|
||||
|
||||
// set the sync control title
|
||||
let atribbutedTitle = "Last Synced: \(lastSyncedTimeString())"
|
||||
syncControl.attributedTitle = NSAttributedString(string: atribbutedTitle)
|
||||
|
|
@ -552,12 +552,12 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
formatter.timeStyle = .short
|
||||
return formatter.string(from: date)
|
||||
}
|
||||
|
||||
|
||||
private func reloadTableView(parent: PasswordEntity?, anim: CAAnimation? = nil) {
|
||||
initPasswordsTableEntries(parent: parent)
|
||||
reloadTableView(data: passwordsTableEntries, anim: anim)
|
||||
}
|
||||
|
||||
|
||||
@objc func actOnReloadTableViewRelatedNotification() {
|
||||
DispatchQueue.main.async { [weak weakSelf = self] in
|
||||
guard let strongSelf = weakSelf else { return }
|
||||
|
|
@ -565,11 +565,11 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
strongSelf.reloadTableView(data: strongSelf.passwordsTableEntries)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func handleRefresh(_ syncControl: UIRefreshControl) {
|
||||
syncPasswords()
|
||||
}
|
||||
|
||||
|
||||
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
|
||||
if viewController == self.navigationController {
|
||||
let currentTime = Date().timeIntervalSince1970
|
||||
|
|
@ -586,14 +586,14 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
backAction(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
|
||||
// update the default search scope
|
||||
SharedDefaults[.isSearchDefaultAll] = searchController.searchBar.scopeButtonTitles![selectedScope] == "All"
|
||||
updateSearchResults(for: searchController)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
|
||||
// set the default search scope to "all"
|
||||
if SharedDefaults[.isShowFolderOn] && SharedDefaults[.isSearchDefaultAll] {
|
||||
|
|
@ -603,14 +603,14 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool {
|
||||
// set the default search scope to "current"
|
||||
searchController.searchBar.selectedScopeButtonIndex = 0
|
||||
updateSearchResults(for: searchController)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
private func requestGitPassword(credential: GitCredential.Credential, lastPassword: String?) -> String? {
|
||||
let sem = DispatchSemaphore(value: 0)
|
||||
var password: String?
|
||||
|
|
@ -621,7 +621,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
case .ssh:
|
||||
message = "Please fill in the password of your SSH key."
|
||||
}
|
||||
|
||||
|
||||
DispatchQueue.main.async {
|
||||
SVProgressHUD.dismiss()
|
||||
let alert = UIAlertController(title: "Password", message: message, preferredStyle: UIAlertControllerStyle.alert)
|
||||
|
|
@ -639,7 +639,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
})
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
let _ = sem.wait(timeout: .distantFuture)
|
||||
return password
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,90 +17,90 @@ protocol QRScannerControllerDelegate {
|
|||
}
|
||||
|
||||
class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
|
||||
|
||||
|
||||
@IBOutlet weak var scannerOutput: UILabel!
|
||||
|
||||
|
||||
var captureSession: AVCaptureSession?
|
||||
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
|
||||
var qrCodeFrameView: UIView?
|
||||
|
||||
|
||||
let supportedCodeTypes = [AVMetadataObject.ObjectType.qr]
|
||||
|
||||
|
||||
var delegate: QRScannerControllerDelegate?
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
||||
if AVCaptureDevice.authorizationStatus(for: .video) == .denied {
|
||||
presentCameraSettings()
|
||||
}
|
||||
|
||||
|
||||
// Get an instance of the AVCaptureDevice class to initialize a device object and provide the video as the media type parameter.
|
||||
let captureDevice = AVCaptureDevice.default(for: AVMediaType.video)
|
||||
do {
|
||||
// Get an instance of the AVCaptureDeviceInput class using the previous device object.
|
||||
let input = try AVCaptureDeviceInput(device: captureDevice!)
|
||||
|
||||
|
||||
// Initialize the captureSession object.
|
||||
captureSession = AVCaptureSession()
|
||||
|
||||
// Set the input device on the capture session.
|
||||
captureSession?.addInput(input)
|
||||
|
||||
|
||||
// Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session.
|
||||
let captureMetadataOutput = AVCaptureMetadataOutput()
|
||||
captureSession?.addOutput(captureMetadataOutput)
|
||||
|
||||
|
||||
// Set delegate and use the default dispatch queue to execute the call back
|
||||
captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
|
||||
captureMetadataOutput.metadataObjectTypes = supportedCodeTypes
|
||||
|
||||
|
||||
// Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer.
|
||||
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
|
||||
videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
|
||||
videoPreviewLayer?.frame = view.layer.bounds
|
||||
view.layer.addSublayer(videoPreviewLayer!)
|
||||
|
||||
|
||||
// Start video capture.
|
||||
captureSession?.startRunning()
|
||||
|
||||
|
||||
// Move the message label to the front
|
||||
scannerOutput.layer.cornerRadius = 10
|
||||
scannerOutput.text = "No QR code detected"
|
||||
view.bringSubview(toFront: scannerOutput)
|
||||
|
||||
|
||||
// Initialize QR Code Frame to highlight the QR code
|
||||
qrCodeFrameView = UIView()
|
||||
|
||||
|
||||
if let qrCodeFrameView = qrCodeFrameView {
|
||||
qrCodeFrameView.layer.borderColor = UIColor.green.cgColor
|
||||
qrCodeFrameView.layer.borderWidth = 2
|
||||
view.addSubview(qrCodeFrameView)
|
||||
view.bringSubview(toFront: qrCodeFrameView)
|
||||
}
|
||||
|
||||
|
||||
} catch {
|
||||
scannerOutput.text = error.localizedDescription
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func didReceiveMemoryWarning() {
|
||||
super.didReceiveMemoryWarning()
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// MARK: - AVCaptureMetadataOutputObjectsDelegate Methods
|
||||
|
||||
|
||||
func metadataOutput(_ captureOutput: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: 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
|
||||
|
||||
|
||||
// check whether it is a valid result
|
||||
if let scanned = metadataObj.stringValue {
|
||||
if let (accept, message) = delegate?.checkScannedOutput(line: scanned) {
|
||||
|
|
@ -121,13 +121,13 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg
|
|||
} else {
|
||||
scannerOutput.text = "No string value"
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
qrCodeFrameView?.frame = CGRect.zero
|
||||
scannerOutput.text = "No QR code detected"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func presentCameraSettings() {
|
||||
let alertController = UIAlertController(title: "Error",
|
||||
message: "Camera access denied.\nWARNING: Toggle the camera permission resets the app! Save your changes.",
|
||||
|
|
@ -140,7 +140,7 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg
|
|||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
present(alertController, animated: true)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class RawPasswordViewController: UIViewController {
|
|||
|
||||
@IBOutlet weak var rawPasswordTextView: UITextView!
|
||||
var password: Password?
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
navigationItem.title = password?.name
|
||||
|
|
|
|||
|
|
@ -14,21 +14,21 @@ class SSHKeySettingTableViewController: UITableViewController {
|
|||
|
||||
@IBOutlet weak var privateKeyURLTextField: UITextField!
|
||||
let passwordStore = PasswordStore.shared
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
privateKeyURLTextField.text = SharedDefaults[.gitSSHPrivateKeyURL]?.absoluteString
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@IBAction func doneButtonTapped(_ sender: UIButton) {
|
||||
guard let privateKeyURL = URL(string: privateKeyURLTextField.text!.trimmed) else {
|
||||
Utils.alert(title: "Cannot Save", message: "Please set Private Key URL first.", controller: self, completion: nil)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
SharedDefaults[.gitSSHPrivateKeyURL] = privateKeyURL
|
||||
|
||||
|
||||
do {
|
||||
try Data(contentsOf: privateKeyURL).write(to: URL(fileURLWithPath: Globals.gitSSHPrivateKeyPath), options: .atomic)
|
||||
} catch {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class SettingsSplitViewController: UISplitViewController, UISplitViewControllerD
|
|||
self.delegate = self
|
||||
self.preferredDisplayMode = .allVisible
|
||||
}
|
||||
|
||||
|
||||
func splitViewController(
|
||||
_ splitViewController: UISplitViewController,
|
||||
collapseSecondary secondaryViewController: UIViewController,
|
||||
|
|
|
|||
|
|
@ -16,14 +16,14 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
@IBOutlet weak var passcodeTableViewCell: UITableViewCell!
|
||||
@IBOutlet weak var passwordRepositoryTableViewCell: UITableViewCell!
|
||||
var setPasscodeLockAlert: UIAlertController?
|
||||
|
||||
|
||||
let passwordStore = PasswordStore.shared
|
||||
var passcodeLock = PasscodeLock.shared
|
||||
|
||||
|
||||
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
|
||||
navigationController?.popViewController(animated: true)
|
||||
}
|
||||
|
||||
|
||||
@IBAction func savePGPKey(segue: UIStoryboardSegue) {
|
||||
if let controller = segue.source as? PGPKeySettingTableViewController {
|
||||
SharedDefaults[.pgpPrivateKeyURL] = URL(string: controller.pgpPrivateKeyURLTextField.text!.trimmed)
|
||||
|
|
@ -32,7 +32,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
self.passwordStore.pgpKeyPassphrase = controller.pgpPassphrase
|
||||
}
|
||||
SharedDefaults[.pgpKeySource] = "url"
|
||||
|
||||
|
||||
SVProgressHUD.setDefaultMaskType(.black)
|
||||
SVProgressHUD.setDefaultStyle(.light)
|
||||
SVProgressHUD.show(withStatus: "Fetching PGP Key")
|
||||
|
|
@ -53,7 +53,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else if let controller = segue.source as? PGPKeyArmorSettingTableViewController {
|
||||
SharedDefaults[.pgpKeySource] = "armor"
|
||||
if SharedDefaults[.isRememberPGPPassphraseOn] {
|
||||
|
|
@ -62,7 +62,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
|
||||
SharedDefaults[.pgpPublicKeyArmor] = controller.armorPublicKeyTextView.text!
|
||||
SharedDefaults[.pgpPrivateKeyArmor] = controller.armorPrivateKeyTextView.text!
|
||||
|
||||
|
||||
SVProgressHUD.setDefaultMaskType(.black)
|
||||
SVProgressHUD.setDefaultStyle(.light)
|
||||
SVProgressHUD.show(withStatus: "Fetching PGP Key")
|
||||
|
|
@ -84,7 +84,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func saveImportedPGPKey() {
|
||||
// load keys
|
||||
SharedDefaults[.pgpKeySource] = "file"
|
||||
|
|
@ -108,11 +108,11 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@IBAction func saveGitServerSetting(segue: UIStoryboardSegue) {
|
||||
self.passwordRepositoryTableViewCell.detailTextLabel?.text = SharedDefaults[.gitURL]?.host
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return super.tableView(tableView, numberOfRowsInSection: section)
|
||||
}
|
||||
|
|
@ -125,12 +125,12 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
setPasswordRepositoryTableViewCellDetailText()
|
||||
setPasscodeLockCell()
|
||||
}
|
||||
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(true)
|
||||
tabBarController!.delegate = self
|
||||
}
|
||||
|
||||
|
||||
private func setPasscodeLockCell() {
|
||||
if passcodeLock.hasPasscode {
|
||||
self.passcodeTableViewCell.detailTextLabel?.text = "On"
|
||||
|
|
@ -138,7 +138,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
self.passcodeTableViewCell.detailTextLabel?.text = "Off"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func setPGPKeyTableViewCellDetailText() {
|
||||
if let pgpKeyID = self.passwordStore.pgpKeyID {
|
||||
pgpKeyTableViewCell.detailTextLabel?.text = pgpKeyID
|
||||
|
|
@ -146,7 +146,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
pgpKeyTableViewCell.detailTextLabel?.text = "Not Set"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func setPasswordRepositoryTableViewCellDetailText() {
|
||||
if SharedDefaults[.gitURL] == nil {
|
||||
passwordRepositoryTableViewCell.detailTextLabel?.text = "Not Set"
|
||||
|
|
@ -154,13 +154,13 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
passwordRepositoryTableViewCell.detailTextLabel?.text = SharedDefaults[.gitURL]!.host
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func actOnPasswordStoreErasedNotification() {
|
||||
setPGPKeyTableViewCellDetailText()
|
||||
setPasswordRepositoryTableViewCellDetailText()
|
||||
setPasscodeLockCell()
|
||||
}
|
||||
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
if tableView.cellForRow(at: indexPath) == passcodeTableViewCell {
|
||||
if SharedDefaults[.passcodeKey] != nil{
|
||||
|
|
@ -173,13 +173,13 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
}
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
|
||||
|
||||
func showPGPKeyActionSheet() {
|
||||
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||
var urlActionTitle = "Download from URL"
|
||||
var armorActionTitle = "ASCII-Armor Encrypted Key"
|
||||
var fileActionTitle = "iTunes File Sharing"
|
||||
|
||||
|
||||
if SharedDefaults[.pgpKeySource] == "url" {
|
||||
urlActionTitle = "✓ \(urlActionTitle)"
|
||||
} else if SharedDefaults[.pgpKeySource] == "armor" {
|
||||
|
|
@ -235,8 +235,8 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
}
|
||||
optionMenu.addAction(fileAction)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if SharedDefaults[.pgpKeySource] != nil {
|
||||
let deleteAction = UIAlertAction(title: "Remove PGP Keys", style: .destructive) { _ in
|
||||
self.passwordStore.removePGPKeys()
|
||||
|
|
@ -249,12 +249,12 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
optionMenu.popoverPresentationController?.sourceRect = pgpKeyTableViewCell.bounds
|
||||
self.present(optionMenu, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
func showPasscodeActionSheet() {
|
||||
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||
let passcodeRemoveViewController = PasscodeLockViewController()
|
||||
|
||||
|
||||
|
||||
|
||||
let removePasscodeAction = UIAlertAction(title: "Remove Passcode", style: .destructive) { [weak self] _ in
|
||||
passcodeRemoveViewController.successCallback = {
|
||||
self?.passcodeLock.delete()
|
||||
|
|
@ -262,11 +262,11 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
}
|
||||
self?.present(passcodeRemoveViewController, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
let changePasscodeAction = UIAlertAction(title: "Change Passcode", style: .default) { [weak self] _ in
|
||||
self?.setPasscodeLock()
|
||||
}
|
||||
|
||||
|
||||
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
|
||||
optionMenu.addAction(removePasscodeAction)
|
||||
optionMenu.addAction(changePasscodeAction)
|
||||
|
|
@ -289,7 +289,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func setPasscodeLock() {
|
||||
// prepare the alert for setting the passcode
|
||||
setPasscodeLockAlert = UIAlertController(title: "Set passcode", message: "Fill in your passcode for Pass (at least 4 characters)", preferredStyle: .alert)
|
||||
|
|
@ -303,7 +303,7 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
textField.isSecureTextEntry = true
|
||||
textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControlEvents.editingChanged)
|
||||
})
|
||||
|
||||
|
||||
// save action
|
||||
let saveAction = UIAlertAction(title: "Save", style: .default) { (action:UIAlertAction) -> Void in
|
||||
let passcode: String = self.setPasscodeLockAlert!.textFields![0].text!
|
||||
|
|
@ -312,10 +312,10 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
|
|||
self.setPasscodeLockCell()
|
||||
}
|
||||
saveAction.isEnabled = false // disable the Save button by default
|
||||
|
||||
|
||||
// cancel action
|
||||
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
|
||||
|
||||
|
||||
// present
|
||||
setPasscodeLockAlert?.addAction(saveAction)
|
||||
setPasscodeLockAlert?.addAction(cancelAction)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class SpecialThanksTableViewController: BasicStaticTableViewController {
|
|||
["FlatIcon",
|
||||
"https://www.flaticon.com"],
|
||||
]
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
tableData.append([])
|
||||
for item in openSourceComponents {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue