Digital ACT-191 ONEAPP-7013 story: Fixed Constraints issue and refactored Code

This commit is contained in:
vasavk 2024-06-14 13:17:29 +05:30
parent de8a2ebdee
commit a829df86e5

View File

@ -33,25 +33,11 @@ open class Carousel: View {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Enums // MARK: - Enums
//-------------------------------------------------- //--------------------------------------------------
/// Enum used to describe the aspect ratios used for this component.
public enum AspectRatio: String, CaseIterable {
case ratio1x1 = "1:1"
case ratio3x4 = "3:4"
case ratio4x3 = "4:3"
case ratio2x3 = "2:3"
case ratio3x2 = "3:2"
case ratio9x16 = "9:16"
case ratio16x9 = "16:9"
case ratio1x2 = "1:2"
case ratio2x1 = "2:1"
case none
}
/// 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.
public enum Gutter: String, CaseIterable { public enum Gutter: String, CaseIterable {
case twelvePX = "12px" case twelvePX = "12px"
case twentyFourPX = "24px" case twentyFourPX = "24px"
var value: CGFloat { var value: CGFloat {
switch self { switch self {
case .twelvePX: case .twelvePX:
@ -61,7 +47,7 @@ open class Carousel: View {
} }
} }
} }
/// 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
@ -72,8 +58,7 @@ open class Carousel: View {
public enum Peek: String, CaseIterable { public enum Peek: String, CaseIterable {
case standard, minimum, none case standard, minimum, none
} }
// TO DO: move to model class
/// Enum used to describe the vertical of slotAlignment. /// Enum used to describe the vertical of slotAlignment.
public enum Vertical: String, CaseIterable { public enum Vertical: String, CaseIterable {
case top, middle, bottom case top, middle, bottom
@ -94,11 +79,11 @@ open class Carousel: View {
// MARK: - Public Properties // MARK: - Public Properties
//-------------------------------------------------- //--------------------------------------------------
/// Aspect-ratio options for tilelet in the carousel. If 'none' is passed, the tilelet will take the height of the tallest item in the carousel. /// Aspect-ratio options for tilelet in the carousel. If 'none' is passed, the tilelet will take the height of the tallest item in the carousel.
open var aspectRatio: AspectRatio = .ratio1x1 { didSet { setNeedsUpdate() } } open var aspectRatio: Tilelet.AspectRatio = .ratio1x1 { didSet { setNeedsUpdate() } }
/// Data used to render tilelets in the carousel. /// Data used to render tilelets in the carousel.
open var data: [Any] = [] { didSet { setNeedsUpdate() } } open var data: [Any] = [] { didSet { setNeedsUpdate() } }
/// If provided, width of slots will be rendered based on this value. If omitted, default widths are rendered. /// If provided, width of slots will be rendered based on this value. If omitted, default widths are rendered.
open var width : Width? { open var width : Width? {
get { _width } get { _width }
@ -129,7 +114,7 @@ open class Carousel: View {
setNeedsUpdate() setNeedsUpdate()
} }
} }
/// The amount of slides visible in the carousel container at one time. The default value will be 3UP in tablet and 1UP in mobile. /// The amount of slides visible in the carousel container at one time. The default value will be 3UP in tablet and 1UP in mobile.
open var layout: CarouselScrollbar.Layout { open var layout: CarouselScrollbar.Layout {
get { return _layout } get { return _layout }
@ -138,9 +123,9 @@ open class Carousel: View {
setNeedsUpdate() setNeedsUpdate()
} }
} }
/// A callback when moving the carousel. Returns event object and selectedGroupIndex. /// A callback when moving the carousel. Returns event object and selectedGroupIndex.
open var onChange: ((Int) -> Void)? { // TO DO: return object and index open var onChange: ((Int) -> Void)? {
get { nil } get { nil }
set { set {
onChangeCancellable?.cancel() onChangeCancellable?.cancel()
@ -161,7 +146,7 @@ open class Carousel: View {
setNeedsUpdate() setNeedsUpdate()
} }
} }
/// If provided, will determine the conditions to render the pagination arrows. /// If provided, will determine the conditions to render the pagination arrows.
open var paginationDisplay: PaginationDisplay { open var paginationDisplay: PaginationDisplay {
get { return _paginationDisplay } get { return _paginationDisplay }
@ -170,7 +155,7 @@ open class Carousel: View {
setNeedsUpdate() setNeedsUpdate()
} }
} }
/// If provided, will apply margin to pagination arrows. Can be set to either positive or negative values. /// If provided, will apply margin to pagination arrows. Can be set to either positive or negative values.
/// The default value will be 12px in tablet and 8px in mobile. /// The default value will be 12px in tablet and 8px in mobile.
open var paginationInset: CGFloat { open var paginationInset: CGFloat {
@ -189,19 +174,19 @@ open class Carousel: View {
setNeedsUpdate() setNeedsUpdate()
} }
} }
/// The initial visible slide's index in the carousel. /// The initial visible slide's index in the carousel.
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] = [] { didSet { setNeedsUpdate() } }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Properties // MARK: - Private Properties
//-------------------------------------------------- //--------------------------------------------------
// Sizes are from InVision design specs. // Sizes are from InVision design specs.
internal var containerSize: CGSize { CGSize(width: 320, height: 44) } internal var containerSize: CGSize { CGSize(width: 320, height: 44) }
private let contentStackView = UIStackView().with { private let contentStackView = UIStackView().with {
$0.translatesAutoresizingMaskIntoConstraints = false $0.translatesAutoresizingMaskIntoConstraints = false
$0.axis = .vertical $0.axis = .vertical
@ -231,28 +216,32 @@ open class Carousel: View {
$0.backgroundColor = .clear $0.backgroundColor = .clear
} }
/// Previous button to show previous slide. /// Previous button to show previous slide.
private var previousButton = ButtonIcon().with { private var previousButton = ButtonIcon().with {
$0.kind = .lowContrast $0.kind = .lowContrast
$0.iconName = .leftCaret $0.iconName = .leftCaret
$0.iconOffset = .init(x: -2, y: 0) $0.iconOffset = .init(x: -2, y: 0)
$0.customContainerSize = UIDevice.isIPad ? 40 : 28 $0.customContainerSize = UIDevice.isIPad ? 40 : 28
$0.icon.customSize = UIDevice.isIPad ? 16 : 12 $0.icon.customSize = UIDevice.isIPad ? 16 : 12
} }
/// Next button to show next slide. /// Next button to show next slide.
private var nextButton = ButtonIcon().with { private var nextButton = ButtonIcon().with {
$0.kind = .lowContrast $0.kind = .lowContrast
$0.iconName = .rightCaret $0.iconName = .rightCaret
$0.iconOffset = .init(x: 2, y: 0) $0.iconOffset = .init(x: 2, y: 0)
$0.customContainerSize = UIDevice.isIPad ? 40 : 28 $0.customContainerSize = UIDevice.isIPad ? 40 : 28
$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 the scrubber position changes. Passes parameters (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?
internal var _layout: CarouselScrollbar.Layout = UIDevice.isIPad ? .threeUP : .oneUP internal var _layout: CarouselScrollbar.Layout = UIDevice.isIPad ? .threeUP : .oneUP
internal var _pagination: CarouselPaginationModel = .init(kind: .lowContrast, floating: true) internal var _pagination: CarouselPaginationModel = .init(kind: .lowContrast, floating: true)
internal var _paginationDisplay: PaginationDisplay = .none internal var _paginationDisplay: PaginationDisplay = .none
@ -260,12 +249,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 = .none internal var _peek: Peek = .none
internal var _numberOfSlides: Int = 1 internal var _numberOfSlides: Int = 1
private var _width: Width? = nil private var _width: Width? = nil
private var selectedGroupIndex: Int? { didSet { setNeedsUpdate() } } private var selectedGroupIndex: Int? { didSet { setNeedsUpdate() } }
private var containerStackHeightConstraint: NSLayoutConstraint? private var containerStackHeightConstraint: NSLayoutConstraint?
private var containerViewHeightConstraint: NSLayoutConstraint? private var containerViewHeightConstraint: NSLayoutConstraint?
// 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
@ -282,7 +271,7 @@ open class Carousel: View {
open override func setup() { open override func setup() {
super.setup() super.setup()
isAccessibilityElement = false isAccessibilityElement = false
// add containerView // add containerView
addSubview(containerView) addSubview(containerView)
containerView containerView
@ -305,12 +294,12 @@ open class Carousel: View {
previousButton previousButton
.pinLeading(paginationInset) .pinLeading(paginationInset)
.pinCenterY() .pinCenterY()
scrollContainerView.addSubview(nextButton) scrollContainerView.addSubview(nextButton)
nextButton nextButton
.pinTrailing(paginationInset) .pinTrailing(paginationInset)
.pinCenterY() .pinCenterY()
// add scroll container view & carousel scrollbar // add scroll container view & carousel scrollbar
contentStackView.addArrangedSubview(scrollContainerView) contentStackView.addArrangedSubview(scrollContainerView)
contentStackView.addArrangedSubview(carouselScrollBar) contentStackView.addArrangedSubview(carouselScrollBar)
@ -320,13 +309,15 @@ open class Carousel: View {
.pinBottom() .pinBottom()
.pinLeading() .pinLeading()
.pinTrailing() .pinTrailing()
.heightGreaterThanEqualTo(scrollbarTopSpace + containerSize.height) .heightGreaterThanEqualTo(containerSize.height)
contentStackView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() contentStackView.centerXAnchor.constraint(equalTo: centerXAnchor).activate()
addlisteners()
} }
open override func updateView() { open override func updateView() {
super.updateView() super.updateView()
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 carouselScrollBar.position = (carouselScrollBar.position == 0 || carouselScrollBar.position > carouselScrollBar.numberOfSlides) ? 1 : carouselScrollBar.position
@ -354,7 +345,7 @@ open class Carousel: View {
for x in 0...data.count - 1 { for x in 0...data.count - 1 {
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)
} }
scrollView.addSubview(carouselSlot) scrollView.addSubview(carouselSlot)
carouselSlot carouselSlot
@ -365,7 +356,6 @@ open class Carousel: View {
.height(slotHeight) .height(slotHeight)
xPos = xPos + minimumSlotWidth + gutter.value xPos = xPos + minimumSlotWidth + gutter.value
} }
scrollView.heightAnchor.constraint(equalToConstant: slotHeight).isActive = true
scrollView.contentSize = CGSize(width: xPos - gutter.value, height: slotHeight) scrollView.contentSize = CGSize(width: xPos - gutter.value, height: slotHeight)
} }
@ -380,7 +370,6 @@ open class Carousel: View {
containerViewHeightConstraint?.isActive = true containerViewHeightConstraint?.isActive = true
containerStackHeightConstraint?.isActive = true containerStackHeightConstraint?.isActive = true
addlisteners()
layoutIfNeeded() layoutIfNeeded()
} }
@ -401,10 +390,10 @@ open class Carousel: View {
previousButton.onClick = { _ in self.previousButtonClick() } previousButton.onClick = { _ in self.previousButtonClick() }
//setup test page to show scrubber id was changed //setup test page to show scrubber id was changed
// carouselScrollBar.onScrubberDrag = { [weak self] scrubberId in // carouselScrollBar.onScrubberDrag = { [weak self] scrubberId in
// guard let self else { return } // guard let self else { return }
// updateScrollPosition(position: scrubberId, callbackText:"onScrubberDrag") // updateScrollPosition(position: scrubberId, callbackText:"onScrubberDrag")
// } // }
/// will be called when the thumb move forward. /// will be called when the thumb move forward.
carouselScrollBar.onMoveForward = { [weak self] scrubberId in carouselScrollBar.onMoveForward = { [weak self] scrubberId in
@ -467,7 +456,7 @@ open class Carousel: View {
showPaginationControls() showPaginationControls()
updateScrollPosition(position: carouselScrollBar.position, callbackText:"pageControlClicks") updateScrollPosition(position: carouselScrollBar.position, callbackText:"pageControlClicks")
} }
func updateScrollPosition(position: Int, callbackText: String) { func updateScrollPosition(position: Int, callbackText: String) {
if carouselScrollBar.numberOfSlides > 0 { if carouselScrollBar.numberOfSlides > 0 {
let contentOffsetWidth = scrollView.contentSize.width let contentOffsetWidth = scrollView.contentSize.width