Digital ACT-191 ONEAPP-7013 story: removing width prop, and passing selectedGroupIndex through onChange

This commit is contained in:
Vasavi Kanamarlapudi 2024-07-18 12:25:04 +05:30
parent 928db0f1fc
commit 4ae07b6402
2 changed files with 20 additions and 88 deletions

View File

@ -81,31 +81,6 @@ open class Carousel: View {
/// views used to render view in the carousel slots. /// views used to render view in the carousel slots.
open var views: [UIView] = [] { didSet { setNeedsUpdate() } } open var views: [UIView] = [] { didSet { setNeedsUpdate() } }
/// If provided, width of slots will be rendered based on this value. If omitted, default widths are rendered.
open var width: Width? {
get { _width }
set {
if let newValue {
switch newValue {
case .percentage(let percentage):
if percentage >= 10 && percentage <= 100.0 {
let expectedWidth = safeAreaLayoutGuide.layoutFrame.size.width * (percentage/100)
if expectedWidth > carouselScrollbarMinWidth {
_width = newValue
}
}
case .value(let value):
if value > carouselScrollbarMinWidth {
_width = newValue
}
}
} else {
_width = nil
}
setNeedsUpdate()
}
}
/// Space between each tile. The default value will be 24px (6X) in tablet and 12px (3X) in mobile. /// Space between each tile. The default value will be 24px (6X) in tablet and 12px (3X) in mobile.
open var gutter: Gutter = UIDevice.isIPad ? .twentyFourPX : .twelvePX { didSet { setNeedsUpdate() } } open var gutter: Gutter = UIDevice.isIPad ? .twentyFourPX : .twelvePX { didSet { setNeedsUpdate() } }
@ -117,7 +92,7 @@ open class Carousel: View {
} }
} }
/// A callback when moving the carousel. Returns initial visible slide's index in the carousel. /// A callback when moving the carousel. Returns selectedGroupIndex.
open var onChange: ((Int) -> Void)? { open var onChange: ((Int) -> Void)? {
get { nil } get { nil }
set { set {
@ -150,12 +125,6 @@ open class Carousel: View {
/// 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? = nil { didSet { setNeedsUpdate() } } open var slotAlignment: CarouselSlotAlignmentModel? = nil { didSet { setNeedsUpdate() } }
/// Render item style. If provided, the slot gets the background, width, height, border-radius.
open var renderItemStyle: CarouselRenderItemStyle? = nil { didSet { setNeedsUpdate() } }
// /// Render item. It passes a data array object and expects the styled component to apply in return.
// open var renderItem: CarouselSlotItemModel? = nil { didSet { setNeedsUpdate() } }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Properties // MARK: - Private Properties
//-------------------------------------------------- //--------------------------------------------------
@ -207,15 +176,10 @@ open class Carousel: View {
$0.icon.customSize = UIDevice.isIPad ? 16 : 12 $0.icon.customSize = UIDevice.isIPad ? 16 : 12
} }
/// A publisher for when the scrubber position changes. Passes parameters (position). /// A publisher for when moving the carousel. Passes parameters selectedGroupIndex (position).
open var onChangePublisher = PassthroughSubject<Int, Never>() open var onChangePublisher = PassthroughSubject<Int, Never>()
private var onChangeCancellable: AnyCancellable? private var onChangeCancellable: AnyCancellable?
/// A publisher for when the carousel moves. Passes parameters (data).
open var onScrollPublisher = PassthroughSubject<Array<Any>, Never>()
private var onScrollCancellable: AnyCancellable?
private var _width: Width? = nil
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?
@ -225,7 +189,7 @@ open class Carousel: View {
// The scrollbar has top 5X space. So the expected top space is adjusted for tablet and mobile. // The scrollbar has top 5X space. So the expected top space is adjusted for tablet and mobile.
let scrollbarTopSpace = UIDevice.isIPad ? VDSLayout.space3X : VDSLayout.space1X let scrollbarTopSpace = UIDevice.isIPad ? VDSLayout.space3X : VDSLayout.space1X
var slotHeight = 50.0 var slotDefaultHeight = 50.0
var peekMinimum = 24.0 var peekMinimum = 24.0
var minimumSlotWidth = 0.0 var minimumSlotWidth = 0.0
var carouselScrollbarMinWidth = 96.0 var carouselScrollbarMinWidth = 96.0
@ -248,13 +212,10 @@ open class Carousel: View {
containerView containerView
.pinTop() .pinTop()
.pinBottom() .pinBottom()
.pinLeadingGreaterThanOrEqualTo() .pinLeading()
.pinTrailing() .pinTrailing()
.heightGreaterThanEqualTo(containerSize.height) .heightGreaterThanEqualTo(containerSize.height)
containerView.centerYAnchor.constraint(equalTo: centerYAnchor).activate() containerView.centerYAnchor.constraint(equalTo: centerYAnchor).activate()
containerLeadingConstraint = containerView.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 0)
containerLeadingConstraint?.activate()
// Add content stackview // Add content stackview
containerView.addSubview(contentStackView) containerView.addSubview(contentStackView)
@ -293,23 +254,6 @@ open class Carousel: View {
open override func updateView() { open override func updateView() {
super.updateView() super.updateView()
if containerView.frame.size.width > 0 {
if let width {
containerLeadingConstraint?.deactivate()
switch width {
case .value(let value):
var expectedWidth = value
let fullWidth = safeAreaLayoutGuide.layoutFrame.size.width
expectedWidth = expectedWidth > fullWidth ? fullWidth : expectedWidth
containerLeadingConstraint?.constant = safeAreaLayoutGuide.layoutFrame.size.width - expectedWidth
case .percentage(let percentage):
let expectedWidth = safeAreaLayoutGuide.layoutFrame.size.width * (percentage/100)
containerLeadingConstraint?.constant = safeAreaLayoutGuide.layoutFrame.size.width - expectedWidth
}
containerLeadingConstraint?.activate()
}
}
carouselScrollBar.numberOfSlides = views.count carouselScrollBar.numberOfSlides = views.count
carouselScrollBar.layout = layout carouselScrollBar.layout = layout
if (carouselScrollBar.position == 0 || carouselScrollBar.position > carouselScrollBar.numberOfSlides) { if (carouselScrollBar.position == 0 || carouselScrollBar.position > carouselScrollBar.numberOfSlides) {
@ -347,7 +291,6 @@ open class Carousel: View {
paginationInset = UIDevice.isIPad ? VDSLayout.space3X : VDSLayout.space2X paginationInset = UIDevice.isIPad ? VDSLayout.space3X : VDSLayout.space2X
gutter = UIDevice.isIPad ? .twentyFourPX : .twelvePX gutter = UIDevice.isIPad ? .twentyFourPX : .twelvePX
peek = .standard peek = .standard
width = nil
} }
//-------------------------------------------------- //--------------------------------------------------
@ -412,17 +355,16 @@ open class Carousel: View {
return estItemSize.height return estItemSize.height
} }
private func fetchCarouselHeight() { private func fetchCarouselHeight() -> CGFloat {
var height = slotDefaultHeight
if views.count > 0 { if views.count > 0 {
var height = slotHeight
for x in 0...views.count - 1 { for x in 0...views.count - 1 {
// Add received component let item : CarouselSlotItemModel = .init(component: views[x])
let item : CarouselSlotItemModel = .init(style: renderItemStyle, component: views[x]) let estHeight = estimateHeightFor(item: item, with: minimumSlotWidth)
slotHeight = estimateHeightFor(item: item, with: minimumSlotWidth) height = estHeight > height ? estHeight : height
height = slotHeight > height ? slotHeight : height
} }
slotHeight = height
} }
return height
} }
// Add carousel slots and load data if any // Add carousel slots and load data if any
@ -431,6 +373,7 @@ open class Carousel: View {
if containerView.frame.size.width > 0 { if containerView.frame.size.width > 0 {
containerViewHeightConstraint?.isActive = false containerViewHeightConstraint?.isActive = false
containerStackHeightConstraint?.isActive = false containerStackHeightConstraint?.isActive = false
let slotHeight = fetchCarouselHeight()
// Perform a loop to iterate each subView // Perform a loop to iterate each subView
scrollView.subviews.forEach { subView in scrollView.subviews.forEach { subView in
@ -438,8 +381,6 @@ open class Carousel: View {
subView.removeFromSuperview() subView.removeFromSuperview()
} }
fetchCarouselHeight()
// Add carousel items // Add carousel items
if views.count > 0 { if views.count > 0 {
var xPos = 0.0 var xPos = 0.0
@ -463,7 +404,7 @@ open class Carousel: View {
xPos = xPos + minimumSlotWidth + gutter.value xPos = xPos + minimumSlotWidth + gutter.value
// Add received component // Add received component
let item : CarouselSlotItemModel = .init(style: renderItemStyle, component: views[x]) let item : CarouselSlotItemModel = .init(component: views[x])
let contentViewHeight = estimateHeightFor(item: item, with: minimumSlotWidth) let contentViewHeight = estimateHeightFor(item: item, with: minimumSlotWidth)
// Add subview for content to Carousel Slot // Add subview for content to Carousel Slot
@ -479,12 +420,15 @@ open class Carousel: View {
contentView.heightAnchor.constraint(equalToConstant: contentViewHeight).activate() contentView.heightAnchor.constraint(equalToConstant: contentViewHeight).activate()
setSlotAlignment(contentView: contentView, parentView: carouselSlot) setSlotAlignment(contentView: contentView, parentView: carouselSlot)
} else { } else {
// // If no slotAlignment, should use full slot // If no slotAlignment, should use full slot
contentView.pinToSuperView() contentView.pinToSuperView()
} }
carouselSlot.backgroundColor = .clear
carouselSlot.layer.cornerRadius = 0
contentView.addSubview(component) contentView.addSubview(component)
component.pinToSuperView() component.pinToSuperView()
if var surfacedView = component as? Surfaceable { if var surfacedView = component as? Surfaceable {
contentView.surface = surface
surfacedView.surface = surface surfacedView.surface = surface
} }
} }
@ -628,9 +572,7 @@ 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(position-1)
onChangePublisher.send(selectedIndex ?? 1)
selectedGroupIndex = position
} }
} }

View File

@ -12,22 +12,12 @@ import VDSCoreTokens
/// A custom data type that holds the style and component for a slot of the 'Carousel' component. /// A custom data type that holds the style and component for a slot of the 'Carousel' component.
public struct CarouselSlotItemModel { public struct CarouselSlotItemModel {
/// Style props if provided any
public var style: CarouselRenderItemStyle?
public let defaultHeight: CGFloat = 50.0 public let defaultHeight: CGFloat = 50.0
/// Component to be show on Carousel slot /// Component to be show on Carousel slot
public var component: UIView? public var component: UIView?
public init(style: CarouselRenderItemStyle? = nil, component: UIView? = nil) { public init(component: UIView? = nil) {
self.style = style
self.component = component self.component = component
if let color = style?.backgroundColor {
self.component?.backgroundColor = .init(hexString: color)
}
if let borderRadius = style?.borderRadius {
self.component?.layer.cornerRadius = borderRadius
}
} }
} }