added new Pagination component
This commit is contained in:
parent
7496baa3df
commit
40883825b5
@ -16,6 +16,7 @@
|
||||
5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; };
|
||||
5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; };
|
||||
7115BD3C2B84C0C200E0A610 /* TileContainerChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */; };
|
||||
71B23C2D2B91FA690027F7D9 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71B23C2C2B91FA690027F7D9 /* Pagination.swift */; };
|
||||
71BFA70A2B7F70E6000DCE33 /* Dropshadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* Dropshadowable.swift */; };
|
||||
71C02B382B7BD98F00E93E66 /* NotificationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */; };
|
||||
EA0B18022A9E236900F2D0CD /* SelectorGroupBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0B18012A9E236900F2D0CD /* SelectorGroupBase.swift */; };
|
||||
@ -184,6 +185,7 @@
|
||||
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>"; };
|
||||
7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileContainerChangeLog.txt; sourceTree = "<group>"; };
|
||||
71B23C2C2B91FA690027F7D9 /* Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pagination.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>"; };
|
||||
EA0B18012A9E236900F2D0CD /* SelectorGroupBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorGroupBase.swift; sourceTree = "<group>"; };
|
||||
@ -384,6 +386,14 @@
|
||||
path = Button;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
71B23C2B2B91FA510027F7D9 /* Pagination */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
71B23C2C2B91FA690027F7D9 /* Pagination.swift */,
|
||||
);
|
||||
path = Pagination;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EA0B17FF2A9E21CA00F2D0CD /* Selector */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -487,6 +497,7 @@
|
||||
EA33619D288B1E330071C351 /* Components */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
71B23C2B2B91FA510027F7D9 /* Pagination */,
|
||||
EA4DB2FE28DCBC1900103EE3 /* Badge */,
|
||||
EAD062AE2A3B87210015965D /* BadgeIndicator */,
|
||||
EA0FC2BE2912D18200DF80B4 /* Buttons */,
|
||||
@ -1051,6 +1062,7 @@
|
||||
EA8E40932A82889500934ED3 /* TooltipDialog.swift in Sources */,
|
||||
44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */,
|
||||
EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */,
|
||||
71B23C2D2B91FA690027F7D9 /* Pagination.swift in Sources */,
|
||||
EA0D1C372A681CCE00E5C127 /* ToggleView.swift in Sources */,
|
||||
EAF7F0B9289C139800B287F5 /* ColorConfiguration.swift in Sources */,
|
||||
EA3361BD288B2C760071C351 /* TypeAlias.swift in Sources */,
|
||||
|
||||
228
VDS/Components/Pagination/Pagination.swift
Normal file
228
VDS/Components/Pagination/Pagination.swift
Normal file
@ -0,0 +1,228 @@
|
||||
//
|
||||
// Pagination.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Bandaru, Krishna Kishore on 01/03/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import VDSColorTokens
|
||||
import Combine
|
||||
|
||||
@objc(VDSPagination)
|
||||
open class Pagination: View {
|
||||
|
||||
@Published var onPreviousTapped: PassthroughSubject<Int, Never> = PassthroughSubject()
|
||||
@Published var onNextTapped: PassthroughSubject<Int, Never> = PassthroughSubject()
|
||||
@Published var onPageWillChange: PassthroughSubject<Int, Never> = PassthroughSubject()
|
||||
@Published var onPageChanged: PassthroughSubject<Int, Never> = PassthroughSubject()
|
||||
|
||||
public var total: Int = 0 {
|
||||
didSet {
|
||||
setNeedsUpdate()
|
||||
}
|
||||
}
|
||||
public var selectedPage: Int = 0 { didSet { setNeedsUpdate() } }
|
||||
private var numberOfRows: Int = 0 {
|
||||
didSet {
|
||||
collectionView.collectionViewLayout.invalidateLayout()
|
||||
setNeedsUpdate()
|
||||
}
|
||||
}
|
||||
private let pageItemCellSize: CGSize = .init(width: 20, height: 16)
|
||||
private let spacingBetweenCell: CGFloat = VDSLayout.Spacing.space1X.value
|
||||
private let buttonTintColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteWhite)
|
||||
private let buttonTextColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteWhite)
|
||||
|
||||
private lazy var collectionView: UICollectionView = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.itemSize = pageItemCellSize
|
||||
layout.scrollDirection = .horizontal
|
||||
layout.minimumInteritemSpacing = spacingBetweenCell
|
||||
layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
|
||||
layout.minimumLineSpacing = spacingBetweenCell
|
||||
layout.sectionInset = .zero
|
||||
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
||||
collectionView.isScrollEnabled = false
|
||||
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.showsHorizontalScrollIndicator = false
|
||||
collectionView.showsVerticalScrollIndicator = false
|
||||
collectionView.register(PaginationCellItem.self, forCellWithReuseIdentifier: PaginationCellItem.identifier)
|
||||
collectionView.backgroundColor = .clear
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
//TODO: Need to check with textStyle with Matt as its getter only in ButtonBase
|
||||
private lazy var previousButton: ButtonBase = {
|
||||
let previousButton: ButtonBase
|
||||
if #available(iOS 15.0, *) {
|
||||
var configuration = ButtonBase.Configuration.plain()
|
||||
configuration.imagePadding = VDSLayout.Spacing.space2X.value
|
||||
configuration.attributedTitle = AttributedString("Previous", attributes: AttributeContainer([NSAttributedString.Key.font: TextStyle.boldBodySmall.font]))
|
||||
configuration.titleAlignment = .leading
|
||||
configuration.imagePlacement = .leading
|
||||
configuration.contentInsets = .zero
|
||||
previousButton = ButtonBase(configuration: configuration)
|
||||
} else {
|
||||
previousButton = ButtonBase()
|
||||
previousButton.imageEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: VDSLayout.Spacing.space2X.value)
|
||||
previousButton.setTitle("Previous", for: .normal)
|
||||
previousButton.titleLabel?.font = TextStyle.boldBodySmall.font
|
||||
}
|
||||
previousButton.contentHorizontalAlignment = .leading
|
||||
previousButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
previousButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||
previousButton.setImage(BundleManager.shared.image(for: "pagination-arrow-left")?.withRenderingMode(.alwaysTemplate), for: .normal)
|
||||
return previousButton
|
||||
}()
|
||||
|
||||
private let nextButton: ButtonBase = {
|
||||
let nextButton: ButtonBase
|
||||
if #available(iOS 15.0, *) {
|
||||
var configuration = ButtonBase.Configuration.plain()
|
||||
configuration.imagePadding = VDSLayout.Spacing.space2X.value
|
||||
configuration.attributedTitle = AttributedString("Next", attributes: AttributeContainer([NSAttributedString.Key.font: TextStyle.boldBodySmall.font]))
|
||||
configuration.imagePlacement = .trailing
|
||||
configuration.titleAlignment = .trailing
|
||||
configuration.contentInsets = .zero
|
||||
nextButton = ButtonBase(configuration: configuration)
|
||||
} else {
|
||||
nextButton = ButtonBase()
|
||||
nextButton.imageEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: VDSLayout.Spacing.space2X.value)
|
||||
nextButton.semanticContentAttribute = .forceRightToLeft
|
||||
nextButton.titleLabel?.font = TextStyle.boldBodySmall.font
|
||||
nextButton.setTitle("Next", for: .normal)
|
||||
}
|
||||
//nextButton.textStyle = .boldBodySmall
|
||||
nextButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
nextButton.contentHorizontalAlignment = .trailing
|
||||
nextButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||
nextButton.setImage(BundleManager.shared.image(for: "pagination-arrow-right")?.withRenderingMode(.alwaysTemplate), for: .normal)
|
||||
return nextButton
|
||||
}()
|
||||
|
||||
private let containerView: View = View().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
|
||||
open override func initialSetup() {
|
||||
super.initialSetup()
|
||||
|
||||
addSubview(containerView)
|
||||
containerView.pinToSuperView()
|
||||
containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 288).activate()
|
||||
containerView.heightAnchor.constraint(equalToConstant: 44).activate()
|
||||
containerView.addSubview(previousButton)
|
||||
containerView.addSubview(collectionView)
|
||||
containerView.addSubview(nextButton)
|
||||
|
||||
previousButton
|
||||
.pinTop()
|
||||
.pinBottom()
|
||||
.pinLeading()
|
||||
previousButton.trailingAnchor.constraint(greaterThanOrEqualTo: collectionView.leadingAnchor).activate()
|
||||
collectionView.heightAnchor.constraint(equalToConstant: VDSLayout.Spacing.space4X.value).activate()
|
||||
collectionView.centerYAnchor.constraint(equalTo: centerYAnchor).activate()
|
||||
collectionView.centerXAnchor.constraint(equalTo: centerXAnchor).activate()
|
||||
collectionView.trailingAnchor.constraint(greaterThanOrEqualTo: nextButton.leadingAnchor).activate()
|
||||
collectionView.widthAnchor.constraint(equalToConstant: 92).activate()
|
||||
nextButton
|
||||
.pinTop()
|
||||
.pinBottom()
|
||||
.pinTrailing()
|
||||
nextButton.onClick = onbuttonTapped
|
||||
previousButton.onClick = onbuttonTapped
|
||||
previousButton.isHidden = true
|
||||
}
|
||||
|
||||
open override func updateView() {
|
||||
super.updateView()
|
||||
|
||||
previousButton.tintColor = buttonTintColorConfiguration.getColor(surface)
|
||||
nextButton.tintColor = buttonTintColorConfiguration.getColor(surface)
|
||||
previousButton.setTitleColor(buttonTextColorConfiguration.getColor(surface), for: .normal)
|
||||
nextButton.setTitleColor(buttonTextColorConfiguration.getColor(surface), for: .normal)
|
||||
collectionView.reloadData()
|
||||
}
|
||||
|
||||
private func onbuttonTapped(_ sender: UIButton) {
|
||||
let isNextAction = sender == nextButton
|
||||
if isNextAction {
|
||||
selectedPage += 1
|
||||
} else {
|
||||
selectedPage -= 1
|
||||
}
|
||||
updateSelection()
|
||||
}
|
||||
|
||||
private func updateSelection() {
|
||||
collectionView.scrollToItem(at: IndexPath(row: max(selectedPage-1, 0), section: 0), at: .left, animated: false)
|
||||
previousButton.isHidden = selectedPage == 0
|
||||
nextButton.isHidden = selectedPage == total - 1
|
||||
}
|
||||
}
|
||||
|
||||
extension Pagination: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
|
||||
|
||||
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { total }
|
||||
|
||||
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PaginationCellItem.identifier, for: indexPath) as? PaginationCellItem else { return UICollectionViewCell() }
|
||||
cell.update(selectedPage, currentIndex: indexPath.row, surface: surface)
|
||||
return cell
|
||||
}
|
||||
|
||||
public func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool {
|
||||
onPageWillChange.send(selectedPage)
|
||||
return true
|
||||
}
|
||||
|
||||
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
selectedPage = indexPath.row
|
||||
updateSelection()
|
||||
onPageChanged.send(indexPath.row)
|
||||
}
|
||||
}
|
||||
|
||||
internal final class PaginationCellItem: UICollectionViewCell {
|
||||
|
||||
static let identifier: String = String(describing: PaginationCellItem.self)
|
||||
private let textColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark)
|
||||
|
||||
private var indexLabel: Label = Label().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.textAlignment = .center
|
||||
$0.numberOfLines = 1
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
setUp()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
setUp()
|
||||
}
|
||||
|
||||
private func setUp() {
|
||||
let containerView = View()
|
||||
containerView.translatesAutoresizingMaskIntoConstraints = false
|
||||
containerView.addSubview(indexLabel)
|
||||
contentView.addSubview(containerView)
|
||||
containerView.pinToSuperView()
|
||||
indexLabel.pinToSuperView()
|
||||
indexLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: VDSLayout.Spacing.space5X.value).activate()
|
||||
contentView.backgroundColor = .clear
|
||||
containerView.backgroundColor = .clear
|
||||
indexLabel.backgroundColor = .clear
|
||||
}
|
||||
|
||||
internal func update(_ selectedIndex: Int, currentIndex: Int, surface: Surface) {
|
||||
indexLabel.textStyle = selectedIndex == currentIndex ? .boldBodySmall : .bodySmall
|
||||
indexLabel.text = "\(currentIndex)"
|
||||
indexLabel.textColor = textColorConfiguration.getColor(surface)
|
||||
}
|
||||
}
|
||||
12
VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/Contents.json
vendored
Normal file
12
VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "pagination-arrow-left.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_36674_119239)">
|
||||
<path d="M11.0098 6.50388H2.67786L6.63428 10.4248L5.93018 11.1357L0.750489 6.002L5.92725 0.870117L6.63135 1.58012L2.67371 5.50388H11.0098L11.0098 6.50388Z" fill="black"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_36674_119239">
|
||||
<rect width="12" height="12" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 426 B |
12
VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/Contents.json
vendored
Normal file
12
VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "pagination-arrow-right.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
<svg width="11" height="12" viewBox="0 0 11 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.2596 6.00176L5.07986 11.1355L4.37576 10.4246L8.33256 6.50419H0.000762939V5.50419H8.33776L4.37918 1.57987L5.08328 0.869873L10.2596 6.00176Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 271 B |
Loading…
Reference in New Issue
Block a user