Skip to content

Commit a9c4230

Browse files
authored
Refactor FXIOS-13799 - [Accessory View] - Update UI (#30845)
* Update minimal address bar design based on platform. * Restore changes and cast to the concrete conformance. * Switch to comment. * Fix iPhone with home button and ios 26 case. Fix tests. * Fix swiftlint error. * Update accessory view GUI. * Update minimal address bar to the glass capsule effect. * Fix tests. * Add gradient. * Check if should show/hide overkeyboard container. * Remove unused constant, code indentation.
1 parent 48f369b commit a9c4230

File tree

5 files changed

+112
-101
lines changed

5 files changed

+112
-101
lines changed

BrowserKit/Sources/ToolbarKit/AddressToolbar/LocationView/LocationView.swift

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ final class LocationView: UIView,
2222
static let iconAnimationDelay: CGFloat = 0.03
2323
static let bottomAddressBarYoffset: CGFloat = -16
2424
static let bottomAddressBarYoffsetForHomeButton: CGFloat = -28
25-
static let bottomAddressBarYoffsetForDefaultScale: CGFloat = -10
2625
static let topAddressBarYoffset: CGFloat = 26
2726
static let smallScale: CGFloat = 0.7
2827
static let identityResetAnimationDuration: TimeInterval = 0.2
@@ -178,8 +177,7 @@ final class LocationView: UIView,
178177

179178
applyToolbarAlphaIfNeeded(
180179
alpha: uxConfig.scrollAlpha,
181-
barPosition: addressBarPosition,
182-
isKeyboardVisible: config.shouldShowKeyboard
180+
barPosition: addressBarPosition
183181
)
184182
configureLockIconButton(config)
185183
configureURLTextField(config)
@@ -431,7 +429,7 @@ final class LocationView: UIView,
431429
}
432430

433431
// MARK: - LocationView Scaling
434-
private func shrinkLocationView(barPosition: AddressToolbarPosition, isKeyboardVisible: Bool) {
432+
private func shrinkLocationView(barPosition: AddressToolbarPosition) {
435433
let isiPad = UIDevice.current.userInterfaceIdiom == .pad
436434
let bottomAddressBarYoffset = if #available(iOS 26.0, *) {
437435
UX.bottomAddressBarYoffset
@@ -440,10 +438,7 @@ final class LocationView: UIView,
440438
}
441439
let yOffset: CGFloat = (barPosition == .bottom && !isiPad) ? bottomAddressBarYoffset : UX.topAddressBarYoffset
442440
let scaledTransformation = CGAffineTransform(scaleX: UX.smallScale, y: UX.smallScale).translatedBy(x: 0, y: yOffset)
443-
transform = isKeyboardVisible ? CGAffineTransform(
444-
translationX: 0,
445-
y: UX.bottomAddressBarYoffsetForDefaultScale
446-
) : scaledTransformation
441+
transform = scaledTransformation
447442
urlTextField.isUserInteractionEnabled = false
448443
}
449444

@@ -461,15 +456,12 @@ final class LocationView: UIView,
461456
)
462457
}
463458

464-
private func applyToolbarAlphaIfNeeded(alpha: CGFloat, barPosition: AddressToolbarPosition, isKeyboardVisible: Bool) {
459+
private func applyToolbarAlphaIfNeeded(alpha: CGFloat, barPosition: AddressToolbarPosition) {
465460
guard scrollAlpha != alpha else { return }
466461
scrollAlpha = alpha
467462
if scrollAlpha.isZero {
468-
shrinkLocationView(barPosition: barPosition, isKeyboardVisible: isKeyboardVisible)
469-
if #available(iOS 26.0, *) {
470-
let shouldSetGlassEffect = barPosition == .bottom && !isKeyboardVisible
471-
effectView.effect = shouldSetGlassEffect ? glassEffect : nil
472-
}
463+
shrinkLocationView(barPosition: barPosition)
464+
if #available(iOS 26.0, *) { effectView.effect = barPosition == .bottom ? glassEffect : nil }
473465
} else {
474466
restoreLocationViewSize()
475467
effectView.effect = nil
@@ -722,7 +714,7 @@ final class LocationView: UIView,
722714
let colors = theme.colors
723715

724716
let mainBackgroundColor = hasAlternativeLocationColor ? colors.layerSurfaceMediumAlt : colors.layerSurfaceMedium
725-
if #available(iOS 26.0, *), scrollAlpha.isZero, config?.shouldShowKeyboard == false {
717+
if #available(iOS 26.0, *), scrollAlpha.isZero {
726718
// We want to use system colors when the location view is fully transparent
727719
// To make sure it blends well with the background when using glass effect.
728720
urlTextFieldColor = .label

firefox-ios/Client/AccessoryViewProvider.swift

Lines changed: 38 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,14 @@ final class AccessoryViewProvider: UIView, Themeable, InjectedThemeUUIDIdentifia
1414
// MARK: - Constants
1515
private struct UX {
1616
static let accessoryViewHeight: CGFloat = 56
17-
static let fixedSpacerWidth: CGFloat = if #available(iOS 26.0, *) { 16 } else { 10 }
17+
static let fixedSpacerWidth: CGFloat = if #available(iOS 26.0, *) { 8 } else { 10 }
1818
static let fixedSpacerHeight: CGFloat = 30
1919
static let fixedLeadingSpacerWidth: CGFloat = 2
2020
static let fixedTrailingSpacerWidth: CGFloat = 3
21-
static let leadingTrailingOffset: CGFloat = 12
22-
static let topOffset: CGFloat = 2
23-
static let bottomOffset: CGFloat = 8
24-
static let backgroundViewHeight: CGFloat = 44
21+
static let bottomOffset: CGFloat = if #available(iOS 26.0, *) { 8 } else { 0 }
2522
static let spacerViewHeight: CGFloat = 4
2623
static let cornerRadius: CGFloat = 24.0
27-
static let backgroundCornerRadius: CGFloat = 22
28-
static let shadowRadius: CGFloat = 10
29-
static let shadowOffset = CGSize(width: 0, height: 2)
24+
static let buttonsWidth: CGFloat = 40
3025
}
3126

3227
// MARK: - Properties
@@ -49,10 +44,33 @@ final class AccessoryViewProvider: UIView, Themeable, InjectedThemeUUIDIdentifia
4944
var hasAccessoryView: Bool {
5045
return autofillAccessoryView != nil
5146
}
47+
5248
private var searchBarPosition: SearchBarPosition {
5349
return featureFlags.getCustomState(for: .searchBarPosition) ?? .bottom
5450
}
5551

52+
private var toolbarItems: [UIBarButtonItem] {
53+
guard #available(iOS 26.0, *) else {
54+
return [
55+
navigationButtonsBarItem,
56+
.flexibleSpace(),
57+
autofillAccessoryView,
58+
.flexibleSpace(),
59+
.fixedSpace(UX.fixedSpacerWidth),
60+
doneButton
61+
].compactMap { $0 }
62+
}
63+
64+
let isiPad = UIDevice.current.userInterfaceIdiom == .pad
65+
if isiPad {
66+
return [.flexibleSpace(), autofillAccessoryView].compactMap { $0 }
67+
} else if let autofillAccessoryView {
68+
return [navigationButtonsBarItem, autofillAccessoryView, doneButton]
69+
} else {
70+
return [navigationButtonsBarItem, .flexibleSpace(), doneButton]
71+
}
72+
}
73+
5674
// MARK: - UI Elements
5775
private let toolbar: UIToolbar = .build()
5876
private let toolbarTopHeightSpacer: UIView = .build()
@@ -77,15 +95,13 @@ final class AccessoryViewProvider: UIView, Themeable, InjectedThemeUUIDIdentifia
7795

7896
private lazy var navigationButtonsStackView: UIStackView = .build {
7997
$0.spacing = UX.fixedSpacerWidth
80-
$0.alignment = .center
8198
}
8299

83100
/// On iOS 26+, `UIBarButtonItem` has a fixed default padding between elements that cannot be reduced.
84101
/// To work around this limitation, we wrap the next and previous buttons in a `UIStackView` where
85102
/// we can control the spacing between them, then add the stack view as a single `UIBarButtonItem`.
86103
private lazy var navigationButtonsBarItem: UIBarButtonItem = {
87104
let barButton = UIBarButtonItem(customView: navigationButtonsStackView)
88-
if #available(iOS 26.0, *) { barButton.hidesSharedBackground = true }
89105
return barButton
90106
}()
91107

@@ -95,7 +111,6 @@ final class AccessoryViewProvider: UIView, Themeable, InjectedThemeUUIDIdentifia
95111
button.addTarget(self, action: #selector(self.tappedDoneButton), for: .touchUpInside)
96112
button.titleLabel?.font = FXFontStyles.Regular.body.scaledFont()
97113
let barButton = UIBarButtonItem(customView: button)
98-
if #available(iOS 26.0, *) { barButton.hidesSharedBackground = true }
99114
barButton.accessibilityIdentifier = AccessibilityIdentifiers.Browser.KeyboardAccessory.doneButton
100115
barButton.accessibilityLabel = .CreditCard.Settings.Done
101116
return barButton
@@ -116,7 +131,6 @@ final class AccessoryViewProvider: UIView, Themeable, InjectedThemeUUIDIdentifia
116131
accessoryView.accessibilityIdentifier =
117132
AccessibilityIdentifiers.Browser.KeyboardAccessory.creditCardAutofillButton
118133
accessoryView.isAccessibilityElement = true
119-
if #available(iOS 26.0, *) { accessoryView.hidesSharedBackground = true }
120134
return accessoryView
121135
}()
122136

@@ -132,7 +146,6 @@ final class AccessoryViewProvider: UIView, Themeable, InjectedThemeUUIDIdentifia
132146
accessoryView.accessibilityIdentifier =
133147
AccessibilityIdentifiers.Browser.KeyboardAccessory.addressAutofillButton
134148
accessoryView.isAccessibilityElement = true
135-
if #available(iOS 26.0, *) { accessoryView.hidesSharedBackground = true }
136149
return accessoryView
137150
}()
138151

@@ -147,7 +160,6 @@ final class AccessoryViewProvider: UIView, Themeable, InjectedThemeUUIDIdentifia
147160
accessoryView.accessibilityLabel = .PasswordAutofill.UseSavedPasswordFromKeyboard
148161
accessoryView.accessibilityIdentifier = AccessibilityIdentifiers.Autofill.footerPrimaryAction
149162
accessoryView.isAccessibilityElement = true
150-
if #available(iOS 26.0, *) { accessoryView.hidesSharedBackground = true }
151163
return accessoryView
152164
}()
153165

@@ -162,7 +174,6 @@ final class AccessoryViewProvider: UIView, Themeable, InjectedThemeUUIDIdentifia
162174
accessoryView.accessibilityLabel = .PasswordGenerator.KeyboardAccessoryButtonLabel
163175
accessoryView.accessibilityIdentifier = AccessibilityIdentifiers.PasswordGenerator.keyboardButton
164176
accessoryView.isAccessibilityElement = true
165-
if #available(iOS 26.0, *) { accessoryView.hidesSharedBackground = true }
166177
return accessoryView
167178
}()
168179

@@ -177,7 +188,6 @@ final class AccessoryViewProvider: UIView, Themeable, InjectedThemeUUIDIdentifia
177188
accessoryView.accessibilityLabel = .RelayMask.UseRelayEmailMaskFromKeyboard
178189
accessoryView.accessibilityIdentifier = AccessibilityIdentifiers.Browser.KeyboardAccessory.relayMaskAutofillButton
179190
accessoryView.isAccessibilityElement = true
180-
if #available(iOS 26.0, *) { accessoryView.hidesSharedBackground = true }
181191
return accessoryView
182192
}()
183193

@@ -209,15 +219,6 @@ final class AccessoryViewProvider: UIView, Themeable, InjectedThemeUUIDIdentifia
209219
}
210220

211221
// MARK: - Lifecycle
212-
override func layoutSubviews() {
213-
super.layoutSubviews()
214-
guard #available(iOS 26.0, *) else { return }
215-
backgroundView.layer.shadowPath = UIBezierPath(
216-
roundedRect: backgroundView.bounds,
217-
cornerRadius: UX.backgroundCornerRadius
218-
).cgPath
219-
}
220-
221222
override func removeFromSuperview() {
222223
super.removeFromSuperview()
223224
// Reset showing of credit card when dismissing the view
@@ -264,47 +265,20 @@ final class AccessoryViewProvider: UIView, Themeable, InjectedThemeUUIDIdentifia
264265
spacer.accessibilityElementsHidden = true
265266
}
266267

267-
private lazy var backgroundView: UIView = .build {
268-
$0.layer.cornerRadius = UX.backgroundCornerRadius
269-
$0.layer.shadowRadius = UX.shadowRadius
270-
$0.layer.shadowOffset = UX.shadowOffset
271-
$0.layer.shadowOpacity = 1
272-
}
273-
274268
private func setupLayout() {
275269
[previousButton, nextButton].forEach { navigationButtonsStackView.addArrangedSubview($0) }
276270
setupHeightSpacer(toolbarTopHeightSpacer, height: UX.spacerViewHeight)
277271
setupSpacer(leadingFixedSpacer, width: UX.fixedLeadingSpacerWidth)
278272
setupSpacer(trailingFixedSpacer, width: UX.fixedTrailingSpacerWidth)
273+
if #unavailable(iOS 26.0) { layer.cornerRadius = UX.cornerRadius }
279274

280-
addSubview(toolbarTopHeightSpacer)
275+
addSubviews(toolbarTopHeightSpacer, toolbar)
281276
if #available(iOS 26.0, *) {
282-
addSubview(backgroundView)
283-
backgroundView.addSubview(toolbar)
284-
285277
NSLayoutConstraint.activate([
286-
backgroundView.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor,
287-
constant: UX.leadingTrailingOffset),
288-
backgroundView.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor,
289-
constant: -UX.leadingTrailingOffset),
290-
backgroundView.topAnchor.constraint(lessThanOrEqualTo: topAnchor, constant: UX.topOffset),
291-
backgroundView.bottomAnchor.constraint(lessThanOrEqualTo: bottomAnchor, constant: -UX.bottomOffset),
292-
backgroundView.heightAnchor.constraint(equalToConstant: UX.backgroundViewHeight),
293-
294-
toolbar.leadingAnchor.constraint(equalTo: backgroundView.leadingAnchor),
295-
toolbar.trailingAnchor.constraint(equalTo: backgroundView.trailingAnchor),
296-
toolbar.bottomAnchor.constraint(equalTo: backgroundView.bottomAnchor)
297-
])
298-
} else {
299-
layer.cornerRadius = UX.cornerRadius
300-
addSubview(toolbar)
301-
NSLayoutConstraint.activate([
302-
toolbar.leadingAnchor.constraint(equalTo: leadingAnchor),
303-
toolbar.trailingAnchor.constraint(equalTo: trailingAnchor),
304-
toolbar.bottomAnchor.constraint(equalTo: bottomAnchor)
278+
previousButton.widthAnchor.constraint(equalToConstant: UX.buttonsWidth),
279+
nextButton.widthAnchor.constraint(equalToConstant: UX.buttonsWidth)
305280
])
306281
}
307-
308282
NSLayoutConstraint.activate([
309283
leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor),
310284
trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor),
@@ -314,49 +288,35 @@ final class AccessoryViewProvider: UIView, Themeable, InjectedThemeUUIDIdentifia
314288
toolbarTopHeightSpacer.bottomAnchor.constraint(equalTo: toolbar.topAnchor),
315289

316290
toolbar.topAnchor.constraint(equalTo: toolbarTopHeightSpacer.bottomAnchor),
291+
toolbar.leadingAnchor.constraint(equalTo: leadingAnchor),
292+
toolbar.trailingAnchor.constraint(equalTo: trailingAnchor),
293+
toolbar.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -UX.bottomOffset),
317294
])
318295
}
319296

320297
// MARK: - Private Methods
321298
private func configureToolbarItems() {
322-
toolbar.setItems([
323-
navigationButtonsBarItem,
324-
.flexibleSpace(),
325-
autofillAccessoryView,
326-
.flexibleSpace(),
327-
.fixedSpace(UX.fixedSpacerWidth),
328-
doneButton
329-
].compactMap { $0 }, animated: true)
330-
331-
toolbar.accessibilityElements = [
332-
previousButton,
333-
nextButton,
334-
autofillAccessoryView?.customView,
335-
doneButton.customView
336-
].compactMap { $0 }
299+
toolbar.setItems(toolbarItems, animated: true)
337300
}
338301

339302
// MARK: - ThemeApplicable
340303
func applyTheme() {
341304
let colors = themeManager.getCurrentTheme(for: windowUUID).colors
342-
let barButtonsTintColor = if #available(iOS 26.0, *) { colors.iconPrimary } else { colors.iconAccentBlue }
305+
// We want to use `.label` system color to make sure it blends well with the background when using glass effects.
306+
let barButtonsTintColor: UIColor = if #available(iOS 26.0, *) { .label } else { colors.iconAccentBlue }
343307
let buttonsBackgroundColor: UIColor = if #available(iOS 26.0, *) {
344308
.clear
345309
} else {
346310
colors.layer5Hover
347311
}
348-
if #available(iOS 26.0, *) {
349-
backgroundView.backgroundColor = colors.layerSurfaceMedium
350-
backgroundView.layer.shadowColor = colors.shadowStrong.cgColor
351-
}
352312

353313
backgroundColor = .clear
354-
doneButton.customView?.tintColor = barButtonsTintColor
314+
doneButton.customView?.tintColor = if #available(iOS 26.0, *) { colors.actionPrimary } else { colors.iconAccentBlue }
355315
previousButton.tintColor = barButtonsTintColor
356316
nextButton.tintColor = barButtonsTintColor
357317

358318
[creditCardAutofillView, addressAutofillView, loginAutofillView, passwordGeneratorView, relayMaskView].forEach {
359-
$0.accessoryImageViewTintColor = colors.iconPrimary
319+
$0.accessoryImageViewTintColor = if #available(iOS 26.0, *) { .label } else { colors.iconPrimary }
360320
$0.backgroundColor = buttonsBackgroundColor
361321
}
362322
}

firefox-ios/Client/Frontend/Autofill/AutofillAccessoryViewButtonItem.swift

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ final class AutofillAccessoryViewButtonItem: UIBarButtonItem {
2727
static let accessoryImageViewSize: CGFloat = 24
2828
static let accessoryButtonStackViewSpacing: CGFloat = 2
2929
static let cornerRadius: CGFloat = 4
30-
static let padding: CGFloat = 4
30+
static let iPadPadding: CGFloat = 80
3131
}
3232

3333
// MARK: - Properties
@@ -103,11 +103,42 @@ final class AutofillAccessoryViewButtonItem: UIBarButtonItem {
103103

104104
// Add constraints to provide padding
105105
accessoryView.translatesAutoresizingMaskIntoConstraints = false
106+
let isiPad = UIDevice.current.userInterfaceIdiom == .pad
107+
108+
if #available(iOS 26.0, *) {
109+
sharesBackground = false
110+
accessoryView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
111+
}
112+
113+
let leadingConstraint = if #available(iOS 26.0, *), isiPad {
114+
accessoryView.leadingAnchor
115+
.constraint(
116+
equalTo: containerView.leadingAnchor,
117+
constant: UX.iPadPadding
118+
)
119+
} else {
120+
accessoryView.leadingAnchor
121+
.constraint(
122+
greaterThanOrEqualTo: containerView.leadingAnchor
123+
)
124+
}
125+
126+
let trailingConstraint = if #available(iOS 26.0, *), isiPad {
127+
accessoryView.trailingAnchor
128+
.constraint(
129+
equalTo: containerView.trailingAnchor,
130+
constant: -UX.iPadPadding
131+
)
132+
} else {
133+
accessoryView.trailingAnchor
134+
.constraint(
135+
lessThanOrEqualTo: containerView.trailingAnchor
136+
)
137+
}
138+
106139
NSLayoutConstraint.activate([
107-
accessoryView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor,
108-
constant: UX.padding),
109-
accessoryView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor,
110-
constant: -UX.padding),
140+
leadingConstraint,
141+
trailingConstraint,
111142
accessoryView.topAnchor.constraint(equalTo: containerView.topAnchor),
112143
accessoryView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
113144
])
@@ -131,7 +162,7 @@ final class AutofillAccessoryViewButtonItem: UIBarButtonItem {
131162
}
132163

133164
private func updateBackgroundColor() {
134-
if let backgroundColor = backgroundColor {
165+
if let backgroundColor {
135166
customView?.backgroundColor = backgroundColor
136167
}
137168
}

0 commit comments

Comments
 (0)