Skip to content

Commit

Permalink
Refactor buttons to use UIButton.Configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
mojganii committed Oct 4, 2024
1 parent 0e32a21 commit 973ed38
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 228 deletions.
4 changes: 0 additions & 4 deletions ios/MullvadVPN.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,6 @@
58FF9FE42B075BDD00E4C97D /* EditAccessMethodItemIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FF9FE32B075BDD00E4C97D /* EditAccessMethodItemIdentifier.swift */; };
58FF9FE82B07650A00E4C97D /* ButtonCellContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FF9FE72B07650A00E4C97D /* ButtonCellContentConfiguration.swift */; };
58FF9FEA2B07653800E4C97D /* ButtonCellContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FF9FE92B07653800E4C97D /* ButtonCellContentView.swift */; };
58FF9FEC2B07A7CB00E4C97D /* NSDirectionalEdgeInsets+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FF9FEB2B07A7CB00E4C97D /* NSDirectionalEdgeInsets+Helpers.swift */; };
58FF9FF02B07C4D300E4C97D /* PersistentAccessMethod+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FF9FEF2B07C4D300E4C97D /* PersistentAccessMethod+ViewModel.swift */; };
58FF9FF42B07C61B00E4C97D /* AccessMethodValidationError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FF9FF32B07C61B00E4C97D /* AccessMethodValidationError.swift */; };
7A02D4EB2A9CEC7A00C19E31 /* MullvadVPNScreenshots.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = 7A02D4EA2A9CEC7A00C19E31 /* MullvadVPNScreenshots.xctestplan */; };
Expand Down Expand Up @@ -1781,7 +1780,6 @@
58FF9FE32B075BDD00E4C97D /* EditAccessMethodItemIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAccessMethodItemIdentifier.swift; sourceTree = "<group>"; };
58FF9FE72B07650A00E4C97D /* ButtonCellContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonCellContentConfiguration.swift; sourceTree = "<group>"; };
58FF9FE92B07653800E4C97D /* ButtonCellContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonCellContentView.swift; sourceTree = "<group>"; };
58FF9FEB2B07A7CB00E4C97D /* NSDirectionalEdgeInsets+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSDirectionalEdgeInsets+Helpers.swift"; sourceTree = "<group>"; };
58FF9FEF2B07C4D300E4C97D /* PersistentAccessMethod+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PersistentAccessMethod+ViewModel.swift"; sourceTree = "<group>"; };
58FF9FF32B07C61B00E4C97D /* AccessMethodValidationError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessMethodValidationError.swift; sourceTree = "<group>"; };
7A02D4EA2A9CEC7A00C19E31 /* MullvadVPNScreenshots.xctestplan */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = MullvadVPNScreenshots.xctestplan; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3010,7 +3008,6 @@
children = (
58CCA0152242560B004F3011 /* UIColor+Palette.swift */,
A9E034632ABB302000E59A5A /* UIEdgeInsets+Extensions.swift */,
58FF9FEB2B07A7CB00E4C97D /* NSDirectionalEdgeInsets+Helpers.swift */,
585CA70E25F8C44600B47C62 /* UIMetrics.swift */,
);
path = "UI appearance";
Expand Down Expand Up @@ -5832,7 +5829,6 @@
7A5869B92B56E7F000640D27 /* IPOverrideViewControllerDelegate.swift in Sources */,
586C0D7A2B039CE300E7CDD7 /* ShadowsocksCipherPicker.swift in Sources */,
58B93A1326C3F13600A55733 /* TunnelState.swift in Sources */,
58FF9FEC2B07A7CB00E4C97D /* NSDirectionalEdgeInsets+Helpers.swift in Sources */,
586C0D832B03D2FF00E7CDD7 /* ShadowsocksSectionHandler.swift in Sources */,
58B26E262943522400D5980C /* NotificationProvider.swift in Sources */,
58CE5E64224146200008646E /* AppDelegate.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ class ButtonCellContentView: UIView, UIContentView {
button.titleLabel?.font = .systemFont(ofSize: 17)
button.isEnabled = actualConfiguration.isEnabled
button.style = actualConfiguration.style
button.overrideContentEdgeInsets = true
button.directionalContentEdgeInsets = actualConfiguration.directionalContentEdgeInsets
button.configuration?.contentInsets = actualConfiguration.directionalContentEdgeInsets
}

private func addSubviews() {
Expand Down
21 changes: 0 additions & 21 deletions ios/MullvadVPN/UI appearance/NSDirectionalEdgeInsets+Helpers.swift

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,18 @@ final class AccountInputGroupView: UIView {
button.titleLabel?.font = accountNumberFont()
button.setTitle(" ", for: .normal)
button.contentHorizontalAlignment = .leading
button.contentEdgeInsets = UIMetrics.textFieldMargins
button.setTitleColor(UIColor.AccountTextField.NormalState.textColor, for: .normal)
button.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
button.accessibilityLabel = NSLocalizedString(
"LAST_USED_ACCOUNT_ACCESSIBILITY_LABEL",
tableName: "AccountInput",
value: "Last used account",
comment: ""
)

var config = UIButton.Configuration.plain()
config.contentInsets = UIMetrics.textFieldMargins.toDirectionalInsets
config.baseForegroundColor = .AccountTextField.NormalState.textColor
button.configuration = config
return button
}()

Expand Down
25 changes: 17 additions & 8 deletions ios/MullvadVPN/View controllers/Tunnel/DisconnectSplitButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ class DisconnectSplitButton: UIView {
UIImage(named: "IconReload")?.imageFlippedForRightToLeftLayoutDirection(),
for: .normal
)

primaryButton.overrideContentEdgeInsets = true
secondaryButtonWidthConstraint = secondaryButton.widthAnchor.constraint(equalToConstant: 0)
secondaryButtonHeightConstraint = secondaryButton.heightAnchor
.constraint(equalToConstant: 0)
Expand Down Expand Up @@ -72,18 +70,29 @@ class DisconnectSplitButton: UIView {
}

private func adjustTitleLabelPosition() {
var contentInsets = primaryButton.defaultContentInsets
// Instead of setting contentEdgeInsets manually, we update UIButtonConfiguration
var primaryButtonConfig = primaryButton.configuration ?? UIButton.Configuration.filled()

let offset = stackView.spacing + secondaryButtonSize.width

// Create content insets depending on layout direction
if case .leftToRight = effectiveUserInterfaceLayoutDirection {
contentInsets.left = offset
contentInsets.right = 0
primaryButtonConfig.contentInsets = NSDirectionalEdgeInsets(
top: primaryButton.defaultContentInsets.top,
leading: offset,
bottom: primaryButton.defaultContentInsets.bottom,
trailing: 0
)
} else {
contentInsets.left = 0
contentInsets.right = offset
primaryButtonConfig.contentInsets = NSDirectionalEdgeInsets(
top: primaryButton.defaultContentInsets.top,
leading: 0,
bottom: primaryButton.defaultContentInsets.bottom,
trailing: offset
)
}

primaryButton.contentEdgeInsets = contentInsets
// Apply updated configuration to the primary button
primaryButton.configuration = primaryButtonConfig
}
}
69 changes: 22 additions & 47 deletions ios/MullvadVPN/Views/AppButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import UIKit
/// A subclass that implements action buttons used across the app
class AppButton: CustomButton {
/// Default content insets based on current trait collection.
var defaultContentInsets: UIEdgeInsets {
var defaultContentInsets: NSDirectionalEdgeInsets {
switch traitCollection.userInterfaceIdiom {
case .phone:
return UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
return NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
case .pad:
return UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 15)
return NSDirectionalEdgeInsets(top: 15, leading: 15, bottom: 15, trailing: 15)
default:
return .zero
}
Expand Down Expand Up @@ -87,30 +87,6 @@ class AppButton: CustomButton {
}
}

/// Prevents updating `contentEdgeInsets` on changes to trait collection.
var overrideContentEdgeInsets = false

override var contentEdgeInsets: UIEdgeInsets {
didSet {
// Reset inner directional insets when contentEdgeInsets are set directly.
innerDirectionalContentEdgeInsets = nil
}
}

/// Directional content edge insets that are automatically translated into `contentEdgeInsets` immeditely upon updating the property and on trait collection
/// changes.
var directionalContentEdgeInsets: NSDirectionalEdgeInsets {
get {
innerDirectionalContentEdgeInsets ?? contentEdgeInsets.toDirectionalInsets
}
set {
innerDirectionalContentEdgeInsets = newValue
updateContentEdgeInsetsFromDirectional()
}
}

private var innerDirectionalContentEdgeInsets: NSDirectionalEdgeInsets?

init(style: Style) {
self.style = style
super.init(frame: .zero)
Expand All @@ -128,32 +104,31 @@ class AppButton: CustomButton {
}

private func commonInit() {
super.contentEdgeInsets = defaultContentInsets
imageAlignment = .trailingFixed

titleLabel?.font = UIFont.systemFont(ofSize: 18, weight: .semibold)

let states: [UIControl.State] = [.normal, .highlighted, .disabled]
states.forEach { state in
if let titleColor = state.customButtonTitleColor {
setTitleColor(titleColor, for: state)
imageAlignment = .trailing
titleAlignment = .leading

var config = super.configuration ?? .plain()
config.title = title(for: state)
config.contentInsets = defaultContentInsets
config.background.image = style.backgroundImage
config.titleTextAttributesTransformer =
UIConfigurationTextAttributesTransformer { [weak self] attributeContainer in
guard let self = self else { return attributeContainer }
var updatedAttributeContainer = attributeContainer
updatedAttributeContainer.font = UIFont.systemFont(ofSize: 18, weight: .semibold)
updatedAttributeContainer.foregroundColor = self.state.customButtonTitleColor
return updatedAttributeContainer
}
}

// Avoid setting the background image if it's already set via Interface Builder
if backgroundImage(for: .normal) == nil {
updateButtonBackground()
let configurationHandler: UIButton.ConfigurationUpdateHandler = { button in
button.alpha = button.state == .disabled ? 0.5 : 1.0
}
self.configuration = config
self.configurationUpdateHandler = configurationHandler
}

/// Set background image based on current style.
private func updateButtonBackground() {
setBackgroundImage(style.backgroundImage, for: .normal)
}

/// Update content edge insets from directional edge insets if set.
private func updateContentEdgeInsetsFromDirectional() {
guard let directionalEdgeInsets = innerDirectionalContentEdgeInsets else { return }
super.contentEdgeInsets = directionalEdgeInsets.toEdgeInsets(effectiveUserInterfaceLayoutDirection)
self.configuration?.background.image = style.backgroundImage
}
}
Loading

0 comments on commit 973ed38

Please sign in to comment.