transitioning logical view model separation

This commit is contained in:
Kevin G Christiano 2020-03-02 15:52:02 -05:00
parent 3e3b7dac79
commit b00485c81a
4 changed files with 54 additions and 85 deletions

View File

@ -36,7 +36,7 @@ open class CarouselIndicator: Control, CarouselPageControlProtocol {
/// The types of indicators that can appear. /// The types of indicators that can appear.
public enum IndicatorType: String { public enum IndicatorType: String {
case bar case bars
case numeric case numeric
case hybrid // bar & numeric case hybrid // bar & numeric
} }
@ -77,29 +77,10 @@ open class CarouselIndicator: Control, CarouselPageControlProtocol {
} }
} }
/// The maxmum count of pages before the indicatorView forces a Numeric Indicator in place of Bar.
public var hybridThreshold: Int = 5
/// Set this closure to perform an action when a different indicator was selected. /// Set this closure to perform an action when a different indicator was selected.
/// Passes through oldInde and newIndex, respectively. /// Passes through oldInde and newIndex, respectively.
public var indicatorTouchAction: ((CarouselPageControlProtocol) -> ())? public var indicatorTouchAction: ((CarouselPageControlProtocol) -> ())?
/// Allows sendActions() to trigger even if index is already at min/max index.
public var alwaysSendAction = false
/// Set true to make the accessibility value as "Slide #currentPage of #totalPage", otherwise will be "Page #currentPage of #totalPage", default is false
public var accessibilityHasSlidesInsteadOfPage = false
public var isAnimated = true
/// Will hide this control if page count is 1.
public var hidesForSinglePage = false {
didSet { isHidden = hidesForSinglePage && numberOfPages <= 1 }
}
/// If true, then index will wraparound, otherwise it will stop paging at min/max index.
public var allowIndexWraparound = false
public override var isEnabled: Bool { public override var isEnabled: Bool {
didSet { didSet {
isUserInteractionEnabled = isEnabled isUserInteractionEnabled = isEnabled
@ -117,10 +98,7 @@ open class CarouselIndicator: Control, CarouselPageControlProtocol {
public var currentIndex: Int { public var currentIndex: Int {
get { return _currentIndex } get { return _currentIndex }
set (newIndex) { set (newIndex) {
if !allowIndexWraparound {
guard _currentIndex != newIndex else { return }
}
previousIndex = _currentIndex previousIndex = _currentIndex
_currentIndex = newIndex _currentIndex = newIndex
performAction() performAction()
@ -138,7 +116,7 @@ open class CarouselIndicator: Control, CarouselPageControlProtocol {
guard _numberOfPages != newTotal else { return } guard _numberOfPages != newTotal else { return }
_numberOfPages = newTotal _numberOfPages = newTotal
isHidden = hidesForSinglePage && newTotal <= 1 isHidden = carouselIndicatorModel?.hidesForSinglePage ?? false && newTotal <= 1
if isBarIndicator() { if isBarIndicator() {
(indicatorView as? BarsIndicatorView)?.generateBars() (indicatorView as? BarsIndicatorView)?.generateBars()
@ -148,14 +126,14 @@ open class CarouselIndicator: Control, CarouselPageControlProtocol {
} }
} }
public var disabledIndicatorColor: UIColor = .mvmCoolGray3 public var disabledIndicatorColor: UIColor {
return carouselIndicatorModel?.disabledIndicatorColor.uiColor ?? .mvmCoolGray3
private var _indicatorTintColor: UIColor = .black }
public var indicatorTintColor: UIColor { public var indicatorTintColor: UIColor {
get { return _indicatorTintColor } get { return carouselIndicatorModel?.indicatorColor.uiColor ?? .black }
set (newColor) { set (newColor) {
_indicatorTintColor = newColor carouselIndicatorModel?.indicatorColor = Color(uiColor: newColor)
if isBarIndicator(), let barIndicator = indicatorView as? BarsIndicatorView { if isBarIndicator(), let barIndicator = indicatorView as? BarsIndicatorView {
for (i, barTuple) in barIndicator.barReferences.enumerated() where i != currentIndex { for (i, barTuple) in barIndicator.barReferences.enumerated() where i != currentIndex {
@ -175,7 +153,7 @@ open class CarouselIndicator: Control, CarouselPageControlProtocol {
carouselIndicatorModel?.currentIndicatorColor = Color(uiColor: newColor) carouselIndicatorModel?.currentIndicatorColor = Color(uiColor: newColor)
if isBarIndicator() { if isBarIndicator() {
if let barIndicator = indicatorView as? BarsIndicatorView { if let barIndicator = indicatorView as? BarsIndicatorView, !barIndicator.barReferences.isEmpty {
barIndicator.barReferences[currentIndex].view.backgroundColor = newColor barIndicator.barReferences[currentIndex].view.backgroundColor = newColor
} }
} }
@ -219,10 +197,6 @@ open class CarouselIndicator: Control, CarouselPageControlProtocol {
assignIndicatorView() assignIndicatorView()
setupGestures() setupGestures()
if let accessibleValue = MVMCoreUIUtility.hardcodedString(withKey: accessibilityHasSlidesInsteadOfPage ? "MVMCoreUIPageControlslides_currentpage_index" : "MVMCoreUIPageControl_currentpage_index") {
accessibilityValue = String(format: accessibleValue, currentIndex + 1, numberOfPages)
}
} }
//-------------------------------------------------- //--------------------------------------------------
@ -293,7 +267,7 @@ open class CarouselIndicator: Control, CarouselPageControlProtocol {
indicatorView?.updateUI(previousIndex: previousIndex, indicatorView?.updateUI(previousIndex: previousIndex,
newIndex: currentIndex, newIndex: currentIndex,
totalCount: numberOfPages, totalCount: numberOfPages,
isAnimated: isAnimated) isAnimated: carouselIndicatorModel?.isAnimated ?? true)
} }
public func performAction() { public func performAction() {
@ -306,20 +280,21 @@ open class CarouselIndicator: Control, CarouselPageControlProtocol {
func assignIndicatorView() { func assignIndicatorView() {
switch indicatorType { switch indicatorType {
case .bar: case .bars:
indicatorView = BarsIndicatorView() indicatorView = BarsIndicatorView()
case .numeric: case .numeric:
indicatorView = NumericIndicatorView() indicatorView = NumericIndicatorView()
case .hybrid: case .hybrid:
indicatorView = numberOfPages >= hybridThreshold ? NumericIndicatorView() : BarsIndicatorView()
indicatorView = numberOfPages >= carouselIndicatorModel?.hybridThreshold ?? 0 ? NumericIndicatorView() : BarsIndicatorView()
} }
} }
/// Convenience to determine if current view is displaying bars. /// Convenience to determine if current view is displaying bars.
func isBarIndicator() -> Bool { func isBarIndicator() -> Bool {
return indicatorType == .bar || indicatorType == .hybrid && numberOfPages <= hybridThreshold return indicatorType == .bars || indicatorType == .hybrid && numberOfPages <= carouselIndicatorModel?.hybridThreshold ?? 5
} }
public func scrollViewDidScroll(_ collectionView: UICollectionView) { } public func scrollViewDidScroll(_ collectionView: UICollectionView) { }
@ -328,18 +303,20 @@ open class CarouselIndicator: Control, CarouselPageControlProtocol {
// MARK: - MoleculeViewProtocol // MARK: - MoleculeViewProtocol
//-------------------------------------------------- //--------------------------------------------------
open override func set(with model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { open override func set(with model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
// super.setWithModel(model, delegateObject, additionalData) // super.setWithModel(model, delegateObject, additionalData)
guard let model = model as? CarouselIndicatorModel else { return } guard let model = model as? CarouselIndicatorModel else { return }
indicatorType = IndicatorType(rawValue: model.type ?? "") ?? .hybrid indicatorType = IndicatorType(rawValue: model.type) ?? .hybrid
backgroundColor = model.backgroundColor?.uiColor backgroundColor = model.backgroundColor?.uiColor
// barsColor = model.barsColor currentIndicatorColor = model.currentIndicatorColor.uiColor
// pageIndicatorTintColor indicatorTintColor = model.indicatorColor.uiColor
// currentPageIndicatorTintColor isEnabled = model.isEnabled
if let accessibleValue = MVMCoreUIUtility.hardcodedString(withKey: model.accessibilityHasSlidesInsteadOfPage ? "MVMCoreUIPageControlslides_currentpage_index" : "MVMCoreUIPageControl_currentpage_index") {
accessibilityValue = String(format: accessibleValue, currentIndex + 1, numberOfPages)
}
} }
//-------------------------------------------------- //--------------------------------------------------
@ -358,8 +335,8 @@ open class CarouselIndicator: Control, CarouselPageControlProtocol {
func accessibilityAdjust(toPage index: Int) { func accessibilityAdjust(toPage index: Int) {
if (index < numberOfPages && index >= 0) || alwaysSendAction { if (index < numberOfPages && index >= 0) || carouselIndicatorModel?.alwaysSendAction ?? false {
isAnimated = false carouselIndicatorModel?.isAnimated = false
previousIndex = currentIndex previousIndex = currentIndex
currentIndex = index currentIndex = index
performAction() performAction()

View File

@ -21,20 +21,22 @@ public class CarouselIndicatorModel: CarouselPagingModelProtocol {
public var backgroundColor: Color? public var backgroundColor: Color?
public var moleculeName: String? public var moleculeName: String?
public var type: String = "hybrid" public var type: String = "hybrid"
/// The maxmum count of pages before the indicatorView forces a Numeric Indicator in place of Bar.
public var hybridThreshold: Int = 5 public var hybridThreshold: Int = 5
public var barsColor: Color?
public var currentBarColor: Color?
public var currentIndex: Int = 0
public var numberOfPages: Int = 0 public var numberOfPages: Int = 0
public var alwaysSendEvent: Bool = false
public var isAnimated: Bool = true public var isAnimated: Bool = true
public var hidesForSinglePage: Bool = false public var hidesForSinglePage: Bool = false
/// Set true to make the accessibility value as "Slide #currentPage of #totalPage", otherwise will be "Page #currentPage of #totalPage", default is false
public var accessibilityHasSlidesInsteadOfPage: Bool = false public var accessibilityHasSlidesInsteadOfPage: Bool = false
public var isEnabled: Bool = false public var isEnabled: Bool = true
public var disabledIndicatorColor: Color = Color(uiColor: .mvmCoolGray3) public var disabledIndicatorColor: Color = Color(uiColor: .mvmCoolGray3)
public var indicatorTintColor: Color = Color(uiColor: .mvmBlack) public var indicatorColor: Color = Color(uiColor: .mvmBlack)
public var currentIndicatorColor: Color = Color(uiColor: .mvmBlack) public var currentIndicatorColor: Color = Color(uiColor: .mvmBlack)
public var position: Float? public var padding: Float?
/// Allows sendActions() to trigger even if index is already at min/max index.
public var alwaysSendAction = false
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Keys // MARK: - Keys
@ -45,18 +47,16 @@ public class CarouselIndicatorModel: CarouselPagingModelProtocol {
case backgroundColor case backgroundColor
case type case type
case hybridThreshold case hybridThreshold
case barsColor
case currentBarColor
case currentIndex
case numberOfPages case numberOfPages
case alwaysSendEvent case alwaysSendAction
case isAnimated case isAnimated
case hidesForSinglePage case hidesForSinglePage
case accessibilityHasSlidesInsteadOfPage case accessibilityHasSlidesInsteadOfPage
case isEnabled case isEnabled
case disabledIndicatorColor case disabledIndicatorColor
case indicatorTintColor case indicatorColor
case currentIndicatorColor case currentIndicatorColor
case padding
} }
//-------------------------------------------------- //--------------------------------------------------
@ -66,12 +66,8 @@ public class CarouselIndicatorModel: CarouselPagingModelProtocol {
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
moleculeName = try typeContainer.decodeIfPresent(String.self, forKey: .moleculeName) moleculeName = try typeContainer.decodeIfPresent(String.self, forKey: .moleculeName)
currentBarColor = try typeContainer.decodeIfPresent(Color.self, forKey: .currentBarColor)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
barsColor = try typeContainer.decodeIfPresent(Color.self, forKey: .barsColor)
barsColor = try typeContainer.decodeIfPresent(Color.self, forKey: .barsColor)
currentBarColor = try typeContainer.decodeIfPresent(Color.self, forKey: .currentBarColor)
if let type = try typeContainer.decodeIfPresent(String.self, forKey: .type) { if let type = try typeContainer.decodeIfPresent(String.self, forKey: .type) {
self.type = type self.type = type
} }
@ -80,16 +76,16 @@ public class CarouselIndicatorModel: CarouselPagingModelProtocol {
self.hybridThreshold = hybridThreshold self.hybridThreshold = hybridThreshold
} }
if let currentIndex = try typeContainer.decodeIfPresent(Int.self, forKey: .currentIndex) {
self.currentIndex = currentIndex
}
if let numberOfPages = try typeContainer.decodeIfPresent(Int.self, forKey: .numberOfPages) { if let numberOfPages = try typeContainer.decodeIfPresent(Int.self, forKey: .numberOfPages) {
self.numberOfPages = numberOfPages self.numberOfPages = numberOfPages
} }
if let alwaysSendEvent = try typeContainer.decodeIfPresent(Bool.self, forKey: .alwaysSendEvent) { if let alwaysSendAction = try typeContainer.decodeIfPresent(Bool.self, forKey: .alwaysSendAction) {
self.alwaysSendEvent = alwaysSendEvent self.alwaysSendAction = alwaysSendAction
}
if let padding = try typeContainer.decodeIfPresent(Float.self, forKey: .padding) {
self.padding = padding
} }
if let isAnimated = try typeContainer.decodeIfPresent(Bool.self, forKey: .isAnimated) { if let isAnimated = try typeContainer.decodeIfPresent(Bool.self, forKey: .isAnimated) {
@ -112,8 +108,8 @@ public class CarouselIndicatorModel: CarouselPagingModelProtocol {
self.disabledIndicatorColor = disabledIndicatorColor self.disabledIndicatorColor = disabledIndicatorColor
} }
if let indicatorTintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .indicatorTintColor) { if let indicatorColor = try typeContainer.decodeIfPresent(Color.self, forKey: .indicatorColor) {
self.indicatorTintColor = indicatorTintColor self.indicatorColor = indicatorColor
} }
if let currentIndicatorColor = try typeContainer.decodeIfPresent(Color.self, forKey: .currentIndicatorColor) { if let currentIndicatorColor = try typeContainer.decodeIfPresent(Color.self, forKey: .currentIndicatorColor) {
@ -125,21 +121,17 @@ public class CarouselIndicatorModel: CarouselPagingModelProtocol {
var container = encoder.container(keyedBy: CodingKeys.self) var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName) try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encodeIfPresent(barsColor, forKey: .barsColor)
try container.encodeIfPresent(currentBarColor, forKey: .currentBarColor)
try container.encodeIfPresent(type, forKey: .type) try container.encodeIfPresent(type, forKey: .type)
try container.encodeIfPresent(hybridThreshold, forKey: .hybridThreshold) try container.encodeIfPresent(hybridThreshold, forKey: .hybridThreshold)
try container.encodeIfPresent(barsColor, forKey: .barsColor)
try container.encodeIfPresent(currentBarColor, forKey: .currentBarColor)
try container.encodeIfPresent(currentIndex, forKey: .currentIndex)
try container.encodeIfPresent(numberOfPages, forKey: .numberOfPages) try container.encodeIfPresent(numberOfPages, forKey: .numberOfPages)
try container.encodeIfPresent(alwaysSendEvent, forKey: .alwaysSendEvent) try container.encodeIfPresent(alwaysSendAction, forKey: .alwaysSendAction)
try container.encodeIfPresent(isAnimated, forKey: .isAnimated) try container.encodeIfPresent(isAnimated, forKey: .isAnimated)
try container.encodeIfPresent(hidesForSinglePage, forKey: .hidesForSinglePage) try container.encodeIfPresent(hidesForSinglePage, forKey: .hidesForSinglePage)
try container.encodeIfPresent(accessibilityHasSlidesInsteadOfPage, forKey: .accessibilityHasSlidesInsteadOfPage) try container.encodeIfPresent(accessibilityHasSlidesInsteadOfPage, forKey: .accessibilityHasSlidesInsteadOfPage)
try container.encodeIfPresent(isEnabled, forKey: .isEnabled) try container.encodeIfPresent(isEnabled, forKey: .isEnabled)
try container.encodeIfPresent(disabledIndicatorColor, forKey: .disabledIndicatorColor) try container.encodeIfPresent(disabledIndicatorColor, forKey: .disabledIndicatorColor)
try container.encodeIfPresent(indicatorTintColor, forKey: .indicatorTintColor) try container.encodeIfPresent(indicatorColor, forKey: .indicatorColor)
try container.encodeIfPresent(currentIndicatorColor, forKey: .currentIndicatorColor) try container.encodeIfPresent(currentIndicatorColor, forKey: .currentIndicatorColor)
try container.encodeIfPresent(padding, forKey: .padding)
} }
} }

View File

@ -10,5 +10,5 @@ import Foundation
public protocol CarouselPagingModelProtocol: MoleculeModelProtocol { public protocol CarouselPagingModelProtocol: MoleculeModelProtocol {
var position: Float? { get } var padding: Float? { get }
} }

View File

@ -176,7 +176,7 @@ open class Carousel: View {
pagingView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(molecule, delegateObject, false) as? (UIView & CarouselPageControlProtocol) pagingView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(molecule, delegateObject, false) as? (UIView & CarouselPageControlProtocol)
} }
addPaging(view: pagingView, position: (CGFloat(molecule?.position ?? 20))) addPaging(view: pagingView, padding: (CGFloat(molecule?.padding ?? 20)))
} }
/// Registers the cells with the collection view /// Registers the cells with the collection view
@ -221,7 +221,7 @@ open class Carousel: View {
} }
/// Adds a paging view. Centers it horizontally with the collection view. The position is the vertical distance from the center of the page view to the bottom of the collection view. /// Adds a paging view. Centers it horizontally with the collection view. The position is the vertical distance from the center of the page view to the bottom of the collection view.
open func addPaging(view: (UIView & CarouselPageControlProtocol)?, position: CGFloat) { open func addPaging(view: (UIView & CarouselPageControlProtocol)?, padding: CGFloat) {
pagingView?.removeFromSuperview() pagingView?.removeFromSuperview()
bottomPin?.isActive = false bottomPin?.isActive = false
@ -234,7 +234,7 @@ open class Carousel: View {
addSubview(pagingView) addSubview(pagingView)
pagingView.centerXAnchor.constraint(equalTo: collectionView.centerXAnchor).isActive = true pagingView.centerXAnchor.constraint(equalTo: collectionView.centerXAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: pagingView.bottomAnchor, constant: position).isActive = true collectionView.bottomAnchor.constraint(equalTo: pagingView.bottomAnchor, constant: padding).isActive = true
bottomPin = bottomAnchor.constraint(equalTo: collectionView.bottomAnchor) bottomPin = bottomAnchor.constraint(equalTo: collectionView.bottomAnchor)
bottomPin?.priority = .defaultLow bottomPin?.priority = .defaultLow
bottomPin?.isActive = true bottomPin?.isActive = true