Skip to content

Commit

Permalink
Make alert view scrollable
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon Petersson committed Oct 24, 2023
1 parent 8fc622a commit 564e0f0
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 26 deletions.
5 changes: 4 additions & 1 deletion ios/MullvadVPN/UI appearance/UIMetrics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ enum UIMetrics {
trailing: 16
)

/// Spacing between views in container (main view) in `CustomAlertViewController`
/// Spacing between view containers in `CustomAlertViewController`
static let containerSpacing: CGFloat = 16

/// Spacing between view containers in `CustomAlertViewController`
static let interContainerSpacing: CGFloat = 4
}

enum DimmingView {
Expand Down
96 changes: 71 additions & 25 deletions ios/MullvadVPN/View controllers/Alert/AlertViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,33 @@ class AlertViewController: UIViewController {
typealias Handler = () -> Void
var onDismiss: Handler?

private let containerView: UIStackView = {
let view = UIStackView()
let scrollView = UIScrollView()
var scrollViewHeightConstraint: NSLayoutConstraint!

private let viewContainer: UIView = {
let view = UIView()

view.axis = .vertical
view.backgroundColor = .secondaryColor
view.layer.cornerRadius = 11

return view
}()

private let buttonView: UIStackView = {
let view = UIStackView()

view.axis = .vertical
view.spacing = UIMetrics.CustomAlert.containerSpacing
view.isLayoutMarginsRelativeArrangement = true
view.directionalLayoutMargins = UIMetrics.CustomAlert.containerMargins

return view
}()

private let contentView: UIStackView = {
let view = UIStackView()

view.axis = .vertical
view.spacing = UIMetrics.CustomAlert.containerSpacing
view.isLayoutMarginsRelativeArrangement = true
view.directionalLayoutMargins = UIMetrics.CustomAlert.containerMargins
Expand Down Expand Up @@ -96,48 +117,73 @@ class AlertViewController: UIViewController {
title.flatMap { addTitle($0) }
addMessageCallback()

containerView.arrangedSubviews.last.flatMap {
containerView.setCustomSpacing(UIMetrics.CustomAlert.containerMargins.top, after: $0)
}

// Icon only alerts should have equal top and bottom margin.
if icon != nil, containerView.arrangedSubviews.count == 1 {
containerView.directionalLayoutMargins.bottom = UIMetrics.CustomAlert.containerMargins.top
if icon != nil, contentView.arrangedSubviews.count == 1 {
contentView.directionalLayoutMargins.bottom = UIMetrics.CustomAlert.containerMargins.top
}
}

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()

view.layoutIfNeeded()
scrollViewHeightConstraint.constant = scrollView.contentSize.height
}

override func viewDidLoad() {
super.viewDidLoad()

view.backgroundColor = .black.withAlphaComponent(0.5)

view.addConstrainedSubviews([containerView]) {
containerView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
containerView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
viewContainer.addConstrainedSubviews([scrollView, buttonView]) {
scrollView.pinEdgesToSuperview(.all().excluding(.bottom))
buttonView.pinEdgesToSuperview(.all().excluding(.top))
buttonView.topAnchor.constraint(equalTo: scrollView.bottomAnchor)
}

containerView.widthAnchor
scrollView.addConstrainedSubviews([contentView]) {
contentView.pinEdgesToSuperview(.all())
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
}

scrollViewHeightConstraint = scrollView.heightAnchor.constraint(equalToConstant: 0).withPriority(.defaultLow)
scrollViewHeightConstraint.isActive = true

view.addConstrainedSubviews([viewContainer]) {
viewContainer.centerXAnchor.constraint(equalTo: view.centerXAnchor)
viewContainer.centerYAnchor.constraint(equalTo: view.centerYAnchor)

viewContainer.widthAnchor
.constraint(lessThanOrEqualToConstant: UIMetrics.preferredFormSheetContentSize.width)

containerView.leadingAnchor
viewContainer.topAnchor
.constraint(greaterThanOrEqualTo: view.layoutMarginsGuide.topAnchor)
.withPriority(.defaultHigh)

view.layoutMarginsGuide.bottomAnchor
.constraint(greaterThanOrEqualTo: viewContainer.bottomAnchor)
.withPriority(.defaultHigh)

viewContainer.leadingAnchor
.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor)
.withPriority(.defaultHigh)

view.layoutMarginsGuide.trailingAnchor
.constraint(equalTo: containerView.trailingAnchor)
.constraint(equalTo: viewContainer.trailingAnchor)
.withPriority(.defaultHigh)
}
}

func addAction(title: String, style: AlertActionStyle, handler: (() -> Void)? = nil) {
// The presence of a button should reset any custom button margin to default.
containerView.directionalLayoutMargins.bottom = UIMetrics.CustomAlert.containerMargins.bottom
// The presence of a button should yield a custom top margin.
buttonView.directionalLayoutMargins.top = UIMetrics.CustomAlert.interContainerSpacing

let button = AppButton(style: style.buttonStyle)

button.setTitle(title, for: .normal)
button.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)

containerView.addArrangedSubview(button)
buttonView.addArrangedSubview(button)
handler.flatMap { handlers[button] = $0 }
}

Expand All @@ -151,8 +197,8 @@ class AlertViewController: UIViewController {
header.textAlignment = .center
header.numberOfLines = 0

containerView.addArrangedSubview(header)
containerView.setCustomSpacing(16, after: header)
contentView.addArrangedSubview(header)
contentView.setCustomSpacing(16, after: header)
}

private func addTitle(_ title: String) {
Expand All @@ -164,8 +210,8 @@ class AlertViewController: UIViewController {
label.adjustsFontForContentSizeCategory = true
label.numberOfLines = 0

containerView.addArrangedSubview(label)
containerView.setCustomSpacing(8, after: label)
contentView.addArrangedSubview(label)
contentView.setCustomSpacing(8, after: label)
}

private func addMessage(_ message: String) {
Expand All @@ -185,7 +231,7 @@ class AlertViewController: UIViewController {
label.adjustsFontForContentSizeCategory = true
label.numberOfLines = 0

containerView.addArrangedSubview(label)
contentView.addArrangedSubview(label)
}

private func addMessage(_ message: NSAttributedString) {
Expand All @@ -196,12 +242,12 @@ class AlertViewController: UIViewController {
label.adjustsFontForContentSizeCategory = true
label.numberOfLines = 0

containerView.addArrangedSubview(label)
contentView.addArrangedSubview(label)
}

private func addIcon(_ icon: AlertIcon) {
let iconView = icon == .spinner ? getSpinnerView() : getImageView(for: icon)
containerView.addArrangedSubview(iconView)
contentView.addArrangedSubview(iconView)
}

private func getImageView(for icon: AlertIcon) -> UIView {
Expand Down

0 comments on commit 564e0f0

Please sign in to comment.