From 57d7a5f7ccff9e091d928972162e16ead2c7face Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 4 Jun 2020 11:46:37 -0400 Subject: [PATCH] Add action to collection cells make paging configurable for carousel. add insets to carousel use button helper function for collection and table cell. --- .../CarouselIndicatorModel.swift | 4 +- .../Items/MoleculeCollectionItemModel.swift | 10 + MVMCoreUI/Atomic/Organisms/Carousel.swift | 187 ++++++++++-------- .../Atomic/Organisms/CarouselModel.swift | 44 +++-- .../CarouselPagingModelProtocol.swift | 2 +- .../Atomic/Templates/CollectionTemplate.swift | 2 +- .../BaseClasses/CollectionViewCell.swift | 32 ++- .../CollectionItemModelProtocol.swift | 10 +- MVMCoreUI/BaseClasses/TableViewCell.swift | 8 +- .../ThreeLayerCollectionViewController.swift | 4 + 10 files changed, 182 insertions(+), 121 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/CarouselIndicatorModel.swift b/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/CarouselIndicatorModel.swift index 359fe98a..8bf3fa19 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/CarouselIndicatorModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/CarouselIndicatorModel.swift @@ -33,7 +33,7 @@ open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelPro public var disabledIndicatorColor: Color = Color(uiColor: .mvmCoolGray3) public var indicatorColor: Color = Color(uiColor: .mvmBlack) public var indicatorColor_inverted: Color = Color(uiColor: .mvmWhite) - public var position: Float? + public var position: CGFloat? /// Allows sendActions() to trigger even if index is already at min/max index. public var alwaysSendAction = false @@ -79,7 +79,7 @@ open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelPro self.inverted = inverted } - if let position = try typeContainer.decodeIfPresent(Float.self, forKey: .position) { + if let position = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .position) { self.position = position } diff --git a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift index 4f203813..645d16b1 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift @@ -13,6 +13,12 @@ import Foundation open override class var identifier: String { return "collectionItem" } + + public var action: ActionModelProtocol? + + private enum CodingKeys: String, CodingKey { + case action + } /// Defaults to set public override func setDefaults() { @@ -35,10 +41,14 @@ import Foundation } required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + action = try typeContainer.decodeModelIfPresent(codingKey: .action) try super.init(from: decoder) } public override func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeModelIfPresent(action, forKey: .action) try super.encode(to: encoder) } } diff --git a/MVMCoreUI/Atomic/Organisms/Carousel.swift b/MVMCoreUI/Atomic/Organisms/Carousel.swift index 9fa72b5d..4a55c425 100644 --- a/MVMCoreUI/Atomic/Organisms/Carousel.swift +++ b/MVMCoreUI/Atomic/Organisms/Carousel.swift @@ -19,8 +19,14 @@ public protocol CarouselPageControlProtocol { open class Carousel: View { - public let collectionView = CollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) - + public let collectionView: CollectionView = { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .horizontal + layout.minimumInteritemSpacing = 0 + layout.minimumLineSpacing = 0 + return CollectionView(frame: .zero, collectionViewLayout: layout) + }() + /// The current index of the collection view. Includes dummy cells when looping. public var currentIndex = 0 @@ -36,13 +42,13 @@ open class Carousel: View { open var numberOfPages = 0 /// The models for the molecules. - var molecules: [MoleculeModelProtocol & CarouselItemModelProtocol]? + public var molecules: [MoleculeModelProtocol & CarouselItemModelProtocol]? /// The horizontal alignment of the cell in the collection view. Only noticeable if the itemWidthPercent is less than 100%. public var itemAlignment = UICollectionView.ScrollPosition.left /// From 0-1. The item width as a percent of the carousel width. - public var itemWidthPercent: Float = 1 + public var itemWidthPercent: CGFloat = 1 /// The height of the carousel. Default is 300. public var collectionViewHeight: NSLayoutConstraint? @@ -51,7 +57,7 @@ open class Carousel: View { public var pagingView: (UIView & CarouselPageControlProtocol)? /// If the carousel should loop after scrolling past the first and final cells. - var loop = false + public var loop = false private var dragging = false @@ -81,6 +87,8 @@ open class Carousel: View { showPeaking(false) // Go to current cell. layoutIfNeeded is needed otherwise cellForItem returns nil for peaking logic. The dispatch is a sad way to ensure the collection view is ready to be scrolled. + guard let model = model as? CarouselModel, + (model.paging == true || model.loop == true) else { return } DispatchQueue.main.async { self.collectionView.scrollToItem(at: IndexPath(row: self.currentIndex, section: 0), at: self.itemAlignment, animated: false) self.collectionView.layoutIfNeeded() @@ -98,15 +106,23 @@ open class Carousel: View { collectionView.delegate = self addSubview(collectionView) bottomPin = NSLayoutConstraint.constraintPinSubview(toSuperview: collectionView)?[ConstraintBot] as? NSLayoutConstraint - collectionViewHeight = collectionView.heightAnchor.constraint(equalToConstant: 300) - collectionViewHeight?.isActive = false + collectionViewHeight?.isActive = true } open override func updateView(_ size: CGFloat) { super.updateView(size) self.size = size + // Set insets for the carousel. + var inset = UIEdgeInsets.zero + let carouselModel = model as? CarouselModel + if carouselModel?.useHorizontalMargins ?? false { + inset.left = carouselModel?.leftPadding ?? Padding.Component.horizontalPaddingForSize(size) + inset.right = carouselModel?.rightPadding ?? Padding.Component.horizontalPaddingForSize(size) + } + (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.sectionInset = inset + // Update cells and re-layout. for cell in collectionView.visibleCells { (cell as? MVMCoreViewProtocol)?.updateView(size) @@ -128,19 +144,19 @@ open class Carousel: View { collectionView.layer.borderColor = backgroundColor?.cgColor collectionView.layer.borderWidth = (carouselModel.border ?? false) ? 1 : 0 backgroundColor = .white - - registerCells(with: carouselModel, delegateObject: delegateObject) - setupLayout(with: carouselModel) - prepareMolecules(with: carouselModel) - itemWidthPercent = (carouselModel.itemWidthPercent ?? 100) / 100 + (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing = carouselModel.spacing ?? 0 + + itemWidthPercent = carouselModel.itemWidthPercent / 100.0 if let alignment = carouselModel.itemAlignment { itemAlignment = alignment } if let height = carouselModel.height { - collectionViewHeight?.constant = CGFloat(height) - collectionViewHeight?.isActive = true + collectionViewHeight?.constant = height } + + registerCells(with: carouselModel, delegateObject: delegateObject) + prepareMolecules(with: carouselModel) setupPagingMolecule(carouselModel.pagingMolecule, delegateObject: delegateObject) @@ -153,16 +169,6 @@ open class Carousel: View { // MARK: - JSON Setters //-------------------------------------------------- - /// Updates the layout being used - func setupLayout(with carouselModel: CarouselModel?) { - - let layout = UICollectionViewFlowLayout() - layout.scrollDirection = .horizontal - layout.minimumLineSpacing = CGFloat(carouselModel?.spacing ?? 1) - layout.minimumInteritemSpacing = 0 - collectionView.collectionViewLayout = layout - } - func prepareMolecules(with carouselModel: CarouselModel?) { guard let newMolecules = carouselModel?.molecules else { numberOfPages = 0 @@ -191,7 +197,7 @@ open class Carousel: View { pagingView = MoleculeObjectMapping.shared()?.createMolecule(molecule, delegateObject: delegateObject) as? (UIView & CarouselPageControlProtocol) } - addPaging(view: pagingView, position: (CGFloat(molecule?.position ?? 20))) + addPaging(view: pagingView, position: molecule?.position ?? 20) } /// Registers the cells with the collection view @@ -294,7 +300,7 @@ open class Carousel: View { extension Carousel: UICollectionViewDelegateFlowLayout { open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { - let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent) + let itemWidth = collectionView.bounds.width * itemWidthPercent return CGSize(width: itemWidth, height: collectionView.bounds.height) } @@ -324,8 +330,15 @@ extension Carousel: UICollectionViewDataSource { } } +extension Carousel: UICollectionViewDelegate { + open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + (collectionView.cellForItem(at: indexPath) as? CollectionTemplateItemProtocol)?.didSelectCell(at: indexPath, delegateObject: delegateObject, additionalData: nil) + } +} + extension Carousel: UIScrollViewDelegate { + /// Go to the cell at the specified index. func goTo(_ index: Int, animated: Bool) { showPeaking(false) @@ -339,51 +352,33 @@ extension Carousel: UIScrollViewDelegate { } } - func handleUserOnBufferCell() { - guard loop else { return } - - let lastPageIndex = numberOfPages + 1 - let goToIndex = { (index: Int) in - self.goTo(index, animated: false) - self.collectionView.layoutIfNeeded() - self.pagingView?.currentIndex = self.pageIndex - } - - if currentIndex < 2 { - // If on a "buffer" last row (which is the first index), go to the real last row secretly. layoutIfNeeded is needed otherwise cellForItem returns nil for peaking. - goToIndex(lastPageIndex) - } else if currentIndex > lastPageIndex { - // If on the "buffer" first row (which is the index after the real last row), go to the real first row secretly. - goToIndex(2) - } - } - - func checkForDraggingOutOfBounds(_ scrollView: UIScrollView) { - - guard loop, dragging else { return } - - // Checks if the user is not paging but attempting to drag endlessly and goes out of bounds. Caps the index. - if let separatorWidth = (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing { - let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent) - let index = scrollView.contentOffset.x / (itemWidth + separatorWidth) - let lastCellIndex = collectionView(collectionView, numberOfItemsInSection: 0) - 1 - - if index < 1 { - currentIndex = 0 - updateModelIndex() - } else if index > CGFloat(lastCellIndex - 1) { - currentIndex = lastCellIndex - updateModelIndex() + /// Adjusts the current contentOffset if we are going onto buffer cells while looping to help with the endless scrolling appearance. + func adjustOffsetForLooping(_ scrollView: UIScrollView) { + let translatedPoint = scrollView.panGestureRecognizer.translation(in: scrollView.superview).x + if translatedPoint > 0 { + // Moving left, see if we are moving passed the first left buffer card and adjust + if let threshold = collectionView.layoutAttributesForItem(at: IndexPath(item: 1, section: 0))?.frame.minX, + scrollView.contentOffset.x < threshold, + let newOffset = collectionView.layoutAttributesForItem(at: IndexPath(item: numberOfPages + 1, section: 0))?.frame.minX { + scrollView.contentOffset.x = newOffset + } + } else if translatedPoint < 0 { + // Moving right, see if we are moving passed the first right buffer card and adjust + if let threshold = collectionView.layoutAttributesForItem(at: IndexPath(item: numberOfPages + 2, section: 0))?.frame.maxX, + scrollView.contentOffset.x + scrollView.bounds.width > threshold, + let newEndOffset = collectionView.layoutAttributesForItem(at: IndexPath(item: 2, section: 0))?.frame.maxX { + scrollView.contentOffset.x = newEndOffset - scrollView.bounds.width } } - - handleUserOnBufferCell() } open func scrollViewDidScroll(_ scrollView: UIScrollView) { - - // Check if the user is dragging the card even further past the next card. - //checkForDraggingOutOfBounds(scrollView) + + // Adjust for looping + if let model = model as? CarouselModel, + model.loop == true { + adjustOffsetForLooping(scrollView) + } // Let the pager know our progress if needed. pagingView?.scrollViewDidScroll(collectionView) @@ -391,6 +386,7 @@ extension Carousel: UIScrollViewDelegate { public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { + // Disable peaking when dragging. dragging = true showPeaking(false) } @@ -398,32 +394,63 @@ extension Carousel: UIScrollViewDelegate { public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { dragging = false - targetContentOffset.pointee = scrollView.contentOffset - // This is for setting up smooth custom paging. (Since UICollectionView only handles paging based on collection view size and not cell size). - guard let separatorWidth = (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing else { return } + // This is for setting up smooth custom paging. (Since UICollectionView only handles paging based on collection view size and not cell size). Math requires that we are using UICollectionViewFlowLayout. + guard (model as? CarouselModel)?.paging == true, + let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else { return } - // We switch cards if we pass the velocity threshold or position threshold (currently 50%). - let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent) - var cellToSwipeTo = Int(scrollView.contentOffset.x / (itemWidth + separatorWidth) + 0.5) - let lastCellIndex = collectionView(collectionView, numberOfItemsInSection: 0) - 1 - let velocityThreshold: CGFloat = 1.1 + let separatorWidth = layout.minimumLineSpacing + let itemWidth = collectionView.bounds.width * itemWidthPercent + let width = itemWidth + separatorWidth - if velocity.x > velocityThreshold { - cellToSwipeTo = currentIndex + 1 - - } else if velocity.x < -velocityThreshold { - cellToSwipeTo = currentIndex - 1 + // Adjusts the offset for the contentInset. Adds imaginary half separator to the left of the first card, which is necessary for determining the percent of a given card we are currently at. + let adjustedOffset = scrollView.contentOffset.x - layout.sectionInset.left + (separatorWidth / 2) + + // Calculates the offset per card depending on the alignment. + var offsetByCard: CGFloat + switch itemAlignment { + case .right: + offsetByCard = ((adjustedOffset + scrollView.bounds.width) / width) - 1 + case .centeredHorizontally: + offsetByCard = ((adjustedOffset + (scrollView.bounds.width / 2)) / width) - 0.5 + default: + offsetByCard = adjustedOffset / width } + // Adjust card for velocity impact. + let velocityThreshold: CGFloat = 1.1 + var cellToSwipeTo: Int + if velocity.x > velocityThreshold { + cellToSwipeTo = Int(ceil(offsetByCard)) + } else if velocity.x < -velocityThreshold { + cellToSwipeTo = Int(floor(offsetByCard)) + } else { + cellToSwipeTo = Int(round(offsetByCard)) + } + + // If we are swiping to a buffer cell, change to real cell before beginning animation so we don't go out of bounds. + if cellToSwipeTo < 2 { + let newOffset = scrollView.contentOffset.x + (width * CGFloat(numberOfPages)) + scrollView.contentOffset.x = newOffset + targetContentOffset.pointee.x = newOffset + cellToSwipeTo = cellToSwipeTo + numberOfPages + } else if cellToSwipeTo > numberOfPages + 1 { + let newOffset = scrollView.contentOffset.x - (width * CGFloat(numberOfPages)) + scrollView.contentOffset.x = newOffset + targetContentOffset.pointee.x = newOffset + cellToSwipeTo = cellToSwipeTo - numberOfPages + } else { + targetContentOffset.pointee = scrollView.contentOffset + } + // Cap the index. + let lastCellIndex = collectionView(collectionView, numberOfItemsInSection: 0) - 1 goTo(min(max(cellToSwipeTo, 0), lastCellIndex), animated: true) } // To give the illusion of endless scrolling. Since we are always calling scrollToItem we can assume finished paging in here. public func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { // Cycle to other end if on buffer cell. - handleUserOnBufferCell() pagingView?.currentIndex = pageIndex showPeaking(true) } diff --git a/MVMCoreUI/Atomic/Organisms/CarouselModel.swift b/MVMCoreUI/Atomic/Organisms/CarouselModel.swift index 5ff753aa..20915799 100644 --- a/MVMCoreUI/Atomic/Organisms/CarouselModel.swift +++ b/MVMCoreUI/Atomic/Organisms/CarouselModel.swift @@ -21,14 +21,18 @@ import UIKit public var backgroundColor: Color? public var molecules: [MoleculeModelProtocol & CarouselItemModelProtocol] public var index: Int = 0 - public var spacing: Float? + public var spacing: CGFloat? public var border: Bool? public var loop: Bool? - public var height: Float? - public var itemWidthPercent: Float? + public var height: CGFloat? + @Percent public var itemWidthPercent = 100 public var itemAlignment: UICollectionView.ScrollPosition? public var pagingMolecule: (CarouselPagingModelProtocol & MoleculeModelProtocol)? - + public var paging: Bool = true + public var useHorizontalMargins: Bool? + public var leftPadding: CGFloat? + public var rightPadding: CGFloat? + public init(molecules: [MoleculeModelProtocol & CarouselItemModelProtocol]) { self.molecules = molecules } @@ -49,6 +53,10 @@ import UIKit case itemWidthPercent case itemAlignment case pagingMolecule + case paging + case useHorizontalMargins + case leftPadding + case rightPadding } //-------------------------------------------------- @@ -60,13 +68,21 @@ import UIKit molecules = try typeContainer.decodeModels(codingKey: .molecules) index = try typeContainer.decodeIfPresent(Int.self, forKey: .index) ?? 0 backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) - spacing = try typeContainer.decodeIfPresent(Float.self, forKey: .spacing) + spacing = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .spacing) border = try typeContainer.decodeIfPresent(Bool.self, forKey: .border) loop = try typeContainer.decodeIfPresent(Bool.self, forKey: .loop) - height = try typeContainer.decodeIfPresent(Float.self, forKey: .height) - itemWidthPercent = try typeContainer.decodeIfPresent(Float.self, forKey: .itemWidthPercent) + height = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .height) + if let itemWidthPercent = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .itemWidthPercent) { + self.itemWidthPercent = itemWidthPercent + } itemAlignment = try typeContainer.decodeIfPresent(UICollectionView.ScrollPosition.self, forKey: .itemAlignment) pagingMolecule = try typeContainer.decodeModelIfPresent(codingKey: .pagingMolecule) + if let paging = try typeContainer.decodeIfPresent(Bool.self, forKey: .paging) { + self.paging = paging + } + useHorizontalMargins = try typeContainer.decodeIfPresent(Bool.self, forKey: .useHorizontalMargins) + leftPadding = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .leftPadding) + rightPadding = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .rightPadding) } public func encode(to encoder: Encoder) throws { @@ -74,12 +90,16 @@ import UIKit try container.encode(moleculeName, forKey: .moleculeName) try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeModels(molecules, forKey: .molecules) - try container.encode(spacing, forKey: .spacing) - try container.encode(border, forKey: .border) - try container.encode(loop, forKey: .loop) - try container.encode(height, forKey: .height) + try container.encodeIfPresent(spacing, forKey: .spacing) + try container.encodeIfPresent(border, forKey: .border) + try container.encodeIfPresent(loop, forKey: .loop) + try container.encodeIfPresent(height, forKey: .height) try container.encode(itemWidthPercent, forKey: .itemWidthPercent) - try container.encode(itemAlignment, forKey: .itemAlignment) + try container.encodeIfPresent(itemAlignment, forKey: .itemAlignment) try container.encodeModelIfPresent(pagingMolecule, forKey: .pagingMolecule) + try container.encode(paging, forKey: .paging) + try container.encodeIfPresent(useHorizontalMargins, forKey: .useHorizontalMargins) + try container.encodeIfPresent(leftPadding, forKey: .leftPadding) + try container.encodeIfPresent(rightPadding, forKey: .rightPadding) } } diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/CarouselPagingModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/CarouselPagingModelProtocol.swift index 72138290..b3dc3f2f 100644 --- a/MVMCoreUI/Atomic/Protocols/ModelProtocols/CarouselPagingModelProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/CarouselPagingModelProtocol.swift @@ -10,5 +10,5 @@ import Foundation public protocol CarouselPagingModelProtocol { - var position: Float? { get } + var position: CGFloat? { get } } diff --git a/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift b/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift index be4273df..b65e96f1 100644 --- a/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift @@ -131,7 +131,7 @@ import Foundation return cell } - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + public override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { (collectionView.cellForItem(at: indexPath) as? CollectionTemplateItemProtocol)?.didSelectCell(at: indexPath, delegateObject: delegateObjectIVar, additionalData: nil) } diff --git a/MVMCoreUI/BaseClasses/CollectionViewCell.swift b/MVMCoreUI/BaseClasses/CollectionViewCell.swift index aa74d229..848509c9 100644 --- a/MVMCoreUI/BaseClasses/CollectionViewCell.swift +++ b/MVMCoreUI/BaseClasses/CollectionViewCell.swift @@ -10,7 +10,7 @@ import Foundation /// A base collection view cell with basic mvm functionality. -open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCoreViewProtocol, CollectionTemplateItemProtocol { +open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCoreViewProtocol, CollectionTemplateItemProtocol, MFButtonProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -25,10 +25,6 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo private var initialSetupPerformed = false - //-------------------------------------------------- - // MARK: - Properties - //-------------------------------------------------- - // MARK: - Inits public override init(frame: CGRect) { super.init(frame: .zero) @@ -47,10 +43,6 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo } } - //-------------------------------------------------- - // MARK: - Properties - //-------------------------------------------------- - // MARK: - MVMCoreViewProtocol open func setupView() { isAccessibilityElement = false @@ -68,16 +60,6 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo (molecule as? MVMCoreViewProtocol)?.updateView(size) } - open func reset() { - molecule?.reset() - backgroundColor = .mvmWhite - width = nil - } - - //-------------------------------------------------- - // MARK: - Properties - //-------------------------------------------------- - // MARK: - MoleculeViewProtocol open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { guard let model = model as? CollectionItemModelProtocol else { return } @@ -94,6 +76,12 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo } } + open func reset() { + molecule?.reset() + backgroundColor = .mvmWhite + width = nil + } + /// Convenience function. Adds a molecule to the view. open func addMolecule(_ molecule: MoleculeViewProtocol) { contentView.addSubview(molecule) @@ -109,6 +97,12 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo self.width = width } + // MARK: - Override + public func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + guard let action = model?.action else { return } + Button.performButtonAction(with: action, button: self, delegateObject: delegateObject, additionalData: additionalData) + } + // Column logic, set width. override open func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { let autoLayoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes) diff --git a/MVMCoreUI/BaseClasses/Protocols/CollectionItemModelProtocol.swift b/MVMCoreUI/BaseClasses/Protocols/CollectionItemModelProtocol.swift index 9361ab1e..faed7548 100644 --- a/MVMCoreUI/BaseClasses/Protocols/CollectionItemModelProtocol.swift +++ b/MVMCoreUI/BaseClasses/Protocols/CollectionItemModelProtocol.swift @@ -9,5 +9,13 @@ import Foundation public protocol CollectionItemModelProtocol { - + var action: ActionModelProtocol? { get set } +} + +// Not a strict requirement. +public extension CollectionItemModelProtocol { + var action: ActionModelProtocol? { + get { return nil } + set { } + } } diff --git a/MVMCoreUI/BaseClasses/TableViewCell.swift b/MVMCoreUI/BaseClasses/TableViewCell.swift index 254a09f0..caaeec85 100644 --- a/MVMCoreUI/BaseClasses/TableViewCell.swift +++ b/MVMCoreUI/BaseClasses/TableViewCell.swift @@ -8,7 +8,7 @@ import UIKit -@objcMembers open class TableViewCell: UITableViewCell, MoleculeViewProtocol, MoleculeListCellProtocol, MVMCoreViewProtocol { +@objcMembers open class TableViewCell: UITableViewCell, MoleculeViewProtocol, MoleculeListCellProtocol, MVMCoreViewProtocol, MFButtonProtocol { open var molecule: MoleculeViewProtocol? open var listItemModel: ListItemModelProtocol? @@ -267,10 +267,8 @@ import UIKit } public func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - //TODO: Use object when handleAction is rewrote to handle action model - if let actionMap = self.listItemModel?.action?.toJSON() { - MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) - } + guard let action = listItemModel?.action else { return } + Button.performButtonAction(with: action, button: self, delegateObject: delegateObject, additionalData: additionalData) } public func willDisplay() { diff --git a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift index 88d8157a..4011f4f8 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift @@ -233,4 +233,8 @@ import Foundation } fatalError() } + + open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + (collectionView.cellForItem(at: indexPath) as? CollectionTemplateItemProtocol)?.didSelectCell(at: indexPath, delegateObject: delegateObjectIVar, additionalData: nil) + } }