// // ButtonGroupConstants.swift // VDS // // Created by Matt Bruce on 12/1/22. // import Foundation 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 { //large button if let button = primary as? Button, button.size == .large { if let neighboringButton = neighboring as? Button, neighboringButton.size == .large { return axis == .horizontal ? 12.0 : 12.0 } else if neighboring is TextLinkCaret { return axis == .horizontal ? 24.0 : 24.0 } else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .large { return axis == .horizontal ? 16.0 : 16.0 } else { return defaultSpace } } //large text link else if let textLink = primary as? TextLink, textLink.size == .large { if let neighboringButton = neighboring as? Button, neighboringButton.size == .large { return axis == .horizontal ? 16.0 : 16.0 } else if neighboring is TextLinkCaret { return axis == .horizontal ? 24.0 : 24.0 } else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .large { return axis == .horizontal ? 16.0 : 24.0 } else { return defaultSpace } } //text link caret else if let _ = primary as? TextLinkCaret { if let neighboringButton = neighboring as? Button, neighboringButton.size == .large { return axis == .horizontal ? 24.0 : 24.0 } else if let _ = neighboring as? TextLinkCaret { return axis == .horizontal ? 24.0 : 24.0 } else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .large { return axis == .horizontal ? 24.0 : 24.0 } else { return defaultSpace } } //small button else if let button = primary as? Button, button.size == .small { if let neighboringButton = neighboring as? Button, neighboringButton.size == .small { return axis == .horizontal ? 12.0 : 12.0 } else if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .small { return axis == .horizontal ? 16.0 : 24.0 } else { return defaultSpace } } //small text link else if let textLink = primary as? TextLink, textLink.size == .small { if let neighboringTextLink = neighboring as? TextLink, neighboringTextLink.size == .small { return axis == .horizontal ? 16.0 : 24.0 } else if let _ = neighboring as? Button { return axis == .horizontal ? 16.0 : 32.0 } else { return defaultSpace } } //return defaultSpace else { return defaultSpace } } // /// Gets the tallest ButtonBases within the row /// - Parameter row: Row that includes the attributes /// - Returns: Array of [ButtonLayoutAttributes] of the tallest items private static func getTallestAttributes(for row: ButtonCollectionViewRow) -> [ButtonLayoutAttributes] { var height = 0.0 var foundIndexes:[Int] = [] for (index, attribute) in row.attributes.enumerated() { if attribute.frame.height >= height { height = attribute.frame.height foundIndexes.append(index) } } return foundIndexes.compactMap { row.attributes[$0] } } /// Gets the vertical spacing that will go between rows. /// - Parameters: /// - row: Primary row that the space will go between /// - neighboringRow: Secondary row that will be below the Primary /// - Returns: Amount of space that should live between these rows based off of the items. The largest space will win when the comparison occurs. static func getVerticalSpacing(for row: ButtonCollectionViewRow, neighboringRow: ButtonCollectionViewRow?) -> CGFloat { // if the neighboringRow is nil, this is the last row in the collection // so return no space guard let neighboringRow else { return 0.0 } let primaryTallestAttributes = getTallestAttributes(for: row) let neighboringTallestAttributes = getTallestAttributes(for: neighboringRow) if primaryTallestAttributes.count > 0 && neighboringTallestAttributes.count > 0 { // If there is a tie for “tallest child,” the tiebreaker criteria is to refer to the child with the larger space requirement (for vertical spacing). var largestVerticalSpace = defaultSpace primaryTallestAttributes.forEach { primaryAttribute in neighboringTallestAttributes.forEach { neighboringTallestAttribute in let space = getSpacing(for: .vertical, with: primaryAttribute.button!, neighboring: neighboringTallestAttribute.button!) if space > largestVerticalSpace { largestVerticalSpace = space } } } return largestVerticalSpace } else { return defaultSpace } } }