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:
Danny Mösch 2021-10-01 19:32:14 +02:00 committed by GitHub
parent 63e7235978
commit e1cbcb5d7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 155 additions and 76 deletions

View file

@ -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

View file

@ -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) {

View file

@ -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";

View file

@ -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";