Table component refactoring
This commit is contained in:
parent
ed684acd62
commit
0d421190a2
@ -25,9 +25,7 @@
|
||||
445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; };
|
||||
44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; };
|
||||
44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; };
|
||||
446209482BE8E3AF003EBC19 /* TableCellImageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 446209472BE8E3AF003EBC19 /* TableCellImageModel.swift */; };
|
||||
44A952D92BE384C40009F874 /* TableCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952D82BE384C40009F874 /* TableCellModel.swift */; };
|
||||
44A952DB2BE3852E0009F874 /* TableCellLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952DA2BE3852E0009F874 /* TableCellLabelModel.swift */; };
|
||||
44A952DD2BE3DA820009F874 /* TableFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */; };
|
||||
5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; };
|
||||
5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; };
|
||||
@ -220,9 +218,7 @@
|
||||
445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = "<group>"; };
|
||||
44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = "<group>"; };
|
||||
44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
|
||||
446209472BE8E3AF003EBC19 /* TableCellImageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableCellImageModel.swift; sourceTree = "<group>"; };
|
||||
44A952D82BE384C40009F874 /* TableCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableCellModel.swift; sourceTree = "<group>"; };
|
||||
44A952DA2BE3852E0009F874 /* TableCellLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableCellLabelModel.swift; sourceTree = "<group>"; };
|
||||
44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableFlowLayout.swift; sourceTree = "<group>"; };
|
||||
5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = "<group>"; };
|
||||
5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = "<group>"; };
|
||||
@ -446,8 +442,6 @@
|
||||
443DBAF92BDA303F0021497E /* TableCellItem.swift */,
|
||||
44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */,
|
||||
44A952D82BE384C40009F874 /* TableCellModel.swift */,
|
||||
44A952DA2BE3852E0009F874 /* TableCellLabelModel.swift */,
|
||||
446209472BE8E3AF003EBC19 /* TableCellImageModel.swift */,
|
||||
);
|
||||
path = Table;
|
||||
sourceTree = "<group>";
|
||||
@ -1224,7 +1218,6 @@
|
||||
EA0B18052A9E2D2D00F2D0CD /* SelectorBase.swift in Sources */,
|
||||
EAC71A1D2A2E155A00E47A9F /* Checkbox.swift in Sources */,
|
||||
EAF7F0AB289B13FD00B287F5 /* TextStyleLabelAttribute.swift in Sources */,
|
||||
44A952DB2BE3852E0009F874 /* TableCellLabelModel.swift in Sources */,
|
||||
EAB1D29C28A5618900DAE764 /* RadioButtonGroup.swift in Sources */,
|
||||
EA81410B2A0E8E3C004F60D2 /* ButtonIcon.swift in Sources */,
|
||||
EA985BE629688F6A00F2FF2E /* TileletBadgeModel.swift in Sources */,
|
||||
@ -1245,7 +1238,6 @@
|
||||
EA0D1C392A6AD4DF00E5C127 /* Typography+SpacingConfig.swift in Sources */,
|
||||
EAB2376629E9952D00AABE9A /* UIApplication.swift in Sources */,
|
||||
EAB5FED429267EB300998C17 /* UIView+NSLayoutConstraint.swift in Sources */,
|
||||
446209482BE8E3AF003EBC19 /* TableCellImageModel.swift in Sources */,
|
||||
EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */,
|
||||
EA33623E2892EE950071C351 /* UIDevice.swift in Sources */,
|
||||
EA985C692971B90B00F2FF2E /* IconSize.swift in Sources */,
|
||||
|
||||
@ -32,6 +32,10 @@ open class Table: View {
|
||||
private lazy var flowLayout = MatrixFlowLayout().with {
|
||||
$0.delegate = self
|
||||
}
|
||||
|
||||
private var tableData: [[TableItemModel]] {
|
||||
return tableHeader + tableRows
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Enums
|
||||
@ -67,15 +71,9 @@ open class Table: View {
|
||||
|
||||
open var padding: Padding = .standard { didSet { setNeedsUpdate() } }
|
||||
|
||||
open var headerBottomLine: Bool = false { didSet { setNeedsUpdate() } }
|
||||
open var tableHeader: [[TableItemModel]] = [] { didSet { setNeedsUpdate() } }
|
||||
|
||||
open var rowBottomLine: Bool = false { didSet { setNeedsUpdate() } }
|
||||
|
||||
open var headerBottomLineType: Line.Style = .primary { didSet { setNeedsUpdate() } }
|
||||
|
||||
open var rowBottomLineType: Line.Style = .secondary { didSet { setNeedsUpdate() } }
|
||||
|
||||
open var tableData: [[TableCellModel]] = [] { didSet { setNeedsUpdate() } }
|
||||
open var tableRows: [[TableItemModel]] = [] { didSet { setNeedsUpdate() } }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Overrides
|
||||
@ -108,13 +106,11 @@ extension Table: UICollectionViewDelegate, UICollectionViewDataSource, TableColl
|
||||
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TableCellItem.Identifier, for: indexPath) as? TableCellItem else { return UICollectionViewCell() }
|
||||
let currentItem = tableData[indexPath.section][indexPath.row]
|
||||
let shouldStrip = striped ? (indexPath.section % 2 != 0) : false
|
||||
let style = indexPath.section == 0 ? headerBottomLineType : rowBottomLineType
|
||||
let hideSeparator = indexPath.section == 0 ? headerBottomLine : rowBottomLine
|
||||
cell.updateCell(content: currentItem, surface: surface, separatorStyle: style, isHeader: indexPath.section == 0, hideSeparator: hideSeparator, striped: shouldStrip, padding: padding)
|
||||
cell.updateCell(content: currentItem, surface: surface, striped: shouldStrip, padding: padding)
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableCellModel {
|
||||
func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableItemModel {
|
||||
return tableData[indexPath.section][indexPath.row]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
//
|
||||
// TableCellImageModel.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Nadigadda, Sumanth on 06/05/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Table {
|
||||
|
||||
public struct TableCellImageModel: TableCellModel, Surfaceable {
|
||||
|
||||
public var defaultHeight: CGFloat { return 50.0 }
|
||||
|
||||
public var name: Icon.Name
|
||||
|
||||
public var size: Icon.Size
|
||||
|
||||
public var surface: Surface
|
||||
|
||||
public init(name: Icon.Name, size: Icon.Size, surface: Surface = .light) {
|
||||
self.name = name
|
||||
self.size = size
|
||||
self.surface = surface
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -15,18 +15,6 @@ final class TableCellItem: UICollectionViewCell {
|
||||
|
||||
private let containerView = View()
|
||||
|
||||
private var cellLabel = Label().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
||||
$0.setContentHuggingPriority(.defaultHigh, for:.vertical)
|
||||
$0.textAlignment = .left
|
||||
$0.lineBreakMode = .byWordWrapping
|
||||
}
|
||||
|
||||
private var icon = Icon().with {
|
||||
$0.size = UIDevice.isIPad ? .medium : .small
|
||||
}
|
||||
|
||||
private let separator: Line = Line()
|
||||
|
||||
private let backgroundColorConfiguration = SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryDark)
|
||||
@ -51,60 +39,32 @@ final class TableCellItem: UICollectionViewCell {
|
||||
containerView.pinToSuperView()
|
||||
}
|
||||
|
||||
func updateCell(content: TableCellModel, surface: Surface, separatorStyle: Line.Style, isHeader: Bool = false, hideSeparator: Bool = false, striped: Bool = false, padding: Table.Padding = .standard) {
|
||||
func updateCell(content: TableItemModel, surface: Surface, striped: Bool = false, padding: Table.Padding = .standard) {
|
||||
|
||||
containerView.subviews.forEach({ $0.removeFromSuperview() })
|
||||
self.padding = padding
|
||||
containerView.surface = surface
|
||||
containerView.backgroundColor = striped ? stripedColorConfiguration.getColor(surface) : backgroundColorConfiguration.getColor(surface)
|
||||
|
||||
if let model = content as? Table.TableCellLabelModel {
|
||||
addLabel(model: model, surface: surface, isHeader: isHeader, padding: padding)
|
||||
} else if let model = content as? Table.TableCellImageModel {
|
||||
addImage(model: model, surface: surface)
|
||||
containerView.addSubview(content.component)
|
||||
|
||||
if var surfacedView = content.component as? Surfaceable {
|
||||
surfacedView.surface = surface
|
||||
}
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
content.component.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: VDSLayout.space1X),
|
||||
content.component.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor, constant: padding.verticalValue()),
|
||||
containerView.bottomAnchor.constraint(greaterThanOrEqualTo: content.component.bottomAnchor, constant: padding.verticalValue()),
|
||||
containerView.trailingAnchor.constraint(greaterThanOrEqualTo: content.component.trailingAnchor, constant: padding.horizontalValue()),
|
||||
containerView.centerYAnchor.constraint(equalTo: content.component.centerYAnchor)
|
||||
])
|
||||
|
||||
containerView.addSubview(separator)
|
||||
separator.pinLeading().pinTrailing().pinBottom()
|
||||
|
||||
separator.isHidden = !hideSeparator
|
||||
separator.style = separatorStyle
|
||||
separator.style = content.bottomLine ?? .primary
|
||||
separator.isHidden = content.bottomLine == nil
|
||||
separator.surface = surface
|
||||
}
|
||||
|
||||
private func addLabel(model: Table.TableCellLabelModel, surface: Surface, isHeader: Bool, padding: Table.Padding) {
|
||||
|
||||
containerView.addSubview(cellLabel)
|
||||
cellLabel.pinLeading(VDSLayout.space1X)
|
||||
NSLayoutConstraint.activate([
|
||||
cellLabel.topAnchor.constraint(equalTo: containerView.topAnchor, constant: padding.verticalValue()),
|
||||
containerView.bottomAnchor.constraint(equalTo: cellLabel.bottomAnchor, constant: padding.verticalValue()),
|
||||
containerView.trailingAnchor.constraint(equalTo: cellLabel.trailingAnchor, constant: padding.horizontalValue())
|
||||
])
|
||||
|
||||
cellLabel.textStyle = textStyle(for: isHeader)
|
||||
cellLabel.text = model.text
|
||||
cellLabel.surface = surface
|
||||
}
|
||||
|
||||
private func addImage(model: Table.TableCellImageModel, surface: Surface) {
|
||||
containerView.addSubview(icon)
|
||||
icon.pinLeading().pinCenterY()
|
||||
|
||||
icon.name = model.name
|
||||
icon.surface = surface
|
||||
}
|
||||
|
||||
private func textStyle(for header:Bool) -> TextStyle {
|
||||
return header ? .boldTitleSmall : UIDevice.isIPad ? .bodyLarge : .bodySmall
|
||||
}
|
||||
|
||||
// override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
|
||||
// let labelWidth = layoutAttributes.frame.size.width - (2 * padding.horizontalValue())
|
||||
// let maxbounds = CGSize(width: labelWidth, height: CGFloat.greatestFiniteMagnitude)
|
||||
// let labelSize = cellLabel.textRect(forBounds: CGRect(origin: .zero, size: maxbounds), limitedToNumberOfLines: cellLabel.numberOfLines)
|
||||
// var labelHeight = max(labelSize.height, layoutAttributes.frame.size.height) + (2 * padding.horizontalValue())
|
||||
// layoutAttributes.frame.size = CGSize(width: layoutAttributes.frame.size.width, height: labelHeight)
|
||||
// return layoutAttributes
|
||||
// }
|
||||
}
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
//
|
||||
// TableCellLabelModel.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Nadigadda, Sumanth on 02/05/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Table {
|
||||
public struct TableCellLabelModel: TableCellModel, Surfaceable {
|
||||
|
||||
public var defaultHeight: CGFloat { return 50.0 }
|
||||
|
||||
public var text: String
|
||||
|
||||
public var accessibilityString: String?
|
||||
|
||||
public var surface: Surface
|
||||
|
||||
public init(text: String, accessibilityString: String? = "", surface: Surface = .light) {
|
||||
self.text = text
|
||||
self.accessibilityString = accessibilityString
|
||||
self.surface = surface
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,38 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import VDSTokens
|
||||
|
||||
public protocol TableCellModel {
|
||||
var defaultHeight: CGFloat { get }
|
||||
public protocol ComponentHeight {
|
||||
func estimatedHeight(for width: CGFloat) -> CGFloat?
|
||||
}
|
||||
|
||||
public struct TableItemModel {
|
||||
|
||||
public var defaultHeight: CGFloat { return 50.0 }
|
||||
|
||||
public var bottomLine: Line.Style?
|
||||
|
||||
public var component: UIView & ComponentHeight
|
||||
|
||||
public init(bottomLine: Line.Style? = nil, component: UIView & ComponentHeight) {
|
||||
self.bottomLine = bottomLine
|
||||
self.component = component
|
||||
}
|
||||
}
|
||||
|
||||
extension Label: ComponentHeight {
|
||||
|
||||
public func estimatedHeight(for width: CGFloat) -> CGFloat? {
|
||||
let maxbounds = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)
|
||||
return self.sizeThatFits(maxbounds).height
|
||||
}
|
||||
}
|
||||
|
||||
extension Icon: ComponentHeight {
|
||||
|
||||
public func estimatedHeight(for width: CGFloat) -> CGFloat? {
|
||||
return intrinsicContentSize.height
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ import UIKit
|
||||
import VDSTokens
|
||||
|
||||
protocol TableCollectionViewLayoutDataDelegate: AnyObject {
|
||||
func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableCellModel
|
||||
func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableItemModel
|
||||
}
|
||||
|
||||
class MatrixFlowLayout : UICollectionViewLayout {
|
||||
@ -47,7 +47,7 @@ class MatrixFlowLayout : UICollectionViewLayout {
|
||||
|
||||
let selectedItem = delegate.collectionView(collectionView, dataForItemAt: indexPath)
|
||||
|
||||
let itemHeight = estimateHeightFor(item: selectedItem, with: itemWidth, padding: layoutPadding, isHeader: currentSection == 0)
|
||||
let itemHeight = estimateHeightFor(item: selectedItem, with: itemWidth)
|
||||
|
||||
let attribute = UICollectionViewLayoutAttributes(forCellWith: indexPath)
|
||||
|
||||
@ -73,12 +73,11 @@ class MatrixFlowLayout : UICollectionViewLayout {
|
||||
}
|
||||
|
||||
|
||||
private func estimateHeightFor(item: TableCellModel, with width: CGFloat, padding: Table.Padding, isHeader: Bool) -> CGFloat {
|
||||
private func estimateHeightFor(item: TableItemModel, with width: CGFloat) -> CGFloat {
|
||||
|
||||
if let model = item as? Table.TableCellLabelModel {
|
||||
return estimatedHeightForLabel(item: model, with: width, padding: padding, isHeader: isHeader)
|
||||
}
|
||||
return (item.defaultHeight + (2 * padding.verticalValue()))
|
||||
let itemWidth = width - layoutPadding.horizontalValue() - VDSLayout.space1X
|
||||
let height = item.component.estimatedHeight(for: itemWidth) ?? 0
|
||||
return height + (2 * layoutPadding.verticalValue())
|
||||
}
|
||||
|
||||
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
|
||||
@ -104,18 +103,3 @@ class MatrixFlowLayout : UICollectionViewLayout {
|
||||
return collectionView.bounds.width
|
||||
}
|
||||
}
|
||||
|
||||
extension MatrixFlowLayout {
|
||||
|
||||
private func estimatedHeightForLabel(item: Table.TableCellLabelModel, with width: CGFloat, padding: Table.Padding, isHeader: Bool) -> CGFloat {
|
||||
|
||||
let cellLabel = Label()
|
||||
cellLabel.textStyle = isHeader ? .boldTitleSmall : UIDevice.isIPad ? .bodyLarge : .bodySmall
|
||||
cellLabel.text = item.text
|
||||
|
||||
let labelWidth = width - padding.horizontalValue() - VDSLayout.space1X
|
||||
let maxbounds = CGSize(width: labelWidth, height: CGFloat.greatestFiniteMagnitude)
|
||||
let labelSize = cellLabel.sizeThatFits(maxbounds)
|
||||
return labelSize.height + (2 * padding.verticalValue())
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user