From 5a02cb726eed3a526c94632492ee1fe502c46f75 Mon Sep 17 00:00:00 2001 From: Yishi Lin Date: Thu, 23 Mar 2017 01:28:46 +0800 Subject: [PATCH] Improve the password length slider - the slider appears after clicking "generate" - the slider goes away after clicking a non-password-related section - generate new password if the slider value changes --- .../AddPasswordTableViewController.swift | 3 +- .../EditPasswordTableViewController.swift | 3 +- .../PasswordEditorTableViewController.swift | 56 ++++++++++++++++--- pass/Views/FillPasswordTableViewCell.swift | 6 +- pass/Views/SliderTableViewCell.swift | 22 ++++++-- pass/Views/SliderTableViewCell.xib | 10 ++-- 6 files changed, 75 insertions(+), 25 deletions(-) diff --git a/pass/Controllers/AddPasswordTableViewController.swift b/pass/Controllers/AddPasswordTableViewController.swift index 7c59287..423cac7 100644 --- a/pass/Controllers/AddPasswordTableViewController.swift +++ b/pass/Controllers/AddPasswordTableViewController.swift @@ -16,8 +16,7 @@ class AddPasswordTableViewController: PasswordEditorTableViewController { override func viewDidLoad() { tableData = [ [[.type: PasswordEditorCellType.textFieldCell, .title: "name"]], - [[.type: PasswordEditorCellType.fillPasswordCell, .title: "password"], - [.type: PasswordEditorCellType.passwordLengthCell, .title: "passwordlength"]], + [[.type: PasswordEditorCellType.fillPasswordCell, .title: "password"]], [[.type: PasswordEditorCellType.textViewCell, .title: "additions"]], ] super.viewDidLoad() diff --git a/pass/Controllers/EditPasswordTableViewController.swift b/pass/Controllers/EditPasswordTableViewController.swift index a6ef6cf..a1c2fdd 100644 --- a/pass/Controllers/EditPasswordTableViewController.swift +++ b/pass/Controllers/EditPasswordTableViewController.swift @@ -12,8 +12,7 @@ class EditPasswordTableViewController: PasswordEditorTableViewController { override func viewDidLoad() { tableData = [ [[.type: PasswordEditorCellType.textFieldCell, .title: "name", .content: password!.name]], - [[.type: PasswordEditorCellType.fillPasswordCell, .title: "password", .content: password!.password], - [.type: PasswordEditorCellType.passwordLengthCell, .title: "passwordlength"]], + [[.type: PasswordEditorCellType.fillPasswordCell, .title: "password", .content: password!.password]], [[.type: PasswordEditorCellType.textViewCell, .title: "additions", .content: password!.getAdditionsPlainText()]], [[.type: PasswordEditorCellType.deletePasswordCell]], ] diff --git a/pass/Controllers/PasswordEditorTableViewController.swift b/pass/Controllers/PasswordEditorTableViewController.swift index d3a055e..cf00013 100644 --- a/pass/Controllers/PasswordEditorTableViewController.swift +++ b/pass/Controllers/PasswordEditorTableViewController.swift @@ -15,7 +15,7 @@ enum PasswordEditorCellKey { case type, title, content, placeholders } -class PasswordEditorTableViewController: UITableViewController, FillPasswordTableViewCellDelegate { +class PasswordEditorTableViewController: UITableViewController, FillPasswordTableViewCellDelegate, PasswordSettingSliderTableViewCellDelegate, UIGestureRecognizerDelegate { var navigationItemTitle: String? var password: Password? var tableData = [ @@ -23,7 +23,9 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl ]() var sectionHeaderTitles = ["name", "password", "additions",""].map {$0.uppercased()} var sectionFooterTitles = ["", "", "Use \"key: value\" format for additional fields.", ""] + let passwordSection = 1 + var fillPasswordCell: FillPasswordTableViewCell? var passwordLengthCell: SliderTableViewCell? var deletePasswordCell: UITableViewCell? @@ -47,6 +49,10 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl tableView.estimatedRowHeight = 48 self.tableView.sectionFooterHeight = UITableViewAutomaticDimension; self.tableView.estimatedSectionFooterHeight = 0; + + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tableTapped)) + tapGesture.delegate = self + tableView.addGestureRecognizer(tapGesture) } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { @@ -58,13 +64,14 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl cell.setContent(content: cellData[PasswordEditorCellKey.content] as? String) return cell case .fillPasswordCell: - let cell = tableView.dequeueReusableCell(withIdentifier: "fillPasswordCell", for: indexPath) as! FillPasswordTableViewCell - cell.delegate = self - cell.setContent(content: cellData[PasswordEditorCellKey.content] as? String) - return cell + fillPasswordCell = tableView.dequeueReusableCell(withIdentifier: "fillPasswordCell", for: indexPath) as? FillPasswordTableViewCell + fillPasswordCell?.delegate = self + fillPasswordCell?.setContent(content: cellData[PasswordEditorCellKey.content] as? String) + return fillPasswordCell! case .passwordLengthCell: passwordLengthCell = tableView.dequeueReusableCell(withIdentifier: "passwordLengthCell", for: indexPath) as? SliderTableViewCell passwordLengthCell?.reset(title: "Length", minimumValue: Globals.passwordMinimumLength, maximumValue: Globals.passwordMaximumLength, defaultValue: Globals.passwordDefaultLength) + passwordLengthCell?.delegate = self return passwordLengthCell! case .deletePasswordCell: return deletePasswordCell! @@ -86,7 +93,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return tableData[section].count } - + override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return sectionHeaderTitles[section] } @@ -107,8 +114,41 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl tableView.deselectRow(at: indexPath, animated: true) } - func generatePassword() -> String { + // generate password, copy to pasteboard, and set the cell + func generateAndCopyPassword() { + // insert the length slider if not existed + if passwordLengthCell == nil { + let row = tableData[passwordSection].count + tableData[passwordSection].append([.type: PasswordEditorCellType.passwordLengthCell, .title: "passwordlength"]) + let indexPath = IndexPath(row: row, section: passwordSection) + tableView.insertRows(at: [indexPath], with: UITableViewRowAnimation.automatic) + } let length = passwordLengthCell?.roundedValue ?? Globals.passwordDefaultLength - return Utils.generatePassword(length: length) + let plainPassword = Utils.generatePassword(length: length) + Utils.copyToPasteboard(textToCopy: plainPassword) + fillPasswordCell?.setContent(content: plainPassword) + } + + func tableTapped(tap: UITapGestureRecognizer) { + let location = tap.location(in: self.tableView) + let path = self.tableView.indexPathForRow(at: location) + if path?.section != passwordSection, tableData[passwordSection].count > 1 { + // remove password settings (e.g., sliders) + let row = tableData[passwordSection].count + passwordLengthCell = nil + tableData[passwordSection].removeLast(row - 1) + let indexPaths = (1...row-1).map{IndexPath(row: $0, section: passwordSection)} + print(indexPaths) + tableView.deleteRows(at: indexPaths, with: UITableViewRowAnimation.automatic) + } + } + + func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { + if (gestureRecognizer is UITapGestureRecognizer) { + // so that the tap gesture could be passed by + return true + } else { + return false + } } } diff --git a/pass/Views/FillPasswordTableViewCell.swift b/pass/Views/FillPasswordTableViewCell.swift index 5e4eee1..b7a9ae0 100644 --- a/pass/Views/FillPasswordTableViewCell.swift +++ b/pass/Views/FillPasswordTableViewCell.swift @@ -9,7 +9,7 @@ import UIKit protocol FillPasswordTableViewCellDelegate { - func generatePassword() -> String + func generateAndCopyPassword() } class FillPasswordTableViewCell: ContentTableViewCell { @@ -30,9 +30,7 @@ class FillPasswordTableViewCell: ContentTableViewCell { } @IBAction func generatePassword(_ sender: UIButton) { - let plainPassword = self.delegate?.generatePassword() ?? Utils.generatePassword(length: 16) - self.setContent(content: plainPassword) - Utils.copyToPasteboard(textToCopy: plainPassword) + self.delegate?.generateAndCopyPassword() } override func getContent() -> String? { diff --git a/pass/Views/SliderTableViewCell.swift b/pass/Views/SliderTableViewCell.swift index 7de2c9d..a641c44 100644 --- a/pass/Views/SliderTableViewCell.swift +++ b/pass/Views/SliderTableViewCell.swift @@ -9,15 +9,21 @@ import UIKit +protocol PasswordSettingSliderTableViewCellDelegate { + func generateAndCopyPassword() +} + class SliderTableViewCell: ContentTableViewCell { @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var valueLabel: UILabel! @IBOutlet weak var slider: UISlider! + var delegate: UITableViewController? + var roundedValue: Int { get { - return Int(slider.value) + return Int(valueLabel.text!)! } } @@ -33,9 +39,17 @@ class SliderTableViewCell: ContentTableViewCell { } @IBAction func handleSliderValueChange(_ sender: UISlider) { - let roundedValue = round(sender.value) - sender.value = roundedValue - valueLabel.text = "\(Int(roundedValue))" + let oldRoundedValue = self.roundedValue + let newRoundedValue = Int(sender.value) + // proceed only when the rounded value gets updated + guard newRoundedValue != oldRoundedValue else { + return; + } + sender.value = Float(newRoundedValue) + valueLabel.text = "\(newRoundedValue)" + if let delegate: PasswordSettingSliderTableViewCellDelegate = self.delegate as? PasswordSettingSliderTableViewCellDelegate { + delegate.generateAndCopyPassword() + } } func reset(title: String, minimumValue: Int, maximumValue: Int, defaultValue: Int) { diff --git a/pass/Views/SliderTableViewCell.xib b/pass/Views/SliderTableViewCell.xib index 2d1a911..09698e8 100644 --- a/pass/Views/SliderTableViewCell.xib +++ b/pass/Views/SliderTableViewCell.xib @@ -13,20 +13,20 @@ - + - + - +