// // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only // import PureLayout import SafariServices import SignalServiceKit import SignalUI // MARK: - RegistrationSplashPresenter public protocol RegistrationSplashPresenter: AnyObject { func continueFromSplash() func switchToDeviceLinkingMode() func transferDevice() } // MARK: - RegistrationSplashViewController public class RegistrationSplashViewController: OWSViewController { private weak var presenter: RegistrationSplashPresenter? public init(presenter: RegistrationSplashPresenter) { self.presenter = presenter super.init() } public override func viewDidLoad() { super.viewDidLoad() navigationItem.setHidesBackButton(true, animated: false) view.backgroundColor = Theme.backgroundColor let stackView = UIStackView() stackView.axis = .vertical stackView.alignment = .fill stackView.layoutMargins = { let horizontalSizeClass = traitCollection.horizontalSizeClass var result = UIEdgeInsets.layoutMarginsForRegistration(horizontalSizeClass) // We want the hero image a bit closer to the top. result.top = 16 return result }() stackView.isLayoutMarginsRelativeArrangement = true view.addSubview(stackView) stackView.autoPinEdgesToSuperviewMargins() let canSwitchModes = UIDevice.current.isIPad || FeatureFlags.linkedPhones var transferButtonTrailingView: UIView = self.view var transferButtonTrailingEdge: ALEdge = .trailing if canSwitchModes { let modeSwitchButton = UIButton() modeSwitchButton.setTemplateImageName( UIDevice.current.isIPad ? "link" : "link-slash", tintColor: .ows_gray25 ) modeSwitchButton.addTarget(self, action: #selector(didTapModeSwitch), for: .touchUpInside) modeSwitchButton.accessibilityIdentifier = "onboarding.splash.modeSwitch" view.addSubview(modeSwitchButton) modeSwitchButton.autoSetDimensions(to: CGSize(square: 40)) modeSwitchButton.autoPinEdge(toSuperviewMargin: .trailing) modeSwitchButton.autoPinEdge(toSuperviewMargin: .top) transferButtonTrailingEdge = .leading transferButtonTrailingView = modeSwitchButton } if FeatureFlags.preRegDeviceTransfer { let transferButton = UIButton() transferButton.setImage(Theme.iconImage(.transfer), animated: false) transferButton.addTarget(self, action: #selector(didTapTransfer), for: .touchUpInside) transferButton.accessibilityIdentifier = "onboarding.splash.transfer" view.addSubview(transferButton) transferButton.autoSetDimensions(to: CGSize(square: 40)) transferButton.autoPinEdge( .trailing, to: transferButtonTrailingEdge, of: transferButtonTrailingView ) transferButton.autoPinEdge(toSuperviewMargin: .top) } let heroImage = UIImage(named: "onboarding_splash_hero") let heroImageView = UIImageView(image: heroImage) heroImageView.contentMode = .scaleAspectFit heroImageView.layer.minificationFilter = .trilinear heroImageView.layer.magnificationFilter = .trilinear heroImageView.setCompressionResistanceLow() heroImageView.setContentHuggingVerticalLow() heroImageView.accessibilityIdentifier = "registration.splash.heroImageView" stackView.addArrangedSubview(heroImageView) stackView.setCustomSpacing(22, after: heroImageView) let titleText = { if TSConstants.isUsingProductionService { return OWSLocalizedString( "ONBOARDING_SPLASH_TITLE", comment: "Title of the 'onboarding splash' view." ) } else { return "Internal Staging Build\n\(AppVersionImpl.shared.currentAppVersion)" } }() let titleLabel = UILabel.titleLabelForRegistration(text: titleText) titleLabel.accessibilityIdentifier = "registration.splash.titleLabel" stackView.addArrangedSubview(titleLabel) stackView.setCustomSpacing(92, after: titleLabel) // TODO: This should be a button, not a label. let explanationLabel = UILabel() explanationLabel.text = OWSLocalizedString( "ONBOARDING_SPLASH_TERM_AND_PRIVACY_POLICY", comment: "Link to the 'terms and privacy policy' in the 'onboarding splash' view." ) 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(explanationLabelTapped))) explanationLabel.accessibilityIdentifier = "registration.splash.explanationLabel" stackView.addArrangedSubview(explanationLabel) stackView.setCustomSpacing(24, after: explanationLabel) let continueButton = OWSFlatButton.primaryButtonForRegistration( title: CommonStrings.continueButton, target: self, selector: #selector(continuePressed) ) continueButton.accessibilityIdentifier = "registration.splash.continueButton" stackView.addArrangedSubview(continueButton) continueButton.autoSetDimension(.width, toSize: 280) continueButton.autoHCenterInSuperview() NSLayoutConstraint.autoSetPriority(.defaultLow) { continueButton.autoPinEdge(toSuperviewEdge: .leading) continueButton.autoPinEdge(toSuperviewEdge: .trailing) } } // MARK: - Events @objc private func didTapModeSwitch() { Logger.info("") presenter?.switchToDeviceLinkingMode() } @objc private func didTapTransfer() { Logger.info("") presenter?.transferDevice() } @objc private func explanationLabelTapped(sender: UIGestureRecognizer) { guard sender.state == .recognized else { return } let safariVC = SFSafariViewController(url: TSConstants.legalTermsUrl) present(safariVC, animated: true) } @objc private func continuePressed() { Logger.info("") presenter?.continueFromSplash() } }