Digital ACT-191 ONEAPP-7013 story: refactored code

This commit is contained in:
Vasavi Kanamarlapudi 2024-07-02 14:47:20 +05:30
parent 668b20f77b
commit 8619c64109

View File

@ -183,13 +183,11 @@ 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] = [] { didSet { setNeedsUpdate() } } open var slotAlignment: [CarouselSlotAlignmentModel] = [] { didSet { setNeedsUpdate() } }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Properties // MARK: - Private Properties
//-------------------------------------------------- //--------------------------------------------------
// Sizes are from InVision design specs. internal var containerSize: CGSize { CGSize(width: frame.size.width, 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
@ -260,7 +258,7 @@ open class Carousel: View {
private var prevButtonLeadingConstraint: NSLayoutConstraint? private var prevButtonLeadingConstraint: NSLayoutConstraint?
private var nextButtonTrailingConstraint: NSLayoutConstraint? private var nextButtonTrailingConstraint: NSLayoutConstraint?
private var containerLeadingConstraint: NSLayoutConstraint? private var containerLeadingConstraint: 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
@ -268,18 +266,21 @@ open class Carousel: View {
var peekMinimum = 24.0 var peekMinimum = 24.0
var minimumSlotWidth = 0.0 var minimumSlotWidth = 0.0
var carouselScrollbarMinWidth = 96.0 var carouselScrollbarMinWidth = 96.0
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Lifecycle // MARK: - Lifecycle
//-------------------------------------------------- //--------------------------------------------------
/// Executed on initialization for this View.
open override func initialSetup() { open override func initialSetup() {
super.initialSetup() super.initialSetup()
} }
/// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations.
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
.pinTop() .pinTop()
@ -287,18 +288,19 @@ open class Carousel: View {
.pinLeadingGreaterThanOrEqualTo() .pinLeadingGreaterThanOrEqualTo()
.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 = containerView.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 0)
containerLeadingConstraint?.activate() containerLeadingConstraint?.activate()
// add content stackview // Add content stackview
containerView.addSubview(contentStackView) containerView.addSubview(contentStackView)
// add scrollview // Add scrollview
scrollContainerView.addSubview(scrollView) scrollContainerView.addSubview(scrollView)
scrollView.pinToSuperView() scrollView.pinToSuperView()
// add pagination button icons // Add pagination button icons
scrollContainerView.addSubview(previousButton) scrollContainerView.addSubview(previousButton)
previousButton previousButton
.pinLeadingGreaterThanOrEqualTo() .pinLeadingGreaterThanOrEqualTo()
@ -309,7 +311,7 @@ open class Carousel: View {
.pinTrailingLessThanOrEqualTo() .pinTrailingLessThanOrEqualTo()
.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)
contentStackView.setCustomSpacing(scrollbarTopSpace, after: scrollContainerView) contentStackView.setCustomSpacing(scrollbarTopSpace, after: scrollContainerView)
@ -322,7 +324,8 @@ open class Carousel: View {
addlisteners() addlisteners()
} }
/// Used to make changes to the View based off a change events or from local properties.
open override func updateView() { open override func updateView() {
super.updateView() super.updateView()
@ -353,7 +356,7 @@ open class Carousel: View {
if peek == .none { if peek == .none {
paginationDisplay = .persistent paginationDisplay = .persistent
} }
// 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.
if UIDevice.isIPad && peek == .minimum { if UIDevice.isIPad && peek == .minimum {
peek = .standard peek = .standard
@ -363,11 +366,12 @@ open class Carousel: View {
if peek == .standard && !UIDevice.isIPad && layout != CarouselScrollbar.Layout.oneUP { if peek == .standard && !UIDevice.isIPad && layout != CarouselScrollbar.Layout.oneUP {
peek = .minimum peek = .minimum
} }
updatePaginationControls() updatePaginationControls()
addCarouselSlots() addCarouselSlots()
} }
/// Resets to default settings.
open override func reset() { open override func reset() {
super.reset() super.reset()
shouldUpdateView = false shouldUpdateView = false
@ -384,19 +388,69 @@ open class Carousel: View {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Methods // MARK: - Private Methods
//-------------------------------------------------- //--------------------------------------------------
private func addlisteners() {
nextButton.onClick = { _ in self.nextButtonClick() }
previousButton.onClick = { _ in self.previousButtonClick() }
/// Will be called when the thumb move forward.
carouselScrollBar.onMoveForward = { [weak self] scrubberId in
guard let self else { return }
updateScrollPosition(position: scrubberId, callbackText:"onMoveForward")
}
/// Will be called when the thumb move backward.
carouselScrollBar.onMoveBackward = { [weak self] scrubberId in
guard let self else { return }
updateScrollPosition(position: scrubberId, callbackText:"onMoveBackward")
}
/// Will be called when the thumb touch start.
carouselScrollBar.onThumbTouchStart = { [weak self] scrubberId in
guard let self else { return }
updateScrollPosition(position: scrubberId, callbackText:"onThumbTouchStart")
}
/// Will be called when the thumb touch end.
carouselScrollBar.onThumbTouchEnd = { [weak self] scrubberId in
guard let self else { return }
updateScrollPosition(position: scrubberId, callbackText:"onThumbTouchEnd")
}
}
private func updatePaginationControls() {
containerView.surface = surface
showPaginationControls()
previousButton.kind = pagination.kind
previousButton.floating = pagination.floating
nextButton.kind = pagination.kind
nextButton.floating = pagination.floating
previousButton.surface = surface
nextButton.surface = surface
}
private func showPaginationControls() {
if carouselScrollBar.numberOfSlides == _layout.value {
previousButton.isHidden = true
nextButton.isHidden = true
} else {
previousButton.isHidden = (carouselScrollBar.position == 1) || (paginationDisplay == .none)
nextButton.isHidden = (carouselScrollBar.position == totalPositions()) || (paginationDisplay == .none)
}
}
private func addCarouselSlots() { private func addCarouselSlots() {
getSlotWidth() getSlotWidth()
if containerView.frame.size.width > 0 { if containerView.frame.size.width > 0 {
containerViewHeightConstraint?.isActive = false containerViewHeightConstraint?.isActive = false
containerStackHeightConstraint?.isActive = false containerStackHeightConstraint?.isActive = false
// perform a loop to iterate each subView // Perform a loop to iterate each subView
scrollView.subviews.forEach { subView in scrollView.subviews.forEach { subView in
// removing subView from its parent view // Removing subView from its parent view
subView.removeFromSuperview() subView.removeFromSuperview()
} }
// add carousel items // Add carousel items
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 {
@ -433,86 +487,7 @@ open class Carousel: View {
} }
} }
private func ratioSize(for width: CGFloat) -> CGSize { private func getSlotWidth() {
var height: CGFloat = width
switch aspectRatio {
case .ratio1x1:
break;
case .ratio3x4:
height = (4 / 3) * width
case .ratio4x3:
height = (3 / 4) * width
case .ratio2x3:
height = (3 / 2) * width
case .ratio3x2:
height = (2 / 3) * width
case .ratio9x16:
height = (16 / 9) * width
case .ratio16x9:
height = (9 / 16) * width
case .ratio1x2:
height = (2 / 1) * width
case .ratio2x1:
height = (1 / 2) * width
default:
break
}
return CGSize(width: width, height: height)
}
func addlisteners() {
nextButton.onClick = { _ in self.nextButtonClick() }
previousButton.onClick = { _ in self.previousButtonClick() }
/// will be called when the thumb move forward.
carouselScrollBar.onMoveForward = { [weak self] scrubberId in
guard let self else { return }
updateScrollPosition(position: scrubberId, callbackText:"onMoveForward")
}
/// will be called when the thumb move backward.
carouselScrollBar.onMoveBackward = { [weak self] scrubberId in
guard let self else { return }
updateScrollPosition(position: scrubberId, callbackText:"onMoveBackward")
}
/// will be called when the thumb touch start.
carouselScrollBar.onThumbTouchStart = { [weak self] scrubberId in
guard let self else { return }
updateScrollPosition(position: scrubberId, callbackText:"onThumbTouchStart")
}
/// will be called when the thumb touch end.
carouselScrollBar.onThumbTouchEnd = { [weak self] scrubberId in
guard let self else { return }
updateScrollPosition(position: scrubberId, callbackText:"onThumbTouchEnd")
}
}
func updatePaginationControls() {
containerView.surface = surface
showPaginationControls()
previousButton.kind = pagination.kind
previousButton.floating = pagination.floating
nextButton.kind = pagination.kind
nextButton.floating = pagination.floating
previousButton.surface = surface
nextButton.surface = surface
}
func updatePaginationInset() {
prevButtonLeadingConstraint?.isActive = false
nextButtonTrailingConstraint?.isActive = false
prevButtonLeadingConstraint = previousButton.leadingAnchor.constraint(equalTo: scrollContainerView.leadingAnchor, constant: paginationInset)
nextButtonTrailingConstraint = nextButton.trailingAnchor.constraint(equalTo: scrollContainerView.trailingAnchor, constant: -paginationInset)
prevButtonLeadingConstraint?.isActive = true
nextButtonTrailingConstraint?.isActive = true
}
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
let isPeekMinimumOnTablet = UIDevice.isIPad && peek == .minimum let isPeekMinimumOnTablet = UIDevice.isIPad && peek == .minimum
@ -538,19 +513,69 @@ open class Carousel: View {
minimumSlotWidth = minimumSlotWidth / CGFloat(layout.value) minimumSlotWidth = minimumSlotWidth / CGFloat(layout.value)
} }
func nextButtonClick() { private func nextButtonClick() {
carouselScrollBar.position = carouselScrollBar.position+1 carouselScrollBar.position = carouselScrollBar.position+1
showPaginationControls() showPaginationControls()
updateScrollPosition(position: carouselScrollBar.position, callbackText:"pageControlClicks") updateScrollPosition(position: carouselScrollBar.position, callbackText:"pageControlClicks")
} }
func previousButtonClick() { private func previousButtonClick() {
carouselScrollBar.position = carouselScrollBar.position-1 carouselScrollBar.position = carouselScrollBar.position-1
showPaginationControls() showPaginationControls()
updateScrollPosition(position: carouselScrollBar.position, callbackText:"pageControlClicks") updateScrollPosition(position: carouselScrollBar.position, callbackText:"pageControlClicks")
} }
func updateScrollPosition(position: Int, callbackText: String) { private func ratioSize(for width: CGFloat) -> CGSize {
var height: CGFloat = width
switch aspectRatio {
case .ratio1x1:
break;
case .ratio3x4:
height = (4 / 3) * width
case .ratio4x3:
height = (3 / 4) * width
case .ratio2x3:
height = (3 / 2) * width
case .ratio3x2:
height = (2 / 3) * width
case .ratio9x16:
height = (16 / 9) * width
case .ratio16x9:
height = (9 / 16) * width
case .ratio1x2:
height = (2 / 1) * width
case .ratio2x1:
height = (1 / 2) * width
default:
break
}
return CGSize(width: width, height: height)
}
private func updatePaginationInset() {
prevButtonLeadingConstraint?.isActive = false
nextButtonTrailingConstraint?.isActive = false
prevButtonLeadingConstraint = previousButton.leadingAnchor.constraint(equalTo: scrollContainerView.leadingAnchor, constant: paginationInset)
nextButtonTrailingConstraint = nextButton.trailingAnchor.constraint(equalTo: scrollContainerView.trailingAnchor, constant: -paginationInset)
prevButtonLeadingConstraint?.isActive = true
nextButtonTrailingConstraint?.isActive = true
}
private func updateScrollbarPosition(targetContentOffsetXPos:CGFloat) {
let scrollContentSizeWidth = scrollView.contentSize.width
let totalPositions = totalPositions()
let layoutSpace = Int (floor( Double(scrollContentSizeWidth / Double(totalPositions))))
let remindSpace = Int(targetContentOffsetXPos) % layoutSpace
var contentPos = (Int(targetContentOffsetXPos) / layoutSpace) + 1
contentPos = remindSpace > layoutSpace/2 ? contentPos+1 : contentPos
carouselScrollBar.position = contentPos
updateScrollPosition(position: contentPos, callbackText: "ScrollViewMoved")
}
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
let totalPositions = totalPositions() let totalPositions = totalPositions()
@ -586,30 +611,9 @@ open class Carousel: View {
} }
} }
func updateScrollbarPosition(targetContentOffsetXPos:CGFloat) {
let scrollContentSizeWidth = scrollView.contentSize.width
let totalPositions = totalPositions()
let layoutSpace = Int (floor( Double(scrollContentSizeWidth / Double(totalPositions))))
let remindSpace = Int(targetContentOffsetXPos) % layoutSpace
var contentPos = (Int(targetContentOffsetXPos) / layoutSpace) + 1
contentPos = remindSpace > layoutSpace/2 ? contentPos+1 : contentPos
carouselScrollBar.position = contentPos
updateScrollPosition(position: contentPos, callbackText: "ScrollViewMoved")
}
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)))
} }
func showPaginationControls() {
if carouselScrollBar.numberOfSlides == _layout.value {
previousButton.isHidden = true
nextButton.isHidden = true
} else {
previousButton.isHidden = (carouselScrollBar.position == 1) || (paginationDisplay == .none)
nextButton.isHidden = (carouselScrollBar.position == totalPositions()) || (paginationDisplay == .none)
}
}
} }
extension Carousel: UIScrollViewDelegate { extension Carousel: UIScrollViewDelegate {
@ -619,6 +623,7 @@ extension Carousel: UIScrollViewDelegate {
public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
updateScrollbarPosition(targetContentOffsetXPos: targetContentOffset.pointee.x) updateScrollbarPosition(targetContentOffsetXPos: targetContentOffset.pointee.x)
} }
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
var visibleRect = CGRect() var visibleRect = CGRect()
visibleRect.origin = scrollView.contentOffset visibleRect.origin = scrollView.contentOffset