Commit 24684741 authored by ueshiba's avatar ueshiba
Browse files

Show QR Scanner view and update textfield when the gift code is found

Show button to dismiss QR Scanner view
Refactor error messages for the camera
parent e3f07bc3
......@@ -240,6 +240,7 @@
0EFEB4C420077AC900F81029 /* PIATunnelProvider+Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EFEB4BF2007784A00F81029 /* PIATunnelProvider+Profile.swift */; };
0EFEB4C520077AC900F81029 /* PIATunnelProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EFEB4C02007784A00F81029 /* PIATunnelProfile.swift */; };
5EA54E484C7FD035341E021E /* Pods_PIALibrary_PIALibraryTests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A22DD34A821A4EDAED288D2 /* Pods_PIALibrary_PIALibraryTests_iOS.framework */; };
841BE60D212AD0F3002EF2D1 /* ValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841BE60C212AD0F3002EF2D1 /* ValidatorTests.swift */; };
843C67C22122E714005A3FDA /* AccountInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843C67C12122E714005A3FDA /* AccountInfoTests.swift */; };
843C67C32122EA13005A3FDA /* AccountInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843C67C12122E714005A3FDA /* AccountInfoTests.swift */; };
84D5DA702126CE2900F753F8 /* QRCameraScannerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D5DA6F2126CE2900F753F8 /* QRCameraScannerViewController.swift */; };
......@@ -482,6 +483,7 @@
378AC49FB4E07B2415156492 /* Pods-PIALibrary-PIALibraryTests-iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PIALibrary-PIALibraryTests-iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-PIALibrary-PIALibraryTests-iOS/Pods-PIALibrary-PIALibraryTests-iOS.release.xcconfig"; sourceTree = "<group>"; };
476E8514A236C48F405ACA40 /* Pods_PIALibrary_PIALibraryHost_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PIALibrary_PIALibraryHost_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
64C04C071DE1CB44DE7945D6 /* Pods-PIALibrary-PIALibrary-iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PIALibrary-PIALibrary-iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PIALibrary-PIALibrary-iOS/Pods-PIALibrary-PIALibrary-iOS.debug.xcconfig"; sourceTree = "<group>"; };
841BE60C212AD0F3002EF2D1 /* ValidatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorTests.swift; sourceTree = "<group>"; };
843C67C12122E714005A3FDA /* AccountInfoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountInfoTests.swift; sourceTree = "<group>"; };
84D5DA6F2126CE2900F753F8 /* QRCameraScannerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCameraScannerViewController.swift; sourceTree = "<group>"; };
9A22DD34A821A4EDAED288D2 /* Pods_PIALibrary_PIALibraryTests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PIALibrary_PIALibraryTests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
......@@ -917,6 +919,7 @@
0EA4C4411FDDFD830041C3D8 /* ServerTests.swift */,
0E2ADD441FE1583A00BB170C /* VPNTests.swift */,
843C67C12122E714005A3FDA /* AccountInfoTests.swift */,
841BE60C212AD0F3002EF2D1 /* ValidatorTests.swift */,
0EE78B011F818A20002E4CDD /* Info-iOS.plist */,
0E2ADD201FE13B8600BB170C /* Info-macOS.plist */,
);
......@@ -1575,6 +1578,7 @@
buildActionMask = 2147483647;
files = (
0E53A85A1FE5E3CD000C2A18 /* MockProviders.swift in Sources */,
841BE60D212AD0F3002EF2D1 /* ValidatorTests.swift in Sources */,
843C67C22122E714005A3FDA /* AccountInfoTests.swift in Sources */,
0EE78B001F818A20002E4CDD /* AccountTests.swift in Sources */,
0EA4C4421FDDFD840041C3D8 /* ServerTests.swift in Sources */,
......
......@@ -1375,9 +1375,25 @@ You will not be charged during this process.</string>
<view key="view" contentMode="scaleToFill" id="ep7-uG-1hN">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="xjW-oD-kRx">
<rect key="frame" x="19" y="39" width="126" height="87"/>
<state key="normal" backgroundImage="image-account-failed"/>
<connections>
<action selector="dismissView:" destination="hSc-7t-RTF" eventType="touchUpInside" id="6rL-tJ-P3p"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="xjW-oD-kRx" firstAttribute="top" secondItem="bb6-gq-GN1" secondAttribute="top" constant="19" id="PSn-O5-oZX"/>
<constraint firstItem="xjW-oD-kRx" firstAttribute="leading" secondItem="bb6-gq-GN1" secondAttribute="leading" constant="19" id="e3d-hl-FCD"/>
</constraints>
<viewLayoutGuide key="safeArea" id="bb6-gq-GN1"/>
</view>
<connections>
<outlet property="closeButton" destination="xjW-oD-kRx" id="nl4-yD-KQR"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="GlS-xa-MJS" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
......@@ -1385,6 +1401,7 @@ You will not be charged during this process.</string>
</scene>
</scenes>
<resources>
<image name="image-account-failed" width="126" height="87"/>
<image name="nav-logo" width="354" height="36"/>
</resources>
<inferredMetricsTieBreakers>
......
......@@ -61,3 +61,4 @@
"camera.access.error.title" = "Camera not available";
"camera.access.error.message" = "Your device does not support scanning a code. Please use a device with a camera.";
"camera.access.denied.message" = "Please grant permission to use the Camera.";
......@@ -10,7 +10,9 @@ import AVFoundation
import UIKit
class QRCameraScannerViewController: AutolayoutViewController {
@IBOutlet private weak var closeButton: UIButton!
var captureSession: AVCaptureSession!
var previewLayer: AVCaptureVideoPreviewLayer!
weak var delegate: RedeemScannerDelegate!
......@@ -45,6 +47,14 @@ class QRCameraScannerViewController: AutolayoutViewController {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
@IBAction private func dismissView(_ sender: Any?) {
dismissModal()
}
private func setupCaptureSession() {
captureSession = AVCaptureSession()
......@@ -84,21 +94,20 @@ class QRCameraScannerViewController: AutolayoutViewController {
}
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer.frame = view.layer.bounds
previewLayer.frame = UIScreen.main.bounds
previewLayer.videoGravity = .resizeAspectFill
view.layer.addSublayer(previewLayer)
view.bringSubview(toFront: closeButton)
captureSession.startRunning()
}
private func found(code: String) {
delegate.giftCardCodeFound(withCode: code)
}
private func failed() {
captureSession = nil
dismissModal()
dismiss(animated: true) { [weak self] in
self?.delegate.errorFound()
}
}
}
......@@ -109,6 +118,7 @@ extension QRCameraScannerViewController: AVCaptureMetadataOutputObjectsDelegate
didOutput metadataObjects: [AVMetadataObject],
from connection: AVCaptureConnection) {
captureSession.stopRunning()
var code = ""
if let metadataObject = metadataObjects.first {
guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else {
return
......@@ -116,11 +126,13 @@ extension QRCameraScannerViewController: AVCaptureMetadataOutputObjectsDelegate
guard let stringValue = readableObject.stringValue else {
return
}
code = stringValue
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
found(code: stringValue)
}
dismiss(animated: true)
dismiss(animated: true) { [weak self] in
self?.delegate.giftCardCodeFound(withCode: code)
}
}
}
......@@ -14,6 +14,7 @@ private let log = SwiftyBeaver.self
protocol RedeemScannerDelegate: class {
func giftCardCodeFound(withCode code: String)
func errorFound()
}
class RedeemViewController: AutolayoutViewController, WelcomeChild {
......@@ -117,21 +118,15 @@ class RedeemViewController: AutolayoutViewController, WelcomeChild {
}
guard let email = textEmail.text?.trimmed(), Validator.validate(email: email) else {
let alert = Macros.alert(
L10n.Welcome.Redeem.Error.title,
L10n.Welcome.Purchase.Error.validation
)
alert.addCancelAction(L10n.Ui.Global.ok)
present(alert, animated: true, completion: nil)
presentAlertWith(title: L10n.Welcome.Redeem.Error.title,
andMessage: L10n.Welcome.Purchase.Error.validation,
andButtonTitle: L10n.Ui.Global.ok)
return
}
guard let code = redeemCode?.trimmed(), Validator.validate(giftCode: code) else {
let alert = Macros.alert(
L10n.Welcome.Redeem.Error.title,
L10n.Welcome.Redeem.Error.code(RedeemViewController.codeLength)
)
alert.addCancelAction(L10n.Ui.Global.ok)
present(alert, animated: true, completion: nil)
presentAlertWith(title: L10n.Welcome.Redeem.Error.title,
andMessage: L10n.Welcome.Redeem.Error.code(RedeemViewController.codeLength),
andButtonTitle: L10n.Ui.Global.ok)
return
}
......@@ -153,16 +148,19 @@ class RedeemViewController: AutolayoutViewController, WelcomeChild {
@IBAction private func showCameraToScanQRCodes(_ sender: Any?) {
AVCaptureDevice.requestAccess(for: AVMediaType.video) { response in
if response {
DispatchQueue.main.async {
self.perform(segue: StoryboardSegue.Welcome.signupQRCameraScannerSegue)
if AVCaptureDevice.authorizationStatus(for: AVMediaType.video) == .denied {
presentAlertWith(title: L10n.Welcome.Camera.Access.Error.title,
andMessage: L10n.Welcome.Camera.Access.Denied.message,
andButtonTitle: L10n.Ui.Global.close)
} else {
AVCaptureDevice.requestAccess(for: AVMediaType.video) { response in
if response {
DispatchQueue.main.async {
self.perform(segue: StoryboardSegue.Welcome.signupQRCameraScannerSegue)
}
} else {
self.errorFound()
}
} else {
let alert = Macros.alert(L10n.Welcome.Camera.Access.Error.title,
L10n.Welcome.Camera.Access.Error.message)
alert.addCancelAction(L10n.Ui.Global.close)
self.present(alert, animated: true)
}
}
......@@ -198,6 +196,19 @@ class RedeemViewController: AutolayoutViewController, WelcomeChild {
}
}
private func presentAlertWith(title: String,
andMessage message: String,
andButtonTitle buttonTitle: String ) {
let alert = Macros.alert(title,
message)
alert.addCancelAction(buttonTitle)
present(alert,
animated: true,
completion: nil)
}
private func enableInteractions(_ enable: Bool) {
parent?.view.isUserInteractionEnabled = enable
......@@ -291,11 +302,16 @@ extension RedeemViewController: RedeemScannerDelegate {
if Validator.validate(giftCode: code) {
textCode.text = friendlyRedeemCode(code)
} else {
let alert = Macros.alert(L10n.Welcome.Redeem.Error.title,
L10n.Welcome.Redeem.Error.Qrcode.invalid)
alert.addCancelAction(L10n.Ui.Global.ok)
self.present(alert, animated: true)
presentAlertWith(title: L10n.Welcome.Redeem.Error.title,
andMessage: L10n.Welcome.Redeem.Error.Qrcode.invalid,
andButtonTitle:L10n.Ui.Global.ok)
}
}
func errorFound() {
presentAlertWith(title: L10n.Welcome.Camera.Access.Error.title,
andMessage: L10n.Welcome.Camera.Access.Error.message,
andButtonTitle:L10n.Ui.Global.close)
}
}
......@@ -199,7 +199,11 @@ enum L10n {
static let title = L10n.tr("Welcome", "camera.access.error.title")
/// Your device does not support scanning a code. Please use a device with a camera.
static let message = L10n.tr("Welcome", "camera.access.error.message")
}
enum Denied {
/// Please grant permission to use the Camera.
static let message = L10n.tr("Welcome", "camera.access.denied.message")
}
}
}
......
//
// ValidatorTests.swift
// PIALibraryTests-iOS
//
// Created by Jose Antonio Blaya Garcia on 20/8/18.
// Copyright © 2018 London Trust Media. All rights reserved.
//
import XCTest
@testable import PIALibrary
class ValidatorTests: XCTestCase {
func testValidatorGiftCardIsValid() {
let giftCode = "1234567812345678"
XCTAssertTrue(Validator.validate(giftCode: giftCode))
}
func testValidatorGiftCardIsInvalid() {
let giftCode = "12345678678"
XCTAssertFalse(Validator.validate(giftCode: giftCode))
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment