From bf5a832aff67092d5a8dcad698453fc8a38fe590 Mon Sep 17 00:00:00 2001 From: Felix Schwarz Date: Tue, 29 Aug 2023 15:03:31 +0200 Subject: [PATCH] - BottomButtonBar: adapt layout dynamically to size class, placing the promptText above the buttons in any but regular horizontal class size and stretching the buttons to fill the space beneath it --- .../User Interface/BottomButtonBar.swift | 87 +++++++++++++++---- 1 file changed, 69 insertions(+), 18 deletions(-) diff --git a/ownCloudAppShared/Client/User Interface/BottomButtonBar.swift b/ownCloudAppShared/Client/User Interface/BottomButtonBar.swift index 0d6f9c951..ab36d4cd5 100644 --- a/ownCloudAppShared/Client/User Interface/BottomButtonBar.swift +++ b/ownCloudAppShared/Client/User Interface/BottomButtonBar.swift @@ -43,6 +43,9 @@ open class BottomButtonBar: ThemeCSSView { } } + open var promptText: String? + open var hasCancelButton: Bool + var activityIndicator: UIActivityIndicatorView? var showActivityIndicatorWhileModalActionRunning = true open var modalActionRunning: Bool = false { @@ -77,6 +80,7 @@ open class BottomButtonBar: ThemeCSSView { public init(prompt: String? = nil, selectButtonTitle: String, cancelButtonTitle: String? = "Cancel".localized, hasCancelButton: Bool, selectAction: UIAction?, cancelAction: UIAction?) { self.selectButtonTitle = selectButtonTitle + self.hasCancelButton = hasCancelButton super.init() @@ -93,9 +97,6 @@ open class BottomButtonBar: ThemeCSSView { selectButton.setContentCompressionResistancePriority(.required, for: .vertical) cancelButton.setContentCompressionResistancePriority(.required, for: .vertical) - var constraints: [NSLayoutConstraint] = [] - var leadingButtonAnchor = selectButton.leadingAnchor - var selectButtonConfig = UIButton.Configuration.borderedProminent() selectButtonConfig.title = selectButtonTitle selectButtonConfig.cornerStyle = .large @@ -114,42 +115,92 @@ open class BottomButtonBar: ThemeCSSView { } addSubview(cancelButton) - - leadingButtonAnchor = cancelButton.leadingAnchor - - constraints.append(contentsOf: [ - cancelButton.trailingAnchor.constraint(equalTo: selectButton.leadingAnchor, constant: -15), - cancelButton.centerYAnchor.constraint(equalTo: selectButton.centerYAnchor) - ]) } + promptText = prompt promptLabel.text = prompt addSubview(selectButton) addSubview(promptLabel) addSubview(bottomSeparatorLine) - constraints.append(contentsOf: [ - promptLabel.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 20), - promptLabel.trailingAnchor.constraint(lessThanOrEqualTo: leadingButtonAnchor, constant: -20), - promptLabel.centerYAnchor.constraint(equalTo: selectButton.centerYAnchor), + updateLayout() + } + + var barConstraints: [NSLayoutConstraint]? { + willSet { + if let barConstraints { + NSLayoutConstraint.deactivate(barConstraints) + } + } + didSet { + if let barConstraints { + NSLayoutConstraint.activate(barConstraints) + } + } + } + + func updateLayout() { + var constraints: [NSLayoutConstraint] = [] + let isHorizontalLayout = (traitCollection.horizontalSizeClass == .regular) || (promptText == nil) - selectButton.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor, constant: -20), - selectButton.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 20), - selectButton.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -20), + if isHorizontalLayout { + let leadingButtonAnchor = hasCancelButton ? cancelButton.leadingAnchor : selectButton.leadingAnchor + constraints.append(contentsOf: [ + promptLabel.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 20), + promptLabel.trailingAnchor.constraint(lessThanOrEqualTo: leadingButtonAnchor, constant: -20), + promptLabel.centerYAnchor.constraint(equalTo: selectButton.centerYAnchor), + + selectButton.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor, constant: -20), + selectButton.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 20), + selectButton.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -20) + ]) + } else { + constraints.append(contentsOf: [ + promptLabel.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 20), + promptLabel.trailingAnchor.constraint(lessThanOrEqualTo: safeAreaLayoutGuide.trailingAnchor, constant: -20), + promptLabel.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 10), + + selectButton.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 20).with(priority: .defaultHigh), + selectButton.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor, constant: -20), + selectButton.topAnchor.constraint(equalTo: promptLabel.bottomAnchor, constant: 10), + selectButton.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -20) + ]) + + if hasCancelButton { + constraints.append( + cancelButton.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 20) + ) + } + } + + if hasCancelButton { + constraints.append(contentsOf: [ + cancelButton.trailingAnchor.constraint(equalTo: selectButton.leadingAnchor, constant: -15), + cancelButton.centerYAnchor.constraint(equalTo: selectButton.centerYAnchor) + ]) + } + + constraints.append(contentsOf: [ bottomSeparatorLine.leftAnchor.constraint(equalTo: leftAnchor), bottomSeparatorLine.rightAnchor.constraint(equalTo: rightAnchor), bottomSeparatorLine.topAnchor.constraint(equalTo: topAnchor), bottomSeparatorLine.heightAnchor.constraint(equalToConstant: 1) ]) - NSLayoutConstraint.activate(constraints) + barConstraints = constraints } required public init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + updateLayout() + } } extension ThemeCSSSelector {