Add notification action to copy OTP or just inform about the copied OTP (#513)
* Add notification action to copy OTP or just inform about the copied OTP The notification either shows the current OTP which can be copied by a notification action or it shows just a hint to inform about the copied OTP. This depends on the new option "autoCopyOTP". * Extract method * Set type and style one-time
This commit is contained in:
parent
63e7235978
commit
e1cbcb5d7a
11 changed files with 155 additions and 76 deletions
|
|
@ -28,6 +28,14 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
return uiSwitch
|
||||
}()
|
||||
|
||||
let autoCopyOTPSwitch: UISwitch = {
|
||||
let uiSwitch = UISwitch()
|
||||
uiSwitch.onTintColor = Colors.systemBlue
|
||||
uiSwitch.sizeToFit()
|
||||
uiSwitch.addTarget(self, action: #selector(autoCopyOTPSwitchAction(_:)), for: UIControl.Event.valueChanged)
|
||||
return uiSwitch
|
||||
}()
|
||||
|
||||
let rememberPGPPassphraseSwitch: UISwitch = {
|
||||
let uiSwitch = UISwitch()
|
||||
uiSwitch.onTintColor = Colors.systemBlue
|
||||
|
|
@ -91,6 +99,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
[.title: "HidePasswordImages".localize(), .action: "none"],
|
||||
[.title: "HideUnknownFields".localize(), .action: "none"],
|
||||
[.title: "HideOtpFields".localize(), .action: "none"],
|
||||
[.title: "AutoCopyOTP".localize(), .action: "none"],
|
||||
],
|
||||
]
|
||||
super.viewDidLoad()
|
||||
|
|
@ -98,71 +107,64 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = super.tableView(tableView, cellForRowAt: indexPath)
|
||||
cell.accessoryType = .none
|
||||
cell.selectionStyle = .none
|
||||
switch cell.textLabel!.text! {
|
||||
case "HideUnknownFields".localize():
|
||||
cell.accessoryType = .none
|
||||
let detailButton = UIButton(type: .detailDisclosure)
|
||||
hideUnknownSwitch.frame = CGRect(x: detailButton.bounds.width + 10, y: 0, width: hideUnknownSwitch.bounds.width, height: hideUnknownSwitch.bounds.height)
|
||||
detailButton.frame = CGRect(x: 0, y: 5, width: detailButton.bounds.width, height: detailButton.bounds.height)
|
||||
detailButton.addTarget(self, action: #selector(GeneralSettingsTableViewController.tapHideUnknownSwitchDetailButton(_:)), for: UIControl.Event.touchDown)
|
||||
let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hideUnknownSwitch.bounds.width + 10, height: cell.contentView.bounds.height))
|
||||
accessoryView.addSubview(detailButton)
|
||||
accessoryView.addSubview(hideUnknownSwitch)
|
||||
hideUnknownSwitch.center.y = accessoryView.center.y
|
||||
detailButton.center.y = accessoryView.center.y
|
||||
cell.accessoryView = accessoryView
|
||||
cell.selectionStyle = .none
|
||||
hideUnknownSwitch.isOn = Defaults.isHideUnknownOn
|
||||
addDetailButton(to: cell, for: hideUnknownSwitch, with: #selector(tapHideUnknownSwitchDetailButton))
|
||||
case "HideOtpFields".localize():
|
||||
cell.accessoryType = .none
|
||||
let detailButton = UIButton(type: .detailDisclosure)
|
||||
hideOTPSwitch.frame = CGRect(x: detailButton.bounds.width + 10, y: 0, width: hideOTPSwitch.bounds.width, height: hideOTPSwitch.bounds.height)
|
||||
detailButton.frame = CGRect(x: 0, y: 5, width: detailButton.bounds.width, height: detailButton.bounds.height)
|
||||
detailButton.addTarget(self, action: #selector(GeneralSettingsTableViewController.tapHideOTPSwitchDetailButton(_:)), for: UIControl.Event.touchDown)
|
||||
let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hideOTPSwitch.bounds.width + 10, height: cell.contentView.bounds.height))
|
||||
accessoryView.addSubview(detailButton)
|
||||
accessoryView.addSubview(hideOTPSwitch)
|
||||
hideOTPSwitch.center.y = accessoryView.center.y
|
||||
detailButton.center.y = accessoryView.center.y
|
||||
cell.accessoryView = accessoryView
|
||||
cell.selectionStyle = .none
|
||||
hideOTPSwitch.isOn = Defaults.isHideOTPOn
|
||||
addDetailButton(to: cell, for: hideOTPSwitch, with: #selector(tapHideOTPSwitchDetailButton))
|
||||
case "RememberPgpKeyPassphrase".localize():
|
||||
cell.accessoryType = .none
|
||||
cell.selectionStyle = .none
|
||||
cell.accessoryView = rememberPGPPassphraseSwitch
|
||||
case "RememberGitCredentialPassphrase".localize():
|
||||
cell.accessoryType = .none
|
||||
cell.selectionStyle = .none
|
||||
cell.accessoryView = rememberGitCredentialPassphraseSwitch
|
||||
case "ShowFolders".localize():
|
||||
cell.accessoryType = .none
|
||||
cell.selectionStyle = .none
|
||||
cell.accessoryView = showFolderSwitch
|
||||
case "EnableGPGID".localize():
|
||||
cell.accessoryType = .none
|
||||
cell.selectionStyle = .none
|
||||
cell.accessoryView = enableGPGIDSwitch
|
||||
case "HidePasswordImages".localize():
|
||||
cell.accessoryType = .none
|
||||
let detailButton = UIButton(type: .detailDisclosure)
|
||||
hidePasswordImagesSwitch.frame = CGRect(x: detailButton.bounds.width + 10, y: 0, width: hidePasswordImagesSwitch.bounds.width, height: hidePasswordImagesSwitch.bounds.height)
|
||||
detailButton.frame = CGRect(x: 0, y: 5, width: detailButton.bounds.width, height: detailButton.bounds.height)
|
||||
detailButton.addTarget(self, action: #selector(GeneralSettingsTableViewController.tapHidePasswordImagesSwitchDetailButton(_:)), for: UIControl.Event.touchDown)
|
||||
let accessoryView = UIView(frame: CGRect(x: 0, y: 0, width: detailButton.bounds.width + hidePasswordImagesSwitch.bounds.width + 10, height: cell.contentView.bounds.height))
|
||||
accessoryView.addSubview(detailButton)
|
||||
accessoryView.addSubview(hidePasswordImagesSwitch)
|
||||
hidePasswordImagesSwitch.center.y = accessoryView.center.y
|
||||
detailButton.center.y = accessoryView.center.y
|
||||
cell.accessoryView = accessoryView
|
||||
cell.selectionStyle = .none
|
||||
hidePasswordImagesSwitch.isOn = Defaults.isHidePasswordImagesOn
|
||||
addDetailButton(to: cell, for: hidePasswordImagesSwitch, with: #selector(tapHidePasswordImagesSwitchDetailButton))
|
||||
case "AutoCopyOTP".localize():
|
||||
autoCopyOTPSwitch.isOn = Defaults.autoCopyOTP
|
||||
addDetailButton(to: cell, for: autoCopyOTPSwitch, with: #selector(tapAutoCopyOTPSwitchDetailButton))
|
||||
default:
|
||||
break
|
||||
}
|
||||
return cell
|
||||
}
|
||||
|
||||
private func addDetailButton(to cell: UITableViewCell, for uiSwitch: UISwitch, with action: Selector) {
|
||||
let detailButton = UIButton(type: .detailDisclosure)
|
||||
uiSwitch.frame = CGRect(
|
||||
x: detailButton.bounds.width + 10,
|
||||
y: 0,
|
||||
width: uiSwitch.bounds.width,
|
||||
height: uiSwitch.bounds.height
|
||||
)
|
||||
detailButton.frame = CGRect(
|
||||
x: 0,
|
||||
y: 5,
|
||||
width: detailButton.bounds.width,
|
||||
height: detailButton.bounds.height
|
||||
)
|
||||
detailButton.addTarget(self, action: action, for: UIControl.Event.touchDown)
|
||||
let accessoryViewFrame = CGRect(
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: detailButton.bounds.width + uiSwitch.bounds.width + 10,
|
||||
height: cell.contentView.bounds.height
|
||||
)
|
||||
let accessoryView = UIView(frame: accessoryViewFrame)
|
||||
accessoryView.addSubview(detailButton)
|
||||
accessoryView.addSubview(uiSwitch)
|
||||
uiSwitch.center.y = accessoryView.center.y
|
||||
detailButton.center.y = accessoryView.center.y
|
||||
cell.accessoryView = accessoryView
|
||||
}
|
||||
|
||||
@objc
|
||||
func tapHideUnknownSwitchDetailButton(_: Any?) {
|
||||
let alertMessage = "HideUnknownFieldsExplanation.".localize()
|
||||
|
|
@ -178,6 +180,13 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
||||
}
|
||||
|
||||
@objc
|
||||
func tapAutoCopyOTPSwitchDetailButton(_: Any?) {
|
||||
let alertMessage = "AutoCopyOTPExplanation.".localize()
|
||||
let alertTitle = "AutoCopyOTP".localize()
|
||||
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
|
||||
}
|
||||
|
||||
@objc
|
||||
func tapHidePasswordImagesSwitchDetailButton(_: Any?) {
|
||||
let alertMessage = "HidePasswordImagesExplanation.".localize()
|
||||
|
|
@ -197,6 +206,11 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
|||
NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil)
|
||||
}
|
||||
|
||||
@objc
|
||||
func autoCopyOTPSwitchAction(_: Any?) {
|
||||
Defaults.autoCopyOTP = autoCopyOTPSwitch.isOn
|
||||
}
|
||||
|
||||
@objc
|
||||
func rememberPGPPassphraseSwitchAction(_: Any?) {
|
||||
Defaults.isRememberPGPPassphraseOn = rememberPGPPassphraseSwitch.isOn
|
||||
|
|
|
|||
|
|
@ -80,8 +80,26 @@ class PasswordNavigationViewController: UIViewController {
|
|||
}
|
||||
|
||||
private func requestNotificationPermission() {
|
||||
// Ask for permission to receive notifications
|
||||
let notificationCenter = UNUserNotificationCenter.current()
|
||||
let permissionOptions = UNAuthorizationOptions(arrayLiteral: .alert)
|
||||
UNUserNotificationCenter.current().requestAuthorization(options: permissionOptions) { _, _ in }
|
||||
notificationCenter.requestAuthorization(options: permissionOptions) { _, _ in }
|
||||
|
||||
// Register notification action
|
||||
let copyAction = UNNotificationAction(
|
||||
identifier: Globals.otpNotificationCopyAction,
|
||||
title: "CopyToPasteboard".localize(),
|
||||
options: UNNotificationActionOptions(rawValue: 0)
|
||||
)
|
||||
let otpCategory = UNNotificationCategory(
|
||||
identifier: Globals.otpNotificationCategory,
|
||||
actions: [copyAction],
|
||||
intentIdentifiers: [],
|
||||
hiddenPreviewsBodyPlaceholder: "",
|
||||
options: []
|
||||
)
|
||||
notificationCenter.setNotificationCategories([otpCategory])
|
||||
notificationCenter.delegate = NotificationCenterDispatcher.shared
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
|
|
|
|||
|
|
@ -18,11 +18,15 @@
|
|||
"Contributors" = "Mitwirkende";
|
||||
|
||||
// OTP related
|
||||
"TimeBased" = "Zeitbasiert";
|
||||
"HmacBased" = "HMAC-basiert";
|
||||
"None" = "Kein valides Token";
|
||||
"ExpiresIn" = "(läuft in %ds ab)";
|
||||
"OTPFor" = "Einmalpasswort für %@";
|
||||
"TimeBased" = "Zeitbasiert";
|
||||
"HmacBased" = "HMAC-basiert";
|
||||
"None" = "Kein valides Token";
|
||||
"ExpiresIn" = "(läuft in %ds ab)";
|
||||
"OTPForPassword" = "Einmalpasswort für %@";
|
||||
"OTPForPasswordCopied" = "Einmalpasswort für %@ kopiert";
|
||||
"CopyToPasteboard" = "In Zwischenablage kopieren";
|
||||
"AutoCopyOTP" = "OTPs automatisch kopieren";
|
||||
"AutoCopyOTPExplanation." = "Nachdem Login und Passwort automatisch in die vorgesehenen Felder gefüllt wurden, wird eine Benachrichtigung mit dem aktuellen Einmalpasswort angezeigt. Dieses kann in die Zwischenablage kopiert werden. Ist diese Option aktiviert, geschieht das Kopieren automatisch.";
|
||||
|
||||
// General (error) messages
|
||||
"Error" = "Fehler";
|
||||
|
|
|
|||
|
|
@ -18,11 +18,15 @@
|
|||
"Contributors" = "Contributors";
|
||||
|
||||
// OTP related
|
||||
"TimeBased" = "time-based";
|
||||
"HmacBased" = "HMAC-based";
|
||||
"None" = "None";
|
||||
"ExpiresIn" = "(expires in %ds)";
|
||||
"OTPFor" = "One-time Password for %@";
|
||||
"TimeBased" = "time-based";
|
||||
"HmacBased" = "HMAC-based";
|
||||
"None" = "None";
|
||||
"ExpiresIn" = "(expires in %ds)";
|
||||
"OTPForPassword" = "One-time password for %@";
|
||||
"OTPForPasswordCopied" = "One-time password for %@ copied";
|
||||
"CopyToPasteboard" = "Copy to pasteboard";
|
||||
"AutoCopyOTP" = "Automatically Copy OTPs";
|
||||
"AutoCopyOTPExplanation." = "After username and password have been auto-filled into a form by Pass, a notification is shown with the current one-time password which can be copied to the pasteboard. Enabling this option automatically copies the current one-time password.";
|
||||
|
||||
// General (error) messages
|
||||
"Error" = "Error";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue