diff --git a/VDS/Components/Carousel/Carousel.swift b/VDS/Components/Carousel/Carousel.swift index 90b35588..5595ef68 100644 --- a/VDS/Components/Carousel/Carousel.swift +++ b/VDS/Components/Carousel/Carousel.swift @@ -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() private var onChangeCancellable: AnyCancellable? - /// A publisher for when the carousel moves. Passes parameters (data). - open var onScrollPublisher = PassthroughSubject, 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) } } diff --git a/VDS/Components/Carousel/CarouselSlotItemModel.swift b/VDS/Components/Carousel/CarouselSlotItemModel.swift index a52192c4..3cb7240a 100644 --- a/VDS/Components/Carousel/CarouselSlotItemModel.swift +++ b/VDS/Components/Carousel/CarouselSlotItemModel.swift @@ -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 - } } }