mirror of
https://github.com/AU-COVIDSafe/mobile-ios.git
synced 2025-04-05 06:14:59 +00:00
249 lines
11 KiB
Swift
249 lines
11 KiB
Swift
// Copyright © 2020 Australian Government All rights reserved.
|
|
import SafariServices
|
|
import UIKit
|
|
import FlagKit
|
|
|
|
class PhoneNumberViewController: UIViewController, UITextFieldDelegate, RegistrationHandler, CountrySelectionDelegate {
|
|
|
|
@IBOutlet weak var phoneNumberField: UITextField!
|
|
@IBOutlet weak var countryCodeField: UITextField!
|
|
@IBOutlet weak var getOTPButton: UIButton!
|
|
@IBOutlet weak var titleLabel: UILabel!
|
|
@IBOutlet weak var phoneExample: UILabel!
|
|
@IBOutlet weak var phoneError: UILabel!
|
|
@IBOutlet weak var phoneLabel: UILabel!
|
|
@IBOutlet weak var stepCounterLabel: UILabel!
|
|
@IBOutlet weak var backButton: UIButton!
|
|
var countryFlagContainerView: UIView!
|
|
var flagImageView: UIImageView!
|
|
|
|
let PHONE_NUMBER_LENGTH = 17 // e.g. "+61 4 12 345 678 " if text is auto-pasted from text message
|
|
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
|
|
var selectedCountry: Country?
|
|
var countryList: [String] = CountriesData.countryArray
|
|
// If this view is part of the reauthentiation flow of an expired JWT
|
|
var reauthenticating: Bool = false
|
|
var registrationInfo: RegistrationRequest?
|
|
var initialLabelTextColour: UIColor?
|
|
var initialTextFieldBorderColour: UIColor?
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
self.phoneNumberField.addTarget(self, action: #selector(self.phoneNumberFieldDidChange), for: UIControl.Event.editingChanged)
|
|
self.phoneNumberFieldDidChange()
|
|
phoneNumberField.delegate = self
|
|
dismissKeyboardOnTap()
|
|
if (reauthenticating) {
|
|
self.titleLabel.text = "EnterPhoneReVerify".localizedString(comment: "Enter your mobile number to re-verify")
|
|
}
|
|
countryCodeField.text = "(+61) " + "country_region_name_au".localizedString()
|
|
countryCodeField.accessibilityValue = String.init(format: "SelectedCountryTemplate".localizedString(), "61", "country_region_name_au".localizedString())
|
|
|
|
let toolBar = UIToolbar()
|
|
toolBar.sizeToFit()
|
|
let nextBarButtonItem = UIBarButtonItem(title: "Done".localizedString(),
|
|
style: .plain,
|
|
target: self,
|
|
action: #selector(self.dismissKeyboard))
|
|
let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
|
|
toolBar.setItems([spacer, nextBarButtonItem], animated: true)
|
|
toolBar.isUserInteractionEnabled = true
|
|
self.phoneNumberField.inputAccessoryView = toolBar
|
|
|
|
// Set initial Country img
|
|
countryFlagContainerView = UIView(frame: CGRect(x: 0, y: 0, width: 60, height: 24))
|
|
let flag = Flag(countryCode: "AU")!
|
|
let flagImage = flag.originalImage
|
|
flagImageView = UIImageView(frame: CGRect(x: 0, y: 2, width: 28, height: 20))
|
|
flagImageView.contentMode = .scaleAspectFit
|
|
flagImageView.image = flagImage
|
|
countryFlagContainerView.addSubview(flagImageView)
|
|
|
|
// Set View
|
|
let chevronImg = UIImage(named: "ChevronRight")
|
|
let chevronImgView = UIImageView(frame: CGRect(x: 32, y: 0, width: 24, height: 24))
|
|
if UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft {
|
|
// change frame of the chevron and flag
|
|
chevronImgView.frame = CGRect(x: 0, y: 0, width: 24, height: 24)
|
|
flagImageView.frame = CGRect(x: 28, y: 2, width: 28, height: 20)
|
|
}
|
|
chevronImgView.image = chevronImg
|
|
countryFlagContainerView.addSubview(chevronImgView)
|
|
|
|
countryCodeField.rightView = countryFlagContainerView
|
|
countryCodeField.rightViewMode = .always
|
|
countryCodeField.delegate = self
|
|
|
|
initialLabelTextColour = phoneLabel.textColor
|
|
initialTextFieldBorderColour = phoneNumberField.borderColor
|
|
navigationController?.view.backgroundColor = UIColor.white
|
|
|
|
stepCounterLabel.text = String.localizedStringWithFormat( "stepCounter".localizedString(),
|
|
2,
|
|
UserDefaults.standard.bool(forKey: "allowedPermissions") ? 3 : 4
|
|
)
|
|
}
|
|
|
|
@IBAction func onBackTapped(_ sender: UIButton) {
|
|
self.navigationController?.popViewController(animated: true)
|
|
}
|
|
|
|
@IBAction func nextButtonClicked(_ sender: Any) {
|
|
parsePhoneNumberAndProceed(self.phoneNumberField.text ?? "")
|
|
}
|
|
|
|
@objc
|
|
func phoneNumberFieldDidChange() {
|
|
guard let phoneNumberString = self.phoneNumberField.text else { return }
|
|
if (selectedCountry == nil || selectedCountry?.name == "Australia") {
|
|
let result = PhoneNumberParser.parse(phoneNumberString, countryCode: "61")
|
|
if case .success = result {
|
|
self.phoneNumberField.resignFirstResponder()
|
|
}
|
|
}
|
|
}
|
|
|
|
func parsePhoneNumberAndProceed(_ number: String) {
|
|
let result = PhoneNumberParser.parse(number, countryCode: selectedCountry?.phoneCode ?? "61")
|
|
|
|
switch result {
|
|
case .success(let parsedNumber):
|
|
activityIndicator.startAnimating()
|
|
getOTPButton.isEnabled = false
|
|
verifyPhoneNumber(parsedNumber)
|
|
|
|
case .failure(let error):
|
|
let errorAlert = UIAlertController(title: "PhoneNumberFormatErrorTitle".localizedString(),
|
|
message: "PhoneNumberFormatErrorMessage".localizedString(),
|
|
preferredStyle: .alert)
|
|
errorAlert.addAction(UIAlertAction(title: "global_OK".localizedString(), style: .default, handler: { _ in
|
|
NSLog("Unable to verify phone number")
|
|
}))
|
|
present(errorAlert, animated: true)
|
|
DLog("Client side phone number verification error: \(error.localizedDescription)")
|
|
return
|
|
}
|
|
}
|
|
|
|
private func verifyPhoneNumber(_ phoneNumber: String) {
|
|
guard self.registrationInfo != nil else {
|
|
return
|
|
}
|
|
self.registrationInfo?.phoneNumber = phoneNumber
|
|
self.registrationInfo?.countryPhoneCode = selectedCountry?.phoneCode ?? "61"
|
|
PhoneValidationAPI.verifyPhoneNumber(regInfo: self.registrationInfo!) {[weak self] (session, error) in
|
|
self?.activityIndicator.stopAnimating()
|
|
self?.getOTPButton.isEnabled = true
|
|
if let error = error {
|
|
let errorAlert = UIAlertController(title: "PhoneVerificationErrorTitle".localizedString(),
|
|
message: "PhoneVerificationErrorMessage".localizedString(),
|
|
preferredStyle: .alert)
|
|
errorAlert.addAction(UIAlertAction(title: "global_OK".localizedString(), style: .default, handler: { _ in
|
|
DLog("Unable to verify phone number")
|
|
}))
|
|
self?.present(errorAlert, animated: true)
|
|
DLog("Phone number verification error: \(error.localizedDescription)")
|
|
return
|
|
}
|
|
UserDefaults.standard.set(session, forKey: "session")
|
|
self?.performSegue(withIdentifier: "segueFromNumberToOTP", sender: self)
|
|
}
|
|
}
|
|
|
|
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
|
if var vc = segue.destination as? RegistrationHandler {
|
|
vc.reauthenticating = self.reauthenticating
|
|
vc.registrationInfo = self.registrationInfo
|
|
}
|
|
if let vc = segue.destination as? SelectCountryViewController {
|
|
navigationController?.setNavigationBarHidden(false, animated: false)
|
|
vc.countrySelectionDelegate = self
|
|
}
|
|
}
|
|
|
|
// limit text field input to 17 characters
|
|
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
|
|
replacementString string: String) -> Bool
|
|
{
|
|
let maxLength = PHONE_NUMBER_LENGTH
|
|
let currentString: NSString = textField.text! as NSString
|
|
let newString: NSString =
|
|
currentString.replacingCharacters(in: range, with: string) as NSString
|
|
return newString.length <= maxLength
|
|
}
|
|
|
|
func textFieldDidEndEditing(_ textField: UITextField) {
|
|
if textField == phoneNumberField {
|
|
validatePhoneNumber()
|
|
}
|
|
}
|
|
|
|
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
|
if textField == countryCodeField {
|
|
phoneNumberField.resignFirstResponder()
|
|
performSegue(withIdentifier: "selectCountrySegue", sender: self)
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
@objc func action() {
|
|
view.endEditing(true)
|
|
}
|
|
|
|
func setCountry(country: Country) {
|
|
selectedCountry = country
|
|
|
|
flagImageView.image = selectedCountry?.flag?.originalImage
|
|
guard let countryName = country.name, let countryPhoneCode = country.phoneCode else {
|
|
return
|
|
}
|
|
countryCodeField.text = "(+\(countryPhoneCode)) \(countryName)"
|
|
countryCodeField.accessibilityValue = String.init(format: "SelectedCountryTemplate".localizedString(), countryPhoneCode, countryName)
|
|
if selectedCountry?.isoCode == "AU2" {
|
|
phoneExample.isHidden = false
|
|
} else {
|
|
phoneExample.isHidden = true
|
|
}
|
|
validatePhoneNumber()
|
|
}
|
|
|
|
func validatePhoneNumber() {
|
|
phoneExample.textColor = initialLabelTextColour
|
|
phoneLabel.textColor = initialLabelTextColour
|
|
phoneNumberField.borderColor = initialTextFieldBorderColour
|
|
phoneError.isHidden = true
|
|
let countryCode = selectedCountry?.phoneCode ?? "61"
|
|
|
|
guard let phoneText = phoneNumberField.text, phoneText.count > 0 else {
|
|
return
|
|
}
|
|
|
|
let parseResult = PhoneNumberParser.parse(phoneText, countryCode: countryCode)
|
|
|
|
switch parseResult {
|
|
case .failure( _):
|
|
phoneError.isHidden = false
|
|
phoneExample.textColor = UIColor.covidSafeErrorColor
|
|
phoneLabel.textColor = UIColor.covidSafeErrorColor
|
|
phoneNumberField.borderColor = UIColor.covidSafeErrorColor
|
|
if selectedCountry == nil || selectedCountry?.isoCode == "AU" {
|
|
phoneError.text = "invalid_australian_phone_number_error_prompt".localizedString()
|
|
} else if selectedCountry?.isoCode == "AU2" {
|
|
phoneError.text = "invalid_norfolk_island_phone_number_error_prompt".localizedString()
|
|
}
|
|
|
|
if UIAccessibility.isVoiceOverRunning {
|
|
UIAccessibility.post(notification: .layoutChanged, argument: phoneError)
|
|
}
|
|
break
|
|
default:
|
|
break
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
protocol CountrySelectionDelegate {
|
|
func setCountry(country: Country)
|
|
}
|