Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,7 @@ struct AccessibilityIdentifiers {
struct Addresses {
static let title = "Addresses"
static let addAddress = "Add address"
static let addressCell = "AddressCell"
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,37 @@ struct AddressAutofillSettingsView: View {
viewBackground = Color(color.layer1)
}
}

struct ListHeaderPadding: ViewModifier {
let isLandscape: Bool
let paddingSize: CGFloat

func body(content: Content) -> some View {
let isPad = UIDevice().userInterfaceIdiom == .pad
let shouldAddPadding = !isLandscape || (isPad && isLandscape)
if #available(iOS 26.0, *) {
if shouldAddPadding {
content.padding(.leading, paddingSize)
} else {
content
}
} else {
content
}
}
}

struct ListItemIconPadding: ViewModifier {
let isLandscape: Bool
let paddingSize: CGFloat

func body(content: Content) -> some View {
let isPad = UIDevice().userInterfaceIdiom == .pad
let shouldAddPadding = !isLandscape || (isPad && isLandscape)
if #available(iOS 26.0, *), shouldAddPadding {
content.padding(.leading, paddingSize)
} else {
content
}
}
}
117 changes: 75 additions & 42 deletions firefox-ios/Client/Frontend/Autofill/Address/AddressCellView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ import struct MozillaAppServices.Address

/// A view representing a cell displaying address information.
struct AddressCellView: View {
// MARK: - Constants

private enum UX {
static let listIconPadding: CGFloat = -8
static let hStackSpacing: CGFloat = 24
static let vStackSpacing: CGFloat = 0
static let dividerHeight: CGFloat = 1
}

// MARK: - Properties

let windowUUID: WindowUUID
Expand All @@ -20,48 +29,76 @@ struct AddressCellView: View {
@State private var textColor: Color = .clear
@State private var customLightGray: Color = .clear
@State private var iconPrimary: Color = .clear
@State private var backgroundColor: Color = .clear
@State private var highlightColor: Color = .clear

@State private var isHighlighted = false
@GestureState private var isPressing = false
@State private var isLandscape = false

private(set) var address: Address
private(set) var onTap: () -> Void

// MARK: - Body

var body: some View {
Button(action: onTap) {
VStack(alignment: .leading, spacing: 0) {
HStack(alignment: .midIconAndLabel, spacing: 24) {
Image(StandardImageIdentifiers.Large.location)
.renderingMode(.template)
.padding(.leading, 16)
.foregroundColor(iconPrimary)
.alignmentGuide(.midIconAndLabel) { $0[VerticalAlignment.center] }
VStack(alignment: .leading) {
if !address.name.isEmpty {
Text(address.name)
.font(.body)
.foregroundColor(textColor)
.alignmentGuide(.midIconAndLabel) { $0[VerticalAlignment.center] }
}
if !address.streetAddress.isEmpty {
Text(address.streetAddress)
.font(.subheadline)
.foregroundColor(customLightGray)
}
if !address.addressCityStateZipcode.isEmpty {
Text(address.addressCityStateZipcode)
.font(.subheadline)
.foregroundColor(customLightGray)
}
VStack(spacing: UX.vStackSpacing) {
HStack(alignment: .midIconAndLabel, spacing: UX.hStackSpacing) {
Image(decorative: StandardImageIdentifiers.Large.location)
.renderingMode(.template)
.modifier(ListItemIconPadding(isLandscape: isLandscape,
paddingSize: UX.listIconPadding))
.foregroundColor(iconPrimary)
.alignmentGuide(.midIconAndLabel) { $0[VerticalAlignment.center] }
VStack(alignment: .leading) {
if !address.name.isEmpty {
Text(address.name)
.font(.body)
.foregroundColor(textColor)
.alignmentGuide(.midIconAndLabel) { $0[VerticalAlignment.center] }
}
if !address.streetAddress.isEmpty {
Text(address.streetAddress)
.font(.subheadline)
.foregroundColor(customLightGray)
}
if !address.addressCityStateZipcode.isEmpty {
Text(address.addressCityStateZipcode)
.font(.subheadline)
.foregroundColor(customLightGray)
}
Spacer()
}
Spacer()
}
.padding()
Spacer().frame(height: 0)
Divider().frame(height: 1)
Divider().frame(height: UX.dividerHeight)
}
.contentShape(Rectangle())
.onChange(of: isPressing) { pressing in
if pressing {
isHighlighted = true
} else {
withAnimation(.easeOut(duration: 0.2)) {
isHighlighted = false
}
}
}
.gesture(
DragGesture(minimumDistance: 0)
.updating($isPressing) { _, state, _ in state = true }
.onEnded { value in
let isWithinTapBounds = abs(value.translation.width) < 20
&& abs(value.translation.height) < 20
if isWithinTapBounds {
onTap()
}
}
)
.listRowInsets(EdgeInsets())
.buttonStyle(AddressButtonStyle(theme: themeManager.getCurrentTheme(for: windowUUID)))
.listRowBackground(
(isHighlighted ? highlightColor : backgroundColor)
.edgesIgnoringSafeArea([.leading, .trailing])
)
.listRowSeparator(.hidden)
.onAppear {
applyTheme(theme: themeManager.getCurrentTheme(for: windowUUID))
Expand All @@ -70,7 +107,14 @@ struct AddressCellView: View {
guard let uuid = notification.windowUUID, uuid == windowUUID else { return }
applyTheme(theme: themeManager.getCurrentTheme(for: windowUUID))
}
.onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
isLandscape = UIDevice.current.orientation.isLandscape
}
.accessibilityElement(children: .ignore)
.accessibilityIdentifier(AccessibilityIdentifiers.Settings.Address.Addresses.addressCell)
.accessibilityLabel(address.a11ySettingsRow)
.accessibilityAddTraits(.isButton)
.accessibilityAction { onTap() }
}

// MARK: - Theme Application
Expand All @@ -82,18 +126,7 @@ struct AddressCellView: View {
textColor = Color(color.textPrimary)
customLightGray = Color(color.textSecondary)
iconPrimary = Color(color.iconPrimary)
}
}

// MARK: - CustomButtonStyle

/// A address button style with a specific theme.
struct AddressButtonStyle: ButtonStyle {
let theme: Theme

func makeBody(configuration: Configuration) -> some View {
configuration.label
.background(configuration.isPressed ? Color(theme.colors.layer1) : Color(theme.colors.layer2))
.foregroundColor(.white)
backgroundColor = Color(color.layer2)
highlightColor = Color(color.layer5Hover)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct AddressListView: View {
static let titleFontSize: CGFloat = 22
static let subtitleFontSize: CGFloat = 16
static let contentUnavailableViewTopPadding: CGFloat = 125
static let listPadding: CGFloat = -8
}

// MARK: - Properties
Expand All @@ -34,13 +35,17 @@ struct AddressListView: View {
@State var imageColor: Color = .clear
@State var listColor: Color = .clear

@State private var isLandscape = false

// MARK: - Body

var body: some View {
Group {
if viewModel.showSection {
List {
Section(header: Text(String.Addresses.Settings.SavedAddressesSectionTitle)) {
Section(header: Text(String.Addresses.Settings.SavedAddressesSectionTitle)
.modifier(ListHeaderPadding(isLandscape: isLandscape,
paddingSize: UX.listPadding))) {
ForEach(viewModel.addresses, id: \.self) { address in
AddressCellView(
windowUUID: windowUUID,
Expand Down Expand Up @@ -86,6 +91,9 @@ struct AddressListView: View {
guard let uuid = notification.windowUUID, uuid == windowUUID else { return }
applyTheme(theme: themeManager.getCurrentTheme(for: windowUUID))
}
.onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
isLandscape = UIDevice.current.orientation.isLandscape
}
.onDisappear {
viewModel.editAddressWebViewManager.teardownWebView()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ struct ColoredListStyle: ViewModifier {
.scrollContentBackground(.hidden)
.background(backgroundColor)
} else {
content.listStyle(.plain)
content
.listStyle(.plain)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ final class AddressScreen {
}

func reachEditAndRemoveAddress() {
app.collectionViews.cells.buttons.staticTexts.firstMatch.tapWithRetry()
app.collectionViews.cells.buttons[AccessibilityIdentifiers.Settings.Address.Addresses.addressCell].tapWithRetry()
// Update the all addresses fields
let buttonEdit = sel.BUTTON_EDIT.element(in: app)
buttonEdit.waitAndTap()
Expand Down
Loading