From 7870a116c69c7d974aabae4d5bc731cbe07307d7 Mon Sep 17 00:00:00 2001 From: panxi Date: Thu, 31 Oct 2019 16:15:47 -0400 Subject: [PATCH 1/8] create circle progress view --- MVMCoreUI.xcodeproj/project.pbxproj | 8 + MVMCoreUI/Atoms/Views/GraphView.swift | 280 ++++++++++++++++++ .../Views/GraphViewAnimationHandler.swift | 32 ++ .../MVMCoreUIMoleculeMappingObject.m | 1 + 4 files changed, 321 insertions(+) create mode 100644 MVMCoreUI/Atoms/Views/GraphView.swift create mode 100644 MVMCoreUI/Atoms/Views/GraphViewAnimationHandler.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index a0ef1271..eee7013d 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -28,6 +28,8 @@ 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; }; 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; }; + 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F3236B77BB006A1E82 /* GraphView.swift */; }; + 943784F6236B77BB006A1E82 /* GraphViewAnimationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */; }; 9455B19C234F8A0400A574DB /* MVMAnimationFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9455B19B234F8A0400A574DB /* MVMAnimationFramework.framework */; }; 948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948DB67D2326DCD90011F916 /* MultiProgress.swift */; }; D206997721FB8A0B00CAE0DE /* MVMCoreUINavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -223,6 +225,8 @@ 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = ""; }; 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = ""; }; 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxWithLabelView.swift; sourceTree = ""; }; + 943784F3236B77BB006A1E82 /* GraphView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphView.swift; sourceTree = ""; }; + 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphViewAnimationHandler.swift; sourceTree = ""; }; 9455B19B234F8A0400A574DB /* MVMAnimationFramework.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MVMAnimationFramework.framework; path = ../SharedFrameworks/MVMAnimationFramework.framework; sourceTree = ""; }; 948DB67D2326DCD90011F916 /* MultiProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiProgress.swift; sourceTree = ""; }; D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUINavigationController.h; sourceTree = ""; }; @@ -751,6 +755,8 @@ 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */, 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */, 01004F2F22721C3800991ECC /* RadioButton.swift */, + 943784F3236B77BB006A1E82 /* GraphView.swift */, + 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */, ); path = Views; sourceTree = ""; @@ -1038,6 +1044,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */, D29DF32121ED0CBA003B2FB9 /* LabelView.m in Sources */, DBC4391822442197001AB423 /* CaretView.swift in Sources */, D29770F221F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m in Sources */, @@ -1124,6 +1131,7 @@ D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */, D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */, D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */, + 943784F6236B77BB006A1E82 /* GraphViewAnimationHandler.swift in Sources */, D29DF2AA21E7B2F9003B2FB9 /* MVMCoreUIConstants.m in Sources */, 948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */, D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */, diff --git a/MVMCoreUI/Atoms/Views/GraphView.swift b/MVMCoreUI/Atoms/Views/GraphView.swift new file mode 100644 index 00000000..ebd074a0 --- /dev/null +++ b/MVMCoreUI/Atoms/Views/GraphView.swift @@ -0,0 +1,280 @@ +// +// GraphView.swift +// MobileFirstFramework +// +// Created by Ryan on 10/24/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + + +enum GraphSize: String { + case small, medium, large +} + +enum GraphStyle: String { + case unlimited, safetyMode +} + +///Graph Object contains properties +public struct GraphObject { + + var style: GraphStyle { + didSet { + updateStyle() + } + } + var size: GraphSize { + didSet { + updateSize() + } + } + var diameter: CGFloat = 24 + var lineWidth: CGFloat = 5 + var clockwise: Bool = true + var duration : Double = 1.0 + var colors = [CGColor]() + + public init(_ json: [AnyHashable : Any]?) { + style = .unlimited + size = .small + guard let json = json else { + return + } + if let styleString = json.optionalStringForKey("style") { + style = GraphStyle(rawValue: styleString) ?? .unlimited + } + if let sizeString = json.optionalStringForKey("size") { + size = GraphSize(rawValue: sizeString) ?? .small + } + updateStyle() + updateSize() + if let diameter = json.optionalCGFloatForKey("diameter") { + self.diameter = diameter + } + if let lineWidth = json.optionalCGFloatForKey("lineWidth") { + self.lineWidth = lineWidth + } + if let clockwise = json.optionalBoolForKey("clockwise") { + self.clockwise = clockwise + } + if let duration = json["duration"] as? Double { + self.duration = duration + } + if let colorArray = json.optionalArrayForKey("colors") as? [String] { + colors = getCGColorsFromArray(colorArray) + } + } + + func getCGColorsFromArray(_ colorArray: [String]) -> [CGColor] { + return colorArray.map { (colorString) -> CGColor in + return UIColor.mfGet(forHex: colorString).cgColor + } + } + + mutating func updateStyle() { + switch style { + case .unlimited: + duration = 1.0 + clockwise = true + //current style, only the end part shows darker look + colors = getCGColorsFromArray(["#007AB8","#007AB8","#033554"]) + break + case .safetyMode: + duration = 1.5 + clockwise = true + colors = getCGColorsFromArray(["#CC4D0F","#CC4D0F","AB0309"]) + break + } + } + + //those are + mutating func updateSize() { + switch size { + case .small: + diameter = MFSizeObject(standardSize: 24)?.getValueBasedOnApplicationWidth() ?? 24 + lineWidth = MFSizeObject(standardSize: 5)?.getValueBasedOnApplicationWidth() ?? 5 + break + case .medium: + diameter = MFSizeObject(standardSize: 100)?.getValueBasedOnApplicationWidth() ?? 100 + lineWidth = MFSizeObject(standardSize: 8)?.getValueBasedOnApplicationWidth() ?? 8 + break + case .large: + diameter = MFSizeObject(standardSize: 180)?.getValueBasedOnApplicationWidth() ?? 180 + lineWidth = MFSizeObject(standardSize: 12)?.getValueBasedOnApplicationWidth() ?? 12 + break + } + } +} + + +@objcMembers open class GraphView: View { + + var heightConstraint: NSLayoutConstraint? + var gradientLayer: CALayer? + var graphObject: GraphObject? + + +// MARK: setup + open override func setupView() { + super.setupView() + //avoid adding height constraint multiple times + guard heightConstraint == nil else { return } + heightConstraint = heightAnchor.constraint(equalToConstant: 0) + heightConstraint?.isActive = true + widthAnchor.constraint(equalTo: heightAnchor).isActive = true + } + + override open func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + let object = GraphObject(json) + graphObject = object + createGraphCircle(object) + rotationAnimation(object) + } + + class func getAngle(_ piValue: Double) -> Double { + return piValue / (2.0 * Double.pi) * 360.0 + } + + class func getPiValue(_ angle: Double) -> Double { + return angle / 360.0 * 2.0 * Double.pi + } + +// MARK: circle + open func createGraphCircle(_ graphObject: GraphObject) { + if let sublayers = layer.sublayers { + for sublayer in sublayers { + sublayer.removeAllAnimations() + sublayer.removeFromSuperlayer() + } + } + heightConstraint?.constant = graphObject.diameter + + //create circle path + let radius = graphObject.diameter / 2.0 + + //begin point will be at the bottom, clockwise direction + let path = UIBezierPath(arcCenter: CGPoint(x: radius + , y: radius), radius: radius - graphObject.lineWidth/2.0, startAngle: CGFloat(GraphView.getPiValue(90.0)), endAngle: CGFloat(GraphView.getPiValue(90.0 + 360.0)), clockwise: true) + path.lineWidth = graphObject.lineWidth + + let circleLayer = CAShapeLayer() + circleLayer.path = path.cgPath + circleLayer.lineCap = .round + circleLayer.lineWidth = graphObject.lineWidth + circleLayer.fillColor = UIColor.clear.cgColor + circleLayer.strokeColor = UIColor.black.cgColor + + //create gradient layer + let gradientLayer = createGradientLayer(graphObject) + gradientLayer.mask = circleLayer + layer.addSublayer(gradientLayer) + self.gradientLayer = gradientLayer + } + +/* + create three gradient layer for circle layout. + _____________ + | → | top layer for smooth gradient + ------------- + | | | + | ↑ | ↓ | + | | | + ------------- +*/ + func createGradientLayer(_ graphObject: GraphObject) -> CALayer { + let containLayer = CALayer() + containLayer.frame = CGRect(x: 0, y: 0, width: graphObject.diameter, height: graphObject.diameter) + let radius = graphObject.diameter / 2.0 + + //create graident layers + guard graphObject.colors.count > 1 else { + containLayer.backgroundColor = graphObject.colors.first + return containLayer + } + var topGradientHeight : CGFloat = 0.0 + var leftColors = graphObject.colors.prefix(through: graphObject.colors.count/2) + let rightColors = graphObject.colors.suffix(from: graphObject.colors.count/2) + + // make the top layer higher than line width for smooth look + topGradientHeight = min(max(graphObject.lineWidth, 1.0/(1.0+CGFloat(graphObject.colors.count))*graphObject.diameter), graphObject.diameter) + let topLayer = CAGradientLayer() + topLayer.frame = CGRect(x: 0.0, y: 0.0, width: graphObject.diameter, height: topGradientHeight) + //make the graident edge more smoothy + topLayer.startPoint = CGPoint(x: 0.25, y: 0.0) + topLayer.endPoint = CGPoint(x: 0.75, y: 0.0) + //if number of colors is even, need to display gradient layer, otherwise make top layer as solid color layer + if graphObject.colors.count % 2 == 0 { + leftColors.removeLast() + topLayer.colors = [leftColors.last!, rightColors.first!] + } else { + topLayer.backgroundColor = leftColors.last + } + containLayer.addSublayer(topLayer) + + let leftLayer = CAGradientLayer() + leftLayer.frame = CGRect(x: 0, y: topGradientHeight, width: radius, height: graphObject.diameter - topGradientHeight) + leftLayer.startPoint = CGPoint(x: 0, y: 1) + leftLayer.endPoint = CGPoint(x: 0, y: 0) + + //count of graidentLayer.colors must be bigger than 1, otherwise set backgroundColor + if leftColors.count > 1 { + leftLayer.colors = Array(leftColors) + } else { + leftLayer.backgroundColor = leftColors.first + } + containLayer.addSublayer(leftLayer) + + let rightLayer = CAGradientLayer() + rightLayer.frame = CGRect(x: radius, y: topGradientHeight, width: radius, height: graphObject.diameter - topGradientHeight) + rightLayer.startPoint = CGPoint(x: 0, y: 0) + rightLayer.endPoint = CGPoint(x: 0, y: 1) + if rightColors.count > 1 { + rightLayer.colors = Array(rightColors) + } else { + rightLayer.backgroundColor = rightColors.first + } + containLayer.addSublayer(rightLayer) + + return containLayer + } + +//MARK: Animation + func rotationAnimation(_ object: GraphObject) { + MVMCoreDispatchUtility.performBlock(onMainThread:{ + let rotation = CABasicAnimation(keyPath: "transform.rotation") + let animationHandler = GraphViewAnimationHandler.shared + let startAngle = animationHandler.getAnimationStartAngle(object.duration, CACurrentMediaTime()) + if startAngle == 0.0 { + animationHandler.storeAnimation(object.duration, CACurrentMediaTime()) + } + var fromValue = GraphView.getPiValue(0.0 + startAngle), toValue = GraphView.getPiValue(360.0 + startAngle) + if !object.clockwise { + fromValue = GraphView.getPiValue(360.0 - startAngle) + toValue = GraphView.getPiValue(0.0 - startAngle) + } + rotation.fromValue = fromValue + rotation.toValue = toValue + rotation.duration = object.duration + rotation.timingFunction = CAMediaTimingFunction(name: .linear) + rotation.fillMode = .both + rotation.isRemovedOnCompletion = false + + //avoid infinity animation take high CPU momery usage when layer is not displayed + rotation.delegate = self + rotation.repeatCount = 1 + self.gradientLayer?.add(rotation, forKey: "rotation") + }) + } +} + + +extension GraphView: CAAnimationDelegate { + public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { + if let object = graphObject { + rotationAnimation(object) + } + } +} diff --git a/MVMCoreUI/Atoms/Views/GraphViewAnimationHandler.swift b/MVMCoreUI/Atoms/Views/GraphViewAnimationHandler.swift new file mode 100644 index 00000000..2d7489dc --- /dev/null +++ b/MVMCoreUI/Atoms/Views/GraphViewAnimationHandler.swift @@ -0,0 +1,32 @@ +// +// GraphViewAnimationHandler.swift +// MobileFirstFramework +// +// Created by Ryan on 10/29/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers open class GraphViewAnimationHandler: NSObject { + + /// duration : CACurrentMediaTime() + private var animations = [Double: Double]() + + static let shared = GraphViewAnimationHandler() + + open func storeAnimation(_ duration: Double, _ currentTime: CFTimeInterval) { + guard animations[duration] == nil else { + return + } + animations[duration] = currentTime + } + + open func getAnimationStartAngle(_ duration: Double, _ currentTime: CFTimeInterval) -> Double { + if let time = animations[duration] { + return (currentTime - time) / duration * 360 + 90 + } + return 0.0 + } + +} diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index e64f643f..8b3f098c 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -42,6 +42,7 @@ @"checkboxWithLabelView" : CheckboxWithLabelView.class, @"cornerLabels" : CornerLabels.class, @"progressbar": ProgressBar.class, + @"circleProgress": GraphView.class, @"multiProgressBar": MultiProgress.class, @"checkbox": MVMCoreUICheckBox.class, @"radioButton": RadioButton.class, From a212dff80f6c9e98d3e5bc66d6d5ffb4fff4cd8c Mon Sep 17 00:00:00 2001 From: "Suresh, Kamlesh" Date: Thu, 7 Nov 2019 10:45:40 -0500 Subject: [PATCH 2/8] fixes --- MVMCoreUI/Atoms/Buttons/PrimaryButton.m | 2 +- MVMCoreUI/Atoms/Views/Checkbox.swift | 4 +++- MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m | 4 ++++ MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/MVMCoreUI/Atoms/Buttons/PrimaryButton.m b/MVMCoreUI/Atoms/Buttons/PrimaryButton.m index 35395557..3b1802e5 100644 --- a/MVMCoreUI/Atoms/Buttons/PrimaryButton.m +++ b/MVMCoreUI/Atoms/Buttons/PrimaryButton.m @@ -669,7 +669,7 @@ - (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { - self.validationRequired = [json boolForKey:@"validationRequired"]; + self.validationRequired = [json boolForKey:@"required"]; self.requiredGroupsList = [json array:@"requiredGroups"]; [FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol]; diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index e5a82b1d..370f5826 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -19,6 +19,7 @@ import MVMCore // Form Validation var isRequired = false var fieldKey: String? + var fieldValue: String? var groupName: String? var delegateObject: MVMCoreUIDelegateObject? @@ -407,6 +408,7 @@ import MVMCore guard let dictionary = json else { return } groupName = dictionary.optionalStringForKey("groupName") + fieldValue = dictionary.optionalStringForKey("value") if let fieldKey = dictionary[KeyFieldKey] as? String { self.fieldKey = fieldKey } @@ -475,6 +477,6 @@ extension Checkbox: FormValidationFormFieldProtocol { } public func formFieldValue() -> Any? { - return NSNumber(value: isSelected) + return isSelected ? fieldValue : nil } } diff --git a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m index ae0db4a7..8ec71241 100644 --- a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m +++ b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m @@ -423,6 +423,10 @@ const CGFloat SwitchShakeIntensity = 2; return UIAccessibilityTraitButton; } +- (NSString * _Nullable)formFieldGroupName { + return [self.json string:@"groupName"]; +} + - (NSString *)accessibilityHint { return [MVMCoreUIUtility hardcodedStringWithKey:@"AccToggleHint"]; } diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 8b3f098c..5298b10c 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -39,7 +39,7 @@ @"textField" : MFTextField.class, @"digitTextField" : MFDigitTextField.class, @"checkbox" : Checkbox.class, - @"checkboxWithLabelView" : CheckboxWithLabelView.class, + @"checkboxWithLabel" : CheckboxWithLabelView.class, @"cornerLabels" : CornerLabels.class, @"progressbar": ProgressBar.class, @"circleProgress": GraphView.class, From 14f68614932c1817521bf55c8aa701ffc165888b Mon Sep 17 00:00:00 2001 From: "Murugan, Vimal" Date: Fri, 8 Nov 2019 22:11:56 +0530 Subject: [PATCH 3/8] moved top and bottom pin to scrolling view controller --- MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.h | 2 -- MVMCoreUI/BaseControllers/MFScrollingViewController.h | 3 +++ MVMCoreUI/BaseControllers/ProgrammaticScrollViewController.h | 2 -- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.h b/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.h index 01ab9820..a568a27a 100644 --- a/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.h +++ b/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.h @@ -12,8 +12,6 @@ @interface MFProgrammaticTableViewController : MFScrollingViewController @property (nullable, weak, nonatomic) UITableView *tableView; -@property (nullable, nonatomic, strong) NSLayoutConstraint *topConstraint; -@property (nullable, nonatomic, strong) NSLayoutConstraint *bottomConstraint; // Registers classes and nibs. Can subclass for different nibs. Can call super and then add new ones after as well. - (void)registerWithTable; diff --git a/MVMCoreUI/BaseControllers/MFScrollingViewController.h b/MVMCoreUI/BaseControllers/MFScrollingViewController.h index 52799769..f44de6c4 100644 --- a/MVMCoreUI/BaseControllers/MFScrollingViewController.h +++ b/MVMCoreUI/BaseControllers/MFScrollingViewController.h @@ -13,6 +13,9 @@ @property (nullable, weak, nonatomic) IBOutlet UIScrollView *scrollView; @property (nullable, weak, nonatomic) IBOutlet UIView *contentView; +@property (nullable, nonatomic, strong) NSLayoutConstraint *topConstraint; +@property (nullable, nonatomic, strong) NSLayoutConstraint *bottomConstraint; + // Recognizes single tap/touches to screen for dismissing keyboard @property (nonnull, strong, nonatomic) UITapGestureRecognizer *dismissKeyboardTapGesture; diff --git a/MVMCoreUI/BaseControllers/ProgrammaticScrollViewController.h b/MVMCoreUI/BaseControllers/ProgrammaticScrollViewController.h index f9f32f69..9e486066 100644 --- a/MVMCoreUI/BaseControllers/ProgrammaticScrollViewController.h +++ b/MVMCoreUI/BaseControllers/ProgrammaticScrollViewController.h @@ -10,7 +10,5 @@ @interface ProgrammaticScrollViewController : MFScrollingViewController -@property (nullable, nonatomic, strong) NSLayoutConstraint *topConstraint; -@property (nullable, nonatomic, strong) NSLayoutConstraint *bottomConstraint; @end From 32c04e05ba8ed49167f822376e118b63f3d0bf8b Mon Sep 17 00:00:00 2001 From: "Khan, Arshad" Date: Fri, 8 Nov 2019 23:26:07 +0530 Subject: [PATCH 4/8] Making moleculesInfo public for providing flexibility in sub classes. As of now required for Settings template in MF code. --- 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 ea2913c2..7fcbe1f6 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -9,7 +9,7 @@ import UIKit open class MoleculeListTemplate: ThreeLayerTableViewController { - var moleculesInfo: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])]? + public var moleculesInfo: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])]? var observer: NSKeyValueObservation? open override var loadObject: MVMCoreLoadObject? { From a5186973ae93d0cb2c174cb9986cfa7ad317a865 Mon Sep 17 00:00:00 2001 From: "Khan, Arshad" Date: Mon, 11 Nov 2019 21:27:08 +0530 Subject: [PATCH 5/8] Adding support for secondaryButton, if server dynamically sends only secondary button in TwoButtonView molecule. --- .../TwoButtonView.swift | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift b/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift index 28ad6dc4..592abb36 100644 --- a/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift +++ b/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift @@ -125,6 +125,18 @@ import UIKit } } + open func setupWithSecondaryButton() { + guard self.secondaryButton == nil else { + return + } + createSecondaryButton() + if let secondaryButton = secondaryButton { + addSubview(secondaryButton) + pinView(toSuperView: secondaryButton) + alignCenterHorizontal() + } + } + // Sets up the number of buttons based on the maps. Doesn't set the buttons with the maps because legacy code handles differently from modern code... func setupUI(withPrimaryButtonMap primaryButtonMap: [AnyHashable: Any]?, secondaryButtonMap: [AnyHashable: Any]?, legacy: Bool) { if primaryButtonMap != nil, secondaryButtonMap != nil { @@ -140,6 +152,10 @@ import UIKit removeButtons() setupWithPrimaryButton() } + } else if secondaryButtonMap != nil { + heightConstraint?.isActive = false + removeButtons() + setupWithSecondaryButton() } else { removeButtons() if heightConstraint == nil { From f6c2935115eebfd75e2c23813296844a14034e7e Mon Sep 17 00:00:00 2001 From: "Khan, Arshad" Date: Mon, 11 Nov 2019 22:41:24 +0530 Subject: [PATCH 6/8] Implemented Scott feedback. --- .../TwoButtonView.swift | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift b/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift index 592abb36..bc45f67d 100644 --- a/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift +++ b/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift @@ -114,7 +114,8 @@ import UIKit } open func setupWithPrimaryButton() { - guard self.primaryButton == nil else { + // should not allow primaryButton addition, if secondaryButton exists + guard (self.primaryButton == nil && self.secondaryButton == nil) else { return } createPrimaryButton() @@ -126,7 +127,8 @@ import UIKit } open func setupWithSecondaryButton() { - guard self.secondaryButton == nil else { + // should not allow secondaryButton addition, if primaryButton exists + guard (self.secondaryButton == nil && self.primaryButton == nil) else { return } createSecondaryButton() @@ -137,16 +139,14 @@ import UIKit } } - // Sets up the number of buttons based on the maps. Doesn't set the buttons with the maps because legacy code handles differently from modern code... - func setupUI(withPrimaryButtonMap primaryButtonMap: [AnyHashable: Any]?, secondaryButtonMap: [AnyHashable: Any]?, legacy: Bool) { + func setupUI(withPrimaryButtonMap primaryButtonMap: [AnyHashable: Any]?, secondaryButtonMap: [AnyHashable: Any]?) { if primaryButtonMap != nil, secondaryButtonMap != nil { heightConstraint?.isActive = false if primaryButton == nil || secondaryButton == nil { removeButtons() setupWithTwoButtons() } - } else if primaryButtonMap != nil || (secondaryButtonMap != nil && legacy) { - // Only legacy sets up the primary button with a secondary map + } else if primaryButtonMap != nil { heightConstraint?.isActive = false if primaryButton == nil || secondaryButton != nil { removeButtons() @@ -166,7 +166,7 @@ import UIKit } open func set(primaryButtonJSON: [AnyHashable: Any]?, secondaryButtonJSON: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - setupUI(withPrimaryButtonMap: primaryButtonJSON, secondaryButtonMap: secondaryButtonJSON, legacy: false) + setupUI(withPrimaryButtonMap: primaryButtonJSON, secondaryButtonMap: secondaryButtonJSON) setDefaultCustom() primaryButton?.setWithJSON(primaryButtonJSON, delegateObject: delegateObject, additionalData: additionalData) secondaryButton?.setWithJSON(secondaryButtonJSON, delegateObject: delegateObject, additionalData: additionalData) @@ -194,7 +194,7 @@ import UIKit } open func setup(primaryButtonMap: [AnyHashable: Any]?, secondaryButtonMap: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable: Any]?) { - setupUI(withPrimaryButtonMap: primaryButtonMap, secondaryButtonMap: secondaryButtonMap, legacy: true) + setupUI(withPrimaryButtonMap: primaryButtonMap, secondaryButtonMap: secondaryButtonMap) if primaryButtonMap != nil, secondaryButtonMap != nil { primaryButton?.setWithActionMap(primaryButtonMap, delegateObject: delegateObject, additionalData: additionalData) secondaryButton?.setWithActionMap(secondaryButtonMap, delegateObject: delegateObject, additionalData: additionalData) @@ -202,8 +202,8 @@ import UIKit primaryButton?.setWithActionMap(primaryButtonMap, delegateObject: delegateObject, additionalData: additionalData) primaryButton?.bordered = false } else if secondaryButtonMap != nil { - primaryButton?.setWithActionMap(secondaryButtonMap, delegateObject: delegateObject, additionalData: additionalData) - primaryButton?.bordered = true + secondaryButton?.setWithActionMap(secondaryButtonMap, delegateObject: delegateObject, additionalData: additionalData) + secondaryButton?.bordered = true } } @@ -213,7 +213,7 @@ import UIKit setup(primaryButtonMap: primaryButtonMap, secondaryButtonMap: secondaryButtonMap, delegateObject: delegateObject, additionalData: additionalData) } - public func hidePrimaryLeftButton() { + public func hideLeftButton() { guard let secondaryButton = secondaryButton, !secondaryButton.isHidden else { return } @@ -225,7 +225,7 @@ import UIKit } } - public func hidePrimaryRightButton() { + public func hideRightButton() { guard let primaryButton = primaryButton, !primaryButton.isHidden else { return } @@ -237,7 +237,7 @@ import UIKit } } - public func showBothPrimaryButtons() { + public func showBothButtons() { primaryButton?.isHidden = false secondaryButton?.isHidden = false if let primaryButton = primaryButton, let secondaryButton = secondaryButton { @@ -247,7 +247,7 @@ import UIKit } } - public func hideBothPrimaryButtons() { + public func hideBothButtons() { primaryButton?.isHidden = true secondaryButton?.isHidden = true } @@ -257,7 +257,7 @@ import UIKit extension TwoButtonView { @available(*, deprecated) open func setup(primaryButtonMap: [AnyHashable: Any]?, secondaryButtonMap: [AnyHashable: Any]?, actionDelegate: NSObjectProtocol?, additionalData: [AnyHashable: Any]?, buttonDelegate: Any?) { - setupUI(withPrimaryButtonMap: primaryButtonMap, secondaryButtonMap: secondaryButtonMap, legacy: true) + setupUI(withPrimaryButtonMap: primaryButtonMap, secondaryButtonMap: secondaryButtonMap) if primaryButtonMap != nil, secondaryButtonMap != nil { primaryButton?.setWithActionMap(primaryButtonMap, actionDelegate: actionDelegate as? MVMCoreActionDelegateProtocol & NSObjectProtocol, additionalData: additionalData, buttonDelegate: buttonDelegate as? ButtonDelegateProtocol) secondaryButton?.setWithActionMap(secondaryButtonMap, actionDelegate: actionDelegate as? MVMCoreActionDelegateProtocol & NSObjectProtocol, additionalData: additionalData, buttonDelegate: buttonDelegate as? ButtonDelegateProtocol) @@ -265,8 +265,8 @@ extension TwoButtonView { primaryButton?.setWithActionMap(primaryButtonMap, actionDelegate: actionDelegate as? MVMCoreActionDelegateProtocol & NSObjectProtocol, additionalData: additionalData, buttonDelegate: buttonDelegate as? ButtonDelegateProtocol) primaryButton?.bordered = false } else if secondaryButtonMap != nil { - primaryButton?.setWithActionMap(secondaryButtonMap, actionDelegate: actionDelegate as? MVMCoreActionDelegateProtocol & NSObjectProtocol, additionalData: additionalData, buttonDelegate: buttonDelegate as? ButtonDelegateProtocol) - primaryButton?.bordered = true + secondaryButton?.setWithActionMap(secondaryButtonMap, actionDelegate: actionDelegate as? MVMCoreActionDelegateProtocol & NSObjectProtocol, additionalData: additionalData, buttonDelegate: buttonDelegate as? ButtonDelegateProtocol) + secondaryButton?.bordered = true } } From 11e549bc501c2245ff8a701dcb10ad9f87cbea3e Mon Sep 17 00:00:00 2001 From: "Khan, Arshad" Date: Mon, 11 Nov 2019 22:47:49 +0530 Subject: [PATCH 7/8] Feedback implementation impact changes. --- .../TopLabelsAndBottomButtonsTableViewController.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m index 5d6a6778..8b0a23bf 100644 --- a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m +++ b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m @@ -427,13 +427,13 @@ if ([self.bottomView isKindOfClass:[TwoButtonView class]]) { TwoButtonView *buttonView = (TwoButtonView *)self.bottomView; if (right && !left) { - [buttonView hidePrimaryRightButton]; + [buttonView hideRightButton]; } else if (!right && left) { - [buttonView hidePrimaryLeftButton]; + [buttonView hideLeftButton]; } else if (right && left) { - [buttonView hideBothPrimaryButtons]; + [buttonView hideBothButtons]; } else if (!right && !left) { - [buttonView showBothPrimaryButtons]; + [buttonView showBothButtons]; } } } From f9cecb9a5d2370c69c2f97ed2c85ed2b2acf3aa1 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Mon, 11 Nov 2019 15:24:10 -0500 Subject: [PATCH 8/8] small code updates --- .../HorizontalCombinationViews/TwoButtonView.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift b/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift index bc45f67d..2c5f0fe5 100644 --- a/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift +++ b/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift @@ -98,7 +98,7 @@ import UIKit } func setupWithTwoButtons() { - guard self.viewForButtons == nil else { + guard viewForButtons == nil else { return } let viewForButtons = MVMCoreUICommonViewsUtility.commonView() @@ -114,8 +114,7 @@ import UIKit } open func setupWithPrimaryButton() { - // should not allow primaryButton addition, if secondaryButton exists - guard (self.primaryButton == nil && self.secondaryButton == nil) else { + guard primaryButton == nil && secondaryButton == nil else { return } createPrimaryButton() @@ -127,8 +126,7 @@ import UIKit } open func setupWithSecondaryButton() { - // should not allow secondaryButton addition, if primaryButton exists - guard (self.secondaryButton == nil && self.primaryButton == nil) else { + guard secondaryButton == nil && primaryButton == nil else { return } createSecondaryButton() @@ -154,8 +152,10 @@ import UIKit } } else if secondaryButtonMap != nil { heightConstraint?.isActive = false - removeButtons() - setupWithSecondaryButton() + if secondaryButton == nil || primaryButton != nil { + removeButtons() + setupWithSecondaryButton() + } } else { removeButtons() if heightConstraint == nil {