Signal-iOS/Signal/Provisioning/UserInterface/ProvisioningQRCodeViewController.swift

139 lines
5.5 KiB
Swift

//
// Copyright 2019 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import SafariServices
import SignalServiceKit
import SignalUI
public class ProvisioningQRCodeViewController: ProvisioningBaseViewController {
let qrCodeView = QRCodeView()
override public func loadView() {
view = UIView()
view.addSubview(primaryView)
primaryView.autoPinEdgesToSuperviewEdges()
view.backgroundColor = Theme.backgroundColor
let titleLabel = self.createTitleLabel(text: OWSLocalizedString("SECONDARY_ONBOARDING_SCAN_CODE_TITLE", comment: "header text while displaying a QR code which, when scanned, will link this device."))
primaryView.addSubview(titleLabel)
titleLabel.accessibilityIdentifier = "onboarding.linking.titleLabel"
titleLabel.setContentHuggingHigh()
let bodyLabel = self.createTitleLabel(text: OWSLocalizedString("SECONDARY_ONBOARDING_SCAN_CODE_BODY", comment: "body text while displaying a QR code which, when scanned, will link this device."))
bodyLabel.font = UIFont.dynamicTypeBody
bodyLabel.numberOfLines = 0
primaryView.addSubview(bodyLabel)
bodyLabel.accessibilityIdentifier = "onboarding.linking.bodyLabel"
bodyLabel.setContentHuggingHigh()
qrCodeView.setContentHuggingVerticalLow()
let explanationLabel = UILabel()
explanationLabel.text = OWSLocalizedString("SECONDARY_ONBOARDING_SCAN_CODE_HELP_TEXT",
comment: "Link text for page with troubleshooting info shown on the QR scanning screen")
explanationLabel.textColor = Theme.accentBlueColor
explanationLabel.font = UIFont.dynamicTypeSubheadlineClamped
explanationLabel.numberOfLines = 0
explanationLabel.textAlignment = .center
explanationLabel.lineBreakMode = .byWordWrapping
explanationLabel.isUserInteractionEnabled = true
explanationLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(didTapExplanationLabel)))
explanationLabel.accessibilityIdentifier = "onboarding.linking.helpLink"
explanationLabel.setContentHuggingHigh()
#if TESTABLE_BUILD
let shareURLButton = UIButton(type: .system)
shareURLButton.setTitle(LocalizationNotNeeded("Debug only: Share URL"), for: .normal)
shareURLButton.addTarget(self, action: #selector(didTapShareURL), for: .touchUpInside)
#endif
let stackView = UIStackView(arrangedSubviews: [
titleLabel,
bodyLabel,
qrCodeView,
explanationLabel
])
#if TESTABLE_BUILD
stackView.addArrangedSubview(shareURLButton)
#endif
stackView.axis = .vertical
stackView.alignment = .fill
stackView.spacing = 12
primaryView.addSubview(stackView)
stackView.autoPinEdgesToSuperviewMargins()
}
override public func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
fetchAndSetQRCode()
}
// MARK: - Events
override func shouldShowBackButton() -> Bool {
// Never show the back button here
// TODO: Linked phones, clean up state to allow backing out
return false
}
@objc
func didTapExplanationLabel(sender: UIGestureRecognizer) {
guard sender.state == .recognized else {
owsFailDebug("unexpected state: \(sender.state)")
return
}
UIApplication.shared.open(URL(string: "https://support.signal.org/hc/articles/360007320451")!)
}
#if TESTABLE_BUILD
@IBAction func didTapShareURL(_ sender: UIButton) {
if let qrCodeURL = self.qrCodeURL {
UIPasteboard.general.url = qrCodeURL
// If we share the plain url and airdrop it to a mac, it will just open the url,
// and fail because signal desktop can't open it.
// Share some text instead so we can open it on mac and copy paste into
// a primary device simulator.
let activityVC = UIActivityViewController(
activityItems: ["Provisioning URL: " + qrCodeURL.absoluteString],
applicationActivities: nil
)
activityVC.popoverPresentationController?.sourceView = sender
self.present(activityVC, animated: true)
} else {
UIPasteboard.general.string = LocalizationNotNeeded("URL NOT READY YET")
}
}
#endif
// MARK: -
private var hasFetchedAndSetQRCode = false
private var qrCodeURL: URL?
public func fetchAndSetQRCode() {
guard !hasFetchedAndSetQRCode else { return }
hasFetchedAndSetQRCode = true
provisioningController.getProvisioningURL().done { url in
self.qrCodeURL = url
self.qrCodeView.setQR(url: url)
}.catch { error in
let title = OWSLocalizedString("SECONDARY_DEVICE_ERROR_FETCHING_LINKING_CODE", comment: "alert title")
let alert = ActionSheetController(title: title, message: error.userErrorDescription)
let retryAction = ActionSheetAction(title: CommonStrings.retryButton,
accessibilityIdentifier: "alert.retry",
style: .default) { _ in
self.provisioningController.resetPromises()
self.fetchAndSetQRCode()
}
alert.addAction(retryAction)
self.present(alert, animated: true)
}
}
}