Add a cancel button to passcode lock of app extension
This commit is contained in:
parent
980b581295
commit
3f899a58d9
4 changed files with 97 additions and 6 deletions
|
|
@ -38,6 +38,7 @@
|
|||
A2A61C201EEFABAD00CFE063 /* UtilsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A61C1F1EEFABAD00CFE063 /* UtilsExtension.swift */; };
|
||||
A2A61C2C1EEFDF3300CFE063 /* ExtensionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A61C2B1EEFDF3300CFE063 /* ExtensionViewController.swift */; };
|
||||
A2A7813F1E97DBD9001311F5 /* QRScannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A7813E1E97DBD9001311F5 /* QRScannerController.swift */; };
|
||||
A2BEC1BB207D2EFE00F3051C /* UIViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2BEC1BA207D2EFE00F3051C /* UIViewExtension.swift */; };
|
||||
A2C532BB201E5A9600DB9F53 /* PasscodeLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2C532BA201E5A9600DB9F53 /* PasscodeLock.swift */; };
|
||||
A2C532BE201E5AA100DB9F53 /* PasscodeLockViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2C532BC201E5AA000DB9F53 /* PasscodeLockViewController.swift */; };
|
||||
A2C532BF201E5AA100DB9F53 /* PasscodeLockPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2C532BD201E5AA100DB9F53 /* PasscodeLockPresenter.swift */; };
|
||||
|
|
@ -200,6 +201,7 @@
|
|||
A2A61C2B1EEFDF3300CFE063 /* ExtensionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionViewController.swift; sourceTree = "<group>"; };
|
||||
A2A7813E1E97DBD9001311F5 /* QRScannerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRScannerController.swift; sourceTree = "<group>"; };
|
||||
A2BC54C71EEE5669001FAFBD /* Objective-CBridgingHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Objective-CBridgingHeader.h"; sourceTree = "<group>"; };
|
||||
A2BEC1BA207D2EFE00F3051C /* UIViewExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = UIViewExtension.swift; path = Helpers/UIViewExtension.swift; sourceTree = "<group>"; };
|
||||
A2C532BA201E5A9600DB9F53 /* PasscodeLock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PasscodeLock.swift; path = Models/PasscodeLock.swift; sourceTree = "<group>"; };
|
||||
A2C532BC201E5AA000DB9F53 /* PasscodeLockViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PasscodeLockViewController.swift; path = Controllers/PasscodeLockViewController.swift; sourceTree = "<group>"; };
|
||||
A2C532BD201E5AA100DB9F53 /* PasscodeLockPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PasscodeLockPresenter.swift; path = Controllers/PasscodeLockPresenter.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -410,6 +412,7 @@
|
|||
A2F4E21B1EED80160011986E /* NotificationNames.swift */,
|
||||
A2F4E21C1EED80160011986E /* UITextFieldExtension.swift */,
|
||||
A2F4E21D1EED80160011986E /* Utils.swift */,
|
||||
A2BEC1BA207D2EFE00F3051C /* UIViewExtension.swift */,
|
||||
);
|
||||
name = Helpers;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -1032,6 +1035,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A2BEC1BB207D2EFE00F3051C /* UIViewExtension.swift in Sources */,
|
||||
A2C532BB201E5A9600DB9F53 /* PasscodeLock.swift in Sources */,
|
||||
A2F4E2151EED800F0011986E /* Password.swift in Sources */,
|
||||
A26075AD1EEC7125005DB03E /* pass.xcdatamodeld in Sources */,
|
||||
|
|
|
|||
|
|
@ -9,15 +9,35 @@
|
|||
import Foundation
|
||||
import passKit
|
||||
|
||||
// cancel means cancel the extension
|
||||
class PasscodeLockViewControllerForExtension: PasscodeLockViewController {
|
||||
var originalExtensionContest: NSExtensionContext?
|
||||
public convenience init(extensionContext: NSExtensionContext?) {
|
||||
self.init()
|
||||
originalExtensionContest = extensionContext
|
||||
}
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
cancelButton?.removeTarget(nil, action: nil, for: .allEvents)
|
||||
cancelButton?.addTarget(self, action: #selector(cancelExtension), for: .touchUpInside)
|
||||
}
|
||||
@objc func cancelExtension() {
|
||||
originalExtensionContest?.completeRequest(returningItems: [], completionHandler: nil)
|
||||
}
|
||||
}
|
||||
|
||||
class PasscodeExtensionDisplay {
|
||||
private var isPasscodePresented = false
|
||||
private let passcodeLockVC: PasscodeLockViewController
|
||||
private let passcodeLockVC: PasscodeLockViewControllerForExtension
|
||||
private let extensionContext: NSExtensionContext?
|
||||
|
||||
init(extensionContext: NSExtensionContext?) {
|
||||
passcodeLockVC = PasscodeLockViewController()
|
||||
self.extensionContext = extensionContext
|
||||
passcodeLockVC = PasscodeLockViewControllerForExtension(extensionContext: extensionContext)
|
||||
passcodeLockVC.dismissCompletionCallback = { [weak self] in
|
||||
self?.dismiss()
|
||||
}
|
||||
passcodeLockVC.setCancellable(true)
|
||||
}
|
||||
|
||||
// present the passcode lock view if passcode is set and the view controller is not presented
|
||||
|
|
|
|||
|
|
@ -21,8 +21,10 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate {
|
|||
weak var passcodeWrongAttemptsLabel: UILabel?
|
||||
weak var passcodeTextField: UITextField?
|
||||
weak var biometryAuthButton: UIButton?
|
||||
open weak var cancelButton: UIButton?
|
||||
|
||||
var passcodeFailedAttempts = 0
|
||||
var isCancellable: Bool = false
|
||||
|
||||
open override func loadView() {
|
||||
super.loadView()
|
||||
|
|
@ -80,6 +82,16 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
let cancelButton = UIButton(type: .custom)
|
||||
cancelButton.setTitle("Cancel", for: .normal)
|
||||
cancelButton.setTitleColor(Globals.blue, for: .normal)
|
||||
cancelButton.addTarget(self, action: #selector(passcodeLockDidCancel), for: .touchUpInside)
|
||||
cancelButton.isHidden = !self.isCancellable
|
||||
cancelButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
cancelButton.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left
|
||||
self.view.addSubview(cancelButton)
|
||||
self.cancelButton = cancelButton
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
passcodeTextField.widthAnchor.constraint(equalToConstant: 300),
|
||||
passcodeTextField.heightAnchor.constraint(equalToConstant: 40),
|
||||
|
|
@ -99,7 +111,12 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate {
|
|||
biometryAuthButton.widthAnchor.constraint(equalToConstant: 150),
|
||||
biometryAuthButton.heightAnchor.constraint(equalToConstant: 40),
|
||||
biometryAuthButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
|
||||
biometryAuthButton.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -40),
|
||||
biometryAuthButton.bottomAnchor.constraint(equalTo: self.view.safeBottomAnchor, constant: -40),
|
||||
// cancel (top-left of the screen)
|
||||
cancelButton.widthAnchor.constraint(equalToConstant: 150),
|
||||
cancelButton.heightAnchor.constraint(equalToConstant: 40),
|
||||
cancelButton.topAnchor.constraint(equalTo: self.view.safeTopAnchor),
|
||||
cancelButton.leftAnchor.constraint(equalTo: self.view.safeLeftAnchor, constant: 20)
|
||||
])
|
||||
|
||||
}
|
||||
|
|
@ -144,11 +161,11 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate {
|
|||
dismissPasscodeLock(completionHandler: successCallback)
|
||||
}
|
||||
|
||||
open func passcodeLockDidCancel() {
|
||||
@objc func passcodeLockDidCancel() {
|
||||
dismissPasscodeLock(completionHandler: cancelCallback)
|
||||
}
|
||||
|
||||
@objc public func bioButtonPressedAction(_ uiButton: UIButton) {
|
||||
@objc func bioButtonPressedAction(_ uiButton: UIButton) {
|
||||
let myContext = LAContext()
|
||||
let myLocalizedReasonString = "Authentication is needed to access Pass."
|
||||
var authError: NSError?
|
||||
|
|
@ -182,9 +199,14 @@ open class PasscodeLockViewController: UIViewController, UITextFieldDelegate {
|
|||
return true
|
||||
}
|
||||
|
||||
@objc public func passcodeTextFieldDidChange(_ textField: UITextField) {
|
||||
@objc func passcodeTextFieldDidChange(_ textField: UITextField) {
|
||||
if PasscodeLock.shared.check(passcode: textField.text ?? "") {
|
||||
self.passcodeLockDidSucceed()
|
||||
}
|
||||
}
|
||||
|
||||
public func setCancellable(_ isCancellable: Bool) {
|
||||
self.isCancellable = isCancellable
|
||||
cancelButton?.isHidden = !isCancellable
|
||||
}
|
||||
}
|
||||
|
|
|
|||
45
passKit/Helpers/UIViewExtension.swift
Normal file
45
passKit/Helpers/UIViewExtension.swift
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// UIViewExtension.swift
|
||||
// passKit
|
||||
//
|
||||
// Created by Yishi Lin on 2018/4/11.
|
||||
// Copyright © 2018 Yishi Lin. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension UIView {
|
||||
|
||||
// Save anchors: https://stackoverflow.com/questions/46317061/use-safe-area-layout-programmatically
|
||||
var safeTopAnchor: NSLayoutYAxisAnchor {
|
||||
if #available(iOS 11.0, *) {
|
||||
return self.safeAreaLayoutGuide.topAnchor
|
||||
} else {
|
||||
return self.topAnchor
|
||||
}
|
||||
}
|
||||
|
||||
var safeLeftAnchor: NSLayoutXAxisAnchor {
|
||||
if #available(iOS 11.0, *){
|
||||
return self.safeAreaLayoutGuide.leftAnchor
|
||||
} else {
|
||||
return self.leftAnchor
|
||||
}
|
||||
}
|
||||
|
||||
var safeRightAnchor: NSLayoutXAxisAnchor {
|
||||
if #available(iOS 11.0, *){
|
||||
return self.safeAreaLayoutGuide.rightAnchor
|
||||
} else {
|
||||
return self.rightAnchor
|
||||
}
|
||||
}
|
||||
|
||||
var safeBottomAnchor: NSLayoutYAxisAnchor {
|
||||
if #available(iOS 11.0, *) {
|
||||
return self.safeAreaLayoutGuide.bottomAnchor
|
||||
} else {
|
||||
return self.bottomAnchor
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue