From 8238a42177fb749d63b1e9f946bb604a83c88f9c Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 13 Sep 2019 12:28:34 -0400 Subject: [PATCH 01/48] Added the new classes. --- MVMCoreUI.xcodeproj/project.pbxproj | 8 + MVMCoreUI/Atoms/Views/CheckBox.swift | 165 ++++++++++++++++++ MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift | 46 +++++ 3 files changed, 219 insertions(+) create mode 100644 MVMCoreUI/Atoms/Views/CheckBox.swift create mode 100644 MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index c1f4a798..c8cebe2b 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -18,6 +18,8 @@ 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 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; }; + 0A7BAFA1232BE61800FB8E22 /* CheckBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* CheckBox.swift */; }; + 0A7BAFA3232BE63400FB8E22 /* CheckBoxWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckBoxWithLabel.swift */; }; 948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948DB67D2326DCD90011F916 /* MultiProgress.swift */; }; B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; }; B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* CornerLabels.swift */; }; @@ -202,6 +204,8 @@ 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 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = ""; }; + 0A7BAFA0232BE61800FB8E22 /* CheckBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckBox.swift; sourceTree = ""; }; + 0A7BAFA2232BE63400FB8E22 /* CheckBoxWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckBoxWithLabel.swift; sourceTree = ""; }; 948DB67D2326DCD90011F916 /* MultiProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiProgress.swift; sourceTree = ""; }; B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; B8200E182281DC1A007245F4 /* CornerLabels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerLabels.swift; sourceTree = ""; }; @@ -719,6 +723,8 @@ DB891E822253FA8500022516 /* Label.swift */, 0198F7A02256A80A0066C936 /* MFRadioButton.h */, 0198F7A22256A80A0066C936 /* MFRadioButton.m */, + 0A7BAFA0232BE61800FB8E22 /* CheckBox.swift */, + 0A7BAFA2232BE63400FB8E22 /* CheckBoxWithLabel.swift */, ); path = Views; sourceTree = ""; @@ -1040,6 +1046,7 @@ D282AACB2243C61700C46919 /* ButtonView.swift in Sources */, D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */, 0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */, + 0A7BAFA1232BE61800FB8E22 /* CheckBox.swift in Sources */, D22479962316AF6E003FCCF9 /* HeadlineBodyTextButton.swift in Sources */, D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */, D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */, @@ -1067,6 +1074,7 @@ D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */, D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */, D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */, + 0A7BAFA3232BE63400FB8E22 /* CheckBoxWithLabel.swift in Sources */, D29DF11D21E684A9003B2FB9 /* MVMCoreUISplitViewController.m in Sources */, 0198F79F225679880066C936 /* FormValidationProtocol.swift in Sources */, D29DF29821E7ADB8003B2FB9 /* MFScrollingViewController.m in Sources */, diff --git a/MVMCoreUI/Atoms/Views/CheckBox.swift b/MVMCoreUI/Atoms/Views/CheckBox.swift new file mode 100644 index 00000000..a990aa90 --- /dev/null +++ b/MVMCoreUI/Atoms/Views/CheckBox.swift @@ -0,0 +1,165 @@ +// +// CheckBox.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 9/13/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import MVMCore + +class CheckBox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + var lineWidth: CGFloat = 0.0 + var lineColor: UIColor? + + + let startXOffset: Float = 42.0 / 124.0 + let startYOffset: Float = 66.0 / 124.0 + let pivotXOffset: Float = 58.0 / 124.0 + let pivotYOffset: Float = 80.0 / 124.0 + let endXOffset: Float = 83.0 / 124.0 + let endYOffset: Float = 46.0 / 124.0 + let pivotPercentage: Float = 0.34 + let endPercentage = 1.0 - pivotPercentage + let animationInterval: Float = 0.01 + + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + + private var drawPercentage: Float = 0.0 + private var animationTimer: Timer? + private var checkLayer: CAShapeLayer? + private var selected = false + + func setupView() { + super.setupView() + backgroundColor = UIColor.clear + drawPercentage = 1.0 + lineColor = UIColor.black + lineWidth = 1.0 + } + + func update(_ size: CGFloat) { + super.update(size) + } + + var lineWidth: CGFloat { + get { + return super.lineWidth + } + set(lineWidth) { + self.lineWidth = lineWidth + if checkLayer { + checkLayer.removeFromSuperlayer() + checkLayer = nil + updateCheckSelected(selected, animated: false) + } + } + } + + + //-------------------------------------------------- + // MARK: - Draw + //-------------------------------------------------- + + func drawCheck() { + if !checkLayer { + layoutIfNeeded() + let path = UIBezierPath() + path.move(to: CGPoint(x: lineWidth / 2, y: bounds.size.height * 0.55)) + path.addLine(to: CGPoint(x: bounds.size.width * 0.45, y: bounds.size.height * 0.85)) + path.addLine(to: CGPoint(x: bounds.size.width - lineWidth / 2, y: lineWidth / 2)) + + checkLayer = CAShapeLayer() + checkLayer.frame = bounds + layer.addSublayer(checkLayer) + checkLayer.strokeColor = lineColor.cgColor ?? UIColor.black.cgColor + checkLayer.fillColor = UIColor.clear.cgColor + checkLayer.path = path.cgPath + checkLayer.lineWidth = lineWidth + + CATransaction.begin() + CATransaction.setDisableActions(true) + checkLayer.strokeEnd = 0.0 + CATransaction.commit() + } + } + + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + + func updateCheckSelected(_ selected: Bool, animated: Bool) { + MVMCoreDispatchUtility.performBlock(onMainThread: { + self.selected = selected + + // animate this bar + self.drawCheck() + + var layer: CAShapeLayer? + if self.checkLayer.presentation() != nil && animated { + layer = self.checkLayer.presentation() + } else { + layer = self.checkLayer + } + + if animated { + let animateStrokeEnd = CABasicAnimation(keyPath: "strokeEnd") + animateStrokeEnd.fillMode = .both + animateStrokeEnd.isRemovedOnCompletion = false + animateStrokeEnd.duration = 0.3 + + animateStrokeEnd.fromValue = NSNumber(value: Float(layer?.strokeEnd ?? 0.0)) + if selected { + animateStrokeEnd.toValue = NSNumber(value: 1) + } else { + animateStrokeEnd.toValue = NSNumber(value: 0) + } + + animateStrokeEnd.timingFunction = CAMediaTimingFunction(name: .linear) + layer?.add(animateStrokeEnd, forKey: "strokeEndAnimation") + } else { + layer?.removeAllAnimations() + CATransaction.begin() + CATransaction.setDisableActions(true) + if selected { + layer?.strokeEnd = 1.0 + } else { + layer?.strokeEnd = 0.0 + } + CATransaction.commit() + } + }) + } + + + func setLineColor(_ lineColor: UIColor?) { + self.lineColor = lineColor + if checkLayer { + checkLayer.strokeColor = lineColor?.cgColor + updateCheckSelected(selected, animated: false) + } + } + + func layoutSubviews() { + drawCheck() + } + + //-------------------------------------------------- + // MARK: - Molecular + //-------------------------------------------------- + + func updateView(_ size: CGFloat) { + <#code#> + } + + func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + <#code#> + } +} diff --git a/MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift b/MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift new file mode 100644 index 00000000..5e7c7739 --- /dev/null +++ b/MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift @@ -0,0 +1,46 @@ +// +// CheckBoxWithLabel.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 9/13/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + + +class CheckBoxWithLabel: ViewConstrainingView { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + weak var checkMark: CheckBox? + private(set) var isSelected = false + var sizeObject: MFSizeObject? + //?????? + var checkedColor: UIColor? + var unCheckedColor: UIColor? + // Label to the right of the check box. + weak var descriptionLabel: Label? + // Setter for the descriptionLabel.text. Also sets the accessibility text. + var descriptionText: String? + var descriptionAttributedText: NSAttributedString? + // A block that is called when the switch is selected. + var switchSelected: ((_ selected: Bool) -> ())? + + //-------------------------------------------------- + // MARK: - Life Cycle + //-------------------------------------------------- + + // TODO: MVMCoreUICheckBox.m + + //-------------------------------------------------- + // MARK: - Molecular + //-------------------------------------------------- + + override func updateView(_ size: CGFloat) { + + } + + override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + + } +} From bbdb0301eb612b2ee49348f91cda249fec95b3a9 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 16 Sep 2019 09:50:35 -0400 Subject: [PATCH 02/48] Further checkbox setups. --- MVMCoreUI/Atoms/Views/CheckBox.swift | 155 ++++++------ MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift | 231 ++++++++++++++++++ MVMCoreUI/Atoms/Views/MVMCoreUICheckBox.m | 2 + 3 files changed, 317 insertions(+), 71 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/CheckBox.swift b/MVMCoreUI/Atoms/Views/CheckBox.swift index a990aa90..ac6adf1a 100644 --- a/MVMCoreUI/Atoms/Views/CheckBox.swift +++ b/MVMCoreUI/Atoms/Views/CheckBox.swift @@ -8,14 +8,18 @@ import MVMCore + class CheckBox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - - var lineWidth: CGFloat = 0.0 - var lineColor: UIColor? + private var _lineColor: UIColor = .black + private var _lineWidth: CGFloat = 1.0 + + private var drawPercentage: Float = 0.0 + private var animationTimer: Timer? + private var checkLayer: CAShapeLayer? let startXOffset: Float = 42.0 / 124.0 let startYOffset: Float = 66.0 / 124.0 @@ -24,7 +28,7 @@ class CheckBox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, M let endXOffset: Float = 83.0 / 124.0 let endYOffset: Float = 46.0 / 124.0 let pivotPercentage: Float = 0.34 - let endPercentage = 1.0 - pivotPercentage + let endPercentage = 0.66 let animationInterval: Float = 0.01 @@ -32,63 +36,73 @@ class CheckBox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, M // MARK: - Lifecycle //-------------------------------------------------- - private var drawPercentage: Float = 0.0 - private var animationTimer: Timer? - private var checkLayer: CAShapeLayer? - private var selected = false + override init(frame: CGRect) { + super.init(frame: frame) - func setupView() { - super.setupView() - backgroundColor = UIColor.clear - drawPercentage = 1.0 - lineColor = UIColor.black - lineWidth = 1.0 - } - - func update(_ size: CGFloat) { - super.update(size) - } + backgroundColor = .clear + drawPercentage = 1.0 + lineColor = .black + lineWidth = 1.0 + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + fatalError("Xib File is not implemented for CheckBox.") + } var lineWidth: CGFloat { get { - return super.lineWidth + return _lineWidth } set(lineWidth) { self.lineWidth = lineWidth - if checkLayer { - checkLayer.removeFromSuperlayer() - checkLayer = nil - updateCheckSelected(selected, animated: false) - } + guard let checkLayer = checkLayer else { return } + checkLayer.removeFromSuperlayer() + checkLayer = nil + updateCheckSelected(isSelected, animated: false) } } + var lineColor: UIColor { + get { + return _lineColor + } + set(lineColor) { + _lineColor = lineColor + + if let checkLayer = checkLayer { + checkLayer.strokeColor = lineColor.cgColor + updateCheckSelected(isSelected, animated: false) + } + } + } //-------------------------------------------------- // MARK: - Draw //-------------------------------------------------- func drawCheck() { - if !checkLayer { - layoutIfNeeded() - let path = UIBezierPath() - path.move(to: CGPoint(x: lineWidth / 2, y: bounds.size.height * 0.55)) - path.addLine(to: CGPoint(x: bounds.size.width * 0.45, y: bounds.size.height * 0.85)) - path.addLine(to: CGPoint(x: bounds.size.width - lineWidth / 2, y: lineWidth / 2)) - - checkLayer = CAShapeLayer() - checkLayer.frame = bounds - layer.addSublayer(checkLayer) - checkLayer.strokeColor = lineColor.cgColor ?? UIColor.black.cgColor - checkLayer.fillColor = UIColor.clear.cgColor - checkLayer.path = path.cgPath - checkLayer.lineWidth = lineWidth - - CATransaction.begin() - CATransaction.setDisableActions(true) - checkLayer.strokeEnd = 0.0 - CATransaction.commit() - } + + guard let checkLayer = checkLayer else { return } + + layoutIfNeeded() + let path = UIBezierPath() + path.move(to: CGPoint(x: lineWidth / 2, y: bounds.size.height * 0.55)) + path.addLine(to: CGPoint(x: bounds.size.width * 0.45, y: bounds.size.height * 0.85)) + path.addLine(to: CGPoint(x: bounds.size.width - lineWidth / 2, y: lineWidth / 2)) + + checkLayer = CAShapeLayer() + checkLayer.frame = bounds + layer.addSublayer(checkLayer) + checkLayer.strokeColor = lineColor.cgColor + checkLayer.fillColor = UIColor.clear.cgColor + checkLayer.path = path.cgPath + checkLayer.lineWidth = lineWidth + + CATransaction.begin() + CATransaction.setDisableActions(true) + checkLayer.strokeEnd = 0.0 + CATransaction.commit() } //-------------------------------------------------- @@ -96,15 +110,17 @@ class CheckBox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, M //-------------------------------------------------- func updateCheckSelected(_ selected: Bool, animated: Bool) { - MVMCoreDispatchUtility.performBlock(onMainThread: { - self.selected = selected + + DispatchQueue.main.async { + + self.isSelected = selected // animate this bar self.drawCheck() var layer: CAShapeLayer? - if self.checkLayer.presentation() != nil && animated { - layer = self.checkLayer.presentation() + if self.checkLayer?.presentation() != nil && animated { + layer = self.checkLayer!.presentation() } else { layer = self.checkLayer } @@ -116,11 +132,8 @@ class CheckBox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, M animateStrokeEnd.duration = 0.3 animateStrokeEnd.fromValue = NSNumber(value: Float(layer?.strokeEnd ?? 0.0)) - if selected { - animateStrokeEnd.toValue = NSNumber(value: 1) - } else { - animateStrokeEnd.toValue = NSNumber(value: 0) - } + + animateStrokeEnd.toValue = NSNumber(value: selected ? 1 : 0) animateStrokeEnd.timingFunction = CAMediaTimingFunction(name: .linear) layer?.add(animateStrokeEnd, forKey: "strokeEndAnimation") @@ -128,38 +141,38 @@ class CheckBox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, M layer?.removeAllAnimations() CATransaction.begin() CATransaction.setDisableActions(true) - if selected { - layer?.strokeEnd = 1.0 - } else { - layer?.strokeEnd = 0.0 - } + layer?.strokeEnd = selected ? 1.0 : 0.0 + CATransaction.commit() } - }) - } - - - func setLineColor(_ lineColor: UIColor?) { - self.lineColor = lineColor - if checkLayer { - checkLayer.strokeColor = lineColor?.cgColor - updateCheckSelected(selected, animated: false) } } - func layoutSubviews() { + override func layoutSubviews() { drawCheck() } + private func defaultState() { + + } + //-------------------------------------------------- // MARK: - Molecular //-------------------------------------------------- + open func reset() { + + } + + open func setAsMolecule() { + + } + func updateView(_ size: CGFloat) { - <#code#> + } func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - <#code#> + } } diff --git a/MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift b/MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift index 5e7c7739..972100d4 100644 --- a/MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift +++ b/MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift @@ -32,6 +32,237 @@ class CheckBoxWithLabel: ViewConstrainingView { // TODO: MVMCoreUICheckBox.m + func needsToBeConstrained() -> Bool { + return true + } + + func alignment() -> UIStackView.Alignment { + return .leading + } + + func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + + FormValidator.setupValidation(withMolecule: self, delegate: delegateObject?.formValidationProtocol) + delegate = delegateObject + fieldKey = json?.string(for: KeyFieldKey) + isRequired = json?.bool(forKey: KeyRequired) + + let checkedColorHex = json?.string("checkedColor") + let unCheckedColorHex = json?.string("unCheckedColor") + + let checkedColor = checkedColorHex != nil ? UIColor.mfGet(forHex: checkedColorHex) : UIColor.clear + let unCheckedColor = unCheckedColorHex != nil ? UIColor.mfGet(forHex: unCheckedColorHex) : UIColor.clear + + setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, label: json?.dict(KeyLabel), delegateObject: delegateObject, additionalData: additionalData) + } + + class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return CGFloat(CheckBoxHeightWidth) + } + + // MARK: - convenient class methods + class func mf() -> Self { + let checkBox = self.init(frame: CGRect.zero) + checkBox.translatesAutoresizingMaskIntoConstraints = false + return checkBox + } + + class func mfCheckBoxWithRoundedRect() -> Self? { + let checkBox = self.init(roundRect: true) + checkBox.translatesAutoresizingMaskIntoConstraints = false + return checkBox + } + + class func mfCheckBox(withCheckedColor checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, text: String?) -> Self { + let checkBox = self.init(checkedColor: checkedColor, unCheck: unCheckedColor, text: text) + checkBox?.translatesAutoresizingMaskIntoConstraints = false + return checkBox + } + + class func mfCheckBox(withCheckedColor checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, atributedText attributedText: NSAttributedString?) -> Self { + let checkBox = self.init(checkedColor: checkedColor, unCheck: unCheckedColor, attributedText: attributedText) + checkBox?.translatesAutoresizingMaskIntoConstraints = false + return checkBox + } + + // MARK: - FormValidationProtocol + func isValidField() -> Bool { + if isRequired { + return isSelected() + } + return true + } + + func formFieldName() -> String? { + return fieldKey + } + + func formFieldValue() -> Any? { + return NSNumber(value: isSelected()) + } + + // MARK: - inits + init() { + super.init() + setupView() + } + + init(checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, text: String?) { + super.init() + setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: text) + addAccessibleProperties() + } + + init(checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, attributedText: NSAttributedString?) { + super.init() + setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: nil) + descriptionAttributedText = attributedText + addAccessibleProperties() + } + + init?(checkMarkView: MVMCoreUICheckMarkView?, checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, text: String?) { + super.init() + checkMark = checkMarkView + setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: text) + addAccessibleProperties() + } + + init?(checkMarkView: MVMCoreUICheckMarkView?, checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, attributedText: NSAttributedString?) { + super.init() + checkMark = checkMarkView + setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: nil) + descriptionAttributedText = attributedText + addAccessibleProperties() + } + + init(roundRect isRoundRect: Bool) { + super.init() + isRoundRectCheckMark = isRoundRect + setup(withCheckedColor: UIColor.white, unCheck: UIColor.white, text: nil) + addAccessibleProperties() + setCheckMarkLayer() + } + + //default inits + required init?(coder: NSCoder) { + super.init(coder: coder) + setupView() + setup(withCheckedColor: UIColor.white, unCheck: UIColor.white, text: nil) + addAccessibleProperties() + } + + init(frame: CGRect) { + super.init(frame: frame) + setupView() + setup(withCheckedColor: UIColor.white, unCheck: UIColor.white, text: nil) + addAccessibleProperties() + } + + func awakeFromNib() { + super.awakeFromNib() + setup(withCheckedColor: UIColor.white, unCheck: UIColor.white, text: nil) + } + + func setupView() { + + let containterView = MVMCoreUICommonViewsUtility.commonView() + containterView?.isUserInteractionEnabled = false + if !sizeObject { + sizeObject = MFSizeObject(standardSize: CheckBoxHeightWidth, standardiPadPortraitSize: Int(CheckBoxHeightWidth) + 6) + } + + //checked circle + if !self.checkedSquare { + let checkedSquare = MVMCoreUICommonViewsUtility.commonView() + checkedSquare?.backgroundColor = UIColor.white + if let checkedSquare = checkedSquare { + containterView?.addSubview(checkedSquare) + } + let size = sizeObject.getValueBasedOnApplicationWidth() + let constraints = NSLayoutConstraint.constraintPinView(checkedSquare, heightConstraint: true, heightConstant: size, widthConstraint: true, widthConstant: size) + checkboxWidth = constraints[ConstraintWidth] + checkboxHeight = constraints[ConstraintHeight] + NSLayoutConstraint.constraintPinSubview(checkedSquare, pinTop: true, pinBottom: true, pinLeft: true, pinRight: false) + + checkboxRightPinConstraint = checkedSquare?.trailingAnchor.constraintEqual(to: containterView?.trailingAnchor) + + NSLayoutConstraint.constraintPinSubview(checkedSquare, pinCenterX: false, pinCenterY: true) + self.checkedSquare = checkedSquare + self.checkBoxBorder = UIColor.black + } + + // TODO: OBJC CODE + + //check mark + if (!self.checkMark) { + MVMCoreUICheckMarkView *checkMark = [[MVMCoreUICheckMarkView alloc] initWithFrame:self.frame]; + checkMark.lineWidth = 2.0; + self.checkMark = checkMark; + self.checkMark.translatesAutoresizingMaskIntoConstraints = NO; + [self.checkedSquare addSubview:self.checkMark]; + [self.checkMark.widthAnchor constraintEqualToAnchor:self.checkedSquare.widthAnchor multiplier:.4].active = YES; + [self.checkMark.heightAnchor constraintEqualToAnchor:self.checkedSquare.heightAnchor multiplier:.4].active = YES; + [self.checkMark.centerXAnchor constraintEqualToAnchor:self.checkedSquare.centerXAnchor].active = YES; + [self.checkMark.centerYAnchor constraintEqualToAnchor:self.checkedSquare.centerYAnchor].active = YES; + } + + //label + if (!self.descriptionLabel) { + Label *descriptionLabel = [Label commonLabelB2:YES]; + [containterView addSubview:descriptionLabel]; + [NSLayoutConstraint constraintPinSubview:descriptionLabel pinCenterX:NO pinCenterY:YES]; + [NSLayoutConstraint constraintPinSubview:descriptionLabel pinTop:NO pinBottom:NO pinLeft:NO pinRight:YES]; + + self.descriptionLabelLeadingConstraint = [NSLayoutConstraint constraintWithItem:descriptionLabel attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.checkedSquare attribute:NSLayoutAttributeTrailing multiplier:1 constant:11]; + self.descriptionLabelLeadingConstraint.active = YES; + + self.descriptionLabelLeadingConstraint.active = YES; + self.descriptionLabel = descriptionLabel; + [self setSelected:NO]; + } + + if (!self.containerView) { + [self addSubview:containterView]; + self.containerView = containterView; + [NSLayoutConstraint constraintPinSubviewToSuperview:containterView]; + } + } + + func setup(withCheckedColor checkedColor: UIColor?, unCheck unCheckedColor: UIColor?) { + if checkedColor != nil { + self.checkedColor = checkedColor + } + if unCheckedColor != nil { + self.unCheckedColor = unCheckedColor + } + } + + func setup(withCheckedColor checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, text: String?) { + setup(withCheckedColor: checkedColor, unCheck: unCheckedColor) + descriptionText = text ?? "" + } + + func setup(withCheckedColor checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, label labelJson: [AnyHashable : Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) { + setup(withCheckedColor: checkedColor, unCheck: unCheckedColor) + descriptionLabel.setWithJSON(labelJson, delegateObject: delegateObject, additionalData: additionalData) + } + + @objc func updateView(_ size: CGFloat) { + MVMCoreDispatchUtility.performBlock(onMainThread: { + self.descriptionLabel.updateView(size) + if self.checkMark.responds(to: #selector(updateView(_:))) { + let width = self.sizeObject.getValueBased(onSize: size) + self.checkboxWidth.constant = width + self.checkboxHeight.constant = width + self.checkMark.updateView(size) + } + }) + } + + func setCheckMarkLayer() { + checkedSquare.layer.cornerRadius = isRoundRectCheckMark ? 5.0 : 0 + } + //-------------------------------------------------- // MARK: - Molecular //-------------------------------------------------- diff --git a/MVMCoreUI/Atoms/Views/MVMCoreUICheckBox.m b/MVMCoreUI/Atoms/Views/MVMCoreUICheckBox.m index 2cde1bc3..d219f2f3 100644 --- a/MVMCoreUI/Atoms/Views/MVMCoreUICheckBox.m +++ b/MVMCoreUI/Atoms/Views/MVMCoreUICheckBox.m @@ -306,6 +306,8 @@ static const CGFloat CheckBoxHeightWidth = 18.0; self.checkedSquare.layer.cornerRadius = self.isRoundRectCheckMark ? 5.0f : 0; } +// TODO:..................................... + #pragma mark - XIB Helpers - (instancetype)awakeAfterUsingCoder:(NSCoder *)aDecoder { From 6f4db10d33b371906dd31d3360baf2d4721fbf27 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 16 Sep 2019 10:24:18 -0400 Subject: [PATCH 03/48] beginning work on hero. --- MVMCoreUI/Atoms/Views/Label.swift | 41 +++++++++++++++++++ .../Molecules/ActionDetailWithImage.swift | 5 +++ 2 files changed, 46 insertions(+) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index ed99fcac..99576509 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -502,6 +502,47 @@ public typealias ActionBlock = () -> () let accessibleAction = customAccessibilityAction(range: range) clauses.append(ActionableClause(range: range, actionBlock: actionBlock, accessibilityID: accessibleAction?.hash ?? -1)) } + +// func rectOfCharacter() { +// +//// label.intrinsicContentSize.width +// if let range = mylabel.text?.range(of: String(describing: mylabel.text?.characters.last!)) { +// let prefix = mylabel.text?.substring(to: range.lowerBound) +// let size: CGSize = prefix!.size(attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 35.0)]) +// let position = CGPoint(x:size.width,y: 0) +// myScrollView.setContentOffset(position, animated: true) +// } +// } + + static func boundingRect(forCharacterRange range: NSRange, in label: Label) -> CGRect { + + guard let attributedText = label.attributedText else { return CGRect() } + + let paragraph = NSMutableParagraphStyle() + paragraph.alignment = label.textAlignment + + let stagedAttributedString = NSMutableAttributedString(attributedString: attributedText) + stagedAttributedString.addAttributes([NSAttributedString.Key.paragraphStyle: paragraph], range: NSRange(location: 0, length: attributedText.string.count)) + + let textStorage = NSTextStorage(attributedString: stagedAttributedString) + let layoutManager = NSLayoutManager() + let textContainer = NSTextContainer(size: .zero) + + layoutManager.addTextContainer(textContainer) + textStorage.addLayoutManager(layoutManager) + + textContainer.lineFragmentPadding = 0 + textContainer.lineBreakMode = label.lineBreakMode + textContainer.maximumNumberOfLines = label.numberOfLines + textContainer.size = label.bounds.size + + var glyphRange = NSRange() + + // Convert the range for glyphs. + layoutManager.characterRange(forGlyphRange: range, actualGlyphRange: &glyphRange) + + return layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer) + } } // MARK: - Atomization diff --git a/MVMCoreUI/Molecules/ActionDetailWithImage.swift b/MVMCoreUI/Molecules/ActionDetailWithImage.swift index ec91c479..8cdddb5f 100644 --- a/MVMCoreUI/Molecules/ActionDetailWithImage.swift +++ b/MVMCoreUI/Molecules/ActionDetailWithImage.swift @@ -166,5 +166,10 @@ import UIKit } else { button.isHidden = true } + + if let text = header.messageLabel.text, text.contains("frog") { + let rect = Label.boundingRect(forCharacterRange: NSRange(location: 65, length: 4), in: header.messageLabel) + print(rect) + } } } From b9e80398c16c150d68cfbdb17e16a7b151823f51 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 17 Sep 2019 09:41:14 -0400 Subject: [PATCH 04/48] Decent palce. --- MVMCoreUI/Atoms/Views/Label.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 99576509..862fd829 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -514,7 +514,7 @@ public typealias ActionBlock = () -> () // } // } - static func boundingRect(forCharacterRange range: NSRange, in label: Label) -> CGRect { + public static func boundingRect(forCharacterRange range: NSRange, in label: Label) -> CGRect { guard let attributedText = label.attributedText else { return CGRect() } @@ -531,7 +531,7 @@ public typealias ActionBlock = () -> () layoutManager.addTextContainer(textContainer) textStorage.addLayoutManager(layoutManager) - textContainer.lineFragmentPadding = 0 + textContainer.lineFragmentPadding = 0.0 textContainer.lineBreakMode = label.lineBreakMode textContainer.maximumNumberOfLines = label.numberOfLines textContainer.size = label.bounds.size From fc4fcc25f6b1ebcbb578d8d3c16fa39ed5e1a157 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 17 Sep 2019 16:37:27 -0400 Subject: [PATCH 05/48] Current take on hero. Needs to be refactored and placed into a protocol. --- MVMCoreUI/Atoms/Views/Label.swift | 12 +++++ .../Templates/MoleculeListTemplate.swift | 45 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 862fd829..81159965 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -25,6 +25,7 @@ public typealias ActionBlock = () -> () /// Set this to use a custom sizing object during updateView instead of the standard. public var sizeObject: MFSizeObject? public var scaleSize: NSNumber? + public var hero: Int? // Used for scaling the font in updateView. private var originalAttributedString: NSAttributedString? @@ -562,6 +563,17 @@ extension Label { clauses = [] Label.setUILabel(self, withJSON: json, delegate: delegateObject, additionalData: additionalData) originalAttributedString = attributedText + + hero = json?["hero"] as? Int + } + + func noticeBounds(_ rect: CGRect, color: UIColor) -> UIView { + + let view = UIView(frame: rect) + view.layer.borderColor = color.cgColor + view.layer.borderWidth = 1.0 + + return view } public func setAsMolecule() { diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index 0270cb63..0db27a35 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -88,6 +88,38 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { return cell } + open override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + + cell.layoutIfNeeded() + let heroLabel = findHeroLabel(views: cell.contentView.subviews) + let rect = Label.boundingRect(forCharacterRange: NSRange(location: heroLabel!.hero!, length: 1), in: heroLabel!) + let rectView = heroLabel?.noticeBounds(rect, color: .clear) + heroLabel?.addSubview(rectView!) + let convert = cell.contentView.convert(rectView!.center, from: heroLabel) + + cell.accessoryView?.center.y = convert.y + rectView?.removeFromSuperview() + } + + // TODO: Write recursively. + func findHeroLabel(views: [UIView]) -> Label? { + + var queue: [UIView] = views + + repeat { + for view in queue { + if let label = view as? Label, label.hero != nil { + return label + } else if !view.subviews.isEmpty { + queue.append(contentsOf: view.subviews) + } + queue.removeFirst() + } + } while (!queue.isEmpty) + + return nil + } + open override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if let cell = tableView.cellForRow(at: indexPath) as? MoleculeListCellProtocol { cell.didSelectCell?(atIndex: indexPath, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, additionalData: nil) @@ -111,11 +143,24 @@ 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.indexPathsForVisibleRows?.contains(indexPath) ?? false { + //------------- tableView.beginUpdates() +// let cell = tableView.cellForRow(at: indexPath) +// cell.layoutIfNeeded() +// let heroLabel = findHeroLabel(views: cell.contentView.subviews) +// let rect = Label.boundingRect(forCharacterRange: NSRange(location: heroLabel!.hero!, length: 1), in: heroLabel!) +// let rectView = heroLabel?.noticeBounds(rect, color: .blue) +// heroLabel?.addSubview(rectView!) +// // let rect = Label.boundingRect(forCharacterRange: NSRange(location: 46, length: 6), in: self) +// let convert = cell.contentView.convert(rectView!.center, from: heroLabel) +// +// cell.accessoryView?.center.y = convert.y + /// ------------ tableView.endUpdates() } } } + open override func addMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { // This dispatch is needed to fix a race condition that can occur if this function is called during the table setup. From 5bc420ac05399ebf31d2310cfe932472b5b77f94 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 18 Sep 2019 14:13:33 -0400 Subject: [PATCH 06/48] accessoryVIew can now center itself in relation to the hero character. --- MVMCoreUI/Atoms/Views/Label.swift | 24 +------- .../Molecules/ActionDetailWithImage.swift | 5 -- .../Items/MoleculeTableViewCell.swift | 57 ++++++++++++++++--- .../Molecules/MVMCoreUIMoleculeViewProtocol.h | 2 + .../Templates/MoleculeListTemplate.swift | 53 ++--------------- 5 files changed, 61 insertions(+), 80 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 81159965..cab341b1 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -25,6 +25,8 @@ public typealias ActionBlock = () -> () /// Set this to use a custom sizing object during updateView instead of the standard. public var sizeObject: MFSizeObject? public var scaleSize: NSNumber? + + /// A specific text index to use as a unique marker. public var hero: Int? // Used for scaling the font in updateView. @@ -503,18 +505,7 @@ public typealias ActionBlock = () -> () let accessibleAction = customAccessibilityAction(range: range) clauses.append(ActionableClause(range: range, actionBlock: actionBlock, accessibilityID: accessibleAction?.hash ?? -1)) } - -// func rectOfCharacter() { -// -//// label.intrinsicContentSize.width -// if let range = mylabel.text?.range(of: String(describing: mylabel.text?.characters.last!)) { -// let prefix = mylabel.text?.substring(to: range.lowerBound) -// let size: CGSize = prefix!.size(attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 35.0)]) -// let position = CGPoint(x:size.width,y: 0) -// myScrollView.setContentOffset(position, animated: true) -// } -// } - + public static func boundingRect(forCharacterRange range: NSRange, in label: Label) -> CGRect { guard let attributedText = label.attributedText else { return CGRect() } @@ -567,15 +558,6 @@ extension Label { hero = json?["hero"] as? Int } - func noticeBounds(_ rect: CGRect, color: UIColor) -> UIView { - - let view = UIView(frame: rect) - view.layer.borderColor = color.cgColor - view.layer.borderWidth = 1.0 - - return view - } - public func setAsMolecule() { styleB2(true) } diff --git a/MVMCoreUI/Molecules/ActionDetailWithImage.swift b/MVMCoreUI/Molecules/ActionDetailWithImage.swift index 8cdddb5f..ec91c479 100644 --- a/MVMCoreUI/Molecules/ActionDetailWithImage.swift +++ b/MVMCoreUI/Molecules/ActionDetailWithImage.swift @@ -166,10 +166,5 @@ import UIKit } else { button.isHidden = true } - - if let text = header.messageLabel.text, text.contains("frog") { - let rect = Label.boundingRect(forCharacterRange: NSRange(location: 65, length: 4), in: header.messageLabel) - print(rect) - } } } diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index 641b3721..ce9fe93c 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -53,6 +53,16 @@ import UIKit } } + open override func layoutSubviews() { + super.layoutSubviews() + + if let center = heroAccessoryCenter { + accessoryView?.center.y = center.y + } + } + + var heroAccessoryCenter: CGPoint? + func styleStandard() { topMarginPadding = 24 bottomMarginPadding = 24 @@ -128,15 +138,51 @@ import UIKit } } + /// NOTE: Should only be called when displayed or about to be displayed. + public func alignAccessoryToHero() { + + layoutIfNeeded() + guard let heroLabel = findHeroLabel(views: contentView.subviews), let hero = heroLabel.hero else { return } + let rect = Label.boundingRect(forCharacterRange: NSRange(location: hero, length: 1), in: heroLabel) + let rectView = UIView(frame: rect) + heroLabel.addSubview(rectView) + accessoryView?.center.y = contentView.convert(rectView.center, from: heroLabel).y + heroAccessoryCenter = accessoryView?.center + rectView.removeFromSuperview() + } + + /** + Used to traverse the view hierarchy for a 🦸‍♂️heroic Label. + */ + private func findHeroLabel(views: [UIView]) -> Label? { + + if views.isEmpty { + return nil + } + + var queue = [UIView]() + + for view in views { + // Only one Label will have a hero in a table cell. + if let label = view as? Label, label.hero != nil { + return label + } + queue.append(contentsOf: view.subviews) + } + + return findHeroLabel(views: queue) + } + // MARK: - MVMCoreUIMoleculeViewProtocol public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - self.json = json; + self.json = json style(with: json?.optionalStringForKey("style")) if let useHorizontalMargins = json?.optionalBoolForKey("useHorizontalMargins") { updateViewHorizontalDefaults = useHorizontalMargins } + if (json?.optionalBoolForKey("useVerticalMargins") ?? true) == false { topMarginPadding = 0 bottomMarginPadding = 0 @@ -161,9 +207,8 @@ import UIKit bottomSeparatorView?.setWithJSON(separator, delegateObject: delegateObject, additionalData: additionalData) } - guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { - return - } + 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) @@ -215,9 +260,7 @@ import UIKit // MARK: - Arrow /// Adds the standard mvm style caret to the accessory view public func addCaretViewAccessory() { - guard accessoryView == nil else { - return - } + guard accessoryView == nil else { return } let width: CGFloat = 6 let height: CGFloat = 10 caretView = CaretView(lineThickness: CaretView.thin) diff --git a/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h b/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h index 4c69b1f7..273329aa 100644 --- a/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h +++ b/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h @@ -24,6 +24,8 @@ /// Resets to default state before set with json is called again. - (void)reset; +/// Currently designed for UITableViewCell. Aligns the accessory view with the center of a character in a line of text. +- (void)alignAccessoryToHero; /// For the molecule list to load more efficiently. + (CGFloat)estimatedHeightForRow:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject; diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index 0db27a35..84a7e64b 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -51,9 +51,8 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { // MARK: - table open override func registerWithTable() { super.registerWithTable() - guard let moleculesInfo = moleculesInfo else { - return - } + guard let moleculesInfo = moleculesInfo else { return } + for moleculeInfo in moleculesInfo { tableView?.register(moleculeInfo.class, forCellReuseIdentifier: moleculeInfo.identifier) } @@ -90,34 +89,9 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { open override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { - cell.layoutIfNeeded() - let heroLabel = findHeroLabel(views: cell.contentView.subviews) - let rect = Label.boundingRect(forCharacterRange: NSRange(location: heroLabel!.hero!, length: 1), in: heroLabel!) - let rectView = heroLabel?.noticeBounds(rect, color: .clear) - heroLabel?.addSubview(rectView!) - let convert = cell.contentView.convert(rectView!.center, from: heroLabel) - - cell.accessoryView?.center.y = convert.y - rectView?.removeFromSuperview() - } - - // TODO: Write recursively. - func findHeroLabel(views: [UIView]) -> Label? { - - var queue: [UIView] = views - - repeat { - for view in queue { - if let label = view as? Label, label.hero != nil { - return label - } else if !view.subviews.isEmpty { - queue.append(contentsOf: view.subviews) - } - queue.removeFirst() - } - } while (!queue.isEmpty) - - return nil + if cell.accessoryView != nil, let protocolCell = cell as? (MoleculeTableViewCell & MVMCoreUIMoleculeViewProtocol) { + protocolCell.alignAccessoryToHero() + } } open override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { @@ -143,31 +117,16 @@ 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.indexPathsForVisibleRows?.contains(indexPath) ?? false { - //------------- tableView.beginUpdates() -// let cell = tableView.cellForRow(at: indexPath) -// cell.layoutIfNeeded() -// let heroLabel = findHeroLabel(views: cell.contentView.subviews) -// let rect = Label.boundingRect(forCharacterRange: NSRange(location: heroLabel!.hero!, length: 1), in: heroLabel!) -// let rectView = heroLabel?.noticeBounds(rect, color: .blue) -// heroLabel?.addSubview(rectView!) -// // let rect = Label.boundingRect(forCharacterRange: NSRange(location: 46, length: 6), in: self) -// let convert = cell.contentView.convert(rectView!.center, from: heroLabel) -// -// cell.accessoryView?.center.y = convert.y - /// ------------ tableView.endUpdates() } } } - open override func addMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { // This dispatch is needed to fix a race condition that can occur if this function is called during the table setup. DispatchQueue.main.async { - guard let cell = sender as? MoleculeTableViewCell, let indexPath = self.tableView?.indexPath(for: cell) else { - return - } + guard let cell = sender as? MoleculeTableViewCell, let indexPath = self.tableView?.indexPath(for: cell) else { return } var indexPaths: [IndexPath] = [] for molecule in molecules { if let info = self.getMoleculeInfo(with: molecule) { From 4ea916bbcd47f01ba6892648bc5f048caf51517c Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 18 Sep 2019 14:14:37 -0400 Subject: [PATCH 07/48] commenting. --- MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index ce9fe93c..1f348bb5 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -151,11 +151,9 @@ import UIKit rectView.removeFromSuperview() } - /** - Used to traverse the view hierarchy for a 🦸‍♂️heroic Label. - */ + /// Used to traverse the view hierarchy for a 🦸‍♂️heroic Label. private func findHeroLabel(views: [UIView]) -> Label? { - + if views.isEmpty { return nil } @@ -169,7 +167,7 @@ import UIKit } queue.append(contentsOf: view.subviews) } - + return findHeroLabel(views: queue) } From 1c416b5653b4feb0b308b04135aeb5c1c3cf8ce1 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 18 Sep 2019 14:15:56 -0400 Subject: [PATCH 08/48] revised. --- MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index 1f348bb5..840e681b 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -151,7 +151,7 @@ import UIKit rectView.removeFromSuperview() } - /// Used to traverse the view hierarchy for a 🦸‍♂️heroic Label. + /// Traverses the view hierarchy for a 🦸‍♂️heroic Label. private func findHeroLabel(views: [UIView]) -> Label? { if views.isEmpty { From 0f5a9be82ee19c3ce079ec2ce409acdd84e9a0a1 Mon Sep 17 00:00:00 2001 From: "Suresh, Kamlesh" Date: Wed, 25 Sep 2019 11:23:18 -0400 Subject: [PATCH 09/48] CXTDT-25210 --- MVMCoreUI/BaseControllers/MFViewController.m | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MVMCoreUI/BaseControllers/MFViewController.m b/MVMCoreUI/BaseControllers/MFViewController.m index 256bf050..edbabf80 100644 --- a/MVMCoreUI/BaseControllers/MFViewController.m +++ b/MVMCoreUI/BaseControllers/MFViewController.m @@ -527,6 +527,13 @@ } } +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + if (self.selectedField) { + [self.selectedField resignFirstResponder]; + } +} + - (void)dealloc { [self stopObservingForResponseJSONUpdates]; MVMCoreLog(@"%@ deallocated", [[self class] description]); From 35f7024f8d47504bae8ddd8b0b35304a66409eed Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 25 Sep 2019 14:19:49 -0400 Subject: [PATCH 10/48] Adding two new checkbox swift classes. --- MVMCoreUI.xcodeproj/project.pbxproj | 16 +- MVMCoreUI/Atoms/Views/CheckBox.swift | 178 ----------- MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift | 277 ----------------- MVMCoreUI/Atoms/Views/Checkbox.swift | 288 +++++++++++++++++ .../Atoms/Views/CheckboxWithLabelView.swift | 289 ++++++++++++++++++ .../MVMCoreUIMoleculeMappingObject.m | 4 +- 6 files changed, 587 insertions(+), 465 deletions(-) delete mode 100644 MVMCoreUI/Atoms/Views/CheckBox.swift delete mode 100644 MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift create mode 100644 MVMCoreUI/Atoms/Views/Checkbox.swift create mode 100644 MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index b2dd623a..9692652c 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -18,8 +18,8 @@ 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 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; }; - 0A7BAFA1232BE61800FB8E22 /* CheckBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* CheckBox.swift */; }; - 0A7BAFA3232BE63400FB8E22 /* CheckBoxWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckBoxWithLabel.swift */; }; + 0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */; }; + 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; }; 948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948DB67D2326DCD90011F916 /* MultiProgress.swift */; }; B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; }; B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* CornerLabels.swift */; }; @@ -205,8 +205,8 @@ 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 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = ""; }; - 0A7BAFA0232BE61800FB8E22 /* CheckBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckBox.swift; sourceTree = ""; }; - 0A7BAFA2232BE63400FB8E22 /* CheckBoxWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckBoxWithLabel.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 = ""; }; 948DB67D2326DCD90011F916 /* MultiProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiProgress.swift; sourceTree = ""; }; B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; B8200E182281DC1A007245F4 /* CornerLabels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerLabels.swift; sourceTree = ""; }; @@ -726,8 +726,8 @@ DB891E822253FA8500022516 /* Label.swift */, 0198F7A02256A80A0066C936 /* MFRadioButton.h */, 0198F7A22256A80A0066C936 /* MFRadioButton.m */, - 0A7BAFA0232BE61800FB8E22 /* CheckBox.swift */, - 0A7BAFA2232BE63400FB8E22 /* CheckBoxWithLabel.swift */, + 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */, + 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */, ); path = Views; sourceTree = ""; @@ -1042,6 +1042,7 @@ D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */, D29DF13021E6851E003B2FB9 /* MVMCoreUITopAlertShortView.m in Sources */, D28B4F8B21FF967C00712C7A /* MVMCoreUIObject.m in Sources */, + 0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */, D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */, D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */, D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */, @@ -1049,7 +1050,7 @@ D282AACB2243C61700C46919 /* ButtonView.swift in Sources */, D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */, 0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */, - 0A7BAFA1232BE61800FB8E22 /* CheckBox.swift in Sources */, + 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */, D22479962316AF6E003FCCF9 /* HeadlineBodyTextButton.swift in Sources */, D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */, D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */, @@ -1077,7 +1078,6 @@ D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */, D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */, D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */, - 0A7BAFA3232BE63400FB8E22 /* CheckBoxWithLabel.swift in Sources */, D27CD4102339057800C1DC07 /* EyebrowHeadlineBodyLink.swift in Sources */, D29DF11D21E684A9003B2FB9 /* MVMCoreUISplitViewController.m in Sources */, 0198F79F225679880066C936 /* FormValidationProtocol.swift in Sources */, diff --git a/MVMCoreUI/Atoms/Views/CheckBox.swift b/MVMCoreUI/Atoms/Views/CheckBox.swift deleted file mode 100644 index ac6adf1a..00000000 --- a/MVMCoreUI/Atoms/Views/CheckBox.swift +++ /dev/null @@ -1,178 +0,0 @@ -// -// CheckBox.swift -// MVMCoreUI -// -// Created by Kevin Christiano on 9/13/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import MVMCore - - -class CheckBox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol { - //-------------------------------------------------- - // MARK: - Properties - //-------------------------------------------------- - - private var _lineColor: UIColor = .black - private var _lineWidth: CGFloat = 1.0 - - private var drawPercentage: Float = 0.0 - private var animationTimer: Timer? - private var checkLayer: CAShapeLayer? - - let startXOffset: Float = 42.0 / 124.0 - let startYOffset: Float = 66.0 / 124.0 - let pivotXOffset: Float = 58.0 / 124.0 - let pivotYOffset: Float = 80.0 / 124.0 - let endXOffset: Float = 83.0 / 124.0 - let endYOffset: Float = 46.0 / 124.0 - let pivotPercentage: Float = 0.34 - let endPercentage = 0.66 - let animationInterval: Float = 0.01 - - - //-------------------------------------------------- - // MARK: - Lifecycle - //-------------------------------------------------- - - override init(frame: CGRect) { - super.init(frame: frame) - - backgroundColor = .clear - drawPercentage = 1.0 - lineColor = .black - lineWidth = 1.0 - } - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - fatalError("Xib File is not implemented for CheckBox.") - } - - var lineWidth: CGFloat { - get { - return _lineWidth - } - set(lineWidth) { - self.lineWidth = lineWidth - guard let checkLayer = checkLayer else { return } - checkLayer.removeFromSuperlayer() - checkLayer = nil - updateCheckSelected(isSelected, animated: false) - } - } - - var lineColor: UIColor { - get { - return _lineColor - } - set(lineColor) { - _lineColor = lineColor - - if let checkLayer = checkLayer { - checkLayer.strokeColor = lineColor.cgColor - updateCheckSelected(isSelected, animated: false) - } - } - } - - //-------------------------------------------------- - // MARK: - Draw - //-------------------------------------------------- - - func drawCheck() { - - guard let checkLayer = checkLayer else { return } - - layoutIfNeeded() - let path = UIBezierPath() - path.move(to: CGPoint(x: lineWidth / 2, y: bounds.size.height * 0.55)) - path.addLine(to: CGPoint(x: bounds.size.width * 0.45, y: bounds.size.height * 0.85)) - path.addLine(to: CGPoint(x: bounds.size.width - lineWidth / 2, y: lineWidth / 2)) - - checkLayer = CAShapeLayer() - checkLayer.frame = bounds - layer.addSublayer(checkLayer) - checkLayer.strokeColor = lineColor.cgColor - checkLayer.fillColor = UIColor.clear.cgColor - checkLayer.path = path.cgPath - checkLayer.lineWidth = lineWidth - - CATransaction.begin() - CATransaction.setDisableActions(true) - checkLayer.strokeEnd = 0.0 - CATransaction.commit() - } - - //-------------------------------------------------- - // MARK: - Methods - //-------------------------------------------------- - - func updateCheckSelected(_ selected: Bool, animated: Bool) { - - DispatchQueue.main.async { - - self.isSelected = selected - - // animate this bar - self.drawCheck() - - var layer: CAShapeLayer? - if self.checkLayer?.presentation() != nil && animated { - layer = self.checkLayer!.presentation() - } else { - layer = self.checkLayer - } - - if animated { - let animateStrokeEnd = CABasicAnimation(keyPath: "strokeEnd") - animateStrokeEnd.fillMode = .both - animateStrokeEnd.isRemovedOnCompletion = false - animateStrokeEnd.duration = 0.3 - - animateStrokeEnd.fromValue = NSNumber(value: Float(layer?.strokeEnd ?? 0.0)) - - animateStrokeEnd.toValue = NSNumber(value: selected ? 1 : 0) - - animateStrokeEnd.timingFunction = CAMediaTimingFunction(name: .linear) - layer?.add(animateStrokeEnd, forKey: "strokeEndAnimation") - } else { - layer?.removeAllAnimations() - CATransaction.begin() - CATransaction.setDisableActions(true) - layer?.strokeEnd = selected ? 1.0 : 0.0 - - CATransaction.commit() - } - } - } - - override func layoutSubviews() { - drawCheck() - } - - private func defaultState() { - - } - - //-------------------------------------------------- - // MARK: - Molecular - //-------------------------------------------------- - - open func reset() { - - } - - open func setAsMolecule() { - - } - - func updateView(_ size: CGFloat) { - - } - - func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - - } -} diff --git a/MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift b/MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift deleted file mode 100644 index 972100d4..00000000 --- a/MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift +++ /dev/null @@ -1,277 +0,0 @@ -// -// CheckBoxWithLabel.swift -// MVMCoreUI -// -// Created by Kevin Christiano on 9/13/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - - -class CheckBoxWithLabel: ViewConstrainingView { - //-------------------------------------------------- - // MARK: - Properties - //-------------------------------------------------- - - weak var checkMark: CheckBox? - private(set) var isSelected = false - var sizeObject: MFSizeObject? - //?????? - var checkedColor: UIColor? - var unCheckedColor: UIColor? - // Label to the right of the check box. - weak var descriptionLabel: Label? - // Setter for the descriptionLabel.text. Also sets the accessibility text. - var descriptionText: String? - var descriptionAttributedText: NSAttributedString? - // A block that is called when the switch is selected. - var switchSelected: ((_ selected: Bool) -> ())? - - //-------------------------------------------------- - // MARK: - Life Cycle - //-------------------------------------------------- - - // TODO: MVMCoreUICheckBox.m - - func needsToBeConstrained() -> Bool { - return true - } - - func alignment() -> UIStackView.Alignment { - return .leading - } - - func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - - FormValidator.setupValidation(withMolecule: self, delegate: delegateObject?.formValidationProtocol) - delegate = delegateObject - fieldKey = json?.string(for: KeyFieldKey) - isRequired = json?.bool(forKey: KeyRequired) - - let checkedColorHex = json?.string("checkedColor") - let unCheckedColorHex = json?.string("unCheckedColor") - - let checkedColor = checkedColorHex != nil ? UIColor.mfGet(forHex: checkedColorHex) : UIColor.clear - let unCheckedColor = unCheckedColorHex != nil ? UIColor.mfGet(forHex: unCheckedColorHex) : UIColor.clear - - setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, label: json?.dict(KeyLabel), delegateObject: delegateObject, additionalData: additionalData) - } - - class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - return CGFloat(CheckBoxHeightWidth) - } - - // MARK: - convenient class methods - class func mf() -> Self { - let checkBox = self.init(frame: CGRect.zero) - checkBox.translatesAutoresizingMaskIntoConstraints = false - return checkBox - } - - class func mfCheckBoxWithRoundedRect() -> Self? { - let checkBox = self.init(roundRect: true) - checkBox.translatesAutoresizingMaskIntoConstraints = false - return checkBox - } - - class func mfCheckBox(withCheckedColor checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, text: String?) -> Self { - let checkBox = self.init(checkedColor: checkedColor, unCheck: unCheckedColor, text: text) - checkBox?.translatesAutoresizingMaskIntoConstraints = false - return checkBox - } - - class func mfCheckBox(withCheckedColor checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, atributedText attributedText: NSAttributedString?) -> Self { - let checkBox = self.init(checkedColor: checkedColor, unCheck: unCheckedColor, attributedText: attributedText) - checkBox?.translatesAutoresizingMaskIntoConstraints = false - return checkBox - } - - // MARK: - FormValidationProtocol - func isValidField() -> Bool { - if isRequired { - return isSelected() - } - return true - } - - func formFieldName() -> String? { - return fieldKey - } - - func formFieldValue() -> Any? { - return NSNumber(value: isSelected()) - } - - // MARK: - inits - init() { - super.init() - setupView() - } - - init(checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, text: String?) { - super.init() - setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: text) - addAccessibleProperties() - } - - init(checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, attributedText: NSAttributedString?) { - super.init() - setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: nil) - descriptionAttributedText = attributedText - addAccessibleProperties() - } - - init?(checkMarkView: MVMCoreUICheckMarkView?, checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, text: String?) { - super.init() - checkMark = checkMarkView - setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: text) - addAccessibleProperties() - } - - init?(checkMarkView: MVMCoreUICheckMarkView?, checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, attributedText: NSAttributedString?) { - super.init() - checkMark = checkMarkView - setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: nil) - descriptionAttributedText = attributedText - addAccessibleProperties() - } - - init(roundRect isRoundRect: Bool) { - super.init() - isRoundRectCheckMark = isRoundRect - setup(withCheckedColor: UIColor.white, unCheck: UIColor.white, text: nil) - addAccessibleProperties() - setCheckMarkLayer() - } - - //default inits - required init?(coder: NSCoder) { - super.init(coder: coder) - setupView() - setup(withCheckedColor: UIColor.white, unCheck: UIColor.white, text: nil) - addAccessibleProperties() - } - - init(frame: CGRect) { - super.init(frame: frame) - setupView() - setup(withCheckedColor: UIColor.white, unCheck: UIColor.white, text: nil) - addAccessibleProperties() - } - - func awakeFromNib() { - super.awakeFromNib() - setup(withCheckedColor: UIColor.white, unCheck: UIColor.white, text: nil) - } - - func setupView() { - - let containterView = MVMCoreUICommonViewsUtility.commonView() - containterView?.isUserInteractionEnabled = false - if !sizeObject { - sizeObject = MFSizeObject(standardSize: CheckBoxHeightWidth, standardiPadPortraitSize: Int(CheckBoxHeightWidth) + 6) - } - - //checked circle - if !self.checkedSquare { - let checkedSquare = MVMCoreUICommonViewsUtility.commonView() - checkedSquare?.backgroundColor = UIColor.white - if let checkedSquare = checkedSquare { - containterView?.addSubview(checkedSquare) - } - let size = sizeObject.getValueBasedOnApplicationWidth() - let constraints = NSLayoutConstraint.constraintPinView(checkedSquare, heightConstraint: true, heightConstant: size, widthConstraint: true, widthConstant: size) - checkboxWidth = constraints[ConstraintWidth] - checkboxHeight = constraints[ConstraintHeight] - NSLayoutConstraint.constraintPinSubview(checkedSquare, pinTop: true, pinBottom: true, pinLeft: true, pinRight: false) - - checkboxRightPinConstraint = checkedSquare?.trailingAnchor.constraintEqual(to: containterView?.trailingAnchor) - - NSLayoutConstraint.constraintPinSubview(checkedSquare, pinCenterX: false, pinCenterY: true) - self.checkedSquare = checkedSquare - self.checkBoxBorder = UIColor.black - } - - // TODO: OBJC CODE - - //check mark - if (!self.checkMark) { - MVMCoreUICheckMarkView *checkMark = [[MVMCoreUICheckMarkView alloc] initWithFrame:self.frame]; - checkMark.lineWidth = 2.0; - self.checkMark = checkMark; - self.checkMark.translatesAutoresizingMaskIntoConstraints = NO; - [self.checkedSquare addSubview:self.checkMark]; - [self.checkMark.widthAnchor constraintEqualToAnchor:self.checkedSquare.widthAnchor multiplier:.4].active = YES; - [self.checkMark.heightAnchor constraintEqualToAnchor:self.checkedSquare.heightAnchor multiplier:.4].active = YES; - [self.checkMark.centerXAnchor constraintEqualToAnchor:self.checkedSquare.centerXAnchor].active = YES; - [self.checkMark.centerYAnchor constraintEqualToAnchor:self.checkedSquare.centerYAnchor].active = YES; - } - - //label - if (!self.descriptionLabel) { - Label *descriptionLabel = [Label commonLabelB2:YES]; - [containterView addSubview:descriptionLabel]; - [NSLayoutConstraint constraintPinSubview:descriptionLabel pinCenterX:NO pinCenterY:YES]; - [NSLayoutConstraint constraintPinSubview:descriptionLabel pinTop:NO pinBottom:NO pinLeft:NO pinRight:YES]; - - self.descriptionLabelLeadingConstraint = [NSLayoutConstraint constraintWithItem:descriptionLabel attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.checkedSquare attribute:NSLayoutAttributeTrailing multiplier:1 constant:11]; - self.descriptionLabelLeadingConstraint.active = YES; - - self.descriptionLabelLeadingConstraint.active = YES; - self.descriptionLabel = descriptionLabel; - [self setSelected:NO]; - } - - if (!self.containerView) { - [self addSubview:containterView]; - self.containerView = containterView; - [NSLayoutConstraint constraintPinSubviewToSuperview:containterView]; - } - } - - func setup(withCheckedColor checkedColor: UIColor?, unCheck unCheckedColor: UIColor?) { - if checkedColor != nil { - self.checkedColor = checkedColor - } - if unCheckedColor != nil { - self.unCheckedColor = unCheckedColor - } - } - - func setup(withCheckedColor checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, text: String?) { - setup(withCheckedColor: checkedColor, unCheck: unCheckedColor) - descriptionText = text ?? "" - } - - func setup(withCheckedColor checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, label labelJson: [AnyHashable : Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) { - setup(withCheckedColor: checkedColor, unCheck: unCheckedColor) - descriptionLabel.setWithJSON(labelJson, delegateObject: delegateObject, additionalData: additionalData) - } - - @objc func updateView(_ size: CGFloat) { - MVMCoreDispatchUtility.performBlock(onMainThread: { - self.descriptionLabel.updateView(size) - if self.checkMark.responds(to: #selector(updateView(_:))) { - let width = self.sizeObject.getValueBased(onSize: size) - self.checkboxWidth.constant = width - self.checkboxHeight.constant = width - self.checkMark.updateView(size) - } - }) - } - - func setCheckMarkLayer() { - checkedSquare.layer.cornerRadius = isRoundRectCheckMark ? 5.0 : 0 - } - - //-------------------------------------------------- - // MARK: - Molecular - //-------------------------------------------------- - - override func updateView(_ size: CGFloat) { - - } - - override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - - } -} diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift new file mode 100644 index 00000000..08f6227f --- /dev/null +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -0,0 +1,288 @@ +// +// Checkbox.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 9/13/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import MVMCore + + +@objcMembers open class Checkbox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public static let defaultHeightWidth: CGFloat = 18.0 + /* + //Offsets based on the 124x124 example checkmark + let startXOffset: Float = 42.0 / 124.0 + let startYOffset: Float = 66.0 / 124.0 + let pivotXOffset: Float = 58.0 / 124.0 + let pivotYOffset: Float = 80.0 / 124.0 + let endXOffset: Float = 83.0 / 124.0 + let endYOffset: Float = 46.0 / 124.0 + let pivotPercentage: Float = 0.34 + let endPercentage = 1.0 - pivotPercentage + let animationInterval: Float = 0.01 + */ + + public var checkedColor: UIColor = .black + public var unCheckedColor: UIColor = .mfPaleGrey() + + public var hasRoundBorder = false + + private var shapeLayer: CAShapeLayer? + private var _lineColor: UIColor = .black + private var _borderColor: UIColor = .black + private var _lineWidth: CGFloat = 1.0 + private var _cornerRadius: CGFloat = 5.0 + + public func setCheckMarkLayer() { + checkedSquare.layer.cornerRadius = checkbox.isRoundRectCheckMark ? 5.0 : 0 + } + + public var lineWidth: CGFloat { + get { return _lineWidth } + set (newLineWidth) { + _lineWidth = newLineWidth + if shapeLayer != nil { + shapeLayer?.removeFromSuperlayer() + shapeLayer = nil + updateCheckSelected(isSelected, animated: false) + } + } + } + + public var lineColor: UIColor { + get { return _lineColor } + set (newLineColor) { + _lineColor = newLineColor + if let shapeLayer = shapeLayer { + shapeLayer.strokeColor = lineColor.cgColor + updateCheckSelected(isSelected, animated: false) + } + } + } + + public var borderColor: UIColor { + get { return _borderColor } + set (newBorderColor) { + _borderColor = newBorderColor + if let shapeLayer = shapeLayer { + shapeLayer.strokeColor = borderColor.cgColor + updateCheckSelected(isSelected, animated: false) + } + } + } + + override open var isSelected: Bool { + didSet { + if isSelected { + layer.addSublayer(shapeLayer!) + shapeLayer?.strokeEnd = 1 + shapeLayer?.removeAllAnimations() + shapeLayer?.add(checkedAnimation, forKey: "strokeEnd") + } else { + shapeLayer?.strokeEnd = 0 + shapeLayer?.removeAllAnimations() + shapeLayer?.add(uncheckedAnimation, forKey: "strokeEnd") + } + } + } + + lazy private var checkedAnimation: CABasicAnimation = { + let check = CABasicAnimation(keyPath: "strokeEnd") + check.timingFunction = CAMediaTimingFunction(name: .linear) + check.fillMode = .both + check.duration = 0.33 + check.fromValue = 0 + check.toValue = 1 + return check + }() + + lazy private var uncheckedAnimation: CABasicAnimation = { + let unCheck = CABasicAnimation(keyPath: "strokeEnd") + unCheck.fillMode = .both + unCheck.duration = 0.33 + unCheck.fromValue = 0 + unCheck.toValue = 1 + return unCheck + }() + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + + override public init(frame: CGRect) { + super.init(frame: frame) + setupView() + } + + public convenience init() { + self.init(frame:.zero) + } + + /// There is currently no intention on using xib files. + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + fatalError("xib file is not implemented for CheckBox.") + } + + public convenience init(checkedColor: UIColor, uncheckColor: UIColor, isChecked: Bool) { + self.init(frame: .zero) + isSelected = isChecked + // TODO: define the rest.... + } + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + + override open func layoutSubviews() { + super.layoutSubviews() + drawCheck() + } + + public func setupView() { + + translatesAutoresizingMaskIntoConstraints = false + backgroundColor = .white + lineColor = .black + lineWidth = 1.0 + + let path = UIBezierPath() + path.move(to: CGPoint(x: lineWidth / 2, y: bounds.size.height * 0.55)) + path.addLine(to: CGPoint(x: bounds.size.width * 0.45, y: bounds.size.height * 0.85)) + path.addLine(to: CGPoint(x: bounds.size.width - lineWidth / 2, y: lineWidth / 2)) + + let shapeLayer = CAShapeLayer() + self.shapeLayer = shapeLayer + shapeLayer.frame = bounds + layer.addSublayer(shapeLayer) + shapeLayer.strokeColor = lineColor.cgColor + shapeLayer.fillColor = UIColor.clear.cgColor + shapeLayer.path = path.cgPath + shapeLayer.lineJoin = .bevel + shapeLayer.lineWidth = lineWidth + } + + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + + private func drawCheck() { + + if shapeLayer == nil { + + layoutIfNeeded() + + let path = UIBezierPath() + path.move(to: CGPoint(x: lineWidth / 2, y: bounds.size.height * 0.55)) + path.addLine(to: CGPoint(x: bounds.size.width * 0.45, y: bounds.size.height * 0.85)) + path.addLine(to: CGPoint(x: bounds.size.width - lineWidth / 2, y: lineWidth / 2)) + + shapeLayer = CAShapeLayer() + shapeLayer?.frame = bounds + layer.addSublayer(shapeLayer!) + shapeLayer?.strokeColor = lineColor.cgColor + shapeLayer?.fillColor = UIColor.clear.cgColor + shapeLayer?.path = path.cgPath + shapeLayer?.lineJoin = .bevel + shapeLayer?.lineWidth = lineWidth + + CATransaction.begin() + CATransaction.setDisableActions(true) + shapeLayer?.strokeEnd = 0.0 + CATransaction.commit() + } + } + + public func updateCheckSelected(_ selected: Bool, animated: Bool) { + + DispatchQueue.main.async { + + self.isSelected = selected + + self.drawCheck() + + var layer: CAShapeLayer? + if let presentation = self.shapeLayer?.presentation(), animated { + layer = presentation + } else { + layer = self.shapeLayer + } + + if animated { + let animateStrokeEnd = CABasicAnimation(keyPath: "strokeEnd") + animateStrokeEnd.fillMode = .both + animateStrokeEnd.isRemovedOnCompletion = false + animateStrokeEnd.duration = 0.33 + animateStrokeEnd.fromValue = layer?.strokeEnd ?? 0.0 + animateStrokeEnd.toValue = selected ? 1 : 0 + animateStrokeEnd.timingFunction = CAMediaTimingFunction(name: .linear) + layer?.add(animateStrokeEnd, forKey: "strokeEndAnimation") + } else { + layer?.removeAllAnimations() + CATransaction.begin() + CATransaction.setDisableActions(true) + layer?.strokeEnd = selected ? 1 : 0 + CATransaction.commit() + } + } + } + + //-------------------------------------------------- + // MARK: - Molecular + //-------------------------------------------------- + + open func needsToBeConstrained() -> Bool { + return true + } + + open func reset() { + setupView() + } + + open func setAsMolecule() { + setupView() + } + + public func updateView(_ size: CGFloat) { + + } + + public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + + guard let dictionary = json else { return } + + if let borderColor = dictionary["borderColor"] as? String { + layer.borderColor = UIColor.mfGet(forHex: borderColor).cgColor + } + + if let checkColor = dictionary["lineColor"] as? String { + _lineColor = UIColor.mfGet(forHex: checkColor) + } + + if let checkColor = dictionary["checkedColor"] as? String { + checkedColor = UIColor.mfGet(forHex: checkColor) + } + + if let unCheckedColor = dictionary["unCheckedColor"] as? String { + uncheckedColor = UIColor.mfGet(forHex: unCheckedColor) + } + + if let backroundColor = dictionary["backroundColor"] as? String { + self.backgroundColor = UIColor.mfGet(forHex: backroundColor) + } + + if let borderWidth = dictionary["borderWidth"] as? CGFloat { + _lineWidth = borderWidth + } + + if let cornerRadius = dictionary["cornerRadius"] as? CGFloat { + _cornerRadius = cornerRadius + } + } +} diff --git a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift new file mode 100644 index 00000000..609937ee --- /dev/null +++ b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift @@ -0,0 +1,289 @@ +// +// CheckboxWithLabelView.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 9/13/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + + +@objcMembers open class CheckboxWithLabelView: ViewConstrainingView { + //-------------------------------------------------- + // MARK: - Outlets + //-------------------------------------------------- + + let checkbox = Checkbox() + let label = Label.commonLabelB2(true) + + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + var sizeObject: MFSizeObject? = MFSizeObject(standardSize: Checkbox.defaultHeightWidth, standardiPadPortraitSize: Checkbox.defaultHeightWidth + 6.0) + + var checkboxWidthConstraint: NSLayoutConstraint? + var checkboxHeightConstraint: NSLayoutConstraint? + + + // Setter for the descriptionLabel.text. Also sets the accessibility text. + var labelText: String? + var labelAttributedText: NSAttributedString? + + // A block that is called when the switch is selected. + public var checkBoxAction: ((_ selected: Bool) -> ())? + + func setDescriptionAttributedText(_ descriptionAttributedText: NSAttributedString?) { + descriptionLabel?.text = nil + descriptionLabel?.attributedText = descriptionAttributedText + self.valueForAccessibilityText = descriptionAttributedText?.string + } + + var descriptionText: String { + get { return super.descriptionText } + set(descriptionText) { + descriptionLabel?.attributedText = nil + descriptionLabel.text = descriptionText + self.valueForAccessibilityText = descriptionText + } + } + + var isRequired = false + var fieldKey: String? + var delegate: DelegateObject? + + + //-------------------------------------------------- + // MARK: - Life Cycle + //-------------------------------------------------- + + override open func setupView() { + super.setupView() + + guard subviews.isEmpty else { return } + + translatesAutoresizingMaskIntoConstraints = false + + addSubview(checkbox) + + let dimension = sizeObject?.getValueBasedOnApplicationWidth() ?? Checkbox.defaultHeightWidth + + checkboxWidthConstraint = checkbox.heightAnchor.constraint(equalToConstant: dimension) + checkboxWidthConstraint?.isActive = true + checkboxHeightConstraint = checkbox.widthAnchor.constraint(equalToConstant: dimension) + checkboxHeightConstraint?.isActive = true + + NSLayoutConstraint.constraintPinSubview(checkbox, pinTop: true, pinBottom: true, pinLeft: true, pinRight: false) + checkbox.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + checkbox.lineWidth = 2.0 + addSubview(label) + + NSLayoutConstraint.constraintPinSubview(label, pinCenterX: false, pinCenterY: true) + NSLayoutConstraint.constraintPinSubview(label, pinTop: false, pinBottom: false, pinLeft: false, pinRight: true) + + label.leadingAnchor.constraint(equalTo: checkbox.trailingAnchor, constant: PaddingTwo).isActive = true + } + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + + //default inits + required public init?(coder: NSCoder) { + super.init(coder: coder) + fatalError("xib file is not implemented for CheckboxWithLabelView") + } + + override init(frame: CGRect) { + super.init(frame: frame) + setupView() + addAccessibleProperties() + } + + convenience init() { + self.init(frame: .zero) + } + + init(checkedColor: UIColor?, unCheckedColor: UIColor?, text: String?) { + super.init(frame: .zero) + checkbox.checkedColor = checkedColor + checkbox.unCheckedColor = unCheckedColor + label.text = text + addAccessibleProperties() + } + + init(checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, attributedText: NSAttributedString?) { + super.init(frame: .zero) + setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: nil) + descriptionAttributedText = attributedText + addAccessibleProperties() + } + + init?(checkMarkView: MVMCoreUICheckMarkView?, checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, text: String?) { + super.init(frame: .zero) + checkMark = checkMarkView + setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: text) + addAccessibleProperties() + } + + init?(checkMarkView: MVMCoreUICheckMarkView?, checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, attributedText: NSAttributedString?) { + super.init(frame: .zero) + checkMark = checkMarkView + setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: nil) + descriptionAttributedText = attributedText + addAccessibleProperties() + } + + init(roundRect isRoundRect: Bool) { + super.init(frame: .zero) + + isRoundRectCheckMark = isRoundRect + setup(withCheckedColor: .white, unCheck: .white, text: nil) + addAccessibleProperties() + setCheckMarkLayer() + } + + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + + override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return CGFloat(CheckBoxHeightWidth) + } + + // MARK: - control methods + func setSelected(_ selected: Bool) { + setSelected(selected, animated: true) + checkbox?.is + } + + func setSelected(_ selected: Bool, animated: Bool) { + setSelected(selected, animated: animated, runBlock: true) + } + + func setSelected(_ selected: Bool, animated: Bool, runBlock: Bool) { + addAccessibilityLabel(selected) + + isSelected = selected + if (switchSelected != nil) && runBlock { + switchSelected(selected) + } + + if selected { + UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { + self.checkedSquare.backgroundColor = self.checkedColor + }) + checkMark.updateCheckSelected(true, animated: animated) + } else { + UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { + self.checkedSquare.backgroundColor = self.unCheckedColor + }) + checkMark?.updateCheckSelected(false, animated: animated) + } + + if delegate && delegate.responds(to: #selector(formValidationProtocol)) && delegate.perform(#selector(formValidationProtocol)).responds(to: #selector(Unmanaged.formValidatorModel)) { + let formValidator = delegate.perform(#selector(formValidationProtocol)).perform(#selector(Unmanaged.formValidatorModel)) as? FormValidator + formValidator?.enableByValidation() + } + } + + //-------------------------------------------------- + // MARK: - UITouch + //-------------------------------------------------- + + func touchesEnded(_ touches: Set, with event: UIEvent) { + + if touchIsOutside(touches.first) { + sendActions(for: .touchUpOutside) + } else { + self.selected = !isSelected() + sendActions(for: .touchUpInside) + } + } + + func touchIsOutside(_ touch: UITouch?) -> Bool { + let endLocation = touch?.location(in: self) + let x = endLocation?.x ?? 0.0 + let y = endLocation?.y ?? 0.0 + let faultTolerance: CGFloat = 20.0 + let widthLimit = CGFloat(frame.size.width + faultTolerance) + let heightLimt = CGFloat(frame.size.height + faultTolerance) + + return x < -faultTolerance || y < -faultTolerance || x > widthLimit || y > heightLimt + } +} + +// MARK: - Molecular +extension CheckboxWithLabelView { + + @objc override open func updateView(_ size: CGFloat) { + + DispatchQueue.main.async { + self.label.updateView(size) + if self.checkbox.responds(to: #selector(self.updateView(_:))) { + if let dimension = self.sizeObject?.getValueBased(onSize: size) { + self.checkboxWidthConstraint?.constant = dimension + self.checkboxHeightConstraint?.constant = dimension + self.checkbox.updateView(size) + } + } + } + } + + override open func alignment() -> UIStackView.Alignment { + return .leading + } + + override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + delegate = delegateObject + FormValidator.setupValidation(molecule: self, delegate: delegateObject?.formValidationProtocol) + + guard let dictionary = json else { return } + + fieldKey = dictionary.string(for: KeyFieldKey) + isRequired = dictionary.bool(forKey: KeyRequired) + + checkbox.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + label.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + } +} + +// MARK:- FormValidationProtocol +extension CheckboxWithLabelView: FormValidationProtocol { + + public func isValidField() -> Bool { + return isRequired ? checkbox.isSelected : true + } + + public func formFieldName() -> String? { + return fieldKey + } + + public func formFieldValue() -> Any? { + return NSNumber(value: checkbox.isSelected) + } + + +} + +// MARK:- Accessibility +extension CheckboxWithLabelView { + + func addAccessibleProperties() { + accessibilityTraits = .none + accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "checkbox_action_hint") + } + + func addAccessibilityLabel(_ selected: Bool) { + let state = selected ? MVMCoreUIUtility.hardcodedString(withKey: "checkbox_checked_state") : MVMCoreUIUtility.hardcodedString(withKey: "checkbox_unchecked_state") + let description = accessibilityText.length ? accessibilityText : "" + accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "checkbox_desc_state"), description, state) + } + + func hideDescriptionLabelAndPinCheckboxToRight() { + + descriptionLabel?.hidden = true + checkboxRightPinConstraint.active = true + descriptionLabelLeadingConstraint.constant = 0 + } +} diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 945eb7bf..aeaf6b8d 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -38,11 +38,11 @@ @"caretButton": CaretButton.class, @"textField" : MFTextField.class, @"digitTextField" : MFDigitTextField.class, - @"checkbox" : MVMCoreUICheckBox.class, + @"checkbox" : Checkbox.class, @"cornerLabels" : CornerLabels.class, @"progressBar": ProgressBar.class, @"multiProgressBar": MultiProgress.class, - @"checkbox": MVMCoreUICheckBox.class, + @"checkboxWithLabelView": CheckboxWithLabelView.class, @"listItem": MoleculeTableViewCell.class, @"accordionListItem": AccordionMoleculeTableViewCell.class, @"switch": MVMCoreUISwitch.class, From 38c74acc6e86acbd8ea4e3631af9d4c1cd2ca2b4 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 25 Sep 2019 14:43:29 -0400 Subject: [PATCH 11/48] moar. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 8 +++---- .../Atoms/Views/CheckboxWithLabelView.swift | 23 +++---------------- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index 08f6227f..f29940f6 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -31,16 +31,16 @@ import MVMCore public var checkedColor: UIColor = .black public var unCheckedColor: UIColor = .mfPaleGrey() - public var hasRoundBorder = false + public var hasRoundCorners = false private var shapeLayer: CAShapeLayer? private var _lineColor: UIColor = .black private var _borderColor: UIColor = .black - private var _lineWidth: CGFloat = 1.0 - private var _cornerRadius: CGFloat = 5.0 + private var _lineWidth: CGFloat = 1 + private var _cornerRadius: CGFloat = 0 public func setCheckMarkLayer() { - checkedSquare.layer.cornerRadius = checkbox.isRoundRectCheckMark ? 5.0 : 0 + layer.cornerRadius = hasRoundCorners ? 5 : 0 } public var lineWidth: CGFloat { diff --git a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift index 609937ee..62589b43 100644 --- a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift +++ b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift @@ -114,29 +114,14 @@ init(checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, attributedText: NSAttributedString?) { super.init(frame: .zero) setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: nil) - descriptionAttributedText = attributedText + setDescriptionAttributedText = attributedText addAccessibleProperties() } - init?(checkMarkView: MVMCoreUICheckMarkView?, checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, text: String?) { - super.init(frame: .zero) - checkMark = checkMarkView - setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: text) - addAccessibleProperties() - } - - init?(checkMarkView: MVMCoreUICheckMarkView?, checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, attributedText: NSAttributedString?) { - super.init(frame: .zero) - checkMark = checkMarkView - setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: nil) - descriptionAttributedText = attributedText - addAccessibleProperties() - } - - init(roundRect isRoundRect: Bool) { + init(hasRoundedCheckbox: Bool) { super.init(frame: .zero) - isRoundRectCheckMark = isRoundRect + checkbox.hasRoundBorder = hasRoundRectCheckbox setup(withCheckedColor: .white, unCheck: .white, text: nil) addAccessibleProperties() setCheckMarkLayer() @@ -262,8 +247,6 @@ extension CheckboxWithLabelView: FormValidationProtocol { public func formFieldValue() -> Any? { return NSNumber(value: checkbox.isSelected) } - - } // MARK:- Accessibility From c75337bfdf03461953defbc53b36be884e10471d Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 26 Sep 2019 11:42:16 -0400 Subject: [PATCH 12/48] Getting closer to testing phase. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 154 +++++++--------- .../Atoms/Views/CheckboxWithLabelView.swift | 164 +++++++----------- 2 files changed, 130 insertions(+), 188 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index f29940f6..4408ea6d 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -15,67 +15,27 @@ import MVMCore //-------------------------------------------------- public static let defaultHeightWidth: CGFloat = 18.0 - /* - //Offsets based on the 124x124 example checkmark - let startXOffset: Float = 42.0 / 124.0 - let startYOffset: Float = 66.0 / 124.0 - let pivotXOffset: Float = 58.0 / 124.0 - let pivotYOffset: Float = 80.0 / 124.0 - let endXOffset: Float = 83.0 / 124.0 - let endYOffset: Float = 46.0 / 124.0 - let pivotPercentage: Float = 0.34 - let endPercentage = 1.0 - pivotPercentage - let animationInterval: Float = 0.01 - */ + /// The color of the box and line when checked. public var checkedColor: UIColor = .black - public var unCheckedColor: UIColor = .mfPaleGrey() + /// The color of the border when unChecked. + public var unCheckedColor: UIColor = .black + + /// If true the border of this checkbox will be circular. public var hasRoundCorners = false + // Internal values to manage the appearance of the checkbox. private var shapeLayer: CAShapeLayer? - private var _lineColor: UIColor = .black - private var _borderColor: UIColor = .black - private var _lineWidth: CGFloat = 1 - private var _cornerRadius: CGFloat = 0 - public func setCheckMarkLayer() { - layer.cornerRadius = hasRoundCorners ? 5 : 0 + public var cornerRadiusValue: CGFloat { + return bounds.height / 2.0 } - public var lineWidth: CGFloat { - get { return _lineWidth } - set (newLineWidth) { - _lineWidth = newLineWidth - if shapeLayer != nil { - shapeLayer?.removeFromSuperlayer() - shapeLayer = nil - updateCheckSelected(isSelected, animated: false) - } - } - } - - public var lineColor: UIColor { - get { return _lineColor } - set (newLineColor) { - _lineColor = newLineColor - if let shapeLayer = shapeLayer { - shapeLayer.strokeColor = lineColor.cgColor - updateCheckSelected(isSelected, animated: false) - } - } - } - - public var borderColor: UIColor { - get { return _borderColor } - set (newBorderColor) { - _borderColor = newBorderColor - if let shapeLayer = shapeLayer { - shapeLayer.strokeColor = borderColor.cgColor - updateCheckSelected(isSelected, animated: false) - } - } - } + public var lineWidth: CGFloat = 1 + public var lineColor: UIColor = .black + public var borderColor: UIColor = .black + private var checkedBackgroundColor: UIColor = .white override open var isSelected: Bool { didSet { @@ -104,6 +64,7 @@ import MVMCore lazy private var uncheckedAnimation: CABasicAnimation = { let unCheck = CABasicAnimation(keyPath: "strokeEnd") + unCheck.timingFunction = CAMediaTimingFunction(name: .linear) unCheck.fillMode = .both unCheck.duration = 0.33 unCheck.fromValue = 0 @@ -120,20 +81,21 @@ import MVMCore setupView() } - public convenience init() { - self.init(frame:.zero) - } - /// There is currently no intention on using xib files. required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) fatalError("xib file is not implemented for CheckBox.") } - public convenience init(checkedColor: UIColor, uncheckColor: UIColor, isChecked: Bool) { + public convenience init() { + self.init(frame:.zero) + } + + public convenience init(checkedColor: UIColor, unCheckedColor: UIColor, isChecked: Bool = false) { self.init(frame: .zero) isSelected = isChecked - // TODO: define the rest.... + self.checkedColor = checkedColor + self.unCheckedColor = unCheckedColor } //-------------------------------------------------- @@ -149,8 +111,6 @@ import MVMCore translatesAutoresizingMaskIntoConstraints = false backgroundColor = .white - lineColor = .black - lineWidth = 1.0 let path = UIBezierPath() path.move(to: CGPoint(x: lineWidth / 2, y: bounds.size.height * 0.55)) @@ -172,8 +132,16 @@ import MVMCore // MARK: - Methods //-------------------------------------------------- - private func drawCheck() { + open override func sendAction(_ action: Selector, to target: Any?, for event: UIEvent?) { + print("Action initiated") + } + open override func sendActions(for controlEvents: UIControl.Event) { + print("Actions Inititaled") + } + + private func drawCheck() { + if shapeLayer == nil { layoutIfNeeded() @@ -199,12 +167,27 @@ import MVMCore } } - public func updateCheckSelected(_ selected: Bool, animated: Bool) { + /* + //Offsets based on the 124x124 example checkmark + let startXOffset: Float = 42.0 / 124.0 + let startYOffset: Float = 66.0 / 124.0 + let pivotXOffset: Float = 58.0 / 124.0 + let pivotYOffset: Float = 80.0 / 124.0 + let endXOffset: Float = 83.0 / 124.0 + let endYOffset: Float = 46.0 / 124.0 + let pivotPercentage: Float = 0.34 + let endPercentage = 1.0 - pivotPercentage + let animationInterval: Float = 0.01 + */ + + public func updateCheckboxSelection(_ selected: Bool, animated: Bool) { + + shapeLayer?.removeFromSuperlayer() + shapeLayer = nil DispatchQueue.main.async { self.isSelected = selected - self.drawCheck() var layer: CAShapeLayer? @@ -227,12 +210,13 @@ import MVMCore layer?.removeAllAnimations() CATransaction.begin() CATransaction.setDisableActions(true) + CATransaction.setAnimationDuration(0) layer?.strokeEnd = selected ? 1 : 0 CATransaction.commit() } } } - + //-------------------------------------------------- // MARK: - Molecular //-------------------------------------------------- @@ -250,39 +234,35 @@ import MVMCore } public func updateView(_ size: CGFloat) { - + // TODO: Ensure the check logic is resized. } public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { guard let dictionary = json else { return } - if let borderColor = dictionary["borderColor"] as? String { - layer.borderColor = UIColor.mfGet(forHex: borderColor).cgColor + if let borderColorHex = dictionary["borderColor"] as? String { + layer.borderColor = UIColor.mfGet(forHex: borderColorHex).cgColor } - if let checkColor = dictionary["lineColor"] as? String { - _lineColor = UIColor.mfGet(forHex: checkColor) - } - - if let checkColor = dictionary["checkedColor"] as? String { - checkedColor = UIColor.mfGet(forHex: checkColor) - } - - if let unCheckedColor = dictionary["unCheckedColor"] as? String { - uncheckedColor = UIColor.mfGet(forHex: unCheckedColor) - } - - if let backroundColor = dictionary["backroundColor"] as? String { - self.backgroundColor = UIColor.mfGet(forHex: backroundColor) - } - if let borderWidth = dictionary["borderWidth"] as? CGFloat { - _lineWidth = borderWidth + layer.borderWidth = borderWidth } - - if let cornerRadius = dictionary["cornerRadius"] as? CGFloat { - _cornerRadius = cornerRadius + + if let checkColorHex = dictionary["lineColor"] as? String { + lineColor = UIColor.mfGet(forHex: checkColorHex) + } + + if let checkColorHex = dictionary["checkedColor"] as? String { + checkedColor = UIColor.mfGet(forHex: checkColorHex) + } + + if let unCheckedColorHex = dictionary["unCheckedColor"] as? String { + unCheckedColor = UIColor.mfGet(forHex: unCheckedColorHex) + } + + if let backroundColorHex = dictionary["backroundColor"] as? String { + backgroundColor = UIColor.mfGet(forHex: backroundColorHex) } } } diff --git a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift index 62589b43..93f8a894 100644 --- a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift +++ b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift @@ -24,34 +24,13 @@ var checkboxWidthConstraint: NSLayoutConstraint? var checkboxHeightConstraint: NSLayoutConstraint? - - // Setter for the descriptionLabel.text. Also sets the accessibility text. - var labelText: String? - var labelAttributedText: NSAttributedString? - // A block that is called when the switch is selected. - public var checkBoxAction: ((_ selected: Bool) -> ())? - - func setDescriptionAttributedText(_ descriptionAttributedText: NSAttributedString?) { - descriptionLabel?.text = nil - descriptionLabel?.attributedText = descriptionAttributedText - self.valueForAccessibilityText = descriptionAttributedText?.string - } - - var descriptionText: String { - get { return super.descriptionText } - set(descriptionText) { - descriptionLabel?.attributedText = nil - descriptionLabel.text = descriptionText - self.valueForAccessibilityText = descriptionText - } - } + public var checkboxAction: ((_ selected: Bool) -> ())? var isRequired = false var fieldKey: String? var delegate: DelegateObject? - //-------------------------------------------------- // MARK: - Life Cycle //-------------------------------------------------- @@ -66,7 +45,6 @@ addSubview(checkbox) let dimension = sizeObject?.getValueBasedOnApplicationWidth() ?? Checkbox.defaultHeightWidth - checkboxWidthConstraint = checkbox.heightAnchor.constraint(equalToConstant: dimension) checkboxWidthConstraint?.isActive = true checkboxHeightConstraint = checkbox.widthAnchor.constraint(equalToConstant: dimension) @@ -75,11 +53,10 @@ NSLayoutConstraint.constraintPinSubview(checkbox, pinTop: true, pinBottom: true, pinLeft: true, pinRight: false) checkbox.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true checkbox.lineWidth = 2.0 + addSubview(label) - - NSLayoutConstraint.constraintPinSubview(label, pinCenterX: false, pinCenterY: true) - NSLayoutConstraint.constraintPinSubview(label, pinTop: false, pinBottom: false, pinLeft: false, pinRight: true) - + label.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + trailingAnchor.constraint(equalTo: label.trailingAnchor).isActive = true label.leadingAnchor.constraint(equalTo: checkbox.trailingAnchor, constant: PaddingTwo).isActive = true } @@ -87,111 +64,99 @@ // MARK: - Initializers //-------------------------------------------------- - //default inits required public init?(coder: NSCoder) { super.init(coder: coder) fatalError("xib file is not implemented for CheckboxWithLabelView") } - override init(frame: CGRect) { + override public init(frame: CGRect) { super.init(frame: frame) setupView() - addAccessibleProperties() +// addAccessibleProperties() } - convenience init() { + public convenience init() { self.init(frame: .zero) } - init(checkedColor: UIColor?, unCheckedColor: UIColor?, text: String?) { - super.init(frame: .zero) + public convenience init(checkedColor: UIColor, unCheckedColor: UIColor, text: String?, isChecked: Bool = false) { + self.init(frame: .zero) + checkbox.checkedColor = checkedColor checkbox.unCheckedColor = unCheckedColor label.text = text - addAccessibleProperties() } - init(checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, attributedText: NSAttributedString?) { - super.init(frame: .zero) - setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: nil) - setDescriptionAttributedText = attributedText - addAccessibleProperties() - } - - init(hasRoundedCheckbox: Bool) { - super.init(frame: .zero) + public convenience init(checkedColor: UIColor, unCheck unCheckedColor: UIColor, attributedText: NSAttributedString, isChecked: Bool = false) { + self.init(frame: .zero) - checkbox.hasRoundBorder = hasRoundRectCheckbox - setup(withCheckedColor: .white, unCheck: .white, text: nil) - addAccessibleProperties() - setCheckMarkLayer() + checkbox.checkedColor = checkedColor + checkbox.unCheckedColor = unCheckedColor + label.attributedText = attributedText + } + + public convenience init(isRoundedCheckbox: Bool) { + self.init(frame: .zero) + + checkbox.hasRoundCorners = isRoundedCheckbox } //-------------------------------------------------- // MARK: - Methods //-------------------------------------------------- - override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - return CGFloat(CheckBoxHeightWidth) + override open class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return CGFloat(Checkbox.defaultHeightWidth) } - // MARK: - control methods - func setSelected(_ selected: Bool) { - setSelected(selected, animated: true) - checkbox?.is - } - - func setSelected(_ selected: Bool, animated: Bool) { - setSelected(selected, animated: animated, runBlock: true) - } - - func setSelected(_ selected: Bool, animated: Bool, runBlock: Bool) { - addAccessibilityLabel(selected) + @objc public func checkboxTapped(checkbox: Checkbox) { +// addAccessibilityLabel(selected) - isSelected = selected - if (switchSelected != nil) && runBlock { - switchSelected(selected) + checkbox.isSelected.toggle() + + if let checkboxAction = checkboxAction { + checkboxAction(checkbox.isSelected) } - if selected { - UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { - self.checkedSquare.backgroundColor = self.checkedColor - }) - checkMark.updateCheckSelected(true, animated: animated) - } else { - UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { - self.checkedSquare.backgroundColor = self.unCheckedColor - }) - checkMark?.updateCheckSelected(false, animated: animated) - } +// if checkbox.isSelected { +// UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { +// self.checkbox.backgroundColor = self.checkedColor +// }) +// checkbox.updateCheckSelected(true, animated: animated) +// } else { +// UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { +// self.checkbox.backgroundColor = self.unCheckedColor +// }) +// +// checkbox.updateCheckSelected(false, animated: animated) +// } - if delegate && delegate.responds(to: #selector(formValidationProtocol)) && delegate.perform(#selector(formValidationProtocol)).responds(to: #selector(Unmanaged.formValidatorModel)) { - let formValidator = delegate.perform(#selector(formValidationProtocol)).perform(#selector(Unmanaged.formValidatorModel)) as? FormValidator - formValidator?.enableByValidation() - } + // if delegate && delegate.responds(to: #selector(formValidationProtocol)) && delegate.perform(#selector(formValidationProtocol)).responds(to: #selector(Unmanaged.formValidatorModel)) { + // let formValidator = delegate.perform(#selector(formValidationProtocol)).perform(#selector(Unmanaged.formValidatorModel)) as? FormValidator + // formValidator?.enableByValidation() + // } } - + //-------------------------------------------------- // MARK: - UITouch //-------------------------------------------------- func touchesEnded(_ touches: Set, with event: UIEvent) { - if touchIsOutside(touches.first) { - sendActions(for: .touchUpOutside) + if touchIsAcceptablyOutside(touches.first) { + checkbox.sendActions(for: .touchUpOutside) } else { - self.selected = !isSelected() - sendActions(for: .touchUpInside) + checkbox.sendActions(for: .touchUpInside) } } - func touchIsOutside(_ touch: UITouch?) -> Bool { + func touchIsAcceptablyOutside(_ touch: UITouch?) -> Bool { let endLocation = touch?.location(in: self) let x = endLocation?.x ?? 0.0 let y = endLocation?.y ?? 0.0 let faultTolerance: CGFloat = 20.0 - let widthLimit = CGFloat(frame.size.width + faultTolerance) - let heightLimt = CGFloat(frame.size.height + faultTolerance) + let widthLimit = CGFloat(bounds.size.width + faultTolerance) + let heightLimt = CGFloat(bounds.size.height + faultTolerance) return x < -faultTolerance || y < -faultTolerance || x > widthLimit || y > heightLimt } @@ -225,8 +190,13 @@ extension CheckboxWithLabelView { guard let dictionary = json else { return } - fieldKey = dictionary.string(for: KeyFieldKey) - isRequired = dictionary.bool(forKey: KeyRequired) + if let fieldKey = dictionary[KeyFieldKey] as? String { + self.fieldKey = fieldKey + } + + if let isRequired = dictionary[KeyRequired] as? Bool { + self.isRequired = isRequired + } checkbox.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) label.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) @@ -253,20 +223,12 @@ extension CheckboxWithLabelView: FormValidationProtocol { extension CheckboxWithLabelView { func addAccessibleProperties() { - accessibilityTraits = .none - accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "checkbox_action_hint") +// accessibilityTraits = .none +// accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "checkbox_action_hint") } func addAccessibilityLabel(_ selected: Bool) { - let state = selected ? MVMCoreUIUtility.hardcodedString(withKey: "checkbox_checked_state") : MVMCoreUIUtility.hardcodedString(withKey: "checkbox_unchecked_state") - let description = accessibilityText.length ? accessibilityText : "" - accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "checkbox_desc_state"), description, state) - } - - func hideDescriptionLabelAndPinCheckboxToRight() { - - descriptionLabel?.hidden = true - checkboxRightPinConstraint.active = true - descriptionLabelLeadingConstraint.constant = 0 +// let state = selected ? MVMCoreUIUtility.hardcodedString(withKey: "checkbox_checked_state") : MVMCoreUIUtility.hardcodedString(withKey: "checkbox_unchecked_state") +// accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "checkbox_desc_state"), label.text ?? "", state) } } From afcf8d535ba987f9ddfd87ab32acbb7e159749e1 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 26 Sep 2019 13:56:02 -0400 Subject: [PATCH 13/48] updates. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index 4408ea6d..1ab976ef 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -29,13 +29,13 @@ import MVMCore private var shapeLayer: CAShapeLayer? public var cornerRadiusValue: CGFloat { - return bounds.height / 2.0 + return bounds.height / 2 } public var lineWidth: CGFloat = 1 public var lineColor: UIColor = .black public var borderColor: UIColor = .black - private var checkedBackgroundColor: UIColor = .white + public var checkedBackgroundColor: UIColor = .white override open var isSelected: Bool { didSet { @@ -129,7 +129,7 @@ import MVMCore } //-------------------------------------------------- - // MARK: - Methods + // MARK: - Action //-------------------------------------------------- open override func sendAction(_ action: Selector, to target: Any?, for event: UIEvent?) { @@ -140,6 +140,10 @@ import MVMCore print("Actions Inititaled") } + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + private func drawCheck() { if shapeLayer == nil { @@ -169,6 +173,7 @@ import MVMCore /* //Offsets based on the 124x124 example checkmark + let startXOffset: Float = 42.0 / 124.0 let startYOffset: Float = 66.0 / 124.0 let pivotXOffset: Float = 58.0 / 124.0 @@ -202,7 +207,7 @@ import MVMCore animateStrokeEnd.fillMode = .both animateStrokeEnd.isRemovedOnCompletion = false animateStrokeEnd.duration = 0.33 - animateStrokeEnd.fromValue = layer?.strokeEnd ?? 0.0 + animateStrokeEnd.fromValue = layer?.strokeEnd ?? 0 animateStrokeEnd.toValue = selected ? 1 : 0 animateStrokeEnd.timingFunction = CAMediaTimingFunction(name: .linear) layer?.add(animateStrokeEnd, forKey: "strokeEndAnimation") From f5f994648aca33f941fead0178d8ed4fed149c91 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 27 Sep 2019 13:43:02 -0400 Subject: [PATCH 14/48] Decent working state with animation and touch. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 270 ++++++++++++------ .../Atoms/Views/CheckboxWithLabelView.swift | 101 ++----- 2 files changed, 212 insertions(+), 159 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index 1ab976ef..d00c2463 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -16,36 +16,54 @@ import MVMCore public static let defaultHeightWidth: CGFloat = 18.0 - /// The color of the box and line when checked. - public var checkedColor: UIColor = .black + /// The color of the background when checked. + public var checkedBackgroundColor: UIColor = .white - /// The color of the border when unChecked. - public var unCheckedColor: UIColor = .black + /// The color of the background when unChecked. + public var unCheckedBackgroundColor: UIColor = .black /// If true the border of this checkbox will be circular. public var hasRoundCorners = false + // Action Block called when the switch is selected. + public var actionBlock: ActionBlock? + // Internal values to manage the appearance of the checkbox. private var shapeLayer: CAShapeLayer? public var cornerRadiusValue: CGFloat { - return bounds.height / 2 + return bounds.size.height / 2 } - public var lineWidth: CGFloat = 1 + public var lineWidth: CGFloat = 2 public var lineColor: UIColor = .black - public var borderColor: UIColor = .black - public var checkedBackgroundColor: UIColor = .white + + open var borderColor: UIColor { + get { + guard let color = layer.borderColor else { return .black } + return UIColor(cgColor: color) + } + set (newColor) { + layer.borderColor = newColor.cgColor + } + } + open var borderWidth: CGFloat { + get { return layer.borderWidth } + set (newWidth) { + layer.borderWidth = newWidth + } + } + override open var isSelected: Bool { didSet { if isSelected { - layer.addSublayer(shapeLayer!) - shapeLayer?.strokeEnd = 1 +// layer.addSublayer(shapeLayer!) +// shapeLayer?.strokeEnd = 1 shapeLayer?.removeAllAnimations() shapeLayer?.add(checkedAnimation, forKey: "strokeEnd") } else { - shapeLayer?.strokeEnd = 0 +// shapeLayer?.strokeEnd = 0 shapeLayer?.removeAllAnimations() shapeLayer?.add(uncheckedAnimation, forKey: "strokeEnd") } @@ -55,8 +73,9 @@ import MVMCore lazy private var checkedAnimation: CABasicAnimation = { let check = CABasicAnimation(keyPath: "strokeEnd") check.timingFunction = CAMediaTimingFunction(name: .linear) + check.isRemovedOnCompletion = false check.fillMode = .both - check.duration = 0.33 + check.duration = 0.3 check.fromValue = 0 check.toValue = 1 return check @@ -65,10 +84,11 @@ import MVMCore lazy private var uncheckedAnimation: CABasicAnimation = { let unCheck = CABasicAnimation(keyPath: "strokeEnd") unCheck.timingFunction = CAMediaTimingFunction(name: .linear) + unCheck.isRemovedOnCompletion = false unCheck.fillMode = .both - unCheck.duration = 0.33 - unCheck.fromValue = 0 - unCheck.toValue = 1 + unCheck.duration = 0.3 + unCheck.fromValue = 1 + unCheck.toValue = 0 return unCheck }() @@ -84,7 +104,7 @@ import MVMCore /// There is currently no intention on using xib files. required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - fatalError("xib file is not implemented for CheckBox.") + fatalError("xib file is not implemented for Checkbox.") } public convenience init() { @@ -94,8 +114,8 @@ import MVMCore public convenience init(checkedColor: UIColor, unCheckedColor: UIColor, isChecked: Bool = false) { self.init(frame: .zero) isSelected = isChecked - self.checkedColor = checkedColor - self.unCheckedColor = unCheckedColor + self.checkedBackgroundColor = checkedColor + self.unCheckedBackgroundColor = unCheckedColor } //-------------------------------------------------- @@ -109,35 +129,31 @@ import MVMCore public func setupView() { + isUserInteractionEnabled = true translatesAutoresizingMaskIntoConstraints = false backgroundColor = .white - - let path = UIBezierPath() - path.move(to: CGPoint(x: lineWidth / 2, y: bounds.size.height * 0.55)) - path.addLine(to: CGPoint(x: bounds.size.width * 0.45, y: bounds.size.height * 0.85)) - path.addLine(to: CGPoint(x: bounds.size.width - lineWidth / 2, y: lineWidth / 2)) - - let shapeLayer = CAShapeLayer() - self.shapeLayer = shapeLayer - shapeLayer.frame = bounds - layer.addSublayer(shapeLayer) - shapeLayer.strokeColor = lineColor.cgColor - shapeLayer.fillColor = UIColor.clear.cgColor - shapeLayer.path = path.cgPath - shapeLayer.lineJoin = .bevel - shapeLayer.lineWidth = lineWidth + layer.borderWidth = 1 + layer.borderColor = UIColor.black.cgColor } //-------------------------------------------------- - // MARK: - Action + // MARK: - Actions //-------------------------------------------------- open override func sendAction(_ action: Selector, to target: Any?, for event: UIEvent?) { - print("Action initiated") + super.sendAction(action, to: target, for: event) + + isSelected.toggle() + actionBlock?() + drawCheck() } - + open override func sendActions(for controlEvents: UIControl.Event) { - print("Actions Inititaled") + super.sendActions(for: controlEvents) + + isSelected.toggle() + actionBlock?() + drawCheck() } //-------------------------------------------------- @@ -147,54 +163,62 @@ import MVMCore private func drawCheck() { if shapeLayer == nil { - - layoutIfNeeded() - - let path = UIBezierPath() - path.move(to: CGPoint(x: lineWidth / 2, y: bounds.size.height * 0.55)) - path.addLine(to: CGPoint(x: bounds.size.width * 0.45, y: bounds.size.height * 0.85)) - path.addLine(to: CGPoint(x: bounds.size.width - lineWidth / 2, y: lineWidth / 2)) - - shapeLayer = CAShapeLayer() - shapeLayer?.frame = bounds - layer.addSublayer(shapeLayer!) - shapeLayer?.strokeColor = lineColor.cgColor - shapeLayer?.fillColor = UIColor.clear.cgColor - shapeLayer?.path = path.cgPath - shapeLayer?.lineJoin = .bevel - shapeLayer?.lineWidth = lineWidth - - CATransaction.begin() - CATransaction.setDisableActions(true) - shapeLayer?.strokeEnd = 0.0 - CATransaction.commit() + + let shapeLayer = CAShapeLayer() + self.shapeLayer = shapeLayer + shapeLayer.frame = bounds + layer.addSublayer(shapeLayer) + shapeLayer.strokeColor = lineColor.cgColor + shapeLayer.fillColor = UIColor.clear.cgColor + shapeLayer.path = checkMarkBezierPath.cgPath + shapeLayer.lineJoin = .bevel + shapeLayer.lineWidth = lineWidth + + CATransaction.withDisabledAnimations { + shapeLayer.strokeEnd = 0.0 + } } } /* - //Offsets based on the 124x124 example checkmark - - let startXOffset: Float = 42.0 / 124.0 - let startYOffset: Float = 66.0 / 124.0 - let pivotXOffset: Float = 58.0 / 124.0 - let pivotYOffset: Float = 80.0 / 124.0 - let endXOffset: Float = 83.0 / 124.0 - let endYOffset: Float = 46.0 / 124.0 + // Offsets based on the 124x124 example checkmark + let startXOffset: Float = 42.0 / 124.0 ~~ 0.33871 + let startYOffset: Float = 66.0 / 124.0 ~~ 0.53225 + let pivotXOffset: Float = 58.0 / 124.0 ~~ 0.46774 + let pivotYOffset: Float = 80.0 / 124.0 ~~ 0.64516 + let endXOffset: Float = 83.0 / 124.0 ~~ 0.66935 + let endYOffset: Float = 46.0 / 124.0 ~~ 0.37097 let pivotPercentage: Float = 0.34 let endPercentage = 1.0 - pivotPercentage let animationInterval: Float = 0.01 */ - public func updateCheckboxSelection(_ selected: Bool, animated: Bool) { + /// Returns a UIBezierPath detailing the path of a checkmark + var checkMarkBezierPath: UIBezierPath { - shapeLayer?.removeFromSuperlayer() - shapeLayer = nil + let sideLength = bounds.size.height + let startPoint = CGPoint(x: 0.33871 * sideLength, y: 0.53225 * sideLength) + let pivotOffSet = CGPoint(x: 0.46774 * sideLength, y: 0.64516 * sideLength) + let endOffset = CGPoint(x: 0.66935 * sideLength , y: 0.37097 * sideLength) + + let path = UIBezierPath() + path.move(to: startPoint) + path.addLine(to: pivotOffSet) + path.addLine(to: endOffset) + + return path + } + + public func updateSelection(_ selected: Bool, animated: Bool) { + +// shapeLayer?.removeFromSuperlayer() +// shapeLayer = nil DispatchQueue.main.async { self.isSelected = selected self.drawCheck() - + var layer: CAShapeLayer? if let presentation = self.shapeLayer?.presentation(), animated { layer = presentation @@ -204,24 +228,93 @@ import MVMCore if animated { let animateStrokeEnd = CABasicAnimation(keyPath: "strokeEnd") + animateStrokeEnd.timingFunction = CAMediaTimingFunction(name: .linear) + animateStrokeEnd.duration = 0.33 animateStrokeEnd.fillMode = .both animateStrokeEnd.isRemovedOnCompletion = false - animateStrokeEnd.duration = 0.33 animateStrokeEnd.fromValue = layer?.strokeEnd ?? 0 animateStrokeEnd.toValue = selected ? 1 : 0 - animateStrokeEnd.timingFunction = CAMediaTimingFunction(name: .linear) layer?.add(animateStrokeEnd, forKey: "strokeEndAnimation") } else { layer?.removeAllAnimations() - CATransaction.begin() - CATransaction.setDisableActions(true) - CATransaction.setAnimationDuration(0) - layer?.strokeEnd = selected ? 1 : 0 - CATransaction.commit() + CATransaction.withDisabledAnimations { + layer?.strokeEnd = selected ? 1 : 0 + } } } } + //-------------------------------------------------- + // MARK: - UITouch + //-------------------------------------------------- + + open override func touchesEnded(_ touches: Set, with event: UIEvent?) { + + if touchIsAcceptablyOutside(touches.first) { + sendActions(for: .touchUpOutside) + } else { + sendActions(for: .touchUpInside) + } + } + + func touchIsAcceptablyOutside(_ touch: UITouch?) -> Bool { + let endLocation = touch?.location(in: self) + let x = endLocation?.x ?? 0.0 + let y = endLocation?.y ?? 0.0 + let faultTolerance: CGFloat = 20.0 + let widthLimit = CGFloat(bounds.size.width + faultTolerance) + let heightLimt = CGFloat(bounds.size.height + faultTolerance) + + return x < -faultTolerance || y < -faultTolerance || x > widthLimit || y > heightLimt + } + + // if checkbox.isSelected { + // UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { + // self.checkbox.backgroundColor = self.checkedColor + // }) + // checkbox.updateCheckSelected(true, animated: animated) + // } else { + // UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { + // self.checkbox.backgroundColor = self.unCheckedColor + // }) + // + // checkbox.updateCheckSelected(false, animated: animated) + // } + + // if delegate && delegate.responds(to: #selector(formValidationProtocol)) && delegate.perform(#selector(formValidationProtocol)).responds(to: #selector(Unmanaged.formValidatorModel)) { + // let formValidator = delegate.perform(#selector(formValidationProtocol)).perform(#selector(Unmanaged.formValidatorModel)) as? FormValidator + // formValidator?.enableByValidation() + // } + + + /* + + - (void)setSelected:(BOOL)selected animated:(BOOL)animated runBlock:(BOOL)runBlock { + [self addAccessibilityLabel:selected]; + + self.isSelected = selected; + if (self.switchSelected && runBlock) { + self.switchSelected(selected); + } + if (selected) { + [UIView animateWithDuration:0.2 delay:0.1 options:UIViewAnimationOptionCurveEaseOut animations:^{ + self.checkedSquare.backgroundColor = self.checkedColor; + } completion:nil]; + [self.checkMark updateCheckSelected:YES animated:animated]; + } else { + [UIView animateWithDuration:0.2 delay:0.1 options:UIViewAnimationOptionCurveEaseOut animations:^{ + self.checkedSquare.backgroundColor = self.unCheckedColor; + } completion:nil]; + [self.checkMark updateCheckSelected:NO animated:animated]; + } + + if (self.delegate && [self.delegate respondsToSelector:@selector(formValidationProtocol)] && [[self.delegate performSelector:@selector(formValidationProtocol)] respondsToSelector:@selector(formValidatorModel)]) { + FormValidator *formValidator = [[self.delegate performSelector:@selector(formValidationProtocol)] performSelector:@selector(formValidatorModel)]; + [formValidator enableByValidation]; + } + } + */ + //-------------------------------------------------- // MARK: - Molecular //-------------------------------------------------- @@ -239,6 +332,7 @@ import MVMCore } public func updateView(_ size: CGFloat) { + // TODO: Ensure the check logic is resized. } @@ -259,15 +353,27 @@ import MVMCore } if let checkColorHex = dictionary["checkedColor"] as? String { - checkedColor = UIColor.mfGet(forHex: checkColorHex) + checkedBackgroundColor = UIColor.mfGet(forHex: checkColorHex) } if let unCheckedColorHex = dictionary["unCheckedColor"] as? String { - unCheckedColor = UIColor.mfGet(forHex: unCheckedColorHex) + unCheckedBackgroundColor = UIColor.mfGet(forHex: unCheckedColorHex) } - if let backroundColorHex = dictionary["backroundColor"] as? String { - backgroundColor = UIColor.mfGet(forHex: backroundColorHex) - } +// if let actionMap = dictionary.optionalDictionaryForKey("actionMap") { +// actionBlock = { MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) } +// } + } +} + +// TODO: Move to its own extension file. +extension CATransaction { + + /// Performs changes without activating animation actions. + static func withDisabledAnimations(_ actionBlock: ActionBlock) { + CATransaction.begin() + CATransaction.setDisableActions(true) + actionBlock() + CATransaction.commit() } } diff --git a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift index 93f8a894..94cd86e2 100644 --- a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift +++ b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift @@ -21,16 +21,17 @@ var sizeObject: MFSizeObject? = MFSizeObject(standardSize: Checkbox.defaultHeightWidth, standardiPadPortraitSize: Checkbox.defaultHeightWidth + 6.0) - var checkboxWidthConstraint: NSLayoutConstraint? - var checkboxHeightConstraint: NSLayoutConstraint? - - // A block that is called when the switch is selected. - public var checkboxAction: ((_ selected: Bool) -> ())? - var isRequired = false var fieldKey: String? var delegate: DelegateObject? + + //-------------------------------------------------- + // MARK: - Constraints + //-------------------------------------------------- + var checkboxWidthConstraint: NSLayoutConstraint? + var checkboxHeightConstraint: NSLayoutConstraint? + //-------------------------------------------------- // MARK: - Life Cycle //-------------------------------------------------- @@ -43,6 +44,7 @@ translatesAutoresizingMaskIntoConstraints = false addSubview(checkbox) + addSubview(label) let dimension = sizeObject?.getValueBasedOnApplicationWidth() ?? Checkbox.defaultHeightWidth checkboxWidthConstraint = checkbox.heightAnchor.constraint(equalToConstant: dimension) @@ -50,13 +52,15 @@ checkboxHeightConstraint = checkbox.widthAnchor.constraint(equalToConstant: dimension) checkboxHeightConstraint?.isActive = true - NSLayoutConstraint.constraintPinSubview(checkbox, pinTop: true, pinBottom: true, pinLeft: true, pinRight: false) + checkbox.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor).isActive = true + layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: checkbox.bottomAnchor).isActive = true + checkbox.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true checkbox.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true - checkbox.lineWidth = 2.0 - addSubview(label) + label.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor).isActive = true + layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: label.bottomAnchor).isActive = true label.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true - trailingAnchor.constraint(equalTo: label.trailingAnchor).isActive = true + layoutMarginsGuide.trailingAnchor.constraint(equalTo: label.trailingAnchor).isActive = true label.leadingAnchor.constraint(equalTo: checkbox.trailingAnchor, constant: PaddingTwo).isActive = true } @@ -82,89 +86,32 @@ public convenience init(checkedColor: UIColor, unCheckedColor: UIColor, text: String?, isChecked: Bool = false) { self.init(frame: .zero) - checkbox.checkedColor = checkedColor - checkbox.unCheckedColor = unCheckedColor + checkbox.checkedBackgroundColor = checkedColor + checkbox.unCheckedBackgroundColor = unCheckedColor label.text = text } public convenience init(checkedColor: UIColor, unCheck unCheckedColor: UIColor, attributedText: NSAttributedString, isChecked: Bool = false) { self.init(frame: .zero) - checkbox.checkedColor = checkedColor - checkbox.unCheckedColor = unCheckedColor + checkbox.checkedBackgroundColor = checkedColor + checkbox.unCheckedBackgroundColor = unCheckedColor label.attributedText = attributedText } public convenience init(isRoundedCheckbox: Bool) { self.init(frame: .zero) - checkbox.hasRoundCorners = isRoundedCheckbox } - - //-------------------------------------------------- - // MARK: - Methods - //-------------------------------------------------- - - override open class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - return CGFloat(Checkbox.defaultHeightWidth) - } - - @objc public func checkboxTapped(checkbox: Checkbox) { -// addAccessibilityLabel(selected) - - checkbox.isSelected.toggle() - - if let checkboxAction = checkboxAction { - checkboxAction(checkbox.isSelected) - } - -// if checkbox.isSelected { -// UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { -// self.checkbox.backgroundColor = self.checkedColor -// }) -// checkbox.updateCheckSelected(true, animated: animated) -// } else { -// UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { -// self.checkbox.backgroundColor = self.unCheckedColor -// }) -// -// checkbox.updateCheckSelected(false, animated: animated) -// } - - // if delegate && delegate.responds(to: #selector(formValidationProtocol)) && delegate.perform(#selector(formValidationProtocol)).responds(to: #selector(Unmanaged.formValidatorModel)) { - // let formValidator = delegate.perform(#selector(formValidationProtocol)).perform(#selector(Unmanaged.formValidatorModel)) as? FormValidator - // formValidator?.enableByValidation() - // } - } - - //-------------------------------------------------- - // MARK: - UITouch - //-------------------------------------------------- - - func touchesEnded(_ touches: Set, with event: UIEvent) { - - if touchIsAcceptablyOutside(touches.first) { - checkbox.sendActions(for: .touchUpOutside) - } else { - checkbox.sendActions(for: .touchUpInside) - } - } - - func touchIsAcceptablyOutside(_ touch: UITouch?) -> Bool { - let endLocation = touch?.location(in: self) - let x = endLocation?.x ?? 0.0 - let y = endLocation?.y ?? 0.0 - let faultTolerance: CGFloat = 20.0 - let widthLimit = CGFloat(bounds.size.width + faultTolerance) - let heightLimt = CGFloat(bounds.size.height + faultTolerance) - - return x < -faultTolerance || y < -faultTolerance || x > widthLimit || y > heightLimt - } } // MARK: - Molecular extension CheckboxWithLabelView { + override open class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return CGFloat(Checkbox.defaultHeightWidth) + } + @objc override open func updateView(_ size: CGFloat) { DispatchQueue.main.async { @@ -198,8 +145,8 @@ extension CheckboxWithLabelView { self.isRequired = isRequired } - checkbox.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - label.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + checkbox.setWithJSON(dictionary.dictionaryForKey("checkbox"), delegateObject: delegateObject, additionalData: additionalData) + label.setWithJSON(dictionary.dictionaryForKey("label"), delegateObject: delegateObject, additionalData: additionalData) } } From b032e40400833219e9aa800ca0d3eb24ea13aaeb Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 27 Sep 2019 14:23:46 -0400 Subject: [PATCH 15/48] Checkbox in good place. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 88 ++++++++++--------- .../Atoms/Views/CheckboxWithLabelView.swift | 6 +- 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index d00c2463..29ecc3c6 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -17,13 +17,17 @@ import MVMCore public static let defaultHeightWidth: CGFloat = 18.0 /// The color of the background when checked. - public var checkedBackgroundColor: UIColor = .white + public var checkedBackgroundColor: UIColor? - /// The color of the background when unChecked. - public var unCheckedBackgroundColor: UIColor = .black + /// The color of the background when unChecked. Will change of the view's background color. + public var unCheckedBackgroundColor: UIColor = .white { + didSet (newColor) { + backgroundColor = newColor + } + } /// If true the border of this checkbox will be circular. - public var hasRoundCorners = false + public var hasRoundedCorners = false // Action Block called when the switch is selected. public var actionBlock: ActionBlock? @@ -37,7 +41,7 @@ import MVMCore public var lineWidth: CGFloat = 2 public var lineColor: UIColor = .black - + open var borderColor: UIColor { get { guard let color = layer.borderColor else { return .black } @@ -54,17 +58,23 @@ import MVMCore layer.borderWidth = newWidth } } - + override open var isSelected: Bool { didSet { + shapeLayer?.removeAllAnimations() if isSelected { -// layer.addSublayer(shapeLayer!) -// shapeLayer?.strokeEnd = 1 - shapeLayer?.removeAllAnimations() + if checkedBackgroundColor != nil { + UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { + self.backgroundColor = self.checkedBackgroundColor + }) + } shapeLayer?.add(checkedAnimation, forKey: "strokeEnd") } else { -// shapeLayer?.strokeEnd = 0 - shapeLayer?.removeAllAnimations() + if checkedBackgroundColor != nil { + UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { + self.backgroundColor = self.unCheckedBackgroundColor + }) + } shapeLayer?.add(uncheckedAnimation, forKey: "strokeEnd") } } @@ -118,6 +128,11 @@ import MVMCore self.unCheckedBackgroundColor = unCheckedColor } + public convenience init(isCircular: Bool) { + self.init(frame: .zero) + hasRoundedCorners = isCircular + } + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -125,13 +140,14 @@ import MVMCore override open func layoutSubviews() { super.layoutSubviews() drawCheck() + layer.cornerRadius = hasRoundedCorners ? cornerRadiusValue : 0 + backgroundColor = unCheckedBackgroundColor ?? .white } public func setupView() { isUserInteractionEnabled = true translatesAutoresizingMaskIntoConstraints = false - backgroundColor = .white layer.borderWidth = 1 layer.borderColor = UIColor.black.cgColor } @@ -145,15 +161,13 @@ import MVMCore isSelected.toggle() actionBlock?() - drawCheck() } - + open override func sendActions(for controlEvents: UIControl.Event) { super.sendActions(for: controlEvents) isSelected.toggle() actionBlock?() - drawCheck() } //-------------------------------------------------- @@ -163,7 +177,7 @@ import MVMCore private func drawCheck() { if shapeLayer == nil { - + let shapeLayer = CAShapeLayer() self.shapeLayer = shapeLayer shapeLayer.frame = bounds @@ -173,7 +187,7 @@ import MVMCore shapeLayer.path = checkMarkBezierPath.cgPath shapeLayer.lineJoin = .bevel shapeLayer.lineWidth = lineWidth - + CATransaction.withDisabledAnimations { shapeLayer.strokeEnd = 0.0 } @@ -181,6 +195,9 @@ import MVMCore } /* + !!! -- DO NOT REMOVE -- !!! + (Unless Design changes the appearance of the checkmark). + // Offsets based on the 124x124 example checkmark let startXOffset: Float = 42.0 / 124.0 ~~ 0.33871 let startYOffset: Float = 66.0 / 124.0 ~~ 0.53225 @@ -208,17 +225,17 @@ import MVMCore return path } - + public func updateSelection(_ selected: Bool, animated: Bool) { -// shapeLayer?.removeFromSuperlayer() -// shapeLayer = nil + // shapeLayer?.removeFromSuperlayer() + // shapeLayer = nil DispatchQueue.main.async { self.isSelected = selected self.drawCheck() - + var layer: CAShapeLayer? if let presentation = self.shapeLayer?.presentation(), animated { layer = presentation @@ -268,19 +285,6 @@ import MVMCore return x < -faultTolerance || y < -faultTolerance || x > widthLimit || y > heightLimt } - // if checkbox.isSelected { - // UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { - // self.checkbox.backgroundColor = self.checkedColor - // }) - // checkbox.updateCheckSelected(true, animated: animated) - // } else { - // UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { - // self.checkbox.backgroundColor = self.unCheckedColor - // }) - // - // checkbox.updateCheckSelected(false, animated: animated) - // } - // if delegate && delegate.responds(to: #selector(formValidationProtocol)) && delegate.perform(#selector(formValidationProtocol)).responds(to: #selector(Unmanaged.formValidatorModel)) { // let formValidator = delegate.perform(#selector(formValidationProtocol)).perform(#selector(Unmanaged.formValidatorModel)) as? FormValidator // formValidator?.enableByValidation() @@ -288,7 +292,7 @@ import MVMCore /* - + - (void)setSelected:(BOOL)selected animated:(BOOL)animated runBlock:(BOOL)runBlock { [self addAccessibilityLabel:selected]; @@ -313,8 +317,8 @@ import MVMCore [formValidator enableByValidation]; } } - */ - + */ + //-------------------------------------------------- // MARK: - Molecular //-------------------------------------------------- @@ -360,9 +364,13 @@ import MVMCore unCheckedBackgroundColor = UIColor.mfGet(forHex: unCheckedColorHex) } -// if let actionMap = dictionary.optionalDictionaryForKey("actionMap") { -// actionBlock = { MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) } -// } + if let isRound = dictionary["isRound"] as? Bool { + hasRoundedCorners = isRound + } + + // if let actionMap = dictionary.optionalDictionaryForKey("actionMap") { + // actionBlock = { MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) } + // } } } diff --git a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift index 94cd86e2..db551800 100644 --- a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift +++ b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift @@ -56,6 +56,7 @@ layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: checkbox.bottomAnchor).isActive = true checkbox.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true checkbox.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + checkbox.checkedBackgroundColor = .yellow label.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor).isActive = true layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: label.bottomAnchor).isActive = true @@ -98,11 +99,6 @@ checkbox.unCheckedBackgroundColor = unCheckedColor label.attributedText = attributedText } - - public convenience init(isRoundedCheckbox: Bool) { - self.init(frame: .zero) - checkbox.hasRoundCorners = isRoundedCheckbox - } } // MARK: - Molecular From 5f8780614f881ce8b38946cdf1ef090365bfa86c Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 27 Sep 2019 14:28:16 -0400 Subject: [PATCH 16/48] borders. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 29 ++++++++-------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index 29ecc3c6..d0599043 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -8,7 +8,9 @@ import MVMCore - +/** + This class expects its height and width to be equal. + */ @objcMembers open class Checkbox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol { //-------------------------------------------------- // MARK: - Properties @@ -41,23 +43,8 @@ import MVMCore public var lineWidth: CGFloat = 2 public var lineColor: UIColor = .black - - open var borderColor: UIColor { - get { - guard let color = layer.borderColor else { return .black } - return UIColor(cgColor: color) - } - set (newColor) { - layer.borderColor = newColor.cgColor - } - } - - open var borderWidth: CGFloat { - get { return layer.borderWidth } - set (newWidth) { - layer.borderWidth = newWidth - } - } + public var borderColor: UIColor = .black + public var borderWidth: CGFloat = 1 override open var isSelected: Bool { didSet { @@ -141,15 +128,15 @@ import MVMCore super.layoutSubviews() drawCheck() layer.cornerRadius = hasRoundedCorners ? cornerRadiusValue : 0 - backgroundColor = unCheckedBackgroundColor ?? .white + backgroundColor = unCheckedBackgroundColor + layer.borderWidth = borderWidth + layer.borderColor = borderColor.cgColor } public func setupView() { isUserInteractionEnabled = true translatesAutoresizingMaskIntoConstraints = false - layer.borderWidth = 1 - layer.borderColor = UIColor.black.cgColor } //-------------------------------------------------- From 77a3eb882781d9814e1268d9f1ecce85152ee6d1 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 2 Oct 2019 15:22:12 -0400 Subject: [PATCH 17/48] Added a new extension file for CATransaction. Implementation of Checkbox and CheckboxWithLabel. --- MVMCoreUI.xcodeproj/project.pbxproj | 4 + MVMCoreUI/Atoms/Views/Checkbox.swift | 323 +++++++++--------- .../Atoms/Views/CheckboxWithLabelView.swift | 204 +++++++---- .../Utility/CATransaction+Extension.swift | 21 ++ 4 files changed, 321 insertions(+), 231 deletions(-) create mode 100644 MVMCoreUI/Utility/CATransaction+Extension.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 9692652c..253371bc 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -19,6 +19,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 */; }; 0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */; }; + 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; }; 948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948DB67D2326DCD90011F916 /* MultiProgress.swift */; }; B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; }; @@ -205,6 +206,7 @@ 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 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = ""; }; + 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.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 = ""; }; 948DB67D2326DCD90011F916 /* MultiProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiProgress.swift; sourceTree = ""; }; @@ -654,6 +656,7 @@ D29DF2A021E7AF4E003B2FB9 /* MVMCoreUIUtility.m */, D29DF2A721E7B2F9003B2FB9 /* MVMCoreUIConstants.h */, D29DF2A821E7B2F9003B2FB9 /* MVMCoreUIConstants.m */, + 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */, ); path = Utility; sourceTree = ""; @@ -1095,6 +1098,7 @@ D29DF25121E6A177003B2FB9 /* MFDigitTextBox.m in Sources */, DBC4391B224421A0001AB423 /* CaretButton.swift in Sources */, 0198F7A82256A80B0066C936 /* MFRadioButton.m in Sources */, + 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */, D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */, D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */, 0105618E224BBE7700E1557D /* FormValidator+TextFields.swift in Sources */, diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index d0599043..9fac4910 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -8,6 +8,22 @@ import MVMCore +/* + !!! -- DO NOT REMOVE -- !!! + (Unless Design changes the appearance of the checkmark). + + // Offsets based on the 124x124 example checkmark + let startXOffset: Float = 42.0 / 124.0 ~~ 0.33871 + let startYOffset: Float = 66.0 / 124.0 ~~ 0.53225 + let pivotXOffset: Float = 58.0 / 124.0 ~~ 0.46774 + let pivotYOffset: Float = 80.0 / 124.0 ~~ 0.64516 + let endXOffset: Float = 83.0 / 124.0 ~~ 0.66935 + let endYOffset: Float = 46.0 / 124.0 ~~ 0.37097 + let pivotPercentage: Float = 0.34 + let endPercentage = 1.0 - pivotPercentage + let animationInterval: Float = 0.01 + */ + /** This class expects its height and width to be equal. */ @@ -16,85 +32,82 @@ import MVMCore // MARK: - Properties //-------------------------------------------------- + // Form Validation + var isRequired = false + var fieldKey: String? + var delegateObject: DelegateObject? + public static let defaultHeightWidth: CGFloat = 18.0 - /// The color of the background when checked. - public var checkedBackgroundColor: UIColor? + /// If true the border of this checkbox will be circular. + public var isRound: Bool = false - /// The color of the background when unChecked. Will change of the view's background color. - public var unCheckedBackgroundColor: UIColor = .white { - didSet (newColor) { - backgroundColor = newColor + /// Determined if the checkbox's UI should animated when selected. + public var isAnimated: Bool = true + + /// Disables all selection logic when setting the value of isSelected, reducing it to a stored property. + public var updateSelectionOnly: Bool = false + + /// The color of the background when checked. + public var checkedBackgroundColor: UIColor = .white { + didSet { + if isSelected { + backgroundColor = checkedBackgroundColor + } } } - /// If true the border of this checkbox will be circular. - public var hasRoundedCorners = false - - // Action Block called when the switch is selected. - public var actionBlock: ActionBlock? - - // Internal values to manage the appearance of the checkbox. - private var shapeLayer: CAShapeLayer? + /// The color of the background when unChecked. + public var unCheckedBackgroundColor: UIColor = .white { + didSet { + if !isSelected { + backgroundColor = unCheckedBackgroundColor + } + } + } public var cornerRadiusValue: CGFloat { return bounds.size.height / 2 } - public var lineWidth: CGFloat = 2 - public var lineColor: UIColor = .black - public var borderColor: UIColor = .black + /// Action Block called when the switch is selected. + public var actionBlock: ActionBlock? + + /// Manages the appearance of the checkbox. + private var shapeLayer: CAShapeLayer? + + public var checkWidth: CGFloat = 2 + public var checkColor: UIColor = .black public var borderWidth: CGFloat = 1 + public var borderColor: UIColor = .black override open var isSelected: Bool { didSet { - shapeLayer?.removeAllAnimations() - if isSelected { - if checkedBackgroundColor != nil { - UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { - self.backgroundColor = self.checkedBackgroundColor - }) + if !updateSelectionOnly { + layoutIfNeeded() + shapeLayer?.removeAllAnimations() + + updateCheckboxUI(selection: isSelected, isAnimated: isAnimated) + + if let delegate = delegateObject as? FormValidationProtocol { + delegate.formValidatorModel?()?.enableByValidation() } - shapeLayer?.add(checkedAnimation, forKey: "strokeEnd") - } else { - if checkedBackgroundColor != nil { - UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { - self.backgroundColor = self.unCheckedBackgroundColor - }) - } - shapeLayer?.add(uncheckedAnimation, forKey: "strokeEnd") + + accessibilityLabel = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "checkbox_checked_state" : "checkbox_unchecked_state") } } } - lazy private var checkedAnimation: CABasicAnimation = { - let check = CABasicAnimation(keyPath: "strokeEnd") - check.timingFunction = CAMediaTimingFunction(name: .linear) - check.isRemovedOnCompletion = false - check.fillMode = .both - check.duration = 0.3 - check.fromValue = 0 - check.toValue = 1 - return check - }() - - lazy private var uncheckedAnimation: CABasicAnimation = { - let unCheck = CABasicAnimation(keyPath: "strokeEnd") - unCheck.timingFunction = CAMediaTimingFunction(name: .linear) - unCheck.isRemovedOnCompletion = false - unCheck.fillMode = .both - unCheck.duration = 0.3 - unCheck.fromValue = 1 - unCheck.toValue = 0 - return unCheck - }() - //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- override public init(frame: CGRect) { super.init(frame: frame) + + accessibilityTraits = .none + accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "checkbox_action_hint") + setupView() } @@ -108,16 +121,20 @@ import MVMCore self.init(frame:.zero) } - public convenience init(checkedColor: UIColor, unCheckedColor: UIColor, isChecked: Bool = false) { + public convenience init(isChecked: Bool) { self.init(frame: .zero) + updateSelectionOnly = true isSelected = isChecked - self.checkedBackgroundColor = checkedColor - self.unCheckedBackgroundColor = unCheckedColor + updateSelectionOnly = false } - public convenience init(isCircular: Bool) { + public convenience init(checkedBackgroundColor: UIColor, unCheckedBackgroundColor: UIColor, isChecked: Bool = false) { self.init(frame: .zero) - hasRoundedCorners = isCircular + updateSelectionOnly = true + isSelected = isChecked + updateSelectionOnly = false + self.checkedBackgroundColor = checkedBackgroundColor + self.unCheckedBackgroundColor = unCheckedBackgroundColor } //-------------------------------------------------- @@ -126,9 +143,9 @@ import MVMCore override open func layoutSubviews() { super.layoutSubviews() + drawCheck() - layer.cornerRadius = hasRoundedCorners ? cornerRadiusValue : 0 - backgroundColor = unCheckedBackgroundColor + layer.cornerRadius = isRound ? cornerRadiusValue : 0 layer.borderWidth = borderWidth layer.borderColor = borderColor.cgColor } @@ -137,6 +154,7 @@ import MVMCore isUserInteractionEnabled = true translatesAutoresizingMaskIntoConstraints = false + backgroundColor = .white } //-------------------------------------------------- @@ -161,6 +179,7 @@ import MVMCore // MARK: - Methods //-------------------------------------------------- + /// Creates the check mark used for the checkbox. private func drawCheck() { if shapeLayer == nil { @@ -169,36 +188,20 @@ import MVMCore self.shapeLayer = shapeLayer shapeLayer.frame = bounds layer.addSublayer(shapeLayer) - shapeLayer.strokeColor = lineColor.cgColor + shapeLayer.strokeColor = checkColor.cgColor shapeLayer.fillColor = UIColor.clear.cgColor - shapeLayer.path = checkMarkBezierPath.cgPath + shapeLayer.path = checkMarkPath.cgPath shapeLayer.lineJoin = .bevel - shapeLayer.lineWidth = lineWidth + shapeLayer.lineWidth = checkWidth CATransaction.withDisabledAnimations { - shapeLayer.strokeEnd = 0.0 + shapeLayer.strokeEnd = isSelected ? 1 : 0 } } } - /* - !!! -- DO NOT REMOVE -- !!! - (Unless Design changes the appearance of the checkmark). - - // Offsets based on the 124x124 example checkmark - let startXOffset: Float = 42.0 / 124.0 ~~ 0.33871 - let startYOffset: Float = 66.0 / 124.0 ~~ 0.53225 - let pivotXOffset: Float = 58.0 / 124.0 ~~ 0.46774 - let pivotYOffset: Float = 80.0 / 124.0 ~~ 0.64516 - let endXOffset: Float = 83.0 / 124.0 ~~ 0.66935 - let endYOffset: Float = 46.0 / 124.0 ~~ 0.37097 - let pivotPercentage: Float = 0.34 - let endPercentage = 1.0 - pivotPercentage - let animationInterval: Float = 0.01 - */ - /// Returns a UIBezierPath detailing the path of a checkmark - var checkMarkBezierPath: UIBezierPath { + var checkMarkPath: UIBezierPath { let sideLength = bounds.size.height let startPoint = CGPoint(x: 0.33871 * sideLength, y: 0.53225 * sideLength) @@ -213,38 +216,43 @@ import MVMCore return path } - public func updateSelection(_ selected: Bool, animated: Bool) { - - // shapeLayer?.removeFromSuperlayer() - // shapeLayer = nil + /// Programmatic means to check/uncheck the box. + /// - parameter selected: state of the check box: true = checked OR false = unchecked. + /// - parameter animated: allows the state of the checkbox to change with or without animation. + public func updateSelection(to selected: Bool, animated: Bool) { DispatchQueue.main.async { + self.updateSelectionOnly = true self.isSelected = selected + self.updateSelectionOnly = false self.drawCheck() + self.shapeLayer?.removeAllAnimations() + self.updateCheckboxUI(selection: selected, isAnimated: animated) + } + } + + func updateCheckboxUI(selection: Bool, isAnimated: Bool) { + + if isAnimated { + let animateStrokeEnd = CABasicAnimation(keyPath: "strokeEnd") + animateStrokeEnd.timingFunction = CAMediaTimingFunction(name: .linear) + animateStrokeEnd.duration = 0.3 + animateStrokeEnd.fillMode = .both + animateStrokeEnd.isRemovedOnCompletion = false + animateStrokeEnd.fromValue = !selection ? 1 : 0 + animateStrokeEnd.toValue = selection ? 1 : 0 + self.shapeLayer?.add(animateStrokeEnd, forKey: "strokeEnd") - var layer: CAShapeLayer? - if let presentation = self.shapeLayer?.presentation(), animated { - layer = presentation - } else { - layer = self.shapeLayer + UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { + self.backgroundColor = selection ? self.checkedBackgroundColor : self.unCheckedBackgroundColor + }) + } else { + CATransaction.withDisabledAnimations { + self.shapeLayer?.strokeEnd = selection ? 1 : 0 } - if animated { - let animateStrokeEnd = CABasicAnimation(keyPath: "strokeEnd") - animateStrokeEnd.timingFunction = CAMediaTimingFunction(name: .linear) - animateStrokeEnd.duration = 0.33 - animateStrokeEnd.fillMode = .both - animateStrokeEnd.isRemovedOnCompletion = false - animateStrokeEnd.fromValue = layer?.strokeEnd ?? 0 - animateStrokeEnd.toValue = selected ? 1 : 0 - layer?.add(animateStrokeEnd, forKey: "strokeEndAnimation") - } else { - layer?.removeAllAnimations() - CATransaction.withDisabledAnimations { - layer?.strokeEnd = selected ? 1 : 0 - } - } + self.backgroundColor = selection ? self.checkedBackgroundColor : self.unCheckedBackgroundColor } } @@ -254,11 +262,7 @@ import MVMCore open override func touchesEnded(_ touches: Set, with event: UIEvent?) { - if touchIsAcceptablyOutside(touches.first) { - sendActions(for: .touchUpOutside) - } else { - sendActions(for: .touchUpInside) - } + sendActions(for: touchIsAcceptablyOutside(touches.first) ? .touchUpOutside : .touchUpInside) } func touchIsAcceptablyOutside(_ touch: UITouch?) -> Bool { @@ -272,40 +276,6 @@ import MVMCore return x < -faultTolerance || y < -faultTolerance || x > widthLimit || y > heightLimt } - // if delegate && delegate.responds(to: #selector(formValidationProtocol)) && delegate.perform(#selector(formValidationProtocol)).responds(to: #selector(Unmanaged.formValidatorModel)) { - // let formValidator = delegate.perform(#selector(formValidationProtocol)).perform(#selector(Unmanaged.formValidatorModel)) as? FormValidator - // formValidator?.enableByValidation() - // } - - - /* - - - (void)setSelected:(BOOL)selected animated:(BOOL)animated runBlock:(BOOL)runBlock { - [self addAccessibilityLabel:selected]; - - self.isSelected = selected; - if (self.switchSelected && runBlock) { - self.switchSelected(selected); - } - if (selected) { - [UIView animateWithDuration:0.2 delay:0.1 options:UIViewAnimationOptionCurveEaseOut animations:^{ - self.checkedSquare.backgroundColor = self.checkedColor; - } completion:nil]; - [self.checkMark updateCheckSelected:YES animated:animated]; - } else { - [UIView animateWithDuration:0.2 delay:0.1 options:UIViewAnimationOptionCurveEaseOut animations:^{ - self.checkedSquare.backgroundColor = self.unCheckedColor; - } completion:nil]; - [self.checkMark updateCheckSelected:NO animated:animated]; - } - - if (self.delegate && [self.delegate respondsToSelector:@selector(formValidationProtocol)] && [[self.delegate performSelector:@selector(formValidationProtocol)] respondsToSelector:@selector(formValidatorModel)]) { - FormValidator *formValidator = [[self.delegate performSelector:@selector(formValidationProtocol)] performSelector:@selector(formValidatorModel)]; - [formValidator enableByValidation]; - } - } - */ - //-------------------------------------------------- // MARK: - Molecular //-------------------------------------------------- @@ -322,15 +292,22 @@ import MVMCore setupView() } - public func updateView(_ size: CGFloat) { - - // TODO: Ensure the check logic is resized. - } + public func updateView(_ size: CGFloat) { } public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + self.delegateObject = delegateObject + FormValidator.setupValidation(molecule: self, delegate: delegateObject?.formValidationProtocol) guard let dictionary = json else { return } + if let fieldKey = dictionary[KeyFieldKey] as? String { + self.fieldKey = fieldKey + } + + if let isRequired = dictionary[KeyRequired] as? Bool { + self.isRequired = isRequired + } + if let borderColorHex = dictionary["borderColor"] as? String { layer.borderColor = UIColor.mfGet(forHex: borderColorHex).cgColor } @@ -339,36 +316,50 @@ import MVMCore layer.borderWidth = borderWidth } - if let checkColorHex = dictionary["lineColor"] as? String { - lineColor = UIColor.mfGet(forHex: checkColorHex) + if let isChecked = dictionary["isChecked"] as? Bool, isChecked { + updateSelectionOnly = true + isSelected = isChecked + updateSelectionOnly = false } - if let checkColorHex = dictionary["checkedColor"] as? String { - checkedBackgroundColor = UIColor.mfGet(forHex: checkColorHex) + if let checkColorHex = dictionary["checkColor"] as? String { + checkColor = UIColor.mfGet(forHex: checkColorHex) } - if let unCheckedColorHex = dictionary["unCheckedColor"] as? String { - unCheckedBackgroundColor = UIColor.mfGet(forHex: unCheckedColorHex) + if let unCheckedBackgroundColorHex = dictionary["unCheckedBackgroundColor"] as? String { + unCheckedBackgroundColor = UIColor.mfGet(forHex: unCheckedBackgroundColorHex) + } + + if let checkedBackgroundColorHex = dictionary["checkedBackgroundColor"] as? String { + checkedBackgroundColor = UIColor.mfGet(forHex: checkedBackgroundColorHex) + } + + if let isAnimated = dictionary["isAnimated"] as? Bool { + self.isAnimated = isAnimated } if let isRound = dictionary["isRound"] as? Bool { - hasRoundedCorners = isRound + self.isRound = isRound } - // if let actionMap = dictionary.optionalDictionaryForKey("actionMap") { - // actionBlock = { MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) } - // } + if let actionMap = dictionary.optionalDictionaryForKey("actionMap") { + actionBlock = { MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) } + } } } -// TODO: Move to its own extension file. -extension CATransaction { +// MARK:- FormValidationProtocol +extension Checkbox: FormValidationProtocol { - /// Performs changes without activating animation actions. - static func withDisabledAnimations(_ actionBlock: ActionBlock) { - CATransaction.begin() - CATransaction.setDisableActions(true) - actionBlock() - CATransaction.commit() + public func isValidField() -> Bool { + return isRequired ? isSelected : true + } + + public func formFieldName() -> String? { + return fieldKey + } + + public func formFieldValue() -> Any? { + return NSNumber(value: isSelected) } } diff --git a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift index db551800..bf0288ae 100644 --- a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift +++ b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift @@ -12,8 +12,8 @@ // MARK: - Outlets //-------------------------------------------------- - let checkbox = Checkbox() - let label = Label.commonLabelB2(true) + public let checkbox = Checkbox() + public let label = Label.commonLabelB2(true) //-------------------------------------------------- // MARK: - Properties @@ -21,17 +21,34 @@ var sizeObject: MFSizeObject? = MFSizeObject(standardSize: Checkbox.defaultHeightWidth, standardiPadPortraitSize: Checkbox.defaultHeightWidth + 6.0) - var isRequired = false - var fieldKey: String? - var delegate: DelegateObject? + var checkboxPosition: CheckboxPosition = .centerLeft + + public enum CheckboxPosition: String { + case centerLeft + case topLeft + case bottomLeft + } //-------------------------------------------------- // MARK: - Constraints //-------------------------------------------------- - + var checkboxWidthConstraint: NSLayoutConstraint? var checkboxHeightConstraint: NSLayoutConstraint? + var checkboxLeadingConstraint: NSLayoutConstraint? + var checkboxTrailingConstraint: NSLayoutConstraint? + var checkboxTopConstraint: NSLayoutConstraint? + var checkboxBottomConstraint: NSLayoutConstraint? + var checkboxCenterYConstraint: NSLayoutConstraint? + + var checkboxLabelConstraint: NSLayoutConstraint? + + var labelLeadingConstraint: NSLayoutConstraint? + var labelTrailingConstraint: NSLayoutConstraint? + var labelTopConstraint: NSLayoutConstraint? + var labelBottomConstraint: NSLayoutConstraint? + //-------------------------------------------------- // MARK: - Life Cycle //-------------------------------------------------- @@ -46,23 +63,24 @@ addSubview(checkbox) addSubview(label) + label.setContentCompressionResistancePriority(.required, for: .vertical) + let dimension = sizeObject?.getValueBasedOnApplicationWidth() ?? Checkbox.defaultHeightWidth checkboxWidthConstraint = checkbox.heightAnchor.constraint(equalToConstant: dimension) checkboxWidthConstraint?.isActive = true checkboxHeightConstraint = checkbox.widthAnchor.constraint(equalToConstant: dimension) checkboxHeightConstraint?.isActive = true - checkbox.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor).isActive = true - layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: checkbox.bottomAnchor).isActive = true - checkbox.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true - checkbox.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true - checkbox.checkedBackgroundColor = .yellow + alignSubviews(by: .centerLeft) - label.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor).isActive = true - layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: label.bottomAnchor).isActive = true - label.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true - layoutMarginsGuide.trailingAnchor.constraint(equalTo: label.trailingAnchor).isActive = true - label.leadingAnchor.constraint(equalTo: checkbox.trailingAnchor, constant: PaddingTwo).isActive = true + label.isUserInteractionEnabled = true + let tap = UITapGestureRecognizer(target: self, action: #selector(tapped)) + tap.numberOfTapsRequired = 1 + label.addGestureRecognizer(tap) + } + + @objc func tapped() { + checkbox.updateSelection(to: !checkbox.isSelected, animated: true) } //-------------------------------------------------- @@ -77,13 +95,18 @@ override public init(frame: CGRect) { super.init(frame: frame) setupView() -// addAccessibleProperties() } public convenience init() { self.init(frame: .zero) } + public convenience init(position: CheckboxPosition) { + self.init(frame: .zero) + + alignSubviews(by: position) + } + public convenience init(checkedColor: UIColor, unCheckedColor: UIColor, text: String?, isChecked: Bool = false) { self.init(frame: .zero) @@ -99,79 +122,130 @@ checkbox.unCheckedBackgroundColor = unCheckedColor label.attributedText = attributedText } + + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + + /// Aligns Checkbox and Label relative to the desired position of the Checkbox. + private func alignSubviews(by position: CheckboxPosition) { + checkboxPosition = position + + label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true + + switch position { + case .centerLeft: + checkboxTopConstraint = checkbox.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor) + checkboxBottomConstraint = layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: checkbox.bottomAnchor) + checkboxLeadingConstraint = checkbox.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor) + checkboxCenterYConstraint = checkbox.centerYAnchor.constraint(equalTo: centerYAnchor) + + labelTopConstraint = label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor) + labelTrailingConstraint = layoutMarginsGuide.trailingAnchor.constraint(equalTo: label.trailingAnchor) + checkboxLabelConstraint = label.leadingAnchor.constraint(equalTo: checkbox.trailingAnchor, constant: PaddingTwo) + + case .topLeft: + checkboxTopConstraint = checkbox.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor) + checkboxBottomConstraint = layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: checkbox.bottomAnchor) + checkboxLeadingConstraint = checkbox.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor) + + labelTopConstraint = label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor) + labelTrailingConstraint = layoutMarginsGuide.trailingAnchor.constraint(equalTo: label.trailingAnchor) + checkboxLabelConstraint = label.leadingAnchor.constraint(equalTo: checkbox.trailingAnchor, constant: PaddingTwo) + + case .bottomLeft: + checkboxTopConstraint = checkbox.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor) + checkboxBottomConstraint = layoutMarginsGuide.bottomAnchor.constraint(equalTo: checkbox.bottomAnchor) + checkboxLeadingConstraint = checkbox.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor) + + labelTopConstraint = label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor) + labelTrailingConstraint = layoutMarginsGuide.trailingAnchor.constraint(equalTo: label.trailingAnchor) + checkboxLabelConstraint = label.leadingAnchor.constraint(equalTo: checkbox.trailingAnchor, constant: PaddingTwo) + labelBottomConstraint = layoutMarginsGuide.bottomAnchor.constraint(equalTo: label.bottomAnchor) + } + + if position != .bottomLeft { + layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: label.bottomAnchor).isActive = true + let labelBottom = label.bottomAnchor.constraint(equalTo: bottomAnchor) + labelBottomConstraint = labelBottom + labelBottom.priority = UILayoutPriority(249) + labelBottom.isActive = true + } + + toggleSubviewConstraints(isActive: true) + } + + func toggleSubviewConstraints(isActive state: Bool) { + + checkboxLeadingConstraint?.isActive = state + checkboxTrailingConstraint?.isActive = state + checkboxTopConstraint?.isActive = state + checkboxBottomConstraint?.isActive = state + checkboxCenterYConstraint?.isActive = state + labelLeadingConstraint?.isActive = state + labelTrailingConstraint?.isActive = state + labelTopConstraint?.isActive = state + labelBottomConstraint?.isActive = state + checkboxLabelConstraint?.isActive = state + + if !state { + checkboxLeadingConstraint = nil + checkboxTrailingConstraint = nil + checkboxTopConstraint = nil + checkboxBottomConstraint = nil + checkboxCenterYConstraint = nil + labelLeadingConstraint = nil + labelTrailingConstraint = nil + labelTopConstraint = nil + labelBottomConstraint = nil + checkboxLabelConstraint = nil + } + } } -// MARK: - Molecular +/// MARK: - Molecular extension CheckboxWithLabelView { - override open class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + override open class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return CGFloat(Checkbox.defaultHeightWidth) } @objc override open func updateView(_ size: CGFloat) { - DispatchQueue.main.async { - self.label.updateView(size) - if self.checkbox.responds(to: #selector(self.updateView(_:))) { - if let dimension = self.sizeObject?.getValueBased(onSize: size) { - self.checkboxWidthConstraint?.constant = dimension - self.checkboxHeightConstraint?.constant = dimension - self.checkbox.updateView(size) - } + label.updateView(size) + + if self.checkbox.responds(to: #selector(self.updateView(_:))) { + if let dimension = sizeObject?.getValueBased(onSize: size) { + checkboxWidthConstraint?.constant = dimension + checkboxHeightConstraint?.constant = dimension + checkbox.updateView(size) } } + + layoutIfNeeded() } override open func alignment() -> UIStackView.Alignment { return .leading } + open override func resetConstraints() { + super.resetConstraints() + + toggleSubviewConstraints(isActive: false) + } + override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - delegate = delegateObject - FormValidator.setupValidation(molecule: self, delegate: delegateObject?.formValidationProtocol) guard let dictionary = json else { return } - if let fieldKey = dictionary[KeyFieldKey] as? String { - self.fieldKey = fieldKey - } - - if let isRequired = dictionary[KeyRequired] as? Bool { - self.isRequired = isRequired + if let checkboxAlignment = dictionary["checkboxAlignment"] as? String, let position = CheckboxPosition(rawValue: checkboxAlignment) { + toggleSubviewConstraints(isActive: false) + alignSubviews(by: position) } checkbox.setWithJSON(dictionary.dictionaryForKey("checkbox"), delegateObject: delegateObject, additionalData: additionalData) label.setWithJSON(dictionary.dictionaryForKey("label"), delegateObject: delegateObject, additionalData: additionalData) } } - -// MARK:- FormValidationProtocol -extension CheckboxWithLabelView: FormValidationProtocol { - - public func isValidField() -> Bool { - return isRequired ? checkbox.isSelected : true - } - - public func formFieldName() -> String? { - return fieldKey - } - - public func formFieldValue() -> Any? { - return NSNumber(value: checkbox.isSelected) - } -} - -// MARK:- Accessibility -extension CheckboxWithLabelView { - - func addAccessibleProperties() { -// accessibilityTraits = .none -// accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "checkbox_action_hint") - } - - func addAccessibilityLabel(_ selected: Bool) { -// let state = selected ? MVMCoreUIUtility.hardcodedString(withKey: "checkbox_checked_state") : MVMCoreUIUtility.hardcodedString(withKey: "checkbox_unchecked_state") -// accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "checkbox_desc_state"), label.text ?? "", state) - } -} diff --git a/MVMCoreUI/Utility/CATransaction+Extension.swift b/MVMCoreUI/Utility/CATransaction+Extension.swift new file mode 100644 index 00000000..66bb33d3 --- /dev/null +++ b/MVMCoreUI/Utility/CATransaction+Extension.swift @@ -0,0 +1,21 @@ +// +// CATransaction+Extension.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 10/2/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + + +extension CATransaction { + + /// Performs changes without activating animation actions. + static func withDisabledAnimations(_ actionBlock: ActionBlock) { + CATransaction.begin() + CATransaction.setDisableActions(true) + actionBlock() + CATransaction.commit() + } +} From 61fcd981c1312d2c27de069210b4a43ba092ccb1 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 2 Oct 2019 15:27:32 -0400 Subject: [PATCH 18/48] setting up the rest. --- .../Atoms/Views/CheckboxWithLabelView.swift | 27 ++----------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift index bf0288ae..40b91f87 100644 --- a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift +++ b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift @@ -72,15 +72,6 @@ checkboxHeightConstraint?.isActive = true alignSubviews(by: .centerLeft) - - label.isUserInteractionEnabled = true - let tap = UITapGestureRecognizer(target: self, action: #selector(tapped)) - tap.numberOfTapsRequired = 1 - label.addGestureRecognizer(tap) - } - - @objc func tapped() { - checkbox.updateSelection(to: !checkbox.isSelected, animated: true) } //-------------------------------------------------- @@ -104,25 +95,10 @@ public convenience init(position: CheckboxPosition) { self.init(frame: .zero) + toggleSubviewConstraints(isActive: false) alignSubviews(by: position) } - public convenience init(checkedColor: UIColor, unCheckedColor: UIColor, text: String?, isChecked: Bool = false) { - self.init(frame: .zero) - - checkbox.checkedBackgroundColor = checkedColor - checkbox.unCheckedBackgroundColor = unCheckedColor - label.text = text - } - - public convenience init(checkedColor: UIColor, unCheck unCheckedColor: UIColor, attributedText: NSAttributedString, isChecked: Bool = false) { - self.init(frame: .zero) - - checkbox.checkedBackgroundColor = checkedColor - checkbox.unCheckedBackgroundColor = unCheckedColor - label.attributedText = attributedText - } - //-------------------------------------------------- // MARK: - Methods //-------------------------------------------------- @@ -211,6 +187,7 @@ extension CheckboxWithLabelView { } @objc override open func updateView(_ size: CGFloat) { + super.updateView(size) label.updateView(size) From 5d1c87819d23d89a7df4aa88404cf014e56b4c1a Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 3 Oct 2019 11:14:16 -0400 Subject: [PATCH 19/48] making changes to align with comments. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 31 ++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index 9fac4910..fd1fa48a 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -76,8 +76,21 @@ import MVMCore /// Manages the appearance of the checkbox. private var shapeLayer: CAShapeLayer? - public var checkWidth: CGFloat = 2 - public var checkColor: UIColor = .black + public var checkWidth: CGFloat = 2 { + didSet { + CATransaction.withDisabledAnimations { + shapeLayer?.lineWidth = checkWidth + } + } + } + public var checkColor: UIColor = .black { + didSet { + CATransaction.withDisabledAnimations { + shapeLayer?.strokeColor = checkColor.cgColor + } + } + } + public var borderWidth: CGFloat = 1 public var borderColor: UIColor = .black @@ -93,7 +106,9 @@ import MVMCore delegate.formValidatorModel?()?.enableByValidation() } - accessibilityLabel = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "checkbox_checked_state" : "checkbox_unchecked_state") + if let state = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "checkbox_checked_state" : "checkbox_unchecked_state") { + accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "checkbox_desc_state") ?? "%@", state) + } } } } @@ -105,8 +120,11 @@ import MVMCore override public init(frame: CGRect) { super.init(frame: frame) - accessibilityTraits = .none + accessibilityTraits = .button accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "checkbox_action_hint") + if let state = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "checkbox_checked_state" : "checkbox_unchecked_state") { + accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "checkbox_desc_state") ?? "%@", state) + } setupView() } @@ -276,6 +294,11 @@ import MVMCore return x < -faultTolerance || y < -faultTolerance || x > widthLimit || y > heightLimt } + override open func accessibilityActivate() -> Bool { + sendActions(for: .touchUpInside) + return true + } + //-------------------------------------------------- // MARK: - Molecular //-------------------------------------------------- From 44e420218db627b5de1e6eab3311b4a47624fdba Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 3 Oct 2019 13:22:15 -0400 Subject: [PATCH 20/48] Constraints mended. more commenting. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 79 ++++++++---- .../Atoms/Views/CheckboxWithLabelView.swift | 121 ++++++------------ 2 files changed, 90 insertions(+), 110 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index fd1fa48a..77a1f342 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -66,6 +66,7 @@ import MVMCore } } + /// Retrieves ideeal radius value to curve square into a circle. public var cornerRadiusValue: CGFloat { return bounds.size.height / 2 } @@ -76,6 +77,7 @@ import MVMCore /// Manages the appearance of the checkbox. private var shapeLayer: CAShapeLayer? + /// Width of the check mark. public var checkWidth: CGFloat = 2 { didSet { CATransaction.withDisabledAnimations { @@ -83,6 +85,8 @@ import MVMCore } } } + + /// Color of the check mark. public var checkColor: UIColor = .black { didSet { CATransaction.withDisabledAnimations { @@ -91,24 +95,35 @@ import MVMCore } } - public var borderWidth: CGFloat = 1 - public var borderColor: UIColor = .black + /// Border width of the checkbox + public var borderWidth: CGFloat = 1 { + didSet { + layer.borderWidth = borderWidth + } + } + /// border color of the Checkbox + public var borderColor: UIColor = .black { + didSet { + layer.borderColor = borderColor.cgColor + } + } + + /// The represented state of the Checkbox. + /// If updateSelectionOnly = true, then this will behave only as a stored property. override open var isSelected: Bool { didSet { if !updateSelectionOnly { layoutIfNeeded() shapeLayer?.removeAllAnimations() - updateCheckboxUI(selection: isSelected, isAnimated: isAnimated) + updateCheckboxUI(isSelected: isSelected, isAnimated: isAnimated) if let delegate = delegateObject as? FormValidationProtocol { delegate.formValidatorModel?()?.enableByValidation() } - if let state = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "checkbox_checked_state" : "checkbox_unchecked_state") { - accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "checkbox_desc_state") ?? "%@", state) - } + updateAccessibilityLabel() } } } @@ -122,9 +137,7 @@ import MVMCore accessibilityTraits = .button accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "checkbox_action_hint") - if let state = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "checkbox_checked_state" : "checkbox_unchecked_state") { - accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "checkbox_desc_state") ?? "%@", state) - } + updateAccessibilityLabel() setupView() } @@ -181,13 +194,16 @@ import MVMCore open override func sendAction(_ action: Selector, to target: Any?, for event: UIEvent?) { super.sendAction(action, to: target, for: event) - - isSelected.toggle() - actionBlock?() + toggleAndAction() } open override func sendActions(for controlEvents: UIControl.Event) { super.sendActions(for: controlEvents) + toggleAndAction() + } + + /// This will toggle the state of the Checkbox and execute the actionBlock if provided. + public func toggleAndAction() { isSelected.toggle() actionBlock?() @@ -208,7 +224,7 @@ import MVMCore layer.addSublayer(shapeLayer) shapeLayer.strokeColor = checkColor.cgColor shapeLayer.fillColor = UIColor.clear.cgColor - shapeLayer.path = checkMarkPath.cgPath + shapeLayer.path = checkMarkPath() shapeLayer.lineJoin = .bevel shapeLayer.lineWidth = checkWidth @@ -219,19 +235,19 @@ import MVMCore } /// Returns a UIBezierPath detailing the path of a checkmark - var checkMarkPath: UIBezierPath { + func checkMarkPath() -> CGPath { let sideLength = bounds.size.height let startPoint = CGPoint(x: 0.33871 * sideLength, y: 0.53225 * sideLength) let pivotOffSet = CGPoint(x: 0.46774 * sideLength, y: 0.64516 * sideLength) let endOffset = CGPoint(x: 0.66935 * sideLength , y: 0.37097 * sideLength) - let path = UIBezierPath() - path.move(to: startPoint) - path.addLine(to: pivotOffSet) - path.addLine(to: endOffset) + let bezierPath = UIBezierPath() + bezierPath.move(to: startPoint) + bezierPath.addLine(to: pivotOffSet) + bezierPath.addLine(to: endOffset) - return path + return bezierPath.cgPath } /// Programmatic means to check/uncheck the box. @@ -246,11 +262,14 @@ import MVMCore self.updateSelectionOnly = false self.drawCheck() self.shapeLayer?.removeAllAnimations() - self.updateCheckboxUI(selection: selected, isAnimated: animated) + self.updateCheckboxUI(isSelected: selected, isAnimated: animated) } } - func updateCheckboxUI(selection: Bool, isAnimated: Bool) { + /// updates the visuals of the check mark and background. + /// - parameter isSelection: the check state of the checkbox. + /// - parameter isAnimated: determines of the changes should animate or immediately refelect. + public func updateCheckboxUI(isSelected: Bool, isAnimated: Bool) { if isAnimated { let animateStrokeEnd = CABasicAnimation(keyPath: "strokeEnd") @@ -258,19 +277,27 @@ import MVMCore animateStrokeEnd.duration = 0.3 animateStrokeEnd.fillMode = .both animateStrokeEnd.isRemovedOnCompletion = false - animateStrokeEnd.fromValue = !selection ? 1 : 0 - animateStrokeEnd.toValue = selection ? 1 : 0 + animateStrokeEnd.fromValue = !isSelected ? 1 : 0 + animateStrokeEnd.toValue = isSelected ? 1 : 0 self.shapeLayer?.add(animateStrokeEnd, forKey: "strokeEnd") UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { - self.backgroundColor = selection ? self.checkedBackgroundColor : self.unCheckedBackgroundColor + self.backgroundColor = isSelected ? self.checkedBackgroundColor : self.unCheckedBackgroundColor }) } else { CATransaction.withDisabledAnimations { - self.shapeLayer?.strokeEnd = selection ? 1 : 0 + self.shapeLayer?.strokeEnd = isSelected ? 1 : 0 } - self.backgroundColor = selection ? self.checkedBackgroundColor : self.unCheckedBackgroundColor + self.backgroundColor = isSelected ? self.checkedBackgroundColor : self.unCheckedBackgroundColor + } + } + + /// Adjust accessibility label based on state of Checkbox. + func updateAccessibilityLabel() { + // Attention: This needs to be addressed with the accessibility team. + if let state = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "checkbox_checked_state" : "checkbox_unchecked_state") { + accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "checkbox_desc_state") ?? "%@", state) } } diff --git a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift index 40b91f87..e9aa0d0e 100644 --- a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift +++ b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift @@ -21,12 +21,12 @@ var sizeObject: MFSizeObject? = MFSizeObject(standardSize: Checkbox.defaultHeightWidth, standardiPadPortraitSize: Checkbox.defaultHeightWidth + 6.0) - var checkboxPosition: CheckboxPosition = .centerLeft + var checkboxPosition: CheckboxPosition = .center public enum CheckboxPosition: String { - case centerLeft - case topLeft - case bottomLeft + case center + case top + case bottom } //-------------------------------------------------- @@ -35,20 +35,10 @@ var checkboxWidthConstraint: NSLayoutConstraint? var checkboxHeightConstraint: NSLayoutConstraint? - - var checkboxLeadingConstraint: NSLayoutConstraint? - var checkboxTrailingConstraint: NSLayoutConstraint? var checkboxTopConstraint: NSLayoutConstraint? var checkboxBottomConstraint: NSLayoutConstraint? var checkboxCenterYConstraint: NSLayoutConstraint? - var checkboxLabelConstraint: NSLayoutConstraint? - - var labelLeadingConstraint: NSLayoutConstraint? - var labelTrailingConstraint: NSLayoutConstraint? - var labelTopConstraint: NSLayoutConstraint? - var labelBottomConstraint: NSLayoutConstraint? - //-------------------------------------------------- // MARK: - Life Cycle //-------------------------------------------------- @@ -71,7 +61,27 @@ checkboxHeightConstraint = checkbox.widthAnchor.constraint(equalToConstant: dimension) checkboxHeightConstraint?.isActive = true - alignSubviews(by: .centerLeft) + checkbox.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true + + let generalTop = checkbox.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor) + generalTop.priority = UILayoutPriority(rawValue: 750) + generalTop.isActive = true + + let generalBottom = checkbox.bottomAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.bottomAnchor) + generalBottom.priority = UILayoutPriority(rawValue: 750) + generalBottom.isActive = true + + // Allows various positions of checkbox. + checkboxBottomConstraint = layoutMarginsGuide.bottomAnchor.constraint(equalTo: checkbox.bottomAnchor) + checkboxTopConstraint = checkbox.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor) + checkboxCenterYConstraint = checkbox.centerYAnchor.constraint(equalTo: centerYAnchor) + + label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true + layoutMarginsGuide.trailingAnchor.constraint(equalTo: label.trailingAnchor).isActive = true + label.leadingAnchor.constraint(equalTo: checkbox.trailingAnchor, constant: PaddingTwo).isActive = true + layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: label.bottomAnchor).isActive = true + + alignSubviews(by: .center) } //-------------------------------------------------- @@ -95,7 +105,6 @@ public convenience init(position: CheckboxPosition) { self.init(frame: .zero) - toggleSubviewConstraints(isActive: false) alignSubviews(by: position) } @@ -107,74 +116,21 @@ private func alignSubviews(by position: CheckboxPosition) { checkboxPosition = position - label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true - switch position { - case .centerLeft: - checkboxTopConstraint = checkbox.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor) - checkboxBottomConstraint = layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: checkbox.bottomAnchor) - checkboxLeadingConstraint = checkbox.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor) - checkboxCenterYConstraint = checkbox.centerYAnchor.constraint(equalTo: centerYAnchor) + case .center: + checkboxCenterYConstraint?.isActive = true + checkboxBottomConstraint?.isActive = false + checkboxTopConstraint?.isActive = false - labelTopConstraint = label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor) - labelTrailingConstraint = layoutMarginsGuide.trailingAnchor.constraint(equalTo: label.trailingAnchor) - checkboxLabelConstraint = label.leadingAnchor.constraint(equalTo: checkbox.trailingAnchor, constant: PaddingTwo) + case .top: + checkboxBottomConstraint?.isActive = false + checkboxTopConstraint?.isActive = true + checkboxCenterYConstraint?.isActive = false - case .topLeft: - checkboxTopConstraint = checkbox.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor) - checkboxBottomConstraint = layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: checkbox.bottomAnchor) - checkboxLeadingConstraint = checkbox.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor) - - labelTopConstraint = label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor) - labelTrailingConstraint = layoutMarginsGuide.trailingAnchor.constraint(equalTo: label.trailingAnchor) - checkboxLabelConstraint = label.leadingAnchor.constraint(equalTo: checkbox.trailingAnchor, constant: PaddingTwo) - - case .bottomLeft: - checkboxTopConstraint = checkbox.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor) - checkboxBottomConstraint = layoutMarginsGuide.bottomAnchor.constraint(equalTo: checkbox.bottomAnchor) - checkboxLeadingConstraint = checkbox.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor) - - labelTopConstraint = label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor) - labelTrailingConstraint = layoutMarginsGuide.trailingAnchor.constraint(equalTo: label.trailingAnchor) - checkboxLabelConstraint = label.leadingAnchor.constraint(equalTo: checkbox.trailingAnchor, constant: PaddingTwo) - labelBottomConstraint = layoutMarginsGuide.bottomAnchor.constraint(equalTo: label.bottomAnchor) - } - - if position != .bottomLeft { - layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: label.bottomAnchor).isActive = true - let labelBottom = label.bottomAnchor.constraint(equalTo: bottomAnchor) - labelBottomConstraint = labelBottom - labelBottom.priority = UILayoutPriority(249) - labelBottom.isActive = true - } - - toggleSubviewConstraints(isActive: true) - } - - func toggleSubviewConstraints(isActive state: Bool) { - - checkboxLeadingConstraint?.isActive = state - checkboxTrailingConstraint?.isActive = state - checkboxTopConstraint?.isActive = state - checkboxBottomConstraint?.isActive = state - checkboxCenterYConstraint?.isActive = state - labelLeadingConstraint?.isActive = state - labelTrailingConstraint?.isActive = state - labelTopConstraint?.isActive = state - labelBottomConstraint?.isActive = state - checkboxLabelConstraint?.isActive = state - - if !state { - checkboxLeadingConstraint = nil - checkboxTrailingConstraint = nil - checkboxTopConstraint = nil - checkboxBottomConstraint = nil - checkboxCenterYConstraint = nil - labelLeadingConstraint = nil - labelTrailingConstraint = nil - labelTopConstraint = nil - labelBottomConstraint = nil - checkboxLabelConstraint = nil + case .bottom: + checkboxBottomConstraint?.isActive = true + checkboxTopConstraint?.isActive = false + checkboxCenterYConstraint?.isActive = false } } } @@ -208,8 +164,6 @@ extension CheckboxWithLabelView { open override func resetConstraints() { super.resetConstraints() - - toggleSubviewConstraints(isActive: false) } override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { @@ -218,7 +172,6 @@ extension CheckboxWithLabelView { guard let dictionary = json else { return } if let checkboxAlignment = dictionary["checkboxAlignment"] as? String, let position = CheckboxPosition(rawValue: checkboxAlignment) { - toggleSubviewConstraints(isActive: false) alignSubviews(by: position) } From 5043964c290074d31cc47c9043a8e36510358e3e Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 3 Oct 2019 16:43:58 -0400 Subject: [PATCH 21/48] revised alignment for case when no label. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 5 ++- .../Atoms/Views/CheckboxWithLabelView.swift | 35 ++++++++++++++----- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index 77a1f342..bf8407be 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -335,7 +335,10 @@ import MVMCore } open func reset() { - setupView() + + backgroundColor = nil + shapeLayer = nil + isSelected = false } open func setAsMolecule() { diff --git a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift index e9aa0d0e..55339e61 100644 --- a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift +++ b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift @@ -53,7 +53,7 @@ addSubview(checkbox) addSubview(label) - label.setContentCompressionResistancePriority(.required, for: .vertical) + label.text = "" let dimension = sizeObject?.getValueBasedOnApplicationWidth() ?? Checkbox.defaultHeightWidth checkboxWidthConstraint = checkbox.heightAnchor.constraint(equalToConstant: dimension) @@ -64,13 +64,17 @@ checkbox.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true let generalTop = checkbox.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor) - generalTop.priority = UILayoutPriority(rawValue: 750) + generalTop.priority = UILayoutPriority(800) generalTop.isActive = true let generalBottom = checkbox.bottomAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.bottomAnchor) - generalBottom.priority = UILayoutPriority(rawValue: 750) + generalBottom.priority = UILayoutPriority(800) generalBottom.isActive = true + let checboxBottom = checkbox.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor) + checboxBottom.priority = UILayoutPriority(249) + checboxBottom.isActive = true + // Allows various positions of checkbox. checkboxBottomConstraint = layoutMarginsGuide.bottomAnchor.constraint(equalTo: checkbox.bottomAnchor) checkboxTopConstraint = checkbox.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor) @@ -79,9 +83,17 @@ label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true layoutMarginsGuide.trailingAnchor.constraint(equalTo: label.trailingAnchor).isActive = true label.leadingAnchor.constraint(equalTo: checkbox.trailingAnchor, constant: PaddingTwo).isActive = true - layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: label.bottomAnchor).isActive = true - alignSubviews(by: .center) + let bottomLabelConstraint = layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: label.bottomAnchor) + bottomLabelConstraint.priority = UILayoutPriority(500) + bottomLabelConstraint.isActive = true + + // layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: label.bottomAnchor).isActive = true + // let labelBottom = label.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor) + // labelBottom.priority = UILayoutPriority(249) + // labelBottom.isActive = true + + alignCheckbox(.center) } //-------------------------------------------------- @@ -105,7 +117,7 @@ public convenience init(position: CheckboxPosition) { self.init(frame: .zero) - alignSubviews(by: position) + alignCheckbox(position) } //-------------------------------------------------- @@ -113,7 +125,7 @@ //-------------------------------------------------- /// Aligns Checkbox and Label relative to the desired position of the Checkbox. - private func alignSubviews(by position: CheckboxPosition) { + private func alignCheckbox(_ position: CheckboxPosition) { checkboxPosition = position switch position { @@ -166,13 +178,20 @@ extension CheckboxWithLabelView { super.resetConstraints() } + open override func reset() { + super.reset() + + label.text = "" + checkbox.reset() + } + override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) guard let dictionary = json else { return } if let checkboxAlignment = dictionary["checkboxAlignment"] as? String, let position = CheckboxPosition(rawValue: checkboxAlignment) { - alignSubviews(by: position) + alignCheckbox(position) } checkbox.setWithJSON(dictionary.dictionaryForKey("checkbox"), delegateObject: delegateObject, additionalData: additionalData) From 1f815fa102f03e335e232834b776e2b7bc6f441f Mon Sep 17 00:00:00 2001 From: "Suresh, Kamlesh" Date: Mon, 7 Oct 2019 12:05:56 -0400 Subject: [PATCH 22/48] remove armv7 --- MVMCoreUI.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 253371bc..a4a3e406 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -1283,6 +1283,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; + VALID_ARCHS = "arm64 arm64e"; }; name = Debug; }; @@ -1312,6 +1313,7 @@ SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; + VALID_ARCHS = "arm64 arm64e"; }; name = Release; }; From 7d6289463d796eab35a8dd4cd606061f552deea9 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 7 Oct 2019 16:30:14 -0400 Subject: [PATCH 23/48] Improved molecular logic of checkbox. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 40 ++++++++++++++----- .../Atoms/Views/CheckboxWithLabelView.swift | 32 +++++++-------- .../MVMCoreUIMoleculeMappingObject.m | 2 +- 3 files changed, 46 insertions(+), 28 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index bf8407be..6253b30d 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -80,8 +80,10 @@ import MVMCore /// Width of the check mark. public var checkWidth: CGFloat = 2 { didSet { - CATransaction.withDisabledAnimations { - shapeLayer?.lineWidth = checkWidth + if shapeLayer != nil { + CATransaction.withDisabledAnimations { + shapeLayer?.lineWidth = checkWidth + } } } } @@ -89,8 +91,10 @@ import MVMCore /// Color of the check mark. public var checkColor: UIColor = .black { didSet { - CATransaction.withDisabledAnimations { - shapeLayer?.strokeColor = checkColor.cgColor + if shapeLayer != nil { + CATransaction.withDisabledAnimations { + shapeLayer?.strokeColor = checkColor.cgColor + } } } } @@ -109,8 +113,11 @@ import MVMCore } } - /// The represented state of the Checkbox. - /// If updateSelectionOnly = true, then this will behave only as a stored property. + /** + The represented state of the Checkbox. + + Setting updateSelectionOnly to true bypasses the animation logic inherent with setting this property. + */ override open var isSelected: Bool { didSet { if !updateSelectionOnly { @@ -181,7 +188,7 @@ import MVMCore layer.borderColor = borderColor.cgColor } - public func setupView() { + open func setupView() { isUserInteractionEnabled = true translatesAutoresizingMaskIntoConstraints = false @@ -225,7 +232,7 @@ import MVMCore shapeLayer.strokeColor = checkColor.cgColor shapeLayer.fillColor = UIColor.clear.cgColor shapeLayer.path = checkMarkPath() - shapeLayer.lineJoin = .bevel + shapeLayer.lineJoin = .miter shapeLayer.lineWidth = checkWidth CATransaction.withDisabledAnimations { @@ -237,7 +244,7 @@ import MVMCore /// Returns a UIBezierPath detailing the path of a checkmark func checkMarkPath() -> CGPath { - let sideLength = bounds.size.height + let sideLength = max(bounds.size.height, bounds.size.width) let startPoint = CGPoint(x: 0.33871 * sideLength, y: 0.53225 * sideLength) let pivotOffSet = CGPoint(x: 0.46774 * sideLength, y: 0.64516 * sideLength) let endOffset = CGPoint(x: 0.66935 * sideLength , y: 0.37097 * sideLength) @@ -336,16 +343,27 @@ import MVMCore open func reset() { - backgroundColor = nil + shapeLayer?.removeAllAnimations() + shapeLayer?.removeFromSuperlayer() shapeLayer = nil + backgroundColor = nil + borderColor = .black + borderWidth = 1.0 + checkColor = .black + checkWidth = 2.0 + updateSelectionOnly = true isSelected = false + updateSelectionOnly = false } open func setAsMolecule() { setupView() } - public func updateView(_ size: CGFloat) { } + public func updateView(_ size: CGFloat) { + + layoutIfNeeded() + } public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { self.delegateObject = delegateObject diff --git a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift index 55339e61..f148863b 100644 --- a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift +++ b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift @@ -38,6 +38,7 @@ var checkboxTopConstraint: NSLayoutConstraint? var checkboxBottomConstraint: NSLayoutConstraint? var checkboxCenterYConstraint: NSLayoutConstraint? + var centerLabelCheckboxConstraint: NSLayoutConstraint? //-------------------------------------------------- // MARK: - Life Cycle @@ -62,14 +63,8 @@ checkboxHeightConstraint?.isActive = true checkbox.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true - - let generalTop = checkbox.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor) - generalTop.priority = UILayoutPriority(800) - generalTop.isActive = true - - let generalBottom = checkbox.bottomAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.bottomAnchor) - generalBottom.priority = UILayoutPriority(800) - generalBottom.isActive = true + checkbox.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor).isActive = true + layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: checkbox.bottomAnchor).isActive = true let checboxBottom = checkbox.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor) checboxBottom.priority = UILayoutPriority(249) @@ -79,20 +74,17 @@ checkboxBottomConstraint = layoutMarginsGuide.bottomAnchor.constraint(equalTo: checkbox.bottomAnchor) checkboxTopConstraint = checkbox.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor) checkboxCenterYConstraint = checkbox.centerYAnchor.constraint(equalTo: centerYAnchor) + centerLabelCheckboxConstraint = label.centerYAnchor.constraint(equalTo: checkbox.centerYAnchor) label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true layoutMarginsGuide.trailingAnchor.constraint(equalTo: label.trailingAnchor).isActive = true label.leadingAnchor.constraint(equalTo: checkbox.trailingAnchor, constant: PaddingTwo).isActive = true - let bottomLabelConstraint = layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: label.bottomAnchor) - bottomLabelConstraint.priority = UILayoutPriority(500) + layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: label.bottomAnchor).isActive = true + let bottomLabelConstraint = layoutMarginsGuide.bottomAnchor.constraint(equalTo: label.bottomAnchor) + bottomLabelConstraint.priority = UILayoutPriority(249) bottomLabelConstraint.isActive = true - // layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: label.bottomAnchor).isActive = true - // let labelBottom = label.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor) - // labelBottom.priority = UILayoutPriority(249) - // labelBottom.isActive = true - alignCheckbox(.center) } @@ -130,19 +122,22 @@ switch position { case .center: - checkboxCenterYConstraint?.isActive = true checkboxBottomConstraint?.isActive = false checkboxTopConstraint?.isActive = false + checkboxCenterYConstraint?.isActive = true + centerLabelCheckboxConstraint?.isActive = true case .top: checkboxBottomConstraint?.isActive = false checkboxTopConstraint?.isActive = true checkboxCenterYConstraint?.isActive = false + centerLabelCheckboxConstraint?.isActive = false case .bottom: checkboxBottomConstraint?.isActive = true checkboxTopConstraint?.isActive = false checkboxCenterYConstraint?.isActive = false + centerLabelCheckboxConstraint?.isActive = false } } } @@ -176,6 +171,11 @@ extension CheckboxWithLabelView { open override func resetConstraints() { super.resetConstraints() + + checkboxCenterYConstraint?.isActive = false + checkboxBottomConstraint?.isActive = false + checkboxTopConstraint?.isActive = false + centerLabelCheckboxConstraint?.isActive = false } open override func reset() { diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index aeaf6b8d..64dbe2e6 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -39,10 +39,10 @@ @"textField" : MFTextField.class, @"digitTextField" : MFDigitTextField.class, @"checkbox" : Checkbox.class, + @"checkboxWithLabelView" : CheckboxWithLabelView.class, @"cornerLabels" : CornerLabels.class, @"progressBar": ProgressBar.class, @"multiProgressBar": MultiProgress.class, - @"checkboxWithLabelView": CheckboxWithLabelView.class, @"listItem": MoleculeTableViewCell.class, @"accordionListItem": AccordionMoleculeTableViewCell.class, @"switch": MVMCoreUISwitch.class, From 66e45378f461e753f678ff853aca24de577fd659 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 7 Oct 2019 16:33:39 -0400 Subject: [PATCH 24/48] shapelayer . --- MVMCoreUI/Atoms/Views/Checkbox.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index 6253b30d..6f308651 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -80,9 +80,9 @@ import MVMCore /// Width of the check mark. public var checkWidth: CGFloat = 2 { didSet { - if shapeLayer != nil { + if let shapeLayer = shapeLayer { CATransaction.withDisabledAnimations { - shapeLayer?.lineWidth = checkWidth + shapeLayer.lineWidth = checkWidth } } } @@ -91,9 +91,9 @@ import MVMCore /// Color of the check mark. public var checkColor: UIColor = .black { didSet { - if shapeLayer != nil { + if let shapeLayer = shapeLayer { CATransaction.withDisabledAnimations { - shapeLayer?.strokeColor = checkColor.cgColor + shapeLayer.strokeColor = checkColor.cgColor } } } From 1d93f0b4524378b7dee09f46628be35b2f071ee0 Mon Sep 17 00:00:00 2001 From: panxi Date: Mon, 7 Oct 2019 16:58:21 -0400 Subject: [PATCH 25/48] add new mvmanimation xc framework --- MVMCoreUI.xcodeproj/project.pbxproj | 8 ++- .../xcshareddata/xcschemes/MVMCoreUI.xcscheme | 67 +++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 MVMCoreUI.xcodeproj/xcshareddata/xcschemes/MVMCoreUI.xcscheme diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 253371bc..39b9b9f1 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ @@ -21,6 +21,7 @@ 0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */; }; 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; }; + 94620EDB234BDB4B006ED207 /* MVMAnimation.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 94620EDA234BDB4B006ED207 /* MVMAnimation.xcframework */; }; 948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948DB67D2326DCD90011F916 /* MultiProgress.swift */; }; B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; }; B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* CornerLabels.swift */; }; @@ -153,7 +154,6 @@ D29DF2CB21E7BFCC003B2FB9 /* MFSizeThreshold.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF14721E68728003B2FB9 /* MFSizeThreshold.m */; }; D29DF2CE21E7C104003B2FB9 /* MFLoadingViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF2CC21E7C104003B2FB9 /* MFLoadingViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF2CF21E7C104003B2FB9 /* MFLoadingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF2CD21E7C104003B2FB9 /* MFLoadingViewController.m */; }; - D29DF2D121E7C1C8003B2FB9 /* MVMAnimationFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D29DF2D021E7C1C8003B2FB9 /* MVMAnimationFramework.framework */; }; D29DF2E121E9240B003B2FB9 /* MVMCoreUIPanelProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF2E021E9240B003B2FB9 /* MVMCoreUIPanelProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF2EE21ECEADF003B2FB9 /* MFFonts.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF14D21E693AD003B2FB9 /* MFFonts.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF14C21E693AD003B2FB9 /* MFFonts.m */; }; @@ -209,6 +209,7 @@ 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.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 = ""; }; + 94620EDA234BDB4B006ED207 /* MVMAnimation.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = MVMAnimation.xcframework; path = /Users/ryan/Documents/mvmrc_ios/mvmrc_ios/../SharedFrameworks/MVMAnimation.xcframework; sourceTree = ""; }; 948DB67D2326DCD90011F916 /* MultiProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiProgress.swift; sourceTree = ""; }; B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; B8200E182281DC1A007245F4 /* CornerLabels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerLabels.swift; sourceTree = ""; }; @@ -393,7 +394,7 @@ buildActionMask = 2147483647; files = ( D29DF0E621E4F3C7003B2FB9 /* MVMCore.framework in Frameworks */, - D29DF2D121E7C1C8003B2FB9 /* MVMAnimationFramework.framework in Frameworks */, + 94620EDB234BDB4B006ED207 /* MVMAnimation.xcframework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -539,6 +540,7 @@ isa = PBXGroup; children = ( D29DF2D021E7C1C8003B2FB9 /* MVMAnimationFramework.framework */, + 94620EDA234BDB4B006ED207 /* MVMAnimation.xcframework */, D29DF0E521E4F3C7003B2FB9 /* MVMCore.framework */, ); name = Frameworks; diff --git a/MVMCoreUI.xcodeproj/xcshareddata/xcschemes/MVMCoreUI.xcscheme b/MVMCoreUI.xcodeproj/xcshareddata/xcschemes/MVMCoreUI.xcscheme new file mode 100644 index 00000000..c686e971 --- /dev/null +++ b/MVMCoreUI.xcodeproj/xcshareddata/xcschemes/MVMCoreUI.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + From 473ec08b07745f196d6be058f91d0639695e1e0b Mon Sep 17 00:00:00 2001 From: panxi Date: Mon, 7 Oct 2019 17:02:06 -0400 Subject: [PATCH 26/48] remove testing scheme --- .../xcshareddata/xcschemes/MVMCoreUI.xcscheme | 67 ------------------- 1 file changed, 67 deletions(-) delete mode 100644 MVMCoreUI.xcodeproj/xcshareddata/xcschemes/MVMCoreUI.xcscheme diff --git a/MVMCoreUI.xcodeproj/xcshareddata/xcschemes/MVMCoreUI.xcscheme b/MVMCoreUI.xcodeproj/xcshareddata/xcschemes/MVMCoreUI.xcscheme deleted file mode 100644 index c686e971..00000000 --- a/MVMCoreUI.xcodeproj/xcshareddata/xcschemes/MVMCoreUI.xcscheme +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - From bbdb2181f22e96db7ca96f9c8b1536158cc564a4 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 8 Oct 2019 11:30:25 -0400 Subject: [PATCH 27/48] aligning with invision. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index 6f308651..f82d6bed 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -244,10 +244,17 @@ import MVMCore /// Returns a UIBezierPath detailing the path of a checkmark func checkMarkPath() -> CGPath { - let sideLength = max(bounds.size.height, bounds.size.width) - let startPoint = CGPoint(x: 0.33871 * sideLength, y: 0.53225 * sideLength) - let pivotOffSet = CGPoint(x: 0.46774 * sideLength, y: 0.64516 * sideLength) - let endOffset = CGPoint(x: 0.66935 * sideLength , y: 0.37097 * sideLength) + let length = max(bounds.size.height, bounds.size.width) + let xInsetLeft = length * 0.25 + let xInsetRight = length * 0.25 + let yInsetTop = length * 0.3 + let yInsetBottom = length * 0.35 + let innerWidth = length - (xInsetLeft + xInsetRight) + let innerHeight = length - (yInsetTop + yInsetBottom) + + let startPoint = CGPoint(x: xInsetLeft, y: yInsetTop + (innerHeight / 2)) + let pivotOffSet = CGPoint(x: xInsetLeft + (innerWidth * 0.33), y: yInsetTop + innerHeight) + let endOffset = CGPoint(x: xInsetLeft + innerWidth, y: yInsetTop) let bezierPath = UIBezierPath() bezierPath.move(to: startPoint) From ec190a28bdf137a1134762400fda080ebdd90328 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 8 Oct 2019 11:47:08 -0400 Subject: [PATCH 28/48] Further updates made. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 32 ++++++---------------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index f82d6bed..187d9d7c 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -8,22 +8,6 @@ import MVMCore -/* - !!! -- DO NOT REMOVE -- !!! - (Unless Design changes the appearance of the checkmark). - - // Offsets based on the 124x124 example checkmark - let startXOffset: Float = 42.0 / 124.0 ~~ 0.33871 - let startYOffset: Float = 66.0 / 124.0 ~~ 0.53225 - let pivotXOffset: Float = 58.0 / 124.0 ~~ 0.46774 - let pivotYOffset: Float = 80.0 / 124.0 ~~ 0.64516 - let endXOffset: Float = 83.0 / 124.0 ~~ 0.66935 - let endYOffset: Float = 46.0 / 124.0 ~~ 0.37097 - let pivotPercentage: Float = 0.34 - let endPercentage = 1.0 - pivotPercentage - let animationInterval: Float = 0.01 - */ - /** This class expects its height and width to be equal. */ @@ -182,7 +166,7 @@ import MVMCore override open func layoutSubviews() { super.layoutSubviews() - drawCheck() + drawShapeLayer() layer.cornerRadius = isRound ? cornerRadiusValue : 0 layer.borderWidth = borderWidth layer.borderColor = borderColor.cgColor @@ -220,8 +204,8 @@ import MVMCore // MARK: - Methods //-------------------------------------------------- - /// Creates the check mark used for the checkbox. - private func drawCheck() { + /// Creates the check mark layer. + private func drawShapeLayer() { if shapeLayer == nil { @@ -241,16 +225,14 @@ import MVMCore } } - /// Returns a UIBezierPath detailing the path of a checkmark + /// - returns: The CGPath of a UIBezierPath detailing the path of a checkmark func checkMarkPath() -> CGPath { let length = max(bounds.size.height, bounds.size.width) let xInsetLeft = length * 0.25 - let xInsetRight = length * 0.25 let yInsetTop = length * 0.3 - let yInsetBottom = length * 0.35 - let innerWidth = length - (xInsetLeft + xInsetRight) - let innerHeight = length - (yInsetTop + yInsetBottom) + let innerWidth = length - (xInsetLeft + length * 0.25) // + Right X Inset + let innerHeight = length - (yInsetTop + length * 0.35) // + Bottom Y Inset let startPoint = CGPoint(x: xInsetLeft, y: yInsetTop + (innerHeight / 2)) let pivotOffSet = CGPoint(x: xInsetLeft + (innerWidth * 0.33), y: yInsetTop + innerHeight) @@ -274,7 +256,7 @@ import MVMCore self.updateSelectionOnly = true self.isSelected = selected self.updateSelectionOnly = false - self.drawCheck() + self.drawShapeLayer() self.shapeLayer?.removeAllAnimations() self.updateCheckboxUI(isSelected: selected, isAnimated: animated) } From 03f12b8a7a014d4a2533dcc440a9e4b9eff23c04 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 8 Oct 2019 13:15:10 -0400 Subject: [PATCH 29/48] added isEnabled func. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 36 ++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index 187d9d7c..1f6a429a 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -62,7 +62,7 @@ import MVMCore private var shapeLayer: CAShapeLayer? /// Width of the check mark. - public var checkWidth: CGFloat = 2 { + public var checkWidth: CGFloat = 2.3 { didSet { if let shapeLayer = shapeLayer { CATransaction.withDisabledAnimations { @@ -75,11 +75,7 @@ import MVMCore /// Color of the check mark. public var checkColor: UIColor = .black { didSet { - if let shapeLayer = shapeLayer { - CATransaction.withDisabledAnimations { - shapeLayer.strokeColor = checkColor.cgColor - } - } + setshapeLayerStrokeColor(checkColor) } } @@ -285,7 +281,7 @@ import MVMCore self.shapeLayer?.strokeEnd = isSelected ? 1 : 0 } - self.backgroundColor = isSelected ? self.checkedBackgroundColor : self.unCheckedBackgroundColor + backgroundColor = isSelected ? checkedBackgroundColor : unCheckedBackgroundColor } } @@ -297,6 +293,32 @@ import MVMCore } } + func isEnabled(_ enabled: Bool) { + + isUserInteractionEnabled = enabled + + if enabled { + layer.borderColor = borderColor.cgColor + backgroundColor = isSelected ? checkedBackgroundColor : unCheckedBackgroundColor + alpha = 1.0 + setshapeLayerStrokeColor(checkColor) + } else { + layer.borderColor = UIColor.mfSilver().cgColor + backgroundColor = .white + alpha = DisableOppacity + setshapeLayerStrokeColor(UIColor.mfSilver()) + } + } + + private func setshapeLayerStrokeColor(_ color: UIColor) { + + if let shapeLayer = shapeLayer { + CATransaction.withDisabledAnimations { + shapeLayer.strokeColor = color.cgColor + } + } + } + //-------------------------------------------------- // MARK: - UITouch //-------------------------------------------------- From cfdf44379d9b250a283c63b3ed4f99d5cdef77ec Mon Sep 17 00:00:00 2001 From: panxi Date: Tue, 8 Oct 2019 13:44:02 -0400 Subject: [PATCH 30/48] update framework relate to group --- MVMCoreUI.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 39b9b9f1..a5774155 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -209,7 +209,7 @@ 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.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 = ""; }; - 94620EDA234BDB4B006ED207 /* MVMAnimation.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = MVMAnimation.xcframework; path = /Users/ryan/Documents/mvmrc_ios/mvmrc_ios/../SharedFrameworks/MVMAnimation.xcframework; sourceTree = ""; }; + 94620EDA234BDB4B006ED207 /* MVMAnimation.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = MVMAnimation.xcframework; path = ../SharedFrameworks/MVMAnimation.xcframework; sourceTree = ""; }; 948DB67D2326DCD90011F916 /* MultiProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiProgress.swift; sourceTree = ""; }; B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; B8200E182281DC1A007245F4 /* CornerLabels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerLabels.swift; sourceTree = ""; }; From 104f45d0b6a4d8d87c4a97fb50d453c758ab51ff Mon Sep 17 00:00:00 2001 From: "Suresh, Kamlesh" Date: Tue, 8 Oct 2019 14:11:31 -0400 Subject: [PATCH 31/48] default arch --- MVMCoreUI.xcodeproj/project.pbxproj | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index a4a3e406..adb09309 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -1271,7 +1271,7 @@ FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../SharedFrameworks"; INFOPLIST_FILE = MVMCoreUI/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1283,7 +1283,6 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - VALID_ARCHS = "arm64 arm64e"; }; name = Debug; }; @@ -1302,7 +1301,7 @@ FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../SharedFrameworks"; INFOPLIST_FILE = MVMCoreUI/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1313,7 +1312,6 @@ SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - VALID_ARCHS = "arm64 arm64e"; }; name = Release; }; From 1618583acce693418af22bb1cd758875f9bb2b88 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 8 Oct 2019 15:19:12 -0400 Subject: [PATCH 32/48] corrected comment. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index 1f6a429a..0d2c3e75 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -259,7 +259,7 @@ import MVMCore } /// updates the visuals of the check mark and background. - /// - parameter isSelection: the check state of the checkbox. + /// - parameter isSelected: the check state of the checkbox. /// - parameter isAnimated: determines of the changes should animate or immediately refelect. public func updateCheckboxUI(isSelected: Bool, isAnimated: Bool) { From 9922ef467422d6b007f9b6b6213eeb9a1855ed6c Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 8 Oct 2019 16:45:34 -0400 Subject: [PATCH 33/48] added enabled molecule logic. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index 0d2c3e75..2ece7d4a 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -354,6 +354,7 @@ import MVMCore open func reset() { + isEnabled(true) shapeLayer?.removeAllAnimations() shapeLayer?.removeFromSuperlayer() shapeLayer = nil @@ -424,9 +425,15 @@ import MVMCore self.isRound = isRound } + if let enabled = dictionary["isEnabled"] as? Bool { + isEnabled(enabled) + } + if let actionMap = dictionary.optionalDictionaryForKey("actionMap") { actionBlock = { MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) } } + +// layoutIfNeeded() } } From 0f6a243e7bb5b78721c00f167b3ad45d033cfc21 Mon Sep 17 00:00:00 2001 From: panxi Date: Wed, 9 Oct 2019 10:10:57 -0400 Subject: [PATCH 34/48] change back to animaitonframework --- MVMCoreUI.xcodeproj/project.pbxproj | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index a5774155..3878406b 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -21,7 +21,7 @@ 0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */; }; 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; }; - 94620EDB234BDB4B006ED207 /* MVMAnimation.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 94620EDA234BDB4B006ED207 /* MVMAnimation.xcframework */; }; + 948B34AC234E1F400005B989 /* MVMAnimationFramework.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 948B34AB234E1F400005B989 /* MVMAnimationFramework.xcframework */; }; 948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948DB67D2326DCD90011F916 /* MultiProgress.swift */; }; B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; }; B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* CornerLabels.swift */; }; @@ -209,7 +209,7 @@ 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.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 = ""; }; - 94620EDA234BDB4B006ED207 /* MVMAnimation.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = MVMAnimation.xcframework; path = ../SharedFrameworks/MVMAnimation.xcframework; sourceTree = ""; }; + 948B34AB234E1F400005B989 /* MVMAnimationFramework.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = MVMAnimationFramework.xcframework; path = ../SharedFrameworks/MVMAnimationFramework.xcframework; sourceTree = ""; }; 948DB67D2326DCD90011F916 /* MultiProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiProgress.swift; sourceTree = ""; }; B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; B8200E182281DC1A007245F4 /* CornerLabels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerLabels.swift; sourceTree = ""; }; @@ -346,7 +346,6 @@ D29DF2C321E7BF57003B2FB9 /* MFTabBarInteractor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFTabBarInteractor.m; sourceTree = ""; }; D29DF2CC21E7C104003B2FB9 /* MFLoadingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFLoadingViewController.h; sourceTree = ""; }; D29DF2CD21E7C104003B2FB9 /* MFLoadingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFLoadingViewController.m; sourceTree = ""; }; - D29DF2D021E7C1C8003B2FB9 /* MVMAnimationFramework.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MVMAnimationFramework.framework; path = ../SharedFrameworks/MVMAnimationFramework.framework; sourceTree = ""; }; D29DF2E021E9240B003B2FB9 /* MVMCoreUIPanelProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIPanelProtocol.h; sourceTree = ""; }; D29DF31621ECECC0003B2FB9 /* NHaasGroteskDSStd-45Lt.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NHaasGroteskDSStd-45Lt.otf"; sourceTree = ""; }; D29DF31721ECECC0003B2FB9 /* OCRAExtended.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = OCRAExtended.ttf; sourceTree = ""; }; @@ -393,8 +392,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 948B34AC234E1F400005B989 /* MVMAnimationFramework.xcframework in Frameworks */, D29DF0E621E4F3C7003B2FB9 /* MVMCore.framework in Frameworks */, - 94620EDB234BDB4B006ED207 /* MVMAnimation.xcframework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -539,9 +538,8 @@ D29DF0E421E4F3C7003B2FB9 /* Frameworks */ = { isa = PBXGroup; children = ( - D29DF2D021E7C1C8003B2FB9 /* MVMAnimationFramework.framework */, - 94620EDA234BDB4B006ED207 /* MVMAnimation.xcframework */, D29DF0E521E4F3C7003B2FB9 /* MVMCore.framework */, + 948B34AB234E1F400005B989 /* MVMAnimationFramework.xcframework */, ); name = Frameworks; sourceTree = ""; From 960d9e0e7ca847191819cde67a49080c59530000 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 9 Oct 2019 10:18:18 -0400 Subject: [PATCH 35/48] removed comment. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index 2ece7d4a..c43accb2 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -432,8 +432,6 @@ import MVMCore if let actionMap = dictionary.optionalDictionaryForKey("actionMap") { actionBlock = { MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) } } - -// layoutIfNeeded() } } From 5ef9754e2cb8a362f098dd74941f6dc17caebed7 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 9 Oct 2019 12:45:18 -0400 Subject: [PATCH 36/48] defaulting to clear. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index c43accb2..c3879f96 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -33,7 +33,7 @@ import MVMCore public var updateSelectionOnly: Bool = false /// The color of the background when checked. - public var checkedBackgroundColor: UIColor = .white { + public var checkedBackgroundColor: UIColor = .clear { didSet { if isSelected { backgroundColor = checkedBackgroundColor @@ -42,7 +42,7 @@ import MVMCore } /// The color of the background when unChecked. - public var unCheckedBackgroundColor: UIColor = .white { + public var unCheckedBackgroundColor: UIColor = .clear { didSet { if !isSelected { backgroundColor = unCheckedBackgroundColor @@ -62,7 +62,7 @@ import MVMCore private var shapeLayer: CAShapeLayer? /// Width of the check mark. - public var checkWidth: CGFloat = 2.3 { + public var checkWidth: CGFloat = 2 { didSet { if let shapeLayer = shapeLayer { CATransaction.withDisabledAnimations { @@ -172,7 +172,7 @@ import MVMCore isUserInteractionEnabled = true translatesAutoresizingMaskIntoConstraints = false - backgroundColor = .white + backgroundColor = .clear } //-------------------------------------------------- @@ -304,7 +304,7 @@ import MVMCore setshapeLayerStrokeColor(checkColor) } else { layer.borderColor = UIColor.mfSilver().cgColor - backgroundColor = .white + backgroundColor = .clear alpha = DisableOppacity setshapeLayerStrokeColor(UIColor.mfSilver()) } @@ -358,7 +358,7 @@ import MVMCore shapeLayer?.removeAllAnimations() shapeLayer?.removeFromSuperlayer() shapeLayer = nil - backgroundColor = nil + backgroundColor = .clear borderColor = .black borderWidth = 1.0 checkColor = .black From f37ee3c9ba5f626bfafa3666f44c4475ef186001 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 9 Oct 2019 13:04:04 -0400 Subject: [PATCH 37/48] os version --- MVMCoreUI.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 3878406b..f505de3a 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -1185,7 +1185,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.1; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -1244,7 +1244,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.1; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -1271,7 +1271,7 @@ FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../SharedFrameworks"; INFOPLIST_FILE = MVMCoreUI/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1301,7 +1301,7 @@ FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../SharedFrameworks"; INFOPLIST_FILE = MVMCoreUI/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", From db583609ac6afb8fd983b37d051757d76477c998 Mon Sep 17 00:00:00 2001 From: panxi Date: Thu, 10 Oct 2019 06:49:31 -0400 Subject: [PATCH 38/48] change to 8.0 --- MVMCoreUI.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index f505de3a..47eed952 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -966,7 +966,7 @@ }; }; buildConfigurationList = D29DF0C621E404D4003B2FB9 /* Build configuration list for PBXProject "MVMCoreUI" */; - compatibilityVersion = "Xcode 9.3"; + compatibilityVersion = "Xcode 8.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( From 93733fb7b613b695e6b54de6ac796a85359cedc9 Mon Sep 17 00:00:00 2001 From: panxi Date: Thu, 10 Oct 2019 12:48:27 -0400 Subject: [PATCH 39/48] add framework back --- MVMCoreUI.xcodeproj/project.pbxproj | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 47eed952..11c20e13 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 48; objects = { /* Begin PBXBuildFile section */ @@ -21,7 +21,7 @@ 0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */; }; 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; }; - 948B34AC234E1F400005B989 /* MVMAnimationFramework.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 948B34AB234E1F400005B989 /* MVMAnimationFramework.xcframework */; }; + 9455B19C234F8A0400A574DB /* MVMAnimationFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9455B19B234F8A0400A574DB /* MVMAnimationFramework.framework */; }; 948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948DB67D2326DCD90011F916 /* MultiProgress.swift */; }; B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; }; B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* CornerLabels.swift */; }; @@ -209,7 +209,7 @@ 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.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 = ""; }; - 948B34AB234E1F400005B989 /* MVMAnimationFramework.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = MVMAnimationFramework.xcframework; path = ../SharedFrameworks/MVMAnimationFramework.xcframework; 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 = ""; }; B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; B8200E182281DC1A007245F4 /* CornerLabels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerLabels.swift; sourceTree = ""; }; @@ -392,8 +392,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 948B34AC234E1F400005B989 /* MVMAnimationFramework.xcframework in Frameworks */, D29DF0E621E4F3C7003B2FB9 /* MVMCore.framework in Frameworks */, + 9455B19C234F8A0400A574DB /* MVMAnimationFramework.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -539,7 +539,7 @@ isa = PBXGroup; children = ( D29DF0E521E4F3C7003B2FB9 /* MVMCore.framework */, - 948B34AB234E1F400005B989 /* MVMAnimationFramework.xcframework */, + 9455B19B234F8A0400A574DB /* MVMAnimationFramework.framework */, ); name = Frameworks; sourceTree = ""; @@ -962,6 +962,7 @@ D29DF0CB21E404D4003B2FB9 = { CreatedOnToolsVersion = 10.1; LastSwiftMigration = 1010; + ProvisioningStyle = Automatic; }; }; }; @@ -1248,8 +1249,7 @@ MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -1272,11 +1272,7 @@ INFOPLIST_FILE = MVMCoreUI/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 11.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.vzw.MVMCoreUI; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -1302,11 +1298,7 @@ INFOPLIST_FILE = MVMCoreUI/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 11.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.vzw.MVMCoreUI; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; From bb51fba0e59f95c99967597d6b237773fb8ecde5 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 17 Oct 2019 10:31:34 -0400 Subject: [PATCH 40/48] remove legacy os code --- MVMCoreUI/Atoms/TextFields/MFTextField.m | 8 ++-- MVMCoreUI/Atoms/Views/MFTextView.m | 9 ++--- MVMCoreUI/Atoms/Views/MFView.m | 4 +- .../MFProgrammaticTableViewController.m | 8 +--- .../MFScrollingViewController.m | 5 +-- .../ThreeLayerTableViewController.swift | 10 ++--- .../ThreeLayerViewController.swift | 14 +++---- ...MVMCoreUITabBarPageControlViewController.m | 10 ----- ...abelsAndBottomButtonsTableViewController.m | 20 ++++------ .../TopLabelsAndBottomButtonsViewController.m | 27 +++++--------- .../Items/MoleculeCollectionViewCell.swift | 8 ++-- .../Items/MoleculeTableViewCell.swift | 37 ++++++------------- .../Utility/MVMCoreUICommonViewsUtility.m | 25 ++++--------- MVMCoreUI/Utility/MVMCoreUIUtility.m | 21 +++-------- 14 files changed, 62 insertions(+), 144 deletions(-) diff --git a/MVMCoreUI/Atoms/TextFields/MFTextField.m b/MVMCoreUI/Atoms/TextFields/MFTextField.m index ba68c0ed..e4709844 100644 --- a/MVMCoreUI/Atoms/TextFields/MFTextField.m +++ b/MVMCoreUI/Atoms/TextFields/MFTextField.m @@ -83,11 +83,9 @@ self.enabled = YES; // Disable SmartQuotes - if (@available(iOS 11.0, *)) { - self.textField.smartQuotesType = UITextSmartQuotesTypeNo; - self.textField.smartDashesType = UITextSmartDashesTypeNo; - self.textField.smartInsertDeleteType = UITextSmartInsertDeleteTypeNo; - } + self.textField.smartQuotesType = UITextSmartQuotesTypeNo; + self.textField.smartDashesType = UITextSmartDashesTypeNo; + self.textField.smartInsertDeleteType = UITextSmartInsertDeleteTypeNo; } } diff --git a/MVMCoreUI/Atoms/Views/MFTextView.m b/MVMCoreUI/Atoms/Views/MFTextView.m index c120d964..424c8117 100644 --- a/MVMCoreUI/Atoms/Views/MFTextView.m +++ b/MVMCoreUI/Atoms/Views/MFTextView.m @@ -173,11 +173,10 @@ view.placeHolderLabel.textColor = [UIColor mfLightGrayColor]; // Disable SmartQuotes - if (@available(iOS 11.0, *)) { - view.textView.smartQuotesType = UITextSmartQuotesTypeNo; - view.textView.smartDashesType = UITextSmartDashesTypeNo; - view.textView.smartInsertDeleteType = UITextSmartInsertDeleteTypeNo; - } + view.textView.smartQuotesType = UITextSmartQuotesTypeNo; + view.textView.smartDashesType = UITextSmartDashesTypeNo; + view.textView.smartInsertDeleteType = UITextSmartInsertDeleteTypeNo; + [view didSetFont:view.textView.font]; view.hideBorder = YES; return view; diff --git a/MVMCoreUI/Atoms/Views/MFView.m b/MVMCoreUI/Atoms/Views/MFView.m index 4e0d71ab..6d939fc8 100644 --- a/MVMCoreUI/Atoms/Views/MFView.m +++ b/MVMCoreUI/Atoms/Views/MFView.m @@ -48,9 +48,7 @@ - (void)setAsMolecule { self.translatesAutoresizingMaskIntoConstraints = NO; - if (@available(iOS 11.0, *)) { - self.insetsLayoutMarginsFromSafeArea = NO; - } + self.insetsLayoutMarginsFromSafeArea = NO; } - (void)reset { diff --git a/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.m b/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.m index 98d2b5ef..1d0d2a3b 100644 --- a/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.m +++ b/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.m @@ -61,12 +61,8 @@ 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; - } + tableView.insetsContentViewsToSafeArea = NO; + tableView.cellLayoutMarginsFollowReadableWidth = NO; return tableView; } diff --git a/MVMCoreUI/BaseControllers/MFScrollingViewController.m b/MVMCoreUI/BaseControllers/MFScrollingViewController.m index 5486b54a..56019cb7 100644 --- a/MVMCoreUI/BaseControllers/MFScrollingViewController.m +++ b/MVMCoreUI/BaseControllers/MFScrollingViewController.m @@ -91,10 +91,7 @@ static NSTimeInterval const HandScrollAnimationTiming = 7.f; - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; - BOOL automaticInset = NO; - if (@available(iOS 11.0, *)) { - automaticInset = self.navigationController && self.scrollView.contentInsetAdjustmentBehavior == UIScrollViewContentInsetAdjustmentAutomatic; - } + BOOL automaticInset = self.navigationController && self.scrollView.contentInsetAdjustmentBehavior == UIScrollViewContentInsetAdjustmentAutomatic; // Takes into account the navigation bar. if (!automaticInset && (self.edgesForExtendedLayout & UIRectEdgeTop)) { diff --git a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift index 0293e860..d1bfa0db 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift @@ -190,13 +190,9 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { footerView.topAnchor.constraint(equalTo: tableView.bottomAnchor).isActive = true footerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true view.rightAnchor.constraint(equalTo: footerView.rightAnchor).isActive = true - if #available(iOS 11.0, *) { - view.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: footerView.bottomAnchor).isActive = true - safeAreaView = MVMCoreUICommonViewsUtility.getAndSetupSafeAreaView(on: view) - safeAreaView?.backgroundColor = bottomView?.backgroundColor - } else { - view.bottomAnchor.constraint(equalTo: footerView.bottomAnchor).isActive = true - } + view.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: footerView.bottomAnchor).isActive = true + safeAreaView = MVMCoreUICommonViewsUtility.getAndSetupSafeAreaView(on: view) + safeAreaView?.backgroundColor = bottomView?.backgroundColor } else { bottomConstraint?.isActive = true var y: CGFloat? diff --git a/MVMCoreUI/BaseControllers/ThreeLayerViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerViewController.swift index dae861dd..ea6923c5 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerViewController.swift @@ -45,7 +45,7 @@ open class ThreeLayerViewController: ProgrammaticScrollViewController { return } - if #available(iOS 11.0, *), scrollView.contentInsetAdjustmentBehavior == UIScrollView.ContentInsetAdjustmentBehavior.automatic { + if scrollView.contentInsetAdjustmentBehavior == UIScrollView.ContentInsetAdjustmentBehavior.automatic { heightConstraint?.constant = -scrollView.adjustedContentInset.top - scrollView.adjustedContentInset.bottom } else { heightConstraint?.constant = -scrollView.contentInset.top - scrollView.contentInset.bottom @@ -233,14 +233,10 @@ extension ThreeLayerViewController { view.topAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true NSLayoutConstraint.pinViewLeft(toSuperview: view, useMargins: useMargins, constant: 0).isActive = true NSLayoutConstraint.pinViewRight(toSuperview: view, useMargins: useMargins, constant: 0).isActive = true - if #available(iOS 11.0, *) { - parentView.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true - if let safeAreaView = MVMCoreUICommonViewsUtility.getAndSetupSafeAreaView(on: parentView) { - safeAreaView.backgroundColor = bottomView?.backgroundColor - self.safeAreaView = safeAreaView - } - } else { - NSLayoutConstraint.pinViewBottom(toSuperview: view, useMargins: useMargins, constant: 0).isActive = true + parentView.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true + if let safeAreaView = MVMCoreUICommonViewsUtility.getAndSetupSafeAreaView(on: parentView) { + safeAreaView.backgroundColor = bottomView?.backgroundColor + self.safeAreaView = safeAreaView } } } diff --git a/MVMCoreUI/Containers/TabBarController/MVMCoreUITabBarPageControlViewController.m b/MVMCoreUI/Containers/TabBarController/MVMCoreUITabBarPageControlViewController.m index 1d8481d6..cb48eb54 100644 --- a/MVMCoreUI/Containers/TabBarController/MVMCoreUITabBarPageControlViewController.m +++ b/MVMCoreUI/Containers/TabBarController/MVMCoreUITabBarPageControlViewController.m @@ -283,16 +283,6 @@ // So we will update titles. [self newDataBuildScreen]; - - // Fix for right bar button item with custom view which disappears when user navigates to top tabbar page controller - if (@available(iOS 11.0, *)) { - } else { - NSMutableArray *buttonItems = [[NSMutableArray alloc] init]; - UIBarButtonItem *space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:self action:nil]; - [buttonItems addObject:space]; - [buttonItems addObjectsFromArray:self.navigationItem.rightBarButtonItems]; - self.navigationItem.rightBarButtonItems = buttonItems; - } } - (void)viewWillDisappear:(BOOL)animated { diff --git a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m index ca75b778..1c90d9e0 100644 --- a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m +++ b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m @@ -325,19 +325,13 @@ NSLayoutConstraint *bottomViewTop = [NSLayoutConstraint constraintWithItem:footerView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:tableView attribute:NSLayoutAttributeBottom multiplier:1 constant:0]; bottomViewTop.active = YES; - NSLayoutConstraint *bottomViewBot = nil; - if (@available(iOS 11.0, *)) { - bottomViewBot = [self.view.safeAreaLayoutGuide.bottomAnchor constraintEqualToAnchor:footerView.bottomAnchor]; - - UIView *safeAreaView = [MVMCoreUICommonViewsUtility getAndSetupSafeAreaViewOnView:self.view]; - safeAreaView.backgroundColor = footerView.backgroundColor; - self.safeAreaView = safeAreaView; - } else { - // Fallback on earlier versions - bottomViewBot = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:footerView attribute:NSLayoutAttributeBottom multiplier:1 constant:0]; - } - bottomViewBot.priority = 900; - bottomViewBot.active = YES; + NSLayoutConstraint *bottomViewBot = [self.view.safeAreaLayoutGuide.bottomAnchor constraintEqualToAnchor:footerView.bottomAnchor]; + bottomViewBot.priority = 900; + bottomViewBot.active = YES; + + UIView *safeAreaView = [MVMCoreUICommonViewsUtility getAndSetupSafeAreaViewOnView:self.view]; + safeAreaView.backgroundColor = footerView.backgroundColor; + self.safeAreaView = safeAreaView; [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[footerView]-0@900-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(footerView)]]; } else { diff --git a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.m b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.m index 77472e11..0c9d1d5d 100644 --- a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.m +++ b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsViewController.m @@ -272,13 +272,8 @@ - (void)updateViewConstraints { [super updateViewConstraints]; - // Updates for ios 11 - if (@available(iOS 11.0, *)) { - if (self.scrollView.contentInsetAdjustmentBehavior == UIScrollViewContentInsetAdjustmentAutomatic) { - self.heightConstraint.constant = -self.scrollView.adjustedContentInset.top - self.scrollView.adjustedContentInset.bottom; - } else { - self.heightConstraint.constant = -self.scrollView.contentInset.top - self.scrollView.contentInset.bottom; - } + if (self.scrollView.contentInsetAdjustmentBehavior == UIScrollViewContentInsetAdjustmentAutomatic) { + self.heightConstraint.constant = -self.scrollView.adjustedContentInset.top - self.scrollView.adjustedContentInset.bottom; } else { self.heightConstraint.constant = -self.scrollView.contentInset.top - self.scrollView.contentInset.bottom; } @@ -322,17 +317,13 @@ [self.view addSubview:bottomView]; UIScrollView *scrollview = self.scrollView; - if (@available(iOS 11.0, *)) { - [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[scrollview]-0-[bottomView]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(scrollview,bottomView)]]; - [self.view.safeAreaLayoutGuide.bottomAnchor constraintEqualToAnchor:bottomView.bottomAnchor].active = YES; - - UIView *safeAreaView = [MVMCoreUICommonViewsUtility getAndSetupSafeAreaViewOnView:self.view]; - safeAreaView.backgroundColor = bottomView.backgroundColor; - self.safeAreaView = safeAreaView; - } else { - // Fallback on earlier versions - [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[scrollview]-0-[bottomView]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(scrollview,bottomView)]]; - } + [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[scrollview]-0-[bottomView]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(scrollview,bottomView)]]; + [self.view.safeAreaLayoutGuide.bottomAnchor constraintEqualToAnchor:bottomView.bottomAnchor].active = YES; + + UIView *safeAreaView = [MVMCoreUICommonViewsUtility getAndSetupSafeAreaViewOnView:self.view]; + safeAreaView.backgroundColor = bottomView.backgroundColor; + self.safeAreaView = safeAreaView; + [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[bottomView]-0@900-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(bottomView)]]; } diff --git a/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift index 42a5e5cd..685d2e7a 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift @@ -37,11 +37,9 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi } isAccessibilityElement = false contentView.isAccessibilityElement = false - if #available(iOS 11.0, *) { - insetsLayoutMarginsFromSafeArea = false - contentView.insetsLayoutMarginsFromSafeArea = false - contentView.preservesSuperviewLayoutMargins = false - } + insetsLayoutMarginsFromSafeArea = false + contentView.insetsLayoutMarginsFromSafeArea = false + contentView.preservesSuperviewLayoutMargins = false // Covers the card when peaking. peakingCover.backgroundColor = .white diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index 641b3721..3c20402e 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -87,29 +87,16 @@ import UIKit // MARK: - MFViewProtocol public func updateView(_ size: CGFloat) { MFStyler.setMarginsFor(self, size: size, defaultHorizontal: updateViewHorizontalDefaults, top: topMarginPadding, bottom: bottomMarginPadding) - if #available(iOS 11.0, *) { - if accessoryView != nil { - // Smaller left margin if accessory view. - var margin = directionalLayoutMargins - margin.trailing = 16 - contentView.directionalLayoutMargins = margin - } else { - contentView.directionalLayoutMargins = directionalLayoutMargins - } - topSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading) - bottomSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading) + if accessoryView != nil { + // Smaller left margin if accessory view. + var margin = directionalLayoutMargins + margin.trailing = 16 + contentView.directionalLayoutMargins = margin } else { - if accessoryView != nil { - // Smaller left margin if accessory view. - var margin = layoutMargins - margin.right = 16 - contentView.layoutMargins = margin - } else { - contentView.layoutMargins = layoutMargins - } - topSeparatorView?.setLeftAndRightPinConstant(layoutMargins.left) - bottomSeparatorView?.setLeftAndRightPinConstant(layoutMargins.left) + contentView.directionalLayoutMargins = directionalLayoutMargins } + topSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading) + bottomSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading) molecule?.updateView(size) if let _ = accessoryView, let caretView = caretView, let widthObject = caretViewWidthSizeObject, let heightObject = caretViewHeightSizeObject { @@ -121,11 +108,9 @@ import UIKit public func setupView() { selectionStyle = .none - if #available(iOS 11.0, *) { - insetsLayoutMarginsFromSafeArea = false - contentView.insetsLayoutMarginsFromSafeArea = false - contentView.preservesSuperviewLayoutMargins = false - } + insetsLayoutMarginsFromSafeArea = false + contentView.insetsLayoutMarginsFromSafeArea = false + contentView.preservesSuperviewLayoutMargins = false } // MARK: - MVMCoreUIMoleculeViewProtocol diff --git a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m index 94c6ca85..fd5c9b21 100644 --- a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m @@ -198,13 +198,8 @@ static const CGFloat VertialShadowOffset = 6; [view.rightAnchor constraintEqualToAnchor:button.rightAnchor constant:PaddingTwo].active = YES; [view.centerYAnchor constraintEqualToAnchor:button.centerYAnchor].active = YES; } else { - if (@available(iOS 11.0, *)) { - [button.topAnchor constraintEqualToAnchor:view.safeAreaLayoutGuide.topAnchor constant:PaddingOne].active = YES; - [view.safeAreaLayoutGuide.trailingAnchor constraintEqualToAnchor:button.trailingAnchor constant:PaddingTwo].active = YES; - } else { - [NSLayoutConstraint constraintPinSubview:button pinTop:YES topConstant:PaddingOne pinBottom:NO bottomConstant:0 pinLeft:NO leftConstant:0 pinRight:YES rightConstant:PaddingTwo]; - } - + [button.topAnchor constraintEqualToAnchor:view.safeAreaLayoutGuide.topAnchor constant:PaddingOne].active = YES; + [view.safeAreaLayoutGuide.trailingAnchor constraintEqualToAnchor:button.trailingAnchor constant:PaddingTwo].active = YES; } } return button; @@ -249,16 +244,12 @@ static const CGFloat VertialShadowOffset = 6; } + (nullable UIView *)getAndSetupSafeAreaViewOnView:(nonnull UIView *)view { - if (@available(iOS 11.0, *)) { - UIView *safeAreaView = [MVMCoreUICommonViewsUtility commonView]; - [view addSubview:safeAreaView]; - [safeAreaView.topAnchor constraintEqualToAnchor:view.safeAreaLayoutGuide.bottomAnchor].active = YES; - [view.bottomAnchor constraintEqualToAnchor:safeAreaView.bottomAnchor].active = YES; - [NSLayoutConstraint constraintPinSubview:safeAreaView pinTop:NO topConstant:0 pinBottom:NO bottomConstant:0 pinLeft:YES leftConstant:0 pinRight:YES rightConstant:0]; - return safeAreaView; - } else { - return nil; - } + UIView *safeAreaView = [MVMCoreUICommonViewsUtility commonView]; + [view addSubview:safeAreaView]; + [safeAreaView.topAnchor constraintEqualToAnchor:view.safeAreaLayoutGuide.bottomAnchor].active = YES; + [view.bottomAnchor constraintEqualToAnchor:safeAreaView.bottomAnchor].active = YES; + [NSLayoutConstraint constraintPinSubview:safeAreaView pinTop:NO topConstant:0 pinBottom:NO bottomConstant:0 pinLeft:YES leftConstant:0 pinRight:YES rightConstant:0]; + return safeAreaView; } #pragma mark - shadows diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.m b/MVMCoreUI/Utility/MVMCoreUIUtility.m index 4f150783..257014f5 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.m @@ -58,21 +58,13 @@ } + (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; - } + return UIEdgeInsetsMake(view.directionalLayoutMargins.top, view.directionalLayoutMargins.leading, view.directionalLayoutMargins.bottom, view.directionalLayoutMargins.trailing) } #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); - } + view.directionalLayoutMargins = NSDirectionalEdgeInsetsMake(top, leading, bottom, trailing); } #pragma mark - Formatting @@ -152,12 +144,9 @@ CGFloat topInset = scrollview.contentInset.top; CGFloat bottomInset = scrollview.contentInset.bottom; - // Updates for ios 11 - if (@available(iOS 11.0, *)) { - if (scrollview.contentInsetAdjustmentBehavior == UIScrollViewContentInsetAdjustmentAutomatic) { - topInset = scrollview.adjustedContentInset.top; - bottomInset = scrollview.adjustedContentInset.bottom; - } + if (scrollview.contentInsetAdjustmentBehavior == UIScrollViewContentInsetAdjustmentAutomatic) { + topInset = scrollview.adjustedContentInset.top; + bottomInset = scrollview.adjustedContentInset.bottom; } CGFloat remainingSpace = frameHeight - contentSizeHeight - topInset - bottomInset; From 38beb2c7faa28b3c0c7e41688ff6dec9027fadf0 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 17 Oct 2019 11:21:42 -0400 Subject: [PATCH 41/48] typo fix --- MVMCoreUI/Utility/MVMCoreUIUtility.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.m b/MVMCoreUI/Utility/MVMCoreUIUtility.m index 257014f5..48a7a6a1 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.m @@ -58,7 +58,7 @@ } + (UIEdgeInsets)getMarginsForView:(nullable UIView *)view { - return UIEdgeInsetsMake(view.directionalLayoutMargins.top, view.directionalLayoutMargins.leading, view.directionalLayoutMargins.bottom, view.directionalLayoutMargins.trailing) + return UIEdgeInsetsMake(view.directionalLayoutMargins.top, view.directionalLayoutMargins.leading, view.directionalLayoutMargins.bottom, view.directionalLayoutMargins.trailing); } #pragma mark - Setters From f267b98438dbd5711e8d0124a3959f499476aea1 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 17 Oct 2019 11:57:30 -0400 Subject: [PATCH 42/48] constraints added. changes made. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 35 ++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index c3879f96..a568622b 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -75,7 +75,7 @@ import MVMCore /// Color of the check mark. public var checkColor: UIColor = .black { didSet { - setshapeLayerStrokeColor(checkColor) + setShapeLayerStrokeColor(checkColor) } } @@ -115,6 +115,21 @@ import MVMCore } } + //-------------------------------------------------- + // MARK: - Constraints + //-------------------------------------------------- + + private var heightConstraint: NSLayoutConstraint? + private var widthConstraint: NSLayoutConstraint? + + /// Updates the height and width anchors of the Checkbox with the assigned value. + public var heigthWidthConstant: Int = Checkbox.defaultHeightWidth { + didSet { + heightConstraint?.constant = heigthWidthConstant + widthConstraint?.constant = heigthWidthConstant + } + } + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -170,9 +185,15 @@ import MVMCore open func setupView() { + guard constraints.isEmpty else { return } + isUserInteractionEnabled = true translatesAutoresizingMaskIntoConstraints = false backgroundColor = .clear + + widthConstraint = widthAnchor.constraint(equalToConstant: Checkbox.defaultHeightWidth) + heightConstraint = heightAnchor.constraint(equalToConstant: Checkbox.defaultHeightWidth) + heightWidthIsActive(true) } //-------------------------------------------------- @@ -301,16 +322,16 @@ import MVMCore layer.borderColor = borderColor.cgColor backgroundColor = isSelected ? checkedBackgroundColor : unCheckedBackgroundColor alpha = 1.0 - setshapeLayerStrokeColor(checkColor) + setShapeLayerStrokeColor(checkColor) } else { layer.borderColor = UIColor.mfSilver().cgColor backgroundColor = .clear alpha = DisableOppacity - setshapeLayerStrokeColor(UIColor.mfSilver()) + setShapeLayerStrokeColor(UIColor.mfSilver()) } } - private func setshapeLayerStrokeColor(_ color: UIColor) { + private func setShapeLayerStrokeColor(_ color: UIColor) { if let shapeLayer = shapeLayer { CATransaction.withDisabledAnimations { @@ -319,6 +340,12 @@ import MVMCore } } + public func heightWidthIsActive(_ isActive: Bool) { + + heightConstraint?.isActive = isActive + widthConstraint?.isActive = isActive + } + //-------------------------------------------------- // MARK: - UITouch //-------------------------------------------------- From 2fdc4795f40859be9cd9ade4d4f99a10f25998f2 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 17 Oct 2019 12:00:44 -0400 Subject: [PATCH 43/48] correcting type. --- MVMCoreUI/Atoms/Views/Checkbox.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index a568622b..d139f130 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -123,7 +123,7 @@ import MVMCore private var widthConstraint: NSLayoutConstraint? /// Updates the height and width anchors of the Checkbox with the assigned value. - public var heigthWidthConstant: Int = Checkbox.defaultHeightWidth { + public var heigthWidthConstant: CGFloat = Checkbox.defaultHeightWidth { didSet { heightConstraint?.constant = heigthWidthConstant widthConstraint?.constant = heigthWidthConstant @@ -140,7 +140,6 @@ import MVMCore accessibilityTraits = .button accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "checkbox_action_hint") updateAccessibilityLabel() - setupView() } From b5dcf68c5d4344e346d71479dbc2d7b4228c99e5 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 17 Oct 2019 12:17:14 -0400 Subject: [PATCH 44/48] refactoring taxtcontainer. --- MVMCoreUI/Atoms/Views/Label.swift | 44 ++++++++++++------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index cab341b1..cf1ed6f4 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -505,10 +505,12 @@ public typealias ActionBlock = () -> () let accessibleAction = customAccessibilityAction(range: range) clauses.append(ActionableClause(range: range, actionBlock: actionBlock, accessibilityID: accessibleAction?.hash ?? -1)) } - - public static func boundingRect(forCharacterRange range: NSRange, in label: Label) -> CGRect { - - guard let attributedText = label.attributedText else { return CGRect() } + + /// Provides a text container in memory of how the text would appear on screen. + func abstractTextContainer() -> NSTextContainer? { + + // Must configure the attributed string to translate what would appear on screen to accurately analyze. + guard let attributedText = attributedText else { return nil } let paragraph = NSMutableParagraphStyle() paragraph.alignment = label.textAlignment @@ -524,9 +526,16 @@ public typealias ActionBlock = () -> () textStorage.addLayoutManager(layoutManager) textContainer.lineFragmentPadding = 0.0 - textContainer.lineBreakMode = label.lineBreakMode - textContainer.maximumNumberOfLines = label.numberOfLines - textContainer.size = label.bounds.size + textContainer.lineBreakMode = lineBreakMode + textContainer.maximumNumberOfLines = numberOfLines + textContainer.size = bounds.size + + return textContainer + } + + public static func boundingRect(forCharacterRange range: NSRange, in label: Label) -> CGRect { + + let textContainer = abstractTextContainer() var glyphRange = NSRange() @@ -669,26 +678,7 @@ extension UITapGestureRecognizer { return true } - // Must configure the attributed string to translate what would appear on screen to accurately analyze. - guard let attributedText = label.attributedText else { return false } - - let paragraph = NSMutableParagraphStyle() - paragraph.alignment = label.textAlignment - - let stagedAttributedString = NSMutableAttributedString(attributedString: attributedText) - stagedAttributedString.addAttributes([NSAttributedString.Key.paragraphStyle: paragraph], range: NSRange(location: 0, length: attributedText.string.count)) - - let textStorage = NSTextStorage(attributedString: stagedAttributedString) - let layoutManager = NSLayoutManager() - let textContainer = NSTextContainer(size: .zero) - - layoutManager.addTextContainer(textContainer) - textStorage.addLayoutManager(layoutManager) - - textContainer.lineFragmentPadding = 0.0 - textContainer.lineBreakMode = label.lineBreakMode - textContainer.maximumNumberOfLines = label.numberOfLines - textContainer.size = label.bounds.size + guard let textContainer = label.abstractTextContainer() else { return false } let indexOfGlyph = layoutManager.glyphIndex(for: location(in: label), in: textContainer) From 73ac4b932bb37dc413b829296d40a017d63ef599 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 17 Oct 2019 12:39:05 -0400 Subject: [PATCH 45/48] refacgtorerd. --- MVMCoreUI/Atoms/Views/Label.swift | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index cf1ed6f4..fefd686d 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -506,14 +506,17 @@ public typealias ActionBlock = () -> () clauses.append(ActionableClause(range: range, actionBlock: actionBlock, accessibilityID: accessibleAction?.hash ?? -1)) } - /// Provides a text container in memory of how the text would appear on screen. - func abstractTextContainer() -> NSTextContainer? { + /** + Provides a text container and layout manager of how the text would appear on screen. + They are used in tandem to derive low-level TextKit results of the label. + */ + public func abstractTextContainer() -> (NSTextContainer, NSLayoutManager)? { // Must configure the attributed string to translate what would appear on screen to accurately analyze. guard let attributedText = attributedText else { return nil } let paragraph = NSMutableParagraphStyle() - paragraph.alignment = label.textAlignment + paragraph.alignment = textAlignment let stagedAttributedString = NSMutableAttributedString(attributedString: attributedText) stagedAttributedString.addAttributes([NSAttributedString.Key.paragraphStyle: paragraph], range: NSRange(location: 0, length: attributedText.string.count)) @@ -530,12 +533,14 @@ public typealias ActionBlock = () -> () textContainer.maximumNumberOfLines = numberOfLines textContainer.size = bounds.size - return textContainer + return (textContainer, layoutManager) } public static func boundingRect(forCharacterRange range: NSRange, in label: Label) -> CGRect { - let textContainer = abstractTextContainer() + guard let abstractContainer = label.abstractTextContainer() else { return CGRect() } + let textContainer = abstractContainer.0 + let layoutManager = abstractContainer.1 var glyphRange = NSRange() @@ -678,7 +683,9 @@ extension UITapGestureRecognizer { return true } - guard let textContainer = label.abstractTextContainer() else { return false } + guard let abstractContainer = label.abstractTextContainer() else { return false } + let textContainer = abstractContainer.0 + let layoutManager = abstractContainer.1 let indexOfGlyph = layoutManager.glyphIndex(for: location(in: label), in: textContainer) From 6d52663b4f66bd8ee7ae6760e2ff4b84c6d371c7 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 17 Oct 2019 14:06:01 -0400 Subject: [PATCH 46/48] fixed small error in refactor. --- MVMCoreUI/Atoms/Views/Label.swift | 4 ++-- MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index fefd686d..6fc496bd 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -510,7 +510,7 @@ public typealias ActionBlock = () -> () Provides a text container and layout manager of how the text would appear on screen. They are used in tandem to derive low-level TextKit results of the label. */ - public func abstractTextContainer() -> (NSTextContainer, NSLayoutManager)? { + public func abstractTextContainer() -> (NSTextContainer, NSLayoutManager, NSTextStorage)? { // Must configure the attributed string to translate what would appear on screen to accurately analyze. guard let attributedText = attributedText else { return nil } @@ -533,7 +533,7 @@ public typealias ActionBlock = () -> () textContainer.maximumNumberOfLines = numberOfLines textContainer.size = bounds.size - return (textContainer, layoutManager) + return (textContainer, layoutManager, textStorage) } public static func boundingRect(forCharacterRange range: NSRange, in label: Label) -> CGRect { diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index 568a551c..2e8b9bfc 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -126,14 +126,12 @@ import UIKit /// NOTE: Should only be called when displayed or about to be displayed. public func alignAccessoryToHero() { + // Layout call required to force draw in memory to get dinmensions of subviews. layoutIfNeeded() guard let heroLabel = findHeroLabel(views: contentView.subviews), let hero = heroLabel.hero else { return } let rect = Label.boundingRect(forCharacterRange: NSRange(location: hero, length: 1), in: heroLabel) - let rectView = UIView(frame: rect) - heroLabel.addSubview(rectView) - accessoryView?.center.y = contentView.convert(rectView.center, from: heroLabel).y + accessoryView?.center.y = contentView.convert(UIView(frame: rect).center, from: heroLabel).y heroAccessoryCenter = accessoryView?.center - rectView.removeFromSuperview() } /// Traverses the view hierarchy for a 🦸‍♂️heroic Label. From f067a20ba97734c8c82a044fe4630aaeac014dbb Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 18 Oct 2019 08:47:14 -0400 Subject: [PATCH 47/48] hero stuff. --- MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift | 10 ++++++++-- MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h | 3 --- MVMCoreUI/Templates/MoleculeListCellProtocol.h | 3 +++ MVMCoreUI/Templates/MoleculeListTemplate.swift | 4 ++-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index 2e8b9bfc..2ae52775 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -56,6 +56,7 @@ import UIKit open override func layoutSubviews() { super.layoutSubviews() + // Ensures accessory view aligns to the center y derived from the if let center = heroAccessoryCenter { accessoryView?.center.y = center.y } @@ -83,6 +84,11 @@ import UIKit bottomSeparatorView?.hide() } + public func willDisplay() { + + alignAccessoryToHero() + } + // MARK: - Inits public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -126,7 +132,7 @@ import UIKit /// NOTE: Should only be called when displayed or about to be displayed. public func alignAccessoryToHero() { - // Layout call required to force draw in memory to get dinmensions of subviews. + // Layout call required to force draw in memory to get dimensions of subviews. layoutIfNeeded() guard let heroLabel = findHeroLabel(views: contentView.subviews), let hero = heroLabel.hero else { return } let rect = Label.boundingRect(forCharacterRange: NSRange(location: hero, length: 1), in: heroLabel) @@ -240,7 +246,7 @@ import UIKit // MARK: - Arrow /// Adds the standard mvm style caret to the accessory view - public func addCaretViewAccessory() { + @objc public func addCaretViewAccessory() { guard accessoryView == nil else { return } let width: CGFloat = 6 let height: CGFloat = 10 diff --git a/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h b/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h index 273329aa..a499eb7c 100644 --- a/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h +++ b/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h @@ -24,9 +24,6 @@ /// Resets to default state before set with json is called again. - (void)reset; -/// Currently designed for UITableViewCell. Aligns the accessory view with the center of a character in a line of text. -- (void)alignAccessoryToHero; - /// For the molecule list to load more efficiently. + (CGFloat)estimatedHeightForRow:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject; diff --git a/MVMCoreUI/Templates/MoleculeListCellProtocol.h b/MVMCoreUI/Templates/MoleculeListCellProtocol.h index 7603c820..8eae2e58 100644 --- a/MVMCoreUI/Templates/MoleculeListCellProtocol.h +++ b/MVMCoreUI/Templates/MoleculeListCellProtocol.h @@ -17,4 +17,7 @@ /// Handle action - (void)didSelectCellAtIndex:(nonnull NSIndexPath *)indexPath delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData; +/// Currently designed for UITableViewCell. Aligns the accessory view with the center of a character in a line of text. +- (void)willDisplay; + @end diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index 84a7e64b..b400f0a9 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -89,8 +89,8 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { open override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { - if cell.accessoryView != nil, let protocolCell = cell as? (MoleculeTableViewCell & MVMCoreUIMoleculeViewProtocol) { - protocolCell.alignAccessoryToHero() + if let protocolCell = cell as? MoleculeListCellProtocol { + protocolCell.willDisplay?() } } From 0bb1debc77500bfa1b4d833b4800db334ab3ff40 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 18 Oct 2019 10:28:22 -0400 Subject: [PATCH 48/48] no comment. --- MVMCoreUI/Templates/MoleculeListCellProtocol.h | 1 - 1 file changed, 1 deletion(-) diff --git a/MVMCoreUI/Templates/MoleculeListCellProtocol.h b/MVMCoreUI/Templates/MoleculeListCellProtocol.h index 8eae2e58..3fa19a02 100644 --- a/MVMCoreUI/Templates/MoleculeListCellProtocol.h +++ b/MVMCoreUI/Templates/MoleculeListCellProtocol.h @@ -17,7 +17,6 @@ /// Handle action - (void)didSelectCellAtIndex:(nonnull NSIndexPath *)indexPath delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData; -/// Currently designed for UITableViewCell. Aligns the accessory view with the center of a character in a line of text. - (void)willDisplay; @end