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.
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.
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)? {
get { nil }
set {
@ -150,12 +125,6 @@ open class Carousel: View {
/// If provided, will set the alignment for slot content when the slots has different heights.
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
//--------------------------------------------------
@ -207,15 +176,10 @@ open class Carousel: View {
$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>()
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 containerViewHeightConstraint: 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.
let scrollbarTopSpace = UIDevice.isIPad ? VDSLayout.space3X : VDSLayout.space1X
var slotHeight = 50.0
var slotDefaultHeight = 50.0
var peekMinimum = 24.0
var minimumSlotWidth = 0.0
var carouselScrollbarMinWidth = 96.0
@ -248,13 +212,10 @@ open class Carousel: View {
containerView
.pinTop()
.pinBottom()
.pinLeadingGreaterThanOrEqualTo()
.pinLeading()
.pinTrailing()
.heightGreaterThanEqualTo(containerSize.height)
containerView.centerYAnchor.constraint(equalTo: centerYAnchor).activate()
containerLeadingConstraint = containerView.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 0)
containerLeadingConstraint?.activate()
// Add content stackview
containerView.addSubview(contentStackView)
@ -293,23 +254,6 @@ open class Carousel: View {
open override func 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.layout = layout
if (carouselScrollBar.position == 0 || carouselScrollBar.position > carouselScrollBar.numberOfSlides) {
@ -347,7 +291,6 @@ open class Carousel: View {
paginationInset = UIDevice.isIPad ? VDSLayout.space3X : VDSLayout.space2X
gutter = UIDevice.isIPad ? .twentyFourPX : .twelvePX
peek = .standard
width = nil
}
//--------------------------------------------------
@ -412,17 +355,16 @@ open class Carousel: View {
return estItemSize.height
}
private func fetchCarouselHeight() {
private func fetchCarouselHeight() -> CGFloat {
var height = slotDefaultHeight
if views.count > 0 {
var height = slotHeight
for x in 0...views.count - 1 {
// Add received component
let item : CarouselSlotItemModel = .init(style: renderItemStyle, component: views[x])
slotHeight = estimateHeightFor(item: item, with: minimumSlotWidth)
height = slotHeight > height ? slotHeight : height
let item : CarouselSlotItemModel = .init(component: views[x])
let estHeight = estimateHeightFor(item: item, with: minimumSlotWidth)
height = estHeight > height ? estHeight : height
}
slotHeight = height
}
return height
}
// Add carousel slots and load data if any
@ -431,14 +373,13 @@ open class Carousel: View {
if containerView.frame.size.width > 0 {
containerViewHeightConstraint?.isActive = false
containerStackHeightConstraint?.isActive = false
let slotHeight = fetchCarouselHeight()
// Perform a loop to iterate each subView
scrollView.subviews.forEach { subView in
// Removing subView from its parent view
subView.removeFromSuperview()
}
fetchCarouselHeight()
// Add carousel items
if views.count > 0 {
@ -452,7 +393,7 @@ open class Carousel: View {
}
scrollView.addSubview(carouselSlot)
scrollView.delegate = self
carouselSlot
.pinTop()
.pinBottom()
@ -463,7 +404,7 @@ open class Carousel: View {
xPos = xPos + minimumSlotWidth + gutter.value
// 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)
// Add subview for content to Carousel Slot
@ -471,7 +412,7 @@ open class Carousel: View {
$0.clipsToBounds = true
}
carouselSlot.addSubview(contentView)
if let component = item.component {
if slotAlignment != nil {
// If slotAlignment exist, should use expected height
@ -479,12 +420,15 @@ open class Carousel: View {
contentView.heightAnchor.constraint(equalToConstant: contentViewHeight).activate()
setSlotAlignment(contentView: contentView, parentView: carouselSlot)
} else {
// // If no slotAlignment, should use full slot
// If no slotAlignment, should use full slot
contentView.pinToSuperView()
}
carouselSlot.backgroundColor = .clear
carouselSlot.layer.cornerRadius = 0
contentView.addSubview(component)
component.pinToSuperView()
if var surfacedView = component as? Surfaceable {
contentView.surface = surface
surfacedView.surface = surface
}
}
@ -628,9 +572,7 @@ open class Carousel: View {
let yPos = scrollView.contentOffset.y
scrollView.setContentOffset(CGPoint(x: xPos, y: yPos), animated: true)
showPaginationControls()
selectedIndex = ((position-1) * layout.value) + 1
onChangePublisher.send(selectedIndex ?? 1)
selectedGroupIndex = position
onChangePublisher.send(position-1)
}
}

View File

@ -11,23 +11,13 @@ 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?
public let defaultHeight: CGFloat = 50.0
/// Component to be show on Carousel slot
public var component: UIView?
public init(style: CarouselRenderItemStyle? = nil, component: UIView? = nil) {
self.style = style
public init(component: UIView? = nil) {
self.component = component
if let color = style?.backgroundColor {
self.component?.backgroundColor = .init(hexString: color)
}
if let borderRadius = style?.borderRadius {
self.component?.layer.cornerRadius = borderRadius
}
}
}