diff --git a/Signal/src/ViewControllers/HomeView/Stories/Context View/StoryContextOnboardingOverlayView.swift b/Signal/src/ViewControllers/HomeView/Stories/Context View/StoryContextOnboardingOverlayView.swift index d3834a735f..10f60a8f24 100644 --- a/Signal/src/ViewControllers/HomeView/Stories/Context View/StoryContextOnboardingOverlayView.swift +++ b/Signal/src/ViewControllers/HomeView/Stories/Context View/StoryContextOnboardingOverlayView.swift @@ -123,101 +123,114 @@ class StoryContextOnboardingOverlayView: UIView { vStack.alignment = .center vStack.distribution = .equalSpacing vStack.spacing = 42 + vStack.translatesAutoresizingMaskIntoConstraints = false animationViews = [] for asset in assets { - let imageContainer = UIView() - let animationView = LottieAnimationView(name: asset.lottieName) animationView.loopMode = .playOnce animationView.backgroundBehavior = .forceFinish - animationView.autoSetDimensions(to: .square(54)) + let imageContainer = UIView() imageContainer.addSubview(animationView) + animationView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + animationView.widthAnchor.constraint(equalToConstant: 54), + animationView.heightAnchor.constraint(equalTo: animationView.widthAnchor), - imageContainer.autoPinHeight(toHeightOf: animationView) - imageContainer.autoPinWidth(toWidthOf: animationView) - animationView.autoVCenterInSuperview() - animationView.autoAlignAxis(.vertical, toSameAxisOf: imageContainer) + animationView.topAnchor.constraint(equalTo: imageContainer.topAnchor), + animationView.leadingAnchor.constraint(equalTo: imageContainer.leadingAnchor), + animationView.trailingAnchor.constraint(equalTo: imageContainer.trailingAnchor), + animationView.bottomAnchor.constraint(equalTo: imageContainer.bottomAnchor), + ]) let label = UILabel() - label.textColor = .ows_gray05 + label.textColor = .Signal.label label.font = .dynamicTypeBodyClamped label.text = asset.text label.numberOfLines = 0 label.textAlignment = .center label.setContentHuggingPriority(.defaultLow, for: .horizontal) - let innerVStack = UIStackView() + let innerVStack = UIStackView(arrangedSubviews: [imageContainer, label]) innerVStack.axis = .vertical innerVStack.alignment = .center - innerVStack.distribution = .equalSpacing innerVStack.spacing = 12 - innerVStack.addArrangedSubviews([imageContainer, label]) vStack.addArrangedSubview(innerVStack) - animationViews.append(animationView) } - let confirmButtonContainer = ManualLayoutView(name: "confirm_button") - confirmButtonContainer.shouldDeactivateConstraints = false - - confirmButtonContainer.translatesAutoresizingMaskIntoConstraints = false - let confirmButton = OWSButton() - confirmButton.translatesAutoresizingMaskIntoConstraints = false - confirmButton.setTitle( - OWSLocalizedString( - "STORY_VIEWER_ONBOARDING_CONFIRMATION", - comment: "Confirmation text shown the first time the user opens the story viewer to dismiss instructions.", - ), - for: .normal, + let confirmButtonTitle = NSLocalizedString( + "STORY_VIEWER_ONBOARDING_CONFIRMATION", + comment: "Confirmation text shown the first time the user opens the story viewer to dismiss instructions.", ) - confirmButton.titleLabel?.font = .dynamicTypeSubheadlineClamped.semibold() - confirmButton.backgroundColor = .ows_white - confirmButton.setTitleColor(.ows_black, for: .normal) - confirmButton.ows_contentEdgeInsets = UIEdgeInsets(hMargin: 23, vMargin: 8) - confirmButton.block = { [weak self] in - self?.dismiss() + var confirmButtonConfiguration: UIButton.Configuration + if #available(iOS 26, *) { + confirmButtonConfiguration = .largeSecondary(title: confirmButtonTitle) + } else { + confirmButtonConfiguration = UIButton.Configuration.bordered() + confirmButtonConfiguration.baseForegroundColor = .black + confirmButtonConfiguration.baseBackgroundColor = .white + confirmButtonConfiguration.title = confirmButtonTitle + confirmButtonConfiguration.attributedTitle?.font = UIFont.dynamicTypeSubheadlineClamped.semibold() + confirmButtonConfiguration.contentInsets = .init(hMargin: 24, vMargin: 8) + confirmButtonConfiguration.cornerStyle = .capsule } - confirmButtonContainer.addSubview(confirmButton) { view in - confirmButton.layer.cornerRadius = confirmButton.height / 2 - } - confirmButton.autoPinEdges(toEdgesOf: confirmButtonContainer) + let confirmButton = UIButton( + configuration: confirmButtonConfiguration, + primaryAction: UIAction { [weak self] _ in + self?.dismiss() + }, + ) + confirmButton.translatesAutoresizingMaskIntoConstraints = false + + let closeButton = UIButton( + configuration: .round(themeIcon: .buttonX), + primaryAction: UIAction { [weak self] _ in + guard let self else { return } + self.delegate?.storyContextOnboardingOverlayWantsToExitStoryViewer(self) + }, + ) + closeButton.translatesAutoresizingMaskIntoConstraints = false - let closeButton = OWSButton() - closeButton.setImage(Theme.iconImage(.buttonX).withTintColor(.ows_white, renderingMode: .alwaysOriginal), for: .normal) - closeButton.contentMode = .center - closeButton.block = { [weak self] in - guard let self else { return } - self.delegate?.storyContextOnboardingOverlayWantsToExitStoryViewer(self) - } blurView.contentView.addSubview(closeButton) blurView.contentView.addSubview(vStack) - blurView.contentView.addSubview(confirmButtonContainer) + blurView.contentView.addSubview(confirmButton) let vStackLayoutGuide = UILayoutGuide() blurView.contentView.addLayoutGuide(vStackLayoutGuide) - confirmButtonContainer.autoHCenterInSuperview() - confirmButtonContainer.autoPinEdge(toSuperviewSafeArea: .bottom, withInset: 32) - - vStack.autoPinEdge(.leading, to: .leading, of: blurView, withOffset: 12) - vStack.autoPinEdge(.trailing, to: .trailing, of: blurView, withOffset: -12) - vStack.autoPinEdge(.top, to: .bottom, of: closeButton, withOffset: 12, relation: .greaterThanOrEqual) - vStack.autoPinEdge(.bottom, to: .top, of: confirmButtonContainer, withOffset: -42, relation: .lessThanOrEqual) - + let horizontalMargin = OWSTableViewController2.defaultHOuterMargin + var closeButtonMargin = horizontalMargin + if #unavailable(iOS 26), let buttonConfiguration = closeButton.configuration { + // Button has no background so decrease margin by its content inset amount (should be equal on all sides). + closeButtonMargin -= buttonConfiguration.contentInsets.leading + } NSLayoutConstraint.activate([ + closeButton.topAnchor.constraint(equalTo: blurView.topAnchor, constant: closeButtonMargin), + closeButton.trailingAnchor.constraint(equalTo: blurView.trailingAnchor, constant: -closeButtonMargin), + vStackLayoutGuide.topAnchor.constraint(equalTo: closeButton.bottomAnchor, constant: 12), - vStackLayoutGuide.bottomAnchor.constraint(equalTo: confirmButtonContainer.topAnchor, constant: -42), + vStackLayoutGuide.leadingAnchor.constraint(equalTo: blurView.leadingAnchor, constant: horizontalMargin), + vStackLayoutGuide.trailingAnchor.constraint(equalTo: blurView.trailingAnchor, constant: -horizontalMargin), + vStackLayoutGuide.bottomAnchor.constraint(equalTo: confirmButton.topAnchor, constant: -42), + + vStack.topAnchor.constraint(greaterThanOrEqualTo: vStackLayoutGuide.topAnchor), vStack.centerYAnchor.constraint(equalTo: vStackLayoutGuide.centerYAnchor), + vStack.leadingAnchor.constraint(equalTo: vStackLayoutGuide.leadingAnchor), + vStack.trailingAnchor.constraint(equalTo: vStackLayoutGuide.trailingAnchor), + + confirmButton.centerXAnchor.constraint(equalTo: blurView.centerXAnchor), + confirmButton.bottomAnchor.constraint(equalTo: blurView.safeAreaLayoutGuide.bottomAnchor, constant: -32), ]) - closeButton.autoSetDimensions(to: .square(42)) - closeButton.autoPinEdge(toSuperviewEdge: .top, withInset: 20) - closeButton.autoPinEdge(toSuperviewEdge: .leading, withInset: 20) + // When using glass button make it generously wide - at least 44% of the screen width. + if #available(iOS 26, *) { + confirmButton.widthAnchor.constraint(greaterThanOrEqualTo: blurView.widthAnchor, multiplier: 0.44).isActive = true + } } private func startAnimations() { diff --git a/SignalUI/UIKitExtensions/UIButton+SignalUI.swift b/SignalUI/UIKitExtensions/UIButton+SignalUI.swift index 3954213ff0..6dc82c17d0 100644 --- a/SignalUI/UIKitExtensions/UIButton+SignalUI.swift +++ b/SignalUI/UIKitExtensions/UIButton+SignalUI.swift @@ -252,6 +252,20 @@ public extension UIButton.Configuration { configuration.background.backgroundColor = .Signal.secondaryFill return configuration } + + static func round(themeIcon: ThemeIcon) -> Self { + var configuration: UIButton.Configuration + if #available(iOS 26, *) { + configuration = .glass() + configuration.cornerStyle = .capsule + } else { + configuration = .plain() + } + configuration.image = Theme.iconImage(themeIcon) + configuration.baseForegroundColor = .Signal.label + configuration.contentInsets = .init(margin: 10) // 44 dp wide and tall if icon is a standard 24x24 + return configuration + } } // MARK: - UIBarButtonItem