Digital ACT-191 ONEAPP-7013 story: slot alignment and rendering data

This commit is contained in:
Vasavi Kanamarlapudi 2024-07-04 20:24:33 +05:30
parent 8619c64109
commit 77288e4c54
5 changed files with 212 additions and 33 deletions

View File

@ -7,6 +7,8 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
18013CED2C355BF900907F18 /* CarouselSlotItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18013CEC2C355BF900907F18 /* CarouselSlotItemModel.swift */; };
18013CEF2C355C5200907F18 /* CarouselRenderItemStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18013CEE2C355C5200907F18 /* CarouselRenderItemStyle.swift */; };
1808BEBC2BA41C3200129230 /* CarouselScrollbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1808BEBB2BA41C3200129230 /* CarouselScrollbar.swift */; }; 1808BEBC2BA41C3200129230 /* CarouselScrollbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1808BEBB2BA41C3200129230 /* CarouselScrollbar.swift */; };
1832AC572BA0791D008AE476 /* BreadcrumbCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */; }; 1832AC572BA0791D008AE476 /* BreadcrumbCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */; };
1842B1DF2BECE28B0021AFCA /* CalendarDateViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1842B1DE2BECE28B0021AFCA /* CalendarDateViewCell.swift */; }; 1842B1DF2BECE28B0021AFCA /* CalendarDateViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1842B1DE2BECE28B0021AFCA /* CalendarDateViewCell.swift */; };
@ -19,11 +21,9 @@
18A65A022B96E848006602CC /* Breadcrumbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A012B96E848006602CC /* Breadcrumbs.swift */; }; 18A65A022B96E848006602CC /* Breadcrumbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A012B96E848006602CC /* Breadcrumbs.swift */; };
18A65A042B96F050006602CC /* BreadcrumbItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A032B96F050006602CC /* BreadcrumbItem.swift */; }; 18A65A042B96F050006602CC /* BreadcrumbItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A032B96F050006602CC /* BreadcrumbItem.swift */; };
18AE87502C06FDA60075F181 /* Carousel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18AE874F2C06FDA60075F181 /* Carousel.swift */; }; 18AE87502C06FDA60075F181 /* Carousel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18AE874F2C06FDA60075F181 /* Carousel.swift */; };
18AE87542C06FE610075F181 /* CarouselChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18AE87532C06FE610075F181 /* CarouselChangeLog.txt */; };
18B42AC62C09D197008D6262 /* CarouselSlotAlignmentModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B42AC52C09D197008D6262 /* CarouselSlotAlignmentModel.swift */; }; 18B42AC62C09D197008D6262 /* CarouselSlotAlignmentModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B42AC52C09D197008D6262 /* CarouselSlotAlignmentModel.swift */; };
18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */; }; 18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */; };
18B9763F2C11BA4A009271DF /* CarouselPaginationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B9763E2C11BA4A009271DF /* CarouselPaginationModel.swift */; }; 18B9763F2C11BA4A009271DF /* CarouselPaginationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B9763E2C11BA4A009271DF /* CarouselPaginationModel.swift */; };
18BDEE822B75316E00452358 /* ButtonIconChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */; };
18FEA1AD2BDD137500A56439 /* CalendarIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */; }; 18FEA1AD2BDD137500A56439 /* CalendarIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */; };
18FEA1B52BE0E63600A56439 /* Date+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B42BE0E63600A56439 /* Date+Extension.swift */; }; 18FEA1B52BE0E63600A56439 /* Date+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B42BE0E63600A56439 /* Date+Extension.swift */; };
445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; };
@ -209,6 +209,8 @@
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
18013CEC2C355BF900907F18 /* CarouselSlotItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselSlotItemModel.swift; sourceTree = "<group>"; };
18013CEE2C355C5200907F18 /* CarouselRenderItemStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselRenderItemStyle.swift; sourceTree = "<group>"; };
1808BEBB2BA41C3200129230 /* CarouselScrollbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselScrollbar.swift; sourceTree = "<group>"; }; 1808BEBB2BA41C3200129230 /* CarouselScrollbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselScrollbar.swift; sourceTree = "<group>"; };
1808BEBF2BA456B700129230 /* CarouselScrollbarChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CarouselScrollbarChangeLog.txt; sourceTree = "<group>"; }; 1808BEBF2BA456B700129230 /* CarouselScrollbarChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CarouselScrollbarChangeLog.txt; sourceTree = "<group>"; };
1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbCellItem.swift; sourceTree = "<group>"; }; 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbCellItem.swift; sourceTree = "<group>"; };
@ -502,6 +504,8 @@
18AE874F2C06FDA60075F181 /* Carousel.swift */, 18AE874F2C06FDA60075F181 /* Carousel.swift */,
18B9763E2C11BA4A009271DF /* CarouselPaginationModel.swift */, 18B9763E2C11BA4A009271DF /* CarouselPaginationModel.swift */,
18B42AC52C09D197008D6262 /* CarouselSlotAlignmentModel.swift */, 18B42AC52C09D197008D6262 /* CarouselSlotAlignmentModel.swift */,
18013CEC2C355BF900907F18 /* CarouselSlotItemModel.swift */,
18013CEE2C355C5200907F18 /* CarouselRenderItemStyle.swift */,
18AE87532C06FE610075F181 /* CarouselChangeLog.txt */, 18AE87532C06FE610075F181 /* CarouselChangeLog.txt */,
); );
path = Carousel; path = Carousel;
@ -1363,6 +1367,7 @@
EAC71A1D2A2E155A00E47A9F /* Checkbox.swift in Sources */, EAC71A1D2A2E155A00E47A9F /* Checkbox.swift in Sources */,
EAF7F0AB289B13FD00B287F5 /* TextStyleLabelAttribute.swift in Sources */, EAF7F0AB289B13FD00B287F5 /* TextStyleLabelAttribute.swift in Sources */,
18AE87502C06FDA60075F181 /* Carousel.swift in Sources */, 18AE87502C06FDA60075F181 /* Carousel.swift in Sources */,
18013CEF2C355C5200907F18 /* CarouselRenderItemStyle.swift in Sources */,
EAB1D29C28A5618900DAE764 /* RadioButtonGroup.swift in Sources */, EAB1D29C28A5618900DAE764 /* RadioButtonGroup.swift in Sources */,
EA81410B2A0E8E3C004F60D2 /* ButtonIcon.swift in Sources */, EA81410B2A0E8E3C004F60D2 /* ButtonIcon.swift in Sources */,
EA985BE629688F6A00F2FF2E /* TileletBadgeModel.swift in Sources */, EA985BE629688F6A00F2FF2E /* TileletBadgeModel.swift in Sources */,
@ -1405,6 +1410,7 @@
EA596ABF2A16B4F500300C4B /* Tabs.swift in Sources */, EA596ABF2A16B4F500300C4B /* Tabs.swift in Sources */,
EAD062A72A3B67770015965D /* UIView+CALayer.swift in Sources */, EAD062A72A3B67770015965D /* UIView+CALayer.swift in Sources */,
EAD068942A560C13002E3A2D /* LoaderLaunchable.swift in Sources */, EAD068942A560C13002E3A2D /* LoaderLaunchable.swift in Sources */,
18013CED2C355BF900907F18 /* CarouselSlotItemModel.swift in Sources */,
18FEA1AD2BDD137500A56439 /* CalendarIndicatorModel.swift in Sources */, 18FEA1AD2BDD137500A56439 /* CalendarIndicatorModel.swift in Sources */,
EA985BEC2968A91200F2FF2E /* TitleLockupTitleModel.swift in Sources */, EA985BEC2968A91200F2FF2E /* TitleLockupTitleModel.swift in Sources */,
5FC35BE328D51405004EBEAC /* Button.swift in Sources */, 5FC35BE328D51405004EBEAC /* Button.swift in Sources */,

View File

@ -33,21 +33,6 @@ open class Carousel: View {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Enums // MARK: - Enums
//-------------------------------------------------- //--------------------------------------------------
/// Space between each tile. The default value will be 24px (6X) in tablet and 12px (3X) in mobile.
public enum Gutter: String, CaseIterable {
case twelvePX = "12px"
case twentyFourPX = "24px"
var value: CGFloat {
switch self {
case .twelvePX:
VDSLayout.space3X
case .twentyFourPX:
VDSLayout.space6X
}
}
}
/// Enum used to describe the pagination display for this component. /// Enum used to describe the pagination display for this component.
public enum PaginationDisplay: String, CaseIterable { public enum PaginationDisplay: String, CaseIterable {
case persistent, none case persistent, none
@ -75,6 +60,21 @@ open class Carousel: View {
case value(CGFloat) case value(CGFloat)
} }
/// Space between each tile. The default value will be 24px (6X) in tablet and 12px (3X) in mobile.
public enum Gutter: String, CaseIterable {
case twelvePX = "12px"
case twentyFourPX = "24px"
var value: CGFloat {
switch self {
case .twelvePX:
VDSLayout.space3X
case .twentyFourPX:
VDSLayout.space6X
}
}
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Public Properties // MARK: - Public Properties
//-------------------------------------------------- //--------------------------------------------------
@ -123,11 +123,12 @@ open class Carousel: View {
get { return _layout } get { return _layout }
set { set {
_layout = newValue _layout = newValue
carouselScrollBar.position = 0
setNeedsUpdate() setNeedsUpdate()
} }
} }
/// A callback when moving the carousel. Returns event object and selectedGroupIndex. /// A callback when moving the carousel. Returns initial visible slide's index in the carousel.
open var onChange: ((Int) -> Void)? { open var onChange: ((Int) -> Void)? {
get { nil } get { nil }
set { set {
@ -182,7 +183,42 @@ open class Carousel: View {
open var selectedIndex: Int? { didSet { setNeedsUpdate() } } open var selectedIndex: Int? { didSet { setNeedsUpdate() } }
/// If provided, will set the alignment for slot content when the slots has different heights. /// If provided, will set the alignment for slot content when the slots has different heights.
open var slotAlignment: [CarouselSlotAlignmentModel] = [] { didSet { setNeedsUpdate() } } open var slotAlignment: CarouselSlotAlignmentModel? {
get { return _slotAlignment }
set {
if let newValue {
_slotAlignment = newValue
} else {
_slotAlignment = nil
}
setNeedsUpdate()
}
}
/// Render item style. If provided, the slot gets the background, width, height, border-radius.
open var renderItemStyle: CarouselRenderItemStyle? {
get { return _renderItemStyle }
set {
if let newValue {
_renderItemStyle = newValue
} else {
_renderItemStyle = nil
}
setNeedsUpdate()
}
}
/// Render item. It passes a data array object and expects the styled component to apply in return.
open var renderItem: CarouselSlotItemModel? {
get { _renderItem }
set {
if let newValue {
_renderItem = newValue
} else {
_renderItem = nil
}
}
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Properties // MARK: - Private Properties
@ -250,9 +286,12 @@ open class Carousel: View {
internal var _gutter: Gutter = UIDevice.isIPad ? .twentyFourPX : .twelvePX internal var _gutter: Gutter = UIDevice.isIPad ? .twentyFourPX : .twelvePX
internal var _peek: Peek = .standard internal var _peek: Peek = .standard
internal var _numberOfSlides: Int = 1 internal var _numberOfSlides: Int = 1
internal var _slotAlignment: CarouselSlotAlignmentModel? = nil
internal var _renderItemStyle: CarouselRenderItemStyle? = nil
internal var _renderItem: CarouselSlotItemModel? = nil
private var _width: Width? = nil private var _width: Width? = nil
private var selectedGroupIndex: Int? { didSet { setNeedsUpdate() } } private var selectedGroupIndex: Int? = nil
private var containerStackHeightConstraint: NSLayoutConstraint? private var containerStackHeightConstraint: NSLayoutConstraint?
private var containerViewHeightConstraint: NSLayoutConstraint? private var containerViewHeightConstraint: NSLayoutConstraint?
private var prevButtonLeadingConstraint: NSLayoutConstraint? private var prevButtonLeadingConstraint: NSLayoutConstraint?
@ -323,6 +362,7 @@ open class Carousel: View {
.heightGreaterThanEqualTo(containerSize.height) .heightGreaterThanEqualTo(containerSize.height)
addlisteners() addlisteners()
updatePaginationInset()
} }
/// Used to make changes to the View based off a change events or from local properties. /// Used to make changes to the View based off a change events or from local properties.
@ -348,7 +388,9 @@ open class Carousel: View {
carouselScrollBar.numberOfSlides = data.count carouselScrollBar.numberOfSlides = data.count
carouselScrollBar.layout = _layout carouselScrollBar.layout = _layout
carouselScrollBar.position = (carouselScrollBar.position == 0 || carouselScrollBar.position > carouselScrollBar.numberOfSlides) ? 1 : carouselScrollBar.position if (carouselScrollBar.position == 0 || carouselScrollBar.position > carouselScrollBar.numberOfSlides) {
carouselScrollBar.position = 1
}
carouselScrollBar.isHidden = (totalPositions() <= 1) ? true : false carouselScrollBar.isHidden = (totalPositions() <= 1) ? true : false
// Mobile/Tablet layouts without peek - must show pagination controls. // Mobile/Tablet layouts without peek - must show pagination controls.
@ -392,31 +434,32 @@ open class Carousel: View {
nextButton.onClick = { _ in self.nextButtonClick() } nextButton.onClick = { _ in self.nextButtonClick() }
previousButton.onClick = { _ in self.previousButtonClick() } previousButton.onClick = { _ in self.previousButtonClick() }
/// Will be called when the thumb move forward. /// Will be called when the scrollbar thumb move forward.
carouselScrollBar.onMoveForward = { [weak self] scrubberId in carouselScrollBar.onMoveForward = { [weak self] scrubberId in
guard let self else { return } guard let self else { return }
updateScrollPosition(position: scrubberId, callbackText:"onMoveForward") updateScrollPosition(position: scrubberId, callbackText:"onMoveForward")
} }
/// Will be called when the thumb move backward. /// Will be called when the scrollbar thumb move backward.
carouselScrollBar.onMoveBackward = { [weak self] scrubberId in carouselScrollBar.onMoveBackward = { [weak self] scrubberId in
guard let self else { return } guard let self else { return }
updateScrollPosition(position: scrubberId, callbackText:"onMoveBackward") updateScrollPosition(position: scrubberId, callbackText:"onMoveBackward")
} }
/// Will be called when the thumb touch start. /// Will be called when the scrollbar thumb touch start.
carouselScrollBar.onThumbTouchStart = { [weak self] scrubberId in carouselScrollBar.onThumbTouchStart = { [weak self] scrubberId in
guard let self else { return } guard let self else { return }
updateScrollPosition(position: scrubberId, callbackText:"onThumbTouchStart") updateScrollPosition(position: scrubberId, callbackText:"onThumbTouchStart")
} }
/// Will be called when the thumb touch end. /// Will be called when the scrollbar thumb touch end.
carouselScrollBar.onThumbTouchEnd = { [weak self] scrubberId in carouselScrollBar.onThumbTouchEnd = { [weak self] scrubberId in
guard let self else { return } guard let self else { return }
updateScrollPosition(position: scrubberId, callbackText:"onThumbTouchEnd") updateScrollPosition(position: scrubberId, callbackText:"onThumbTouchEnd")
} }
} }
// Update pagination buttons with selected surface, kind, floating values
private func updatePaginationControls() { private func updatePaginationControls() {
containerView.surface = surface containerView.surface = surface
showPaginationControls() showPaginationControls()
@ -428,6 +471,7 @@ open class Carousel: View {
nextButton.surface = surface nextButton.surface = surface
} }
// Show/Hide pagination buttons of Carousel based on First or Middle or Last
private func showPaginationControls() { private func showPaginationControls() {
if carouselScrollBar.numberOfSlides == _layout.value { if carouselScrollBar.numberOfSlides == _layout.value {
previousButton.isHidden = true previousButton.isHidden = true
@ -438,6 +482,7 @@ open class Carousel: View {
} }
} }
// Add carousel slots and load data if any
private func addCarouselSlots() { private func addCarouselSlots() {
getSlotWidth() getSlotWidth()
if containerView.frame.size.width > 0 { if containerView.frame.size.width > 0 {
@ -454,6 +499,8 @@ open class Carousel: View {
if data.count > 0 { if data.count > 0 {
var xPos = 0.0 var xPos = 0.0
for x in 0...data.count - 1 { for x in 0...data.count - 1 {
// Add Carousel Slot
let carouselSlot = View().with { let carouselSlot = View().with {
$0.clipsToBounds = true $0.clipsToBounds = true
$0.backgroundColor = UIColor(red: CGFloat(216) / 255.0, green: CGFloat(218) / 255.0, blue: CGFloat(218) / 255.0, alpha: 1) $0.backgroundColor = UIColor(red: CGFloat(216) / 255.0, green: CGFloat(218) / 255.0, blue: CGFloat(218) / 255.0, alpha: 1)
@ -470,6 +517,29 @@ open class Carousel: View {
.height(slotHeight) .height(slotHeight)
carouselSlot.layer.cornerRadius = 12.0 carouselSlot.layer.cornerRadius = 12.0
xPos = xPos + minimumSlotWidth + gutter.value xPos = xPos + minimumSlotWidth + gutter.value
// Add subview for content to Carousel Slot
let contentView = View().with {
$0.clipsToBounds = true
$0.backgroundColor = UIColor(red: CGFloat(216) / 255.0, green: CGFloat(218) / 255.0, blue: CGFloat(218) / 255.0, alpha: 1)
}
carouselSlot.addSubview(contentView)
// Add received component
let item : CarouselSlotItemModel = .init(style: renderItemStyle, component: data[x] as? UIView)
if let component = item.component {
if slotAlignment != nil {
setSlotAlignment(contentView: contentView, parentView: carouselSlot)
} else {
contentView.pinToSuperView()
}
contentView.addSubview(component)
component.pinToSuperView()
contentView.layer.cornerRadius = component.layer.cornerRadius
if var surfacedView = component as? Surfaceable {
surfacedView.surface = surface
}
}
} }
scrollView.contentSize = CGSize(width: xPos - gutter.value, height: slotHeight) scrollView.contentSize = CGSize(width: xPos - gutter.value, height: slotHeight)
} }
@ -487,6 +557,37 @@ open class Carousel: View {
} }
} }
// Set slot alignment if provided. Used only when slot content have different heights or widths.
private func setSlotAlignment(contentView: View, parentView: View) {
parentView.backgroundColor = .clear
switch slotAlignment?.vertical {
case .top:
contentView.topAnchor.constraint(equalTo: parentView.topAnchor).activate()
break
case .middle:
contentView.centerYAnchor.constraint(equalTo: parentView.centerYAnchor).activate()
break
case .bottom:
contentView.bottomAnchor.constraint(equalTo: parentView.bottomAnchor).activate()
break
default: break
}
switch slotAlignment?.horizontal {
case .left:
contentView.leadingAnchor.constraint(equalTo: parentView.leadingAnchor).activate()
break
case .center:
contentView.centerXAnchor.constraint(equalTo: parentView.centerXAnchor).activate()
break
case .right:
parentView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).activate()
break
default: break
}
}
// Get the slot width relative to the peak
private func getSlotWidth() { private func getSlotWidth() {
let actualWidth = containerView.frame.size.width let actualWidth = containerView.frame.size.width
let isScrollbarSuppressed = data.count > 0 && layout.value == data.count let isScrollbarSuppressed = data.count > 0 && layout.value == data.count
@ -505,7 +606,7 @@ open class Carousel: View {
case .minimum: case .minimum:
// Peek Mimumum Width: 24px from edge of container (at the default view of the carousel with one peek visible) // Peek Mimumum Width: 24px from edge of container (at the default view of the carousel with one peek visible)
// Minimum (Mobile only) Supported only on Mobile viewports. If a user passes Minimum for tablet carousel, the peek reverts to Standard. // Minimum (Mobile only) Supported only on Mobile viewports. If a user passes Minimum for tablet carousel, the peek reverts to Standard.
minimumSlotWidth = isPeekMinimumOnTablet ? minimumSlotWidth : minimumSlotWidth - peekMinimum minimumSlotWidth = isPeekMinimumOnTablet ? minimumSlotWidth : minimumSlotWidth - peekMinimum - gutter.value
case .none: case .none:
break break
} }
@ -525,6 +626,7 @@ open class Carousel: View {
updateScrollPosition(position: carouselScrollBar.position, callbackText:"pageControlClicks") updateScrollPosition(position: carouselScrollBar.position, callbackText:"pageControlClicks")
} }
// The size of slot depends on the selected aspect ratio
private func ratioSize(for width: CGFloat) -> CGSize { private func ratioSize(for width: CGFloat) -> CGSize {
var height: CGFloat = width var height: CGFloat = width
@ -575,6 +677,7 @@ open class Carousel: View {
updateScrollPosition(position: contentPos, callbackText: "ScrollViewMoved") updateScrollPosition(position: contentPos, callbackText: "ScrollViewMoved")
} }
// Update scrollview offset relative to scrollbar thumb position
private func updateScrollPosition(position: Int, callbackText: String) { private func updateScrollPosition(position: Int, callbackText: String) {
if carouselScrollBar.numberOfSlides > 0 { if carouselScrollBar.numberOfSlides > 0 {
let scrollContentSizeWidth = scrollView.contentSize.width let scrollContentSizeWidth = scrollView.contentSize.width
@ -598,7 +701,7 @@ open class Carousel: View {
xPos = xPosition - gutter.value - (minimumSlotWidth/4)/2 xPos = xPosition - gutter.value - (minimumSlotWidth/4)/2
} }
case .minimum: case .minimum:
xPos = isPeekMinimumOnTablet ? xPosition : xPosition - peekMinimum/2 xPos = isPeekMinimumOnTablet ? xPosition : xPosition - peekMinimum
case .none: case .none:
xPos = xPosition xPos = xPosition
} }
@ -608,9 +711,13 @@ open class Carousel: View {
let yPos = scrollView.contentOffset.y let yPos = scrollView.contentOffset.y
scrollView.setContentOffset(CGPoint(x: xPos, y: yPos), animated: true) scrollView.setContentOffset(CGPoint(x: xPos, y: yPos), animated: true)
showPaginationControls() showPaginationControls()
selectedIndex = ((position-1) * layout.value) + 1
onChangePublisher.send(selectedIndex ?? 1)
selectedGroupIndex = position
} }
} }
// Get the overall positions of the carousel scrollbar relative to the slides and selected layout
private func totalPositions() -> Int { private func totalPositions() -> Int {
return Int (ceil (Double(carouselScrollBar.numberOfSlides) / Double(_layout.value))) return Int (ceil (Double(carouselScrollBar.numberOfSlides) / Double(_layout.value)))
} }

View File

@ -0,0 +1,33 @@
//
// CarouselRenderItemStyle.swift
// VDS
//
// Created by Kanamarlapudi, Vasavi on 30/06/24.
//
import Foundation
import UIKit
import VDSCoreTokens
/// A custom data type that holds the style props if provided any.
public struct CarouselRenderItemStyle {
/// BackgroundColor for slot
public let backgroundColor: String?
/// Height for slot
public var height: CGFloat?
/// BorderRadius for slot
public var borderRadius: CGFloat?
/// Width for slot
public var width: CGFloat?
public init(backgroundColor: String?, height: CGFloat?, width: CGFloat?, borderRadius: CGFloat?) {
self.backgroundColor = backgroundColor
self.height = height
self.borderRadius = borderRadius ?? 12.0
self.width = width
}
}

View File

@ -7,17 +7,19 @@
import Foundation import Foundation
/// Custom data type for slotAlignment prop for 'Carousel' component. /// Custom data type for the SlotAlignment prop for the 'carousel' component.
extension Carousel { extension Carousel {
/// Used only when slot content have different heights or widths.
public struct CarouselSlotAlignmentModel { public struct CarouselSlotAlignmentModel {
/// Text that shown to an indicator for legend /// Used for vertical alignment of slot alignment.
public var vertical: String public var vertical: Carousel.Vertical
/// Date to an indicator /// Used for horizontal alignment of slot alignment.
public var horizontal: String public var horizontal: Carousel.Horizontal
public init(vertical: String, horizontal: String) { public init(vertical: Carousel.Vertical, horizontal: Carousel.Horizontal) {
self.vertical = vertical self.vertical = vertical
self.horizontal = horizontal self.horizontal = horizontal
} }

View File

@ -0,0 +1,31 @@
//
// CarouselSlotItemModel.swift
// VDS
//
// Created by Kanamarlapudi, Vasavi on 30/06/24.
//
import Foundation
import UIKit
import VDSCoreTokens
/// A custom data type that holds the style and component for a slot of the 'Carousel' component.
public struct CarouselSlotItemModel {
/// Style props if provided any
public var style: CarouselRenderItemStyle?
/// Component to be show on Carousel slot
public var component: UIView?
public init(style: CarouselRenderItemStyle? = nil, component: UIView? = nil) {
self.style = style
self.component = component
if let color = style?.backgroundColor {
self.component?.backgroundColor = .init(hexString: color)
}
if let borderRadius = style?.borderRadius {
self.component?.layer.cornerRadius = borderRadius
}
}
}