Merge branch 'feature/breadcrumbs' into 'develop'

Feature/breadcrumbs

See merge request BPHV_MIPS/vds_ios!190
This commit is contained in:
Bruce, Matt R 2024-03-27 19:46:33 +00:00
commit f327fce1c9
7 changed files with 72 additions and 70 deletions

View File

@ -23,9 +23,9 @@
710607952B91A99500F2863F /* TitleletChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 710607942B91A99500F2863F /* TitleletChangeLog.txt */; };
7115BD3C2B84C0C200E0A610 /* TileContainerChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */; };
71ACE89C2BA0451200FB6ADC /* PaginationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71ACE89B2BA0451200FB6ADC /* PaginationContainer.swift */; };
71ACE89E2BA1CC1700FB6ADC /* TiletEyebrowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71ACE89D2BA1CC1700FB6ADC /* TiletEyebrowModel.swift */; };
71B23C2D2B91FA690027F7D9 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71B23C2C2B91FA690027F7D9 /* Pagination.swift */; };
71B5FCBB2B95A0CA00269BCC /* PaginationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */; };
71ACE89E2BA1CC1700FB6ADC /* TiletEyebrowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71ACE89D2BA1CC1700FB6ADC /* TiletEyebrowModel.swift */; };
71BFA70A2B7F70E6000DCE33 /* DropShadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */; };
71C02B382B7BD98F00E93E66 /* NotificationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */; };
71FC86DA2B96F44C00700965 /* PaginationButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FC86D92B96F44C00700965 /* PaginationButton.swift */; };
@ -165,7 +165,6 @@
EAEEECAF2B1FC2BA00531FC2 /* ToggleViewChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = EAEEECAE2B1FC2BA00531FC2 /* ToggleViewChangeLog.txt */; };
EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9829D4850E00101452 /* Clickable.swift */; };
EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9A29DB1A6000101452 /* Changeable.swift */; };
EAF4A6A12BAC8B94006BCC2C /* BreadcrumbsFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF4A6A02BAC8B94006BCC2C /* BreadcrumbsFlowLayout.swift */; };
EAF7F0952899861000B287F5 /* CheckboxItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0932899861000B287F5 /* CheckboxItem.swift */; };
EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0992899B17200B287F5 /* CATransaction.swift */; };
EAF7F0A0289AB7EC00B287F5 /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F09F289AB7EC00B287F5 /* View.swift */; };
@ -211,9 +210,9 @@
710607942B91A99500F2863F /* TitleletChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TitleletChangeLog.txt; sourceTree = "<group>"; };
7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileContainerChangeLog.txt; sourceTree = "<group>"; };
71ACE89B2BA0451200FB6ADC /* PaginationContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationContainer.swift; sourceTree = "<group>"; };
71ACE89D2BA1CC1700FB6ADC /* TiletEyebrowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TiletEyebrowModel.swift; sourceTree = "<group>"; };
71B23C2C2B91FA690027F7D9 /* Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pagination.swift; sourceTree = "<group>"; };
71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = PaginationChangeLog.txt; sourceTree = "<group>"; };
71ACE89D2BA1CC1700FB6ADC /* TiletEyebrowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TiletEyebrowModel.swift; sourceTree = "<group>"; };
71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropShadowable.swift; sourceTree = "<group>"; };
71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = NotificationChangeLog.txt; sourceTree = "<group>"; };
71FC86D92B96F44C00700965 /* PaginationButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationButton.swift; sourceTree = "<group>"; };
@ -355,7 +354,6 @@
EAEEECAE2B1FC2BA00531FC2 /* ToggleViewChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ToggleViewChangeLog.txt; sourceTree = "<group>"; };
EAF1FE9829D4850E00101452 /* Clickable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clickable.swift; sourceTree = "<group>"; };
EAF1FE9A29DB1A6000101452 /* Changeable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Changeable.swift; sourceTree = "<group>"; };
EAF4A6A02BAC8B94006BCC2C /* BreadcrumbsFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbsFlowLayout.swift; sourceTree = "<group>"; };
EAF7F0932899861000B287F5 /* CheckboxItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckboxItem.swift; sourceTree = "<group>"; };
EAF7F0992899B17200B287F5 /* CATransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CATransaction.swift; sourceTree = "<group>"; };
EAF7F09F289AB7EC00B287F5 /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = "<group>"; };
@ -400,7 +398,6 @@
isa = PBXGroup;
children = (
18A65A012B96E848006602CC /* Breadcrumbs.swift */,
EAF4A6A02BAC8B94006BCC2C /* BreadcrumbsFlowLayout.swift */,
18A65A032B96F050006602CC /* BreadcrumbItem.swift */,
1855EC652BAABF2A002ACAC2 /* BreadcrumbItemModel.swift */,
1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */,
@ -1139,7 +1136,6 @@
71FC86DA2B96F44C00700965 /* PaginationButton.swift in Sources */,
EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */,
EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */,
EAF4A6A12BAC8B94006BCC2C /* BreadcrumbsFlowLayout.swift in Sources */,
EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */,
EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */,
EA8E40932A82889500934ED3 /* TooltipDialog.swift in Sources */,

View File

@ -24,6 +24,8 @@ final class BreadcrumbCellItem: UICollectionViewCell {
$0.distribution = .fill
$0.alignment = .fill
$0.spacing = VDSLayout.Spacing.space1X.value
$0.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
$0.setContentHuggingPriority(.defaultHigh, for: .horizontal)
}
}()
@ -64,13 +66,14 @@ final class BreadcrumbCellItem: UICollectionViewCell {
///Updating the breadCrumbItem and UI based on the selected flag along with the surface
func update(surface: Surface, hideSlash: Bool, breadCrumbItem: BreadcrumbItem) {
//remove views from stack
separator.removeFromSuperview()
self.breadCrumbItem?.removeFromSuperview()
//update surface
separator.surface = surface
breadCrumbItem.surface = surface
breadCrumbItem.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
breadCrumbItem.setContentHuggingPriority(.defaultLow, for: .horizontal)
//remove previous views
stackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
//add to stack
stackView.addArrangedSubview(separator)
@ -80,15 +83,8 @@ final class BreadcrumbCellItem: UICollectionViewCell {
//update separator
separator.textColor = textColorConfiguration.getColor(surface)
separator.isHidden = hideSlash
self.breadCrumbItem = breadCrumbItem
layoutIfNeeded()
}
/// Remove views from StackView.
override func prepareForReuse() {
super.prepareForReuse()
separator.removeFromSuperview()
breadCrumbItem?.removeFromSuperview()
}
}

View File

@ -44,9 +44,15 @@ open class BreadcrumbItem: ButtonBase {
/// The natural size for the receiving view, considering only properties of the view itself.
open override var intrinsicContentSize: CGSize {
return titleLabel?.intrinsicContentSize ?? super.intrinsicContentSize
guard let titleLabel else { return super.intrinsicContentSize }
// Calculate the titleLabel's intrinsic content size
let labelSize = titleLabel.sizeThatFits(CGSize(width: self.frame.width, height: CGFloat.greatestFiniteMagnitude))
// Adjust the size if needed (add any additional padding if your design requires)
let adjustedSize = CGSize(width: labelSize.width + contentEdgeInsets.left + contentEdgeInsets.right,
height: labelSize.height + contentEdgeInsets.top + contentEdgeInsets.bottom)
return adjustedSize
}
//--------------------------------------------------
// MARK: - Private Properties
//--------------------------------------------------
@ -64,8 +70,8 @@ open class BreadcrumbItem: ButtonBase {
open override func setup() {
super.setup()
isAccessibilityElement = true
accessibilityTraits = .button
accessibilityLabel = "Breadcrumb"
accessibilityTraits = .link
contentHorizontalAlignment = .leading
}
/// Used to make changes to the View based off a change events or from local properties.
@ -86,4 +92,11 @@ open class BreadcrumbItem: ButtonBase {
shouldUpdateView = true
setNeedsUpdate()
}
/// Used to update any Accessibility properties.
open override func updateAccessibility() {
super.updateAccessibility()
accessibilityLabel = "Breadcrumb \(text ?? "")"
}
}

View File

@ -47,14 +47,17 @@ open class Breadcrumbs: View {
//--------------------------------------------------
// MARK: - Private Properties
//--------------------------------------------------
let layout: UICollectionViewFlowLayout = BreadcrumbsFlowLayout().with {
$0.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
$0.minimumInteritemSpacing = VDSLayout.Spacing.space1X.value
$0.minimumLineSpacing = VDSLayout.Spacing.space1X.value
$0.sectionInset = .zero
$0.scrollDirection = .vertical
fileprivate lazy var layout = ButtonGroupPositionLayout().with {
$0.position = .left
$0.delegate = self
$0.axisSpacer = { _, _, _ in
return VDSLayout.Spacing.space1X.value
}
$0.verticalSpacer = { _, _ in
return VDSLayout.Spacing.space1X.value
}
}
///Collectionview to render Breadcrumb Items
private lazy var collectionView: SelfSizingCollectionView = {
let collectionView = SelfSizingCollectionView(frame: .zero, collectionViewLayout: layout)
@ -134,9 +137,10 @@ open class Breadcrumbs: View {
self.collectionView.collectionViewLayout.invalidateLayout()
}
}
private var separatorWidth = Label().with { $0.text = "/"; $0.sizeToFit() }.intrinsicContentSize.width
}
extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource {
extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource, ButtongGroupPositionLayoutDelegate {
//--------------------------------------------------
// MARK: - UICollectionView Delegate & Datasource
//--------------------------------------------------
@ -150,5 +154,16 @@ extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource {
cell.update(surface: surface, hideSlash: hideSlash, breadCrumbItem: breadcrumbs[indexPath.row])
return cell
}
public func collectionView(_ collectionView: UICollectionView, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
let breadcrumb = breadcrumbs[indexPath.row]
let intrinsicSize = breadcrumb.intrinsicContentSize
let separatorFullWidth: CGFloat = indexPath.row == 0 ? 0 : VDSLayout.Spacing.space1X.value + separatorWidth
let cellwidth = intrinsicSize.width + separatorFullWidth
return .init(width: min(cellwidth, collectionView.frame.width), height: intrinsicSize.height)
}
public func collectionView(_ collectionView: UICollectionView, buttonBaseAtIndexPath indexPath: IndexPath) -> ButtonBase {
breadcrumbs[indexPath.row]
}
}

View File

@ -1,31 +0,0 @@
//
// BreadcrumsFlowLayout.swift
// VDS
//
// Created by Matt Bruce on 3/21/24.
//
import Foundation
import UIKit
class BreadcrumbsFlowLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributes = super.layoutAttributesForElements(in: rect)
var leftMargin = sectionInset.left
var maxY: CGFloat = -1.0
attributes?.forEach { layoutAttribute in
if layoutAttribute.frame.origin.y >= maxY {
leftMargin = sectionInset.left
}
layoutAttribute.frame.origin.x = leftMargin
leftMargin += layoutAttribute.frame.width + minimumInteritemSpacing
maxY = max(layoutAttribute.frame.maxY , maxY)
}
return attributes
}
}

View File

@ -6,21 +6,18 @@
//
import Foundation
import UIKit
struct ButtonGroupConstants {
static let defaultSpace = 12.0
enum ButtonSpacingAxis {
case horizontal, vertical
}
/// This will determine the spacing that will go between 2 ButtonBases either horizontally or vertically
/// - Parameters:
/// - axis: horizontal/vertical
/// - primary: first ButtonBase
/// - neighboring: next ButtonBase based off of axis
/// - Returns: float value
static func getSpacing(for axis: ButtonSpacingAxis, with primary: ButtonBase, neighboring: ButtonBase) -> CGFloat {
static func getSpacing(for axis: NSLayoutConstraint.Axis, with primary: ButtonBase, neighboring: ButtonBase) -> CGFloat {
//large button
if let button = primary as? Button, button.size == .large {

View File

@ -146,6 +146,8 @@ class ButtonLayoutAttributes: UICollectionViewLayoutAttributes{
class ButtonGroupPositionLayout: UICollectionViewLayout {
weak var delegate: ButtongGroupPositionLayoutDelegate?
var verticalSpacer: ((ButtonCollectionViewRow, ButtonCollectionViewRow?) -> CGFloat)?
var axisSpacer: ((NSLayoutConstraint.Axis, ButtonBase, ButtonBase) -> CGFloat)?
// Total height of the content. Will be used to configure the scrollview content
var layoutHeight: CGFloat = 0.0
@ -154,7 +156,7 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
var buttonPercentage: CGFloat?
private var itemCache: [ButtonLayoutAttributes] = []
override func prepare() {
super.prepare()
@ -226,7 +228,7 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
let neighbor = delegate.collectionView(collectionView, buttonBaseAtIndexPath: IndexPath(item: nextItem, section: section))
// get the spacing to go between the current and next button
itemSpacing = ButtonGroupConstants.getSpacing(for: .horizontal, with: itemButtonBase, neighboring: neighbor)
itemSpacing = getAxisSpacing(for: .horizontal, with: itemButtonBase, neighboring: neighbor)
}
// create the custom layout attribute
@ -255,7 +257,7 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
if item > 0 {
let prevRow = rows[item - 1]
rowSpacing = ButtonGroupConstants.getVerticalSpacing(for: prevRow, neighboringRow: row)
rowSpacing = getVerticalSpacing(for: prevRow, neighboringRow: row)
row.rowY = layoutHeight + rowSpacing
layoutHeight += rowSpacing
}
@ -300,5 +302,19 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
}
return collectionView.bounds.width
}
private func getAxisSpacing(for axis: NSLayoutConstraint.Axis, with primary: ButtonBase, neighboring: ButtonBase) -> CGFloat {
guard let axisSpacer else {
return ButtonGroupConstants.getSpacing(for: axis, with: primary, neighboring: neighboring)
}
return axisSpacer(axis, primary, neighboring)
}
private func getVerticalSpacing(for row: ButtonCollectionViewRow, neighboringRow: ButtonCollectionViewRow?) -> CGFloat {
guard let verticalSpacer else {
return ButtonGroupConstants.getVerticalSpacing(for: row, neighboringRow: neighboringRow)
}
return verticalSpacer(row, neighboringRow)
}
}