From ba84d2780dfac5e09d57f353d492b1de9f10ab36 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 24 Jun 2019 10:48:28 -0400 Subject: [PATCH 01/62] Added standardlistitem. --- MVMCoreUI.xcodeproj/project.pbxproj | 4 + .../Views/StandardListItemWithImage.swift | 146 ++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index d45f3185..24108276 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */; }; 01DF567021FA5AB300CC099B /* TextFieldListFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */; }; 01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; }; + 0A1214A022C11A18007C7030 /* StandardListItemWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* StandardListItemWithImage.swift */; }; B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; }; B8200E192281DC1A007245F4 /* ProgressBarWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */; }; D206997721FB8A0B00CAE0DE /* MVMCoreUINavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -186,6 +187,7 @@ 01CA51B4229716F60071A6EE /* Switch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Switch.swift; sourceTree = ""; }; 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = ""; }; 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = ""; }; + 0A12149F22C11A17007C7030 /* StandardListItemWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StandardListItemWithImage.swift; sourceTree = ""; }; B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarWithLabel.swift; sourceTree = ""; }; D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUINavigationController.h; sourceTree = ""; }; @@ -620,6 +622,7 @@ D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */, DBC4391C2245232D001AB423 /* LabelWithInternalButton.swift */, DB891E822253FA8500022516 /* Label.swift */, + 0A12149F22C11A17007C7030 /* StandardListItemWithImage.swift */, 0198F7A02256A80A0066C936 /* MFRadioButton.h */, 0198F7A22256A80A0066C936 /* MFRadioButton.m */, ); @@ -975,6 +978,7 @@ D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */, D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */, 0105618E224BBE7700E1557D /* FormValidator+TextFields.swift in Sources */, + 0A1214A022C11A18007C7030 /* StandardListItemWithImage.swift in Sources */, D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */, D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */, D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */, diff --git a/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift b/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift new file mode 100644 index 00000000..69062ea1 --- /dev/null +++ b/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift @@ -0,0 +1,146 @@ +// +// StandardListItemWithImage.swift +// MVMCoreUI +// +// Created by Christiano, Kevin on 6/20/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + + +@objcMembers open class StandardListItemWithImage: ViewConstrainingView { + //------------------------------------------------------ + // MARK: - Outlets + //------------------------------------------------------ + + let title = Label.commonLabelH3(true) + let message = Label.commonLabelB3(true) + let button = ButtonView(frame: .zero) + let imageloader = MFLoadImageView() + let leftContainer = ViewConstrainingView.empty() + + //------------------------------------------------------ + // MARK: - Constraints + //------------------------------------------------------ + + //------------------------------------------------------ + // MARK: - Initialization + //------------------------------------------------------ + + public init() { + super.init(frame: .zero) + } + + public override init(frame: CGRect) { + super.init(frame: frame) + } + + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + public convenience init(json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { + self.init() + setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + } + + //------------------------------------------------------ + // MARK: - View Lifecycle + //------------------------------------------------------ + + override open func setupView() { + super.setupView() + + guard subviews.isEmpty else { return } + + addSubview(leftContainer) + leftContainer.addSubview(title) + leftContainer.addSubview(message) + leftContainer.addSubview(button) + addSubview(imageloader) + + imageloader.translatesAutoresizingMaskIntoConstraints = false + button.translatesAutoresizingMaskIntoConstraints = false + + imageloader.imageView.contentMode = .scaleAspectFit + + leftContainer.topAnchor.constraint(equalTo: topAnchor).isActive = true + leftContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true + + let leftContainerBottom = leftContainer.bottomAnchor.constraint(equalTo: bottomAnchor) + leftContainerBottom.priority = UILayoutPriority(249) + leftContainerBottom.isActive = true + + bottomAnchor.constraint(greaterThanOrEqualTo: leftContainer.bottomAnchor).isActive = true + + title.topAnchor.constraint(equalTo: topAnchor).isActive = true + title.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true + + title.widthAnchor.constraint(equalTo: leftContainer.widthAnchor).isActive = true + + message.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 6).isActive = true + message.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true + + message.widthAnchor.constraint(equalTo: leftContainer.widthAnchor).isActive = true + + imageloader.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + layoutMarginsGuide.trailingAnchor.constraint(equalTo: imageloader.trailingAnchor).isActive = true + imageloader.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true + + let imageloaderBottom = imageloader.bottomAnchor.constraint(equalTo: bottomAnchor) + imageloaderBottom.priority = UILayoutPriority(249) + imageloaderBottom.isActive = true + + bottomAnchor.constraint(greaterThanOrEqualTo: imageloader.bottomAnchor).isActive = true + + imageloader.leadingAnchor.constraint(equalTo: leftContainer.trailingAnchor, constant: 16).isActive = true + + button.topAnchor.constraint(equalTo: message.bottomAnchor, constant: 12).isActive = true + button.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true + + title.setContentHuggingPriority(UILayoutPriority(rawValue: 901), for: .horizontal) + message.setContentHuggingPriority(UILayoutPriority(rawValue: 902), for: .horizontal) + + title.setContentHuggingPriority(.required, for: .vertical) + message.setContentHuggingPriority(.required, for: .vertical) + + title.setContentCompressionResistancePriority(.required, for: .vertical) + message.setContentCompressionResistancePriority(.required, for: .vertical) + } + + override open func updateView(_ size: CGFloat) { + super.updateView(size) + } + + override open func reset() { + super.reset() + + title.text = "" + message.text = "" + imageloader.imageView.image = nil + backgroundColor = nil + } + + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { + super.setWithJSON(json, delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData) + + guard let dictionary = json else { return } + + title.setWithJSON(dictionary.optionalDictionaryForKey("title"), delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData) + message.setWithJSON(dictionary.optionalDictionaryForKey("message"), delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData) + button.setWithJSON(dictionary.optionalDictionaryForKey("button"), delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData) + imageloader.setWithJSON(dictionary.optionalDictionaryForKey("imageView"), delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData) + + if let imageJSON = dictionary.optionalDictionaryForKey("imageView") { + imageloader.loadImage(withName: imageJSON.optionalStringForKey("image"), + format: imageJSON.optionalStringForKey("imageFormat"), + width: imageJSON.int32ForKey("imageWidth") as NSNumber, + height: imageJSON.int32ForKey("imageHeight") as NSNumber) + } + + if let backgroundColorHex = dictionary[KeyBackgroundColor] as? String { + backgroundColor = UIColor.mfGet(forHex: backgroundColorHex) + } + } +} From 569ae1481c5c78d002bde22831e4daf5786989d6 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 24 Jun 2019 16:04:06 -0400 Subject: [PATCH 02/62] latest iteration. --- .../Views/StandardListItemWithImage.swift | 28 ++++++++++--------- .../MVMCoreUIMoleculeMappingObject.m | 3 +- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift b/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift index 69062ea1..83ab4498 100644 --- a/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift +++ b/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift @@ -16,14 +16,10 @@ import UIKit let title = Label.commonLabelH3(true) let message = Label.commonLabelB3(true) - let button = ButtonView(frame: .zero) + let button = PrimaryButton.primaryTinyButton(false)! let imageloader = MFLoadImageView() let leftContainer = ViewConstrainingView.empty() - //------------------------------------------------------ - // MARK: - Constraints - //------------------------------------------------------ - //------------------------------------------------------ // MARK: - Initialization //------------------------------------------------------ @@ -54,17 +50,18 @@ import UIKit guard subviews.isEmpty else { return } + button.setAsSecondaryCustom() + addSubview(leftContainer) leftContainer.addSubview(title) leftContainer.addSubview(message) leftContainer.addSubview(button) addSubview(imageloader) + imageloader.imageView.contentMode = .scaleAspectFit imageloader.translatesAutoresizingMaskIntoConstraints = false button.translatesAutoresizingMaskIntoConstraints = false - imageloader.imageView.contentMode = .scaleAspectFit - leftContainer.topAnchor.constraint(equalTo: topAnchor).isActive = true leftContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true @@ -76,28 +73,25 @@ import UIKit title.topAnchor.constraint(equalTo: topAnchor).isActive = true title.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true - title.widthAnchor.constraint(equalTo: leftContainer.widthAnchor).isActive = true message.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 6).isActive = true message.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true - message.widthAnchor.constraint(equalTo: leftContainer.widthAnchor).isActive = true imageloader.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true layoutMarginsGuide.trailingAnchor.constraint(equalTo: imageloader.trailingAnchor).isActive = true imageloader.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true + imageloader.leadingAnchor.constraint(equalTo: leftContainer.trailingAnchor, constant: 16).isActive = true + bottomAnchor.constraint(greaterThanOrEqualTo: imageloader.bottomAnchor).isActive = true let imageloaderBottom = imageloader.bottomAnchor.constraint(equalTo: bottomAnchor) imageloaderBottom.priority = UILayoutPriority(249) imageloaderBottom.isActive = true - bottomAnchor.constraint(greaterThanOrEqualTo: imageloader.bottomAnchor).isActive = true - - imageloader.leadingAnchor.constraint(equalTo: leftContainer.trailingAnchor, constant: 16).isActive = true - button.topAnchor.constraint(equalTo: message.bottomAnchor, constant: 12).isActive = true button.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true + button.bottomAnchor.constraint(equalTo: leftContainer.bottomAnchor).isActive = true title.setContentHuggingPriority(UILayoutPriority(rawValue: 901), for: .horizontal) message.setContentHuggingPriority(UILayoutPriority(rawValue: 902), for: .horizontal) @@ -107,10 +101,18 @@ import UIKit title.setContentCompressionResistancePriority(.required, for: .vertical) message.setContentCompressionResistancePriority(.required, for: .vertical) + + imageloader.imageView.setContentCompressionResistancePriority(.required, for: .vertical) } override open func updateView(_ size: CGFloat) { super.updateView(size) + + title.updateView(size) + message.updateView(size) + button.updateView(size) + imageloader.updateView(size) + leftContainer.updateView(size) } override open func reset() { diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index ebac9da4..0e8a8e77 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -43,7 +43,8 @@ @"listItem": MoleculeTableViewCell.class, @"switchLineItem": SwitchLineItem.class, @"switch": Switch.class, - @"leftRightLabelView": LeftRightLabelView.class + @"leftRightLabelView": LeftRightLabelView.class, + @"standardListItemWithImage": StandardListItemWithImage.class } mutableCopy]; }); return mapping; From dbeb5156c5e47602a162fe629a4a6ac3aa0a9cbf Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 26 Jun 2019 14:49:01 -0400 Subject: [PATCH 03/62] StandardListItemWithImage assembled. --- .../Views/StandardListItemWithImage.swift | 65 ++++++++++++------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift b/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift index 83ab4498..f35249ef 100644 --- a/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift +++ b/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift @@ -20,6 +20,14 @@ import UIKit let imageloader = MFLoadImageView() let leftContainer = ViewConstrainingView.empty() + //------------------------------------------------------ + // MARK: - Constraints + //------------------------------------------------------ + + var imageWidthConstraint: NSLayoutConstraint? + var imageHeightConstraint: NSLayoutConstraint? + var buttonTopConstraint: NSLayoutConstraint? + //------------------------------------------------------ // MARK: - Initialization //------------------------------------------------------ @@ -52,57 +60,59 @@ import UIKit button.setAsSecondaryCustom() + imageloader.imageView.contentMode = .scaleAspectFit + addSubview(leftContainer) + addSubview(imageloader) leftContainer.addSubview(title) leftContainer.addSubview(message) leftContainer.addSubview(button) - addSubview(imageloader) - - imageloader.imageView.contentMode = .scaleAspectFit - imageloader.translatesAutoresizingMaskIntoConstraints = false - button.translatesAutoresizingMaskIntoConstraints = false leftContainer.topAnchor.constraint(equalTo: topAnchor).isActive = true leftContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true + bottomAnchor.constraint(greaterThanOrEqualTo: leftContainer.bottomAnchor).isActive = true let leftContainerBottom = leftContainer.bottomAnchor.constraint(equalTo: bottomAnchor) leftContainerBottom.priority = UILayoutPriority(249) leftContainerBottom.isActive = true - bottomAnchor.constraint(greaterThanOrEqualTo: leftContainer.bottomAnchor).isActive = true - - title.topAnchor.constraint(equalTo: topAnchor).isActive = true + title.topAnchor.constraint(equalTo: leftContainer.topAnchor).isActive = true title.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true + title.trailingAnchor.constraint(equalTo: leftContainer.trailingAnchor).isActive = true title.widthAnchor.constraint(equalTo: leftContainer.widthAnchor).isActive = true - message.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 6).isActive = true + message.topAnchor.constraint(equalTo: title.bottomAnchor, constant: PaddingOne).isActive = true message.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true + message.trailingAnchor.constraint(equalTo: leftContainer.trailingAnchor).isActive = true message.widthAnchor.constraint(equalTo: leftContainer.widthAnchor).isActive = true + buttonTopConstraint = button.topAnchor.constraint(equalTo: message.bottomAnchor, constant: PaddingTwo) + buttonTopConstraint?.isActive = true + + button.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true + button.bottomAnchor.constraint(equalTo: leftContainer.bottomAnchor).isActive = true + leftContainer.trailingAnchor.constraint(greaterThanOrEqualTo: button.trailingAnchor).isActive = true + imageloader.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true layoutMarginsGuide.trailingAnchor.constraint(equalTo: imageloader.trailingAnchor).isActive = true - imageloader.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true imageloader.leadingAnchor.constraint(equalTo: leftContainer.trailingAnchor, constant: 16).isActive = true + imageHeightConstraint = imageloader.heightAnchor.constraint(equalToConstant: 0) + imageHeightConstraint?.isActive = true + + imageWidthConstraint = imageloader.widthAnchor.constraint(equalToConstant: 0) + imageWidthConstraint?.isActive = true + bottomAnchor.constraint(greaterThanOrEqualTo: imageloader.bottomAnchor).isActive = true let imageloaderBottom = imageloader.bottomAnchor.constraint(equalTo: bottomAnchor) imageloaderBottom.priority = UILayoutPriority(249) imageloaderBottom.isActive = true - button.topAnchor.constraint(equalTo: message.bottomAnchor, constant: 12).isActive = true - button.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true - button.bottomAnchor.constraint(equalTo: leftContainer.bottomAnchor).isActive = true - - title.setContentHuggingPriority(UILayoutPriority(rawValue: 901), for: .horizontal) - message.setContentHuggingPriority(UILayoutPriority(rawValue: 902), for: .horizontal) + title.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 901), for: .horizontal) + message.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 902), for: .horizontal) title.setContentHuggingPriority(.required, for: .vertical) message.setContentHuggingPriority(.required, for: .vertical) - - title.setContentCompressionResistancePriority(.required, for: .vertical) - message.setContentCompressionResistancePriority(.required, for: .vertical) - - imageloader.imageView.setContentCompressionResistancePriority(.required, for: .vertical) } override open func updateView(_ size: CGFloat) { @@ -113,6 +123,8 @@ import UIKit button.updateView(size) imageloader.updateView(size) leftContainer.updateView(size) + + buttonTopConstraint?.constant = message.hasText ? PaddingTwo : PaddingOne } override open func reset() { @@ -121,6 +133,7 @@ import UIKit title.text = "" message.text = "" imageloader.imageView.image = nil + imageWidthConstraint?.constant = 0 backgroundColor = nil } @@ -135,10 +148,16 @@ import UIKit imageloader.setWithJSON(dictionary.optionalDictionaryForKey("imageView"), delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData) if let imageJSON = dictionary.optionalDictionaryForKey("imageView") { + let width = CGFloat(imageJSON.floatForKey("width")) + let height = CGFloat(imageJSON.floatForKey("height")) + imageloader.loadImage(withName: imageJSON.optionalStringForKey("image"), format: imageJSON.optionalStringForKey("imageFormat"), - width: imageJSON.int32ForKey("imageWidth") as NSNumber, - height: imageJSON.int32ForKey("imageHeight") as NSNumber) + width: width as NSNumber, + height: height as NSNumber) + + imageWidthConstraint?.constant = width + imageHeightConstraint?.constant = height } if let backgroundColorHex = dictionary[KeyBackgroundColor] as? String { From b821250042b46d4a53a88be4d7b7d7c0595fc6de Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 1 Jul 2019 12:28:28 -0400 Subject: [PATCH 04/62] improvements made. --- .../Views/StandardListItemWithImage.swift | 54 +++++++++---------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift b/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift index f35249ef..7300daa2 100644 --- a/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift +++ b/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift @@ -27,6 +27,7 @@ import UIKit var imageWidthConstraint: NSLayoutConstraint? var imageHeightConstraint: NSLayoutConstraint? var buttonTopConstraint: NSLayoutConstraint? + var messageTopConstraint: NSLayoutConstraint? //------------------------------------------------------ // MARK: - Initialization @@ -44,7 +45,7 @@ import UIKit super.init(coder: aDecoder) } - public convenience init(json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { + public convenience init(json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { self.init() setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) } @@ -79,12 +80,12 @@ import UIKit title.topAnchor.constraint(equalTo: leftContainer.topAnchor).isActive = true title.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true title.trailingAnchor.constraint(equalTo: leftContainer.trailingAnchor).isActive = true - title.widthAnchor.constraint(equalTo: leftContainer.widthAnchor).isActive = true - message.topAnchor.constraint(equalTo: title.bottomAnchor, constant: PaddingOne).isActive = true + messageTopConstraint = message.topAnchor.constraint(equalTo: title.bottomAnchor, constant: PaddingOne) + messageTopConstraint?.isActive = true + message.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true message.trailingAnchor.constraint(equalTo: leftContainer.trailingAnchor).isActive = true - message.widthAnchor.constraint(equalTo: leftContainer.widthAnchor).isActive = true buttonTopConstraint = button.topAnchor.constraint(equalTo: message.bottomAnchor, constant: PaddingTwo) buttonTopConstraint?.isActive = true @@ -96,10 +97,11 @@ import UIKit imageloader.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true layoutMarginsGuide.trailingAnchor.constraint(equalTo: imageloader.trailingAnchor).isActive = true imageloader.leadingAnchor.constraint(equalTo: leftContainer.trailingAnchor, constant: 16).isActive = true + imageloader.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true imageHeightConstraint = imageloader.heightAnchor.constraint(equalToConstant: 0) imageHeightConstraint?.isActive = true - + imageWidthConstraint = imageloader.widthAnchor.constraint(equalToConstant: 0) imageWidthConstraint?.isActive = true @@ -107,7 +109,7 @@ import UIKit let imageloaderBottom = imageloader.bottomAnchor.constraint(equalTo: bottomAnchor) imageloaderBottom.priority = UILayoutPriority(249) imageloaderBottom.isActive = true - + title.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 901), for: .horizontal) message.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 902), for: .horizontal) @@ -124,7 +126,15 @@ import UIKit imageloader.updateView(size) leftContainer.updateView(size) - buttonTopConstraint?.constant = message.hasText ? PaddingTwo : PaddingOne + messageTopConstraint?.constant = title.hasText ? PaddingOne : 0 + + if message.hasText { + buttonTopConstraint?.constant = PaddingTwo + } else if title.hasText { + buttonTopConstraint?.constant = PaddingOne + } else { + buttonTopConstraint?.constant = 0 + } } override open func reset() { @@ -137,31 +147,19 @@ import UIKit backgroundColor = nil } - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData) + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) guard let dictionary = json else { return } - title.setWithJSON(dictionary.optionalDictionaryForKey("title"), delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData) - message.setWithJSON(dictionary.optionalDictionaryForKey("message"), delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData) - button.setWithJSON(dictionary.optionalDictionaryForKey("button"), delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData) - imageloader.setWithJSON(dictionary.optionalDictionaryForKey("imageView"), delegateObject: delegateObject as? MVMCoreUIDelegateObject, additionalData: additionalData) + title.setWithJSON(dictionary.optionalDictionaryForKey("title"), delegateObject: delegateObject, additionalData: additionalData) + message.setWithJSON(dictionary.optionalDictionaryForKey("message"), delegateObject: delegateObject, additionalData: additionalData) + button.setWithJSON(dictionary.optionalDictionaryForKey("button"), delegateObject: delegateObject, additionalData: additionalData) + imageloader.setWithJSON(dictionary.optionalDictionaryForKey("image"), delegateObject: delegateObject, additionalData: additionalData) - if let imageJSON = dictionary.optionalDictionaryForKey("imageView") { - let width = CGFloat(imageJSON.floatForKey("width")) - let height = CGFloat(imageJSON.floatForKey("height")) - - imageloader.loadImage(withName: imageJSON.optionalStringForKey("image"), - format: imageJSON.optionalStringForKey("imageFormat"), - width: width as NSNumber, - height: height as NSNumber) - - imageWidthConstraint?.constant = width - imageHeightConstraint?.constant = height - } - - if let backgroundColorHex = dictionary[KeyBackgroundColor] as? String { - backgroundColor = UIColor.mfGet(forHex: backgroundColorHex) + if let imageJSON = dictionary.optionalDictionaryForKey("image") { + imageWidthConstraint?.constant = CGFloat(imageJSON.floatForKey("width")) + imageHeightConstraint?.constant = CGFloat(imageJSON.floatForKey("height")) } } } From ada34f6f13c19fa15d2fe06665f310176aaec60d Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 1 Jul 2019 13:16:14 -0400 Subject: [PATCH 05/62] condensed constraint command. --- MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift b/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift index 7300daa2..1c65b0bd 100644 --- a/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift +++ b/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift @@ -127,14 +127,7 @@ import UIKit leftContainer.updateView(size) messageTopConstraint?.constant = title.hasText ? PaddingOne : 0 - - if message.hasText { - buttonTopConstraint?.constant = PaddingTwo - } else if title.hasText { - buttonTopConstraint?.constant = PaddingOne - } else { - buttonTopConstraint?.constant = 0 - } + buttonTopConstraint?.constant = message.hasText ? PaddingTwo : (title.hasText ? PaddingOne : 0) } override open func reset() { From 033cf878a656abe1538d4f59e079e1207125d9ec Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 3 Jul 2019 13:18:27 -0400 Subject: [PATCH 06/62] carousel --- MVMCoreUI.xcodeproj/project.pbxproj | 8 ++ MVMCoreUI/Molecules/Carousel.swift | 128 ++++++++++++++++++ .../MoleculeCollectionViewCell.swift | 65 +++++++++ .../MVMCoreUIMoleculeMappingObject.m | 4 +- 4 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 MVMCoreUI/Molecules/Carousel.swift create mode 100644 MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 04c2b811..afe89464 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -162,6 +162,8 @@ D2A514672213885800345BFB /* StandardHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A514662213885800345BFB /* StandardHeaderView.swift */; }; D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; }; D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A638FC22CA98280052ED1F /* HeadlineBody.swift */; }; + D2A6390122CBB1820052ED1F /* Carousel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A6390022CBB1820052ED1F /* Carousel.swift */; }; + D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */; }; D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */; }; D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */; }; @@ -335,6 +337,8 @@ D2A514662213885800345BFB /* StandardHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardHeaderView.swift; sourceTree = ""; }; D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerViewController.swift; sourceTree = ""; }; D2A638FC22CA98280052ED1F /* HeadlineBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBody.swift; sourceTree = ""; }; + D2A6390022CBB1820052ED1F /* Carousel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Carousel.swift; sourceTree = ""; }; + D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeCollectionViewCell.swift; sourceTree = ""; }; D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewControllerMappingObject.h; sourceTree = ""; }; D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIViewControllerMappingObject.m; sourceTree = ""; }; D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIDelegateObject.swift; sourceTree = ""; }; @@ -475,6 +479,8 @@ B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */, D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */, D2A638FC22CA98280052ED1F /* HeadlineBody.swift */, + D2A6390022CBB1820052ED1F /* Carousel.swift */, + D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */, ); path = Molecules; sourceTree = ""; @@ -951,6 +957,8 @@ 01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */, D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */, D29DF2C921E7BFC6003B2FB9 /* MFSizeObject.m in Sources */, + D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */, + D2A6390122CBB1820052ED1F /* Carousel.swift in Sources */, D29DF2C721E7BF57003B2FB9 /* MFTabBarInteractor.m in Sources */, 016A1071228122180009D605 /* SwitchLineItem.swift in Sources */, D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */, diff --git a/MVMCoreUI/Molecules/Carousel.swift b/MVMCoreUI/Molecules/Carousel.swift new file mode 100644 index 00000000..3333855b --- /dev/null +++ b/MVMCoreUI/Molecules/Carousel.swift @@ -0,0 +1,128 @@ +// +// Carousel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 7/2/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +open class Carousel: ViewConstrainingView { + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) + var currentIndex = 1 + var numberOfCards = 0 + var molecules: [[AnyHashable : Any]]? + + var collectionViewHeight: NSLayoutConstraint? + + open override func setupView() { + super.setupView() + guard collectionView.superview == nil else { + return + } + collectionView.translatesAutoresizingMaskIntoConstraints = false + collectionView.dataSource = self + collectionView.delegate = self + collectionView.showsHorizontalScrollIndicator = false + collectionView.backgroundColor = .clear + addSubview(collectionView) + pinView(toSuperView: collectionView) + + collectionViewHeight = collectionView.heightAnchor.constraint(equalToConstant: 300) + collectionViewHeight?.isActive = true + } + + /// Registers the cells with the collection view + func registerCells(with json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) { + if let molecules = json?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] { + for molecule in molecules { + if let info = getMoleculeInfo(with: molecule, delegateObject: delegateObject) { + collectionView.register(info.class, forCellWithReuseIdentifier: info.identifier) + } + } + } + } + + /// Updates the layout being used + func setupLayout(with json:[AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .horizontal + layout.minimumLineSpacing = json?["spacing"] as? CGFloat ?? 0 + layout.minimumInteritemSpacing = 0 + //layout.itemSize = CGSize(width: 300, height: 200) + collectionView.collectionViewLayout = layout + } + + func prepareMolecules(_ json: [AnyHashable : Any]?) { + guard let newMolecules = json?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] else { + numberOfCards = 0 + molecules = nil + return + } + + numberOfCards = newMolecules.count + molecules = newMolecules + if json?.boolForKey("loop") ?? false && newMolecules.count > 2 { + // Sets up the row data with a buffer cell on each side (for illusion of endless scroll... also has one more buffer cell on right since we can peek that cell). + molecules?.insert(newMolecules.last!, at: 0) + molecules?.append(newMolecules.first!) + molecules?.append(newMolecules[1]) + } + } + + open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + + collectionViewHeight?.constant = json?.optionalCGFloatForKey("height") ?? 300 + + registerCells(with: json, delegateObject: delegateObject) + setupLayout(with: json, delegateObject: delegateObject) + prepareMolecules(json) + collectionView.reloadData() + + // Go to starting cell. layoutIfNeeded is needed otherwise cellForItem returns nil for peaking logic. + collectionView.scrollToItem(at: IndexPath(row: currentIndex, section: 0), at: .left, animated: false) + collectionView.layoutIfNeeded() + } + + open override func setAsMolecule() { + super.setAsMolecule() + updateViewHorizontalDefaults = false + } + + // MARK: - Convenience + /// Returns the (identifier, class) of the molecule for the given map. + func getMoleculeInfo(with molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> (identifier: String, class: AnyClass, molecule: [AnyHashable: Any])? { + guard let molecule = molecule, + let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule), + let moleculeName = moleculeClass.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) else { + return nil + } + return (moleculeName, moleculeClass, molecule) + } +} + +extension Carousel: UICollectionViewDelegate { + +} + +extension Carousel: UICollectionViewDataSource { + public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return molecules?.count ?? 0 + } + + public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let molecule = molecules?[indexPath.row], + let moleculeInfo = getMoleculeInfo(with: molecule, delegateObject: nil) else { + return UICollectionViewCell() + } + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: moleculeInfo.identifier, for: indexPath) + if let protocolCell = cell as? MVMCoreUIMoleculeViewProtocol { + protocolCell.reset?() + protocolCell.setWithJSON(moleculeInfo.molecule, delegateObject: nil, additionalData: nil) + protocolCell.updateView(collectionView.bounds.width) + } + return cell + } +} diff --git a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift new file mode 100644 index 00000000..d28819ac --- /dev/null +++ b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift @@ -0,0 +1,65 @@ +// +// MoleculeCollectionViewCell.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 7/2/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol { + open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)? + + public override init(frame: CGRect) { + super.init(frame: .zero) + setupView() + } + + public required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setupView() + } + + public func setupView() { + } + + public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { + return + } + if molecule == nil { + if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) { + contentView.addSubview(moleculeView) + let standardConstraints = (moleculeView as? MVMCoreUIViewConstrainingProtocol)?.useStandardConstraints?() ?? true + NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: standardConstraints).values)) + if standardConstraints { + let constraint = contentView.heightAnchor.constraint(equalToConstant: 80) + constraint.priority = .defaultLow + constraint.isActive = true + } + molecule = moleculeView + } + } else { + molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) + } + if let castView = molecule as? MVMCoreUIViewConstrainingProtocol { + let standardConstraints = castView.useStandardConstraints?() ?? true + castView.shouldSetHorizontalMargins?(!standardConstraints) + castView.shouldSetVerticalMargins?(!standardConstraints) + } + + backgroundColor = molecule?.backgroundColor + } + + public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { + guard let molecule = molecule?.optionalDictionaryForKey(KeyMolecule) else { + return nil + } + return MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) + } + + public func updateView(_ size: CGFloat) { + + } +} diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 67279c6e..61230208 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -48,7 +48,9 @@ @"image": MFLoadImageView.class, @"leftRightLabelView": LeftRightLabelView.class, @"moduleMolecule": ModuleMolecule.class, - @"headlineBody": HeadlineBody.class + @"headlineBody": HeadlineBody.class, + @"carousel": Carousel.class, + @"carouselItem": MoleculeCollectionViewCell.class } mutableCopy]; }); return mapping; From ce1a8c3598e9e236895739a60440ea72487d619b Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 8 Jul 2019 10:36:34 -0400 Subject: [PATCH 07/62] Renamed to comply with MFAtom design doc. --- MVMCoreUI.xcodeproj/project.pbxproj | 8 +- MVMCoreUI/Atoms/Views/ListItemWithImage.swift | 152 ++++++++++++++++++ .../MVMCoreUIMoleculeMappingObject.m | 2 +- 3 files changed, 157 insertions(+), 5 deletions(-) create mode 100644 MVMCoreUI/Atoms/Views/ListItemWithImage.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index ca3ea276..1f21b44e 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -18,7 +18,7 @@ 01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */; }; 01DF567021FA5AB300CC099B /* TextFieldListFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */; }; 01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; }; - 0A1214A022C11A18007C7030 /* StandardListItemWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* StandardListItemWithImage.swift */; }; + 0A1214A022C11A18007C7030 /* ListItemWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ListItemWithImage.swift */; }; B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; }; B8200E192281DC1A007245F4 /* ProgressBarWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */; }; D206997721FB8A0B00CAE0DE /* MVMCoreUINavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -187,7 +187,7 @@ 01CA51B4229716F60071A6EE /* Switch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Switch.swift; sourceTree = ""; }; 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = ""; }; 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = ""; }; - 0A12149F22C11A17007C7030 /* StandardListItemWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StandardListItemWithImage.swift; sourceTree = ""; }; + 0A12149F22C11A17007C7030 /* ListItemWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListItemWithImage.swift; sourceTree = ""; }; B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarWithLabel.swift; sourceTree = ""; }; D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUINavigationController.h; sourceTree = ""; }; @@ -623,7 +623,7 @@ D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */, DBC4391C2245232D001AB423 /* LabelWithInternalButton.swift */, DB891E822253FA8500022516 /* Label.swift */, - 0A12149F22C11A17007C7030 /* StandardListItemWithImage.swift */, + 0A12149F22C11A17007C7030 /* ListItemWithImage.swift */, 0198F7A02256A80A0066C936 /* MFRadioButton.h */, 0198F7A22256A80A0066C936 /* MFRadioButton.m */, ); @@ -978,7 +978,7 @@ D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */, D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */, 0105618E224BBE7700E1557D /* FormValidator+TextFields.swift in Sources */, - 0A1214A022C11A18007C7030 /* StandardListItemWithImage.swift in Sources */, + 0A1214A022C11A18007C7030 /* ListItemWithImage.swift in Sources */, D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */, D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */, D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */, diff --git a/MVMCoreUI/Atoms/Views/ListItemWithImage.swift b/MVMCoreUI/Atoms/Views/ListItemWithImage.swift new file mode 100644 index 00000000..dfd80aef --- /dev/null +++ b/MVMCoreUI/Atoms/Views/ListItemWithImage.swift @@ -0,0 +1,152 @@ +// +// StandardListItemWithImage.swift +// MVMCoreUI +// +// Created by Christiano, Kevin on 6/20/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + + +@objcMembers open class ListItemWithImage: ViewConstrainingView { + //------------------------------------------------------ + // MARK: - Outlets + //------------------------------------------------------ + + let title = Label.commonLabelH3(true) + let message = Label.commonLabelB3(true) + let button = PrimaryButton.primaryTinyButton(false)! + let imageloader = MFLoadImageView() + let leftContainer = ViewConstrainingView.empty() + + //------------------------------------------------------ + // MARK: - Constraints + //------------------------------------------------------ + + var imageWidthConstraint: NSLayoutConstraint? + var imageHeightConstraint: NSLayoutConstraint? + var buttonTopConstraint: NSLayoutConstraint? + var messageTopConstraint: NSLayoutConstraint? + + //------------------------------------------------------ + // MARK: - Initialization + //------------------------------------------------------ + + public init() { + super.init(frame: .zero) + } + + public override init(frame: CGRect) { + super.init(frame: frame) + } + + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + public convenience init(json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + self.init() + setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + } + + //------------------------------------------------------ + // MARK: - View Lifecycle + //------------------------------------------------------ + + override open func setupView() { + super.setupView() + + guard subviews.isEmpty else { return } + + button.setAsSecondaryCustom() + + imageloader.imageView.contentMode = .scaleAspectFit + + addSubview(leftContainer) + addSubview(imageloader) + leftContainer.addSubview(title) + leftContainer.addSubview(message) + leftContainer.addSubview(button) + + leftContainer.topAnchor.constraint(equalTo: topAnchor).isActive = true + leftContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true + + bottomAnchor.constraint(greaterThanOrEqualTo: leftContainer.bottomAnchor).isActive = true + let leftContainerBottom = leftContainer.bottomAnchor.constraint(equalTo: bottomAnchor) + leftContainerBottom.priority = UILayoutPriority(249) + leftContainerBottom.isActive = true + + title.topAnchor.constraint(equalTo: leftContainer.topAnchor).isActive = true + title.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true + title.trailingAnchor.constraint(equalTo: leftContainer.trailingAnchor).isActive = true + + messageTopConstraint = message.topAnchor.constraint(equalTo: title.bottomAnchor, constant: PaddingOne) + messageTopConstraint?.isActive = true + + message.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true + message.trailingAnchor.constraint(equalTo: leftContainer.trailingAnchor).isActive = true + + buttonTopConstraint = button.topAnchor.constraint(equalTo: message.bottomAnchor, constant: PaddingTwo) + buttonTopConstraint?.isActive = true + + button.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true + button.bottomAnchor.constraint(equalTo: leftContainer.bottomAnchor).isActive = true + leftContainer.trailingAnchor.constraint(greaterThanOrEqualTo: button.trailingAnchor).isActive = true + + imageloader.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + layoutMarginsGuide.trailingAnchor.constraint(equalTo: imageloader.trailingAnchor).isActive = true + imageloader.leadingAnchor.constraint(equalTo: leftContainer.trailingAnchor, constant: 16).isActive = true + imageloader.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true + + imageHeightConstraint = imageloader.heightAnchor.constraint(equalToConstant: 0) + imageHeightConstraint?.isActive = true + + imageWidthConstraint = imageloader.widthAnchor.constraint(equalToConstant: 0) + imageWidthConstraint?.isActive = true + + bottomAnchor.constraint(greaterThanOrEqualTo: imageloader.bottomAnchor).isActive = true + let imageloaderBottom = imageloader.bottomAnchor.constraint(equalTo: bottomAnchor) + imageloaderBottom.priority = UILayoutPriority(249) + imageloaderBottom.isActive = true + } + + override open func updateView(_ size: CGFloat) { + super.updateView(size) + + title.updateView(size) + message.updateView(size) + button.updateView(size) + imageloader.updateView(size) + leftContainer.updateView(size) + + messageTopConstraint?.constant = title.hasText ? PaddingOne : 0 + buttonTopConstraint?.constant = message.hasText ? PaddingTwo : (title.hasText ? PaddingOne : 0) + } + + override open func reset() { + super.reset() + + title.text = "" + message.text = "" + imageloader.imageView.image = nil + imageWidthConstraint?.constant = 0 + backgroundColor = nil + } + + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + + guard let dictionary = json else { return } + + title.setWithJSON(dictionary.optionalDictionaryForKey("title"), delegateObject: delegateObject, additionalData: additionalData) + message.setWithJSON(dictionary.optionalDictionaryForKey("message"), delegateObject: delegateObject, additionalData: additionalData) + button.setWithJSON(dictionary.optionalDictionaryForKey("button"), delegateObject: delegateObject, additionalData: additionalData) + imageloader.setWithJSON(dictionary.optionalDictionaryForKey("image"), delegateObject: delegateObject, additionalData: additionalData) + + if let imageJSON = dictionary.optionalDictionaryForKey("image") { + imageWidthConstraint?.constant = CGFloat(imageJSON.floatForKey("width")) + imageHeightConstraint?.constant = CGFloat(imageJSON.floatForKey("height")) + } + } +} diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 7367fd42..b125f74d 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -46,7 +46,7 @@ @"switchLineItem": SwitchLineItem.class, @"switch": Switch.class, @"leftRightLabelView": LeftRightLabelView.class, - @"standardListItemWithImage": StandardListItemWithImage.class, + @"listItemWithImage": ListItemWithImage.class, @"image": MFLoadImageView.class, @"moduleMolecule": ModuleMolecule.class } mutableCopy]; From 1bfbe95b68a703a93df48ce3fb120be5307d772a Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 8 Jul 2019 10:36:56 -0400 Subject: [PATCH 08/62] updated file name. --- .../Views/StandardListItemWithImage.swift | 158 ------------------ 1 file changed, 158 deletions(-) delete mode 100644 MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift diff --git a/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift b/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift deleted file mode 100644 index 1c65b0bd..00000000 --- a/MVMCoreUI/Atoms/Views/StandardListItemWithImage.swift +++ /dev/null @@ -1,158 +0,0 @@ -// -// StandardListItemWithImage.swift -// MVMCoreUI -// -// Created by Christiano, Kevin on 6/20/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import UIKit - - -@objcMembers open class StandardListItemWithImage: ViewConstrainingView { - //------------------------------------------------------ - // MARK: - Outlets - //------------------------------------------------------ - - let title = Label.commonLabelH3(true) - let message = Label.commonLabelB3(true) - let button = PrimaryButton.primaryTinyButton(false)! - let imageloader = MFLoadImageView() - let leftContainer = ViewConstrainingView.empty() - - //------------------------------------------------------ - // MARK: - Constraints - //------------------------------------------------------ - - var imageWidthConstraint: NSLayoutConstraint? - var imageHeightConstraint: NSLayoutConstraint? - var buttonTopConstraint: NSLayoutConstraint? - var messageTopConstraint: NSLayoutConstraint? - - //------------------------------------------------------ - // MARK: - Initialization - //------------------------------------------------------ - - public init() { - super.init(frame: .zero) - } - - public override init(frame: CGRect) { - super.init(frame: frame) - } - - required public init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - } - - public convenience init(json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - self.init() - setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - } - - //------------------------------------------------------ - // MARK: - View Lifecycle - //------------------------------------------------------ - - override open func setupView() { - super.setupView() - - guard subviews.isEmpty else { return } - - button.setAsSecondaryCustom() - - imageloader.imageView.contentMode = .scaleAspectFit - - addSubview(leftContainer) - addSubview(imageloader) - leftContainer.addSubview(title) - leftContainer.addSubview(message) - leftContainer.addSubview(button) - - leftContainer.topAnchor.constraint(equalTo: topAnchor).isActive = true - leftContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true - - bottomAnchor.constraint(greaterThanOrEqualTo: leftContainer.bottomAnchor).isActive = true - let leftContainerBottom = leftContainer.bottomAnchor.constraint(equalTo: bottomAnchor) - leftContainerBottom.priority = UILayoutPriority(249) - leftContainerBottom.isActive = true - - title.topAnchor.constraint(equalTo: leftContainer.topAnchor).isActive = true - title.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true - title.trailingAnchor.constraint(equalTo: leftContainer.trailingAnchor).isActive = true - - messageTopConstraint = message.topAnchor.constraint(equalTo: title.bottomAnchor, constant: PaddingOne) - messageTopConstraint?.isActive = true - - message.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true - message.trailingAnchor.constraint(equalTo: leftContainer.trailingAnchor).isActive = true - - buttonTopConstraint = button.topAnchor.constraint(equalTo: message.bottomAnchor, constant: PaddingTwo) - buttonTopConstraint?.isActive = true - - button.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true - button.bottomAnchor.constraint(equalTo: leftContainer.bottomAnchor).isActive = true - leftContainer.trailingAnchor.constraint(greaterThanOrEqualTo: button.trailingAnchor).isActive = true - - imageloader.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true - layoutMarginsGuide.trailingAnchor.constraint(equalTo: imageloader.trailingAnchor).isActive = true - imageloader.leadingAnchor.constraint(equalTo: leftContainer.trailingAnchor, constant: 16).isActive = true - imageloader.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true - - imageHeightConstraint = imageloader.heightAnchor.constraint(equalToConstant: 0) - imageHeightConstraint?.isActive = true - - imageWidthConstraint = imageloader.widthAnchor.constraint(equalToConstant: 0) - imageWidthConstraint?.isActive = true - - bottomAnchor.constraint(greaterThanOrEqualTo: imageloader.bottomAnchor).isActive = true - let imageloaderBottom = imageloader.bottomAnchor.constraint(equalTo: bottomAnchor) - imageloaderBottom.priority = UILayoutPriority(249) - imageloaderBottom.isActive = true - - title.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 901), for: .horizontal) - message.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 902), for: .horizontal) - - title.setContentHuggingPriority(.required, for: .vertical) - message.setContentHuggingPriority(.required, for: .vertical) - } - - override open func updateView(_ size: CGFloat) { - super.updateView(size) - - title.updateView(size) - message.updateView(size) - button.updateView(size) - imageloader.updateView(size) - leftContainer.updateView(size) - - messageTopConstraint?.constant = title.hasText ? PaddingOne : 0 - buttonTopConstraint?.constant = message.hasText ? PaddingTwo : (title.hasText ? PaddingOne : 0) - } - - override open func reset() { - super.reset() - - title.text = "" - message.text = "" - imageloader.imageView.image = nil - imageWidthConstraint?.constant = 0 - backgroundColor = nil - } - - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - - guard let dictionary = json else { return } - - title.setWithJSON(dictionary.optionalDictionaryForKey("title"), delegateObject: delegateObject, additionalData: additionalData) - message.setWithJSON(dictionary.optionalDictionaryForKey("message"), delegateObject: delegateObject, additionalData: additionalData) - button.setWithJSON(dictionary.optionalDictionaryForKey("button"), delegateObject: delegateObject, additionalData: additionalData) - imageloader.setWithJSON(dictionary.optionalDictionaryForKey("image"), delegateObject: delegateObject, additionalData: additionalData) - - if let imageJSON = dictionary.optionalDictionaryForKey("image") { - imageWidthConstraint?.constant = CGFloat(imageJSON.floatForKey("width")) - imageHeightConstraint?.constant = CGFloat(imageJSON.floatForKey("height")) - } - } -} From ae7d757dbc2a8bdff3941eafc2e343506adf979e Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 9 Jul 2019 13:53:49 -0400 Subject: [PATCH 09/62] Updated variable name. removed padding if image is not there. --- MVMCoreUI/Atoms/Views/ListItemWithImage.swift | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/ListItemWithImage.swift b/MVMCoreUI/Atoms/Views/ListItemWithImage.swift index dfd80aef..dc0fc68a 100644 --- a/MVMCoreUI/Atoms/Views/ListItemWithImage.swift +++ b/MVMCoreUI/Atoms/Views/ListItemWithImage.swift @@ -17,7 +17,7 @@ import UIKit let title = Label.commonLabelH3(true) let message = Label.commonLabelB3(true) let button = PrimaryButton.primaryTinyButton(false)! - let imageloader = MFLoadImageView() + let imageLoader = MFLoadImageView() let leftContainer = ViewConstrainingView.empty() //------------------------------------------------------ @@ -26,6 +26,7 @@ import UIKit var imageWidthConstraint: NSLayoutConstraint? var imageHeightConstraint: NSLayoutConstraint? + var imageLeadingConstraint: NSLayoutConstraint? var buttonTopConstraint: NSLayoutConstraint? var messageTopConstraint: NSLayoutConstraint? @@ -60,11 +61,10 @@ import UIKit guard subviews.isEmpty else { return } button.setAsSecondaryCustom() - - imageloader.imageView.contentMode = .scaleAspectFit + imageLoader.imageView.contentMode = .scaleAspectFit addSubview(leftContainer) - addSubview(imageloader) + addSubview(imageLoader) leftContainer.addSubview(title) leftContainer.addSubview(message) leftContainer.addSubview(button) @@ -94,19 +94,20 @@ import UIKit button.bottomAnchor.constraint(equalTo: leftContainer.bottomAnchor).isActive = true leftContainer.trailingAnchor.constraint(greaterThanOrEqualTo: button.trailingAnchor).isActive = true - imageloader.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true - layoutMarginsGuide.trailingAnchor.constraint(equalTo: imageloader.trailingAnchor).isActive = true - imageloader.leadingAnchor.constraint(equalTo: leftContainer.trailingAnchor, constant: 16).isActive = true - imageloader.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true + imageLoader.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + layoutMarginsGuide.trailingAnchor.constraint(equalTo: imageLoader.trailingAnchor).isActive = true + imageLeadingConstraint = imageLoader.leadingAnchor.constraint(greaterThanOrEqualTo: leftContainer.trailingAnchor, constant: 16) + imageLeadingConstraint?.isActive = true + imageLoader.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true - imageHeightConstraint = imageloader.heightAnchor.constraint(equalToConstant: 0) + imageHeightConstraint = imageLoader.heightAnchor.constraint(equalToConstant: 0) imageHeightConstraint?.isActive = true - - imageWidthConstraint = imageloader.widthAnchor.constraint(equalToConstant: 0) + + imageWidthConstraint = imageLoader.widthAnchor.constraint(equalToConstant: 0) imageWidthConstraint?.isActive = true - bottomAnchor.constraint(greaterThanOrEqualTo: imageloader.bottomAnchor).isActive = true - let imageloaderBottom = imageloader.bottomAnchor.constraint(equalTo: bottomAnchor) + bottomAnchor.constraint(greaterThanOrEqualTo: imageLoader.bottomAnchor).isActive = true + let imageloaderBottom = imageLoader.bottomAnchor.constraint(equalTo: bottomAnchor) imageloaderBottom.priority = UILayoutPriority(249) imageloaderBottom.isActive = true } @@ -117,11 +118,15 @@ import UIKit title.updateView(size) message.updateView(size) button.updateView(size) - imageloader.updateView(size) + imageLoader.updateView(size) leftContainer.updateView(size) messageTopConstraint?.constant = title.hasText ? PaddingOne : 0 buttonTopConstraint?.constant = message.hasText ? PaddingTwo : (title.hasText ? PaddingOne : 0) + + if imageWidthConstraint?.constant == 0 { + imageLeadingConstraint?.constant = 0 + } } override open func reset() { @@ -129,8 +134,9 @@ import UIKit title.text = "" message.text = "" - imageloader.imageView.image = nil + imageLoader.imageView.image = nil imageWidthConstraint?.constant = 0 + imageLeadingConstraint?.constant = 16 backgroundColor = nil } @@ -142,7 +148,7 @@ import UIKit title.setWithJSON(dictionary.optionalDictionaryForKey("title"), delegateObject: delegateObject, additionalData: additionalData) message.setWithJSON(dictionary.optionalDictionaryForKey("message"), delegateObject: delegateObject, additionalData: additionalData) button.setWithJSON(dictionary.optionalDictionaryForKey("button"), delegateObject: delegateObject, additionalData: additionalData) - imageloader.setWithJSON(dictionary.optionalDictionaryForKey("image"), delegateObject: delegateObject, additionalData: additionalData) + imageLoader.setWithJSON(dictionary.optionalDictionaryForKey("image"), delegateObject: delegateObject, additionalData: additionalData) if let imageJSON = dictionary.optionalDictionaryForKey("image") { imageWidthConstraint?.constant = CGFloat(imageJSON.floatForKey("width")) From 33020844dc414336be7b81a5138e62e17d41acdd Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 11 Jul 2019 11:54:14 -0400 Subject: [PATCH 10/62] carousel --- MVMCoreUI.xcodeproj/project.pbxproj | 12 + MVMCoreUI/MVMCoreUI.h | 2 + MVMCoreUI/Molecules/Carousel.swift | 394 ++++++++++++++--- MVMCoreUI/Molecules/MVMCoreUIPageControl.h | 60 +++ MVMCoreUI/Molecules/MVMCoreUIPageControl.m | 395 ++++++++++++++++++ MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h | 22 + .../MoleculeCollectionViewCell.swift | 7 +- .../MVMCoreUIMoleculeMappingObject.m | 4 +- 8 files changed, 840 insertions(+), 56 deletions(-) create mode 100644 MVMCoreUI/Molecules/MVMCoreUIPageControl.h create mode 100644 MVMCoreUI/Molecules/MVMCoreUIPageControl.m create mode 100644 MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index afe89464..9323507e 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -31,6 +31,9 @@ D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */; }; D22D1F562204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D22D1F542204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; D22D1F572204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D22D1F552204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m */; }; + D260D7B122D65BDD007E7233 /* MVMCoreUIPageControl.h in Headers */ = {isa = PBXBuildFile; fileRef = D260D7AF22D65BDD007E7233 /* MVMCoreUIPageControl.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */ = {isa = PBXBuildFile; fileRef = D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */; }; + D260D7B622D68514007E7233 /* MVMCoreUIPagingProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; D274CA332236A78900B01B62 /* StandardFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D274CA322236A78900B01B62 /* StandardFooterView.swift */; }; D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AAB3223FDDAE00C46919 /* MFLoadImageView.swift */; }; D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AAB9224131D100C46919 /* MFTransparentGIFView.swift */; }; @@ -202,6 +205,9 @@ D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUISwitch.m; sourceTree = ""; }; D22D1F542204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIStackableViewController.h; sourceTree = ""; }; D22D1F552204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIStackableViewController.m; sourceTree = ""; }; + D260D7AF22D65BDD007E7233 /* MVMCoreUIPageControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIPageControl.h; sourceTree = ""; }; + D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIPageControl.m; sourceTree = ""; }; + D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIPagingProtocol.h; sourceTree = ""; }; D274CA322236A78900B01B62 /* StandardFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardFooterView.swift; sourceTree = ""; }; D282AAB3223FDDAE00C46919 /* MFLoadImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MFLoadImageView.swift; sourceTree = ""; }; D282AAB9224131D100C46919 /* MFTransparentGIFView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MFTransparentGIFView.swift; sourceTree = ""; }; @@ -481,6 +487,9 @@ D2A638FC22CA98280052ED1F /* HeadlineBody.swift */, D2A6390022CBB1820052ED1F /* Carousel.swift */, D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */, + D260D7AF22D65BDD007E7233 /* MVMCoreUIPageControl.h */, + D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */, + D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */, ); path = Molecules; sourceTree = ""; @@ -757,6 +766,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + D260D7B622D68514007E7233 /* MVMCoreUIPagingProtocol.h in Headers */, D29DF18021E69E49003B2FB9 /* MFView.h in Headers */, D29DF27921E7A533003B2FB9 /* MVMCoreUISession.h in Headers */, D206997721FB8A0B00CAE0DE /* MVMCoreUINavigationController.h in Headers */, @@ -815,6 +825,7 @@ D29770FD21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h in Headers */, D29DF17421E69E1F003B2FB9 /* MFCustomButton.h in Headers */, D29DF29721E7ADB8003B2FB9 /* MFScrollingViewController.h in Headers */, + D260D7B122D65BDD007E7233 /* MVMCoreUIPageControl.h in Headers */, D29DF26F21E6AA0B003B2FB9 /* FLAnimatedImageView.h in Headers */, D29DF2A121E7AF4E003B2FB9 /* MVMCoreUIUtility.h in Headers */, D29DF17621E69E1F003B2FB9 /* PrimaryButton.h in Headers */, @@ -940,6 +951,7 @@ DBEFFA04225A829700230692 /* Label.swift in Sources */, D29DF13021E6851E003B2FB9 /* MVMCoreUITopAlertShortView.m in Sources */, D28B4F8B21FF967C00712C7A /* MVMCoreUIObject.m in Sources */, + D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */, D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */, D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */, D282AACB2243C61700C46919 /* ButtonView.swift in Sources */, diff --git a/MVMCoreUI/MVMCoreUI.h b/MVMCoreUI/MVMCoreUI.h index 4ef880c0..258fcd1c 100644 --- a/MVMCoreUI/MVMCoreUI.h +++ b/MVMCoreUI/MVMCoreUI.h @@ -108,5 +108,7 @@ FOUNDATION_EXPORT const unsigned char MVMCoreUIVersionString[]; #pragma mark - Molecules #import #import +#import +#import #pragma mark - Templates diff --git a/MVMCoreUI/Molecules/Carousel.swift b/MVMCoreUI/Molecules/Carousel.swift index 3333855b..cb0bbf2b 100644 --- a/MVMCoreUI/Molecules/Carousel.swift +++ b/MVMCoreUI/Molecules/Carousel.swift @@ -10,12 +10,44 @@ import UIKit open class Carousel: ViewConstrainingView { let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) - var currentIndex = 1 - var numberOfCards = 0 - var molecules: [[AnyHashable : Any]]? - var collectionViewHeight: NSLayoutConstraint? + /// The current index of the collection view. Includes dummy cells when looping. + var currentIndex = 0 + + /// The index of the page, does not include dummy cells. + var pageIndex: Int { + get { + return loop ? currentIndex - 2 : currentIndex + } + set(newIndex) { + currentIndex = loop ? newIndex + 2 : newIndex + } + } + + /// The number of pages that there are. Used for the page control and for calculations. Should not include the looping dummy cells. Be sure to set this if subclassing and not using the molecules. + var numberOfPages = 0 + + /// The json for the molecules. + var molecules: [[AnyHashable: Any]]? + /// The horizontal alignment of the cell in the collection view. Only noticeable if the itemWidthPercent is less than 100%. + var itemAlignment = UICollectionView.ScrollPosition.left + + /// From 0-1. The item width as a percent of the carousel width. + var itemWidthPercent: CGFloat = 1 + + /// The height of the carousel. Default is 300. + var collectionViewHeight: NSLayoutConstraint? + + /// The view that we use for paging + var pagingView: (UIView & MVMCoreUIPagingProtocol)? + + /// If the carousel should loop after scrolling past the first and final cells. + var loop = false + private var dragging = false + private var previousContentOffsetX: CGFloat = 0 + + // MARK: - MVMCoreViewProtocol open override func setupView() { super.setupView() guard collectionView.superview == nil else { @@ -33,8 +65,67 @@ open class Carousel: ViewConstrainingView { collectionViewHeight?.isActive = true } + open override func updateView(_ size: CGFloat) { + super.updateView(size) + 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.currentIndex, section: 0), at: self.itemAlignment, animated: false) + self.collectionView.layoutIfNeeded() + } + } + + // MARK: - MVMCoreUIMoleculeViewProtocol + open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + registerCells(with: json, delegateObject: delegateObject) + setupLayout(with: json) + prepareMolecules(with: json) + itemWidthPercent = (json?.optionalCGFloatForKey("itemWidthPercent") ?? 100) / 100 + setAlignment(with: json?.optionalStringForKey("itemAlignment")) + collectionViewHeight?.constant = json?.optionalCGFloatForKey("height") ?? 300 + setupPagingMolecule(json: json?.optionalDictionaryForKey("pagingMolecule"), delegateObject: delegateObject) + collectionView.reloadData() + } + + open override func shouldSetHorizontalMargins(_ shouldSet: Bool) { + super.shouldSetHorizontalMargins(shouldSet) + updateViewHorizontalDefaults = false + } + + // MARK: - JSON Setters + /// Updates the layout being used + func setupLayout(with json:[AnyHashable: Any]?) { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .horizontal + layout.minimumLineSpacing = json?["spacing"] as? CGFloat ?? 1 + layout.minimumInteritemSpacing = 0 + collectionView.collectionViewLayout = layout + } + + func prepareMolecules(with json: [AnyHashable: Any]?) { + guard let newMolecules = json?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] else { + numberOfPages = 0 + molecules = nil + return + } + + numberOfPages = newMolecules.count + molecules = newMolecules + if json?.boolForKey("loop") ?? false && newMolecules.count > 2 { + // Sets up the row data with buffer cells on each side (for illusion of endless scroll... also has one more buffer cell on each side in case we can peek that cell). + loop = true + molecules?.insert(newMolecules.last!, at: 0) + molecules?.insert(newMolecules[(newMolecules.count - 1)], at: 0) + molecules?.append(newMolecules.first!) + molecules?.append(newMolecules[1]) + } + pageIndex = 0 + } + /// Registers the cells with the collection view - func registerCells(with json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) { + func registerCells(with json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) { if let molecules = json?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] { for molecule in molecules { if let info = getMoleculeInfo(with: molecule, delegateObject: delegateObject) { @@ -44,51 +135,13 @@ open class Carousel: ViewConstrainingView { } } - /// Updates the layout being used - func setupLayout(with json:[AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) { - let layout = UICollectionViewFlowLayout() - layout.scrollDirection = .horizontal - layout.minimumLineSpacing = json?["spacing"] as? CGFloat ?? 0 - layout.minimumInteritemSpacing = 0 - //layout.itemSize = CGSize(width: 300, height: 200) - collectionView.collectionViewLayout = layout - } - - func prepareMolecules(_ json: [AnyHashable : Any]?) { - guard let newMolecules = json?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] else { - numberOfCards = 0 - molecules = nil - return + /// Sets up the paging molecule + open func setupPagingMolecule(json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) { + var pagingView: (UIView & MVMCoreUIPagingProtocol)? = nil + if let json = json { + pagingView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: json, delegateObject: delegateObject, constrainIfNeeded: true) as? (UIView & MVMCoreUIPagingProtocol) } - - numberOfCards = newMolecules.count - molecules = newMolecules - if json?.boolForKey("loop") ?? false && newMolecules.count > 2 { - // Sets up the row data with a buffer cell on each side (for illusion of endless scroll... also has one more buffer cell on right since we can peek that cell). - molecules?.insert(newMolecules.last!, at: 0) - molecules?.append(newMolecules.first!) - molecules?.append(newMolecules[1]) - } - } - - open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - - collectionViewHeight?.constant = json?.optionalCGFloatForKey("height") ?? 300 - - registerCells(with: json, delegateObject: delegateObject) - setupLayout(with: json, delegateObject: delegateObject) - prepareMolecules(json) - collectionView.reloadData() - - // Go to starting cell. layoutIfNeeded is needed otherwise cellForItem returns nil for peaking logic. - collectionView.scrollToItem(at: IndexPath(row: currentIndex, section: 0), at: .left, animated: false) - collectionView.layoutIfNeeded() - } - - open override func setAsMolecule() { - super.setAsMolecule() - updateViewHorizontalDefaults = false + addPaging(view: pagingView, position: (json?.optionalCGFloatForKey("position") ?? 20)) } // MARK: - Convenience @@ -101,10 +154,60 @@ open class Carousel: ViewConstrainingView { } return (moleculeName, moleculeClass, molecule) } + + /// Sets the alignment from the string. + open func setAlignment(with string: String?) { + switch string { + case "leading": + itemAlignment = .left + case "trailing": + itemAlignment = .right + case "center": + itemAlignment = .centeredHorizontally + default: break + } + } + + /// 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 & MVMCoreUIPagingProtocol)?, position: CGFloat) { + pagingView?.removeFromSuperview() + guard let pagingView = view else { + bottomPin?.isActive = false + bottomPin = bottomAnchor.constraint(equalTo: collectionView.bottomAnchor) + bottomPin?.isActive = true + return + } + pagingView.translatesAutoresizingMaskIntoConstraints = false + addSubview(pagingView) + pagingView.centerXAnchor.constraint(equalTo: collectionView.centerXAnchor).isActive = true + collectionView.bottomAnchor.constraint(equalTo: pagingView.centerYAnchor, constant: position).isActive = true + bottomAnchor.constraint(greaterThanOrEqualTo: pagingView.bottomAnchor).isActive = true + bottomPin?.isActive = false + bottomPin = bottomAnchor.constraint(equalTo: collectionView.bottomAnchor) + bottomPin?.priority = .defaultLow + bottomPin?.isActive = true + + pagingView.setNumberOfPages(numberOfPages) + (pagingView as? MVMCoreUIViewConstrainingProtocol)?.alignHorizontal?(.fill) + pagingView.setPagingTouch { [weak self] (pager) in + MVMCoreDispatchUtility.performBlock(onMainThread: { + guard let localSelf = self else { + return + } + let currentPage = pager.currentPage() + localSelf.pageIndex = currentPage + self?.collectionView.scrollToItem(at: IndexPath(row: localSelf.currentIndex, section: 0), at: (self?.itemAlignment ?? .left), animated: true) + }) + } + self.pagingView = pagingView + } } -extension Carousel: UICollectionViewDelegate { - +extension Carousel: UICollectionViewDelegateFlowLayout { + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + let itemWidth = collectionView.bounds.width * itemWidthPercent + return CGSize(width: itemWidth, height: collectionView.bounds.height) + } } extension Carousel: UICollectionViewDataSource { @@ -123,6 +226,195 @@ extension Carousel: UICollectionViewDataSource { protocolCell.setWithJSON(moleculeInfo.molecule, delegateObject: nil, additionalData: nil) protocolCell.updateView(collectionView.bounds.width) } + return cell } } + +extension Carousel: UIScrollViewDelegate { + /*// For getting the scroll progress to set the page control color progress. + - (CGFloat)getPageControlPercentBasedOnScrollView:(UIScrollView *)scrollView { + CGFloat cardWidth = ((UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout).itemSize.width; + CGFloat separatorWidth = ((UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout).minimumLineSpacing; + CGFloat contentOfsetInCard = fmodf(scrollView.contentOffset.x, cardWidth + separatorWidth); + CGFloat endThresholdPageControl = cardWidth + separatorWidth - CGRectGetMaxX(self.pageControl.frame); + CGFloat progress = contentOfsetInCard - endThresholdPageControl; + CGFloat width = CGRectGetWidth(self.pageControl.bounds); + CGFloat percent = (width - progress)/width; + CGFloat cappedPercent = MAX(MIN(percent, 1), 0); + return cappedPercent; + } + + - (void)setPageControlColorsBasedOnScrollView:(UIScrollView *)scrollView { + + // Check if we will need to change colors. + BOOL needToShiftColors = NO; + NSInteger nextCardIndex = 0; + CGFloat cardWidth = ((UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout).itemSize.width; + CGFloat separatorWidth = ((UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout).minimumLineSpacing; + NSInteger currentCard = scrollView.contentOffset.x / (cardWidth + separatorWidth); + CGFloat cardStart = currentCard * (cardWidth + separatorWidth); + CGFloat cardEnd = cardStart + cardWidth + separatorWidth; + NSInteger pageIndicator = currentCard; + if ((self.previousContentOffsetX == NSNotFound || self.previousContentOffsetX <= cardStart) && scrollView.contentOffset.x >= cardStart) { + + // We are passed the threshold and moving right, change to right card color. + needToShiftColors = YES; + nextCardIndex = currentCard + 1; + pageIndicator = currentCard - 1; + } else if ((self.previousContentOffsetX == NSNotFound || self.previousContentOffsetX >= cardEnd) && scrollView.contentOffset.x < cardEnd) { + + // We are passed the threshold and moving left, change to left card color. + needToShiftColors = YES; + nextCardIndex = currentCard - 1; + } + + if (needToShiftColors) { + // Only shift the page control if we are dragging still, otherwise end animation will control. + if (self.dragging) { + [self.pageControl setCurrentPage:pageIndicator]; + } + + // Get the current page color + NSString *colorString = [[self.feedModules objectAtIndex:currentCard] string:KeyPageIndicatorColor]; + UIColor *currentCardPageControlColor = colorString ? [UIColor mfGetColorForHex:colorString] : [UIColor blackColor]; + + // Get the next page color and set accordingly. + colorString = [[self.feedModules dictionaryAtIndex:nextCardIndex] string:KeyPageIndicatorColor]; + UIColor *nextCardPageControlColor = colorString ? [UIColor mfGetColorForHex:colorString] : [UIColor blackColor]; + + // Which color needs to be on top or bottom depends on which direction we are moving. + if (nextCardIndex > currentCard) { + [self setPageControlColor:nextCardPageControlColor progressColor:currentCardPageControlColor]; + } else { + [self setPageControlColor:currentCardPageControlColor progressColor:nextCardPageControlColor]; + } + } + } + + */ + + func handleUserOnBufferCell() { + guard loop else { + return + } + + let lastPageIndex = numberOfPages + 1 + let goToIndex = {(index: Int) in + self.currentIndex = index + self.previousContentOffsetX = CGFloat(NSNotFound) + self.collectionView.scrollToItem(at: IndexPath(row: self.currentIndex, section: 0), at: self.itemAlignment, animated: false) + self.collectionView.layoutIfNeeded() + self.pagingView?.setPage(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 * itemWidthPercent + let index = Int(scrollView.contentOffset.x / (itemWidth + separatorWidth)) + let lastCellIndex = collectionView(collectionView, numberOfItemsInSection: 0) - 1 + if index < 0 { + self.currentIndex = 0 + } else if index > lastCellIndex { + self.currentIndex = lastCellIndex + } + } + + handleUserOnBufferCell() + } + + public func scrollViewDidScroll(_ scrollView: UIScrollView) { + // Check if the user is dragging the card even further past the next card. + checkForDraggingOutOfBounds(scrollView) + + // Set the page control direction colors if needed. + //[self setPageControlColorsBasedOnScrollView:scrollView]; + + // Set the percent of progress. + //self.pageControl.progressView.progress = [self getPageControlPercentBasedOnScrollView:scrollView]; + + previousContentOffsetX = scrollView.contentOffset.x; + } + + public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { + dragging = true + +// // Hide coverview and arrow. +// FeedBaseCollectionViewCell *peakingCell = (FeedBaseCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:self.currentIndex + 1 inSection:0]]; +// [peakingCell setPeaking:NO animated:YES]; + } + + 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 + } + + // We switch cards if we pass the velocity threshold or position threshold (currently 50%). + let itemWidth = collectionView.bounds.width * itemWidthPercent + var cellToSwipeTo = Int(scrollView.contentOffset.x/(itemWidth + separatorWidth) + 0.5) + let lastCellIndex = collectionView(collectionView, numberOfItemsInSection: 0) - 1 + let velocityThreshold: CGFloat = 1.1 + if velocity.x > velocityThreshold { + cellToSwipeTo = currentIndex + 1 + } else if velocity.x < -velocityThreshold { + cellToSwipeTo = currentIndex - 1 + } + + // Cap the index. + currentIndex = min(max(cellToSwipeTo, 0), lastCellIndex) + + collectionView.scrollToItem(at: IndexPath(row: currentIndex, section: 0), at: itemAlignment, animated: true) + + // Notify that card changed + /*if (self.cardChanged) { + self.cardChanged(self.currentIndex, [self.module string:[MFBaseHomeViewController getFeedContainerNameKey]]); + }*/ + } + + // 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?.setPage(pageIndex) + /* + // Update to the new page in the control if needed. + if (self.currentIndex - 1 != self.pageControl.currentPage) { + [self.pageControl setCurrentPage:self.currentIndex - 1]; + } + // Show overlay and arrow in next Cell + FeedBaseCollectionViewCell *nextCell = (FeedBaseCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:self.currentIndex + 1 inSection:0]]; + [nextCell setPeaking:YES animated:YES]; + + FeedBaseCollectionViewCell *currentCell = (FeedBaseCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:self.currentIndex inSection:0]]; + if (currentCell) { + self.accessibilityElements = @[currentCell.containerView, self.pageControl]; + currentCell.containerView.isAccessibilityElement = YES; + currentCell.accessibilityElementsHidden = NO; + UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification,currentCell.containerView); + } + + // Set the page control again if pageControl is tapped or voice over is using. + [self setPageControlColorsBasedOnScrollView:scrollView]; + + // send adobe tracker action + [self sendAdobeTrackerAction];*/ + } +} diff --git a/MVMCoreUI/Molecules/MVMCoreUIPageControl.h b/MVMCoreUI/Molecules/MVMCoreUIPageControl.h new file mode 100644 index 00000000..af699ddc --- /dev/null +++ b/MVMCoreUI/Molecules/MVMCoreUIPageControl.h @@ -0,0 +1,60 @@ +// +// MVMCoreUIPageControl.h +// MobileFirstFramework +// +// Created by Seshamani, Shreyas on 1/5/18. +// Copyright © 2018 Verizon Wireless. All rights reserved. +// + +#import +#import +#import +#import + +@interface MVMCoreUIPageControl : UIControl + +// These properties effectively do what their corresponding namesakes do in UIPageControl +@property (nonatomic) NSInteger currentPage; +@property (nonatomic) NSInteger numberOfPages; +@property (nonatomic, getter=isAnimated) BOOL animated; +@property (nullable, strong, nonatomic) UIColor *pageIndicatorTintColor; +@property (nullable, strong, nonatomic) UIColor *currentPageIndicatorTintColor; +@property (nullable, strong, nonatomic, readonly) NSArray *rectangles; +@property (nullable, weak, nonatomic) UIView *containerView; +@property (nullable, weak, nonatomic) UIView *indicatorRectangle; +@property (nullable, copy, nonatomic) PagingTouchBlock pagingTouchBlock; + +///set YES to make the accessibility value as "Slide #currentPage of #totalPage", otherwise will be "Page #currentPage of #totalPage", default is NO +@property (nonatomic) BOOL isSlidesAcc; + +/// This property may be used for indicating the user's selected option (not the currentPage). For instance, in Plan Explore Sizes, it indicates what plan the user is currently on. +@property (nonatomic) NSInteger persistentPreselectedPage; + +//customize pagecontrol properties +@property (nonatomic) CGFloat rectangleWidth; + +/// Indicates the color of the persistentPreselectedPage +@property (nullable, strong, nonatomic) UIColor *persisitentPreselectedPageTintColor; + +//top bottom constraints +@property (nullable, strong, nonatomic) NSLayoutConstraint *topConstraint; +@property (nullable, strong, nonatomic) NSLayoutConstraint *bottomConstraint; + +//a flag to allow to send UIControlEventValueChanged actions all the time +//e.g. going to previous element at first place and going to next at last place +//While current rectangle won't change, need update current page +@property (nonatomic) BOOL alwaysSendingControlEvent; + +- (nullable instancetype)initWithAnimation:(BOOL)animated; +- (void)setCurrentPage:(NSInteger)currentPage animated:(BOOL)animated; + +// Sets up the horizontal constraint to have the pages centered horizontally. +- (void)setupHorizontalConstraints; + +// For subclassing only. +- (void)setupView; +- (void)setupRectangles; + +- (void)setTopBottomSpace:(CGFloat)constant; + +@end diff --git a/MVMCoreUI/Molecules/MVMCoreUIPageControl.m b/MVMCoreUI/Molecules/MVMCoreUIPageControl.m new file mode 100644 index 00000000..e5855f7d --- /dev/null +++ b/MVMCoreUI/Molecules/MVMCoreUIPageControl.m @@ -0,0 +1,395 @@ +// +// MVMCoreUIPageControl.m +// MobileFirstFramework +// +// Created by Seshamani, Shreyas on 1/5/18. +// Copyright © 2018 Verizon Wireless. All rights reserved. +// + +#import "MVMCoreUIPageControl.h" +#import "MVMCoreUICommonViewsUtility.h" +#import +#import +#import "MVMCoreUIUtility.h" +#import "MVMCoreUIConstants.h" +@interface MVMCoreUIPageControl () + +@property (nullable, weak, nonatomic) UIView *animationRectangle; +@property (nullable, strong, nonatomic, readwrite) NSArray *rectangles; + +@property (nullable, strong, nonatomic) NSLayoutConstraint *indicatorRectangleLeadingConstraint; + +@property (nonatomic) CGFloat interRectangleSpacing; +@property (nonatomic) BOOL isDoAnimating; +@property (nonatomic) BOOL isDisAnimating; + +@end + +@implementation MVMCoreUIPageControl + +static CGFloat const DefaultInterRectangleSpacing = 6; +static CGFloat const DefaultRectangleWidth = 24; +static CGFloat const RectangleHeight = 1; +static CGFloat const IndicatorRectangleHeight = 4; + +- (void)updateView:(CGFloat)size { +} + +#pragma mark - Properties + +- (instancetype)init { + self = [super init]; + if (self) { + [self initValues]; + [self setupView]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + [self initValues]; + [self setupView]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + if (self) { + [self initValues]; + [self setupView]; + } + return self; +} + +- (instancetype)initWithAnimation:(BOOL)animated { + self = [super init]; + if (self) { + [self initValues]; + [self setupView]; + self.animated = animated; + } + return self; +} + +- (void)initValues { + self.interRectangleSpacing = DefaultInterRectangleSpacing; + self.rectangleWidth = DefaultRectangleWidth; + self.animated = YES; + self.isSlidesAcc = NO; +} + +- (void)setCurrentPage:(NSInteger)currentPage { + [self setCurrentPage:currentPage animated:self.animated]; +} + +- (void)setCurrentPage:(NSInteger)currentPage animated:(BOOL)animated { + if (_currentPage!=currentPage) { + _currentPage = currentPage; + if (currentPage >= 0 && currentPage < self.numberOfPages) { + self.animationRectangle.frame = self.indicatorRectangle.frame; + self.indicatorRectangleLeadingConstraint.constant = (_currentPage * (self.rectangleWidth + self.interRectangleSpacing) + self.interRectangleSpacing); + [self displayIndicator:animated]; + [self dismissAnimationIndicator:animated]; + [self layoutIfNeeded]; + } + } +} + +- (void)setNumberOfPages:(NSInteger)numberOfPages { + if (_numberOfPages != numberOfPages) { + _numberOfPages = numberOfPages; + [self updateRectangleWidthAndSpacing]; + [self setupRectangles]; + } +} + +- (void)setPersistentPreselectedPage:(NSInteger)persistentPreselectedPage { + _persistentPreselectedPage = persistentPreselectedPage; + + if (!self.rectangles) { + [self setupRectangles]; + } + + if (persistentPreselectedPage >= 0 && persistentPreselectedPage < self.numberOfPages) { + UIView *persistentRectangle = self.rectangles[persistentPreselectedPage]; + persistentRectangle.backgroundColor = self.persisitentPreselectedPageTintColor; + } +} + +@synthesize currentPageIndicatorTintColor = _currentPageIndicatorTintColor; + +- (UIColor *)currentPageIndicatorTintColor { + if (!_currentPageIndicatorTintColor) { + _currentPageIndicatorTintColor = [UIColor blackColor]; + } + return _currentPageIndicatorTintColor; +} + +- (void)setCurrentPageIndicatorTintColor:(UIColor *)currentPageIndicatorTintColor { + + _currentPageIndicatorTintColor = currentPageIndicatorTintColor; + if (!self.indicatorRectangle) { + [self setupRectangles]; + } + self.indicatorRectangle.backgroundColor = currentPageIndicatorTintColor; + self.animationRectangle.backgroundColor = currentPageIndicatorTintColor; +} + +@synthesize pageIndicatorTintColor = _pageIndicatorTintColor; + +- (UIColor *)pageIndicatorTintColor { + if (!_pageIndicatorTintColor) { + return [UIColor mfBattleshipGrey]; + } + return _pageIndicatorTintColor; +} + +- (void)setPageIndicatorTintColor:(UIColor *)pageIndicatorTintColor { + _pageIndicatorTintColor = pageIndicatorTintColor; + if (!self.rectangles) { + [self setupRectangles]; + } + for (UIView *rectangle in self.rectangles) { + rectangle.backgroundColor = pageIndicatorTintColor; + } +} + +@synthesize persisitentPreselectedPageTintColor = _persisitentPreselectedPageTintColor; + +- (UIColor *)persisitentPreselectedPageTintColor { + if (!_persisitentPreselectedPageTintColor) { + _persisitentPreselectedPageTintColor = [UIColor mfCerulean]; + } + return _persisitentPreselectedPageTintColor; +} + +- (void)setPersisitentPreselectedPageTintColor:(UIColor *)persisitentPreselectedPageTintColor { + _persisitentPreselectedPageTintColor = persisitentPreselectedPageTintColor; + + if (!self.rectangles) { + [self setupRectangles]; + } + + if (self.persistentPreselectedPage >= 0 && self.persistentPreselectedPage < self.numberOfPages) { + UIView *persistentRectangle = self.rectangles[self.persistentPreselectedPage]; + persistentRectangle.backgroundColor = persisitentPreselectedPageTintColor; + } +} + +#pragma mark - Setup + +- (void)updateRectangleWidthAndSpacing { + + CGFloat screenWidth = [MVMCoreUIUtility getWidth]; + CGFloat pageControlRequiredWidth = self.numberOfPages * (self.rectangleWidth + self.interRectangleSpacing) + DefaultInterRectangleSpacing; + + if (pageControlRequiredWidth > screenWidth) { + // the Inter rectangle spacing is a quarter of the rectangle width + self.interRectangleSpacing = screenWidth / ((self.numberOfPages + 1) + (self.numberOfPages * 4)); + self.rectangleWidth = self.interRectangleSpacing * 4; + } +} + +- (void)setupRectangles { + + // Create the rectangles for all the indexes + [self removeRectangles]; + NSMutableArray *rectangles = [[NSMutableArray alloc] init]; + for (int index = 0; index < self.numberOfPages; index++) { + + UIView *rectangle = [MVMCoreUICommonViewsUtility commonView]; + [rectangles addObject:rectangle]; + rectangle.translatesAutoresizingMaskIntoConstraints = NO; + rectangle.frame = CGRectMake((self.interRectangleSpacing * (index + 1)) + (self.rectangleWidth * index), IndicatorRectangleHeight- RectangleHeight, self.rectangleWidth, RectangleHeight); + [rectangle.heightAnchor constraintEqualToConstant:RectangleHeight].active = YES; + [rectangle.widthAnchor constraintEqualToConstant:self.rectangleWidth].active = YES; + rectangle.backgroundColor = self.pageIndicatorTintColor; + } + + [StackableViewController populateViewHorizontally:self.containerView withUIArray:rectangles withSpacingBlock:^UIEdgeInsets(id _Nullable object) { + + if (object == [rectangles lastObject]) { + return UIEdgeInsetsMake(RectangleHeight, self.interRectangleSpacing, 0, self.interRectangleSpacing); + } + return UIEdgeInsetsMake(RectangleHeight, self.interRectangleSpacing, 0, 0); + }]; + self.rectangles = rectangles; + + // Create the indicator rectangle + UIView *indicatorRectangle = [MVMCoreUICommonViewsUtility commonView]; + [self.containerView addSubview:indicatorRectangle]; + indicatorRectangle.backgroundColor = self.currentPageIndicatorTintColor; + [indicatorRectangle.heightAnchor constraintEqualToConstant:IndicatorRectangleHeight].active = YES; + [indicatorRectangle.widthAnchor constraintEqualToConstant:self.rectangleWidth].active = YES; + [indicatorRectangle.topAnchor constraintGreaterThanOrEqualToAnchor:self.containerView.topAnchor].active = YES; + [indicatorRectangle.bottomAnchor constraintEqualToAnchor:self.containerView.bottomAnchor].active = YES; + self.indicatorRectangleLeadingConstraint = [indicatorRectangle.leadingAnchor constraintEqualToAnchor:self.containerView.leadingAnchor constant:self.interRectangleSpacing]; + self.indicatorRectangleLeadingConstraint.active = YES; + self.indicatorRectangle = indicatorRectangle; + indicatorRectangle.frame = CGRectMake(self.interRectangleSpacing, 0, self.rectangleWidth, IndicatorRectangleHeight); + + // Create shadow indicator rectangle for animaiton + UIView *animatedIndicatorRectangle = [MVMCoreUICommonViewsUtility commonView]; + [self.containerView addSubview:animatedIndicatorRectangle]; + animatedIndicatorRectangle.backgroundColor = self.currentPageIndicatorTintColor; + self.animationRectangle = animatedIndicatorRectangle; +} + +- (void)setupView { + + if (!self.containerView) { + // Create a container view that keeps everything centered + UIView *containerView = [MVMCoreUICommonViewsUtility commonView]; + [self addSubview:containerView]; + self.containerView = containerView; + [self setupHorizontalConstraints]; + + NSLayoutConstraint *topConstraint = [containerView.topAnchor constraintEqualToAnchor:self.topAnchor constant:PaddingThree]; + topConstraint.priority = UILayoutPriorityDefaultHigh; + topConstraint.active = YES; + self.topConstraint = topConstraint; + + NSLayoutConstraint *bottomConstraint = [self.bottomAnchor constraintEqualToAnchor:containerView.bottomAnchor constant:PaddingThree]; + bottomConstraint.priority = UILayoutPriorityDefaultHigh; + bottomConstraint.active = YES; + self.bottomConstraint = bottomConstraint; + + [self updateRectangleWidthAndSpacing]; + + // Create the rectangles for all the indexes + [self setupRectangles]; + + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] init]; + [tapGesture addTarget:self action:@selector(rectangleTapped:)]; + [self addGestureRecognizer:tapGesture]; + } +} + +- (void)setupHorizontalConstraints { + [self.containerView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor].active = YES; + [self.containerView.leadingAnchor constraintGreaterThanOrEqualToAnchor:self.leadingAnchor].active = YES; + [self.containerView.trailingAnchor constraintLessThanOrEqualToAnchor:self.trailingAnchor].active = YES; +} + +- (void)removeRectangles { + for (UIView *subview in self.containerView.subviews) { + [subview removeFromSuperview]; + } +} + +#pragma mark - Actions + +- (void)rectangleTapped:(UITapGestureRecognizer *)tapGesture { + if (self.userInteractionEnabled) { + CGPoint touchPoint = [tapGesture locationInView:self.containerView]; + NSInteger selectedIndex = [self.rectangles indexOfObjectPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + UIView *subview = self.rectangles[idx]; + if (CGRectGetMaxX(subview.frame) >= touchPoint.x && CGRectGetMinX(subview.frame) <= touchPoint.x) { + *stop = YES; + } + return *stop; + }]; + if (selectedIndex != NSNotFound) { + self.currentPage = selectedIndex; + [self sendActionsForControlEvents:UIControlEventValueChanged]; + self.pagingTouchBlock(self); + } + } +} + +#pragma mark - MVMCoreUIPagingProtocol + +- (void)setPage:(NSUInteger)page { + self.currentPage = page; +} + +#pragma mark - MoleculeViewProtocol + +- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { + NSString *colorString = [json string:KeyBackgroundColor]; + if (colorString) { + self.backgroundColor = [UIColor mfGetColorForHex:colorString]; + } + colorString = [json string:@"barsColor"]; + if (colorString) { + UIColor *color = [UIColor mfGetColorForHex:colorString]; + self.pageIndicatorTintColor = color; + self.currentPageIndicatorTintColor = color; + } + colorString = [json string:@"currentBarColor"]; + if (colorString) { + self.currentPageIndicatorTintColor = [UIColor mfGetColorForHex:colorString]; + } +} + +#pragma mark - Accessibility +- (UIAccessibilityTraits)accessibilityTraits { + return UIAccessibilityTraitAdjustable; +} + +- (NSString *)accessibilityValue { + NSString *stringKey = self.isSlidesAcc ? @"MVMCoreUIPageControlslides_currentpage_index" : @"MVMCoreUIPageControl_currentpage_index"; + return [NSString stringWithFormat:[MVMCoreUIUtility hardcodedStringWithKey:stringKey],self.currentPage+1, self.numberOfPages]; +} + +- (void)accessibilityIncrement { + [self accessibilityAdjustToPage:self.currentPage + 1]; +} + +- (void)accessibilityDecrement { + [self accessibilityAdjustToPage:self.currentPage -1]; +} + +//when self.awlaysSenfingControlEven it NO, and user is already at first or final index, if user try to increment or decrement, won't do action +//while self.awlaysSenfingControlEven is YES, it still send control event, while the rectangle won't change, need set currentPage again. +- (void)accessibilityAdjustToPage:(NSInteger)index { + if ((index < self.numberOfPages && index >= 0) || self.alwaysSendingControlEvent) { + [self setCurrentPage:index animated:NO]; + [self sendActionsForControlEvents:UIControlEventValueChanged]; + } +} + +#pragma mark - Animate pagecontrol indicator + +- (void)displayIndicator:(BOOL)animated { + if (!animated) { + return; + } + if (!self.isDoAnimating) { + self.indicatorRectangle.frame = CGRectMake(CGRectGetMinX(self.indicatorRectangle.frame), CGRectGetMinY(self.indicatorRectangle.frame) + IndicatorRectangleHeight, CGRectGetWidth(self.indicatorRectangle.frame), 0.f); + [UIView animateWithDuration:0.3f animations:^{ + self.isDoAnimating = YES; + self.indicatorRectangle.frame = CGRectMake(CGRectGetMinX(self.indicatorRectangle.frame), CGRectGetMinY(self.indicatorRectangle.frame)-IndicatorRectangleHeight, CGRectGetWidth(self.indicatorRectangle.frame), IndicatorRectangleHeight); + } completion:^(BOOL finished) { + self.isDoAnimating = NO; + }]; + } +} + +- (void)dismissAnimationIndicator:(BOOL)animated { + if (animated) { + if (!self.isDisAnimating) { + [UIView animateWithDuration:0.3f animations:^{ + self.isDisAnimating = YES; + self.animationRectangle.frame = CGRectMake(CGRectGetMinX(self.animationRectangle.frame), CGRectGetMinY(self.animationRectangle.frame) + IndicatorRectangleHeight, CGRectGetWidth(self.animationRectangle.frame), 0.f); + } completion:^(BOOL finished) { + [self layoutIfNeeded]; + self.animationRectangle.frame = self.indicatorRectangle.frame; + self.isDisAnimating = NO; + }]; + } + } else { + [self layoutIfNeeded]; + self.animationRectangle.frame = self.indicatorRectangle.frame; + } +} + +- (void)setTopBottomSpace:(CGFloat)constant { + self.bottomConstraint.constant = constant; + self.topConstraint.constant = constant; +} + +@end diff --git a/MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h b/MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h new file mode 100644 index 00000000..ac8aee3c --- /dev/null +++ b/MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h @@ -0,0 +1,22 @@ +// +// MVMCoreUIPagingProtocol.h +// MVMCoreUI +// +// Created by Scott Pfeil on 7/10/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// +#import + +@protocol MVMCoreUIPagingProtocol + +typedef void (^PagingTouchBlock)(NSObject* _Nonnull sender); + +- (NSInteger)currentPage; + +- (void)setNumberOfPages:(NSInteger)numberOfPages; + +- (void)setPage:(NSInteger)page; + +- (void)setPagingTouchBlock:(nullable PagingTouchBlock)pagingTouchBlock; + +@end diff --git a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift index d28819ac..2eb61e68 100644 --- a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift @@ -45,10 +45,9 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi } if let castView = molecule as? MVMCoreUIViewConstrainingProtocol { let standardConstraints = castView.useStandardConstraints?() ?? true - castView.shouldSetHorizontalMargins?(!standardConstraints) - castView.shouldSetVerticalMargins?(!standardConstraints) + castView.shouldSetHorizontalMargins?(standardConstraints) + castView.shouldSetVerticalMargins?(standardConstraints) } - backgroundColor = molecule?.backgroundColor } @@ -60,6 +59,6 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi } public func updateView(_ size: CGFloat) { - + molecule?.updateView(size) } } diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 61230208..325a8fed 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -14,6 +14,7 @@ #import "MVMCoreUIObject.h" #import #import "MFTextField.h" +#import "MVMCoreUIPageControl.h" #import "MVMCoreUIViewConstrainingProtocol.h" @implementation MVMCoreUIMoleculeMappingObject @@ -50,7 +51,8 @@ @"moduleMolecule": ModuleMolecule.class, @"headlineBody": HeadlineBody.class, @"carousel": Carousel.class, - @"carouselItem": MoleculeCollectionViewCell.class + @"carouselItem": MoleculeCollectionViewCell.class, + @"barsPager": MVMCoreUIPageControl.class, } mutableCopy]; }); return mapping; From 8866e91caa86612da557aff4af19fe9bb6e14d14 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 11 Jul 2019 16:11:58 -0400 Subject: [PATCH 11/62] add peaking logic --- MVMCoreUI/Molecules/Carousel.swift | 127 ++++-------------- MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h | 3 + .../MoleculeCollectionViewCell.swift | 60 ++++++++- .../Media.xcassets/Contents.json | 6 + .../peakingRightArrow.imageset/Contents.json | 23 ++++ .../E_UBI_003_G.png | Bin 0 -> 168 bytes .../E_UBI_003_G@2x.png | Bin 0 -> 275 bytes .../E_UBI_003_G@3x.png | Bin 0 -> 379 bytes 8 files changed, 115 insertions(+), 104 deletions(-) create mode 100644 MVMCoreUI/SupportingFiles/Media.xcassets/Contents.json create mode 100644 MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/Contents.json create mode 100644 MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G.png create mode 100644 MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G@2x.png create mode 100644 MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G@3x.png diff --git a/MVMCoreUI/Molecules/Carousel.swift b/MVMCoreUI/Molecules/Carousel.swift index cb0bbf2b..cb5d7243 100644 --- a/MVMCoreUI/Molecules/Carousel.swift +++ b/MVMCoreUI/Molecules/Carousel.swift @@ -45,7 +45,6 @@ open class Carousel: ViewConstrainingView { /// If the carousel should loop after scrolling past the first and final cells. var loop = false private var dragging = false - private var previousContentOffsetX: CGFloat = 0 // MARK: - MVMCoreViewProtocol open override func setupView() { @@ -73,6 +72,7 @@ open class Carousel: ViewConstrainingView { DispatchQueue.main.async { self.collectionView.scrollToItem(at: IndexPath(row: self.currentIndex, section: 0), at: self.itemAlignment, animated: false) self.collectionView.layoutIfNeeded() + self.showPeaking(true) } } @@ -201,6 +201,24 @@ open class Carousel: ViewConstrainingView { } self.pagingView = pagingView } + + open func showPeaking(_ peaking: Bool) { + if peaking { + // Show overlay and arrow in peaking Cell + let visibleItemsPaths = collectionView.indexPathsForVisibleItems.sorted { $0.row < $1.row } + if let firstItem = visibleItemsPaths.first, firstItem.row != currentIndex { + (collectionView.cellForItem(at: firstItem) as? MoleculeCollectionViewCell)?.setPeaking(true, animated: true) + } + if let lastItem = visibleItemsPaths.last, lastItem.row != currentIndex { + (collectionView.cellForItem(at: lastItem) as? MoleculeCollectionViewCell)?.setPeaking(true, animated: true) + } + } else { + // Hide peaking. + for item in collectionView.visibleCells { + (item as? MoleculeCollectionViewCell)?.setPeaking(false, animated: true) + } + } + } } extension Carousel: UICollectionViewDelegateFlowLayout { @@ -232,68 +250,6 @@ extension Carousel: UICollectionViewDataSource { } extension Carousel: UIScrollViewDelegate { - /*// For getting the scroll progress to set the page control color progress. - - (CGFloat)getPageControlPercentBasedOnScrollView:(UIScrollView *)scrollView { - CGFloat cardWidth = ((UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout).itemSize.width; - CGFloat separatorWidth = ((UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout).minimumLineSpacing; - CGFloat contentOfsetInCard = fmodf(scrollView.contentOffset.x, cardWidth + separatorWidth); - CGFloat endThresholdPageControl = cardWidth + separatorWidth - CGRectGetMaxX(self.pageControl.frame); - CGFloat progress = contentOfsetInCard - endThresholdPageControl; - CGFloat width = CGRectGetWidth(self.pageControl.bounds); - CGFloat percent = (width - progress)/width; - CGFloat cappedPercent = MAX(MIN(percent, 1), 0); - return cappedPercent; - } - - - (void)setPageControlColorsBasedOnScrollView:(UIScrollView *)scrollView { - - // Check if we will need to change colors. - BOOL needToShiftColors = NO; - NSInteger nextCardIndex = 0; - CGFloat cardWidth = ((UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout).itemSize.width; - CGFloat separatorWidth = ((UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout).minimumLineSpacing; - NSInteger currentCard = scrollView.contentOffset.x / (cardWidth + separatorWidth); - CGFloat cardStart = currentCard * (cardWidth + separatorWidth); - CGFloat cardEnd = cardStart + cardWidth + separatorWidth; - NSInteger pageIndicator = currentCard; - if ((self.previousContentOffsetX == NSNotFound || self.previousContentOffsetX <= cardStart) && scrollView.contentOffset.x >= cardStart) { - - // We are passed the threshold and moving right, change to right card color. - needToShiftColors = YES; - nextCardIndex = currentCard + 1; - pageIndicator = currentCard - 1; - } else if ((self.previousContentOffsetX == NSNotFound || self.previousContentOffsetX >= cardEnd) && scrollView.contentOffset.x < cardEnd) { - - // We are passed the threshold and moving left, change to left card color. - needToShiftColors = YES; - nextCardIndex = currentCard - 1; - } - - if (needToShiftColors) { - // Only shift the page control if we are dragging still, otherwise end animation will control. - if (self.dragging) { - [self.pageControl setCurrentPage:pageIndicator]; - } - - // Get the current page color - NSString *colorString = [[self.feedModules objectAtIndex:currentCard] string:KeyPageIndicatorColor]; - UIColor *currentCardPageControlColor = colorString ? [UIColor mfGetColorForHex:colorString] : [UIColor blackColor]; - - // Get the next page color and set accordingly. - colorString = [[self.feedModules dictionaryAtIndex:nextCardIndex] string:KeyPageIndicatorColor]; - UIColor *nextCardPageControlColor = colorString ? [UIColor mfGetColorForHex:colorString] : [UIColor blackColor]; - - // Which color needs to be on top or bottom depends on which direction we are moving. - if (nextCardIndex > currentCard) { - [self setPageControlColor:nextCardPageControlColor progressColor:currentCardPageControlColor]; - } else { - [self setPageControlColor:currentCardPageControlColor progressColor:nextCardPageControlColor]; - } - } - } - - */ - func handleUserOnBufferCell() { guard loop else { return @@ -302,7 +258,6 @@ extension Carousel: UIScrollViewDelegate { let lastPageIndex = numberOfPages + 1 let goToIndex = {(index: Int) in self.currentIndex = index - self.previousContentOffsetX = CGFloat(NSNotFound) self.collectionView.scrollToItem(at: IndexPath(row: self.currentIndex, section: 0), at: self.itemAlignment, animated: false) self.collectionView.layoutIfNeeded() self.pagingView?.setPage(self.pageIndex) @@ -337,24 +292,17 @@ extension Carousel: UIScrollViewDelegate { } public func scrollViewDidScroll(_ scrollView: UIScrollView) { + // Check if the user is dragging the card even further past the next card. checkForDraggingOutOfBounds(scrollView) - // Set the page control direction colors if needed. - //[self setPageControlColorsBasedOnScrollView:scrollView]; - - // Set the percent of progress. - //self.pageControl.progressView.progress = [self getPageControlPercentBasedOnScrollView:scrollView]; - - previousContentOffsetX = scrollView.contentOffset.x; + // Let the pager know our progress if needed. + pagingView?.scrollViewDidScroll?(collectionView) } public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { dragging = true - -// // Hide coverview and arrow. -// FeedBaseCollectionViewCell *peakingCell = (FeedBaseCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:self.currentIndex + 1 inSection:0]]; -// [peakingCell setPeaking:NO animated:YES]; + showPeaking(false) } public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { @@ -363,7 +311,7 @@ extension Carousel: UIScrollViewDelegate { // 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 + return } // We switch cards if we pass the velocity threshold or position threshold (currently 50%). @@ -381,11 +329,6 @@ extension Carousel: UIScrollViewDelegate { currentIndex = min(max(cellToSwipeTo, 0), lastCellIndex) collectionView.scrollToItem(at: IndexPath(row: currentIndex, section: 0), at: itemAlignment, animated: true) - - // Notify that card changed - /*if (self.cardChanged) { - self.cardChanged(self.currentIndex, [self.module string:[MFBaseHomeViewController getFeedContainerNameKey]]); - }*/ } // To give the illusion of endless scrolling. Since we are always calling scrollToItem we can assume finished paging in here. @@ -394,27 +337,7 @@ extension Carousel: UIScrollViewDelegate { handleUserOnBufferCell() pagingView?.setPage(pageIndex) - /* - // Update to the new page in the control if needed. - if (self.currentIndex - 1 != self.pageControl.currentPage) { - [self.pageControl setCurrentPage:self.currentIndex - 1]; - } - // Show overlay and arrow in next Cell - FeedBaseCollectionViewCell *nextCell = (FeedBaseCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:self.currentIndex + 1 inSection:0]]; - [nextCell setPeaking:YES animated:YES]; - FeedBaseCollectionViewCell *currentCell = (FeedBaseCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:self.currentIndex inSection:0]]; - if (currentCell) { - self.accessibilityElements = @[currentCell.containerView, self.pageControl]; - currentCell.containerView.isAccessibilityElement = YES; - currentCell.accessibilityElementsHidden = NO; - UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification,currentCell.containerView); - } - - // Set the page control again if pageControl is tapped or voice over is using. - [self setPageControlColorsBasedOnScrollView:scrollView]; - - // send adobe tracker action - [self sendAdobeTrackerAction];*/ + showPeaking(true) } } diff --git a/MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h b/MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h index ac8aee3c..89dd279b 100644 --- a/MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h +++ b/MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h @@ -18,5 +18,8 @@ typedef void (^PagingTouchBlock)(NSObject* _Nonnull sen - (void)setPage:(NSInteger)page; - (void)setPagingTouchBlock:(nullable PagingTouchBlock)pagingTouchBlock; + +@optional +- (void)scrollViewDidScroll:(nonnull UICollectionView *)collectionView; @end diff --git a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift index 2eb61e68..23850e70 100644 --- a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift @@ -11,6 +11,11 @@ import UIKit open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol { open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)? + open var allowsPeaking = false + var peakingLeftArrow = UIImageView(image: MVMCoreUIUtility.imageNamed("peakingRightArrow")?.withRenderingMode(.alwaysTemplate)) + var peakingRightArrow = UIImageView(image: MVMCoreUIUtility.imageNamed("peakingRightArrow")?.withRenderingMode(.alwaysTemplate)) + var peakingCover = MVMCoreUICommonViewsUtility.commonView() + public override init(frame: CGRect) { super.init(frame: .zero) setupView() @@ -22,15 +27,49 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi } public func setupView() { + guard peakingCover.superview == nil else { + return + } + // Covers the card when peaking. + peakingCover.backgroundColor = .white + peakingCover.alpha = 0 + contentView.addSubview(peakingCover) + NSLayoutConstraint.constraintPinSubview(toSuperview: peakingCover) + + // A small arrow on the next card for when peaking. + let ratio: CGFloat = 0.015 + peakingLeftArrow.translatesAutoresizingMaskIntoConstraints = false + peakingLeftArrow.alpha = 0 + peakingLeftArrow.tintColor = .black + contentView.addSubview(peakingLeftArrow) + peakingLeftArrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true + NSLayoutConstraint.scalingPinViewLeft(toSuper: peakingLeftArrow, ratio: ratio, anchor: contentView.widthAnchor) + + peakingRightArrow.translatesAutoresizingMaskIntoConstraints = false + peakingRightArrow.transform = CGAffineTransform(scaleX: -1, y: 1) // Flip + peakingRightArrow.alpha = 0 + peakingRightArrow.tintColor = .black + contentView.addSubview(peakingRightArrow) + peakingRightArrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true + NSLayoutConstraint.scalingPinViewRight(toSuper: peakingRightArrow, ratio: ratio, anchor: contentView.widthAnchor) } public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { + + // Handles peaking. + allowsPeaking = json?.optionalBoolForKey("peakingUI") ?? true + if let peakingArrowColor = json?.optionalStringForKey("peakingArrowColor") { + let color = UIColor.mfGet(forHex: peakingArrowColor) + peakingLeftArrow.tintColor = color + peakingRightArrow.tintColor = color + } + + guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule) else { return } if molecule == nil { if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) { - contentView.addSubview(moleculeView) + contentView.insertSubview(moleculeView, at: 0) let standardConstraints = (moleculeView as? MVMCoreUIViewConstrainingProtocol)?.useStandardConstraints?() ?? true NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: standardConstraints).values)) if standardConstraints { @@ -61,4 +100,21 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi public func updateView(_ size: CGFloat) { molecule?.updateView(size) } + + public func setPeaking(_ peaking: Bool, animated: Bool) { + guard allowsPeaking else { + return + } + let animation = {() in + self.peakingRightArrow.alpha = peaking ? 1 : 0 + self.peakingLeftArrow.alpha = peaking ? 1 : 0 + self.peakingCover.alpha = peaking ? 0.5 : 0 + print("\(self.peakingCover.alpha)") + } + if animated { + UIView.animate(withDuration: 0.4, animations: animation) + } else { + animation() + } + } } diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/Contents.json b/MVMCoreUI/SupportingFiles/Media.xcassets/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MVMCoreUI/SupportingFiles/Media.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/Contents.json b/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/Contents.json new file mode 100644 index 00000000..0851ce22 --- /dev/null +++ b/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "E_UBI_003_G.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "E_UBI_003_G@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "E_UBI_003_G@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G.png b/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G.png new file mode 100644 index 0000000000000000000000000000000000000000..8c789309b9b6158736aa92340a311bfe13a7e644 GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&k#^NA%Cx&(BWL^R}NuDl_AsV8| z2?zKNH6A*8W9f!&BgWR}jD?zInQs;;_!c+pVA^d`7U;I%Lyp3_LwdcjB1gTe~DWM4fpzt|a literal 0 HcmV?d00001 diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G@2x.png b/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b6453e48a2bbeceeb317ec1000da984b4aa7b85c GIT binary patch literal 275 zcmV+u0qp*XP)Px#%}GQ-R7efgmfZ>gQ5Z!Tf8!ZEpd?9}lH7R;4?!Z4+`0BjSX;Srv%i|}!l^aQ z#oF!pJLgQR;g2Tj1_to(W4>9U-rxx%KNd6l=vPq5I2QG7-N^-BF!5tCQzd6m$ut)A z?H=k0R5J5pF|&()1eMHVQQua{0aQ}?v6$IG--AjPv8ZpWWCto)`mva)k}arYrDz-O zI;nA}L}Lv_@j3mY!_OnC^V(BivgShCXPP?EQkRO<#V&QZPTg=)w@h7m>ZbqwZ5c*p Z=Nk_lFH7J3S+M{B002ovPDHLkV1fd9cWnRw literal 0 HcmV?d00001 diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G@3x.png b/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..7fe147c7942353596fc01b9c9427daea9b2012e7 GIT binary patch literal 379 zcmV->0fhdEP)Px$HAzH4R9Fekm`REPK@dgN+Bvt{M{wbpM4S*25fNz+L3-2B_h=VhLs1l^6^HXU z{D4Xb3S0$L{eVwco1c$LD>5>?m_0mL{6R_RX1B9D{KDc1-JzP@&hGFDi!0=y>UK-J zLkSia1=X}$+8v6pIQvi!OgF#}W@5NieX#R9cbP!k5I6d;xg zYU-fk_)&HbA!q5I7Er}scZU2UKvExA;yb}Y;yCEG%z=fS-~Oq?29foo7SVk6RE3f1 z=#Uei=5VEIKd2fssuq^2$)~yoQC$>+SLv3N<)|V!Y-mIUBJ0wPW9SA}GSZtvRe4?3 ZcmYEIX$}#dZKD7H002ovPDHLkV1lz)oE888 literal 0 HcmV?d00001 From 39cb9302636ec7367d5f00d213a407eefe720b5c Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Fri, 12 Jul 2019 10:25:42 -0400 Subject: [PATCH 12/62] accessibility and page control fixes --- MVMCoreUI/Molecules/Carousel.swift | 36 +++++++++++++------ MVMCoreUI/Molecules/MVMCoreUIPageControl.m | 3 +- .../MoleculeCollectionViewCell.swift | 4 ++- .../Strings/en.lproj/Localizable.strings | 3 ++ .../Strings/es-MX.lproj/Localizable.strings | 3 ++ .../Strings/es.lproj/Localizable.strings | 3 ++ 6 files changed, 40 insertions(+), 12 deletions(-) diff --git a/MVMCoreUI/Molecules/Carousel.swift b/MVMCoreUI/Molecules/Carousel.swift index cb5d7243..27cc59f6 100644 --- a/MVMCoreUI/Molecules/Carousel.swift +++ b/MVMCoreUI/Molecules/Carousel.swift @@ -57,6 +57,7 @@ open class Carousel: ViewConstrainingView { collectionView.delegate = self collectionView.showsHorizontalScrollIndicator = false collectionView.backgroundColor = .clear + collectionView.isAccessibilityElement = false addSubview(collectionView) pinView(toSuperView: collectionView) @@ -117,7 +118,7 @@ open class Carousel: ViewConstrainingView { // Sets up the row data with buffer cells on each side (for illusion of endless scroll... also has one more buffer cell on each side in case we can peek that cell). loop = true molecules?.insert(newMolecules.last!, at: 0) - molecules?.insert(newMolecules[(newMolecules.count - 1)], at: 0) + molecules?.insert(newMolecules[(newMolecules.count - 2)], at: 0) molecules?.append(newMolecules.first!) molecules?.append(newMolecules[1]) } @@ -140,6 +141,7 @@ open class Carousel: ViewConstrainingView { var pagingView: (UIView & MVMCoreUIPagingProtocol)? = nil if let json = json { pagingView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: json, delegateObject: delegateObject, constrainIfNeeded: true) as? (UIView & MVMCoreUIPagingProtocol) + pagingView?.isAccessibilityElement = true } addPaging(view: pagingView, position: (json?.optionalCGFloatForKey("position") ?? 20)) } @@ -196,7 +198,7 @@ open class Carousel: ViewConstrainingView { } let currentPage = pager.currentPage() localSelf.pageIndex = currentPage - self?.collectionView.scrollToItem(at: IndexPath(row: localSelf.currentIndex, section: 0), at: (self?.itemAlignment ?? .left), animated: true) + localSelf.goTo(localSelf.currentIndex, animated: !UIAccessibility.isVoiceOverRunning) }) } self.pagingView = pagingView @@ -244,12 +246,27 @@ extension Carousel: UICollectionViewDataSource { protocolCell.setWithJSON(moleculeInfo.molecule, delegateObject: nil, additionalData: nil) protocolCell.updateView(collectionView.bounds.width) } + + if indexPath.row == currentIndex { + cell.accessibilityElementsHidden = false +// self.accessibilityElements = @[cell.containerView, self.pageControl]; + } else { + cell.accessibilityElementsHidden = true + } return cell } } extension Carousel: UIScrollViewDelegate { + + func goTo(_ index: Int, animated: Bool) { + collectionView.cellForItem(at: IndexPath(row: self.currentIndex, section: 0))?.accessibilityElementsHidden = true + self.currentIndex = index + collectionView.cellForItem(at: IndexPath(row: self.currentIndex, section: 0))?.accessibilityElementsHidden = false + self.collectionView.scrollToItem(at: IndexPath(row: self.currentIndex, section: 0), at: self.itemAlignment, animated: animated) + } + func handleUserOnBufferCell() { guard loop else { return @@ -257,8 +274,7 @@ extension Carousel: UIScrollViewDelegate { let lastPageIndex = numberOfPages + 1 let goToIndex = {(index: Int) in - self.currentIndex = index - self.collectionView.scrollToItem(at: IndexPath(row: self.currentIndex, section: 0), at: self.itemAlignment, animated: false) + self.goTo(index, animated: false) self.collectionView.layoutIfNeeded() self.pagingView?.setPage(self.pageIndex) } @@ -279,11 +295,11 @@ extension Carousel: UIScrollViewDelegate { // 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 * itemWidthPercent - let index = Int(scrollView.contentOffset.x / (itemWidth + separatorWidth)) + let index = scrollView.contentOffset.x / (itemWidth + separatorWidth) let lastCellIndex = collectionView(collectionView, numberOfItemsInSection: 0) - 1 - if index < 0 { + if index < 1 { self.currentIndex = 0 - } else if index > lastCellIndex { + } else if index > CGFloat(lastCellIndex - 1) { self.currentIndex = lastCellIndex } } @@ -326,9 +342,7 @@ extension Carousel: UIScrollViewDelegate { } // Cap the index. - currentIndex = min(max(cellToSwipeTo, 0), lastCellIndex) - - collectionView.scrollToItem(at: IndexPath(row: currentIndex, section: 0), at: itemAlignment, animated: true) + 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. @@ -339,5 +353,7 @@ extension Carousel: UIScrollViewDelegate { pagingView?.setPage(pageIndex) showPeaking(true) + + //UIAccessibility.post(notification: .layoutChanged, argument: currentIndex) UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification,currentCell.containerView); } } diff --git a/MVMCoreUI/Molecules/MVMCoreUIPageControl.m b/MVMCoreUI/Molecules/MVMCoreUIPageControl.m index e5855f7d..cbfe0300 100644 --- a/MVMCoreUI/Molecules/MVMCoreUIPageControl.m +++ b/MVMCoreUI/Molecules/MVMCoreUIPageControl.m @@ -302,7 +302,7 @@ static CGFloat const IndicatorRectangleHeight = 4; #pragma mark - MVMCoreUIPagingProtocol -- (void)setPage:(NSUInteger)page { +- (void)setPage:(NSInteger)page { self.currentPage = page; } @@ -349,6 +349,7 @@ static CGFloat const IndicatorRectangleHeight = 4; if ((index < self.numberOfPages && index >= 0) || self.alwaysSendingControlEvent) { [self setCurrentPage:index animated:NO]; [self sendActionsForControlEvents:UIControlEventValueChanged]; + self.pagingTouchBlock(self); } } diff --git a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift index 23850e70..82d7f4a2 100644 --- a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift @@ -30,6 +30,9 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi guard peakingCover.superview == nil else { return } + isAccessibilityElement = false + contentView.isAccessibilityElement = false + // Covers the card when peaking. peakingCover.backgroundColor = .white peakingCover.alpha = 0 @@ -109,7 +112,6 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi self.peakingRightArrow.alpha = peaking ? 1 : 0 self.peakingLeftArrow.alpha = peaking ? 1 : 0 self.peakingCover.alpha = peaking ? 0.5 : 0 - print("\(self.peakingCover.alpha)") } if animated { UIView.animate(withDuration: 0.4, animations: animation) diff --git a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings index 96088cab..2e7677f3 100644 --- a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings @@ -40,6 +40,9 @@ "AccOn" = "on"; "AccOff" = "off"; "AccToggleHint" = "double tap to toggle"; +// Carousel +"MVMCoreUIPageControl_currentpage_index" = "page %ld of %ld"; +"MVMCoreUIPageControlslides_currentpage_index" = "slide %ld of %ld"; //Styler "CountDownDay" = " day"; "CountDownHour" = " hour"; diff --git a/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings index a006b218..bf4f4e47 100644 --- a/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings @@ -39,6 +39,9 @@ "AccOn" = "encendido"; "AccOff" = "apagado"; "AccToggleHint" = "toca dos veces para alternar"; +// Carousel +"MVMCoreUIPageControl_currentpage_index" = "página %ld de %ld"; +"MVMCoreUIPageControlslides_currentpage_index" = "diapositiva %ld of %ld"; //Styler "CountDownDay" = " día"; "CountDownHour" = " hora"; diff --git a/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings index a006b218..bf4f4e47 100644 --- a/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings @@ -39,6 +39,9 @@ "AccOn" = "encendido"; "AccOff" = "apagado"; "AccToggleHint" = "toca dos veces para alternar"; +// Carousel +"MVMCoreUIPageControl_currentpage_index" = "página %ld de %ld"; +"MVMCoreUIPageControlslides_currentpage_index" = "diapositiva %ld of %ld"; //Styler "CountDownDay" = " día"; "CountDownHour" = " hora"; From 5e2d0093130a683ff50f881cc1479b2cca67dac2 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Fri, 12 Jul 2019 14:49:16 -0400 Subject: [PATCH 13/62] accessibility --- MVMCoreUI/Atoms/Views/ViewConstrainingView.h | 3 ++ MVMCoreUI/Atoms/Views/ViewConstrainingView.m | 13 ++++++ MVMCoreUI/Molecules/Carousel.swift | 45 ++++++++++++------- MVMCoreUI/Molecules/MVMCoreUIPageControl.m | 2 + MVMCoreUI/Molecules/ModuleMolecule.swift | 7 +++ .../MoleculeCollectionViewCell.swift | 9 +--- MVMCoreUI/Molecules/MoleculeStackView.swift | 9 +--- 7 files changed, 59 insertions(+), 29 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.h b/MVMCoreUI/Atoms/Views/ViewConstrainingView.h index 9ec6c193..acf451a8 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.h +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.h @@ -85,4 +85,7 @@ /// Convenience function for getting the alignment from a map. + (UIStackViewAlignment)getAlignmentForString:(nullable NSString *)alignmentString defaultAlignment:(UIStackViewAlignment)defaultAlignment; +/// Makes the view isAccessibilityElement false and adds molecule elements to accessbilityElements. +- (void)setMoleculeAccessibility; + @end diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m index 093e1ecc..c6152bcc 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m @@ -27,6 +27,7 @@ [self addConstrainedView:molecule alignment:alignment]; [self setAsMolecule]; } + [self setMoleculeAccessibility]; self.molecule = molecule; } return self; @@ -327,6 +328,17 @@ #pragma mark - MVMCoreUIMoleculeViewProtocol +- (void)setMoleculeAccessibility { + if (self.molecule) { + self.isAccessibilityElement = NO; + if (self.molecule.accessibilityElements) { + self.accessibilityElements = self.molecule.accessibilityElements; + } else { + self.accessibilityElements = @[self.molecule]; + } + } +} + - (void)reset { if ([self.molecule respondsToSelector:@selector(reset)]) { [self.molecule performSelector:@selector(reset)]; @@ -350,6 +362,7 @@ [self pinViewToSuperView:molecule]; } } + [self setMoleculeAccessibility]; } if (self.molecule) { if ([self.molecule respondsToSelector:@selector(copyBackgroundColor)] && [self.molecule performSelector:@selector(copyBackgroundColor)]) { diff --git a/MVMCoreUI/Molecules/Carousel.swift b/MVMCoreUI/Molecules/Carousel.swift index 27cc59f6..082fcd6d 100644 --- a/MVMCoreUI/Molecules/Carousel.swift +++ b/MVMCoreUI/Molecules/Carousel.swift @@ -68,7 +68,8 @@ open class Carousel: ViewConstrainingView { open override func updateView(_ size: CGFloat) { super.updateView(size) collectionView.collectionViewLayout.invalidateLayout() - + 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. DispatchQueue.main.async { self.collectionView.scrollToItem(at: IndexPath(row: self.currentIndex, section: 0), at: self.itemAlignment, animated: false) @@ -141,7 +142,6 @@ open class Carousel: ViewConstrainingView { var pagingView: (UIView & MVMCoreUIPagingProtocol)? = nil if let json = json { pagingView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: json, delegateObject: delegateObject, constrainIfNeeded: true) as? (UIView & MVMCoreUIPagingProtocol) - pagingView?.isAccessibilityElement = true } addPaging(view: pagingView, position: (json?.optionalCGFloatForKey("position") ?? 20)) } @@ -205,7 +205,7 @@ open class Carousel: ViewConstrainingView { } open func showPeaking(_ peaking: Bool) { - if peaking { + if peaking && !UIAccessibility.isVoiceOverRunning { // Show overlay and arrow in peaking Cell let visibleItemsPaths = collectionView.indexPathsForVisibleItems.sorted { $0.row < $1.row } if let firstItem = visibleItemsPaths.first, firstItem.row != currentIndex { @@ -221,6 +221,26 @@ open class Carousel: ViewConstrainingView { } } } + + func setAccessiblity(_ cell: UICollectionViewCell?, index: Int) { + guard let cell = cell else { + return + } + if index == currentIndex { + cell.accessibilityElementsHidden = false + var array = cell.accessibilityElements + + if let acc = pagingView?.accessibilityElements { + array?.append(contentsOf: acc) + } else { + array?.append(pagingView!) + } + + self.accessibilityElements = array + } else { + cell.accessibilityElementsHidden = true + } + } } extension Carousel: UICollectionViewDelegateFlowLayout { @@ -246,14 +266,7 @@ extension Carousel: UICollectionViewDataSource { protocolCell.setWithJSON(moleculeInfo.molecule, delegateObject: nil, additionalData: nil) protocolCell.updateView(collectionView.bounds.width) } - - if indexPath.row == currentIndex { - cell.accessibilityElementsHidden = false -// self.accessibilityElements = @[cell.containerView, self.pageControl]; - } else { - cell.accessibilityElementsHidden = true - } - + setAccessiblity(cell, index: indexPath.row) return cell } } @@ -261,10 +274,14 @@ extension Carousel: UICollectionViewDataSource { extension Carousel: UIScrollViewDelegate { func goTo(_ index: Int, animated: Bool) { - collectionView.cellForItem(at: IndexPath(row: self.currentIndex, section: 0))?.accessibilityElementsHidden = true + showPeaking(false) + setAccessiblity(collectionView.cellForItem(at: IndexPath(row: self.currentIndex, section: 0)), index: index) self.currentIndex = index - collectionView.cellForItem(at: IndexPath(row: self.currentIndex, section: 0))?.accessibilityElementsHidden = false self.collectionView.scrollToItem(at: IndexPath(row: self.currentIndex, section: 0), at: self.itemAlignment, animated: animated) + if let cell = collectionView.cellForItem(at: IndexPath(row: self.currentIndex, section: 0)) { + setAccessiblity(collectionView.cellForItem(at: IndexPath(row: self.currentIndex, section: 0)), index: index) + UIAccessibility.post(notification: .layoutChanged, argument: cell) + } } func handleUserOnBufferCell() { @@ -353,7 +370,5 @@ extension Carousel: UIScrollViewDelegate { pagingView?.setPage(pageIndex) showPeaking(true) - - //UIAccessibility.post(notification: .layoutChanged, argument: currentIndex) UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification,currentCell.containerView); } } diff --git a/MVMCoreUI/Molecules/MVMCoreUIPageControl.m b/MVMCoreUI/Molecules/MVMCoreUIPageControl.m index cbfe0300..16783ca9 100644 --- a/MVMCoreUI/Molecules/MVMCoreUIPageControl.m +++ b/MVMCoreUI/Molecules/MVMCoreUIPageControl.m @@ -241,6 +241,8 @@ static CGFloat const IndicatorRectangleHeight = 4; - (void)setupView { if (!self.containerView) { + self.isAccessibilityElement = YES; + // Create a container view that keeps everything centered UIView *containerView = [MVMCoreUICommonViewsUtility commonView]; [self addSubview:containerView]; diff --git a/MVMCoreUI/Molecules/ModuleMolecule.swift b/MVMCoreUI/Molecules/ModuleMolecule.swift index 7781021f..c993b0c2 100644 --- a/MVMCoreUI/Molecules/ModuleMolecule.swift +++ b/MVMCoreUI/Molecules/ModuleMolecule.swift @@ -31,6 +31,13 @@ open class ModuleMolecule: ViewConstrainingView { addSubview(moleculeView) NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: false).values)) moduleMolecule = moleculeView + + isAccessibilityElement = false + if moleculeView.accessibilityElements != nil { + accessibilityElements = moleculeView.accessibilityElements + } else { + accessibilityElements = [moleculeView] + } } } else { moduleMolecule?.setWithJSON(module, delegateObject: delegateObject, additionalData: additionalData) diff --git a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift index 82d7f4a2..5f18d454 100644 --- a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift @@ -73,13 +73,7 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi if molecule == nil { if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) { contentView.insertSubview(moleculeView, at: 0) - let standardConstraints = (moleculeView as? MVMCoreUIViewConstrainingProtocol)?.useStandardConstraints?() ?? true - NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: standardConstraints).values)) - if standardConstraints { - let constraint = contentView.heightAnchor.constraint(equalToConstant: 80) - constraint.priority = .defaultLow - constraint.isActive = true - } + NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: false).values)) molecule = moleculeView } } else { @@ -91,6 +85,7 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi castView.shouldSetVerticalMargins?(standardConstraints) } backgroundColor = molecule?.backgroundColor + accessibilityElements = molecule?.subviews } public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { diff --git a/MVMCoreUI/Molecules/MoleculeStackView.swift b/MVMCoreUI/Molecules/MoleculeStackView.swift index 3183800f..f769bb05 100644 --- a/MVMCoreUI/Molecules/MoleculeStackView.swift +++ b/MVMCoreUI/Molecules/MoleculeStackView.swift @@ -175,13 +175,8 @@ public class MoleculeStackView: ViewConstrainingView { spacing = json?.optionalCGFloatForKey("spacing") ?? 16 // Set the alignment for the stack in the containing view. The json driven value is for the axis direction alignment. - if axis == .vertical { - alignHorizontal(.fill) - alignVertical(ViewConstrainingView.getAlignmentFor(json?.optionalStringForKey("alignment"), defaultAlignment: .fill)) - } else { - alignHorizontal(ViewConstrainingView.getAlignmentFor(json?.optionalStringForKey("alignment"), defaultAlignment: .fill)) - alignVertical(.fill) - } + alignHorizontal(ViewConstrainingView.getAlignmentFor(json?.optionalStringForKey("horizontalAlignment"), defaultAlignment: .fill)) + alignVertical(ViewConstrainingView.getAlignmentFor(json?.optionalStringForKey("verticalAlignment"), defaultAlignment: .fill)) // Adds the molecules and sets the json. for (index, map) in molecules.enumerated() { From 3fefff2d518e355e3a997024ed4af28b469caf11 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Mon, 15 Jul 2019 10:41:41 -0400 Subject: [PATCH 14/62] still need to workout how to know when to use margins... --- MVMCoreUI/Molecules/MoleculeStackView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/MVMCoreUI/Molecules/MoleculeStackView.swift b/MVMCoreUI/Molecules/MoleculeStackView.swift index f769bb05..74178f5f 100644 --- a/MVMCoreUI/Molecules/MoleculeStackView.swift +++ b/MVMCoreUI/Molecules/MoleculeStackView.swift @@ -140,6 +140,7 @@ public class MoleculeStackView: ViewConstrainingView { public override func shouldSetHorizontalMargins(_ shouldSet: Bool) { super.shouldSetHorizontalMargins(shouldSet) + updateViewHorizontalDefaults = false moleculesShouldSetHorizontalMargins = (shouldSet && axis == .vertical) for item in items { (item.view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(moleculesShouldSetHorizontalMargins) From b8b1e0ddba0cc7ad1976380c0cdfa0fb0242b4df Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Mon, 15 Jul 2019 11:43:42 -0400 Subject: [PATCH 15/62] Expose status bar color setting. --- MVMCoreUI/TopAlert/MVMCoreUITopAlertView.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.h b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.h index 5f49eb13..9850cca3 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.h +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.h @@ -50,4 +50,7 @@ // Get the background color based on the type - (nonnull UIColor *)getBackgroundColorForType:(nullable NSString *)type; +// Set the status bar color. Used for updating the status bar when the view changes. +- (void)setStatusBarColor:(nullable UIColor *)statusBarColor statusBarStyle:(UIStatusBarStyle)style; + @end From 9444df4d7c2112bffb717e1b8d3f6c943c6bf30f Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 16 Jul 2019 10:25:53 -0400 Subject: [PATCH 16/62] latest take on listitemwithimage. --- MVMCoreUI/Atoms/Views/ListItemWithImage.swift | 32 ++++++------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/ListItemWithImage.swift b/MVMCoreUI/Atoms/Views/ListItemWithImage.swift index dc0fc68a..334020e4 100644 --- a/MVMCoreUI/Atoms/Views/ListItemWithImage.swift +++ b/MVMCoreUI/Atoms/Views/ListItemWithImage.swift @@ -17,15 +17,13 @@ import UIKit let title = Label.commonLabelH3(true) let message = Label.commonLabelB3(true) let button = PrimaryButton.primaryTinyButton(false)! - let imageLoader = MFLoadImageView() + let imageLoader = MFLoadImageView(pinnedEdges: .all) let leftContainer = ViewConstrainingView.empty() //------------------------------------------------------ // MARK: - Constraints //------------------------------------------------------ - var imageWidthConstraint: NSLayoutConstraint? - var imageHeightConstraint: NSLayoutConstraint? var imageLeadingConstraint: NSLayoutConstraint? var buttonTopConstraint: NSLayoutConstraint? var messageTopConstraint: NSLayoutConstraint? @@ -58,6 +56,8 @@ import UIKit override open func setupView() { super.setupView() + imageLoader.addSizeConstraintsForAspectRatio = true + guard subviews.isEmpty else { return } button.setAsSecondaryCustom() @@ -96,16 +96,10 @@ import UIKit imageLoader.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true layoutMarginsGuide.trailingAnchor.constraint(equalTo: imageLoader.trailingAnchor).isActive = true - imageLeadingConstraint = imageLoader.leadingAnchor.constraint(greaterThanOrEqualTo: leftContainer.trailingAnchor, constant: 16) + imageLeadingConstraint = imageLoader.leadingAnchor.constraint(equalTo: leftContainer.trailingAnchor, constant: 16) imageLeadingConstraint?.isActive = true imageLoader.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true - imageHeightConstraint = imageLoader.heightAnchor.constraint(equalToConstant: 0) - imageHeightConstraint?.isActive = true - - imageWidthConstraint = imageLoader.widthAnchor.constraint(equalToConstant: 0) - imageWidthConstraint?.isActive = true - bottomAnchor.constraint(greaterThanOrEqualTo: imageLoader.bottomAnchor).isActive = true let imageloaderBottom = imageLoader.bottomAnchor.constraint(equalTo: bottomAnchor) imageloaderBottom.priority = UILayoutPriority(249) @@ -114,7 +108,7 @@ import UIKit override open func updateView(_ size: CGFloat) { super.updateView(size) - + title.updateView(size) message.updateView(size) button.updateView(size) @@ -123,19 +117,18 @@ import UIKit messageTopConstraint?.constant = title.hasText ? PaddingOne : 0 buttonTopConstraint?.constant = message.hasText ? PaddingTwo : (title.hasText ? PaddingOne : 0) - - if imageWidthConstraint?.constant == 0 { - imageLeadingConstraint?.constant = 0 - } } + //------------------------------------------------------ + // MARK: - Methods + //------------------------------------------------------ + override open func reset() { super.reset() title.text = "" message.text = "" imageLoader.imageView.image = nil - imageWidthConstraint?.constant = 0 imageLeadingConstraint?.constant = 16 backgroundColor = nil } @@ -144,15 +137,10 @@ import UIKit super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) guard let dictionary = json else { return } - + title.setWithJSON(dictionary.optionalDictionaryForKey("title"), delegateObject: delegateObject, additionalData: additionalData) message.setWithJSON(dictionary.optionalDictionaryForKey("message"), delegateObject: delegateObject, additionalData: additionalData) button.setWithJSON(dictionary.optionalDictionaryForKey("button"), delegateObject: delegateObject, additionalData: additionalData) imageLoader.setWithJSON(dictionary.optionalDictionaryForKey("image"), delegateObject: delegateObject, additionalData: additionalData) - - if let imageJSON = dictionary.optionalDictionaryForKey("image") { - imageWidthConstraint?.constant = CGFloat(imageJSON.floatForKey("width")) - imageHeightConstraint?.constant = CGFloat(imageJSON.floatForKey("height")) - } } } From ecf34bb34d5ce35d7cbc437171915785b27a7637 Mon Sep 17 00:00:00 2001 From: vasavk Date: Thu, 18 Jul 2019 15:45:52 +0530 Subject: [PATCH 17/62] Added multiLabelListItem - iOS as per MOBFIRST-17824 Signed-off-by: vasavk --- MVMCoreUI.xcodeproj/project.pbxproj | 4 ++ MVMCoreUI/Molecules/MultiLabelListItem.swift | 48 +++++++++++++++++++ .../MVMCoreUIMoleculeMappingObject.m | 1 + 3 files changed, 53 insertions(+) create mode 100644 MVMCoreUI/Molecules/MultiLabelListItem.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 04c2b811..9c0e69fa 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */; }; 01DF567021FA5AB300CC099B /* TextFieldListFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */; }; 01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; }; + 18423C7E22E07B260069C7B7 /* MultiLabelListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18423C7D22E07B260069C7B7 /* MultiLabelListItem.swift */; }; B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; }; B8200E192281DC1A007245F4 /* ProgressBarWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */; }; D206997721FB8A0B00CAE0DE /* MVMCoreUINavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -187,6 +188,7 @@ 01CA51B4229716F60071A6EE /* Switch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Switch.swift; sourceTree = ""; }; 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = ""; }; 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = ""; }; + 18423C7D22E07B260069C7B7 /* MultiLabelListItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiLabelListItem.swift; sourceTree = ""; }; B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarWithLabel.swift; sourceTree = ""; }; D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUINavigationController.h; sourceTree = ""; }; @@ -459,6 +461,7 @@ D29DF10E21E67A77003B2FB9 /* Molecules */ = { isa = PBXGroup; children = ( + 18423C7D22E07B260069C7B7 /* MultiLabelListItem.swift */, 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */, D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */, D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */, @@ -901,6 +904,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 18423C7E22E07B260069C7B7 /* MultiLabelListItem.swift in Sources */, D29DF32121ED0CBA003B2FB9 /* LabelView.m in Sources */, DBC4391822442197001AB423 /* CaretView.swift in Sources */, D29770F221F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m in Sources */, diff --git a/MVMCoreUI/Molecules/MultiLabelListItem.swift b/MVMCoreUI/Molecules/MultiLabelListItem.swift new file mode 100644 index 00000000..adbd7cf3 --- /dev/null +++ b/MVMCoreUI/Molecules/MultiLabelListItem.swift @@ -0,0 +1,48 @@ +// +// multiLabelListItem.swift +// MVMCoreUI +// +// Created by Kanamarlapudi, Vasavi on 15/7/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers public class MultiLabelListItem: ViewConstrainingView { + + var moleculestackview = MoleculeStackView(frame: .zero) + + open override func needsToBeConstrained() -> Bool { + return true + } + + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + + let moleculestackjson = json?.optionalDictionaryForKey("moleculeStack") + moleculestackview.setWithJSON(moleculestackjson, delegateObject: delegateObject, additionalData: additionalData) + moleculestackview.useStackSpacingBeforeFirstItem = true + } + + override open func setupView() { + super.setupView() + addSubview(moleculestackview) + + moleculestackview.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true + moleculestackview.topAnchor.constraint(equalTo: self.topAnchor).isActive = true + let topleftwidthconstraint = NSLayoutConstraint(item: moleculestackview, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 0.5, constant: 0.0) + topleftwidthconstraint.priority = UILayoutPriority(100) + topleftwidthconstraint.isActive = true + moleculestackview.setContentHuggingPriority(UILayoutPriority(911), for: .horizontal) + moleculestackview.setContentHuggingPriority(UILayoutPriority(911), for: .vertical) + + var bottomconstraint = bottomAnchor.constraint(equalTo: moleculestackview.bottomAnchor, constant: PaddingTwo) + bottomconstraint.priority = UILayoutPriority(249) + bottomconstraint.isActive = true + bottomAnchor.constraint(greaterThanOrEqualTo: moleculestackview.bottomAnchor, constant: PaddingTwo).isActive = true + bottomconstraint = bottomAnchor.constraint(equalTo: moleculestackview.bottomAnchor, constant: PaddingTwo) + bottomconstraint.priority = UILayoutPriority(249) + bottomconstraint.isActive = true + bottomAnchor.constraint(greaterThanOrEqualTo: moleculestackview.bottomAnchor, constant: PaddingTwo).isActive = true + } +} diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 67279c6e..b45255e4 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -48,6 +48,7 @@ @"image": MFLoadImageView.class, @"leftRightLabelView": LeftRightLabelView.class, @"moduleMolecule": ModuleMolecule.class, + @"multiLabelListItem": MultiLabelListItem.class, @"headlineBody": HeadlineBody.class } mutableCopy]; }); From 5b1fab39a7960e11a743839f2cbd803a3de8ed4a Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Fri, 19 Jul 2019 10:14:51 -0400 Subject: [PATCH 18/62] alignment defaults change --- MVMCoreUI/Atoms/Views/MFView.m | 2 +- MVMCoreUI/Atoms/Views/ViewConstrainingView.h | 3 +- MVMCoreUI/Atoms/Views/ViewConstrainingView.m | 75 +++++++++++-------- .../MoleculeCollectionViewCell.swift | 35 +++++++-- MVMCoreUI/Molecules/MoleculeStackView.swift | 32 ++------ .../Molecules/MoleculeTableViewCell.swift | 56 +++++++++----- MVMCoreUI/Molecules/StandardFooterView.swift | 6 +- MVMCoreUI/Molecules/StandardHeaderView.swift | 16 ++-- MVMCoreUI/Styles/MFStyler.m | 6 +- MVMCoreUI/Utility/MVMCoreUIUtility.h | 7 ++ MVMCoreUI/Utility/MVMCoreUIUtility.m | 18 +++++ 11 files changed, 158 insertions(+), 98 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/MFView.m b/MVMCoreUI/Atoms/Views/MFView.m index 28bcdd81..9eeb673a 100644 --- a/MVMCoreUI/Atoms/Views/MFView.m +++ b/MVMCoreUI/Atoms/Views/MFView.m @@ -39,7 +39,7 @@ } - (void)setupView { - self.preservesSuperviewLayoutMargins = YES; + self.preservesSuperviewLayoutMargins = NO; } - (void)updateView:(CGFloat)size { diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.h b/MVMCoreUI/Atoms/Views/ViewConstrainingView.h index acf451a8..55280666 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.h +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.h @@ -30,8 +30,9 @@ @property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *topPinLow; @property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *bottomPinLow; -/// In updateView, will set horizontal padding to default if set to YES. +/// In updateView, will set horizontal padding to default if set to NO. @property (nonatomic) BOOL updateViewHorizontalDefaults; +@property (nonatomic) BOOL updateViewVerticalDefaults; /// A molecule if we constrain one. @property (weak, nullable, nonatomic) UIView *molecule; diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m index c6152bcc..73e545c5 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m @@ -14,6 +14,8 @@ #import "MFStyler.h" #import "MVMCoreUIConstants.h" #import "MVMCoreUIMoleculeMappingObject.h" +#import "MVMCoreUIUtility.h" +#import "MVMCoreUIViewConstrainingProtocol.h" @interface ViewConstrainingView () @property (weak, nullable, nonatomic) UIView *constrainedView; @@ -27,8 +29,8 @@ [self addConstrainedView:molecule alignment:alignment]; [self setAsMolecule]; } - [self setMoleculeAccessibility]; self.molecule = molecule; + [self setMoleculeAccessibility]; } return self; } @@ -280,21 +282,14 @@ } - (void)shouldSetHorizontalMargins:(BOOL)shouldSet { - self.updateViewHorizontalDefaults = shouldSet; + if (![self.json optionalNumberForKey:@"useHorizontalMargins"]) { + self.updateViewHorizontalDefaults = shouldSet; + } } - (void)shouldSetVerticalMargins:(BOOL)shouldSet { - BOOL useStandardSpacing = shouldSet; - if (shouldSet && [self.molecule respondsToSelector:@selector(useStandardConstraints)]) { - useStandardSpacing = [((UIView *)self.molecule) useStandardConstraints]; - } - - if (useStandardSpacing) { - [self setTopPinConstant:PaddingDefaultVerticalSpacing]; - [self setBottomPinConstant:PaddingDefaultVerticalSpacing]; - } else { - [self setTopPinConstant:0]; - [self setBottomPinConstant:0]; + if (![self.json optionalNumberForKey:@"useVerticalMargins"]) { + self.updateViewVerticalDefaults = shouldSet; } } @@ -304,11 +299,7 @@ [super setupView]; self.translatesAutoresizingMaskIntoConstraints = NO; self.backgroundColor = [UIColor clearColor]; - if (@available(iOS 11.0, *)) { - self.directionalLayoutMargins = NSDirectionalEdgeInsetsZero; - } else { - self.layoutMargins = UIEdgeInsetsZero; - } + [MVMCoreUIUtility setMarginsForView:self leading:0 top:0 trailing:0 bottom:0]; } - (void)updateView:(CGFloat)size { @@ -316,14 +307,12 @@ if ([self.constrainedView respondsToSelector:@selector(updateView:)]) { [((id)self.constrainedView) updateView:size]; } - if (self.updateViewHorizontalDefaults) { - [MVMCoreDispatchUtility performBlockOnMainThread:^{ - CGFloat padding = [MFStyler defaultHorizontalPaddingForSize:size]; - [self setLeftPinConstant:padding]; - [self setRightPinConstant:padding]; - [MFStyler setDefaultMarginsForView:self size:size]; - }]; - } + [MFStyler setDefaultMarginsForView:self size:size horizontal:self.updateViewHorizontalDefaults vertical:self.updateViewVerticalDefaults]; + UIEdgeInsets margins = [MVMCoreUIUtility getMarginsForView:self]; + [self setLeftPinConstant:margins.left]; + [self setRightPinConstant:margins.right]; + [self setTopPinConstant:margins.top]; + [self setBottomPinConstant:margins.bottom]; } #pragma mark - MVMCoreUIMoleculeViewProtocol @@ -340,13 +329,18 @@ } - (void)reset { + self.updateViewHorizontalDefaults = NO; + self.updateViewVerticalDefaults = NO; + if ([self.molecule respondsToSelector:@selector(alignment)]) { + [self alignHorizontal:[(UIView *)self.molecule alignment]]; + } + [self alignVertical:UIStackViewAlignmentFill]; if ([self.molecule respondsToSelector:@selector(reset)]) { [self.molecule performSelector:@selector(reset)]; } } - (void)setAsMolecule { - self.updateViewHorizontalDefaults = YES; } - (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { @@ -361,13 +355,32 @@ [self insertSubview:molecule atIndex:0]; [self pinViewToSuperView:molecule]; } + self.molecule = molecule; } [self setMoleculeAccessibility]; } - if (self.molecule) { - if ([self.molecule respondsToSelector:@selector(copyBackgroundColor)] && [self.molecule performSelector:@selector(copyBackgroundColor)]) { - self.backgroundColor = self.molecule.backgroundColor; - } + + NSNumber *useHorizontalMargins = [json optionalNumberForKey:@"useHorizontalMargins"]; + if (useHorizontalMargins) { + self.updateViewHorizontalDefaults = [useHorizontalMargins boolValue]; + } + NSNumber *useVerticalMargins = [json optionalNumberForKey:@"useVerticalMargins"]; + if (useVerticalMargins) { + self.updateViewVerticalDefaults = [useVerticalMargins boolValue]; + } + + // Set the alignment for the stack in the containing view. The json driven value is for the axis direction alignment. + NSString *alignment = [json string:@"horizontalAlignment"]; + if (alignment) { + [self alignHorizontal:[ViewConstrainingView getAlignmentForString:alignment defaultAlignment:UIStackViewAlignmentFill]]; + } + alignment = [json string:@"verticalAlignment"]; + if (alignment) { + [self alignVertical:[ViewConstrainingView getAlignmentForString:alignment defaultAlignment:UIStackViewAlignmentFill]]; + } + + if ([self.molecule respondsToSelector:@selector(copyBackgroundColor)] && [self.molecule performSelector:@selector(copyBackgroundColor)]) { + self.backgroundColor = self.molecule.backgroundColor; } } diff --git a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift index 5f18d454..6afec1bc 100644 --- a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift @@ -10,7 +10,12 @@ import UIKit open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol { open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)? + open var json: [AnyHashable: Any]? + // In updateView, will set padding to default. + open var updateViewHorizontalDefaults = true + open var updateViewVerticalDefaults = true + open var allowsPeaking = false var peakingLeftArrow = UIImageView(image: MVMCoreUIUtility.imageNamed("peakingRightArrow")?.withRenderingMode(.alwaysTemplate)) var peakingRightArrow = UIImageView(image: MVMCoreUIUtility.imageNamed("peakingRightArrow")?.withRenderingMode(.alwaysTemplate)) @@ -58,6 +63,14 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi } public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + self.json = json + + if let useHorizontalMargins = json?.optionalBoolForKey("useHorizontalMargins") { + updateViewHorizontalDefaults = useHorizontalMargins + } + if let useVerticalMargins = json?.optionalBoolForKey("useVerticalMargins") { + updateViewVerticalDefaults = useVerticalMargins + } // Handles peaking. allowsPeaking = json?.optionalBoolForKey("peakingUI") ?? true @@ -67,27 +80,38 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi peakingRightArrow.tintColor = color } + if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) { + backgroundColor = UIColor.mfGet(forHex: backgroundColorString) + } + guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule) else { return } if molecule == nil { if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) { contentView.insertSubview(moleculeView, at: 0) - NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: false).values)) + NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: true).values)) molecule = moleculeView } } else { molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) } + // This molecule will handle spacing by default. if let castView = molecule as? MVMCoreUIViewConstrainingProtocol { - let standardConstraints = castView.useStandardConstraints?() ?? true - castView.shouldSetHorizontalMargins?(standardConstraints) - castView.shouldSetVerticalMargins?(standardConstraints) + castView.shouldSetHorizontalMargins?(false) + castView.shouldSetVerticalMargins?(false) } - backgroundColor = molecule?.backgroundColor + accessibilityElements = molecule?.subviews } + public func reset() { + molecule?.reset?() + updateViewVerticalDefaults = true + updateViewHorizontalDefaults = true + backgroundColor = .white + } + public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { guard let molecule = molecule?.optionalDictionaryForKey(KeyMolecule) else { return nil @@ -97,6 +121,7 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi public func updateView(_ size: CGFloat) { molecule?.updateView(size) + MFStyler.setDefaultMarginsFor(contentView, size: size, horizontal: updateViewHorizontalDefaults, vertical: updateViewVerticalDefaults) } public func setPeaking(_ peaking: Bool, animated: Bool) { diff --git a/MVMCoreUI/Molecules/MoleculeStackView.swift b/MVMCoreUI/Molecules/MoleculeStackView.swift index 74178f5f..ad395eec 100644 --- a/MVMCoreUI/Molecules/MoleculeStackView.swift +++ b/MVMCoreUI/Molecules/MoleculeStackView.swift @@ -41,13 +41,12 @@ public class MoleculeStackView: ViewConstrainingView { var items: [StackItem] = [] var useStackSpacingBeforeFirstItem = false - private var moleculesShouldSetHorizontalMargins = true + private var moleculesShouldSetHorizontalMargins = false private var moleculesShouldSetVerticalMargins = false /// For setting the direction of the stack var axis: NSLayoutConstraint.Axis = .vertical { didSet { - moleculesShouldSetHorizontalMargins = (moleculesShouldSetHorizontalMargins && axis == .vertical) if axis != oldValue { restack() } @@ -109,6 +108,8 @@ public class MoleculeStackView: ViewConstrainingView { guard contentView.superview == nil else { return } + MVMCoreUIUtility.setMarginsFor(contentView, leading: 0, top: 0, trailing: 0, bottom: 0) + updateViewHorizontalDefaults = true translatesAutoresizingMaskIntoConstraints = false backgroundColor = .clear addSubview(contentView) @@ -125,12 +126,10 @@ public class MoleculeStackView: ViewConstrainingView { } // MARK: - MVMCoreUIMoleculeViewProtocol - public override func setAsMolecule() { - updateViewHorizontalDefaults = false - } - public override func reset() { + super.reset() backgroundColor = .clear + updateViewHorizontalDefaults = true for item in items { if let view = item.view as? MVMCoreUIMoleculeViewProtocol { view.reset?() @@ -138,23 +137,6 @@ public class MoleculeStackView: ViewConstrainingView { } } - public override func shouldSetHorizontalMargins(_ shouldSet: Bool) { - super.shouldSetHorizontalMargins(shouldSet) - updateViewHorizontalDefaults = false - moleculesShouldSetHorizontalMargins = (shouldSet && axis == .vertical) - for item in items { - (item.view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(moleculesShouldSetHorizontalMargins) - } - } - - public override func shouldSetVerticalMargins(_ shouldSet: Bool) { - super.shouldSetVerticalMargins(shouldSet) - moleculesShouldSetVerticalMargins = false - for item in items { - (item.view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(moleculesShouldSetVerticalMargins) - } - } - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { let previousJSON = self.json super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) @@ -175,10 +157,6 @@ public class MoleculeStackView: ViewConstrainingView { setAxisWithJSON(json) spacing = json?.optionalCGFloatForKey("spacing") ?? 16 - // Set the alignment for the stack in the containing view. The json driven value is for the axis direction alignment. - alignHorizontal(ViewConstrainingView.getAlignmentFor(json?.optionalStringForKey("horizontalAlignment"), defaultAlignment: .fill)) - alignVertical(ViewConstrainingView.getAlignmentFor(json?.optionalStringForKey("verticalAlignment"), defaultAlignment: .fill)) - // Adds the molecules and sets the json. for (index, map) in molecules.enumerated() { if let moleculeJSON = map.optionalDictionaryForKey(KeyMolecule) { diff --git a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/MoleculeTableViewCell.swift index fc681c12..eff1e5c5 100644 --- a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/MoleculeTableViewCell.swift @@ -13,6 +13,10 @@ import UIKit open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)? open var json: [AnyHashable: Any]? + // In updateView, will set padding to default. + open var updateViewHorizontalDefaults = true + open var updateViewVerticalDefaults = true + // For the accessory view convenience. public var caretView: CaretView? private var caretViewWidthSizeObject: MFSizeObject? @@ -41,7 +45,7 @@ import UIKit // MARK: - MFViewProtocol public func updateView(_ size: CGFloat) { - MFStyler.setDefaultMarginsFor(self, size: size, horizontal: true, vertical: true) + MFStyler.setDefaultMarginsFor(self, size: size, horizontal: updateViewHorizontalDefaults, vertical: updateViewVerticalDefaults) if #available(iOS 11.0, *) { if accessoryView != nil { // Smaller left margin if accessory view. @@ -83,6 +87,31 @@ import UIKit // MARK: - MVMCoreUIMoleculeViewProtocol public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { self.json = json; + + if let useHorizontalMargins = json?.optionalBoolForKey("useHorizontalMargins") { + updateViewHorizontalDefaults = useHorizontalMargins + } + if let useVerticalMargins = json?.optionalBoolForKey("useVerticalMargins") { + updateViewVerticalDefaults = useVerticalMargins + } + + if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) { + backgroundColor = UIColor.mfGet(forHex: backgroundColorString) + } + + // Add the caret if there is an action and it's not declared hidden. + if let _ = json?.optionalDictionaryForKey("actionMap"), json!.boolForKey("hideArrow") { + addCaretViewAccessory() + } else { + accessoryView = nil + } + + // override the separator + if let separator = json?.optionalDictionaryForKey("separator") { + addSeparatorsIfNeeded() + bottomSeparatorView?.setWithJSON(separator, delegateObject: delegateObject, additionalData: additionalData) + } + guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { return } @@ -101,30 +130,19 @@ import UIKit } else { molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) } + + // This molecule will by default handle margins. if let castView = molecule as? MVMCoreUIViewConstrainingProtocol { - let standardConstraints = castView.useStandardConstraints?() ?? true - castView.shouldSetHorizontalMargins?(!standardConstraints) - castView.shouldSetVerticalMargins?(!standardConstraints) - } - - backgroundColor = molecule?.backgroundColor - - // Add the caret if there is an action and it's not declared hidden. - if let _ = json.optionalDictionaryForKey("actionMap"), !json.boolForKey("hideArrow") { - addCaretViewAccessory() - } else { - accessoryView = nil - } - - // override the separator - if let separator = json.optionalDictionaryForKey("separator") { - addSeparatorsIfNeeded() - bottomSeparatorView?.setWithJSON(separator, delegateObject: delegateObject, additionalData: additionalData) + castView.shouldSetHorizontalMargins?(false) + castView.shouldSetVerticalMargins?(false) } } public func reset() { molecule?.reset?() + updateViewVerticalDefaults = true + updateViewHorizontalDefaults = true + backgroundColor = .white } public static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { diff --git a/MVMCoreUI/Molecules/StandardFooterView.swift b/MVMCoreUI/Molecules/StandardFooterView.swift index a135ccc0..8f4ca0b5 100644 --- a/MVMCoreUI/Molecules/StandardFooterView.swift +++ b/MVMCoreUI/Molecules/StandardFooterView.swift @@ -12,14 +12,16 @@ open class StandardFooterView: ViewConstrainingView { open override func setupView() { super.setupView() setupMoleculeFromJSON = true + updateViewVerticalDefaults = true + updateViewHorizontalDefaults = true } open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + + // This molecule will by default handle margins. (molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(false) (molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(false) - shouldSetVerticalMargins(true) - shouldSetHorizontalMargins(true) } public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { diff --git a/MVMCoreUI/Molecules/StandardHeaderView.swift b/MVMCoreUI/Molecules/StandardHeaderView.swift index ff5b8538..fbaa5518 100644 --- a/MVMCoreUI/Molecules/StandardHeaderView.swift +++ b/MVMCoreUI/Molecules/StandardHeaderView.swift @@ -15,11 +15,18 @@ public class StandardHeaderView: ViewConstrainingView { open override func updateView(_ size: CGFloat) { super.updateView(size) separatorView?.updateView(size) + if separatorView?.isHidden ?? true { + let margins = MVMCoreUIUtility.getMarginsFor(self) + MVMCoreUIUtility.setMarginsFor(self, leading: margins.left, top: margins.top, trailing: margins.right, bottom: 0) + bottomPin?.constant = 0 + } } public override func setupView() { super.setupView() setupMoleculeFromJSON = true + updateViewVerticalDefaults = true + updateViewHorizontalDefaults = true if separatorView == nil, let separatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionBot, withHorizontalPadding: 0) { separatorView.setAsHeavy() addSubview(separatorView) @@ -40,19 +47,14 @@ public class StandardHeaderView: ViewConstrainingView { // MARK: - MVMCoreUIMoleculeViewProtocol open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + + // This molecule will by default handle margins. (molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(false) (molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(false) - shouldSetVerticalMargins(true) - shouldSetHorizontalMargins(true) if let separatorJSON = json?.optionalDictionaryForKey("separator") { separatorView?.setWithJSON(separatorJSON, delegateObject: delegateObject, additionalData: additionalData) } - if separatorView?.isHidden ?? true { - bottomPin?.constant = 0 - } else { - bottomPin?.constant = PaddingDefaultVerticalSpacing - } } open override func reset() { diff --git a/MVMCoreUI/Styles/MFStyler.m b/MVMCoreUI/Styles/MFStyler.m index dc9288d8..2b0d0a0a 100644 --- a/MVMCoreUI/Styles/MFStyler.m +++ b/MVMCoreUI/Styles/MFStyler.m @@ -98,11 +98,7 @@ CGFloat const LabelWithInternalButtonLineSpace = 2; [MVMCoreDispatchUtility performBlockOnMainThread:^{ CGFloat horizontalPadding = horizontal ? [MFStyler defaultHorizontalPaddingForSize:size] : 0; CGFloat verticalPadding = vertical ? PaddingDefaultVerticalSpacing : 0; - if (@available(iOS 11.0, *)) { - view.directionalLayoutMargins = NSDirectionalEdgeInsetsMake(verticalPadding, horizontalPadding, verticalPadding, horizontalPadding); - } else { - view.layoutMargins = UIEdgeInsetsMake(verticalPadding, horizontalPadding, verticalPadding, horizontalPadding); - } + [MVMCoreUIUtility setMarginsForView:view leading:horizontalPadding top:verticalPadding trailing:horizontalPadding bottom:verticalPadding]; }]; } diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.h b/MVMCoreUI/Utility/MVMCoreUIUtility.h index 81545583..b6698537 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.h +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.h @@ -28,6 +28,13 @@ NS_ASSUME_NONNULL_BEGIN // Returns an image from this framework's bundle + (nullable UIImage *)imageNamed:(nullable NSString *)imageName; +// Returns the margins for a view. ++ (UIEdgeInsets)getMarginsForView:(nullable UIView *)view; + +#pragma mark - Setters + ++ (void)setMarginsForView:(nullable UIView *)view leading:(CGFloat)leading top:(CGFloat)top trailing:(CGFloat)trailing bottom:(CGFloat)bottom; + #pragma mark - Formatting // Formats the given mdn. diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.m b/MVMCoreUI/Utility/MVMCoreUIUtility.m index 1afabeab..8201e999 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.m @@ -57,6 +57,24 @@ return image; } ++ (UIEdgeInsets)getMarginsForView:(nullable UIView *)view { + if (@available(iOS 11.0, *)) { + return UIEdgeInsetsMake(view.directionalLayoutMargins.top, view.directionalLayoutMargins.leading, view.directionalLayoutMargins.bottom, view.directionalLayoutMargins.trailing); + } else { + return view.layoutMargins; + } +} + +#pragma mark - Setters + ++ (void)setMarginsForView:(nullable UIView *)view leading:(CGFloat)leading top:(CGFloat)top trailing:(CGFloat)trailing bottom:(CGFloat)bottom { + if (@available(iOS 11.0, *)) { + view.directionalLayoutMargins = NSDirectionalEdgeInsetsMake(top, leading, bottom, trailing); + } else { + view.layoutMargins = UIEdgeInsetsMake(top, leading, bottom, trailing); + } +} + #pragma mark - Formatting // As per business confirmation format should be xxx.xxx.xxxx same across application From 5c619aa8430db261f327be6c9cdfcea43563dc28 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Fri, 19 Jul 2019 10:48:01 -0400 Subject: [PATCH 19/62] remove preserves --- MVMCoreUI/Atoms/Views/MFView.m | 1 - MVMCoreUI/Molecules/MoleculeTableViewCell.swift | 2 -- 2 files changed, 3 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/MFView.m b/MVMCoreUI/Atoms/Views/MFView.m index 9eeb673a..937da3f2 100644 --- a/MVMCoreUI/Atoms/Views/MFView.m +++ b/MVMCoreUI/Atoms/Views/MFView.m @@ -39,7 +39,6 @@ } - (void)setupView { - self.preservesSuperviewLayoutMargins = NO; } - (void)updateView:(CGFloat)size { diff --git a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/MoleculeTableViewCell.swift index eff1e5c5..492e7d4d 100644 --- a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/MoleculeTableViewCell.swift @@ -79,8 +79,6 @@ import UIKit } public func setupView() { - preservesSuperviewLayoutMargins = false - contentView.preservesSuperviewLayoutMargins = false selectionStyle = .none } From 8400c0eae86a39ed34f39fc081c3d6174273c558 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Fri, 19 Jul 2019 10:53:16 -0400 Subject: [PATCH 20/62] name change --- MVMCoreUI/Atoms/Views/ViewConstrainingView.h | 2 +- MVMCoreUI/Atoms/Views/ViewConstrainingView.m | 2 +- MVMCoreUI/Molecules/StandardFooterView.swift | 2 +- MVMCoreUI/Molecules/StandardHeaderView.swift | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.h b/MVMCoreUI/Atoms/Views/ViewConstrainingView.h index 55280666..995753b1 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.h +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.h @@ -38,7 +38,7 @@ @property (weak, nullable, nonatomic) UIView *molecule; /// A flag for if we should add a molecule from json. -@property (nonatomic) BOOL setupMoleculeFromJSON; +@property (nonatomic) BOOL shouldSetupMoleculeFromJSON; // Returns an empty view + (nonnull ViewConstrainingView *)emptyView; diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m index 73e545c5..c3254678 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m @@ -347,7 +347,7 @@ [super setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; [self.molecule setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; - if (self.setupMoleculeFromJSON && !self.molecule) { + if (self.shouldSetupMoleculeFromJSON && !self.molecule) { NSDictionary *moleculeJSON = [json dict:KeyMolecule]; if (moleculeJSON) { UIView *molecule = [[MVMCoreUIMoleculeMappingObject sharedMappingObject] createMoleculeForJSON:moleculeJSON delegateObject:delegateObject constrainIfNeeded:true]; diff --git a/MVMCoreUI/Molecules/StandardFooterView.swift b/MVMCoreUI/Molecules/StandardFooterView.swift index 8f4ca0b5..f00af028 100644 --- a/MVMCoreUI/Molecules/StandardFooterView.swift +++ b/MVMCoreUI/Molecules/StandardFooterView.swift @@ -11,7 +11,7 @@ import UIKit open class StandardFooterView: ViewConstrainingView { open override func setupView() { super.setupView() - setupMoleculeFromJSON = true + shouldSetupMoleculeFromJSON = true updateViewVerticalDefaults = true updateViewHorizontalDefaults = true } diff --git a/MVMCoreUI/Molecules/StandardHeaderView.swift b/MVMCoreUI/Molecules/StandardHeaderView.swift index fbaa5518..0e6c6776 100644 --- a/MVMCoreUI/Molecules/StandardHeaderView.swift +++ b/MVMCoreUI/Molecules/StandardHeaderView.swift @@ -24,7 +24,7 @@ public class StandardHeaderView: ViewConstrainingView { public override func setupView() { super.setupView() - setupMoleculeFromJSON = true + shouldSetupMoleculeFromJSON = true updateViewVerticalDefaults = true updateViewHorizontalDefaults = true if separatorView == nil, let separatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionBot, withHorizontalPadding: 0) { From c5f8d276367003fb16c764c555240daf9d197e2d Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Fri, 19 Jul 2019 11:34:22 -0400 Subject: [PATCH 21/62] fix prod break defect --- MVMCoreUI/Atoms/Views/ViewConstrainingView.m | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m index c3254678..6295a218 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m @@ -309,10 +309,14 @@ } [MFStyler setDefaultMarginsForView:self size:size horizontal:self.updateViewHorizontalDefaults vertical:self.updateViewVerticalDefaults]; UIEdgeInsets margins = [MVMCoreUIUtility getMarginsForView:self]; - [self setLeftPinConstant:margins.left]; - [self setRightPinConstant:margins.right]; - [self setTopPinConstant:margins.top]; - [self setBottomPinConstant:margins.bottom]; + if (self.updateViewHorizontalDefaults) { + [self setLeftPinConstant:margins.left]; + [self setRightPinConstant:margins.right]; + } + if (self.updateViewVerticalDefaults) { + [self setTopPinConstant:margins.top]; + [self setBottomPinConstant:margins.bottom]; + } } #pragma mark - MVMCoreUIMoleculeViewProtocol From f12805ba2a659d90da24989c3895b2d1daaed138 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Mon, 22 Jul 2019 09:53:22 -0400 Subject: [PATCH 22/62] update comment --- MVMCoreUI/Atoms/Views/ViewConstrainingView.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.h b/MVMCoreUI/Atoms/Views/ViewConstrainingView.h index 995753b1..b07fd6bb 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.h +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.h @@ -30,7 +30,7 @@ @property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *topPinLow; @property (nullable, strong, nonatomic) IBOutlet NSLayoutConstraint *bottomPinLow; -/// In updateView, will set horizontal padding to default if set to NO. +/// In updateView, will set horizontal padding to default. @property (nonatomic) BOOL updateViewHorizontalDefaults; @property (nonatomic) BOOL updateViewVerticalDefaults; From dace6a6374c4bbfa33bcff56673cefaf71cf2d2f Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 23 Jul 2019 09:55:43 -0400 Subject: [PATCH 23/62] update table cell --- MVMCoreUI/Atoms/Views/MFLoadImageView.swift | 4 ++++ MVMCoreUI/OtherHandlers/MoleculeDelegateProtocol.h | 4 ++++ MVMCoreUI/Templates/MoleculeListTemplate.swift | 10 ++++++++++ 3 files changed, 18 insertions(+) diff --git a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift index 703ffd65..996dea95 100644 --- a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift +++ b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift @@ -22,6 +22,8 @@ import UIKit var imageWidth: CGFloat? var imageHeight: CGFloat? + var delegateObject: MVMCoreUIDelegateObject? + // For keeping track of current state. private var edges: UIRectEdge? private var spinnerHeight: CGFloat? @@ -190,6 +192,7 @@ import UIKit open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + self.delegateObject = delegateObject if let accessibilityString = json?.optionalStringForKey("accessibilityText") { imageView.accessibilityLabel = accessibilityString imageView.accessibilityTraits = .staticText @@ -223,6 +226,7 @@ import UIKit self?.loadingSpinnerHeightConstraint?.constant = 0 self?.loadingSpinner.pause() self?.addConstraints(width: width, height: height, size: image?.size) + self?.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated?(self!) completionHandler(image,data,isFallbackImage) })} diff --git a/MVMCoreUI/OtherHandlers/MoleculeDelegateProtocol.h b/MVMCoreUI/OtherHandlers/MoleculeDelegateProtocol.h index 0d027386..fa91e0fc 100644 --- a/MVMCoreUI/OtherHandlers/MoleculeDelegateProtocol.h +++ b/MVMCoreUI/OtherHandlers/MoleculeDelegateProtocol.h @@ -12,4 +12,8 @@ /// returns a module for the corresponding module name. - (nullable NSDictionary *)getModuleWithName:(nullable NSString *)name; +@optional +/// Notifies the delegate that the molecule layout update. Should be called when the layout may change due to an async method. +- (void)moleculeLayoutUpdated:(nonnull UIView *)molecule; + @end diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index f3a4f310..ec2f2ff7 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -106,6 +106,16 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { return loadObject?.requestParameters?.modules } + // MARK: - MoleculeDelegateProtocol + open override func moleculeLayoutUpdated(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) { + if let tableView = tableView { + let point = molecule.convert(molecule.bounds.origin, to: tableView) + if let indexPath = tableView.indexPathForRow(at: point) { + tableView.reloadRows(at: [indexPath], with: .none) + } + } + } + // MARK: - Convenience /// Returns the (identifier, class) of the molecule for the given map. func getMoleculeInfo(with molecule: [AnyHashable: Any]?) -> (identifier: String, class: AnyClass, molecule: [AnyHashable: Any])? { From 482c6c4fababeb1bb7980face7995612a3e7e9e0 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 23 Jul 2019 09:56:49 -0400 Subject: [PATCH 24/62] auto looks better --- MVMCoreUI/Templates/MoleculeListTemplate.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index ec2f2ff7..693a8c4d 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -111,7 +111,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { if let tableView = tableView { let point = molecule.convert(molecule.bounds.origin, to: tableView) if let indexPath = tableView.indexPathForRow(at: point) { - tableView.reloadRows(at: [indexPath], with: .none) + tableView.reloadRows(at: [indexPath], with: .automatic) } } } From 7472533bc12667d9cb0809eaff36fc6b4e596b76 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 23 Jul 2019 10:13:44 -0400 Subject: [PATCH 25/62] fixes error alert. --- MVMCoreUI/Templates/MoleculeStackTemplate.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/MVMCoreUI/Templates/MoleculeStackTemplate.swift b/MVMCoreUI/Templates/MoleculeStackTemplate.swift index 064c910c..d6f78b05 100644 --- a/MVMCoreUI/Templates/MoleculeStackTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeStackTemplate.swift @@ -8,7 +8,7 @@ import UIKit -public class MoleculeStackTemplate: ThreeLayerViewController { +open class MoleculeStackTemplate: ThreeLayerViewController { var observer: NSKeyValueObservation? open override var loadObject: MVMCoreLoadObject? { @@ -25,18 +25,18 @@ public class MoleculeStackTemplate: ThreeLayerViewController { } } - public override func spaceBetweenTopAndMiddle() -> CGFloat? { + open override func spaceBetweenTopAndMiddle() -> CGFloat? { return 0 } - public override func viewForTop() -> UIView? { + open override func viewForTop() -> UIView? { guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { return nil } return molecule } - public override func viewForMiddle() -> UIView? { + open override func viewForMiddle() -> UIView? { guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("moleculeStack") else { return nil } @@ -46,7 +46,7 @@ public class MoleculeStackTemplate: ThreeLayerViewController { return stack } - override public func viewForBottom() -> UIView? { + override open func viewForBottom() -> UIView? { guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { return nil } @@ -54,14 +54,14 @@ public class MoleculeStackTemplate: ThreeLayerViewController { } // MARK: - cache handling - public override func pageTypesToListenFor() -> [Any]? { + open override func pageTypesToListenFor() -> [Any]? { guard let pageType = self.pageType else { return super.pageTypesToListenFor() } return [pageType] } - public override func modulesToListenFor() -> [Any]? { + open override func modulesToListenFor() -> [Any]? { return loadObject?.requestParameters?.modules } From 6537523373fac2b8ea095eae577b2e2cf00c3454 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 23 Jul 2019 11:57:03 -0400 Subject: [PATCH 26/62] different way to update --- MVMCoreUI/Templates/MoleculeListTemplate.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index 693a8c4d..abec1b01 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -110,8 +110,9 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { open override func moleculeLayoutUpdated(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) { if let tableView = tableView { let point = molecule.convert(molecule.bounds.origin, to: tableView) - if let indexPath = tableView.indexPathForRow(at: point) { - tableView.reloadRows(at: [indexPath], with: .automatic) + if let indexPath = tableView.indexPathForRow(at: point), tableView.indexPathsForVisibleRows?.contains(indexPath) ?? false { + tableView.beginUpdates() + tableView.endUpdates() } } } From bc516ff74c5da768bc239dcbf716caeb9b288fe6 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 23 Jul 2019 12:14:18 -0400 Subject: [PATCH 27/62] removed statement causing loop. --- MVMCoreUI/Atoms/Views/ListItemWithImage.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/MVMCoreUI/Atoms/Views/ListItemWithImage.swift b/MVMCoreUI/Atoms/Views/ListItemWithImage.swift index 334020e4..0caa08d2 100644 --- a/MVMCoreUI/Atoms/Views/ListItemWithImage.swift +++ b/MVMCoreUI/Atoms/Views/ListItemWithImage.swift @@ -128,7 +128,6 @@ import UIKit title.text = "" message.text = "" - imageLoader.imageView.image = nil imageLeadingConstraint?.constant = 16 backgroundColor = nil } From f2db8528a7baa3999c7fe8f5bdbe7d096458d9d5 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 24 Jul 2019 12:44:45 -0400 Subject: [PATCH 28/62] threeLayer template scroller molecule border color. remove default height fix missing update view --- MVMCoreUI.xcodeproj/project.pbxproj | 8 +++ MVMCoreUI/Atoms/Views/ViewConstrainingView.m | 3 ++ .../ThreeLayerViewController.swift | 2 +- MVMCoreUI/Molecules/Carousel.swift | 11 +++- MVMCoreUI/Molecules/Scroller.swift | 42 +++++++++++++++ MVMCoreUI/Molecules/StandardHeaderView.swift | 5 -- .../MVMCoreUIMoleculeMappingObject.m | 1 + .../MVMCoreUIViewControllerMappingObject.m | 4 +- MVMCoreUI/Templates/ThreeLayerTemplate.swift | 52 +++++++++++++++++++ 9 files changed, 119 insertions(+), 9 deletions(-) create mode 100644 MVMCoreUI/Molecules/Scroller.swift create mode 100644 MVMCoreUI/Templates/ThreeLayerTemplate.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 9323507e..920b1d72 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -169,6 +169,8 @@ D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */; }; D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */; }; + D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */; }; + D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */; }; D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */; }; D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */; }; D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */; }; @@ -347,6 +349,8 @@ D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeCollectionViewCell.swift; sourceTree = ""; }; D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewControllerMappingObject.h; sourceTree = ""; }; D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIViewControllerMappingObject.m; sourceTree = ""; }; + D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scroller.swift; sourceTree = ""; }; + D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTemplate.swift; sourceTree = ""; }; D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIDelegateObject.swift; sourceTree = ""; }; D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeTableViewCell.swift; sourceTree = ""; }; D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTableViewController.swift; sourceTree = ""; }; @@ -443,6 +447,7 @@ D2A514622213643100345BFB /* MoleculeStackCenteredTemplate.swift */, D296E13B2295969C0051EBE7 /* MoleculeListCellProtocol.h */, D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */, + D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */, ); path = Templates; sourceTree = ""; @@ -490,6 +495,7 @@ D260D7AF22D65BDD007E7233 /* MVMCoreUIPageControl.h */, D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */, D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */, + D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */, ); path = Molecules; sourceTree = ""; @@ -949,12 +955,14 @@ D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */, D2A514672213885800345BFB /* StandardHeaderView.swift in Sources */, DBEFFA04225A829700230692 /* Label.swift in Sources */, + D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */, D29DF13021E6851E003B2FB9 /* MVMCoreUITopAlertShortView.m in Sources */, D28B4F8B21FF967C00712C7A /* MVMCoreUIObject.m in Sources */, D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */, D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */, D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */, D282AACB2243C61700C46919 /* ButtonView.swift in Sources */, + D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */, 0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */, D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */, D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */, diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m index 6295a218..4b4ad4eb 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m @@ -307,6 +307,9 @@ if ([self.constrainedView respondsToSelector:@selector(updateView:)]) { [((id)self.constrainedView) updateView:size]; } + if (self.molecule != self.constrainedView) { + [self.molecule updateView:size]; + } [MFStyler setDefaultMarginsForView:self size:size horizontal:self.updateViewHorizontalDefaults vertical:self.updateViewVerticalDefaults]; UIEdgeInsets margins = [MVMCoreUIUtility getMarginsForView:self]; if (self.updateViewHorizontalDefaults) { diff --git a/MVMCoreUI/BaseControllers/ThreeLayerViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerViewController.swift index 299cdf9b..dae861dd 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerViewController.swift @@ -22,7 +22,7 @@ open class ThreeLayerViewController: ProgrammaticScrollViewController { var bottomViewOutsideOfScroll = false private var safeAreaView: UIView? - private var heightConstraint: NSLayoutConstraint? + var heightConstraint: NSLayoutConstraint? open override func updateViews() { super.updateViews() diff --git a/MVMCoreUI/Molecules/Carousel.swift b/MVMCoreUI/Molecules/Carousel.swift index 082fcd6d..db796782 100644 --- a/MVMCoreUI/Molecules/Carousel.swift +++ b/MVMCoreUI/Molecules/Carousel.swift @@ -62,7 +62,7 @@ open class Carousel: ViewConstrainingView { pinView(toSuperView: collectionView) collectionViewHeight = collectionView.heightAnchor.constraint(equalToConstant: 300) - collectionViewHeight?.isActive = true + collectionViewHeight?.isActive = false } open override func updateView(_ size: CGFloat) { @@ -81,12 +81,19 @@ open class Carousel: ViewConstrainingView { // MARK: - MVMCoreUIMoleculeViewProtocol open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + collectionView.backgroundColor = backgroundColor + collectionView.layer.borderColor = backgroundColor?.cgColor + collectionView.layer.borderWidth = (json?.boolForKey("border") ?? false) ? 1 : 0 + backgroundColor = .white registerCells(with: json, delegateObject: delegateObject) setupLayout(with: json) prepareMolecules(with: json) itemWidthPercent = (json?.optionalCGFloatForKey("itemWidthPercent") ?? 100) / 100 setAlignment(with: json?.optionalStringForKey("itemAlignment")) - collectionViewHeight?.constant = json?.optionalCGFloatForKey("height") ?? 300 + if let height = json?.optionalCGFloatForKey("height") { + collectionViewHeight?.constant = height + collectionViewHeight?.isActive = true + } setupPagingMolecule(json: json?.optionalDictionaryForKey("pagingMolecule"), delegateObject: delegateObject) collectionView.reloadData() } diff --git a/MVMCoreUI/Molecules/Scroller.swift b/MVMCoreUI/Molecules/Scroller.swift new file mode 100644 index 00000000..b76bbb10 --- /dev/null +++ b/MVMCoreUI/Molecules/Scroller.swift @@ -0,0 +1,42 @@ +// +// Scroller.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 7/23/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers open class Scroller: ViewConstrainingView { + public let scrollView = UIScrollView(frame: .zero) + public let contentView = MVMCoreUICommonViewsUtility.commonView() + + override open func setupView() { + super.setupView() + guard scrollView.superview == nil else { + return + } + addConstrainedView(scrollView) + scrollView.addSubview(contentView) + if let constraints = (NSLayoutConstraint.pinView(toSuperview: contentView, useMargins: false) as NSDictionary).allValues as? [NSLayoutConstraint] { + NSLayoutConstraint.activate(constraints) + } + contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, multiplier: 1.0, constant: -0.1).isActive = true + } + + open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { + return + } + if molecule == nil { + if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) { + contentView.addSubview(moleculeView) + pinView(toSuperView: moleculeView) + molecule = moleculeView + } + } else { + molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) + } + } +} diff --git a/MVMCoreUI/Molecules/StandardHeaderView.swift b/MVMCoreUI/Molecules/StandardHeaderView.swift index 0e6c6776..093a2e31 100644 --- a/MVMCoreUI/Molecules/StandardHeaderView.swift +++ b/MVMCoreUI/Molecules/StandardHeaderView.swift @@ -15,11 +15,6 @@ public class StandardHeaderView: ViewConstrainingView { open override func updateView(_ size: CGFloat) { super.updateView(size) separatorView?.updateView(size) - if separatorView?.isHidden ?? true { - let margins = MVMCoreUIUtility.getMarginsFor(self) - MVMCoreUIUtility.setMarginsFor(self, leading: margins.left, top: margins.top, trailing: margins.right, bottom: 0) - bottomPin?.constant = 0 - } } public override func setupView() { diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 325a8fed..c8a0b040 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -53,6 +53,7 @@ @"carousel": Carousel.class, @"carouselItem": MoleculeCollectionViewCell.class, @"barsPager": MVMCoreUIPageControl.class, + @"scroller": Scroller.class } mutableCopy]; }); return mapping; diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIViewControllerMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIViewControllerMappingObject.m index 4e33da75..e770ede5 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIViewControllerMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIViewControllerMappingObject.m @@ -22,7 +22,9 @@ @"textFieldListForm" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[TextFieldListFormViewController class]], @"moleculeStack" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeStackTemplate class]], @"centerMoleculeStack" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeStackCenteredTemplate class]], - @"moleculeList" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeListTemplate class]] + @"moleculeList" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeListTemplate class]], + @"threeLayer" : + [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[ThreeLayerTemplate class]] } mutableCopy]; }); return viewControllerMapping; diff --git a/MVMCoreUI/Templates/ThreeLayerTemplate.swift b/MVMCoreUI/Templates/ThreeLayerTemplate.swift new file mode 100644 index 00000000..20475a6b --- /dev/null +++ b/MVMCoreUI/Templates/ThreeLayerTemplate.swift @@ -0,0 +1,52 @@ +// +// ThreeLayerTemplate.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 7/23/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers open class ThreeLayerTemplate: ThreeLayerViewController { + + override open func viewDidLoad() { + super.viewDidLoad() + bottomViewOutsideOfScroll = true + // Do any additional setup after loading the view. + } + + open override func newDataBuildScreen() { + super.newDataBuildScreen() + heightConstraint?.isActive = true + } + + open override func viewForTop() -> UIView? { + guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { + return nil + } + return molecule + } + + open override func viewForMiddle() -> UIView? { + guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("middle"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { + return nil + } + return molecule + } + + override open func viewForBottom() -> UIView? { + guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { + return nil + } + return molecule + } + + open override func spaceBetweenMiddleAndBottom() -> CGFloat? { + return 0 + } + + open override func spaceBetweenTopAndMiddle() -> CGFloat? { + return 0 + } +} From 5ebc4b0e31119b3e11b75405f97d2bd5754108df Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 24 Jul 2019 15:38:13 -0400 Subject: [PATCH 29/62] strikethrough fix warning fix. --- MVMCoreUI/Atoms/Views/Label.swift | 2 +- MVMCoreUI/Molecules/Scroller.swift | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 10b9220e..57a16ad8 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -217,7 +217,7 @@ public typealias ActionBlock = () -> Void case "strikethrough": attributedString.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.thick.rawValue, range: range) - + attributedString.addAttribute(.baselineOffset, value: 0, range: range) case "color": if let colorHex = attribute.optionalStringForKey(KeyTextColor), !colorHex.isEmpty { attributedString.removeAttribute(.foregroundColor, range: range) diff --git a/MVMCoreUI/Molecules/Scroller.swift b/MVMCoreUI/Molecules/Scroller.swift index b76bbb10..cd2949d8 100644 --- a/MVMCoreUI/Molecules/Scroller.swift +++ b/MVMCoreUI/Molecules/Scroller.swift @@ -17,12 +17,14 @@ import UIKit guard scrollView.superview == nil else { return } + translatesAutoresizingMaskIntoConstraints = false + scrollView.translatesAutoresizingMaskIntoConstraints = false addConstrainedView(scrollView) scrollView.addSubview(contentView) - if let constraints = (NSLayoutConstraint.pinView(toSuperview: contentView, useMargins: false) as NSDictionary).allValues as? [NSLayoutConstraint] { - NSLayoutConstraint.activate(constraints) - } - contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, multiplier: 1.0, constant: -0.1).isActive = true + NSLayoutConstraint.constraintPinSubview(toSuperview: contentView) + let constraint = contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, multiplier: 1.0) + constraint.priority = UILayoutPriority(rawValue: 999) + constraint.isActive = true } open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { From 245d7d93d6578868e5736b9085287b3a209c822b Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 25 Jul 2019 10:44:14 -0400 Subject: [PATCH 30/62] efficiency commit --- MVMCoreUI/Atoms/Views/MFLoadImageView.swift | 63 +++++++++++++++++---- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift index 996dea95..1debda74 100644 --- a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift +++ b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift @@ -155,6 +155,39 @@ import UIKit return false } + // MARK: - Constraints + + func setHeight(_ height: CGFloat) { + if let heightConstraint = heightConstraint, MVMCoreGetterUtility.cgfequal(heightConstraint.multiplier, 1) { + heightConstraint.constant = height + } else { + heightConstraint?.isActive = false + heightConstraint = imageView.heightAnchor.constraint(equalToConstant: height) + heightConstraint?.priority = UILayoutPriority(rawValue: 900) + } + heightConstraint?.isActive = true + } + + func setWidth(_ width: CGFloat) { + if let widthConstraint = widthConstraint, MVMCoreGetterUtility.cgfequal(widthConstraint.multiplier, 1) { + widthConstraint.constant = width + } else { + widthConstraint = imageView.widthAnchor.constraint(equalToConstant: width) + widthConstraint?.priority = UILayoutPriority(rawValue: 900) + } + widthConstraint?.isActive = true + } + + func layoutWillChange(width: CGFloat?, height: CGFloat?, size: CGSize?) -> Bool { + guard addSizeConstraintsForAspectRatio else { + return false + } + let widthWillChange = !MVMCoreGetterUtility.cgfequal(widthConstraint?.constant ?? 0, width ?? 0) + let heightWillChange = !MVMCoreGetterUtility.cgfequal(heightConstraint?.constant ?? 0, height ?? 0) + let sizeWillChange = (width == nil || height == nil) && !(size?.equalTo(imageView.image?.size ?? CGSize.zero) ?? false) + return widthWillChange || heightWillChange || sizeWillChange + } + // Constrains the image view to be the size provided. Used to size it to the image to fix aspect fit defect. func addConstraints(width: NSNumber?, height: NSNumber?, size: CGSize?) { widthConstraint?.isActive = false @@ -164,21 +197,19 @@ import UIKit } if let width = width, let height = height { - heightConstraint = imageView.heightAnchor.constraint(equalToConstant: height.cgfloat()) - widthConstraint = imageView.widthAnchor.constraint(equalToConstant: width.cgfloat()) + setHeight(height.cgfloat()) + setWidth(width.cgfloat()) } else if let width = width, let size = size { - widthConstraint = imageView.widthAnchor.constraint(equalToConstant: width.cgfloat()) + setWidth(width.cgfloat()) heightConstraint = imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: size.height/size.width) + heightConstraint?.priority = UILayoutPriority(rawValue: 900) + heightConstraint?.isActive = true } else if let height = height, let size = size { - heightConstraint = imageView.heightAnchor.constraint(equalToConstant: height.cgfloat()) + setHeight(height.cgfloat()) widthConstraint = imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor, multiplier: size.width/size.height) + widthConstraint?.priority = UILayoutPriority(rawValue: 900) + widthConstraint?.isActive = true } - widthConstraint?.priority = UILayoutPriority(rawValue: 900) - heightConstraint?.priority = UILayoutPriority(rawValue: 900) - heightConstraint?.isActive = true - widthConstraint?.isActive = true - imageView.setContentHuggingPriority(UILayoutPriority.defaultLow, for: NSLayoutConstraint.Axis.horizontal) - imageView.setContentHuggingPriority(UILayoutPriority.defaultLow, for: NSLayoutConstraint.Axis.vertical) } // MARK: - MVMCoreUIMoleculeViewProtocol functions @@ -200,6 +231,13 @@ import UIKit } let width = json?.optionalCGFloatForKey("width") ?? imageWidth let height = json?.optionalCGFloatForKey("height") ?? imageHeight + // For smoother transitions, set constraints that we know immediately. + if let width = width, addSizeConstraintsForAspectRatio { + setWidth(width) + } + if let height = height, addSizeConstraintsForAspectRatio { + setHeight(height) + } if let imageName = json?.optionalStringForKey("image"), shouldLoadImage(withName: imageName, width: width, height: height) { imageView.image = nil imageView.animatedImage = nil @@ -225,8 +263,11 @@ import UIKit self?.isFallbackImage = isFallbackImage self?.loadingSpinnerHeightConstraint?.constant = 0 self?.loadingSpinner.pause() + let layoutWillChange = self?.layoutWillChange(width: self?.currentImageWidth, height: self?.currentImageHeight, size: image?.size) ?? false self?.addConstraints(width: width, height: height, size: image?.size) - self?.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated?(self!) + if layoutWillChange { + self?.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated?(self!) + } completionHandler(image,data,isFallbackImage) })} From 45689c7c51b7ee1ad99a2a5f9c93e9ec8dbe05d8 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Sat, 27 Jul 2019 17:31:19 -0400 Subject: [PATCH 31/62] Made fix to TopLabelBottomButtomVC. Added close X image to replace 'X' char. --- .../TopLabelsAndBottomButtonsViewController.h | 1 + .../TopLabelsAndBottomButtonsViewController.m | 5 ++-- .../closeXBlack.imageset/Contents.json | 23 ++++++++++++++++++ .../closeXBlack.imageset/closeXBlack.png | Bin 0 -> 215 bytes .../closeXBlack.imageset/closeXBlack@2x.png | Bin 0 -> 374 bytes .../closeXBlack.imageset/closeXBlack@3x.png | Bin 0 -> 535 bytes .../Utility/MVMCoreUICommonViewsUtility.m | 2 +- 7 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/Contents.json create mode 100644 MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/closeXBlack.png create mode 100644 MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/closeXBlack@2x.png create mode 100644 MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/closeXBlack@3x.png diff --git a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.h b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.h index 720f0097..4abdb035 100644 --- a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.h +++ b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.h @@ -24,6 +24,7 @@ @property (nullable, weak, nonatomic) UIView *viewOutOfScroll; @property (nullable, strong, nonatomic) UIView *safeAreaView; @property (nullable, weak, nonatomic) ViewConstrainingView *bottomAccessoryView; +//@property (nullable, strong, nonatomic) NSLayoutConstraint *heightConstraint; // Set to overwrite which view is the top edge and/or bottom edge of the between view. must be added to the ui and constrained before buildViewsBetweenLabelsAndButtons. // Use these to create views that are pinned near the labels or buttons and are separate from any centered content. Add and set in buildInAdditionalViewsBeforeCenteredContent. diff --git a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.m b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.m index 0fcc51a2..77472e11 100644 --- a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.m +++ b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.m @@ -303,8 +303,9 @@ } - (void)addViewToContentView:(UIView *)bottomView { - - self.bottomConstraint.active = YES; + if (![self bottomViewOutsideOfScroll]) { + self.bottomConstraint.active = YES; + } // Buttons will be at the bottom of the content view. [self.contentView addSubview:bottomView]; diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/Contents.json b/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/Contents.json new file mode 100644 index 00000000..d7771f8a --- /dev/null +++ b/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "closeXBlack.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "closeXBlack@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "closeXBlack@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/closeXBlack.png b/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/closeXBlack.png new file mode 100644 index 0000000000000000000000000000000000000000..5f31bd2848e43db0f21a371def0f620059cf46a6 GIT binary patch literal 215 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@Rf|#^NA%Cx&(BWL^R}6FprVLo5W> zPH_}!P~dQ#+ZQ1I`d@j*%{a|KqaQ1hjrlnK*Uk`Y`%vfJXS{I3l$e)ug!PUH>^Amp zwVo?zJlRm%#@8kMHP@$WvA30tuLyHr4`JRCrRt#OIFtEE-p0n?{${t6W81ec)cCxR zQ)Px$FiAu~R9Fekm|+gWAPj{UPr`q_|9SZBCA3vp7&7+yC~Qs0q_ppQu(%~#mJ3G^ zZ;uoFDO1^-2r`Q@o-$^dQkF8Kj38r;yZq9H*Y7&RR5Fv8>R}UQ!AMgu3ohJj#WpcB z%nb%Vv^L$?FxRcwEs&XW)AA7V(8%`oeJ-(&1a~vZ86(W}Bp!6N04%i-e6I)rAvJsY zRK5jltx+(vsRpj)P(7Er(g6EUbTN}ea#QK8tvNbwbms*d^V8AWb?PlE&FH+An{tjV zaBFRdIRuE*xR|qmEVYz52Eg<{=6ZyCdaLF<1U)o9=G=rtty`;GpmN@{Cf!&uQKrn= z=7y38%wYyx2tbcY4q2D`*brn(QHH*;)%~nUClv)4N~k9OK8ch?1Ln#M19W{P-_;Ag UXN9MmJpcdz07*qoM6N<$g7AT$p8x;= literal 0 HcmV?d00001 diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/closeXBlack@3x.png b/MVMCoreUI/SupportingFiles/Media.xcassets/closeXBlack.imageset/closeXBlack@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..598475659e712adada27405d4a675351fa7a3a92 GIT binary patch literal 535 zcmV+y0_gpTP)Px$(Md!>RA>e5nq5xAFc5?*o_OZsy$-kFNZ_gDDr(m0{>+#dYRPJecW1tF3{p@o zm)BT(2i_b0wat%(Vt^IQU^fRAKHL0m^Q+Aj!hsR2Ute6MbQRM^7L))=Z7a+D+6?0v9```_ zGShIH*EFNeR?0o)2AeRCUuE7h;l~6AKhqiLf(P)=mS`+Ap=ZQ_^)gdgAOIUJO|zvN zqlAU}Fk`r(09S1dv0j^7|3^#sjh8BEqTdRK47>4XU+Y6sghOiV#wr7>U^d@XTqVSd Z^9Mh_uZWnsYPA3W002ovPDHLkV1mNA@q_>X literal 0 HcmV?d00001 diff --git a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m index 487a7b51..41237640 100644 --- a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m @@ -181,7 +181,7 @@ static const CGFloat VertialShadowOffset = 6; + (nonnull MFCustomButton *)addCloseButtonToView:(UIView *)view action:(ButtonTapBlock)actionBlock verticalCentered:(BOOL)verticalCentered { MFCustomButton *button = [[MFCustomButton alloc] initWithFrame:CGRectZero]; button.translatesAutoresizingMaskIntoConstraints = NO; - [button setTitle:@"✕" forState:UIControlStateNormal]; + [button setImage:[MVMCoreUIUtility imageNamed:@"closeXBlack"] forState:UIControlStateNormal]; button.titleLabel.font = [MFStyler fontForHeadlineAlternative]; //accessibility From 00f31524720e581a6c580679d34a7f64d3d81df9 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 31 Jul 2019 12:03:54 -0400 Subject: [PATCH 32/62] reversed trailing anchor constraints. --- MVMCoreUI/Atoms/Views/ListItemWithImage.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/ListItemWithImage.swift b/MVMCoreUI/Atoms/Views/ListItemWithImage.swift index 0caa08d2..5a383452 100644 --- a/MVMCoreUI/Atoms/Views/ListItemWithImage.swift +++ b/MVMCoreUI/Atoms/Views/ListItemWithImage.swift @@ -79,13 +79,13 @@ import UIKit title.topAnchor.constraint(equalTo: leftContainer.topAnchor).isActive = true title.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true - title.trailingAnchor.constraint(equalTo: leftContainer.trailingAnchor).isActive = true + leftContainer.trailingAnchor.constraint(equalTo: title.trailingAnchor).isActive = true messageTopConstraint = message.topAnchor.constraint(equalTo: title.bottomAnchor, constant: PaddingOne) messageTopConstraint?.isActive = true message.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true - message.trailingAnchor.constraint(equalTo: leftContainer.trailingAnchor).isActive = true + leftContainer.trailingAnchor.constraint(equalTo: message.trailingAnchor).isActive = true buttonTopConstraint = button.topAnchor.constraint(equalTo: message.bottomAnchor, constant: PaddingTwo) buttonTopConstraint?.isActive = true From 7bb6e5ba8dcd0babf8b030a41977018a3511629a Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 1 Aug 2019 09:23:10 -0400 Subject: [PATCH 33/62] check before use --- MVMCoreUI/Molecules/MVMCoreUIPageControl.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Molecules/MVMCoreUIPageControl.m b/MVMCoreUI/Molecules/MVMCoreUIPageControl.m index 16783ca9..6648b513 100644 --- a/MVMCoreUI/Molecules/MVMCoreUIPageControl.m +++ b/MVMCoreUI/Molecules/MVMCoreUIPageControl.m @@ -297,7 +297,9 @@ static CGFloat const IndicatorRectangleHeight = 4; if (selectedIndex != NSNotFound) { self.currentPage = selectedIndex; [self sendActionsForControlEvents:UIControlEventValueChanged]; - self.pagingTouchBlock(self); + if (self.pagingTouchBlock) { + self.pagingTouchBlock(self); + } } } } @@ -351,7 +353,9 @@ static CGFloat const IndicatorRectangleHeight = 4; if ((index < self.numberOfPages && index >= 0) || self.alwaysSendingControlEvent) { [self setCurrentPage:index animated:NO]; [self sendActionsForControlEvents:UIControlEventValueChanged]; - self.pagingTouchBlock(self); + if (self.pagingTouchBlock) { + self.pagingTouchBlock(self); + } } } From 4d905bb17d0e43f2ab479464f54ead4bf35a33ae Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 1 Aug 2019 11:45:10 -0400 Subject: [PATCH 34/62] fix to bool typo --- MVMCoreUI/Molecules/MoleculeTableViewCell.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/MoleculeTableViewCell.swift index 492e7d4d..c6241667 100644 --- a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/MoleculeTableViewCell.swift @@ -98,7 +98,7 @@ import UIKit } // Add the caret if there is an action and it's not declared hidden. - if let _ = json?.optionalDictionaryForKey("actionMap"), json!.boolForKey("hideArrow") { + if let _ = json?.optionalDictionaryForKey("actionMap"), !json!.boolForKey("hideArrow") { addCaretViewAccessory() } else { accessoryView = nil From 85675b8637c60784dad77481b6520d4ad74f4731 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 1 Aug 2019 11:49:17 -0400 Subject: [PATCH 35/62] separator color fix for list item --- MVMCoreUI/Atoms/Views/SeparatorView.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MVMCoreUI/Atoms/Views/SeparatorView.m b/MVMCoreUI/Atoms/Views/SeparatorView.m index 2d01e6d2..a666d450 100644 --- a/MVMCoreUI/Atoms/Views/SeparatorView.m +++ b/MVMCoreUI/Atoms/Views/SeparatorView.m @@ -114,6 +114,11 @@ } else { self.hidden = YES; } + + NSString *colorString = [json string:KeyBackgroundColor]; + if (colorString) { + self.backgroundColor = [UIColor mfGetColorForHex:colorString]; + } } #pragma mark - helper From 708b947b02f079834f5caf785a669d1ecdf3f8c2 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 1 Aug 2019 11:57:57 -0400 Subject: [PATCH 36/62] Revert "Merge branch 'feature/molecule_multiLabelListItem' into 'develop'" This reverts merge request !99 --- MVMCoreUI.xcodeproj/project.pbxproj | 4 -- MVMCoreUI/Molecules/MultiLabelListItem.swift | 48 ------------------- .../MVMCoreUIMoleculeMappingObject.m | 1 - 3 files changed, 53 deletions(-) delete mode 100644 MVMCoreUI/Molecules/MultiLabelListItem.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 1bc3548b..920b1d72 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -18,7 +18,6 @@ 01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */; }; 01DF567021FA5AB300CC099B /* TextFieldListFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */; }; 01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; }; - 18423C7E22E07B260069C7B7 /* MultiLabelListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18423C7D22E07B260069C7B7 /* MultiLabelListItem.swift */; }; B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; }; B8200E192281DC1A007245F4 /* ProgressBarWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */; }; D206997721FB8A0B00CAE0DE /* MVMCoreUINavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -195,7 +194,6 @@ 01CA51B4229716F60071A6EE /* Switch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Switch.swift; sourceTree = ""; }; 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = ""; }; 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = ""; }; - 18423C7D22E07B260069C7B7 /* MultiLabelListItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiLabelListItem.swift; sourceTree = ""; }; B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarWithLabel.swift; sourceTree = ""; }; D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUINavigationController.h; sourceTree = ""; }; @@ -476,7 +474,6 @@ D29DF10E21E67A77003B2FB9 /* Molecules */ = { isa = PBXGroup; children = ( - 18423C7D22E07B260069C7B7 /* MultiLabelListItem.swift */, 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */, D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */, D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */, @@ -927,7 +924,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 18423C7E22E07B260069C7B7 /* MultiLabelListItem.swift in Sources */, D29DF32121ED0CBA003B2FB9 /* LabelView.m in Sources */, DBC4391822442197001AB423 /* CaretView.swift in Sources */, D29770F221F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m in Sources */, diff --git a/MVMCoreUI/Molecules/MultiLabelListItem.swift b/MVMCoreUI/Molecules/MultiLabelListItem.swift deleted file mode 100644 index adbd7cf3..00000000 --- a/MVMCoreUI/Molecules/MultiLabelListItem.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// multiLabelListItem.swift -// MVMCoreUI -// -// Created by Kanamarlapudi, Vasavi on 15/7/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import UIKit - -@objcMembers public class MultiLabelListItem: ViewConstrainingView { - - var moleculestackview = MoleculeStackView(frame: .zero) - - open override func needsToBeConstrained() -> Bool { - return true - } - - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - - let moleculestackjson = json?.optionalDictionaryForKey("moleculeStack") - moleculestackview.setWithJSON(moleculestackjson, delegateObject: delegateObject, additionalData: additionalData) - moleculestackview.useStackSpacingBeforeFirstItem = true - } - - override open func setupView() { - super.setupView() - addSubview(moleculestackview) - - moleculestackview.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true - moleculestackview.topAnchor.constraint(equalTo: self.topAnchor).isActive = true - let topleftwidthconstraint = NSLayoutConstraint(item: moleculestackview, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 0.5, constant: 0.0) - topleftwidthconstraint.priority = UILayoutPriority(100) - topleftwidthconstraint.isActive = true - moleculestackview.setContentHuggingPriority(UILayoutPriority(911), for: .horizontal) - moleculestackview.setContentHuggingPriority(UILayoutPriority(911), for: .vertical) - - var bottomconstraint = bottomAnchor.constraint(equalTo: moleculestackview.bottomAnchor, constant: PaddingTwo) - bottomconstraint.priority = UILayoutPriority(249) - bottomconstraint.isActive = true - bottomAnchor.constraint(greaterThanOrEqualTo: moleculestackview.bottomAnchor, constant: PaddingTwo).isActive = true - bottomconstraint = bottomAnchor.constraint(equalTo: moleculestackview.bottomAnchor, constant: PaddingTwo) - bottomconstraint.priority = UILayoutPriority(249) - bottomconstraint.isActive = true - bottomAnchor.constraint(greaterThanOrEqualTo: moleculestackview.bottomAnchor, constant: PaddingTwo).isActive = true - } -} diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 246e529c..c8a0b040 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -49,7 +49,6 @@ @"image": MFLoadImageView.class, @"leftRightLabelView": LeftRightLabelView.class, @"moduleMolecule": ModuleMolecule.class, - @"multiLabelListItem": MultiLabelListItem.class, @"headlineBody": HeadlineBody.class, @"carousel": Carousel.class, @"carouselItem": MoleculeCollectionViewCell.class, From e0afa92c794e9cadf2f7c9b2dabb8ef6aa9d875a Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Fri, 2 Aug 2019 10:26:16 -0400 Subject: [PATCH 37/62] carousel bug fix. imageHeadlineBody --- MVMCoreUI.xcodeproj/project.pbxproj | 4 + MVMCoreUI/Atoms/Views/MFLoadImageView.swift | 1 + MVMCoreUI/Atoms/Views/MFView.m | 4 + MVMCoreUI/Atoms/Views/ViewConstrainingView.m | 3 - MVMCoreUI/Molecules/Carousel.swift | 4 + MVMCoreUI/Molecules/HeadlineBody.swift | 6 +- MVMCoreUI/Molecules/ImageHeadlineBody.swift | 85 +++++++++++++++++++ .../MVMCoreUIMoleculeMappingObject.m | 3 +- 8 files changed, 104 insertions(+), 6 deletions(-) create mode 100644 MVMCoreUI/Molecules/ImageHeadlineBody.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 920b1d72..b4295986 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -167,6 +167,7 @@ D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A638FC22CA98280052ED1F /* HeadlineBody.swift */; }; D2A6390122CBB1820052ED1F /* Carousel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A6390022CBB1820052ED1F /* Carousel.swift */; }; D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */; }; + D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */; }; D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */; }; D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */; }; @@ -347,6 +348,7 @@ D2A638FC22CA98280052ED1F /* HeadlineBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBody.swift; sourceTree = ""; }; D2A6390022CBB1820052ED1F /* Carousel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Carousel.swift; sourceTree = ""; }; D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeCollectionViewCell.swift; sourceTree = ""; }; + D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageHeadlineBody.swift; sourceTree = ""; }; D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewControllerMappingObject.h; sourceTree = ""; }; D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIViewControllerMappingObject.m; sourceTree = ""; }; D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scroller.swift; sourceTree = ""; }; @@ -496,6 +498,7 @@ D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */, D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */, D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */, + D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */, ); path = Molecules; sourceTree = ""; @@ -995,6 +998,7 @@ D29770C821F7C4AE00B2F0D0 /* TopLabelsView.m in Sources */, D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */, D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */, + D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */, D29DF2AA21E7B2F9003B2FB9 /* MVMCoreUIConstants.m in Sources */, D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */, D29DF11821E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.m in Sources */, diff --git a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift index 1debda74..c0066afe 100644 --- a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift +++ b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift @@ -215,6 +215,7 @@ import UIKit // MARK: - MVMCoreUIMoleculeViewProtocol functions open override func setAsMolecule() { addSizeConstraintsForAspectRatio = true + pinEdges(.all) } public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { diff --git a/MVMCoreUI/Atoms/Views/MFView.m b/MVMCoreUI/Atoms/Views/MFView.m index 937da3f2..740c5ad5 100644 --- a/MVMCoreUI/Atoms/Views/MFView.m +++ b/MVMCoreUI/Atoms/Views/MFView.m @@ -46,6 +46,10 @@ #pragma mark - MVMCoreUIMoleculeViewProtocol +- (void)setAsMolecule { + self.translatesAutoresizingMaskIntoConstraints = NO; +} + - (void)reset { self.backgroundColor = [UIColor clearColor]; } diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m index 4b4ad4eb..f46916b3 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m @@ -347,9 +347,6 @@ } } -- (void)setAsMolecule { -} - - (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { [super setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; diff --git a/MVMCoreUI/Molecules/Carousel.swift b/MVMCoreUI/Molecules/Carousel.swift index db796782..d0efcce3 100644 --- a/MVMCoreUI/Molecules/Carousel.swift +++ b/MVMCoreUI/Molecules/Carousel.swift @@ -255,6 +255,10 @@ extension Carousel: UICollectionViewDelegateFlowLayout { let itemWidth = collectionView.bounds.width * itemWidthPercent return CGSize(width: itemWidth, height: collectionView.bounds.height) } + + public func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { + (cell as? MoleculeCollectionViewCell)?.setPeaking(false, animated: false) + } } extension Carousel: UICollectionViewDataSource { diff --git a/MVMCoreUI/Molecules/HeadlineBody.swift b/MVMCoreUI/Molecules/HeadlineBody.swift index 9eaa602f..d3c37261 100644 --- a/MVMCoreUI/Molecules/HeadlineBody.swift +++ b/MVMCoreUI/Molecules/HeadlineBody.swift @@ -11,6 +11,7 @@ import UIKit open class HeadlineBody: ViewConstrainingView { let headlineLabel = Label.commonLabelH2(true) let messageLabel = Label.commonLabelB2(true) + var spaceBetweenLabelsConstant = PaddingTwo var spaceBetweenLabels: NSLayoutConstraint? var leftConstraintTitle: NSLayoutConstraint? var rightConstraintTitle: NSLayoutConstraint? @@ -44,7 +45,7 @@ open class HeadlineBody: ViewConstrainingView { topPin = headlineLabel.topAnchor.constraint(equalTo: topAnchor, constant: 0) topPin?.isActive = true - spaceBetweenLabels = messageLabel.topAnchor.constraint(equalTo: headlineLabel.bottomAnchor, constant: PaddingTwo) + spaceBetweenLabels = messageLabel.topAnchor.constraint(equalTo: headlineLabel.bottomAnchor, constant: spaceBetweenLabelsConstant) spaceBetweenLabels?.isActive = true leftConstraintTitle = headlineLabel.leftAnchor.constraint(equalTo: leftAnchor) @@ -66,7 +67,7 @@ open class HeadlineBody: ViewConstrainingView { // MARK: - Constraining public func setSpacing() { if headlineLabel.hasText && messageLabel.hasText { - spaceBetweenLabels?.constant = PaddingTwo + spaceBetweenLabels?.constant = spaceBetweenLabelsConstant } else { spaceBetweenLabels?.constant = 0 } @@ -96,6 +97,7 @@ open class HeadlineBody: ViewConstrainingView { super.reset() headlineLabel.styleH2(true) messageLabel.styleB2(true) + spaceBetweenLabelsConstant = PaddingTwo } public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { diff --git a/MVMCoreUI/Molecules/ImageHeadlineBody.swift b/MVMCoreUI/Molecules/ImageHeadlineBody.swift new file mode 100644 index 00000000..f1e295fe --- /dev/null +++ b/MVMCoreUI/Molecules/ImageHeadlineBody.swift @@ -0,0 +1,85 @@ +// +// ImageHeadlineBody.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 8/1/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers open class ImageHeadlineBody: ViewConstrainingView { + let headlineBody = HeadlineBody(frame: .zero) + let imageView = MFLoadImageView() + var constraintBetweenImageLabelsConstant: CGFloat = 16 + var constraintBetweenImageLabels: NSLayoutConstraint? + + // MARK: - MFViewProtocol + + open override func setupView() { + guard subviews.count == 0 else { + return + } + MVMCoreUIUtility.setMarginsFor(self, leading: 0, top: 0, trailing: 0, bottom: 0) + headlineBody.headlineLabel.styleB1(true) + headlineBody.spaceBetweenLabelsConstant = 0 + addSubview(headlineBody) + addSubview(imageView) + + NSLayoutConstraint.pinViewTop(toSuperview: headlineBody, useMargins: true, constant: 0).isActive = true + NSLayoutConstraint.pinViewRight(toSuperview: headlineBody, useMargins: true, constant: 0).isActive = true + layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: headlineBody.bottomAnchor).isActive = true + var constraint = NSLayoutConstraint.pinViewBottom(toSuperview: headlineBody, useMargins: true, constant: 0) + constraint.priority = .defaultLow + constraint.isActive = true + + imageView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + NSLayoutConstraint.pinViewLeft(toSuperview: imageView, useMargins: true, constant: 0).isActive = true + imageView.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor).isActive = true + layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: imageView.bottomAnchor).isActive = true + constraint = NSLayoutConstraint.pinViewBottom(toSuperview: imageView, useMargins: true, constant: 0) + constraint.priority = UILayoutPriority(rawValue: 200) + constraint.isActive = true + constraint = NSLayoutConstraint.pinViewTop(toSuperview: imageView, useMargins: true, constant: 0) + constraint.priority = UILayoutPriority(rawValue: 200) + constraint.isActive = true + + constraintBetweenImageLabels = headlineBody.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: constraintBetweenImageLabelsConstant) + constraintBetweenImageLabels?.isActive = true + } + + open override func updateView(_ size: CGFloat) { + super.updateView(size) + headlineBody.updateView(size) + imageView.updateView(size) + } + + // MARK: - MVMCoreUIMoleculeViewProtocol + + open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + headlineBody.setWithJSON(json?.optionalDictionaryForKey("headlineBody"), delegateObject: delegateObject, additionalData: additionalData) + + let imageJSON = json?.optionalDictionaryForKey("image") + imageView.setWithJSON(imageJSON, delegateObject: delegateObject, additionalData: additionalData) + constraintBetweenImageLabels?.constant = imageJSON != nil ? constraintBetweenImageLabelsConstant : 0 + } + + open override func setAsMolecule() { + super.setAsMolecule() + headlineBody.setAsMolecule() + imageView.setAsMolecule() + } + + open override func reset() { + super.reset() + headlineBody.reset() + headlineBody.headlineLabel.styleB1(true) + headlineBody.spaceBetweenLabelsConstant = 0 + imageView.reset() + } + + public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return 95 + } +} diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index c8a0b040..41513bf0 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -53,7 +53,8 @@ @"carousel": Carousel.class, @"carouselItem": MoleculeCollectionViewCell.class, @"barsPager": MVMCoreUIPageControl.class, - @"scroller": Scroller.class + @"scroller": Scroller.class, + @"imageHeadlineBody": ImageHeadlineBody.class } mutableCopy]; }); return mapping; From dd05284b95e1dbb0e0099e58256ce425a9008682 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 5 Aug 2019 09:09:57 -0400 Subject: [PATCH 38/62] latest updates. --- MVMCoreUI/Atoms/Views/ListItemWithImage.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/ListItemWithImage.swift b/MVMCoreUI/Atoms/Views/ListItemWithImage.swift index 5a383452..55b63edb 100644 --- a/MVMCoreUI/Atoms/Views/ListItemWithImage.swift +++ b/MVMCoreUI/Atoms/Views/ListItemWithImage.swift @@ -1,5 +1,5 @@ // -// StandardListItemWithImage.swift +// ListItemWithImage.swift // MVMCoreUI // // Created by Christiano, Kevin on 6/20/19. @@ -69,7 +69,7 @@ import UIKit leftContainer.addSubview(message) leftContainer.addSubview(button) - leftContainer.topAnchor.constraint(equalTo: topAnchor).isActive = true + leftContainer.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true leftContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true bottomAnchor.constraint(greaterThanOrEqualTo: leftContainer.bottomAnchor).isActive = true @@ -91,17 +91,17 @@ import UIKit buttonTopConstraint?.isActive = true button.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true - button.bottomAnchor.constraint(equalTo: leftContainer.bottomAnchor).isActive = true + leftContainer.bottomAnchor.constraint(equalTo: button.bottomAnchor).isActive = true leftContainer.trailingAnchor.constraint(greaterThanOrEqualTo: button.trailingAnchor).isActive = true imageLoader.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true layoutMarginsGuide.trailingAnchor.constraint(equalTo: imageLoader.trailingAnchor).isActive = true imageLeadingConstraint = imageLoader.leadingAnchor.constraint(equalTo: leftContainer.trailingAnchor, constant: 16) imageLeadingConstraint?.isActive = true - imageLoader.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true + imageLoader.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor).isActive = true - bottomAnchor.constraint(greaterThanOrEqualTo: imageLoader.bottomAnchor).isActive = true - let imageloaderBottom = imageLoader.bottomAnchor.constraint(equalTo: bottomAnchor) + layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: imageLoader.bottomAnchor).isActive = true + let imageloaderBottom = imageLoader.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor) imageloaderBottom.priority = UILayoutPriority(249) imageloaderBottom.isActive = true } From f2d557098946d628d561c57fd318d84aac3ae66b Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 5 Aug 2019 09:58:43 -0400 Subject: [PATCH 39/62] layoutMarginsGuide. --- MVMCoreUI/Atoms/Views/ListItemWithImage.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atoms/Views/ListItemWithImage.swift b/MVMCoreUI/Atoms/Views/ListItemWithImage.swift index 55b63edb..7e6599bc 100644 --- a/MVMCoreUI/Atoms/Views/ListItemWithImage.swift +++ b/MVMCoreUI/Atoms/Views/ListItemWithImage.swift @@ -72,7 +72,7 @@ import UIKit leftContainer.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true leftContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true - bottomAnchor.constraint(greaterThanOrEqualTo: leftContainer.bottomAnchor).isActive = true + layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: leftContainer.bottomAnchor).isActive = true let leftContainerBottom = leftContainer.bottomAnchor.constraint(equalTo: bottomAnchor) leftContainerBottom.priority = UILayoutPriority(249) leftContainerBottom.isActive = true From 519542d3e5add737e8a6afd67e7e616f1b41c103 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 5 Aug 2019 10:09:11 -0400 Subject: [PATCH 40/62] Renamed class. --- MVMCoreUI.xcodeproj/project.pbxproj | 10 ++++------ ...ItemWithImage.swift => ActionDetailWithImage.swift} | 4 ++-- .../OtherHandlers/MVMCoreUIMoleculeMappingObject.m | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) rename MVMCoreUI/Atoms/Views/{ListItemWithImage.swift => ActionDetailWithImage.swift} (98%) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index b5415a3a..a0b4ef65 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -18,8 +18,7 @@ 01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */; }; 01DF567021FA5AB300CC099B /* TextFieldListFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */; }; 01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; }; - 0A1214A022C11A18007C7030 /* ListItemWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ListItemWithImage.swift */; }; - 18423C7E22E07B260069C7B7 /* MultiLabelListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18423C7D22E07B260069C7B7 /* MultiLabelListItem.swift */; }; + 0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; }; B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; }; B8200E192281DC1A007245F4 /* ProgressBarWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */; }; D206997721FB8A0B00CAE0DE /* MVMCoreUINavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -197,8 +196,7 @@ 01CA51B4229716F60071A6EE /* Switch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Switch.swift; sourceTree = ""; }; 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = ""; }; 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = ""; }; - 0A12149F22C11A17007C7030 /* ListItemWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListItemWithImage.swift; sourceTree = ""; }; - 18423C7D22E07B260069C7B7 /* MultiLabelListItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiLabelListItem.swift; sourceTree = ""; }; + 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = ""; }; B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarWithLabel.swift; sourceTree = ""; }; D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUINavigationController.h; sourceTree = ""; }; @@ -652,7 +650,7 @@ D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */, DBC4391C2245232D001AB423 /* LabelWithInternalButton.swift */, DB891E822253FA8500022516 /* Label.swift */, - 0A12149F22C11A17007C7030 /* ListItemWithImage.swift */, + 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */, 0198F7A02256A80A0066C936 /* MFRadioButton.h */, 0198F7A22256A80A0066C936 /* MFRadioButton.m */, ); @@ -1016,7 +1014,7 @@ D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */, D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */, 0105618E224BBE7700E1557D /* FormValidator+TextFields.swift in Sources */, - 0A1214A022C11A18007C7030 /* ListItemWithImage.swift in Sources */, + 0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */, D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */, D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */, D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */, diff --git a/MVMCoreUI/Atoms/Views/ListItemWithImage.swift b/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift similarity index 98% rename from MVMCoreUI/Atoms/Views/ListItemWithImage.swift rename to MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift index 7e6599bc..27d7e7d1 100644 --- a/MVMCoreUI/Atoms/Views/ListItemWithImage.swift +++ b/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift @@ -1,5 +1,5 @@ // -// ListItemWithImage.swift +// ActionDetailWithImage.swift // MVMCoreUI // // Created by Christiano, Kevin on 6/20/19. @@ -9,7 +9,7 @@ import UIKit -@objcMembers open class ListItemWithImage: ViewConstrainingView { +@objcMembers open class ActionDetailWithImage: ViewConstrainingView { //------------------------------------------------------ // MARK: - Outlets //------------------------------------------------------ diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index bdf4a673..cd829697 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -47,7 +47,7 @@ @"switchLineItem": SwitchLineItem.class, @"switch": Switch.class, @"leftRightLabelView": LeftRightLabelView.class, - @"listItemWithImage": ListItemWithImage.class, + @"actionDetailWithImage": ActionDetailWithImage.class, @"image": MFLoadImageView.class, @"moduleMolecule": ModuleMolecule.class, @"headlineBody": HeadlineBody.class, From 1ec98eb29a9e9d5aca6e78311d57b886ebf1024a Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 5 Aug 2019 11:50:15 -0400 Subject: [PATCH 41/62] Needed to expose a few properties of the class in order to have adapt it to slight changes for use in support class. --- MVMCoreUI/Atoms/Views/MFRadioButton.h | 8 ++++++-- MVMCoreUI/Atoms/Views/MFRadioButton.m | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/MFRadioButton.h b/MVMCoreUI/Atoms/Views/MFRadioButton.h index 86837256..c5e053c0 100644 --- a/MVMCoreUI/Atoms/Views/MFRadioButton.h +++ b/MVMCoreUI/Atoms/Views/MFRadioButton.h @@ -30,7 +30,6 @@ typedef void (^PerformActionForRadioButton)(void); @property (nullable, copy, nonatomic) PerformActionForRadioButton performActionForCheck; typedef void (^CircleSelectedClosure)(_Nonnull id sender); - @property (nonatomic, strong, nullable) UIColor* fillColor; @property (nonatomic, strong, nullable) UIColor* borderColor; @property (nonatomic) CGFloat circleBorderWidth; @@ -38,11 +37,16 @@ typedef void (^CircleSelectedClosure)(_Nonnull id sender); @property (nonatomic, copy, nullable) CircleSelectedClosure handleSelectionBlock; @property (nonatomic) CGFloat circleDiameter; @property (nonatomic, nullable, strong, readonly) CAShapeLayer * myCircle; - +@property (nullable, weak, nonatomic) UIView *outerCircleView; +@property (nullable, weak, nonatomic) UIView *innerCircleView; @property (nonatomic, strong, nullable) NSLayoutConstraint *heightConstraint; @property (nonatomic, strong, nullable) NSLayoutConstraint *widthConstraint; @property (nonatomic) BOOL respondsToTapGesture; @property (nonatomic, getter = isSelected) BOOL selected; +@property (strong, nonatomic) NSLayoutConstraint *innerHeightConstarint; +@property (strong, nonatomic) NSLayoutConstraint *innerWidthConstarint; +@property (strong, nonatomic) NSLayoutConstraint *outerHeightConstarint; +@property (strong, nonatomic) NSLayoutConstraint *outerWidthConstarint; // Set line width manually - (void)setCheckMarkLineWidth:(CGFloat)lineWidth; diff --git a/MVMCoreUI/Atoms/Views/MFRadioButton.m b/MVMCoreUI/Atoms/Views/MFRadioButton.m index d1a9ee03..06f6c3a0 100644 --- a/MVMCoreUI/Atoms/Views/MFRadioButton.m +++ b/MVMCoreUI/Atoms/Views/MFRadioButton.m @@ -12,11 +12,6 @@ static CGFloat const DefaultOuterCircleSize = 31; static CGFloat const DefaultInnerCircleSize = 19; -@interface MFRadioButton () -@property (nullable, weak, nonatomic) UIView *outerCircleView; -@property (nullable, weak, nonatomic) UIView *innerCircleView; -@end - @implementation MFRadioButton @@ -64,9 +59,11 @@ static CGFloat const DefaultInnerCircleSize = 19; [outerCircleView.leftAnchor constraintEqualToAnchor:self.leftAnchor].active = YES; [outerCircleView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor].active = YES; [outerCircleView.rightAnchor constraintEqualToAnchor:self.rightAnchor].active = YES; - - [outerCircleView.widthAnchor constraintEqualToConstant:DefaultOuterCircleSize].active = YES; - [outerCircleView.heightAnchor constraintEqualToConstant:DefaultOuterCircleSize].active = YES; + + self.outerHeightConstarint = [outerCircleView.widthAnchor constraintEqualToConstant:DefaultOuterCircleSize]; + self.outerHeightConstarint.active = YES; + self.outerWidthConstarint = [outerCircleView.heightAnchor constraintEqualToConstant:DefaultOuterCircleSize]; + self.outerWidthConstarint.active = YES; UIView *innerCircleView = [[UIView alloc] init]; [outerCircleView addSubview:innerCircleView]; @@ -76,8 +73,11 @@ static CGFloat const DefaultInnerCircleSize = 19; [innerCircleView.centerXAnchor constraintEqualToAnchor:outerCircleView.centerXAnchor].active = YES; [innerCircleView.centerYAnchor constraintEqualToAnchor:outerCircleView.centerYAnchor].active = YES; - [innerCircleView.widthAnchor constraintEqualToConstant:DefaultInnerCircleSize].active = YES; - [innerCircleView.heightAnchor constraintEqualToConstant:DefaultInnerCircleSize].active = YES; + + self.innerHeightConstarint = [innerCircleView.heightAnchor constraintEqualToConstant:DefaultInnerCircleSize]; + self.innerHeightConstarint.active = YES; + self.innerWidthConstarint = [innerCircleView.widthAnchor constraintEqualToConstant:DefaultInnerCircleSize]; + self.innerWidthConstarint.active = YES; outerCircleView.userInteractionEnabled = NO; innerCircleView.userInteractionEnabled = NO; From 93ed26820d9898907aa59b5cf8856092a7381982 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 5 Aug 2019 16:37:27 -0400 Subject: [PATCH 42/62] Latest State --- .../Atoms/Views/ActionDetailWithImage.swift | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift b/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift index 27d7e7d1..950e9b4c 100644 --- a/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift +++ b/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift @@ -20,6 +20,12 @@ import UIKit let imageLoader = MFLoadImageView(pinnedEdges: .all) let leftContainer = ViewConstrainingView.empty() + //------------------------------------------------------ + // MARK: - Properties + //------------------------------------------------------ + + var textPadding: CGFloat = PaddingOne + //------------------------------------------------------ // MARK: - Constraints //------------------------------------------------------ @@ -104,6 +110,18 @@ import UIKit let imageloaderBottom = imageLoader.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor) imageloaderBottom.priority = UILayoutPriority(249) imageloaderBottom.isActive = true + +// title.widthAnchor.constraint(equalTo: leftContainer.widthAnchor).isActive = true +// message.widthAnchor.constraint(equalTo: leftContainer.widthAnchor).isActive = true + +// title.setContentCompressionResistancePriority(UILayoutPriority(970), for: .horizontal) +// title.setContentCompressionResistancePriority(.required, for: .vertical) +// message.setContentCompressionResistancePriority(UILayoutPriority(970), for: .horizontal) +// message.setContentCompressionResistancePriority(.required, for: .vertical) +// button.setContentCompressionResistancePriority(UILayoutPriority(976), for: .horizontal) +// button.setContentCompressionResistancePriority(.required, for: .vertical) +// imageLoader.loadingSpinner.setContentCompressionResistancePriority(UILayoutPriority(975), for: .horizontal) +// imageLoader.imageView.setContentCompressionResistancePriority(UILayoutPriority(975), for: .horizontal) } override open func updateView(_ size: CGFloat) { @@ -115,8 +133,13 @@ import UIKit imageLoader.updateView(size) leftContainer.updateView(size) - messageTopConstraint?.constant = title.hasText ? PaddingOne : 0 - buttonTopConstraint?.constant = message.hasText ? PaddingTwo : (title.hasText ? PaddingOne : 0) + let titlePadding = title.hasText ? textPadding : 0 + messageTopConstraint?.constant = titlePadding + buttonTopConstraint?.constant = message.hasText ? PaddingTwo : titlePadding + } + + public override static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return 197 } //------------------------------------------------------ @@ -132,6 +155,10 @@ import UIKit backgroundColor = nil } + open override func setAsMolecule() { + super.setAsMolecule() + } + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) @@ -141,5 +168,6 @@ import UIKit message.setWithJSON(dictionary.optionalDictionaryForKey("message"), delegateObject: delegateObject, additionalData: additionalData) button.setWithJSON(dictionary.optionalDictionaryForKey("button"), delegateObject: delegateObject, additionalData: additionalData) imageLoader.setWithJSON(dictionary.optionalDictionaryForKey("image"), delegateObject: delegateObject, additionalData: additionalData) + } } From d4a19d9086fa9bec04cbe558055f8960161b5177 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 9 Aug 2019 09:45:44 -0400 Subject: [PATCH 43/62] Removed unneeded line. --- .../LegacyControllers/TopLabelsAndBottomButtonsViewController.h | 1 - 1 file changed, 1 deletion(-) diff --git a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.h b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.h index 4abdb035..720f0097 100644 --- a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.h +++ b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.h @@ -24,7 +24,6 @@ @property (nullable, weak, nonatomic) UIView *viewOutOfScroll; @property (nullable, strong, nonatomic) UIView *safeAreaView; @property (nullable, weak, nonatomic) ViewConstrainingView *bottomAccessoryView; -//@property (nullable, strong, nonatomic) NSLayoutConstraint *heightConstraint; // Set to overwrite which view is the top edge and/or bottom edge of the between view. must be added to the ui and constrained before buildViewsBetweenLabelsAndButtons. // Use these to create views that are pinned near the labels or buttons and are separate from any centered content. Add and set in buildInAdditionalViewsBeforeCenteredContent. From f78a952905b655e12e85d2e56c99d37cafd5c2e8 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 9 Aug 2019 15:22:49 -0400 Subject: [PATCH 44/62] space. --- MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift b/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift index 950e9b4c..fa718a4e 100644 --- a/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift +++ b/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift @@ -168,6 +168,5 @@ import UIKit message.setWithJSON(dictionary.optionalDictionaryForKey("message"), delegateObject: delegateObject, additionalData: additionalData) button.setWithJSON(dictionary.optionalDictionaryForKey("button"), delegateObject: delegateObject, additionalData: additionalData) imageLoader.setWithJSON(dictionary.optionalDictionaryForKey("image"), delegateObject: delegateObject, additionalData: additionalData) - } } From 4fc5ff931347a4b83c29f6ba0200bfb0209d156e Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 12 Aug 2019 09:04:18 -0400 Subject: [PATCH 45/62] adjustments made. --- .../Atoms/Views/ActionDetailWithImage.swift | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift b/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift index fa718a4e..b1b092ec 100644 --- a/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift +++ b/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift @@ -102,7 +102,7 @@ import UIKit imageLoader.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true layoutMarginsGuide.trailingAnchor.constraint(equalTo: imageLoader.trailingAnchor).isActive = true - imageLeadingConstraint = imageLoader.leadingAnchor.constraint(equalTo: leftContainer.trailingAnchor, constant: 16) + imageLeadingConstraint = imageLoader.leadingAnchor.constraint(greaterThanOrEqualTo: leftContainer.trailingAnchor, constant: 16) imageLeadingConstraint?.isActive = true imageLoader.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor).isActive = true @@ -110,18 +110,6 @@ import UIKit let imageloaderBottom = imageLoader.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor) imageloaderBottom.priority = UILayoutPriority(249) imageloaderBottom.isActive = true - -// title.widthAnchor.constraint(equalTo: leftContainer.widthAnchor).isActive = true -// message.widthAnchor.constraint(equalTo: leftContainer.widthAnchor).isActive = true - -// title.setContentCompressionResistancePriority(UILayoutPriority(970), for: .horizontal) -// title.setContentCompressionResistancePriority(.required, for: .vertical) -// message.setContentCompressionResistancePriority(UILayoutPriority(970), for: .horizontal) -// message.setContentCompressionResistancePriority(.required, for: .vertical) -// button.setContentCompressionResistancePriority(UILayoutPriority(976), for: .horizontal) -// button.setContentCompressionResistancePriority(.required, for: .vertical) -// imageLoader.loadingSpinner.setContentCompressionResistancePriority(UILayoutPriority(975), for: .horizontal) -// imageLoader.imageView.setContentCompressionResistancePriority(UILayoutPriority(975), for: .horizontal) } override open func updateView(_ size: CGFloat) { @@ -152,7 +140,7 @@ import UIKit title.text = "" message.text = "" imageLeadingConstraint?.constant = 16 - backgroundColor = nil + imageLoader.reset() } open override func setAsMolecule() { @@ -163,6 +151,8 @@ import UIKit super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) guard let dictionary = json else { return } + + textPadding = dictionary.optionalCGFloatForKey("textPadding") ?? 0.0 title.setWithJSON(dictionary.optionalDictionaryForKey("title"), delegateObject: delegateObject, additionalData: additionalData) message.setWithJSON(dictionary.optionalDictionaryForKey("message"), delegateObject: delegateObject, additionalData: additionalData) From 57f82aa60a78eaae5e590a0d6282132c4de752f0 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 12 Aug 2019 09:40:15 -0400 Subject: [PATCH 46/62] Call super reset in vcv. Further adjustments to atom. --- .../Atoms/Views/ActionDetailWithImage.swift | 23 ++++++++++++------- MVMCoreUI/Atoms/Views/ViewConstrainingView.m | 1 + 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift b/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift index b1b092ec..5e32bc00 100644 --- a/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift +++ b/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift @@ -24,7 +24,7 @@ import UIKit // MARK: - Properties //------------------------------------------------------ - var textPadding: CGFloat = PaddingOne + var titlePadding: CGFloat = PaddingOne //------------------------------------------------------ // MARK: - Constraints @@ -62,12 +62,12 @@ import UIKit override open func setupView() { super.setupView() - imageLoader.addSizeConstraintsForAspectRatio = true - guard subviews.isEmpty else { return } button.setAsSecondaryCustom() + button.isHidden = false imageLoader.imageView.contentMode = .scaleAspectFit + imageLoader.addSizeConstraintsForAspectRatio = true addSubview(leftContainer) addSubview(imageLoader) @@ -121,9 +121,9 @@ import UIKit imageLoader.updateView(size) leftContainer.updateView(size) - let titlePadding = title.hasText ? textPadding : 0 - messageTopConstraint?.constant = titlePadding - buttonTopConstraint?.constant = message.hasText ? PaddingTwo : titlePadding + let topPadding = title.hasText ? titlePadding : 0 + messageTopConstraint?.constant = topPadding + buttonTopConstraint?.constant = message.hasText ? PaddingTwo : topPadding } public override static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { @@ -152,11 +152,18 @@ import UIKit guard let dictionary = json else { return } - textPadding = dictionary.optionalCGFloatForKey("textPadding") ?? 0.0 + if let padding = dictionary.optionalCGFloatForKey("titlePadding") { + titlePadding = padding + } title.setWithJSON(dictionary.optionalDictionaryForKey("title"), delegateObject: delegateObject, additionalData: additionalData) message.setWithJSON(dictionary.optionalDictionaryForKey("message"), delegateObject: delegateObject, additionalData: additionalData) - button.setWithJSON(dictionary.optionalDictionaryForKey("button"), delegateObject: delegateObject, additionalData: additionalData) imageLoader.setWithJSON(dictionary.optionalDictionaryForKey("image"), delegateObject: delegateObject, additionalData: additionalData) + if let buttonDictionary = dictionary.optionalDictionaryForKey("button") { + button.setWithJSON(buttonDictionary, delegateObject: delegateObject, additionalData: additionalData) + button.isHidden = false + } else { + button.isHidden = true + } } } diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m index f46916b3..dff48826 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m @@ -336,6 +336,7 @@ } - (void)reset { + [super reset]; self.updateViewHorizontalDefaults = NO; self.updateViewVerticalDefaults = NO; if ([self.molecule respondsToSelector:@selector(alignment)]) { From fd8b8fb7b7de43513b4934dfeea0dc51c4d11bff Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 12 Aug 2019 12:47:21 -0400 Subject: [PATCH 47/62] updates made to padding and reset/module functionality. --- .../Atoms/Views/ActionDetailWithImage.swift | 45 +++++++++++++------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift b/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift index 5e32bc00..e02e2278 100644 --- a/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift +++ b/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift @@ -24,7 +24,7 @@ import UIKit // MARK: - Properties //------------------------------------------------------ - var titlePadding: CGFloat = PaddingOne + var bottomTitlePadding: CGFloat = PaddingOne //------------------------------------------------------ // MARK: - Constraints @@ -64,10 +64,7 @@ import UIKit guard subviews.isEmpty else { return } - button.setAsSecondaryCustom() - button.isHidden = false - imageLoader.imageView.contentMode = .scaleAspectFit - imageLoader.addSizeConstraintsForAspectRatio = true + setDefaultState() addSubview(leftContainer) addSubview(imageLoader) @@ -121,9 +118,11 @@ import UIKit imageLoader.updateView(size) leftContainer.updateView(size) - let topPadding = title.hasText ? titlePadding : 0 - messageTopConstraint?.constant = topPadding - buttonTopConstraint?.constant = message.hasText ? PaddingTwo : topPadding + let titleMessagePadding = title.hasText ? bottomTitlePadding : 0 + let messageButtonPadding = message.hasText ? titleMessagePadding : 0 + + messageTopConstraint?.constant = messageButtonPadding + buttonTopConstraint?.constant = message.hasText ? PaddingTwo : messageButtonPadding } public override static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { @@ -134,17 +133,38 @@ import UIKit // MARK: - Methods //------------------------------------------------------ + private func setDefaultState() { + + title.font = MFStyler.fontH3() + message.font = MFStyler.fontB3() + button.setAsSecondaryCustom() + button.isHidden = false + imageLoader.imageView.contentMode = .scaleAspectFit + imageLoader.addSizeConstraintsForAspectRatio = true + bottomTitlePadding = PaddingOne + } + override open func reset() { super.reset() - title.text = "" - message.text = "" + title.reset() + message.reset() + button.reset() imageLeadingConstraint?.constant = 16 imageLoader.reset() + + setDefaultState() } open override func setAsMolecule() { super.setAsMolecule() + + title.setAsMolecule() + message.setAsMolecule() + button.setAsMolecule() + imageLoader.setAsMolecule() + + setDefaultState() } open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { @@ -152,8 +172,8 @@ import UIKit guard let dictionary = json else { return } - if let padding = dictionary.optionalCGFloatForKey("titlePadding") { - titlePadding = padding + if let padding = dictionary.optionalCGFloatForKey("bottomTitlePadding") { + bottomTitlePadding = padding } title.setWithJSON(dictionary.optionalDictionaryForKey("title"), delegateObject: delegateObject, additionalData: additionalData) @@ -161,7 +181,6 @@ import UIKit imageLoader.setWithJSON(dictionary.optionalDictionaryForKey("image"), delegateObject: delegateObject, additionalData: additionalData) if let buttonDictionary = dictionary.optionalDictionaryForKey("button") { button.setWithJSON(buttonDictionary, delegateObject: delegateObject, additionalData: additionalData) - button.isHidden = false } else { button.isHidden = true } From 444fbc65f5b974aa63441a1979ed0658678cc3f1 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 12 Aug 2019 13:28:20 -0400 Subject: [PATCH 48/62] padding correction. --- MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift b/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift index e02e2278..e27897c5 100644 --- a/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift +++ b/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift @@ -118,11 +118,9 @@ import UIKit imageLoader.updateView(size) leftContainer.updateView(size) - let titleMessagePadding = title.hasText ? bottomTitlePadding : 0 - let messageButtonPadding = message.hasText ? titleMessagePadding : 0 - - messageTopConstraint?.constant = messageButtonPadding - buttonTopConstraint?.constant = message.hasText ? PaddingTwo : messageButtonPadding + let topPadding = title.hasText ? bottomTitlePadding : 0 + messageTopConstraint?.constant = topPadding + buttonTopConstraint?.constant = message.hasText ? PaddingTwo : topPadding } public override static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { From d754944fcdbb306c4eed6537cfc7de9dc561cd38 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Mon, 12 Aug 2019 15:28:06 -0400 Subject: [PATCH 49/62] text alignment and mark fix --- MVMCoreUI/Atoms/Views/Label.swift | 12 ++++++++++++ .../ThreeLayerTableViewController.swift | 3 +-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 57a16ad8..8c41cefc 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -178,6 +178,17 @@ public typealias ActionBlock = () -> Void setLabel(label, withHTML: json?.optionalStringForKey("html")) + if let alignment = json?.optionalStringForKey("textAlignment") { + switch alignment { + case "center": + label.textAlignment = .center + case "trailing": + label.textAlignment = .right + default: + label.textAlignment = .left + } + } + if let backgroundColorHex = json?.optionalStringForKey(KeyBackgroundColor), !backgroundColorHex.isEmpty { label.backgroundColor = UIColor.mfGet(forHex: backgroundColorHex) } @@ -368,6 +379,7 @@ extension Label { public func reset() { text = nil attributedText = nil + textAlignment = .left originalAttributedString = nil styleB2(true) } diff --git a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift index 85127a45..51a936b0 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift @@ -21,7 +21,7 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { private var topViewBottomConstraint: NSLayoutConstraint? private var bottomViewTopConstraint: NSLayoutConstraint? - //MARK: - MVMCoreViewProtocol + //MARK: - MFViewController open override func updateViews() { super.updateViews() let width = view.bounds.width @@ -37,7 +37,6 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { self.tableView?.reloadData() } - //MARK: - MFViewController open override func newDataBuildScreen() { super.newDataBuildScreen() createViewForTableHeader() From 2424176131a1cf4dbb6062ac0a54c30574824664 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 13 Aug 2019 09:14:56 -0400 Subject: [PATCH 50/62] Calculation of size fix --- .../ThreeLayerTableViewController.swift | 21 ++++++++++--------- MVMCoreUI/Utility/MVMCoreUIUtility.h | 3 ++- MVMCoreUI/Utility/MVMCoreUIUtility.m | 11 ++++++++-- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift index 51a936b0..9d3052a0 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift @@ -28,11 +28,11 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { MFStyler.setDefaultMarginsFor(contentView, size: width) if let topView = topView as? MVMCoreViewProtocol { topView.updateView(width) - showHeader() + showHeader(width) } if let bottomView = bottomView as? MVMCoreViewProtocol { bottomView.updateView(width) - showFooter() + showFooter(width) } self.tableView?.reloadData() } @@ -102,14 +102,15 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { currentSpaceForCompare = currentSpace * 2; } + let width = view.bounds.width if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpaceForCompare, 0.1) { if fillTop && fillBottom { // space both let half = newSpace / 2 topViewBottomConstraint?.constant = half bottomViewTopConstraint?.constant = half - showHeader() - showFooter() + showHeader(width) + showFooter(width) } else if fillTop { // Only top is spaced (half the size if the bottom view is out of the scroll because it needs to be sized as if there are two spacers but there is only one. if bottomViewOutsideOfScrollArea { @@ -117,11 +118,11 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { } else { topViewBottomConstraint?.constant = newSpace } - showHeader() + showHeader(width) } else if fillBottom { // Only bottom is spaced. bottomViewTopConstraint?.constant = newSpace - showFooter() + showFooter(width) } } } @@ -140,7 +141,7 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { topViewBottomConstraint = headerView.bottomAnchor.constraint(equalTo: topView.bottomAnchor, constant: spaceBelowTopView() ?? 0) topViewBottomConstraint?.isActive = true self.headerView = headerView - showHeader() + showHeader(nil) } /// Gets the bottom view and adds it to a spacing view, footerView, and then calls showFooter. @@ -156,11 +157,11 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { footerView.rightAnchor.constraint(equalTo: bottomView.rightAnchor).isActive = true footerView.bottomAnchor.constraint(equalTo: bottomView.bottomAnchor).isActive = true self.footerView = footerView - showFooter() + showFooter(nil) } /// Takes the current headerView and adds it to the tableHeaderView - func showHeader() { + func showHeader(_ sizingWidth: CGFloat?) { headerView?.removeFromSuperview() tableView?.tableHeaderView = nil guard let headerView = headerView else { @@ -176,7 +177,7 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { } /// Takes the current footerView and adds it to the tableFooterView - func showFooter() { + func showFooter(_ sizingWidth: CGFloat?) { footerView?.removeFromSuperview() safeAreaView?.removeFromSuperview() guard let footerView = footerView, let tableView = tableView else { diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.h b/MVMCoreUI/Utility/MVMCoreUIUtility.h index b6698537..9300de90 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.h +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.h @@ -71,8 +71,9 @@ NS_ASSUME_NONNULL_BEGIN // Gets the constraint height to be whatever space is left in the scroll view. + (CGFloat)getVariableConstraintHeight:(CGFloat)currentConstant inScrollView:(nonnull UIScrollView *)scrollView minimumHeight:(CGFloat)minimumHeight; -// Sets the view's frame according to constraint. +/// Sets the view's frame according to constraints. + (void)sizeViewToFit:(nullable UIView *)view; ++ (void)sizeViewToFit:(UIView *)view forWidth:(nullable NSNumber *)width; #pragma mark - Keyboard diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.m b/MVMCoreUI/Utility/MVMCoreUIUtility.m index 8201e999..e8523a61 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.m @@ -119,7 +119,7 @@ #pragma mark - Sizing + (CGFloat)getWidth { - UIViewController *controller = [MVMCoreUISession sharedGlobal].splitViewController ?: [MVMCoreUISession sharedGlobal].navigationController ?: [UIApplication sharedApplication].keyWindow.rootViewController; + UIViewController *controller = [MVMCoreUISession sharedGlobal].splitViewController ?: [MVMCoreUISession sharedGlobal].navigationController; if (controller) { return CGRectGetWidth(controller.view.bounds); } else { @@ -138,7 +138,7 @@ } + (CGFloat)getHeightOfView:(nonnull UIView *)view forWidth:(nullable NSNumber *)width { - CGFloat floatWidth = (width ? width.floatValue : CGRectGetWidth([MVMCoreNavigationHandler sharedNavigationHandler].navigationController.view.bounds)); + CGFloat floatWidth = (width ? width.floatValue : [MVMCoreUIUtility getWidth]); return [view systemLayoutSizeFittingSize:CGSizeMake(floatWidth, UILayoutFittingCompressedSize.height) withHorizontalFittingPriority:1000 verticalFittingPriority:250].height; } @@ -192,6 +192,13 @@ view.frame = frame; } ++ (void)sizeViewToFit:(UIView *)view forWidth:(nullable NSNumber *)width { + CGFloat height = [MVMCoreUIUtility getHeightOfView:view forWidth:width]; + CGRect frame = view.frame; + frame.size.height = height; + view.frame = frame; +} + #pragma mark - Keyboard + (void)setScrollViewInsetForKeyboardShow:(nonnull NSNotification *)notification scrollView:(nonnull UIScrollView *)scrollView viewController:(nonnull UIViewController *)viewController rectToScrollTo:(nonnull CGRect (^)(void))rectToScrollTo { From 324b132051425bbf8c86416edf9ceb9a406bdc8c Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 13 Aug 2019 09:27:38 -0400 Subject: [PATCH 51/62] padding change. --- MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift b/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift index e27897c5..4792dbd6 100644 --- a/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift +++ b/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift @@ -118,9 +118,9 @@ import UIKit imageLoader.updateView(size) leftContainer.updateView(size) - let topPadding = title.hasText ? bottomTitlePadding : 0 - messageTopConstraint?.constant = topPadding - buttonTopConstraint?.constant = message.hasText ? PaddingTwo : topPadding + + messageTopConstraint?.constant = title.hasText && message.hasText ? bottomTitlePadding : 0 + buttonTopConstraint?.constant = message.hasText || title.hasText ? PaddingTwo : 0 } public override static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { From 669d087a57fff27a33d765d27a0d5abd55b8c82b Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 13 Aug 2019 09:38:05 -0400 Subject: [PATCH 52/62] moved file. --- MVMCoreUI.xcodeproj/project.pbxproj | 2 +- .../{Atoms/Views => Molecules}/ActionDetailWithImage.swift | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename MVMCoreUI/{Atoms/Views => Molecules}/ActionDetailWithImage.swift (100%) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index a0b4ef65..37c71b4f 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -478,6 +478,7 @@ D29DF10E21E67A77003B2FB9 /* Molecules */ = { isa = PBXGroup; children = ( + 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */, 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */, D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */, D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */, @@ -650,7 +651,6 @@ D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */, DBC4391C2245232D001AB423 /* LabelWithInternalButton.swift */, DB891E822253FA8500022516 /* Label.swift */, - 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */, 0198F7A02256A80A0066C936 /* MFRadioButton.h */, 0198F7A22256A80A0066C936 /* MFRadioButton.m */, ); diff --git a/MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift b/MVMCoreUI/Molecules/ActionDetailWithImage.swift similarity index 100% rename from MVMCoreUI/Atoms/Views/ActionDetailWithImage.swift rename to MVMCoreUI/Molecules/ActionDetailWithImage.swift From ab08845708d20a78c7b4409beb567d03f8403aa6 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 13 Aug 2019 15:38:06 -0400 Subject: [PATCH 53/62] fix inset defect for safe area --- MVMCoreUI/Atoms/Views/MFView.m | 3 +++ .../BaseControllers/MFProgrammaticTableViewController.m | 3 +++ .../BaseControllers/ThreeLayerTableViewController.swift | 1 - MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift | 5 +++++ MVMCoreUI/Molecules/MoleculeTableViewCell.swift | 5 +++++ 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Atoms/Views/MFView.m b/MVMCoreUI/Atoms/Views/MFView.m index 740c5ad5..4e0d71ab 100644 --- a/MVMCoreUI/Atoms/Views/MFView.m +++ b/MVMCoreUI/Atoms/Views/MFView.m @@ -48,6 +48,9 @@ - (void)setAsMolecule { self.translatesAutoresizingMaskIntoConstraints = NO; + if (@available(iOS 11.0, *)) { + self.insetsLayoutMarginsFromSafeArea = NO; + } } - (void)reset { diff --git a/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.m b/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.m index b728b063..98d2b5ef 100644 --- a/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.m +++ b/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.m @@ -61,6 +61,9 @@ tableView.separatorStyle = UITableViewCellSeparatorStyleNone; tableView.delegate = self; tableView.dataSource = self; + if (@available(iOS 11.0, *)) { + tableView.insetsContentViewsToSafeArea = NO; + } if ([tableView respondsToSelector:@selector(setCellLayoutMarginsFollowReadableWidth:)]) { tableView.cellLayoutMarginsFollowReadableWidth = NO; } diff --git a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift index 9d3052a0..0293e860 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift @@ -25,7 +25,6 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { open override func updateViews() { super.updateViews() let width = view.bounds.width - MFStyler.setDefaultMarginsFor(contentView, size: width) if let topView = topView as? MVMCoreViewProtocol { topView.updateView(width) showHeader(width) diff --git a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift index 6afec1bc..42a5e5cd 100644 --- a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift @@ -37,6 +37,11 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi } isAccessibilityElement = false contentView.isAccessibilityElement = false + if #available(iOS 11.0, *) { + insetsLayoutMarginsFromSafeArea = false + contentView.insetsLayoutMarginsFromSafeArea = false + contentView.preservesSuperviewLayoutMargins = false + } // Covers the card when peaking. peakingCover.backgroundColor = .white diff --git a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/MoleculeTableViewCell.swift index c6241667..00ea68ac 100644 --- a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/MoleculeTableViewCell.swift @@ -80,6 +80,11 @@ import UIKit public func setupView() { selectionStyle = .none + if #available(iOS 11.0, *) { + insetsLayoutMarginsFromSafeArea = false + contentView.insetsLayoutMarginsFromSafeArea = false + contentView.preservesSuperviewLayoutMargins = false + } } // MARK: - MVMCoreUIMoleculeViewProtocol From d5e49d0e5a4fb038de0aeebb8f5d1f2879784223 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 15 Aug 2019 10:50:29 -0400 Subject: [PATCH 54/62] progress bar fixes --- MVMCoreUI.xcodeproj/project.pbxproj | 8 +- MVMCoreUI/Atoms/Views/ViewConstrainingView.h | 3 + MVMCoreUI/Atoms/Views/ViewConstrainingView.m | 8 +- MVMCoreUI/Molecules/CornerLabels.swift | 159 ++++++++++++++++++ MVMCoreUI/Molecules/ProgressBar.swift | 84 ++++++--- .../Molecules/ProgressBarWithLabel.swift | 100 ----------- .../MVMCoreUIMoleculeMappingObject.m | 2 +- 7 files changed, 231 insertions(+), 133 deletions(-) create mode 100644 MVMCoreUI/Molecules/CornerLabels.swift delete mode 100644 MVMCoreUI/Molecules/ProgressBarWithLabel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 37c71b4f..22b92460 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -20,7 +20,7 @@ 01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; }; B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; }; - B8200E192281DC1A007245F4 /* ProgressBarWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */; }; + B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* CornerLabels.swift */; }; D206997721FB8A0B00CAE0DE /* MVMCoreUINavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; D206997821FB8A0B00CAE0DE /* MVMCoreUINavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = D206997621FB8A0B00CAE0DE /* MVMCoreUINavigationController.m */; }; D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; }; @@ -198,7 +198,7 @@ 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = ""; }; 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = ""; }; B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; - B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarWithLabel.swift; sourceTree = ""; }; + B8200E182281DC1A007245F4 /* CornerLabels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerLabels.swift; sourceTree = ""; }; D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUINavigationController.h; sourceTree = ""; }; D206997621FB8A0B00CAE0DE /* MVMCoreUINavigationController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUINavigationController.m; sourceTree = ""; }; D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = ""; }; @@ -492,7 +492,7 @@ D274CA322236A78900B01B62 /* StandardFooterView.swift */, D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */, B8200E142280C4CF007245F4 /* ProgressBar.swift */, - B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */, + B8200E182281DC1A007245F4 /* CornerLabels.swift */, D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */, D2A638FC22CA98280052ED1F /* HeadlineBody.swift */, D2A6390022CBB1820052ED1F /* Carousel.swift */, @@ -1019,7 +1019,7 @@ D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */, D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */, D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */, - B8200E192281DC1A007245F4 /* ProgressBarWithLabel.swift in Sources */, + B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */, D2A514592211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m in Sources */, 0105618D224BBE7700E1557D /* FormValidator.swift in Sources */, D22D1F1B220341F60077CEC0 /* MVMCoreUICheckBox.m in Sources */, diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.h b/MVMCoreUI/Atoms/Views/ViewConstrainingView.h index b07fd6bb..a5e359d0 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.h +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.h @@ -73,6 +73,9 @@ // Add a view to be constrained in this view. - (void)addConstrainedView:(nonnull UIView *)view; +/// Can override to change how the molecule is added when shouldSetupMoleculeFromJSON = true. Inserts the molecule at 0 and calls pinToSuperView. +- (void)addMolecule:(nonnull UIView *)molecule; + // Change the alignment of the label - (void)alignLeft; - (void)alignCenterHorizontal; diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m index dff48826..8f8ec010 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m @@ -241,6 +241,11 @@ } } +- (void)addMolecule:(nonnull UIView *)molecule { + [self insertSubview:molecule atIndex:0]; + [self pinViewToSuperView:molecule]; +} + #pragma mark - MVMCoreUIViewConstrainingProtocol - (void)alignHorizontal:(UIStackViewAlignment)alignment { @@ -357,8 +362,7 @@ if (moleculeJSON) { UIView *molecule = [[MVMCoreUIMoleculeMappingObject sharedMappingObject] createMoleculeForJSON:moleculeJSON delegateObject:delegateObject constrainIfNeeded:true]; if (molecule) { - [self insertSubview:molecule atIndex:0]; - [self pinViewToSuperView:molecule]; + [self addMolecule:molecule]; } self.molecule = molecule; } diff --git a/MVMCoreUI/Molecules/CornerLabels.swift b/MVMCoreUI/Molecules/CornerLabels.swift new file mode 100644 index 00000000..18730336 --- /dev/null +++ b/MVMCoreUI/Molecules/CornerLabels.swift @@ -0,0 +1,159 @@ +// +// ProgressBarView.swift +// MVMCoreUI +// +// Created by Panth Patel on 5/3/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers public class CornerLabels: ViewConstrainingView { + + let topLeftLabel = Label.commonLabelB1(true) + let topRightLabel = Label.commonLabelB1(true) + let bottomLeftLabel = Label.commonLabelB3(true) + let bottomRightLabel = Label.commonLabelB3(true) + let topLabelsView = MVMCoreUICommonViewsUtility.commonView() + let bottomLabelsView = MVMCoreUICommonViewsUtility.commonView() + + /// The space between the molecule and top labels. Set to 0 if the top labels or molecule are not set. + var spaceAboveMolecule: CGFloat = 6.0 { + didSet { + if spaceAboveMolecule != oldValue { + topLabelToMoleculeConstraint?.constant = spaceAboveMolecule + } + } + } + + /// The space between the molecule and bottom labels. Set to 0 if the bottom labels or molecule are not set. + var spaceBelowMolecule: CGFloat = 6.0 { + didSet { + if spaceBelowMolecule != oldValue { + bottomLabelToMoleculeConstraint?.constant = spaceBelowMolecule + } + } + } + + var topLabelToMoleculeConstraint: NSLayoutConstraint? + var bottomLabelToMoleculeConstraint: NSLayoutConstraint? + + public override func addMolecule(_ molecule: UIView) { + insertSubview(molecule, at: 0) + topLabelToMoleculeConstraint?.isActive = false + bottomLabelToMoleculeConstraint?.isActive = false + + molecule.leftAnchor.constraint(equalTo: leftAnchor).isActive = true + rightAnchor.constraint(equalTo: molecule.rightAnchor).isActive = true + + topLabelToMoleculeConstraint = molecule.topAnchor.constraint(equalTo: topLabelsView.bottomAnchor, constant: spaceAboveMolecule) + topLabelToMoleculeConstraint?.isActive = true + bottomLabelToMoleculeConstraint = bottomLabelsView.topAnchor.constraint(equalTo: molecule.bottomAnchor, constant: spaceBelowMolecule) + bottomLabelToMoleculeConstraint?.isActive = true + } + + // MARK: - MVMCoreViewProtocol + open override func updateView(_ size: CGFloat) { + super.updateView(size) + topLeftLabel.updateView(size) + topRightLabel.updateView(size) + bottomLeftLabel.updateView(size) + bottomRightLabel.updateView(size) + } + + public override func setupView() { + super.setupView() + shouldSetupMoleculeFromJSON = true + + guard topLeftLabel.superview == nil else { + return + } + + addSubview(topLabelsView) + addSubview(bottomLabelsView) + topLabelsView.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true + topLabelsView.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor).isActive = true + layoutMarginsGuide.rightAnchor.constraint(equalTo: topLabelsView.rightAnchor).isActive = true + + topLabelToMoleculeConstraint = bottomLabelsView.topAnchor.constraint(equalTo: topLabelsView.bottomAnchor, constant: 0) + topLabelToMoleculeConstraint?.isActive = true + bottomLabelToMoleculeConstraint = topLabelToMoleculeConstraint + + bottomLabelsView.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor).isActive = true + layoutMarginsGuide.rightAnchor.constraint(equalTo: bottomLabelsView.rightAnchor).isActive = true + layoutMarginsGuide.bottomAnchor.constraint(equalTo: bottomLabelsView.bottomAnchor).isActive = true + + topLabelsView.addSubview(topLeftLabel) + topLabelsView.addSubview(topRightLabel) + bottomLabelsView.addSubview(bottomLeftLabel) + bottomLabelsView.addSubview(bottomRightLabel) + + topLeftLabel.topAnchor.constraint(equalTo: topLabelsView.topAnchor).isActive = true + topLeftLabel.leftAnchor.constraint(equalTo: topLabelsView.leftAnchor).isActive = true + topLabelsView.bottomAnchor.constraint(greaterThanOrEqualTo: topLeftLabel.bottomAnchor).isActive = true + topRightLabel.topAnchor.constraint(equalTo: topLabelsView.topAnchor).isActive = true + topLabelsView.rightAnchor.constraint(equalTo: topRightLabel.rightAnchor).isActive = true + topLabelsView.bottomAnchor.constraint(greaterThanOrEqualTo: topRightLabel.bottomAnchor).isActive = true + + var constraint = topLabelsView.bottomAnchor.constraint(equalTo: topLeftLabel.bottomAnchor) + constraint.priority = .defaultHigh + constraint.isActive = true + + constraint = topLabelsView.bottomAnchor.constraint(equalTo: topRightLabel.bottomAnchor) + constraint.priority = .defaultHigh + constraint.isActive = true + + bottomLeftLabel.topAnchor.constraint(equalTo: bottomLabelsView.topAnchor).isActive = true + bottomLeftLabel.leftAnchor.constraint(equalTo: bottomLabelsView.leftAnchor).isActive = true + bottomLabelsView.bottomAnchor.constraint(greaterThanOrEqualTo: bottomLeftLabel.bottomAnchor).isActive = true + bottomRightLabel.topAnchor.constraint(equalTo: bottomLabelsView.topAnchor).isActive = true + bottomRightLabel.rightAnchor.constraint(equalTo: bottomLabelsView.rightAnchor).isActive = true + bottomLabelsView.bottomAnchor.constraint(greaterThanOrEqualTo: bottomRightLabel.bottomAnchor).isActive = true + + constraint = bottomLabelsView.bottomAnchor.constraint(equalTo: bottomLeftLabel.bottomAnchor) + constraint.priority = .defaultHigh + constraint.isActive = true + + constraint = bottomLabelsView.bottomAnchor.constraint(equalTo: bottomRightLabel.bottomAnchor) + constraint.priority = .defaultHigh + constraint.isActive = true + } + + // MARK: - MVMCoreUIMoleculeViewProtocol + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + topLeftLabel.setWithJSON(json?.optionalDictionaryForKey("topLeftLabel"), delegateObject: delegateObject, additionalData: additionalData) + topRightLabel.setWithJSON(json?.optionalDictionaryForKey("topRightLabel"), delegateObject: delegateObject, additionalData: additionalData) + bottomLeftLabel.setWithJSON(json?.optionalDictionaryForKey("bottomLeftLabel"), delegateObject: delegateObject, additionalData: additionalData) + bottomRightLabel.setWithJSON(json?.optionalDictionaryForKey("bottomRightLabel"), delegateObject: delegateObject, additionalData: additionalData) + + topLabelToMoleculeConstraint?.constant = (molecule != nil && (topLeftLabel.hasText || topRightLabel.hasText)) ? spaceAboveMolecule : 0 + bottomLabelToMoleculeConstraint?.constant = (molecule != nil && (bottomLeftLabel.hasText || bottomRightLabel.hasText)) ? spaceBelowMolecule : 0 + } + + public override func setAsMolecule() { + super.setAsMolecule() + topLeftLabel.setAsMolecule() + topRightLabel.setAsMolecule() + bottomLeftLabel.setAsMolecule() + bottomRightLabel.setAsMolecule() + } + + public override func reset() { + super.reset() + + topLeftLabel.styleB1(true) + topRightLabel.styleB1(true) + bottomLeftLabel.styleB3(true) + bottomRightLabel.styleB3(true) + + spaceAboveMolecule = 6.0 + spaceBelowMolecule = 6.0 + + molecule?.reset?() + } + + public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return 34 + } +} diff --git a/MVMCoreUI/Molecules/ProgressBar.swift b/MVMCoreUI/Molecules/ProgressBar.swift index a9d7ad48..5416f0a7 100644 --- a/MVMCoreUI/Molecules/ProgressBar.swift +++ b/MVMCoreUI/Molecules/ProgressBar.swift @@ -8,41 +8,73 @@ import Foundation -public class ProgressBar: UIProgressView { - - var isRounded = Bool() - var thickness : Float = 0.0 { +@objcMembers open class ProgressBar: UIProgressView, MVMCoreUIMoleculeViewProtocol, MVMCoreViewProtocol { + var isRounded = false + var thickness: CGFloat = 8.0 { willSet(newValue) { - heightAnchor.constraint(equalToConstant: CGFloat(newValue)).isActive = true - switch isRounded { - case true: - layer.cornerRadius = CGFloat(newValue/2) - clipsToBounds = true - default: + heightAnchor.constraint(equalToConstant: newValue).isActive = true + if isRounded { + layer.cornerRadius = newValue/2.0 + } else { progressViewStyle = .bar } } } + public override init(frame: CGRect) { + super.init(frame: frame) + setupView() + } + + public required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setupView() + } + + init() { + super.init(frame: .zero) + setupView() + } + + // MARK: - MVMCoreViewProtocol + public func setupView() { + clipsToBounds = true + translatesAutoresizingMaskIntoConstraints = false + reset() + } + + public func updateView(_ size: CGFloat) { + } + + // MARK: - MVMCoreUIMoleculeViewProtocol public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - isRounded = json?.optionalBoolForKey("roundedRect") ?? false - thickness = json?.floatFromStringForKey("thickness") ?? Float(0.0) - let percentage = json?.floatFromStringForKey("percent") - progress = (percentage ?? Float(0.0))/100 - progressTintColor = UIColor.mfBattleshipGrey() - trackTintColor = UIColor.mfLighterGray() - - if let progresscolor = json?.optionalStringForKey("progressColor") { - if !progresscolor.isEmpty { - progressTintColor = UIColor.mfGet(forHex: progresscolor) - } + if let isRounded = json?.optionalBoolForKey("roundedRect") { + self.isRounded = isRounded } - - if let backgroundcolor = json?.optionalStringForKey("backgroundColor") { - if !backgroundcolor.isEmpty { - trackTintColor = UIColor.mfGet(forHex: backgroundcolor) - } + if let thickness = json?.optionalCGFloatForKey("thickness") { + self.thickness = thickness } + if let percentage = json?["percent"] as? Float { + progress = percentage/100.0 + } + if let progressColor = json?.optionalStringForKey("progressColor") { + progressTintColor = UIColor.mfGet(forHex: progressColor) + } + if let backgroundColor = json?.optionalStringForKey("backgroundColor") { + trackTintColor = UIColor.mfGet(forHex: backgroundColor) + } + } + + public func reset() { + isRounded = false + thickness = 8 + progress = 0 + progressTintColor = UIColor.mfCerulean() + trackTintColor = UIColor.mfSilver() + } + + public static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return 8 } } diff --git a/MVMCoreUI/Molecules/ProgressBarWithLabel.swift b/MVMCoreUI/Molecules/ProgressBarWithLabel.swift deleted file mode 100644 index 9740e1ba..00000000 --- a/MVMCoreUI/Molecules/ProgressBarWithLabel.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// ProgressBarView.swift -// MVMCoreUI -// -// Created by Panth Patel on 5/3/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import UIKit - -@objcMembers public class ProgressBarWithLabel: ViewConstrainingView { - - var progress = ProgressBar() - var topleftlabel = Label() - var toprightlabel = Label() - var bottomleftlabel = Label() - var bottomrightlabel = Label() - - open override func needsToBeConstrained() -> Bool { - return true - } - - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - let progressbarjson = json?.optionalDictionaryForKey("progressbar") - progress.setWithJSON(progressbarjson, delegateObject: delegateObject, additionalData: additionalData) - - let topleftlabeljson = json?.optionalDictionaryForKey("label") - let toprightlabeljson = json?.optionalDictionaryForKey("toprightlabel") - let bottomleftlabeljson = json?.optionalDictionaryForKey("bottomleftlabel") - let bottomrightlabeljson = json?.optionalDictionaryForKey("bottomrightlabel") - - topleftlabel.setWithJSON(topleftlabeljson, delegateObject: delegateObject, additionalData: additionalData) - toprightlabel.setWithJSON(toprightlabeljson, delegateObject: delegateObject, additionalData: additionalData) - bottomleftlabel.setWithJSON(bottomleftlabeljson, delegateObject: delegateObject, additionalData: additionalData) - bottomrightlabel.setWithJSON(bottomrightlabeljson, delegateObject: delegateObject, additionalData: additionalData) - } - - override open func setupView() { - super.setupView() - addSubview(topleftlabel) - addSubview(toprightlabel) - addSubview(bottomleftlabel) - addSubview(bottomrightlabel) - addSubview(progress) - - progress.translatesAutoresizingMaskIntoConstraints = false - - topleftlabel.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true - topleftlabel.topAnchor.constraint(equalTo: self.topAnchor).isActive = true - let topleftwidthconstraint = NSLayoutConstraint(item: topleftlabel, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 0.5, constant: 0.0) - topleftwidthconstraint.priority = UILayoutPriority(100) - topleftwidthconstraint.isActive = true - topleftlabel.setContentHuggingPriority(UILayoutPriority(801), for: .horizontal) - topleftlabel.setContentHuggingPriority(UILayoutPriority(801), for: .vertical) - - NSLayoutConstraint(item: toprightlabel, attribute: .leading, relatedBy: .equal, toItem: topleftlabel, attribute: .trailing, multiplier: 1.0, constant: PaddingTwo).isActive = true - toprightlabel.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true - toprightlabel.topAnchor.constraint(equalTo: self.topAnchor).isActive = true - toprightlabel.textAlignment = .right - toprightlabel.setContentHuggingPriority(UILayoutPriority(802), for: .horizontal) - toprightlabel.setContentHuggingPriority(UILayoutPriority(802), for: .vertical) - - var topconstraint = progress.topAnchor.constraint(equalTo: topleftlabel.bottomAnchor, constant: PaddingTwo) - topconstraint.priority = UILayoutPriority(249) - topconstraint.isActive = true - progress.topAnchor.constraint(greaterThanOrEqualTo: topleftlabel.bottomAnchor, constant: PaddingTwo).isActive = true - topconstraint = progress.topAnchor.constraint(equalTo: toprightlabel.bottomAnchor, constant: PaddingTwo) - topconstraint.priority = UILayoutPriority(249) - topconstraint.isActive = true - progress.topAnchor.constraint(greaterThanOrEqualTo: toprightlabel.bottomAnchor, constant: PaddingTwo).isActive = true - - progress.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true - progress.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true - - bottomleftlabel.topAnchor.constraint(equalTo: progress.bottomAnchor, constant: PaddingTwo).isActive = true - bottomleftlabel.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true - let bottomleftwidthconstraint = NSLayoutConstraint(item: bottomleftlabel, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 0.5, constant: 0.0) - bottomleftwidthconstraint.priority = UILayoutPriority(100) - bottomleftwidthconstraint.isActive = true - bottomleftlabel.setContentHuggingPriority(UILayoutPriority(801), for: .horizontal) - bottomleftlabel.setContentHuggingPriority(UILayoutPriority(801), for: .vertical) - - NSLayoutConstraint(item: bottomrightlabel, attribute: .leading, relatedBy: .equal, toItem: bottomleftlabel, attribute: .trailing, multiplier: 1.0, constant: PaddingTwo).isActive = true - bottomrightlabel.topAnchor.constraint(equalTo: progress.bottomAnchor, constant: PaddingTwo).isActive = true - bottomrightlabel.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true - bottomrightlabel.textAlignment = .right - bottomrightlabel.setContentHuggingPriority(UILayoutPriority(802), for: .horizontal) - bottomrightlabel.setContentHuggingPriority(UILayoutPriority(802), for: .vertical) - - var bottomconstraint = bottomAnchor.constraint(equalTo: bottomleftlabel.bottomAnchor, constant: PaddingTwo) - bottomconstraint.priority = UILayoutPriority(249) - bottomconstraint.isActive = true - bottomAnchor.constraint(greaterThanOrEqualTo: bottomleftlabel.bottomAnchor, constant: PaddingTwo).isActive = true - bottomconstraint = bottomAnchor.constraint(equalTo: bottomrightlabel.bottomAnchor, constant: PaddingTwo) - bottomconstraint.priority = UILayoutPriority(249) - bottomconstraint.isActive = true - bottomAnchor.constraint(greaterThanOrEqualTo: bottomrightlabel.bottomAnchor, constant: PaddingTwo).isActive = true - } -} diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index cd829697..0dffc356 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -39,7 +39,7 @@ @"textField" : MFTextField.class, @"digitTextField" : MFDigitTextField.class, @"checkbox" : MVMCoreUICheckBox.class, - @"progressBarWithLabel" : ProgressBarWithLabel.class, + @"cornerLabels" : CornerLabels.class, @"progressBar": ProgressBar.class, @"textField": MFTextField.class, @"checkbox": MVMCoreUICheckBox.class, From f3f8d57a0be72d49751c55aab79e9c06aa3e2ebf Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 15 Aug 2019 10:59:25 -0400 Subject: [PATCH 55/62] timing fix... --- MVMCoreUI/Atoms/Views/Label.swift | 2 +- MVMCoreUI/Molecules/CornerLabels.swift | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 8c41cefc..06ddbed5 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -182,7 +182,7 @@ public typealias ActionBlock = () -> Void switch alignment { case "center": label.textAlignment = .center - case "trailing": + case "right": label.textAlignment = .right default: label.textAlignment = .left diff --git a/MVMCoreUI/Molecules/CornerLabels.swift b/MVMCoreUI/Molecules/CornerLabels.swift index 18730336..930e1c57 100644 --- a/MVMCoreUI/Molecules/CornerLabels.swift +++ b/MVMCoreUI/Molecules/CornerLabels.swift @@ -133,26 +133,26 @@ import UIKit public override func setAsMolecule() { super.setAsMolecule() - topLeftLabel.setAsMolecule() - topRightLabel.setAsMolecule() - bottomLeftLabel.setAsMolecule() - bottomRightLabel.setAsMolecule() + styleDefault() } public override func reset() { super.reset() - topLeftLabel.styleB1(true) - topRightLabel.styleB1(true) - bottomLeftLabel.styleB3(true) - bottomRightLabel.styleB3(true) - + styleDefault() spaceAboveMolecule = 6.0 spaceBelowMolecule = 6.0 molecule?.reset?() } + func styleDefault() { + topLeftLabel.styleB1(true) + topRightLabel.styleB1(true) + bottomLeftLabel.styleB3(true) + bottomRightLabel.styleB3(true) + } + public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 34 } From d810667473d3a38d7fe07545b091fb3001738a2e Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 15 Aug 2019 12:08:44 -0400 Subject: [PATCH 56/62] Fixes! --- MVMCoreUI/Atoms/Views/ViewConstrainingView.m | 10 +++++++--- MVMCoreUI/Styles/MFStyler.m | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m index 8f8ec010..ba5f1bd0 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m @@ -357,16 +357,20 @@ [super setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; [self.molecule setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; - if (self.shouldSetupMoleculeFromJSON && !self.molecule) { + if (self.shouldSetupMoleculeFromJSON) { NSDictionary *moleculeJSON = [json dict:KeyMolecule]; - if (moleculeJSON) { + if (self.molecule) { + [self.molecule setWithJSON:moleculeJSON delegateObject:delegateObject additionalData:additionalData]; + } else if (moleculeJSON) { UIView *molecule = [[MVMCoreUIMoleculeMappingObject sharedMappingObject] createMoleculeForJSON:moleculeJSON delegateObject:delegateObject constrainIfNeeded:true]; if (molecule) { [self addMolecule:molecule]; } self.molecule = molecule; + [self setMoleculeAccessibility]; } - [self setMoleculeAccessibility]; + } else { + [self.molecule setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; } NSNumber *useHorizontalMargins = [json optionalNumberForKey:@"useHorizontalMargins"]; diff --git a/MVMCoreUI/Styles/MFStyler.m b/MVMCoreUI/Styles/MFStyler.m index 2b0d0a0a..12840284 100644 --- a/MVMCoreUI/Styles/MFStyler.m +++ b/MVMCoreUI/Styles/MFStyler.m @@ -97,7 +97,7 @@ CGFloat const LabelWithInternalButtonLineSpace = 2; + (void)setDefaultMarginsForView:(nullable UIView *)view size:(CGFloat)size horizontal:(BOOL)horizontal vertical:(BOOL)vertical { [MVMCoreDispatchUtility performBlockOnMainThread:^{ CGFloat horizontalPadding = horizontal ? [MFStyler defaultHorizontalPaddingForSize:size] : 0; - CGFloat verticalPadding = vertical ? PaddingDefaultVerticalSpacing : 0; + CGFloat verticalPadding = vertical ? 24 : 0; [MVMCoreUIUtility setMarginsForView:view leading:horizontalPadding top:verticalPadding trailing:horizontalPadding bottom:verticalPadding]; }]; } From 10755d888fae5bc24a9157ee42b405ac4cbbe1f9 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 15 Aug 2019 15:24:37 -0400 Subject: [PATCH 57/62] change vertical --- MVMCoreUI/Molecules/MoleculeTableViewCell.swift | 7 +------ MVMCoreUI/Styles/MFStyler.h | 1 + MVMCoreUI/Styles/MFStyler.m | 3 ++- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/MoleculeTableViewCell.swift index 00ea68ac..c1054e33 100644 --- a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/MoleculeTableViewCell.swift @@ -123,11 +123,6 @@ import UIKit contentView.addSubview(moleculeView) let standardConstraints = (moleculeView as? MVMCoreUIViewConstrainingProtocol)?.useStandardConstraints?() ?? true NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: standardConstraints).values)) - if standardConstraints { - let constraint = contentView.heightAnchor.constraint(equalToConstant: 80) - constraint.priority = .defaultLow - constraint.isActive = true - } molecule = moleculeView } } else { @@ -152,7 +147,7 @@ import UIKit guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) else { return 80 } - return max(80, height) + return max(2 * PaddingDefaultVerticalSpacing3, height) } public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { diff --git a/MVMCoreUI/Styles/MFStyler.h b/MVMCoreUI/Styles/MFStyler.h index bda6c112..2ab3c2f2 100644 --- a/MVMCoreUI/Styles/MFStyler.h +++ b/MVMCoreUI/Styles/MFStyler.h @@ -29,6 +29,7 @@ typedef NS_ENUM(NSUInteger, MFTimeFormatUnit) { extern CGFloat const PaddingDefault; extern CGFloat const PaddingDefaultHorizontalSpacing; extern CGFloat const PaddingDefaultVerticalSpacing; +extern CGFloat const PaddingDefaultVerticalSpacing3; extern CGFloat const PaddingBetweenFields; extern CGFloat const PaddingHorizontalHeadlineWhiteView; extern CGFloat const PaddingHorizontalLarge; diff --git a/MVMCoreUI/Styles/MFStyler.m b/MVMCoreUI/Styles/MFStyler.m index 12840284..dfc9909a 100644 --- a/MVMCoreUI/Styles/MFStyler.m +++ b/MVMCoreUI/Styles/MFStyler.m @@ -18,6 +18,7 @@ CGFloat const PaddingDefault = 24; CGFloat const PaddingDefaultHorizontalSpacing = 32; CGFloat const PaddingDefaultVerticalSpacing = 32; +CGFloat const PaddingDefaultVerticalSpacing3 = 24; CGFloat const PaddingBetweenFields = 24; CGFloat const PaddingHorizontalHeadlineWhiteView = 60; CGFloat const PaddingHorizontalLarge = 72; @@ -97,7 +98,7 @@ CGFloat const LabelWithInternalButtonLineSpace = 2; + (void)setDefaultMarginsForView:(nullable UIView *)view size:(CGFloat)size horizontal:(BOOL)horizontal vertical:(BOOL)vertical { [MVMCoreDispatchUtility performBlockOnMainThread:^{ CGFloat horizontalPadding = horizontal ? [MFStyler defaultHorizontalPaddingForSize:size] : 0; - CGFloat verticalPadding = vertical ? 24 : 0; + CGFloat verticalPadding = vertical ? PaddingDefaultVerticalSpacing3 : 0; [MVMCoreUIUtility setMarginsForView:view leading:horizontalPadding top:verticalPadding trailing:horizontalPadding bottom:verticalPadding]; }]; } From 84ecaa9a81a13ae6f4af5e94ddcd7625f306e630 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Mon, 19 Aug 2019 13:30:50 -0400 Subject: [PATCH 58/62] height changes minor --- MVMCoreUI/Atoms/Views/MFLoadImageView.swift | 26 +++++++++------------ 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift index c0066afe..21802b38 100644 --- a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift +++ b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift @@ -25,8 +25,8 @@ import UIKit var delegateObject: MVMCoreUIDelegateObject? // For keeping track of current state. - private var edges: UIRectEdge? - private var spinnerHeight: CGFloat? + private var edges = UIRectEdge(rawValue: 0) + private var spinnerHeight: CGFloat = 0 private var currentImageWidth: CGFloat? private var currentImageHeight: CGFloat? private var currentImageName: String? @@ -39,7 +39,6 @@ import UIKit // The default is an image that is centered with no edges pinned. So it will take the size of the content and fill as needed. public init() { - edges = UIRectEdge(rawValue: 0) super.init(frame: .zero) } @@ -93,10 +92,7 @@ import UIKit pinView(toSuperView: imageView) // Setup edges constraints - if edges == nil { - edges = UIRectEdge(rawValue: 0) - } - pinEdges(edges!) + pinEdges(edges) // Setup spinner. loadingSpinner.clipsToBounds = true @@ -185,7 +181,8 @@ import UIKit let widthWillChange = !MVMCoreGetterUtility.cgfequal(widthConstraint?.constant ?? 0, width ?? 0) let heightWillChange = !MVMCoreGetterUtility.cgfequal(heightConstraint?.constant ?? 0, height ?? 0) let sizeWillChange = (width == nil || height == nil) && !(size?.equalTo(imageView.image?.size ?? CGSize.zero) ?? false) - return widthWillChange || heightWillChange || sizeWillChange + let heightChangeFromSpinner = ((height ?? size?.height) ?? 0) < loadingSpinnerHeightConstraint?.constant ?? CGFloat.leastNormalMagnitude + return widthWillChange || heightWillChange || sizeWillChange || heightChangeFromSpinner } // Constrains the image view to be the size provided. Used to size it to the image to fix aspect fit defect. @@ -252,9 +249,9 @@ import UIKit self.currentImageName = imageName self.currentImageWidth = width?.cgfloat() self.currentImageHeight = height?.cgfloat() - self.loadingSpinner.resumeSpinnerAfterDelay() - if let height = self.spinnerHeight { - self.loadingSpinnerHeightConstraint?.constant = height + if MVMCoreCache.isHostedImage(imageName) { + self.loadingSpinner.resumeSpinnerAfterDelay() + self.loadingSpinnerHeightConstraint?.constant = self.spinnerHeight } let finishedLoadingBlock: MVMCoreGetImageBlock = {[weak self] (image, data, isFallbackImage) in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in @@ -262,10 +259,10 @@ import UIKit return } self?.isFallbackImage = isFallbackImage - self?.loadingSpinnerHeightConstraint?.constant = 0 self?.loadingSpinner.pause() let layoutWillChange = self?.layoutWillChange(width: self?.currentImageWidth, height: self?.currentImageHeight, size: image?.size) ?? false self?.addConstraints(width: width, height: height, size: image?.size) + self?.loadingSpinnerHeightConstraint?.constant = 0 if layoutWillChange { self?.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated?(self!) } @@ -287,9 +284,8 @@ import UIKit MVMCoreDispatchUtility.performBlock(onMainThread: { [unowned self] in self.currentImageName = imageName self.loadingSpinner.resumeSpinnerAfterDelay() - if let height = self.spinnerHeight { - self.loadingSpinnerHeightConstraint?.constant = height - } + self.loadingSpinnerHeightConstraint?.constant = self.spinnerHeight + MVMCoreCache.shared()?.getCroppedImage(imageName, useWidth: width != nil, widthForS7: width?.intValue ?? 0, useHeight: height != nil, heightForS7: height?.intValue ?? 0, finalRect: cropRect, flipImage: flipImage, localFallbackImageName: customFallbackImage ?? MVMCoreUIUtility.localizedImageName("fallback"), completionHandler: { [weak self] (image, data, isFallBackImage) in MVMCoreDispatchUtility.performBlock(onMainThread: { guard let image = image, let loadingImageName = self?.currentImageName, loadingImageName == imageName else { From 021036d88c5b8b2eadffc3d06d580735542bf64c Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Mon, 19 Aug 2019 16:16:50 -0400 Subject: [PATCH 59/62] fix to use margins --- MVMCoreUI/Molecules/CornerLabels.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Molecules/CornerLabels.swift b/MVMCoreUI/Molecules/CornerLabels.swift index 930e1c57..2454563c 100644 --- a/MVMCoreUI/Molecules/CornerLabels.swift +++ b/MVMCoreUI/Molecules/CornerLabels.swift @@ -43,8 +43,8 @@ import UIKit topLabelToMoleculeConstraint?.isActive = false bottomLabelToMoleculeConstraint?.isActive = false - molecule.leftAnchor.constraint(equalTo: leftAnchor).isActive = true - rightAnchor.constraint(equalTo: molecule.rightAnchor).isActive = true + molecule.leftAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true + layoutMarginsGuide.trailingAnchor.constraint(equalTo: molecule.rightAnchor).isActive = true topLabelToMoleculeConstraint = molecule.topAnchor.constraint(equalTo: topLabelsView.bottomAnchor, constant: spaceAboveMolecule) topLabelToMoleculeConstraint?.isActive = true From 11669c173e6c3ed9d81d09c773061a601cfd600d Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Mon, 19 Aug 2019 16:18:27 -0400 Subject: [PATCH 60/62] typo fix --- MVMCoreUI/Molecules/CornerLabels.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Molecules/CornerLabels.swift b/MVMCoreUI/Molecules/CornerLabels.swift index 2454563c..f1c33e4d 100644 --- a/MVMCoreUI/Molecules/CornerLabels.swift +++ b/MVMCoreUI/Molecules/CornerLabels.swift @@ -43,8 +43,8 @@ import UIKit topLabelToMoleculeConstraint?.isActive = false bottomLabelToMoleculeConstraint?.isActive = false - molecule.leftAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true - layoutMarginsGuide.trailingAnchor.constraint(equalTo: molecule.rightAnchor).isActive = true + molecule.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor).isActive = true + layoutMarginsGuide.rightAnchor.constraint(equalTo: molecule.rightAnchor).isActive = true topLabelToMoleculeConstraint = molecule.topAnchor.constraint(equalTo: topLabelsView.bottomAnchor, constant: spaceAboveMolecule) topLabelToMoleculeConstraint?.isActive = true From 6a2405989dc241916db3b91547f960f014e2e091 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 20 Aug 2019 10:00:07 -0400 Subject: [PATCH 61/62] Fixes to ambiguity --- MVMCoreUI/Molecules/CornerLabels.swift | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Molecules/CornerLabels.swift b/MVMCoreUI/Molecules/CornerLabels.swift index f1c33e4d..2a2ad379 100644 --- a/MVMCoreUI/Molecules/CornerLabels.swift +++ b/MVMCoreUI/Molecules/CornerLabels.swift @@ -69,6 +69,9 @@ import UIKit return } + topRightLabel.textAlignment = .right + bottomRightLabel.textAlignment = .right + addSubview(topLabelsView) addSubview(bottomLabelsView) topLabelsView.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true @@ -96,11 +99,11 @@ import UIKit topLabelsView.bottomAnchor.constraint(greaterThanOrEqualTo: topRightLabel.bottomAnchor).isActive = true var constraint = topLabelsView.bottomAnchor.constraint(equalTo: topLeftLabel.bottomAnchor) - constraint.priority = .defaultHigh + constraint.priority = topLeftLabel.contentHuggingPriority(for: .vertical) - 10 constraint.isActive = true constraint = topLabelsView.bottomAnchor.constraint(equalTo: topRightLabel.bottomAnchor) - constraint.priority = .defaultHigh + constraint.priority = topRightLabel.contentHuggingPriority(for: .vertical) - 10 constraint.isActive = true bottomLeftLabel.topAnchor.constraint(equalTo: bottomLabelsView.topAnchor).isActive = true @@ -111,11 +114,11 @@ import UIKit bottomLabelsView.bottomAnchor.constraint(greaterThanOrEqualTo: bottomRightLabel.bottomAnchor).isActive = true constraint = bottomLabelsView.bottomAnchor.constraint(equalTo: bottomLeftLabel.bottomAnchor) - constraint.priority = .defaultHigh + constraint.priority = bottomLeftLabel.contentHuggingPriority(for: .vertical) - 10 constraint.isActive = true constraint = bottomLabelsView.bottomAnchor.constraint(equalTo: bottomRightLabel.bottomAnchor) - constraint.priority = .defaultHigh + constraint.priority = bottomRightLabel.contentHuggingPriority(for: .vertical) - 10 constraint.isActive = true } From a9539c6c896512cf566c7f134c7083fd716b7e01 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 20 Aug 2019 10:44:15 -0400 Subject: [PATCH 62/62] Fix competition --- MVMCoreUI/Molecules/CornerLabels.swift | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Molecules/CornerLabels.swift b/MVMCoreUI/Molecules/CornerLabels.swift index 2a2ad379..06917608 100644 --- a/MVMCoreUI/Molecules/CornerLabels.swift +++ b/MVMCoreUI/Molecules/CornerLabels.swift @@ -88,9 +88,12 @@ import UIKit topLabelsView.addSubview(topLeftLabel) topLabelsView.addSubview(topRightLabel) + setCompetitionConstraints(topLeftLabel,topRightLabel) + bottomLabelsView.addSubview(bottomLeftLabel) bottomLabelsView.addSubview(bottomRightLabel) - + setCompetitionConstraints(bottomLeftLabel,bottomRightLabel) + topLeftLabel.topAnchor.constraint(equalTo: topLabelsView.topAnchor).isActive = true topLeftLabel.leftAnchor.constraint(equalTo: topLabelsView.leftAnchor).isActive = true topLabelsView.bottomAnchor.constraint(greaterThanOrEqualTo: topLeftLabel.bottomAnchor).isActive = true @@ -105,7 +108,9 @@ import UIKit constraint = topLabelsView.bottomAnchor.constraint(equalTo: topRightLabel.bottomAnchor) constraint.priority = topRightLabel.contentHuggingPriority(for: .vertical) - 10 constraint.isActive = true - + + topRightLabel.leftAnchor.constraint(equalTo: topLeftLabel.rightAnchor, constant: 16).isActive = true + bottomLeftLabel.topAnchor.constraint(equalTo: bottomLabelsView.topAnchor).isActive = true bottomLeftLabel.leftAnchor.constraint(equalTo: bottomLabelsView.leftAnchor).isActive = true bottomLabelsView.bottomAnchor.constraint(greaterThanOrEqualTo: bottomLeftLabel.bottomAnchor).isActive = true @@ -120,6 +125,19 @@ import UIKit constraint = bottomLabelsView.bottomAnchor.constraint(equalTo: bottomRightLabel.bottomAnchor) constraint.priority = bottomRightLabel.contentHuggingPriority(for: .vertical) - 10 constraint.isActive = true + + bottomRightLabel.leftAnchor.constraint(greaterThanOrEqualTo: bottomLeftLabel.rightAnchor, constant: 16).isActive = true + } + + /// Sets the rules for the labels if they were to collide. The first view will take priority, but the second view has a minimum width when competing. + func setCompetitionConstraints(_ view1: UIView,_ view2: UIView) { + view1.setContentHuggingPriority(UILayoutPriority(rawValue: 700), for: .horizontal) + view2.setContentHuggingPriority(UILayoutPriority(rawValue: 750), for: .horizontal) + view1.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 350), for: .horizontal) + view2.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 300), for: .horizontal) + let width = view2.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.40) + width.priority = UILayoutPriority(rawValue: 400) + width.isActive = true } // MARK: - MVMCoreUIMoleculeViewProtocol