Add a cancel button to passcode lock of app extension

This commit is contained in:
Yishi Lin 2018-04-11 02:05:00 +08:00
parent 980b581295
commit 3f899a58d9
4 changed files with 97 additions and 6 deletions

View file

@ -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 */,

View file

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

View file

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

View 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
}
}
}