Signal-iOS/Signal/Registration/UserInterface/RegistrationTransferProgressViewController.swift
Adam Sharp b42710cf90 Work around use of deprecated UIButton API
The old UIButton API is still functional as long as we don't use
UIButton.Configuration, so we can safely ignore these warnings until we're
ready to adopt the configuration API across the codebase.
2024-07-03 14:27:48 -04:00

258 lines
9.6 KiB
Swift

//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import MultipeerConnectivity
import SignalServiceKit
import SignalUI
import UIKit
public class RegistrationTransferProgressViewController: OWSViewController {
let progressView: TransferProgressView
public init(progress: Progress) {
self.progressView = TransferProgressView(progress: progress)
super.init()
}
override public func loadView() {
view = UIView()
view.backgroundColor = Theme.backgroundColor
let titleLabel = UILabel.titleLabelForRegistration(
text: OWSLocalizedString(
"DEVICE_TRANSFER_RECEIVING_TITLE",
comment: "The title on the view that shows receiving progress"
)
)
view.addSubview(titleLabel)
titleLabel.accessibilityIdentifier = "onboarding.transferProgress.titleLabel"
titleLabel.setContentHuggingHigh()
let explanationLabel = UILabel.explanationLabelForRegistration(
text: OWSLocalizedString(
"DEVICE_TRANSFER_RECEIVING_EXPLANATION",
comment: "The explanation on the view that shows receiving progress"
)
)
explanationLabel.accessibilityIdentifier = "onboarding.transferProgress.bodyLabel"
explanationLabel.setContentHuggingHigh()
let cancelButton = OWSFlatButton.linkButtonForRegistration(
title: CommonStrings.cancelButton,
target: self,
selector: #selector(didTapCancel)
)
let topSpacer = UIView.vStretchingSpacer()
let bottomSpacer = UIView.vStretchingSpacer()
let stackView = UIStackView(arrangedSubviews: [
titleLabel,
explanationLabel,
topSpacer,
progressView,
bottomSpacer,
cancelButton
])
stackView.axis = .vertical
stackView.alignment = .fill
stackView.spacing = 12
view.addSubview(stackView)
stackView.autoPinEdgesToSuperviewMargins()
topSpacer.autoMatch(.height, to: .height, of: bottomSpacer)
}
override public func viewDidLoad() {
super.viewDidLoad()
navigationItem.setHidesBackButton(true, animated: false)
}
override public func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
progressView.startUpdatingProgress()
deviceTransferService.addObserver(self)
}
public override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
progressView.stopUpdatingProgress()
deviceTransferService.removeObserver(self)
deviceTransferService.cancelTransferFromOldDevice()
}
// MARK: - Events
@objc
func didTapCancel() {
Logger.info("")
let actionSheet = ActionSheetController(
title: OWSLocalizedString("DEVICE_TRANSFER_CANCEL_CONFIRMATION_TITLE",
comment: "The title of the dialog asking the user if they want to cancel a device transfer"),
message: OWSLocalizedString("DEVICE_TRANSFER_CANCEL_CONFIRMATION_MESSAGE",
comment: "The message of the dialog asking the user if they want to cancel a device transfer")
)
actionSheet.addAction(OWSActionSheets.cancelAction)
let okAction = ActionSheetAction(
title: OWSLocalizedString("DEVICE_TRANSFER_CANCEL_CONFIRMATION_ACTION",
comment: "The stop action of the dialog asking the user if they want to cancel a device transfer"),
style: .destructive
) { [weak self] _ in
// viewWillDissapear will cancel the transfer
self?.navigationController?.popViewController(animated: true)
}
actionSheet.addAction(okAction)
present(actionSheet, animated: true)
}
}
extension RegistrationTransferProgressViewController: DeviceTransferServiceObserver {
func deviceTransferServiceDiscoveredNewDevice(peerId: MCPeerID, discoveryInfo: [String: String]?) {}
func deviceTransferServiceDidStartTransfer(progress: Progress) {}
func deviceTransferServiceDidEndTransfer(error: DeviceTransferService.Error?) {
guard let error = error else { return }
switch error {
case .assertion:
progressView.renderError(
text: OWSLocalizedString("DEVICE_TRANSFER_ERROR_GENERIC",
comment: "An error indicating that something went wrong with the transfer and it could not complete")
)
case .backgroundedDevice:
progressView.renderError(
text: OWSLocalizedString(
"DEVICE_TRANSFER_ERROR_BACKGROUNDED",
comment: "An error indicating that the other device closed signal mid-transfer and it could not complete"
)
)
case .cancel:
// User initiated, nothing to do
break
case .certificateMismatch:
owsFailDebug("This should never happen on the new device")
case .notEnoughSpace:
progressView.renderError(
text: OWSLocalizedString("DEVICE_TRANSFER_ERROR_NOT_ENOUGH_SPACE",
comment: "An error indicating that the user does not have enough free space on their device to complete the transfer")
)
case .unsupportedVersion:
progressView.renderError(
text: OWSLocalizedString("DEVICE_TRANSFER_ERROR_UNSUPPORTED_VERSION",
comment: "An error indicating the user must update their device before trying to transfer.")
)
case .modeMismatch:
owsFailDebug("This should never happen on the new device")
}
}
func deviceTransferServiceDidRequestAppRelaunch() {
self.present(TransferRelaunchSheet(), animated: true)
}
}
private class TransferRelaunchSheet: InteractiveSheetViewController {
let stackView = UIStackView()
public override var canBeDismissed: Bool { false }
public override var sheetBackgroundColor: UIColor { Theme.tableView2PresentedBackgroundColor }
override public func viewDidLoad() {
super.viewDidLoad()
minimizedHeight = 460
super.allowsExpansion = false
stackView.axis = .vertical
stackView.layoutMargins = UIEdgeInsets(hMargin: 24, vMargin: 24)
stackView.spacing = 22
stackView.isLayoutMarginsRelativeArrangement = true
contentView.addSubview(stackView)
let image = UIImage(named: "transfer_complete")
let imageView = UIImageView(image: image)
imageView.contentMode = .scaleAspectFit
stackView.addArrangedSubview(imageView)
imageView.autoSetDimensions(to: CGSize(width: 128, height: 64))
let titleLabel = UILabel()
titleLabel.textAlignment = .center
titleLabel.font = UIFont.dynamicTypeTitle2.semibold()
titleLabel.text = OWSLocalizedString(
"TRANSFER_COMPLETE_SHEET_TITLE",
comment: "Title for bottom sheet shown when device transfer completes on the receiving device."
)
stackView.addArrangedSubview(titleLabel)
let subtitleLabel = UILabel()
subtitleLabel.text = OWSLocalizedString(
"TRANSFER_COMPLETE_SHEET_SUBTITLE",
comment: "Subtitle for bottom sheet shown when device transfer completes on the receiving device."
)
subtitleLabel.textAlignment = .center
subtitleLabel.font = .dynamicTypeBody
subtitleLabel.numberOfLines = 0
subtitleLabel.lineBreakMode = .byWordWrapping
stackView.addArrangedSubview(subtitleLabel)
let exitButton = UIButton()
exitButton.backgroundColor = .ows_accentBlue
exitButton.layer.cornerRadius = 8
exitButton.ows_titleEdgeInsets = UIEdgeInsets(hMargin: 0, vMargin: 18)
exitButton.setTitleColor(.ows_white, for: .normal)
exitButton.setTitle(
OWSLocalizedString(
"TRANSFER_COMPLETE_SHEET_BUTTON",
comment: "Button for bottom sheet shown when device transfer completes on the receiving device. Tapping will terminate the Signal app and trigger a notification to relaunch."
),
for: .normal
)
exitButton.addTarget(self, action: #selector(didTapExitButton), for: .touchUpInside)
contentView.addSubview(exitButton)
exitButton.autoPinEdge(
.leading,
to: .leading,
of: contentView,
withOffset: 32,
relation: .greaterThanOrEqual
).priority = .required
exitButton.autoPinEdge(
.trailing,
to: .trailing,
of: contentView,
withOffset: -32,
relation: .greaterThanOrEqual
).priority = .required
exitButton.autoSetDimension(.width, toSize: 325, relation: .greaterThanOrEqual)
exitButton.autoSetDimension(.height, toSize: 48, relation: .greaterThanOrEqual)
exitButton.autoPinEdge(.bottom, to: .bottom, of: contentView, withOffset: -50)
exitButton.autoHCenterInSuperview()
stackView.autoPinEdge(.top, to: .top, of: contentView)
stackView.autoPinWidth(toWidthOf: contentView)
stackView.autoHCenterInSuperview()
}
@objc
private func didTapExitButton() {
Logger.info("")
notificationPresenter.notifyUserToRelaunchAfterTransfer {
Logger.info("Deliberately terminating app post-transfer.")
exit(0)
}
}
}