257 lines
9.7 KiB
Swift
257 lines
9.7 KiB
Swift
//
|
|
// Copyright 2023 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
import MultipeerConnectivity
|
|
import SignalServiceKit
|
|
public 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()
|
|
|
|
AppEnvironment.shared.deviceTransferServiceRef.addObserver(self)
|
|
}
|
|
|
|
public override func viewWillDisappear(_ animated: Bool) {
|
|
super.viewWillDisappear(animated)
|
|
|
|
progressView.stopUpdatingProgress()
|
|
|
|
AppEnvironment.shared.deviceTransferServiceRef.removeObserver(self)
|
|
AppEnvironment.shared.deviceTransferServiceRef.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("")
|
|
SSKEnvironment.shared.notificationPresenterRef.notifyUserToRelaunchAfterTransfer {
|
|
Logger.info("Deliberately terminating app post-transfer.")
|
|
exit(0)
|
|
}
|
|
}
|
|
}
|