diff --git a/MVMCoreUI/Atomic/Atoms/Views/ImageViewModel.swift b/MVMCoreUI/Atomic/Atoms/Views/ImageViewModel.swift index 03c18491..c61739a7 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/ImageViewModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/ImageViewModel.swift @@ -26,6 +26,7 @@ public var localBundle: Bundle? public var cornerRadius: CGFloat? public var clipsImage: Bool? + public var allowServerParameters: Bool? public var shouldMaskRecordedView: Bool? = false //-------------------------------------------------- @@ -56,5 +57,6 @@ case cornerRadius case clipsImage case shouldMaskRecordedView + case allowServerParameters } } diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift index f3d381bc..780f8829 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift @@ -289,7 +289,7 @@ if shouldLoadImage(withName: imageModel.image, width: width, height: height) { imageView.image = nil imageView.animatedImage = nil - loadImage(withName: imageModel.image, format: imageModel.imageFormat, width: width, height: height, customFallbackImage: imageModel.fallbackImage, localBundle: imageModel.localBundle) + loadImage(withName: imageModel.image, format: imageModel.imageFormat, width: width, height: height, customFallbackImage: imageModel.fallbackImage, allowServerParameters: imageModel.allowServerParameters ?? false, localBundle: imageModel.localBundle) } if let contentMode = imageModel.contentMode { diff --git a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/Tabs.swift b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/Tabs.swift index 4e340ab6..e5682e71 100644 --- a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/Tabs.swift +++ b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/Tabs.swift @@ -51,7 +51,7 @@ import VDSColorTokens public let selectionLineMovingTime: TimeInterval = 0.2 //------------------------------------------------- - // MARK:- Layout Views + // MARK: - Layout Views //------------------------------------------------- open override func reset() { @@ -122,8 +122,27 @@ import VDSColorTokens NSLayoutConstraint.constraintPinSubview(bottomLine, pinTop: false, pinBottom: true, pinLeft: true, pinRight: true) } + open override func layoutSubviews() { + super.layoutSubviews() + // Accounts for any collection size changes + DispatchQueue.main.async { + self.layoutCollection() + } + } + + /// Invalidates the layout and ensures we are paged to the correct cell. + open func layoutCollection() { + collectionView?.collectionViewLayout.invalidateLayout() + + // 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. + DispatchQueue.main.async { + self.collectionView?.scrollToItem(at: IndexPath(row: self.selectedIndex, section: 0), at: .left, animated: false) + self.collectionView?.layoutIfNeeded() + } + } + //------------------------------------------------- - // MARK:- Control Methods + // MARK: - Control Methods //------------------------------------------------- public func selectIndex(_ index: Int, animated: Bool) { @@ -146,7 +165,7 @@ import VDSColorTokens } //------------------------------------------------- - // MARK:- Molecule Setup + // MARK: - Molecule Setup //------------------------------------------------- override open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { @@ -163,7 +182,7 @@ import VDSColorTokens } //------------------------------------------------- -// MARK:- Collection View Methods +// MARK: - Collection View Methods //------------------------------------------------- extension Tabs: UICollectionViewDataSource { @@ -283,7 +302,7 @@ extension Tabs: UIScrollViewDelegate { //------------------------------------------------- -// MARK:- Bottom Line Methods +// MARK: - Bottom Line Methods //------------------------------------------------- extension Tabs { func moveSelectionLine(toIndex indexPath: IndexPath, animated: Bool, cell: TabItemCell) { diff --git a/MVMCoreUI/Atomic/Molecules/Items/CarouselItem.swift b/MVMCoreUI/Atomic/Molecules/Items/CarouselItem.swift index a37fe016..301a2274 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/CarouselItem.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/CarouselItem.swift @@ -22,7 +22,8 @@ open class CarouselItem: MoleculeCollectionViewCell, CarouselItemProtocol { open override func setupView() { super.setupView() - + clipsToBounds = true + // Covers the card when peaking. peakingCover.backgroundColor = .white peakingCover.alpha = 0 @@ -51,6 +52,12 @@ open class CarouselItem: MoleculeCollectionViewCell, CarouselItemProtocol { super.set(with: model, delegateObject, additionalData) guard let collectionModel = model as? CarouselItemModel else { return } + if let cornerRadius = (model as? ContainerModel)?.cornerRadius { + layer.cornerRadius = cornerRadius + } else { + layer.cornerRadius = 0 + } + // Handles peaking. allowsPeaking = collectionModel.peakingUI ?? false if let peakingArrowColor = collectionModel.peakingArrowColor { diff --git a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift index 5523d08d..2afda5a4 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift @@ -16,6 +16,7 @@ open override class var identifier: String { "collectionItem" } public var action: ActionModelProtocol? + public var border = false //-------------------------------------------------- // MARK: - Keys @@ -23,6 +24,7 @@ private enum CodingKeys: String, CodingKey { case action + case border } //-------------------------------------------------- @@ -59,12 +61,16 @@ required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) action = try typeContainer.decodeModelIfPresent(codingKey: .action) + if let border = try typeContainer.decodeIfPresent(Bool.self, forKey: .border) { + self.border = border + } 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 container.encodeIfPresent(border, forKey: .border) try super.encode(to: encoder) } } diff --git a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionViewCell.swift b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionViewCell.swift index 4ef4f84b..baad17f8 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionViewCell.swift @@ -15,6 +15,13 @@ open class MoleculeCollectionViewCell: CollectionViewCell { super.set(with: model, delegateObject, additionalData) guard let collectionModel = model as? MoleculeCollectionItemModel else { return } + if collectionModel.border { + contentView.layer.borderColor = UIColor.black.cgColor + contentView.layer.borderWidth = 1 + } else { + contentView.layer.borderWidth = 0 + } + if molecule == nil { if let moleculeView = ModelRegistry.createMolecule(collectionModel.molecule, delegateObject: delegateObject, additionalData: additionalData) { addMolecule(moleculeView) diff --git a/MVMCoreUI/Atomic/Molecules/Items/TabsTableViewCell.swift b/MVMCoreUI/Atomic/Molecules/Items/TabsTableViewCell.swift index 6a941881..e904707e 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/TabsTableViewCell.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/TabsTableViewCell.swift @@ -47,6 +47,7 @@ import UIKit public override func reset() { super.reset() tabs.reset() + tabs.paddingBeforeFirstTab = false } public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { 46 } diff --git a/MVMCoreUI/Atomic/Organisms/Carousel/Carousel.swift b/MVMCoreUI/Atomic/Organisms/Carousel/Carousel.swift index fcaa1010..ea7d89b8 100644 --- a/MVMCoreUI/Atomic/Organisms/Carousel/Carousel.swift +++ b/MVMCoreUI/Atomic/Organisms/Carousel/Carousel.swift @@ -104,6 +104,7 @@ open class Carousel: View { super.setupView() collectionView.dataSource = self collectionView.delegate = self + collectionView.bounces = false addSubview(collectionView) bottomPin = NSLayoutConstraint.constraintPinSubview(toSuperview: collectionView)?[ConstraintBot] as? NSLayoutConstraint collectionViewHeight = collectionView.heightAnchor.constraint(equalToConstant: 300) @@ -129,7 +130,7 @@ open class Carousel: View { inset.left = carouselModel?.leftPadding ?? Padding.Component.horizontalPaddingForSize(size) inset.right = carouselModel?.rightPadding ?? Padding.Component.horizontalPaddingForSize(size) } - (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.sectionInset = inset + collectionView.contentInset = inset // Update cells and re-layout. for cell in collectionView.visibleCells { diff --git a/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift b/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift index 6188aeae..b84792a6 100644 --- a/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift @@ -100,7 +100,8 @@ let columns = templateModel?.columns, columns > 0, let cell = cell as? CollectionTemplateItemProtocol { let width = (size - collectionView.adjustedContentInset.left - collectionView.adjustedContentInset.right) / CGFloat(columns) - cell.set(width: width) + // Makes the width slightly less to avoid rounding errors and the column being a little too big. + cell.set(width: width - 0.1) } } diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift index cace752a..950b6785 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift @@ -72,7 +72,11 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol override open func viewForBottom() -> UIView { guard let footerModel = templateModel?.footer, let molecule = generateMoleculeView(from: footerModel) - else { return super.viewForBottom() } + else { + let view = super.viewForBottom() + view.backgroundColor = templateModel?.backgroundColor?.uiColor ?? .clear + return view + } return molecule } diff --git a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift index f480f083..7d8b991c 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift @@ -169,6 +169,7 @@ open class ThreeLayerTableViewController: ProgrammaticTableViewController { bottomView = MVMCoreUICommonViewsUtility.getView(with: 0.5) } let footerView = MVMCoreUICommonViewsUtility.commonView() + footerView.backgroundColor = bottomView.backgroundColor footerView.addSubview(bottomView) bottomViewTopConstraint = bottomView.topAnchor.constraint(equalTo: footerView.topAnchor, constant: spaceAboveBottomView() ?? 0) bottomViewTopConstraint?.isActive = true diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index b86545fe..d91e776e 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -435,7 +435,7 @@ import MVMCore // Open the support panel if error == nil, - loadObject?.requestParameters?.openSupportPanel ?? (loadObject?.systemParametersJSON?.boolForKey(KeyOpenSupport) ?? false) == true { + (loadObject?.requestParameters?.openSupportPanel ?? false) || (loadObject?.systemParametersJSON?.boolForKey(KeyOpenSupport) ?? false) { MVMCoreUISession.sharedGlobal()?.splitViewController?.showRightPanel(animated: true) } } diff --git a/MVMCoreUI/Containers/NavigationController/UINavigationController+Extension.swift b/MVMCoreUI/Containers/NavigationController/UINavigationController+Extension.swift index 9a0665b9..e1d3a247 100644 --- a/MVMCoreUI/Containers/NavigationController/UINavigationController+Extension.swift +++ b/MVMCoreUI/Containers/NavigationController/UINavigationController+Extension.swift @@ -100,7 +100,13 @@ public extension UINavigationController { appearance.backgroundColor = backgroundColor appearance.titleTextAttributes.updateValue(tint, forKey: .foregroundColor) appearance.titlePositionAdjustment = model.titleOffset ?? .zero - appearance.shadowColor = model.line?.backgroundColor?.uiColor ?? .clear + if let type = model.line?.type, + type != .none, + let color = model.line?.backgroundColor { + appearance.shadowColor = color.uiColor + } else { + appearance.shadowColor = .clear + } appearance.shadowImage = getNavigationBarShadowImage(for: model)?.withRenderingMode(.alwaysTemplate) navigationBar.standardAppearance = appearance navigationBar.scrollEdgeAppearance = appearance diff --git a/MVMCoreUI/Containers/Views/Container.swift b/MVMCoreUI/Containers/Views/Container.swift index 32c22b54..281f8d1b 100644 --- a/MVMCoreUI/Containers/Views/Container.swift +++ b/MVMCoreUI/Containers/Views/Container.swift @@ -31,6 +31,11 @@ open class Container: View, ContainerProtocol { guard let containerModel = model as? ContainerModelProtocol else { return } containerHelper.set(with: containerModel, for: view as? MVMCoreUIViewConstrainingProtocol) + if let cornerRadius = (containerModel as? ContainerModel)?.cornerRadius { + layer.cornerRadius = cornerRadius + } else { + layer.cornerRadius = 0 + } } override open func reset() { diff --git a/MVMCoreUI/Containers/Views/ContainerModel.swift b/MVMCoreUI/Containers/Views/ContainerModel.swift index caa949df..731e9c95 100644 --- a/MVMCoreUI/Containers/Views/ContainerModel.swift +++ b/MVMCoreUI/Containers/Views/ContainerModel.swift @@ -23,6 +23,8 @@ open class ContainerModel: ContainerModelProtocol, Codable { public var topPadding: CGFloat? public var bottomPadding: CGFloat? + public var cornerRadius: CGFloat? + //-------------------------------------------------- // MARK: - Keys //-------------------------------------------------- @@ -36,6 +38,7 @@ open class ContainerModel: ContainerModelProtocol, Codable { case useVerticalMargins case topPadding case bottomPadding + case cornerRadius } //-------------------------------------------------- @@ -83,6 +86,7 @@ open class ContainerModel: ContainerModelProtocol, Codable { useVerticalMargins = try typeContainer.decodeIfPresent(Bool.self, forKey: .useVerticalMargins) topPadding = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .topPadding) bottomPadding = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .bottomPadding) + cornerRadius = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .cornerRadius) setDefaults() } @@ -96,5 +100,6 @@ open class ContainerModel: ContainerModelProtocol, Codable { try container.encodeIfPresent(useVerticalMargins, forKey: .useVerticalMargins) try container.encodeIfPresent(topPadding, forKey: .topPadding) try container.encodeIfPresent(bottomPadding, forKey: .bottomPadding) + try container.encodeIfPresent(cornerRadius, forKey: .cornerRadius) } } diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIViewControllerMappingObject+Extension.swift b/MVMCoreUI/OtherHandlers/MVMCoreUIViewControllerMappingObject+Extension.swift index f126799c..34525751 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIViewControllerMappingObject+Extension.swift +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIViewControllerMappingObject+Extension.swift @@ -19,6 +19,7 @@ public extension MVMCoreUIViewControllerMappingObject { add(toTemplateViewControllerMapping: ["modalStack": MVMCoreViewControllerProgrammaticMappingObject(with: ModalMoleculeStackTemplate.self)!]) register(template: MoleculeListTemplate.self) + register(template: CollectionTemplate.self) add(toTemplateViewControllerMapping: ["modalList": MVMCoreViewControllerProgrammaticMappingObject(with: ModalMoleculeListTemplate.self)!]) add(toTemplateViewControllerMapping: [SectionListTemplateModel.identifier: MVMCoreViewControllerProgrammaticMappingObject(with: SectionListTemplate.self)!]) add(toTemplateViewControllerMapping: [ModalSectionListTemplateModel.identifier: MVMCoreViewControllerProgrammaticMappingObject(with: ModalSectionListTemplate.self)!]) diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/Contents.json b/MVMCoreUI/SupportingFiles/Media.xcassets/Contents.json index da4a164c..73c00596 100644 --- a/MVMCoreUI/SupportingFiles/Media.xcassets/Contents.json +++ b/MVMCoreUI/SupportingFiles/Media.xcassets/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +}