From 540439709b0d7f4d95e52cf550e4182af800ca21 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 8 Jul 2019 16:35:28 -0400 Subject: [PATCH 01/57] Updated Label to account for situations where the text will have an image attachment. There is some bug that affects how the TextContainer looks at multiline text. --- MVMCoreUI/Atoms/Views/Label.swift | 47 ++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 10b9220e..b1e8c4ed 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -26,6 +26,8 @@ public typealias ActionBlock = () -> Void public var sizeObject: MFSizeObject? public var scaleSize: NSNumber? + fileprivate var hasAttachmentImage = false + // Used for scaling the font in updateView. private var originalAttributedString: NSAttributedString? @@ -223,6 +225,21 @@ public typealias ActionBlock = () -> Void attributedString.removeAttribute(.foregroundColor, range: range) attributedString.addAttribute(.foregroundColor, value: UIColor.mfGet(forHex: colorHex), range: range) } + case "externalLink": + let fontSize = (attribute["size"] as? CGFloat ?? label.font.pointSize) * 0.8 + + let imageAttachment = NSTextAttachment() + imageAttachment.image = MVMCoreUIUtility.imageNamed("externalLink") + imageAttachment.bounds = CGRect(x: 0, y: 0, width: fontSize, height: fontSize) + + let mutableAttributedString = NSMutableAttributedString() + mutableAttributedString.append(NSAttributedString(string: " ")) + mutableAttributedString.append(NSAttributedString(attachment: imageAttachment)) + + attributedString.insert(mutableAttributedString, at: location) + + (label as? Label)?.hasAttachmentImage = true + case "font": if let fontStyle = attribute.optionalStringForKey("style") { let styles = MFStyler.styleGetAttributedString("0", withStyle: fontStyle) @@ -342,13 +359,12 @@ public typealias ActionBlock = () -> Void } } - ///Appends an external link image to the end of the attributed string. public func addExternalLinkIcon() { let size = round(font.pointSize * 0.8) - guard let attributedText = self.attributedText else { return } + guard let attributedText = attributedText else { return } let fullString = NSMutableAttributedString(attributedString: attributedText) @@ -359,6 +375,8 @@ public typealias ActionBlock = () -> Void fullString.append(NSAttributedString(string: " ")) fullString.append(NSAttributedString(attachment: imageAttachment)) self.attributedText = fullString + + hasAttachmentImage = true } } @@ -369,6 +387,7 @@ extension Label { text = nil attributedText = nil originalAttributedString = nil + hasAttachmentImage = false styleB2(true) } @@ -489,11 +508,25 @@ extension UITapGestureRecognizer { return true } - guard let attributedText = label.attributedText else { return false } + guard let attributedText = label.attributedText, let font = label.font else { return false } + + var fontToAnalyze: UIFont? = font + + // Necessary where label text is not consistent in font. + for attr in attributedText.attributes(at: targetRange.location, effectiveRange: nil) { + if attr.key == NSAttributedString.Key.font { + fontToAnalyze = attr.value as? UIFont + } + } + + let range = label.hasAttachmentImage ? NSRange(location: 0, length: attributedText.length) : targetRange + + let mutableAttribString = NSMutableAttributedString(attributedString: attributedText) + mutableAttribString.addAttributes([NSAttributedString.Key.font: fontToAnalyze as Any], range: range) let layoutManager = NSLayoutManager() let textContainer = NSTextContainer(size: .zero) - let textStorage = NSTextStorage(attributedString: attributedText) + let textStorage = NSTextStorage(attributedString: mutableAttribString) layoutManager.addTextContainer(textContainer) textStorage.addLayoutManager(layoutManager) @@ -503,8 +536,8 @@ extension UITapGestureRecognizer { textContainer.maximumNumberOfLines = label.numberOfLines textContainer.size = label.bounds.size - let indexOfCharacter = layoutManager.characterIndex(for: location(in: label), in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil) - - return NSLocationInRange(indexOfCharacter, targetRange) + let indexOfGlyph = layoutManager.glyphIndex(for: location(in: label), in: textContainer) + + return NSLocationInRange(indexOfGlyph, targetRange) } } From c06a15c91b96aca96e3665ca202b8ff93f399fa1 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 9 Jul 2019 10:53:29 -0400 Subject: [PATCH 02/57] Added insert external link functionality. Refactored code. --- MVMCoreUI/Atoms/Views/Label.swift | 72 +++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index b1e8c4ed..186c24c8 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -18,6 +18,7 @@ public typealias ActionBlock = () -> Void //------------------------------------------------------ public var makeWholeViewClickable = false + fileprivate var hasAttachmentImage = false /// Set this property if you want updateView to update the font based on this standard and the size passed in. public var standardFontSize: CGFloat = 0.0 @@ -26,8 +27,6 @@ public typealias ActionBlock = () -> Void public var sizeObject: MFSizeObject? public var scaleSize: NSNumber? - fileprivate var hasAttachmentImage = false - // Used for scaling the font in updateView. private var originalAttributedString: NSAttributedString? @@ -226,18 +225,14 @@ public typealias ActionBlock = () -> Void attributedString.addAttribute(.foregroundColor, value: UIColor.mfGet(forHex: colorHex), range: range) } case "externalLink": - let fontSize = (attribute["size"] as? CGFloat ?? label.font.pointSize) * 0.8 + let fontSize = attribute["size"] as? CGFloat ?? label.font.pointSize + let imageAttachment = Label.getTextAttachmentImage(dimension: fontSize) - let imageAttachment = NSTextAttachment() - imageAttachment.image = MVMCoreUIUtility.imageNamed("externalLink") - imageAttachment.bounds = CGRect(x: 0, y: 0, width: fontSize, height: fontSize) - - let mutableAttributedString = NSMutableAttributedString() - mutableAttributedString.append(NSAttributedString(string: " ")) - mutableAttributedString.append(NSAttributedString(attachment: imageAttachment)) - - attributedString.insert(mutableAttributedString, at: location) + let mutableString = NSMutableAttributedString() + mutableString.append(NSAttributedString(string: " ")) + mutableString.append(NSAttributedString(attachment: imageAttachment)) + attributedString.insert(mutableString, at: location) (label as? Label)?.hasAttachmentImage = true case "font": @@ -359,24 +354,55 @@ public typealias ActionBlock = () -> Void } } - ///Appends an external link image to the end of the attributed string. - public func addExternalLinkIcon() { - - let size = round(font.pointSize * 0.8) + /** + Appends an external link image to the end of the attributed string. + Will provide one whitespace to the left of the icon + */ + public func appendExternalLinkIcon() { guard let attributedText = attributedText else { return } - let fullString = NSMutableAttributedString(attributedString: attributedText) + let mutableString = NSMutableAttributedString(attributedString: attributedText) + + mutableString.append(NSAttributedString(string: " ")) + mutableString.append(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize))) + self.attributedText = mutableString + + hasAttachmentImage = true + } + + /** + Insert external link icon anywhere within text of Label. + + - Parameters: + - index: Location within the associated text to insert an external Link Icon + - Note: You will need to increment your current index by 2 for any changes to the text after inserting an icon. + Each icon insertion adds 2 additional characters to the overall text length. + */ + public func insertExternalLinkIcon(at index: Int) { + + guard let attributedText = attributedText, index <= attributedText.string.count && index >= 0 else { return } + + let mutableString = NSMutableAttributedString(attributedString: attributedText) + + if index != 0 { + mutableString.insert(NSAttributedString(string: " "), at: index - 1) + } + mutableString.insert(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)), at: index) + self.attributedText = mutableString + + hasAttachmentImage = true + } + + static func getTextAttachmentImage(dimension: CGFloat) -> NSTextAttachment { + + let dimension = round(dimension * 0.8) let imageAttachment = NSTextAttachment() imageAttachment.image = MVMCoreUIUtility.imageNamed("externalLink") - imageAttachment.bounds = CGRect(x: 0, y: 0, width: size, height: size) + imageAttachment.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension) - fullString.append(NSAttributedString(string: " ")) - fullString.append(NSAttributedString(attachment: imageAttachment)) - self.attributedText = fullString - - hasAttachmentImage = true + return imageAttachment } } From f67392eb6981d84f53685e2a1a681778713a39b5 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 10 Jul 2019 09:04:29 -0400 Subject: [PATCH 03/57] Beginning stages of accessibility. --- MVMCoreUI/Atoms/Views/Label.swift | 57 ++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 186c24c8..5a189cb5 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -14,7 +14,7 @@ public typealias ActionBlock = () -> Void @objcMembers open class Label: UILabel, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol, MFButtonProtocol { //------------------------------------------------------ - // MARK: - General Properties + // MARK: - Properties //------------------------------------------------------ public var makeWholeViewClickable = false @@ -63,6 +63,7 @@ public typealias ActionBlock = () -> Void numberOfLines = 0 lineBreakMode = .byWordWrapping translatesAutoresizingMaskIntoConstraints = false + isAccessibilityElement = false let tapGesture = UITapGestureRecognizer(target: self, action: #selector(textLinkTapped(_:))) tapGesture.numberOfTapsRequired = 1 @@ -152,7 +153,7 @@ public typealias ActionBlock = () -> Void } //------------------------------------------------------ - // MARK: - Functions + // MARK: - Style //------------------------------------------------------ @objc public static func setLabel(_ label: UILabel?, withHTML html: String?) { @@ -272,12 +273,6 @@ public typealias ActionBlock = () -> Void } } - - - //------------------------------------------------------ - // MARK: - Methods - //------------------------------------------------------ - @objc public func styleH1(_ scale: Bool) { MFStyler.styleLabelH1(self, genericScaling: false) setScale(scale) @@ -567,3 +562,49 @@ extension UITapGestureRecognizer { return NSLocationInRange(indexOfGlyph, targetRange) } } + +// MARK: - Accessibility +extension Label { + + override open func accessibilityActivate() -> Bool { + let point = accessibilityActivationPoint + + return true + } + + open override func accessibilityElementDidBecomeFocused() { + <#code#> + } + + open override func accessibilityElementCount() -> Int { + return accessibleClauses.count + } + + open override func accessibilityElement(at index: Int) -> Any? { + return accessibleClauses[index] + } + + open override func index(ofAccessibilityElement element: Any) -> Int { + return accessibleClauses.firstIndex(of: element as! UIAccessibilityElement)! + } + + var accessibleClauses: [UIAccessibilityElement] { + + var elements = [UIAccessibilityElement]() + + for clause in clauses { + + let element = UIAccessibilityElement(accessibilityContainer: self) + let rect = CGRect(x: 10, y: 10, width: 100, height: 30) + element.accessibilityFrame = rect +// element.accessibilityFrame = convert(conceptualSize(range: clause.range)!, to: nil) + element.accessibilityFrameInContainerSpace = rect + element.accessibilityLabel = "Testing" + element.accessibilityTraits = .button + element.isAccessibilityElement = true + elements.append(element) + } + accessibilityElements = elements + return elements + } +} From 244e3c0df3146c90f686dd42db58c9ef4acb1cd4 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 10 Jul 2019 13:15:35 -0400 Subject: [PATCH 04/57] Generally functioning. A ways to go. --- MVMCoreUI/Atoms/Views/Label.swift | 61 +++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 5a189cb5..38fef66f 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -40,7 +40,16 @@ public typealias ActionBlock = () -> Void //------------------------------------------------------ public var clauses: [ActionableClause] = [] { - didSet { isUserInteractionEnabled = !clauses.isEmpty } + didSet { + isUserInteractionEnabled = !clauses.isEmpty + + // Accessibility + let element = UIAccessibilityElement(accessibilityContainer: self) + element.accessibilityFrameInContainerSpace = convert(boundingRect(forCharacterRange: clauses.last!.range!), to: nil) //CGRect(x: 10, y: 10, width: 100, height: 30) + element.accessibilityLabel = "Testing" + element.accessibilityTraits = .button + accessibilityElements?.append(element) + } } /// Used for tappable links in the text. @@ -64,10 +73,7 @@ public typealias ActionBlock = () -> Void lineBreakMode = .byWordWrapping translatesAutoresizingMaskIntoConstraints = false isAccessibilityElement = false - - let tapGesture = UITapGestureRecognizer(target: self, action: #selector(textLinkTapped(_:))) - tapGesture.numberOfTapsRequired = 1 - addGestureRecognizer(tapGesture) + accessibilityElements = [] } @objc public init() { @@ -410,6 +416,7 @@ extension Label { originalAttributedString = nil hasAttachmentImage = false styleB2(true) + accessibilityElements = [] } @objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { @@ -450,6 +457,7 @@ extension Label { } self.attributedText = mutableAttributedString +// accessibleClauses = [] clauses = [] } @@ -567,38 +575,36 @@ extension UITapGestureRecognizer { extension Label { override open func accessibilityActivate() -> Bool { - let point = accessibilityActivationPoint - +// let point = accessibilityActivationPoint return true } open override func accessibilityElementDidBecomeFocused() { - <#code#> + } open override func accessibilityElementCount() -> Int { - return accessibleClauses.count + return accessibilityElements?.count ?? 0 } open override func accessibilityElement(at index: Int) -> Any? { - return accessibleClauses[index] + return accessibilityElements?[index] } open override func index(ofAccessibilityElement element: Any) -> Int { - return accessibleClauses.firstIndex(of: element as! UIAccessibilityElement)! + return 0//accessibilityElements?.firstIndex(of: element as! UIAccessibilityElement)! } + /* var accessibleClauses: [UIAccessibilityElement] { var elements = [UIAccessibilityElement]() - for clause in clauses { - let element = UIAccessibilityElement(accessibilityContainer: self) - let rect = CGRect(x: 10, y: 10, width: 100, height: 30) - element.accessibilityFrame = rect +// let rect = CGRect(x: 10, y: 10, width: 100, height: 30) + element.accessibilityFrame = convert(self.frame, to: nil) // element.accessibilityFrame = convert(conceptualSize(range: clause.range)!, to: nil) - element.accessibilityFrameInContainerSpace = rect +// element.accessibilityFrameInContainerSpace = rect element.accessibilityLabel = "Testing" element.accessibilityTraits = .button element.isAccessibilityElement = true @@ -607,4 +613,27 @@ extension Label { accessibilityElements = elements return elements } + */ + + func boundingRect(forCharacterRange range: NSRange) -> CGRect? { + + guard let attributedText = attributedText else { return nil } + + let textStorage = NSTextStorage(attributedString: attributedText) + let layoutManager = NSLayoutManager() + + textStorage.addLayoutManager(layoutManager) + + let textContainer = NSTextContainer(size: bounds.size) + textContainer.lineFragmentPadding = 0.0 + + layoutManager.addTextContainer(textContainer) + + var glyphRange = NSRange() + + // Convert the range for glyphs. + layoutManager.characterRange(forGlyphRange: range, actualGlyphRange: &glyphRange) + + return layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer) + } } From 67754676067cbb02e70839804ea37654d2f94b09 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 11 Jul 2019 11:43:33 -0400 Subject: [PATCH 05/57] Accessibility update for Label and LabelWithInternalButton. --- MVMCoreUI/Atoms/Views/Label.swift | 118 ++++++------------ .../Atoms/Views/LabelWithInternalButton.swift | 6 +- .../Strings/en.lproj/Localizable.strings | 1 + 3 files changed, 45 insertions(+), 80 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 38fef66f..1b1d622e 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -40,22 +40,15 @@ public typealias ActionBlock = () -> Void //------------------------------------------------------ public var clauses: [ActionableClause] = [] { - didSet { - isUserInteractionEnabled = !clauses.isEmpty - - // Accessibility - let element = UIAccessibilityElement(accessibilityContainer: self) - element.accessibilityFrameInContainerSpace = convert(boundingRect(forCharacterRange: clauses.last!.range!), to: nil) //CGRect(x: 10, y: 10, width: 100, height: 30) - element.accessibilityLabel = "Testing" - element.accessibilityTraits = .button - accessibilityElements?.append(element) - } + didSet { isUserInteractionEnabled = !clauses.isEmpty } } /// Used for tappable links in the text. public struct ActionableClause { var range: NSRange? var actionBlock: ActionBlock? + var text: String? + var hash: Int = 0 func performAction() { actionBlock?() @@ -72,8 +65,7 @@ public typealias ActionBlock = () -> Void numberOfLines = 0 lineBreakMode = .byWordWrapping translatesAutoresizingMaskIntoConstraints = false - isAccessibilityElement = false - accessibilityElements = [] + accessibilityCustomActions = [] } @objc public init() { @@ -267,10 +259,14 @@ public typealias ActionBlock = () -> Void guard let actionLabel = label as? Label else { continue } actionLabel.addActionAttributes(range: range, string: attributedString) - actionLabel.clauses.append(ActionableClause(range: range, - actionBlock: actionLabel.createActionBlockFrom(actionMap: json, - additionalData: additionalData, - delegateObject: delegate))) + let accessibleAction = actionLabel.customAccessibilityAction(range: range) + let actionBlock = actionLabel.createActionBlockFrom(actionMap: json, additionalData: additionalData, delegateObject: delegate) + let actionableClause = ActionableClause(range: range, + actionBlock: actionBlock, + text: accessibleAction?.name ?? "", + hash: accessibleAction?.hash ?? -1) + actionLabel.clauses.append(actionableClause) + default: continue } @@ -416,7 +412,7 @@ extension Label { originalAttributedString = nil hasAttachmentImage = false styleB2(true) - accessibilityElements = [] + accessibilityCustomActions = [] } @objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { @@ -457,7 +453,7 @@ extension Label { } self.attributedText = mutableAttributedString -// accessibleClauses = [] + accessibilityElements = [] clauses = [] } @@ -495,7 +491,9 @@ extension Label { @objc public func addTappableLinkAttribute(range: NSRange, actionBlock: @escaping ActionBlock) { setActionAttributes(range: range) - clauses.append(ActionableClause(range: range, actionBlock: actionBlock)) + let actionText = NSString(string: text!).substring(with: range) + let accessibleAction = customAccessibilityAction(range: range) + clauses.append(ActionableClause(range: range, actionBlock: actionBlock, text: actionText, hash: accessibleAction!.hash)) } /** @@ -511,10 +509,10 @@ extension Label { @objc public func addTappableLinkAttribute(range: NSRange, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) { setActionAttributes(range: range) - clauses.append(ActionableClause(range: range, - actionBlock: createActionBlockFrom(actionMap: actionMap, - additionalData: additionalData, - delegateObject: delegateObject))) + let actionText = NSString(string: text!).substring(with: range) + let accessibleAction = customAccessibilityAction(range: range) + let actionBlock = createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject) + clauses.append(ActionableClause(range: range, actionBlock: actionBlock, text: actionText, hash: accessibleAction!.hash)) } @objc private func textLinkTapped(_ gesture: UITapGestureRecognizer) { @@ -574,66 +572,28 @@ extension UITapGestureRecognizer { // MARK: - Accessibility extension Label { - override open func accessibilityActivate() -> Bool { -// let point = accessibilityActivationPoint - return true - } - - open override func accessibilityElementDidBecomeFocused() { + func customAccessibilityAction(range: NSRange) -> UIAccessibilityCustomAction? { - } - - open override func accessibilityElementCount() -> Int { - return accessibilityElements?.count ?? 0 - } - - open override func accessibilityElement(at index: Int) -> Any? { - return accessibilityElements?[index] - } - - open override func index(ofAccessibilityElement element: Any) -> Int { - return 0//accessibilityElements?.firstIndex(of: element as! UIAccessibilityElement)! - } - - /* - var accessibleClauses: [UIAccessibilityElement] { - - var elements = [UIAccessibilityElement]() - for clause in clauses { - let element = UIAccessibilityElement(accessibilityContainer: self) -// let rect = CGRect(x: 10, y: 10, width: 100, height: 30) - element.accessibilityFrame = convert(self.frame, to: nil) -// element.accessibilityFrame = convert(conceptualSize(range: clause.range)!, to: nil) -// element.accessibilityFrameInContainerSpace = rect - element.accessibilityLabel = "Testing" - element.accessibilityTraits = .button - element.isAccessibilityElement = true - elements.append(element) + guard let text = text else { return nil } + + if accessibilityHint == nil { + accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "plan_selector_int_swipe_action_hint") } - accessibilityElements = elements - return elements + + let actionText = NSString(string: text).substring(with: range) + let accessibleAction = UIAccessibilityCustomAction(name: actionText, target: self, selector: #selector(accessibilityCustomAction(_:))) + accessibilityCustomActions?.append(accessibleAction) + + return accessibleAction } - */ - func boundingRect(forCharacterRange range: NSRange) -> CGRect? { + @objc public func accessibilityCustomAction(_ action: UIAccessibilityCustomAction) { - guard let attributedText = attributedText else { return nil } - - let textStorage = NSTextStorage(attributedString: attributedText) - let layoutManager = NSLayoutManager() - - textStorage.addLayoutManager(layoutManager) - - let textContainer = NSTextContainer(size: bounds.size) - textContainer.lineFragmentPadding = 0.0 - - layoutManager.addTextContainer(textContainer) - - var glyphRange = NSRange() - - // Convert the range for glyphs. - layoutManager.characterRange(forGlyphRange: range, actualGlyphRange: &glyphRange) - - return layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer) + for clause in clauses { + if action.hash == clause.hash { + clause.performAction() + return + } + } } } diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index 5cc6d50b..c8a83862 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -64,7 +64,11 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt if newActionBlock == nil { label?.clearActionableClauses() } else { - label?.clauses = [Label.ActionableClause(range: actionRange, actionBlock: newActionBlock)] + guard let label = label else { return } + + let accessibleAction = UIAccessibilityCustomAction(name: actionText ?? "", target: label, selector: #selector(label.accessibilityCustomAction(_:))) + label.clauses = [Label.ActionableClause(range: actionRange, actionBlock: newActionBlock, text: actionText ?? "", hash: accessibleAction.hash)] + label.accessibilityCustomActions = [accessibleAction] } } } diff --git a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings index 96088cab..bbf3f6d8 100644 --- a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings @@ -8,6 +8,7 @@ //// Accessibility "AccCloseButton" = "Close"; +"plan_selector_int_swipe_action_hint" = "swipe up or down to select action, then double tap to select."; // Tab "AccTab" = ", tab"; "AccTabHint" = "Double tap to select."; From 80c6e7e74ff283debbb9a92b2aaca036a93d4094 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 11 Jul 2019 12:00:49 -0400 Subject: [PATCH 06/57] Removed text from ActionableClause; unneeded. --- MVMCoreUI/Atoms/Views/Label.swift | 13 ++++--------- MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift | 6 +++++- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 1b1d622e..b46f8ac7 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -47,7 +47,7 @@ public typealias ActionBlock = () -> Void public struct ActionableClause { var range: NSRange? var actionBlock: ActionBlock? - var text: String? +// var text: String? var hash: Int = 0 func performAction() { @@ -261,10 +261,7 @@ public typealias ActionBlock = () -> Void actionLabel.addActionAttributes(range: range, string: attributedString) let accessibleAction = actionLabel.customAccessibilityAction(range: range) let actionBlock = actionLabel.createActionBlockFrom(actionMap: json, additionalData: additionalData, delegateObject: delegate) - let actionableClause = ActionableClause(range: range, - actionBlock: actionBlock, - text: accessibleAction?.name ?? "", - hash: accessibleAction?.hash ?? -1) + let actionableClause = ActionableClause(range: range, actionBlock: actionBlock, hash: accessibleAction?.hash ?? -1) actionLabel.clauses.append(actionableClause) default: @@ -491,9 +488,8 @@ extension Label { @objc public func addTappableLinkAttribute(range: NSRange, actionBlock: @escaping ActionBlock) { setActionAttributes(range: range) - let actionText = NSString(string: text!).substring(with: range) let accessibleAction = customAccessibilityAction(range: range) - clauses.append(ActionableClause(range: range, actionBlock: actionBlock, text: actionText, hash: accessibleAction!.hash)) + clauses.append(ActionableClause(range: range, actionBlock: actionBlock, hash: accessibleAction?.hash ?? -1)) } /** @@ -509,10 +505,9 @@ extension Label { @objc public func addTappableLinkAttribute(range: NSRange, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) { setActionAttributes(range: range) - let actionText = NSString(string: text!).substring(with: range) let accessibleAction = customAccessibilityAction(range: range) let actionBlock = createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject) - clauses.append(ActionableClause(range: range, actionBlock: actionBlock, text: actionText, hash: accessibleAction!.hash)) + clauses.append(ActionableClause(range: range, actionBlock: actionBlock, hash: accessibleAction?.hash ?? -1)) } @objc private func textLinkTapped(_ gesture: UITapGestureRecognizer) { diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index c8a83862..39b996a2 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -67,8 +67,12 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt guard let label = label else { return } let accessibleAction = UIAccessibilityCustomAction(name: actionText ?? "", target: label, selector: #selector(label.accessibilityCustomAction(_:))) - label.clauses = [Label.ActionableClause(range: actionRange, actionBlock: newActionBlock, text: actionText ?? "", hash: accessibleAction.hash)] + label.clauses = [Label.ActionableClause(range: actionRange, actionBlock: newActionBlock, hash: accessibleAction.hash)] label.accessibilityCustomActions = [accessibleAction] + + if label.accessibilityHint == nil { + label.accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "plan_selector_int_swipe_action_hint") + } } } } From 7a86febc7c8f7ce60fb46b0b182dfd7cf44231c5 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 25 Jul 2019 15:15:32 -0400 Subject: [PATCH 07/57] corrected logic error. --- MVMCoreUI/Atoms/Views/Label.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 186c24c8..c1ba5ef5 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -358,7 +358,7 @@ public typealias ActionBlock = () -> Void Appends an external link image to the end of the attributed string. Will provide one whitespace to the left of the icon */ - public func appendExternalLinkIcon() { + @objc public func appendExternalLinkIcon() { guard let attributedText = attributedText else { return } @@ -386,9 +386,9 @@ public typealias ActionBlock = () -> Void let mutableString = NSMutableAttributedString(attributedString: attributedText) if index != 0 { - mutableString.insert(NSAttributedString(string: " "), at: index - 1) + mutableString.insert(NSAttributedString(string: " "), at: index) } - mutableString.insert(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)), at: index) + mutableString.insert(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)), at: index + 1) self.attributedText = mutableString hasAttachmentImage = true From a47e8d4313e2237a829f05d5fadd5d659a548d1c Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 25 Jul 2019 16:47:14 -0400 Subject: [PATCH 08/57] Adding check to look for attachments and scale the accordingly. --- MVMCoreUI/Atoms/Views/Label.swift | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index c1ba5ef5..25409b3c 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -324,14 +324,26 @@ public typealias ActionBlock = () -> Void if let originalAttributedString = originalAttributedString { let attributedString = NSMutableAttributedString(attributedString: originalAttributedString) attributedString.removeAttribute(.font, range: NSRange(location: 0, length: attributedString.length)) - originalAttributedString.enumerateAttribute(.font, in: NSRange(location: 0, length: originalAttributedString.length), options: [], using: { value, range, stop in - // Loop the original attributed string, resize the fonts. + + // Loop the original attributed string, resize the fonts. + originalAttributedString.enumerateAttribute(.font, in: NSRange(location: 0, length: originalAttributedString.length), options: []) { value, range, stop in + if let fontObj = value as? UIFont, let stylerSize = MFStyler.sizeObjectGeneric(forCurrentDevice: fontObj.pointSize)?.getValueBased(onSize: size) { attributedString.addAttribute(.font, value: fontObj.withSize(stylerSize) as Any, range: range) } - }) + } + + // Loop the original attributed string, resize the image attachments. + originalAttributedString.enumerateAttribute(.attachment, in: NSRange(location: 0, length: originalAttributedString.length), options: []) { value, range, stop in + if value is NSTextAttachment, let attachment = value as? NSTextAttachment, + let stylerSize = MFStyler.sizeObjectGeneric(forCurrentDevice: attachment.bounds.width)?.getValueBased(onSize: size) { + + let dimension = round(stylerSize) + attachment.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension) + } + } attributedText = attributedString - } else if !MVMCoreGetterUtility.fequal(a: Float(standardFontSize), b: 0.0), let sizeObject: MFSizeObject = self.sizeObject ?? MFStyler.sizeObjectGeneric(forCurrentDevice: standardFontSize) { + } else if !MVMCoreGetterUtility.fequal(a: Float(standardFontSize), b: 0.0), let sizeObject = self.sizeObject ?? MFStyler.sizeObjectGeneric(forCurrentDevice: standardFontSize) { self.font = self.font.withSize(sizeObject.getValueBased(onSize: size)) } } From 81ccaa5bbd4a9cefefd59f03e69c83c654095b0f Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 26 Jul 2019 13:39:28 -0400 Subject: [PATCH 09/57] Restructuring the tappable text feature. Must account of the offset incurred by adding an extra space and image attachment to the overall length of the label. Included a sorting feature to ensure clauses array is always in ascending order by location. --- MVMCoreUI/Atoms/Views/Label.swift | 97 +++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 30 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index fd9349fe..5792f1c7 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -18,7 +18,9 @@ public typealias ActionBlock = () -> Void //------------------------------------------------------ public var makeWholeViewClickable = false - fileprivate var hasAttachmentImage = false + + /// Indication that attributed text attachment will affect range location of attributed text. + fileprivate var hasAttachmentImageInsideText = false /// Set this property if you want updateView to update the font based on this standard and the size passed in. public var standardFontSize: CGFloat = 0.0 @@ -40,7 +42,17 @@ public typealias ActionBlock = () -> Void //------------------------------------------------------ public var clauses: [ActionableClause] = [] { - didSet { isUserInteractionEnabled = !clauses.isEmpty } + didSet { + isUserInteractionEnabled = !clauses.isEmpty + if clauses.count > 1 { + clauses.sort{ first, second in + guard let firstLocation = first.range?.location, + let secondLocation = second.range?.location + else { return false } + return firstLocation < secondLocation + } + } + } } /// Used for tappable links in the text. @@ -212,6 +224,8 @@ public typealias ActionBlock = () -> Void let range = NSRange(location: location, length: length) + print(attributeType) + switch attributeType { case "underline": attributedString.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: range) @@ -233,7 +247,10 @@ public typealias ActionBlock = () -> Void mutableString.append(NSAttributedString(attachment: imageAttachment)) attributedString.insert(mutableString, at: location) - (label as? Label)?.hasAttachmentImage = true + + if location < attributedString.length { + (label as? Label)?.hasAttachmentImageInsideText = true + } case "font": if let fontStyle = attribute.optionalStringForKey("style") { @@ -332,19 +349,20 @@ public typealias ActionBlock = () -> Void attributedString.addAttribute(.font, value: fontObj.withSize(stylerSize) as Any, range: range) } } - + // Loop the original attributed string, resize the image attachments. originalAttributedString.enumerateAttribute(.attachment, in: NSRange(location: 0, length: originalAttributedString.length), options: []) { value, range, stop in if value is NSTextAttachment, let attachment = value as? NSTextAttachment, let stylerSize = MFStyler.sizeObjectGeneric(forCurrentDevice: attachment.bounds.width)?.getValueBased(onSize: size) { - + let dimension = round(stylerSize) attachment.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension) } } + attributedText = attributedString - } else if !MVMCoreGetterUtility.fequal(a: Float(standardFontSize), b: 0.0), let sizeObject = self.sizeObject ?? MFStyler.sizeObjectGeneric(forCurrentDevice: standardFontSize) { - self.font = self.font.withSize(sizeObject.getValueBased(onSize: size)) + } else if !MVMCoreGetterUtility.fequal(a: Float(standardFontSize), b: 0.0), let sizeObject = sizeObject ?? MFStyler.sizeObjectGeneric(forCurrentDevice: standardFontSize) { + font = font.withSize(sizeObject.getValueBased(onSize: size)) } } @@ -379,8 +397,6 @@ public typealias ActionBlock = () -> Void mutableString.append(NSAttributedString(string: " ")) mutableString.append(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize))) self.attributedText = mutableString - - hasAttachmentImage = true } /** @@ -403,7 +419,9 @@ public typealias ActionBlock = () -> Void mutableString.insert(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)), at: index + 1) self.attributedText = mutableString - hasAttachmentImage = true + if index < attributedText.length { + hasAttachmentImageInsideText = true + } } static func getTextAttachmentImage(dimension: CGFloat) -> NSTextAttachment { @@ -425,7 +443,7 @@ extension Label { text = nil attributedText = nil originalAttributedString = nil - hasAttachmentImage = false + hasAttachmentImageInsideText = false styleB2(true) } @@ -528,8 +546,36 @@ extension Label { @objc private func textLinkTapped(_ gesture: UITapGestureRecognizer) { + var offset = 0 + var attachmentLocations: [Int] = [] + var attachmentIndex = 0 + + // Used to identify all images attached in the label. + if hasAttachmentImageInsideText { + attributedText?.enumerateAttribute(.attachment, in: NSRange(location: 0, length: attributedText!.length), options: []) { value, range, stop in + guard value is NSTextAttachment else { return } + + attachmentLocations.append(range.location) + + if range.location == 0 { + offset = 1 + } + } + } + for clause in clauses { - if let range = clause.range, gesture.didTapAttributedTextInLabel(self, inRange: range) { + guard let range = clause.range else { return } + + // Must increment an offset becuase every image added to text interior increases text length by 1 or 2 depending on location. + if hasAttachmentImageInsideText { + if range.location > attachmentLocations[attachmentIndex] { + offset += 2 + attachmentIndex += 1 + } + } + + // This determines if we tapped on the desired range of text. + if gesture.didTapAttributedTextInLabel(self, inRange: range, offset: offset) { clause.performAction() return } @@ -540,31 +586,17 @@ extension Label { // MARK: - extension UITapGestureRecognizer { - func didTapAttributedTextInLabel(_ label: Label, inRange targetRange: NSRange) -> Bool { + func didTapAttributedTextInLabel(_ label: Label, inRange targetRange: NSRange, offset: Int) -> Bool { if label.makeWholeViewClickable { return true } - guard let attributedText = label.attributedText, let font = label.font else { return false } - - var fontToAnalyze: UIFont? = font - - // Necessary where label text is not consistent in font. - for attr in attributedText.attributes(at: targetRange.location, effectiveRange: nil) { - if attr.key == NSAttributedString.Key.font { - fontToAnalyze = attr.value as? UIFont - } - } - - let range = label.hasAttachmentImage ? NSRange(location: 0, length: attributedText.length) : targetRange - - let mutableAttribString = NSMutableAttributedString(attributedString: attributedText) - mutableAttribString.addAttributes([NSAttributedString.Key.font: fontToAnalyze as Any], range: range) - + guard let attributedText = label.attributedText else { return false } + + let textStorage = NSTextStorage(attributedString: attributedText) let layoutManager = NSLayoutManager() let textContainer = NSTextContainer(size: .zero) - let textStorage = NSTextStorage(attributedString: mutableAttribString) layoutManager.addTextContainer(textContainer) textStorage.addLayoutManager(layoutManager) @@ -576,6 +608,11 @@ extension UITapGestureRecognizer { let indexOfGlyph = layoutManager.glyphIndex(for: location(in: label), in: textContainer) + if label.hasAttachmentImageInsideText { + let location = targetRange.location + offset + return NSLocationInRange(indexOfGlyph, NSRange(location: location, length: targetRange.length)) + } + return NSLocationInRange(indexOfGlyph, targetRange) } } From 6dd7cab8f4808504b0e24d0641c4cedc5f51857c Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 26 Jul 2019 14:46:29 -0400 Subject: [PATCH 10/57] Comments added. Further logic added for adding image attachments. --- MVMCoreUI/Atoms/Views/Label.swift | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 5792f1c7..0dfd2ba1 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -413,15 +413,18 @@ public typealias ActionBlock = () -> Void let mutableString = NSMutableAttributedString(attributedString: attributedText) - if index != 0 { + if index == 0 { + mutableString.insert(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)), at: index) + } else { mutableString.insert(NSAttributedString(string: " "), at: index) + mutableString.insert(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)), at: index + 1) } - mutableString.insert(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)), at: index + 1) + self.attributedText = mutableString - if index < attributedText.length { - hasAttachmentImageInsideText = true - } +// if index < attributedText.length { +// hasAttachmentImageInsideText = true +// } } static func getTextAttachmentImage(dimension: CGFloat) -> NSTextAttachment { @@ -588,6 +591,7 @@ extension UITapGestureRecognizer { func didTapAttributedTextInLabel(_ label: Label, inRange targetRange: NSRange, offset: Int) -> Bool { + // There would only ever be one clause to act on. if label.makeWholeViewClickable { return true } From a21774b390dc62b784079d2e4229a0b3e76dc078 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 26 Jul 2019 15:21:01 -0400 Subject: [PATCH 11/57] comment & preventing leading text image due to problem. --- MVMCoreUI/Atoms/Views/Label.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 0dfd2ba1..0ae93988 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -406,10 +406,11 @@ public typealias ActionBlock = () -> Void - index: Location within the associated text to insert an external Link Icon - Note: You will need to increment your current index by 2 for any changes to the text after inserting an icon. Each icon insertion adds 2 additional characters to the overall text length. + This implies that you must insert exertal icons in the order they would appear with tappable links. */ public func insertExternalLinkIcon(at index: Int) { - guard let attributedText = attributedText, index <= attributedText.string.count && index >= 0 else { return } + guard let attributedText = attributedText, index <= attributedText.string.count && index > 0 else { return } let mutableString = NSMutableAttributedString(attributedString: attributedText) From 64e6b8bbfee91795ffeeeae9ee9e2ca15a521850 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 26 Jul 2019 15:21:27 -0400 Subject: [PATCH 12/57] preventing space if 0. --- MVMCoreUI/Atoms/Views/Label.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 0dfd2ba1..8ba09f36 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -243,7 +243,9 @@ public typealias ActionBlock = () -> Void let imageAttachment = Label.getTextAttachmentImage(dimension: fontSize) let mutableString = NSMutableAttributedString() - mutableString.append(NSAttributedString(string: " ")) + if location != 0 { + mutableString.append(NSAttributedString(string: " ")) + } mutableString.append(NSAttributedString(attachment: imageAttachment)) attributedString.insert(mutableString, at: location) From ddb4ba39d0065d7354323c05487a34b718203ef8 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Sat, 27 Jul 2019 17:00:27 -0400 Subject: [PATCH 13/57] Reworked mutable insert logic. Revised comments. --- MVMCoreUI/Atoms/Views/Label.swift | 43 ++++++++++--------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index d21f2195..2cdd6d01 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -406,28 +406,18 @@ public typealias ActionBlock = () -> Void - Parameters: - index: Location within the associated text to insert an external Link Icon - - Note: You will need to increment your current index by 2 for any changes to the text after inserting an icon. - Each icon insertion adds 2 additional characters to the overall text length. - This implies that you must insert exertal icons in the order they would appear with tappable links. + - Note: Each icon insertion adds 2 additional characters to the overall text length. + This means that you MUST insert icons and links in the order they would appear. */ public func insertExternalLinkIcon(at index: Int) { - guard let attributedText = attributedText, index <= attributedText.string.count && index > 0 else { return } - + guard let attributedText = attributedText, index <= attributedText.string.count && index >= 0 else { return } + let mutableString = NSMutableAttributedString(attributedString: attributedText) - - if index == 0 { - mutableString.insert(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)), at: index) - } else { - mutableString.insert(NSAttributedString(string: " "), at: index) - mutableString.insert(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)), at: index + 1) - } + mutableString.insert(NSAttributedString(string: " "), at: index) + mutableString.insert(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)), at: index + (index == 0 ? 0 : 1)) self.attributedText = mutableString - -// if index < attributedText.length { -// hasAttachmentImageInsideText = true -// } } static func getTextAttachmentImage(dimension: CGFloat) -> NSTextAttachment { @@ -521,9 +511,8 @@ extension Label { Provides an actionable range of text. - Attention: This method expects text to be set first. Otherwise, it will do nothing. - - Parameters: - - range: The range of text to be tapped. - - actionBlock: The code triggered when tapping the range of text. + - parameter range: The range of text to be tapped. + - parameter actionBlock: The code triggered when tapping the range of text. */ @objc public func addTappableLinkAttribute(range: NSRange, actionBlock: @escaping ActionBlock) { @@ -535,11 +524,10 @@ extension Label { Provides an actionable range of text. - Attention: This method expects text to be set first. Otherwise, it will do nothing. - - Parameters: - - range: The range of text to be tapped. - - actionMap: - - delegate: - - additionalData: + - parameter range: The range of text to be tapped. + - parameter actionMap: + - parameter delegate: + - parameter additionalData: */ @objc public func addTappableLinkAttribute(range: NSRange, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) { @@ -556,16 +544,12 @@ extension Label { var attachmentLocations: [Int] = [] var attachmentIndex = 0 - // Used to identify all images attached in the label. + // Used to identify all image attachments in the label. if hasAttachmentImageInsideText { attributedText?.enumerateAttribute(.attachment, in: NSRange(location: 0, length: attributedText!.length), options: []) { value, range, stop in guard value is NSTextAttachment else { return } attachmentLocations.append(range.location) - - if range.location == 0 { - offset = 1 - } } } @@ -615,6 +599,7 @@ extension UITapGestureRecognizer { let indexOfGlyph = layoutManager.glyphIndex(for: location(in: label), in: textContainer) + // If text attachment was inserted then extra indices must be accounted for. if label.hasAttachmentImageInsideText { let location = targetRange.location + offset return NSLocationInRange(indexOfGlyph, NSRange(location: location, length: targetRange.length)) From a2d49848225e08728cebc7c58fed02cfe356f9b9 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Sat, 27 Jul 2019 18:11:57 -0400 Subject: [PATCH 14/57] Currently investigate separate treatment for label image attachments in molecular structure. --- MVMCoreUI/Atoms/Views/Label.swift | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 2cdd6d01..69d37804 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -243,11 +243,17 @@ public typealias ActionBlock = () -> Void let imageAttachment = Label.getTextAttachmentImage(dimension: fontSize) let mutableString = NSMutableAttributedString() - if location != 0 { - mutableString.append(NSAttributedString(string: " ")) - } - mutableString.append(NSAttributedString(attachment: imageAttachment)) + let space = NSAttributedString(string: " ") + let attachment = NSAttributedString(attachment: imageAttachment) + if location == 0 { + mutableString.append(attachment) + mutableString.append(space) + } else { + mutableString.append(space) + mutableString.append(attachment) + } + attributedString.insert(mutableString, at: location) if location < attributedString.length { @@ -550,6 +556,9 @@ extension Label { guard value is NSTextAttachment else { return } attachmentLocations.append(range.location) +// if range.location == 0 { +// offset = 2 +// } } } From f6cd3aad18a5658197eca449d7d123891bb46e91 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 29 Jul 2019 09:35:00 -0400 Subject: [PATCH 15/57] Improved functioning of tap when adding icon before action. Appears to have separate behavior when done as a molecule than from source. --- MVMCoreUI/Atoms/Views/Label.swift | 36 +++++++++++++++---------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 69d37804..49ae467f 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -238,9 +238,10 @@ public typealias ActionBlock = () -> Void attributedString.removeAttribute(.foregroundColor, range: range) attributedString.addAttribute(.foregroundColor, value: UIColor.mfGet(forHex: colorHex), range: range) } - case "externalLink": + case "icon": let fontSize = attribute["size"] as? CGFloat ?? label.font.pointSize - let imageAttachment = Label.getTextAttachmentImage(dimension: fontSize) + let iconName = attribute["iconName"] as? String ?? "externalLink" + let imageAttachment = Label.getTextAttachmentImage(name: iconName, dimension: fontSize) let mutableString = NSMutableAttributedString() let space = NSAttributedString(string: " ") @@ -253,7 +254,7 @@ public typealias ActionBlock = () -> Void mutableString.append(space) mutableString.append(attachment) } - + attributedString.insert(mutableString, at: location) if location < attributedString.length { @@ -269,13 +270,13 @@ public typealias ActionBlock = () -> Void } else { let fontSize = attribute["size"] as? CGFloat var font: UIFont? - + if let fontName = attribute.optionalStringForKey("name") { font = MFFonts.mfFont(withName: fontName, size: fontSize ?? label.font.pointSize) } else if let fontSize = fontSize { font = label.font.withSize(fontSize) } - + if let font = font { attributedString.removeAttribute(.font, range: range) attributedString.addAttribute(.font, value: font, range: range) @@ -286,9 +287,9 @@ public typealias ActionBlock = () -> Void actionLabel.addActionAttributes(range: range, string: attributedString) actionLabel.clauses.append(ActionableClause(range: range, - actionBlock: actionLabel.createActionBlockFrom(actionMap: json, - additionalData: additionalData, - delegateObject: delegate))) + actionBlock: actionLabel.createActionBlockFrom(actionMap: json, + additionalData: additionalData, + delegateObject: delegate))) default: continue } @@ -297,8 +298,6 @@ public typealias ActionBlock = () -> Void } } - - //------------------------------------------------------ // MARK: - Methods //------------------------------------------------------ @@ -410,10 +409,9 @@ public typealias ActionBlock = () -> Void /** Insert external link icon anywhere within text of Label. - - Parameters: - - index: Location within the associated text to insert an external Link Icon - Note: Each icon insertion adds 2 additional characters to the overall text length. This means that you MUST insert icons and links in the order they would appear. + - parameter index: Location within the associated text to insert an external Link Icon */ public func insertExternalLinkIcon(at index: Int) { @@ -426,12 +424,12 @@ public typealias ActionBlock = () -> Void self.attributedText = mutableString } - static func getTextAttachmentImage(dimension: CGFloat) -> NSTextAttachment { + static func getTextAttachmentImage(name: String = "externalLink", dimension: CGFloat) -> NSTextAttachment { let dimension = round(dimension * 0.8) let imageAttachment = NSTextAttachment() - imageAttachment.image = MVMCoreUIUtility.imageNamed("externalLink") + imageAttachment.image = MVMCoreUIUtility.imageNamed(name) imageAttachment.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension) return imageAttachment @@ -556,18 +554,18 @@ extension Label { guard value is NSTextAttachment else { return } attachmentLocations.append(range.location) -// if range.location == 0 { -// offset = 2 -// } + if range.location == 0 { + offset = 2 + } } } for clause in clauses { guard let range = clause.range else { return } - // Must increment an offset becuase every image added to text interior increases text length by 1 or 2 depending on location. + // Must increment an offset becuase every image added to text interior increases text length by 2. if hasAttachmentImageInsideText { - if range.location > attachmentLocations[attachmentIndex] { + if range.location >= attachmentLocations[attachmentIndex] - range.length { offset += 2 attachmentIndex += 1 } From 905a2b948e698282c6e8ea32777253433e6909a9 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 29 Jul 2019 09:40:33 -0400 Subject: [PATCH 16/57] Added some sugar to typealias definition. --- MVMCoreUI/Atoms/Views/Label.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 49ae467f..4d3a0687 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -9,7 +9,7 @@ import MVMCore -public typealias ActionBlock = () -> Void +public typealias ActionBlock = () -> () @objcMembers open class Label: UILabel, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol, MFButtonProtocol { From ae92c9bbf8826821f20989aa64ede66d4f8e0e86 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 29 Jul 2019 09:41:42 -0400 Subject: [PATCH 17/57] composition. --- MVMCoreUI/Atoms/Views/Label.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 4d3a0687..e3618831 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -45,7 +45,7 @@ public typealias ActionBlock = () -> () didSet { isUserInteractionEnabled = !clauses.isEmpty if clauses.count > 1 { - clauses.sort{ first, second in + clauses.sort { first, second in guard let firstLocation = first.range?.location, let secondLocation = second.range?.location else { return false } From 248ee9a0d4e9a6fe3131d407f3f3f549f8f490fa Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 14 Aug 2019 10:05:44 -0400 Subject: [PATCH 18/57] Changed code to align with Android. --- .../Molecules/ActionDetailWithImage.swift | 50 +++++++------------ 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/MVMCoreUI/Molecules/ActionDetailWithImage.swift b/MVMCoreUI/Molecules/ActionDetailWithImage.swift index 4792dbd6..3804ed00 100644 --- a/MVMCoreUI/Molecules/ActionDetailWithImage.swift +++ b/MVMCoreUI/Molecules/ActionDetailWithImage.swift @@ -14,8 +14,7 @@ import UIKit // MARK: - Outlets //------------------------------------------------------ - let title = Label.commonLabelH3(true) - let message = Label.commonLabelB3(true) + let header = HeadlineBody(frame: .zero) let button = PrimaryButton.primaryTinyButton(false)! let imageLoader = MFLoadImageView(pinnedEdges: .all) let leftContainer = ViewConstrainingView.empty() @@ -24,7 +23,7 @@ import UIKit // MARK: - Properties //------------------------------------------------------ - var bottomTitlePadding: CGFloat = PaddingOne + var buttomHeaderPadding: CGFloat = PaddingTwo //------------------------------------------------------ // MARK: - Constraints @@ -32,7 +31,6 @@ import UIKit var imageLeadingConstraint: NSLayoutConstraint? var buttonTopConstraint: NSLayoutConstraint? - var messageTopConstraint: NSLayoutConstraint? //------------------------------------------------------ // MARK: - Initialization @@ -68,8 +66,7 @@ import UIKit addSubview(leftContainer) addSubview(imageLoader) - leftContainer.addSubview(title) - leftContainer.addSubview(message) + leftContainer.addSubview(header) leftContainer.addSubview(button) leftContainer.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true @@ -80,17 +77,11 @@ import UIKit leftContainerBottom.priority = UILayoutPriority(249) leftContainerBottom.isActive = true - title.topAnchor.constraint(equalTo: leftContainer.topAnchor).isActive = true - title.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true - leftContainer.trailingAnchor.constraint(equalTo: title.trailingAnchor).isActive = true - - messageTopConstraint = message.topAnchor.constraint(equalTo: title.bottomAnchor, constant: PaddingOne) - messageTopConstraint?.isActive = true - - message.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true - leftContainer.trailingAnchor.constraint(equalTo: message.trailingAnchor).isActive = true - - buttonTopConstraint = button.topAnchor.constraint(equalTo: message.bottomAnchor, constant: PaddingTwo) + header.topAnchor.constraint(equalTo: leftContainer.topAnchor).isActive = true + header.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true + leftContainer.trailingAnchor.constraint(equalTo: header.trailingAnchor).isActive = true + + buttonTopConstraint = button.topAnchor.constraint(equalTo: header.bottomAnchor, constant: PaddingTwo) buttonTopConstraint?.isActive = true button.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true @@ -112,15 +103,12 @@ import UIKit override open func updateView(_ size: CGFloat) { super.updateView(size) - title.updateView(size) - message.updateView(size) + header.updateView(size) button.updateView(size) imageLoader.updateView(size) leftContainer.updateView(size) - - messageTopConstraint?.constant = title.hasText && message.hasText ? bottomTitlePadding : 0 - buttonTopConstraint?.constant = message.hasText || title.hasText ? PaddingTwo : 0 + buttonTopConstraint?.constant = header.headlineLabel.hasText || header.messageLabel.hasText ? PaddingTwo : 0 } public override static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { @@ -133,20 +121,19 @@ import UIKit private func setDefaultState() { - title.font = MFStyler.fontH3() - message.font = MFStyler.fontB3() + header.headlineLabel.font = MFStyler.fontH3() + header.messageLabel.font = MFStyler.fontB3() button.setAsSecondaryCustom() button.isHidden = false imageLoader.imageView.contentMode = .scaleAspectFit imageLoader.addSizeConstraintsForAspectRatio = true - bottomTitlePadding = PaddingOne + buttomHeaderPadding = PaddingTwo } override open func reset() { super.reset() - title.reset() - message.reset() + header.reset() button.reset() imageLeadingConstraint?.constant = 16 imageLoader.reset() @@ -157,8 +144,7 @@ import UIKit open override func setAsMolecule() { super.setAsMolecule() - title.setAsMolecule() - message.setAsMolecule() + header.setAsMolecule() button.setAsMolecule() imageLoader.setAsMolecule() @@ -171,12 +157,12 @@ import UIKit guard let dictionary = json else { return } if let padding = dictionary.optionalCGFloatForKey("bottomTitlePadding") { - bottomTitlePadding = padding + buttomHeaderPadding = padding } - title.setWithJSON(dictionary.optionalDictionaryForKey("title"), delegateObject: delegateObject, additionalData: additionalData) - message.setWithJSON(dictionary.optionalDictionaryForKey("message"), delegateObject: delegateObject, additionalData: additionalData) + header.setWithJSON(dictionary.optionalDictionaryForKey("headlineBody"), delegateObject: delegateObject, additionalData: additionalData) imageLoader.setWithJSON(dictionary.optionalDictionaryForKey("image"), delegateObject: delegateObject, additionalData: additionalData) + if let buttonDictionary = dictionary.optionalDictionaryForKey("button") { button.setWithJSON(buttonDictionary, delegateObject: delegateObject, additionalData: additionalData) } else { From abde89f06fb5d5cb587b86a33a1fed568362cd3f Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 14 Aug 2019 12:58:46 -0400 Subject: [PATCH 19/57] Latest changes to account for variable icon locations and text alignments. --- MVMCoreUI/Atoms/Views/Label.swift | 47 +++++++++---------------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index bc79559a..b2984a57 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -20,7 +20,7 @@ public typealias ActionBlock = () -> () public var makeWholeViewClickable = false /// Indication that attributed text attachment will affect range location of attributed text. - fileprivate var hasAttachmentImageInsideText = false + public var hasAttachmentImageInsideText = false /// Set this property if you want updateView to update the font based on this standard and the size passed in. public var standardFontSize: CGFloat = 0.0 @@ -126,6 +126,7 @@ public typealias ActionBlock = () -> () return label } + /// H32 -> Legal @objc public static func commonLabelH32(_ scale: Bool) -> Label { let label = Label.label() label.styleH32(scale) @@ -153,12 +154,14 @@ public typealias ActionBlock = () -> () return label } + /// B20 -> Legal @objc public static func commonLabelB20(_ scale: Bool) -> Label { let label = Label.label() label.styleB20(scale) return label } + /// Default @objc open class func label() -> Label { return Label(frame: .zero) } @@ -556,35 +559,11 @@ extension Label { @objc private func textLinkTapped(_ gesture: UITapGestureRecognizer) { - var offset = 0 - var attachmentLocations: [Int] = [] - var attachmentIndex = 0 - - // Used to identify all image attachments in the label. - if hasAttachmentImageInsideText { - attributedText?.enumerateAttribute(.attachment, in: NSRange(location: 0, length: attributedText!.length), options: []) { value, range, stop in - guard value is NSTextAttachment else { return } - - attachmentLocations.append(range.location) - if range.location == 0 { - offset = 2 - } - } - } - for clause in clauses { guard let range = clause.range else { return } - // Must increment an offset becuase every image added to text interior increases text length by 2. - if hasAttachmentImageInsideText { - if range.location >= attachmentLocations[attachmentIndex] - range.length { - offset += 2 - attachmentIndex += 1 - } - } - // This determines if we tapped on the desired range of text. - if gesture.didTapAttributedTextInLabel(self, inRange: range, offset: offset) { + if gesture.didTapAttributedTextInLabel(self, inRange: range) { clause.performAction() return } @@ -595,7 +574,7 @@ extension Label { // MARK: - extension UITapGestureRecognizer { - func didTapAttributedTextInLabel(_ label: Label, inRange targetRange: NSRange, offset: Int) -> Bool { + func didTapAttributedTextInLabel(_ label: Label, inRange targetRange: NSRange) -> Bool { // There would only ever be one clause to act on. if label.makeWholeViewClickable { @@ -603,8 +582,14 @@ extension UITapGestureRecognizer { } guard let attributedText = label.attributedText else { return false } + + let paragraph = NSMutableParagraphStyle() + paragraph.alignment = label.textAlignment + + let newAttributedString = NSMutableAttributedString(attributedString: attributedText) + newAttributedString.addAttributes([NSAttributedString.Key.paragraphStyle: paragraph], range: NSRange(location: 0, length: attributedText.string.count)) - let textStorage = NSTextStorage(attributedString: attributedText) + let textStorage = NSTextStorage(attributedString: newAttributedString) let layoutManager = NSLayoutManager() let textContainer = NSTextContainer(size: .zero) @@ -618,12 +603,6 @@ extension UITapGestureRecognizer { let indexOfGlyph = layoutManager.glyphIndex(for: location(in: label), in: textContainer) - // If text attachment was inserted then extra indices must be accounted for. - if label.hasAttachmentImageInsideText { - let location = targetRange.location + offset - return NSLocationInRange(indexOfGlyph, NSRange(location: location, length: targetRange.length)) - } - return NSLocationInRange(indexOfGlyph, targetRange) } } From a4bec1d95617a1d0645e4c3bbcd4570405abdb43 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 19 Aug 2019 12:11:55 -0400 Subject: [PATCH 20/57] mild changes. --- MVMCoreUI/Atoms/Views/Label.swift | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index b2984a57..c46c16e8 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -237,9 +237,7 @@ public typealias ActionBlock = () -> () else { continue } let range = NSRange(location: location, length: length) - - print(attributeType) - + switch attributeType { case "underline": attributedString.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: range) @@ -581,15 +579,16 @@ 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 newAttributedString = NSMutableAttributedString(attributedString: attributedText) - newAttributedString.addAttributes([NSAttributedString.Key.paragraphStyle: paragraph], range: NSRange(location: 0, length: attributedText.string.count)) + let stagedAttributedString = NSMutableAttributedString(attributedString: attributedText) + stagedAttributedString.addAttributes([NSAttributedString.Key.paragraphStyle: paragraph], range: NSRange(location: 0, length: attributedText.string.count)) - let textStorage = NSTextStorage(attributedString: newAttributedString) + let textStorage = NSTextStorage(attributedString: stagedAttributedString) let layoutManager = NSLayoutManager() let textContainer = NSTextContainer(size: .zero) From b21664288d3e4da1d8b94fdb979bb132563d198c Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 19 Aug 2019 13:13:27 -0400 Subject: [PATCH 21/57] Allows JSON to set wholeViewIsClickable. --- MVMCoreUI/Atoms/Views/Label.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index c46c16e8..6054f644 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -205,6 +205,10 @@ public typealias ActionBlock = () -> () } } + if let wholeViewIsClickable = json?.boolForKey("makeWholeViewClickable") { + (label as? Label)?.makeWholeViewClickable = wholeViewIsClickable + } + if let backgroundColorHex = json?.optionalStringForKey(KeyBackgroundColor), !backgroundColorHex.isEmpty { label.backgroundColor = UIColor.mfGet(forHex: backgroundColorHex) } From f73d5e73a58a2257b5d3bde9b62317d073b311f4 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 22 Aug 2019 11:37:50 -0400 Subject: [PATCH 22/57] altered comments. --- 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 6054f644..590a8164 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -126,7 +126,7 @@ public typealias ActionBlock = () -> () return label } - /// H32 -> Legal + /// H32 -> Head @objc public static func commonLabelH32(_ scale: Bool) -> Label { let label = Label.label() label.styleH32(scale) @@ -154,7 +154,7 @@ public typealias ActionBlock = () -> () return label } - /// B20 -> Legal + /// B20 -> Body @objc public static func commonLabelB20(_ scale: Bool) -> Label { let label = Label.label() label.styleB20(scale) From 4bc22dbb8ecd552b7afbe920c5f243167e3155a2 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Mon, 26 Aug 2019 12:35:04 -0400 Subject: [PATCH 23/57] switches --- MVMCoreUI.xcodeproj/project.pbxproj | 10 ++- MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h | 3 +- MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m | 74 ++++++++++++++++++- .../SwitchLineItem.swift | 0 .../MVMCoreUIMoleculeMappingObject.m | 2 +- 5 files changed, 83 insertions(+), 6 deletions(-) rename MVMCoreUI/Molecules/{ => SwitchMolecules}/SwitchLineItem.swift (100%) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 22b92460..7a6d0181 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -391,6 +391,14 @@ path = FormUIHelpers; sourceTree = ""; }; + D224798823142BF2003FCCF9 /* SwitchMolecules */ = { + isa = PBXGroup; + children = ( + 016A1070228122180009D605 /* SwitchLineItem.swift */, + ); + path = SwitchMolecules; + sourceTree = ""; + }; D22D1F582204D2590077CEC0 /* LegacyControllers */ = { isa = PBXGroup; children = ( @@ -478,12 +486,12 @@ D29DF10E21E67A77003B2FB9 /* Molecules */ = { isa = PBXGroup; children = ( + D224798823142BF2003FCCF9 /* SwitchMolecules */, 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */, 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */, D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */, D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */, D282AACA2243C61700C46919 /* ButtonView.swift */, - 016A1070228122180009D605 /* SwitchLineItem.swift */, 01CA51B4229716F60071A6EE /* Switch.swift */, D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */, D2A514662213885800345BFB /* StandardHeaderView.swift */, diff --git a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h index 5591f595..ba36419e 100644 --- a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h +++ b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h @@ -8,10 +8,11 @@ #import +#import @import MVMCore.MVMCoreViewProtocol; typedef void(^ValueChangeBlock)(void); -@interface MVMCoreUISwitch : UIControl +@interface MVMCoreUISwitch : UIControl @property (assign, nonatomic, getter=isOn) BOOL on; @property (nullable, strong, nonatomic) UIColor *onTintColor; diff --git a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m index 9b9e0b96..95264f3c 100644 --- a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m +++ b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m @@ -14,6 +14,7 @@ #import #import #import +#import const CGFloat SwitchWidth = 42; const CGFloat SwitchHeight = 22; @@ -21,7 +22,7 @@ const CGFloat SwitchKnobWidth = 20; const CGFloat SwitchKnobHeight = 20; const CGFloat SwitchShakeIntensity = 2; -@interface MVMCoreUISwitch () +@interface MVMCoreUISwitch () @property (weak, nonatomic) UIView *baseView; @property (weak, nonatomic) UIView *knobView; @@ -37,6 +38,9 @@ const CGFloat SwitchShakeIntensity = 2; @property (nonatomic) BOOL canChangeValue; +@property (strong, nonatomic, nullable) NSDictionary *json; +@property (nullable, strong, nonatomic) DelegateObject *delegate; + @end @implementation MVMCoreUISwitch @@ -137,6 +141,50 @@ const CGFloat SwitchShakeIntensity = 2; } } +#pragma mark - MVMCoreUIMoleculeViewProtocol + +- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { + self.json = json; + + [FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol]; + + NSString *color = [json string:@"onTintColor"]; + if (color) { + self.onTintColor = [UIColor mfGetColorForHex:color]; + } + + color = [json string:@"offTintColor"]; + if (color) { + self.offTintColor = [UIColor mfGetColorForHex:color]; + } + + color = [json string:@"onKnobTintColor"]; + if (color) { + self.onKnobTintColor = [UIColor mfGetColorForHex:color]; + } + + color = [json string:@"offKnobTintColor"]; + if (color) { + self.offKnobTintColor = [UIColor mfGetColorForHex:color]; + } + + [self setState:[json boolForKey:@"state"] animated:false]; +} + ++ (CGFloat)estimatedHeightForRow:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject { + return [self getSwitchHeight]; +} + +#pragma mark - MVMCoreUIMoleculeViewProtocol + +- (BOOL)needsToBeConstrained { + return YES; +} + +- (UIStackViewAlignment)alignment { + return UIStackViewAlignmentTrailing; +} + #pragma mark - UIResponder overide - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { @@ -280,6 +328,11 @@ const CGFloat SwitchShakeIntensity = 2; if (self.valueChangedBlock) { self.valueChangedBlock(); } + + 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]; + } } - (void)setState:(BOOL)state withoutBlockAnimated:(BOOL)animated { @@ -308,7 +361,7 @@ const CGFloat SwitchShakeIntensity = 2; } -- (BOOL)changeValue{ +- (BOOL)changeValue { self.on^=YES; self.shouldTouchToSwitch = NO; [self setState:self.on animated:YES]; @@ -349,7 +402,8 @@ const CGFloat SwitchShakeIntensity = 2; } #pragma mark - Accessibility -- (BOOL)isAccessibilityElement{ + +- (BOOL)isAccessibilityElement { return YES; } @@ -361,4 +415,18 @@ const CGFloat SwitchShakeIntensity = 2; return [MVMCoreUIUtility hardcodedStringWithKey:@"AccToggleHint"]; } +#pragma mark FormValidationProtocol + +- (BOOL)isValidField { + return self.isOn && [self.json boolForKey:@"required"]; +} + +- (NSString *)formFieldName { + return [self.json string:KeyFieldKey]; +} + +- (id)formFieldValue { + return @(self.isOn); +} + @end diff --git a/MVMCoreUI/Molecules/SwitchLineItem.swift b/MVMCoreUI/Molecules/SwitchMolecules/SwitchLineItem.swift similarity index 100% rename from MVMCoreUI/Molecules/SwitchLineItem.swift rename to MVMCoreUI/Molecules/SwitchMolecules/SwitchLineItem.swift diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 0dffc356..123940f4 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -45,7 +45,7 @@ @"checkbox": MVMCoreUICheckBox.class, @"listItem": MoleculeTableViewCell.class, @"switchLineItem": SwitchLineItem.class, - @"switch": Switch.class, + @"switch": MVMCoreUISwitch.class, @"leftRightLabelView": LeftRightLabelView.class, @"actionDetailWithImage": ActionDetailWithImage.class, @"image": MFLoadImageView.class, From c7501f9cd6629b31fec20fc29128f5dbe9f985d3 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 27 Aug 2019 16:28:19 -0400 Subject: [PATCH 24/57] Added asychronous behavior to adding image. --- MVMCoreUI/Atoms/Views/Label.swift | 33 ++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 590a8164..3f17940e 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -257,7 +257,14 @@ public typealias ActionBlock = () -> () case "icon": let fontSize = attribute["size"] as? CGFloat ?? label.font.pointSize let iconName = attribute["iconName"] as? String ?? "externalLink" - let imageAttachment = Label.getTextAttachmentImage(name: iconName, dimension: fontSize) + let imageURL = attribute["image"] as? String + let imageAttachment: NSTextAttachment + + if let url = imageURL, let label = label as? Label { + imageAttachment = Label.getTextAttachmentFrom(url: url, dimension: fontSize, label: label) + } else { + imageAttachment = Label.getTextAttachmentImage(name: iconName, dimension: fontSize) + } let mutableString = NSMutableAttributedString() let space = NSAttributedString(string: " ") @@ -440,6 +447,12 @@ public typealias ActionBlock = () -> () self.attributedText = mutableString } + /* + Retrieves an NSTextAttachment for NSAttributedString that is prepped to be inserted with the text. + + - parameter name: The Asset name of the image. DEFAULT: "externalLink" + - parameter dimension: length of the height and width of the image. Will be 80% the passed magnitude. + */ static func getTextAttachmentImage(name: String = "externalLink", dimension: CGFloat) -> NSTextAttachment { let dimension = round(dimension * 0.8) @@ -450,6 +463,24 @@ public typealias ActionBlock = () -> () return imageAttachment } + + static func getTextAttachmentFrom(url: String, dimension: CGFloat, label: Label) -> NSTextAttachment { + + let imageAttachment = NSTextAttachment() + imageAttachment.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension) + + DispatchQueue.main.async { + + guard let url = URL(string: url), + let data = try? Data(contentsOf: url) + else { return } + + imageAttachment.image = UIImage(data: data) + label.setNeedsDisplay() + } + + return imageAttachment + } } // MARK: - Atomization From e0643d834e9cdda42b562bfeb93e43888e63bcb5 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 28 Aug 2019 10:40:43 -0400 Subject: [PATCH 25/57] adding dimension ratio. --- MVMCoreUI/Atoms/Views/Label.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 3f17940e..53dd90e1 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -466,6 +466,8 @@ public typealias ActionBlock = () -> () static func getTextAttachmentFrom(url: String, dimension: CGFloat, label: Label) -> NSTextAttachment { + let dimension = round(dimension * 0.8) + let imageAttachment = NSTextAttachment() imageAttachment.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension) From b5276f5519b1e3a3feec0a889144ce3ce79be572 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 29 Aug 2019 08:28:07 -0400 Subject: [PATCH 26/57] New molecules and arranging files --- MVMCoreUI.xcodeproj/project.pbxproj | 98 ++++++++++---- .../Buttons}/ButtonView.swift | 0 .../Views}/MVMCoreUIPageControl.h | 0 .../Views}/MVMCoreUIPageControl.m | 0 .../Views}/MVMCoreUIPagingProtocol.h | 0 MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h | 4 +- MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m | 2 +- .../Views}/ProgressBar.swift | 0 .../NSLayoutConstraintExtension.swift | 44 +++++++ .../ImageHeadlineBody.swift | 0 .../TwoButtonView.swift | 0 .../MoleculeCollectionViewCell.swift | 0 .../{ => Items}/MoleculeTableViewCell.swift | 0 .../{ => LeftRightViews}/CornerLabels.swift | 0 .../SwitchMolecules/HeadlineBodySwitch.swift | 57 +++++++++ .../HeadlineBodyTextButtonSwitch.swift | 59 +++++++++ .../SwitchMolecules/LabelSwitch.swift | 57 +++++++++ MVMCoreUI/Molecules/Switch.swift | 91 ------------- .../SwitchMolecules/SwitchLineItem.swift | 121 ------------------ .../HeadlineBody.swift | 26 +++- .../HeadlineBodyTextButton.swift | 78 +++++++++++ .../{Molecules => Organisms}/Carousel.swift | 0 .../MoleculeStackView.swift | 0 .../MVMCoreUIMoleculeMappingObject.m | 8 +- 24 files changed, 401 insertions(+), 244 deletions(-) rename MVMCoreUI/{Molecules => Atoms/Buttons}/ButtonView.swift (100%) rename MVMCoreUI/{Molecules => Atoms/Views}/MVMCoreUIPageControl.h (100%) rename MVMCoreUI/{Molecules => Atoms/Views}/MVMCoreUIPageControl.m (100%) rename MVMCoreUI/{Molecules => Atoms/Views}/MVMCoreUIPagingProtocol.h (100%) rename MVMCoreUI/{Molecules => Atoms/Views}/ProgressBar.swift (100%) create mode 100644 MVMCoreUI/Categories/NSLayoutConstraintExtension.swift rename MVMCoreUI/Molecules/{ => HorizontalCombinationViews}/ImageHeadlineBody.swift (100%) rename MVMCoreUI/Molecules/{ => HorizontalCombinationViews}/TwoButtonView.swift (100%) rename MVMCoreUI/Molecules/{ => Items}/MoleculeCollectionViewCell.swift (100%) rename MVMCoreUI/Molecules/{ => Items}/MoleculeTableViewCell.swift (100%) rename MVMCoreUI/Molecules/{ => LeftRightViews}/CornerLabels.swift (100%) create mode 100644 MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift create mode 100644 MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodyTextButtonSwitch.swift create mode 100644 MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/LabelSwitch.swift delete mode 100644 MVMCoreUI/Molecules/Switch.swift delete mode 100644 MVMCoreUI/Molecules/SwitchMolecules/SwitchLineItem.swift rename MVMCoreUI/Molecules/{ => VerticalCombinationViews}/HeadlineBody.swift (89%) create mode 100644 MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyTextButton.swift rename MVMCoreUI/{Molecules => Organisms}/Carousel.swift (100%) rename MVMCoreUI/{Molecules => Organisms}/MoleculeStackView.swift (100%) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 7a6d0181..2913a9a6 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -10,11 +10,10 @@ 0105618D224BBE7700E1557D /* FormValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618A224BBE7700E1557D /* FormValidator.swift */; }; 0105618E224BBE7700E1557D /* FormValidator+TextFields.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */; }; 0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */; }; - 016A1071228122180009D605 /* SwitchLineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016A1070228122180009D605 /* SwitchLineItem.swift */; }; + 016A1071228122180009D605 /* HeadlineBodyTextButtonSwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016A1070228122180009D605 /* HeadlineBodyTextButtonSwitch.swift */; }; 0198F79F225679880066C936 /* FormValidationProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0198F79E225679870066C936 /* FormValidationProtocol.swift */; }; 0198F7A62256A80B0066C936 /* MFRadioButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 0198F7A02256A80A0066C936 /* MFRadioButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0198F7A82256A80B0066C936 /* MFRadioButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 0198F7A22256A80A0066C936 /* MFRadioButton.m */; }; - 01CA51B5229716F60071A6EE /* Switch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01CA51B4229716F60071A6EE /* Switch.swift */; }; 01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */; }; 01DF567021FA5AB300CC099B /* TextFieldListFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */; }; 01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -24,6 +23,10 @@ D206997721FB8A0B00CAE0DE /* MVMCoreUINavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; D206997821FB8A0B00CAE0DE /* MVMCoreUINavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = D206997621FB8A0B00CAE0DE /* MVMCoreUINavigationController.m */; }; D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; }; + D224798A2314445E003FCCF9 /* LabelSwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479892314445E003FCCF9 /* LabelSwitch.swift */; }; + D224798C231450C8003FCCF9 /* HeadlineBodySwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D224798B231450C8003FCCF9 /* HeadlineBodySwitch.swift */; }; + D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */; }; + D22479962316AF6E003FCCF9 /* HeadlineBodyTextButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479952316AF6D003FCCF9 /* HeadlineBodyTextButton.swift */; }; D22D1F1A220341F60077CEC0 /* MVMCoreUICheckBox.h in Headers */ = {isa = PBXBuildFile; fileRef = D22D1F18220341F50077CEC0 /* MVMCoreUICheckBox.h */; settings = {ATTRIBUTES = (Public, ); }; }; D22D1F1B220341F60077CEC0 /* MVMCoreUICheckBox.m in Sources */ = {isa = PBXBuildFile; fileRef = D22D1F19220341F50077CEC0 /* MVMCoreUICheckBox.m */; }; D22D1F1E220343560077CEC0 /* MVMCoreUICheckMarkView.h in Headers */ = {isa = PBXBuildFile; fileRef = D22D1F1C220343560077CEC0 /* MVMCoreUICheckMarkView.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -189,11 +192,10 @@ 0105618A224BBE7700E1557D /* FormValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormValidator.swift; sourceTree = ""; }; 0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+TextFields.swift"; sourceTree = ""; }; 0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+FormParams.swift"; sourceTree = ""; }; - 016A1070228122180009D605 /* SwitchLineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwitchLineItem.swift; sourceTree = ""; }; + 016A1070228122180009D605 /* HeadlineBodyTextButtonSwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyTextButtonSwitch.swift; sourceTree = ""; }; 0198F79E225679870066C936 /* FormValidationProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormValidationProtocol.swift; sourceTree = ""; }; 0198F7A02256A80A0066C936 /* MFRadioButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFRadioButton.h; sourceTree = ""; }; 0198F7A22256A80A0066C936 /* MFRadioButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFRadioButton.m; sourceTree = ""; }; - 01CA51B4229716F60071A6EE /* Switch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Switch.swift; sourceTree = ""; }; 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = ""; }; 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = ""; }; 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = ""; }; @@ -202,6 +204,10 @@ D206997521FB8A0B00CAE0DE /* MVMCoreUINavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUINavigationController.h; sourceTree = ""; }; D206997621FB8A0B00CAE0DE /* MVMCoreUINavigationController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUINavigationController.m; sourceTree = ""; }; D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = ""; }; + D22479892314445E003FCCF9 /* LabelSwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelSwitch.swift; sourceTree = ""; }; + D224798B231450C8003FCCF9 /* HeadlineBodySwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodySwitch.swift; sourceTree = ""; }; + D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutConstraintExtension.swift; sourceTree = ""; }; + D22479952316AF6D003FCCF9 /* HeadlineBodyTextButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyTextButton.swift; sourceTree = ""; }; D22D1F18220341F50077CEC0 /* MVMCoreUICheckBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUICheckBox.h; sourceTree = ""; }; D22D1F19220341F50077CEC0 /* MVMCoreUICheckBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUICheckBox.m; sourceTree = ""; }; D22D1F1C220343560077CEC0 /* MVMCoreUICheckMarkView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUICheckMarkView.h; sourceTree = ""; }; @@ -394,11 +400,58 @@ D224798823142BF2003FCCF9 /* SwitchMolecules */ = { isa = PBXGroup; children = ( - 016A1070228122180009D605 /* SwitchLineItem.swift */, + D22479892314445E003FCCF9 /* LabelSwitch.swift */, + D224798B231450C8003FCCF9 /* HeadlineBodySwitch.swift */, + 016A1070228122180009D605 /* HeadlineBodyTextButtonSwitch.swift */, ); path = SwitchMolecules; sourceTree = ""; }; + D224798D2316A988003FCCF9 /* VerticalCombinationViews */ = { + isa = PBXGroup; + children = ( + D2A638FC22CA98280052ED1F /* HeadlineBody.swift */, + D22479952316AF6D003FCCF9 /* HeadlineBodyTextButton.swift */, + ); + path = VerticalCombinationViews; + sourceTree = ""; + }; + D224798E2316A995003FCCF9 /* HorizontalCombinationViews */ = { + isa = PBXGroup; + children = ( + D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */, + D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */, + ); + path = HorizontalCombinationViews; + sourceTree = ""; + }; + D224798F2316A99F003FCCF9 /* LeftRightViews */ = { + isa = PBXGroup; + children = ( + D224798823142BF2003FCCF9 /* SwitchMolecules */, + B8200E182281DC1A007245F4 /* CornerLabels.swift */, + ); + path = LeftRightViews; + sourceTree = ""; + }; + D22479902316A9CB003FCCF9 /* Organisms */ = { + isa = PBXGroup; + children = ( + D2A5145E2211DDC100345BFB /* MoleculeStackView.swift */, + D2A6390022CBB1820052ED1F /* Carousel.swift */, + ); + path = Organisms; + sourceTree = ""; + }; + D22479912316A9EF003FCCF9 /* Items */ = { + isa = PBXGroup; + children = ( + D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */, + D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */, + ); + path = Items; + sourceTree = ""; + }; D22D1F582204D2590077CEC0 /* LegacyControllers */ = { isa = PBXGroup; children = ( @@ -444,6 +497,7 @@ D29DF11E21E6851E003B2FB9 /* TopAlert */, D29DF10D21E67A70003B2FB9 /* Atoms */, D29DF10E21E67A77003B2FB9 /* Molecules */, + D22479902316A9CB003FCCF9 /* Organisms */, D29DF0DF21E418B2003B2FB9 /* Templates */, D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */, D29DF0D021E404D4003B2FB9 /* Info.plist */, @@ -486,30 +540,19 @@ D29DF10E21E67A77003B2FB9 /* Molecules */ = { isa = PBXGroup; children = ( - D224798823142BF2003FCCF9 /* SwitchMolecules */, + D22479912316A9EF003FCCF9 /* Items */, + D224798F2316A99F003FCCF9 /* LeftRightViews */, + D224798E2316A995003FCCF9 /* HorizontalCombinationViews */, + D224798D2316A988003FCCF9 /* VerticalCombinationViews */, + D2A5145C2211D22A00345BFB /* MVMCoreUIMoleculeViewProtocol.h */, 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */, 01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */, D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */, D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */, - D282AACA2243C61700C46919 /* ButtonView.swift */, - 01CA51B4229716F60071A6EE /* Switch.swift */, - D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */, D2A514662213885800345BFB /* StandardHeaderView.swift */, - D2A5145C2211D22A00345BFB /* MVMCoreUIMoleculeViewProtocol.h */, - D2A5145E2211DDC100345BFB /* MoleculeStackView.swift */, D274CA322236A78900B01B62 /* StandardFooterView.swift */, - D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */, - B8200E142280C4CF007245F4 /* ProgressBar.swift */, - B8200E182281DC1A007245F4 /* CornerLabels.swift */, D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */, - D2A638FC22CA98280052ED1F /* HeadlineBody.swift */, - D2A6390022CBB1820052ED1F /* Carousel.swift */, - D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */, - D260D7AF22D65BDD007E7233 /* MVMCoreUIPageControl.h */, - D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */, - D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */, D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */, - D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */, ); path = Molecules; sourceTree = ""; @@ -542,6 +585,7 @@ D29DF11321E6805F003B2FB9 /* UIColor+MFConvenience.m */, D29DF11221E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.h */, D29DF11421E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.m */, + D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */, ); path = Categories; sourceTree = ""; @@ -620,6 +664,7 @@ D29DF17021E69E1F003B2FB9 /* MFCustomButton.m */, D29DF16C21E69E1F003B2FB9 /* PrimaryButton.h */, D29DF17121E69E1F003B2FB9 /* PrimaryButton.m */, + D282AACA2243C61700C46919 /* ButtonView.swift */, D29DF16D21E69E1F003B2FB9 /* MFTextButton.h */, D29DF17221E69E1F003B2FB9 /* MFTextButton.m */, ); @@ -629,6 +674,10 @@ D29DF17D21E69E26003B2FB9 /* Views */ = { isa = PBXGroup; children = ( + D260D7AF22D65BDD007E7233 /* MVMCoreUIPageControl.h */, + D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */, + D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */, + B8200E142280C4CF007245F4 /* ProgressBar.swift */, DBC4391622442196001AB423 /* CaretView.swift */, DBC4391722442197001AB423 /* DashLine.swift */, DB06250A2293456500B72DD3 /* LeftRightLabelView.swift */, @@ -951,6 +1000,7 @@ D29DF25321E6A177003B2FB9 /* MFDigitTextField.m in Sources */, D29DF12F21E6851E003B2FB9 /* MVMCoreUITopAlertMainView.m in Sources */, DBC4392122491730001AB423 /* LabelWithInternalButton.swift in Sources */, + D224798C231450C8003FCCF9 /* HeadlineBodySwitch.swift in Sources */, D29DF17C21E69E1F003B2FB9 /* MFTextButton.m in Sources */, D29DF2C521E7BF57003B2FB9 /* MFTabBarSwipeAnimator.m in Sources */, D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */, @@ -975,9 +1025,11 @@ D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */, D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */, D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */, + D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */, D282AACB2243C61700C46919 /* ButtonView.swift in Sources */, D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */, 0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */, + D22479962316AF6E003FCCF9 /* HeadlineBodyTextButton.swift in Sources */, D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */, D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */, D29DF18121E69E50003B2FB9 /* MFView.m in Sources */, @@ -994,12 +1046,13 @@ D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */, D2A6390122CBB1820052ED1F /* Carousel.swift in Sources */, D29DF2C721E7BF57003B2FB9 /* MFTabBarInteractor.m in Sources */, - 016A1071228122180009D605 /* SwitchLineItem.swift in Sources */, + 016A1071228122180009D605 /* HeadlineBodyTextButtonSwitch.swift in Sources */, D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */, D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */, D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */, D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */, DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */, + D224798A2314445E003FCCF9 /* LabelSwitch.swift in Sources */, D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */, D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */, D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */, @@ -1017,7 +1070,6 @@ D29770FC21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m in Sources */, D29DF25121E6A177003B2FB9 /* MFDigitTextBox.m in Sources */, DBC4391B224421A0001AB423 /* CaretButton.swift in Sources */, - 01CA51B5229716F60071A6EE /* Switch.swift in Sources */, 0198F7A82256A80B0066C936 /* MFRadioButton.m in Sources */, D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */, D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */, diff --git a/MVMCoreUI/Molecules/ButtonView.swift b/MVMCoreUI/Atoms/Buttons/ButtonView.swift similarity index 100% rename from MVMCoreUI/Molecules/ButtonView.swift rename to MVMCoreUI/Atoms/Buttons/ButtonView.swift diff --git a/MVMCoreUI/Molecules/MVMCoreUIPageControl.h b/MVMCoreUI/Atoms/Views/MVMCoreUIPageControl.h similarity index 100% rename from MVMCoreUI/Molecules/MVMCoreUIPageControl.h rename to MVMCoreUI/Atoms/Views/MVMCoreUIPageControl.h diff --git a/MVMCoreUI/Molecules/MVMCoreUIPageControl.m b/MVMCoreUI/Atoms/Views/MVMCoreUIPageControl.m similarity index 100% rename from MVMCoreUI/Molecules/MVMCoreUIPageControl.m rename to MVMCoreUI/Atoms/Views/MVMCoreUIPageControl.m diff --git a/MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h b/MVMCoreUI/Atoms/Views/MVMCoreUIPagingProtocol.h similarity index 100% rename from MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h rename to MVMCoreUI/Atoms/Views/MVMCoreUIPagingProtocol.h diff --git a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h index ba36419e..a21dd55f 100644 --- a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h +++ b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h @@ -24,8 +24,8 @@ typedef void(^ValueChangeBlock)(void); @property (nonatomic) BOOL shouldTouchToSwitch; @property (nullable, copy, nonatomic) ValueChangeBlock valueChangedBlock; -+ (nullable instancetype)mvmSwitchDefault; -+ (nullable instancetype)mvmSwitchDefaultWithValueChangeBlock:(nullable ValueChangeBlock)block; ++ (nonnull instancetype)mvmSwitchDefault; ++ (nonnull instancetype)mvmSwitchDefaultWithValueChangeBlock:(nullable ValueChangeBlock)block; - (void)setState:(BOOL)state animated:(BOOL)animated; diff --git a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m index 95264f3c..f994b320 100644 --- a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m +++ b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m @@ -90,7 +90,7 @@ const CGFloat SwitchShakeIntensity = 2; return mySwitch; } -+ (nullable instancetype)mvmSwitchDefaultWithValueChangeBlock:(nullable ValueChangeBlock)block { ++ (nonnull instancetype)mvmSwitchDefaultWithValueChangeBlock:(nullable ValueChangeBlock)block { MVMCoreUISwitch *mySwitch = [[self alloc] initWithFrame:CGRectZero]; mySwitch.valueChangedBlock = block; return mySwitch; diff --git a/MVMCoreUI/Molecules/ProgressBar.swift b/MVMCoreUI/Atoms/Views/ProgressBar.swift similarity index 100% rename from MVMCoreUI/Molecules/ProgressBar.swift rename to MVMCoreUI/Atoms/Views/ProgressBar.swift diff --git a/MVMCoreUI/Categories/NSLayoutConstraintExtension.swift b/MVMCoreUI/Categories/NSLayoutConstraintExtension.swift new file mode 100644 index 00000000..bf6c8f65 --- /dev/null +++ b/MVMCoreUI/Categories/NSLayoutConstraintExtension.swift @@ -0,0 +1,44 @@ +// +// NSLayoutConstraintExtension.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 8/28/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +public extension NSLayoutConstraint { + static func pinSubviewsCenter(leftView: UIView, rightView: UIView) { + guard let superView = leftView.superview else { + return + } + leftView.centerYAnchor.constraint(equalTo: superView.centerYAnchor).isActive = true + leftView.leftAnchor.constraint(equalTo: superView.layoutMarginsGuide.leftAnchor).isActive = true + leftView.topAnchor.constraint(greaterThanOrEqualTo: superView.layoutMarginsGuide.topAnchor).isActive = true + superView.layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: leftView.bottomAnchor).isActive = true + + var constraint = leftView.topAnchor.constraint(equalTo: superView.layoutMarginsGuide.topAnchor) + constraint.priority = .defaultLow + constraint.isActive = true + + constraint = superView.layoutMarginsGuide.bottomAnchor.constraint(equalTo: leftView.bottomAnchor) + constraint.priority = .defaultLow + constraint.isActive = true + + rightView.leftAnchor.constraint(greaterThanOrEqualTo: leftView.rightAnchor, constant: 16).isActive = true + + rightView.centerYAnchor.constraint(equalTo: superView.centerYAnchor).isActive = true + superView.layoutMarginsGuide.rightAnchor.constraint(equalTo: rightView.rightAnchor).isActive = true + rightView.topAnchor.constraint(greaterThanOrEqualTo: superView.layoutMarginsGuide.topAnchor).isActive = true + superView.layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: rightView.bottomAnchor).isActive = true + + constraint = rightView.topAnchor.constraint(equalTo: superView.layoutMarginsGuide.topAnchor) + constraint.priority = .defaultLow + constraint.isActive = true + + constraint = superView.layoutMarginsGuide.bottomAnchor.constraint(equalTo: rightView.bottomAnchor) + constraint.priority = .defaultLow + constraint.isActive = true + } +} diff --git a/MVMCoreUI/Molecules/ImageHeadlineBody.swift b/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBody.swift similarity index 100% rename from MVMCoreUI/Molecules/ImageHeadlineBody.swift rename to MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBody.swift diff --git a/MVMCoreUI/Molecules/TwoButtonView.swift b/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift similarity index 100% rename from MVMCoreUI/Molecules/TwoButtonView.swift rename to MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift diff --git a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift similarity index 100% rename from MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift rename to MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift diff --git a/MVMCoreUI/Molecules/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift similarity index 100% rename from MVMCoreUI/Molecules/MoleculeTableViewCell.swift rename to MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift diff --git a/MVMCoreUI/Molecules/CornerLabels.swift b/MVMCoreUI/Molecules/LeftRightViews/CornerLabels.swift similarity index 100% rename from MVMCoreUI/Molecules/CornerLabels.swift rename to MVMCoreUI/Molecules/LeftRightViews/CornerLabels.swift diff --git a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift new file mode 100644 index 00000000..c856832d --- /dev/null +++ b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift @@ -0,0 +1,57 @@ +// +// HeadlineBodySwitch.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 8/26/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers public class HeadlineBodySwitch: ViewConstrainingView { + let headlineBody = HeadlineBody(frame: .zero) + let mvmSwitch = MVMCoreUISwitch.mvmSwitchDefault() + + // MARK: - MVMCoreViewProtocol + open override func updateView(_ size: CGFloat) { + super.updateView(size) + headlineBody.updateView(size) + mvmSwitch.updateView(size) + } + + public override func setupView() { + super.setupView() + guard mvmSwitch.superview == nil else { + return + } + headlineBody.styleListItem() + addSubview(headlineBody) + addSubview(mvmSwitch) + NSLayoutConstraint.pinSubviewsCenter(leftView: headlineBody, rightView: mvmSwitch) + } + + // MARK: - MVMCoreUIMoleculeViewProtocol + public override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + headlineBody.setWithJSON(json?.optionalDictionaryForKey("headlineBody"), delegateObject: delegateObject, additionalData: additionalData) + mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData) + } + + public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return MVMCoreUISwitch.estimatedHeight(forRow: json, delegateObject: delegateObject) + } + + public override func setAsMolecule() { + super.setAsMolecule() + headlineBody.setAsMolecule() + (mvmSwitch as MVMCoreUIMoleculeViewProtocol).setAsMolecule?() + headlineBody.styleListItem() + } + + public override func reset() { + super.reset() + headlineBody.reset() + (mvmSwitch as MVMCoreUIMoleculeViewProtocol).reset?() + headlineBody.styleListItem() + } +} diff --git a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodyTextButtonSwitch.swift b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodyTextButtonSwitch.swift new file mode 100644 index 00000000..87ca50d5 --- /dev/null +++ b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodyTextButtonSwitch.swift @@ -0,0 +1,59 @@ +// +// SwitchLineItem.swift +// MVMCoreUI +// +// Created by Priya on 5/6/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers public class HeadlineBodyTextButtonSwitch: ViewConstrainingView { + let headlineBodyTextButton = HeadlineBodyTextButton(frame: .zero) + let mvmSwitch = MVMCoreUISwitch.mvmSwitchDefault() + + // MARK: - MVMCoreViewProtocol + open override func updateView(_ size: CGFloat) { + super.updateView(size) + headlineBodyTextButton.updateView(size) + mvmSwitch.updateView(size) + } + + public override func setupView() { + super.setupView() + guard mvmSwitch.superview == nil else { + return + } + headlineBodyTextButton.headlineBody.styleListItem() + addSubview(headlineBodyTextButton) + addSubview(mvmSwitch) + NSLayoutConstraint.pinSubviewsCenter(leftView: headlineBodyTextButton, rightView: mvmSwitch) + } + + // MARK: - MVMCoreUIMoleculeViewProtocol + public override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + headlineBodyTextButton.setWithJSON(json?.optionalDictionaryForKey("headlineBodyTextButton"), delegateObject: delegateObject, additionalData: additionalData) + mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData) + } + + public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return MVMCoreUISwitch.estimatedHeight(forRow: json, delegateObject: delegateObject) + } + + public override func setAsMolecule() { + super.setAsMolecule() + headlineBodyTextButton.setAsMolecule() + (mvmSwitch as MVMCoreUIMoleculeViewProtocol).setAsMolecule?() + headlineBodyTextButton.headlineBody.styleListItem() + } + + public override func reset() { + super.reset() + headlineBodyTextButton.reset() + (mvmSwitch as MVMCoreUIMoleculeViewProtocol).reset?() + headlineBodyTextButton.headlineBody.styleListItem() + } +} + + diff --git a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/LabelSwitch.swift b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/LabelSwitch.swift new file mode 100644 index 00000000..017eee99 --- /dev/null +++ b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/LabelSwitch.swift @@ -0,0 +1,57 @@ +// +// LabelSwitch.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 8/26/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers public class LabelSwitch: ViewConstrainingView { + let label = Label.commonLabelB1(true) + let mvmSwitch = MVMCoreUISwitch.mvmSwitchDefault() + + // MARK: - MVMCoreViewProtocol + open override func updateView(_ size: CGFloat) { + super.updateView(size) + label.updateView(size) + mvmSwitch.updateView(size) + } + + public override func setupView() { + super.setupView() + guard mvmSwitch.superview == nil else { + return + } + addSubview(label) + addSubview(mvmSwitch) + label.setContentHuggingPriority(UILayoutPriority.required, for: NSLayoutConstraint.Axis.vertical) + NSLayoutConstraint.pinSubviewsCenter(leftView: label, rightView: mvmSwitch) + } + + // MARK: - MVMCoreUIMoleculeViewProtocol + public override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + label.setWithJSON(json?.optionalDictionaryForKey("label"), delegateObject: delegateObject, additionalData: additionalData) + mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData) + } + + public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return MVMCoreUISwitch.estimatedHeight(forRow: json, delegateObject: delegateObject) + } + + public override func setAsMolecule() { + super.setAsMolecule() + label.setAsMolecule() + (mvmSwitch as MVMCoreUIMoleculeViewProtocol).setAsMolecule?() + label.styleB1(true) + } + + public override func reset() { + super.reset() + label.reset() + (mvmSwitch as MVMCoreUIMoleculeViewProtocol).reset?() + label.styleB1(true) + } +} diff --git a/MVMCoreUI/Molecules/Switch.swift b/MVMCoreUI/Molecules/Switch.swift deleted file mode 100644 index 5b23b1d5..00000000 --- a/MVMCoreUI/Molecules/Switch.swift +++ /dev/null @@ -1,91 +0,0 @@ -// -// Switch.swift -// MVMCoreUI -// -// Created by Priya on 5/23/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import UIKit - -@objcMembers public class Switch: ViewConstrainingView, FormValidationProtocol{ - public var mvmSwitch = MVMCoreUISwitch() - var isRequired = false - var delegateObject: DelegateObject? - - @objc func switchChanged() { - let delegate = delegateObject as? MVMCoreUIDelegateObject - if let delegate = delegate { - let formValidator = delegate.formValidationProtocol?.formValidatorModel?() - formValidator?.enableByValidation() - } - } - - open override func setupView() { - super.setupView() - mvmSwitch.addTarget(self, action: #selector(Switch.switchChanged), for: .valueChanged) - self.clipsToBounds = true - addSubview(mvmSwitch) - mvmSwitch.translatesAutoresizingMaskIntoConstraints = false - setupContainerConstraints() - } - - public override func updateView(_ size: CGFloat) { - super.updateView(size) - mvmSwitch.updateView(size) - } - - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - isRequired = json?[KeyRequired] as? Bool ?? false - self.delegateObject = delegateObject - if let delegateObject = delegateObject { - FormValidator.setupValidation(molecule: self, delegate: delegateObject.formValidationProtocol) - } - if let onColorString = json?.optionalStringForKey("onTintColor") { - mvmSwitch.onTintColor = .mfGet(forHex: onColorString) - } - if let offColorString = json?.optionalStringForKey("offTintColor") { - mvmSwitch.offTintColor = .mfGet(forHex: offColorString) - } - if let onKnobColorString = json?.optionalStringForKey("onKnobTintColor") { - mvmSwitch.onKnobTintColor = .mfGet(forHex: onKnobColorString) - } - if let offKnobColorString = json?.optionalStringForKey("offKnobTintColor") { - mvmSwitch.offKnobTintColor = .mfGet(forHex: offKnobColorString) - } - mvmSwitch.setState(json?.optionalBoolForKey("state") ?? false, animated: true) - } - - func setupContainerConstraints() { - mvmSwitch.topAnchor.constraint(equalTo: topAnchor).isActive = true - mvmSwitch.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true - mvmSwitch.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true - mvmSwitch.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true - } - - public func isValidField() -> Bool { - return (isRequired == false) ? true : mvmSwitch.isOn - } - - public func formFieldName() -> String? { - return json?.optionalStringForKey(KeyFieldKey) - } - - public func formFieldValue() -> Any? { - return mvmSwitch.isOn - } - - public override func needsToBeConstrained() -> Bool { - return true - } - - public override func alignment() -> UIStackView.Alignment { - return UIStackView.Alignment.leading - } - - public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - return MVMCoreUISwitch.getHeight() - } -} - diff --git a/MVMCoreUI/Molecules/SwitchMolecules/SwitchLineItem.swift b/MVMCoreUI/Molecules/SwitchMolecules/SwitchLineItem.swift deleted file mode 100644 index 8c15e8ec..00000000 --- a/MVMCoreUI/Molecules/SwitchMolecules/SwitchLineItem.swift +++ /dev/null @@ -1,121 +0,0 @@ -// -// SwitchLineItem.swift -// MVMCoreUI -// -// Created by Priya on 5/6/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import UIKit - -@objcMembers public class SwitchLineItem: ViewConstrainingView, FormValidationProtocol{ - public var mvmSwitch = Switch() - public var label = Label() - public var leftContainerView = UIView() - public var mfTextButton = MFTextButton(nil, constrainHeight: true, forWidth: 0) - var isRequired = false - var delegateObject: DelegateObject? - - @objc func switchChanged() { - let delegate = delegateObject as? MVMCoreUIDelegateObject - if let delegate = delegate { - let formValidator = delegate.formValidationProtocol?.formValidatorModel?() - formValidator?.enableByValidation() - } - } - - open override func setupView() { - super.setupView() - leftContainerView.addSubview(label) - leftContainerView.addSubview(mfTextButton) - addSubview(leftContainerView) - addSubview(mvmSwitch) - - leftContainerView.translatesAutoresizingMaskIntoConstraints = false - mvmSwitch.translatesAutoresizingMaskIntoConstraints = false - mfTextButton.translatesAutoresizingMaskIntoConstraints = false - label.translatesAutoresizingMaskIntoConstraints = false - setupContainerConstraints() - } - - public override func updateView(_ size: CGFloat) { - super.updateView(size) - label.updateView(size) - mvmSwitch.updateView(size) - mfTextButton.updateView(size) - } - - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - mvmSwitch.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - label.setWithJSON(json?.optionalDictionaryForKey("label"), delegateObject: delegateObject, additionalData: additionalData) - mfTextButton.setWithJSON(json?.optionalDictionaryForKey("textButton"), delegateObject: delegateObject, additionalData: additionalData) - if (label.text?.count ?? 0) <= 0 && (mfTextButton.titleLabel?.text?.count ?? 0) <= 0 { - mvmSwitch.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0).isActive = true - } - } - - func setupContainerConstraints() { - leftContainerView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true - - var constraint = leftContainerView.topAnchor.constraint(equalTo: topAnchor) - constraint.priority = UILayoutPriority(249) - constraint.isActive = true - - mvmSwitch.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true - - constraint = mvmSwitch.topAnchor.constraint(equalTo: topAnchor) - constraint.priority = UILayoutPriority(249) - constraint.isActive = true - - trailingAnchor.constraint(equalTo: mvmSwitch.trailingAnchor).isActive = true - - constraint = bottomAnchor.constraint(equalTo: mvmSwitch.bottomAnchor) - constraint.priority = UILayoutPriority(249) - constraint.isActive = true - - bottomAnchor.constraint(greaterThanOrEqualTo: mvmSwitch.bottomAnchor).isActive = true - - constraint = bottomAnchor.constraint(equalTo: leftContainerView.bottomAnchor) - constraint.isActive = true - - bottomAnchor.constraint(greaterThanOrEqualTo: leftContainerView.bottomAnchor).isActive = true - leftContainerView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true - - NSLayoutConstraint.constraintPinSubview(leftContainerView, pinCenterX: false, pinCenterY: true) - constraint = mvmSwitch.leadingAnchor.constraint(greaterThanOrEqualTo: leftContainerView.trailingAnchor) - constraint.priority = UILayoutPriority(999) - constraint.isActive = true - NSLayoutConstraint.constraintPinSubview(mvmSwitch, pinCenterX: false, pinCenterY: true) - - leftContainerView.topAnchor.constraint(equalTo: label.topAnchor).isActive = true - leftContainerView.trailingAnchor.constraint(greaterThanOrEqualTo: label.trailingAnchor).isActive = true - - constraint = leftContainerView.trailingAnchor.constraint(equalTo: label.trailingAnchor) - constraint.priority = UILayoutPriority(249) - constraint.isActive = true - - leftContainerView.trailingAnchor.constraint(greaterThanOrEqualTo: mfTextButton.trailingAnchor).isActive = true - - constraint = leftContainerView.trailingAnchor.constraint(equalTo: mfTextButton.trailingAnchor) - constraint.priority = UILayoutPriority(249) - constraint.isActive = true - - leftContainerView.bottomAnchor.constraint(equalTo: mfTextButton.bottomAnchor).isActive = true - mfTextButton.leadingAnchor.constraint(equalTo: leftContainerView.leadingAnchor).isActive = true - label.leadingAnchor.constraint(equalTo: leftContainerView.leadingAnchor).isActive = true - mfTextButton.topAnchor.constraint(equalTo: label.bottomAnchor).isActive = true - leftContainerView.setContentHuggingPriority(.defaultHigh, for: .horizontal) - mvmSwitch.setContentHuggingPriority(.defaultLow, for: .horizontal) - } - - public override func needsToBeConstrained() -> Bool { - return true - } - - public override func alignment() -> UIStackView.Alignment { - return UIStackView.Alignment.leading - } -} - - diff --git a/MVMCoreUI/Molecules/HeadlineBody.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift similarity index 89% rename from MVMCoreUI/Molecules/HeadlineBody.swift rename to MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift index d3c37261..ac0e416e 100644 --- a/MVMCoreUI/Molecules/HeadlineBody.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift @@ -18,6 +18,28 @@ open class HeadlineBody: ViewConstrainingView { var leftConstraintMessage: NSLayoutConstraint? var rightConstraintMessage: NSLayoutConstraint? + func styleLandingPageHeader() { + headlineLabel.styleH1(true) + messageLabel.styleB2(true) + spaceBetweenLabelsConstant = PaddingTwo + } + + func stylePageHeader() { + headlineLabel.styleH2(true) + messageLabel.styleB2(true) + spaceBetweenLabelsConstant = PaddingTwo + } + + func styleListItem() { + headlineLabel.styleB1(true) + messageLabel.styleB2(true) + spaceBetweenLabelsConstant = 0 + } + + func hasText() -> Bool { + return headlineLabel.hasText || messageLabel.hasText + } + // MARK: - MVMCoreViewProtocol open override func updateView(_ size: CGFloat) { super.updateView(size) @@ -95,9 +117,7 @@ open class HeadlineBody: ViewConstrainingView { open override func reset() { super.reset() - headlineLabel.styleH2(true) - messageLabel.styleB2(true) - spaceBetweenLabelsConstant = PaddingTwo + stylePageHeader() } public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyTextButton.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyTextButton.swift new file mode 100644 index 00000000..fbfc279b --- /dev/null +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyTextButton.swift @@ -0,0 +1,78 @@ +// +// HeadlineBodyTextButton.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 8/28/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers public class HeadlineBodyTextButton: ViewConstrainingView { + + let headlineBody = HeadlineBody(frame: .zero) + let textButton = MFTextButton(nil, constrainHeight: true, forWidth: MVMCoreUIUtility.getWidth()) + var spaceBetweenConstant: CGFloat = 0.0 + var spaceBetween: NSLayoutConstraint? + + // MARK: - MVMCoreViewProtocol + open override func updateView(_ size: CGFloat) { + super.updateView(size) + headlineBody.updateView(size) + textButton.updateView(size) + setSpacing() + } + + open override func setupView() { + super.setupView() + guard subviews.count == 0 else { + return + } + addSubview(headlineBody) + addSubview(textButton) + headlineBody.styleListItem() + + headlineBody.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor, constant: 0).isActive = true + headlineBody.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor).isActive = true + var constraint = layoutMarginsGuide.rightAnchor.constraint(equalTo: headlineBody.rightAnchor) + constraint.priority = .defaultHigh + constraint.isActive = true + + spaceBetween = textButton.topAnchor.constraint(equalTo: headlineBody.bottomAnchor, constant: spaceBetweenConstant) + spaceBetween?.isActive = true + + textButton.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor).isActive = true + layoutMarginsGuide.bottomAnchor.constraint(equalTo: textButton.bottomAnchor).isActive = true + layoutMarginsGuide.rightAnchor.constraint(greaterThanOrEqualTo: textButton.rightAnchor).isActive = true + constraint = layoutMarginsGuide.rightAnchor.constraint(equalTo: textButton.rightAnchor) + constraint.priority = .defaultHigh + constraint.isActive = true + } + + // MARK: - Constraining + public func setSpacing() { + if headlineBody.hasText() && (textButton.titleLabel?.text?.count ?? 0) > 0 { + spaceBetween?.constant = spaceBetweenConstant + } else { + spaceBetween?.constant = 0 + } + } + + // MARK: - MVMCoreUIMoleculeViewProtocol + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + headlineBody.setWithJSON(json?.optionalDictionaryForKey("headlineBody"), delegateObject: delegateObject, additionalData: additionalData) + textButton.setWithJSON(json?.optionalDictionaryForKey("textButton"), delegateObject: delegateObject, additionalData: additionalData) + } + + open override func reset() { + super.reset() + headlineBody.reset() + headlineBody.styleListItem() + textButton.reset() + } + + public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return 58 + } +} diff --git a/MVMCoreUI/Molecules/Carousel.swift b/MVMCoreUI/Organisms/Carousel.swift similarity index 100% rename from MVMCoreUI/Molecules/Carousel.swift rename to MVMCoreUI/Organisms/Carousel.swift diff --git a/MVMCoreUI/Molecules/MoleculeStackView.swift b/MVMCoreUI/Organisms/MoleculeStackView.swift similarity index 100% rename from MVMCoreUI/Molecules/MoleculeStackView.swift rename to MVMCoreUI/Organisms/MoleculeStackView.swift diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 123940f4..fe84278b 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -41,10 +41,8 @@ @"checkbox" : MVMCoreUICheckBox.class, @"cornerLabels" : CornerLabels.class, @"progressBar": ProgressBar.class, - @"textField": MFTextField.class, @"checkbox": MVMCoreUICheckBox.class, @"listItem": MoleculeTableViewCell.class, - @"switchLineItem": SwitchLineItem.class, @"switch": MVMCoreUISwitch.class, @"leftRightLabelView": LeftRightLabelView.class, @"actionDetailWithImage": ActionDetailWithImage.class, @@ -55,7 +53,11 @@ @"carouselItem": MoleculeCollectionViewCell.class, @"barsPager": MVMCoreUIPageControl.class, @"scroller": Scroller.class, - @"imageHeadlineBody": ImageHeadlineBody.class + @"imageHeadlineBody": ImageHeadlineBody.class, + @"labelSwitch": LabelSwitch.class, + @"headlineBodySwitch": HeadlineBodySwitch.class, + @"headlineBodyTextButton": HeadlineBodyTextButton.class, + @"headlineBodyTextButtonSwitch": HeadlineBodyTextButtonSwitch.class } mutableCopy]; }); return mapping; From 3234a6ee7ec48fcabd7c61229b026e5727d9ddeb Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 29 Aug 2019 08:35:27 -0400 Subject: [PATCH 27/57] estimated heights update --- .../LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift | 2 +- .../SwitchMolecules/HeadlineBodyTextButtonSwitch.swift | 2 +- .../VerticalCombinationViews/HeadlineBodyTextButton.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift index c856832d..ffab9920 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift @@ -38,7 +38,7 @@ import UIKit } public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - return MVMCoreUISwitch.estimatedHeight(forRow: json, delegateObject: delegateObject) + return 30 } public override func setAsMolecule() { diff --git a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodyTextButtonSwitch.swift b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodyTextButtonSwitch.swift index 87ca50d5..754f508b 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodyTextButtonSwitch.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodyTextButtonSwitch.swift @@ -38,7 +38,7 @@ import UIKit } public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - return MVMCoreUISwitch.estimatedHeight(forRow: json, delegateObject: delegateObject) + return HeadlineBodyTextButton.estimatedHeight(forRow: json, delegateObject: delegateObject) } public override func setAsMolecule() { diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyTextButton.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyTextButton.swift index fbfc279b..bb638624 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyTextButton.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyTextButton.swift @@ -73,6 +73,6 @@ import UIKit } public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - return 58 + return 60 } } From 3e426cb80b032bf6a5b192d866e0e67c89a2b864 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 29 Aug 2019 10:19:28 -0400 Subject: [PATCH 28/57] Fix to two button view --- .../TwoButtonView.swift | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift b/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift index 4b4f64d9..575c01ec 100644 --- a/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift +++ b/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift @@ -8,12 +8,13 @@ import UIKit -@objcMembers open class TwoButtonView: ButtonView { - open var secondaryButton: PrimaryButton? +@objcMembers open class TwoButtonView: ViewConstrainingView { + open var primaryButton: PrimaryButton? = PrimaryButton.button() + open var secondaryButton: PrimaryButton? = PrimaryButton.button() open var viewForButtons: UIView? public var heightConstraint: NSLayoutConstraint? - public override init() { + public init() { super.init(frame: .zero) } @@ -34,25 +35,32 @@ import UIKit open override func updateView(_ size: CGFloat) { super.updateView(size) MVMCoreDispatchUtility.performBlock(onMainThread: { + self.primaryButton?.updateView(size) self.secondaryButton?.updateView(size) }) } + open override func setupView() { + super.setupView() + setupButton() + } + // MARK: - MVMCoreUIMoleculeViewProtocol open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) let primaryButtonMap = json?.optionalDictionaryForKey("primaryButton") let secondaryButtonMap = json?.optionalDictionaryForKey("secondaryButton") set(primaryButtonJSON: primaryButtonMap, secondaryButtonJSON: secondaryButtonMap, delegateObject: delegateObject, additionalData: additionalData) + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) } open override func reset() { super.reset() + primaryButton?.setAsStandardCustom() secondaryButton?.setAsSecondaryCustom() } // MARK: - Constraining - override func setupButton() { + func setupButton() { setupWithTwoButtons() } From 4f47aa9ad5937414f0475955fed91dd9138046cc Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 29 Aug 2019 10:52:20 -0400 Subject: [PATCH 29/57] changed key. --- MVMCoreUI/Molecules/ActionDetailWithImage.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Molecules/ActionDetailWithImage.swift b/MVMCoreUI/Molecules/ActionDetailWithImage.swift index 3804ed00..6162fbc7 100644 --- a/MVMCoreUI/Molecules/ActionDetailWithImage.swift +++ b/MVMCoreUI/Molecules/ActionDetailWithImage.swift @@ -156,7 +156,7 @@ import UIKit guard let dictionary = json else { return } - if let padding = dictionary.optionalCGFloatForKey("bottomTitlePadding") { + if let padding = dictionary.optionalCGFloatForKey("buttomHeaderPadding") { buttomHeaderPadding = padding } From 8e216f8b9024841adcfa74a8716d31a021ccc281 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 29 Aug 2019 14:13:44 -0400 Subject: [PATCH 30/57] Corrections made. --- MVMCoreUI/Molecules/ActionDetailWithImage.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/MVMCoreUI/Molecules/ActionDetailWithImage.swift b/MVMCoreUI/Molecules/ActionDetailWithImage.swift index 6162fbc7..eb46bdc8 100644 --- a/MVMCoreUI/Molecules/ActionDetailWithImage.swift +++ b/MVMCoreUI/Molecules/ActionDetailWithImage.swift @@ -23,7 +23,7 @@ import UIKit // MARK: - Properties //------------------------------------------------------ - var buttomHeaderPadding: CGFloat = PaddingTwo + var buttonHeaderPadding: CGFloat = PaddingTwo //------------------------------------------------------ // MARK: - Constraints @@ -81,7 +81,7 @@ import UIKit header.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true leftContainer.trailingAnchor.constraint(equalTo: header.trailingAnchor).isActive = true - buttonTopConstraint = button.topAnchor.constraint(equalTo: header.bottomAnchor, constant: PaddingTwo) + buttonTopConstraint = button.topAnchor.constraint(equalTo: header.bottomAnchor, constant: buttonHeaderPadding) buttonTopConstraint?.isActive = true button.leadingAnchor.constraint(equalTo: leftContainer.leadingAnchor).isActive = true @@ -107,8 +107,8 @@ import UIKit button.updateView(size) imageLoader.updateView(size) leftContainer.updateView(size) - - buttonTopConstraint?.constant = header.headlineLabel.hasText || header.messageLabel.hasText ? PaddingTwo : 0 + + buttonTopConstraint?.constant = header.hasText() ? PaddingTwo : 0 } public override static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { @@ -127,7 +127,7 @@ import UIKit button.isHidden = false imageLoader.imageView.contentMode = .scaleAspectFit imageLoader.addSizeConstraintsForAspectRatio = true - buttomHeaderPadding = PaddingTwo + buttonHeaderPadding = PaddingTwo } override open func reset() { @@ -156,8 +156,8 @@ import UIKit guard let dictionary = json else { return } - if let padding = dictionary.optionalCGFloatForKey("buttomHeaderPadding") { - buttomHeaderPadding = padding + if let padding = dictionary.optionalCGFloatForKey("buttonHeaderPadding") { + buttonHeaderPadding = padding } header.setWithJSON(dictionary.optionalDictionaryForKey("headlineBody"), delegateObject: delegateObject, additionalData: additionalData) From 2792808c9eb585b9f9c92b99a125af0009b7d502 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 29 Aug 2019 14:20:42 -0400 Subject: [PATCH 31/57] Further changes made. --- MVMCoreUI/Molecules/ActionDetailWithImage.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/MVMCoreUI/Molecules/ActionDetailWithImage.swift b/MVMCoreUI/Molecules/ActionDetailWithImage.swift index eb46bdc8..ec91c479 100644 --- a/MVMCoreUI/Molecules/ActionDetailWithImage.swift +++ b/MVMCoreUI/Molecules/ActionDetailWithImage.swift @@ -108,7 +108,7 @@ import UIKit imageLoader.updateView(size) leftContainer.updateView(size) - buttonTopConstraint?.constant = header.hasText() ? PaddingTwo : 0 + buttonTopConstraint?.constant = header.hasText() ? buttonHeaderPadding : 0 } public override static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { @@ -137,7 +137,6 @@ import UIKit button.reset() imageLeadingConstraint?.constant = 16 imageLoader.reset() - setDefaultState() } @@ -147,7 +146,6 @@ import UIKit header.setAsMolecule() button.setAsMolecule() imageLoader.setAsMolecule() - setDefaultState() } From c2a432fd25ae60cfe4f45be2fd042bc6cb57cc02 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 29 Aug 2019 14:58:02 -0400 Subject: [PATCH 32/57] Updated localizable strings to include spanish. Renamed the variable to be more in line with its generic purpose. --- MVMCoreUI/Atoms/Views/Label.swift | 2 +- MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings | 2 +- .../SupportingFiles/Strings/es-MX.lproj/Localizable.strings | 3 +++ MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings | 3 +++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 635c45a9..36843803 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -584,7 +584,7 @@ extension Label { guard let text = text else { return nil } if accessibilityHint == nil { - accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "plan_selector_int_swipe_action_hint") + accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "swipe_to_select_with_action_hint") } let actionText = NSString(string: text).substring(with: range) diff --git a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings index 54b09109..4812d697 100644 --- a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings @@ -8,7 +8,7 @@ //// Accessibility "AccCloseButton" = "Close"; -"plan_selector_int_swipe_action_hint" = "swipe up or down to select action, then double tap to select."; +"swipe_to_select_with_action_hint" = "swipe up or down to select action, then double tap to select."; // Tab "AccTab" = ", tab"; "AccTabHint" = "Double tap to select."; diff --git a/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings index bf4f4e47..d6505503 100644 --- a/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings @@ -6,6 +6,9 @@ Copyright © 2017 myverizon. All rights reserved. */ +// Accessibility +"swipe_to_select_with_action_hint" = "deslízate hacia arriba o hacia abajo para seleccionar la acción, luego toca dos veces para seleccionar."; + "AccCloseButton" = "Cerrar"; // Tab "AccTab" = ", pestaña"; diff --git a/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings index bf4f4e47..d6505503 100644 --- a/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings @@ -6,6 +6,9 @@ Copyright © 2017 myverizon. All rights reserved. */ +// Accessibility +"swipe_to_select_with_action_hint" = "deslízate hacia arriba o hacia abajo para seleccionar la acción, luego toca dos veces para seleccionar."; + "AccCloseButton" = "Cerrar"; // Tab "AccTab" = ", pestaña"; From 38912a4f859a7c07255b89d06552d65335cb5918 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 29 Aug 2019 16:21:30 -0400 Subject: [PATCH 33/57] some changes made. More to come. --- MVMCoreUI/Atoms/Views/Label.swift | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 15ec60b2..8ede8588 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -254,16 +254,16 @@ public typealias ActionBlock = () -> () attributedString.removeAttribute(.foregroundColor, range: range) attributedString.addAttribute(.foregroundColor, value: UIColor.mfGet(forHex: colorHex), range: range) } - case "icon": + case "image": let fontSize = attribute["size"] as? CGFloat ?? label.font.pointSize - let iconName = attribute["iconName"] as? String ?? "externalLink" - let imageURL = attribute["image"] as? String + let imageName = attribute["name"] as? String ?? "externalLink" + let imageURL = attribute["URL"] as? String let imageAttachment: NSTextAttachment if let url = imageURL, let label = label as? Label { imageAttachment = Label.getTextAttachmentFrom(url: url, dimension: fontSize, label: label) } else { - imageAttachment = Label.getTextAttachmentImage(name: iconName, dimension: fontSize) + imageAttachment = Label.getTextAttachmentImage(name: imageName, dimension: fontSize) } let mutableString = NSMutableAttributedString() @@ -382,7 +382,7 @@ public typealias ActionBlock = () -> () // Loop the original attributed string, resize the image attachments. originalAttributedString.enumerateAttribute(.attachment, in: NSRange(location: 0, length: originalAttributedString.length), options: []) { value, range, stop in - if value is NSTextAttachment, let attachment = value as? NSTextAttachment, + if let attachment = value as? NSTextAttachment, let stylerSize = MFStyler.sizeObjectGeneric(forCurrentDevice: attachment.bounds.width)?.getValueBased(onSize: size) { let dimension = round(stylerSize) @@ -471,14 +471,16 @@ public typealias ActionBlock = () -> () let imageAttachment = NSTextAttachment() imageAttachment.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension) - DispatchQueue.main.async { + DispatchQueue.global(qos: .default).async { guard let url = URL(string: url), let data = try? Data(contentsOf: url) else { return } imageAttachment.image = UIImage(data: data) - label.setNeedsDisplay() + DispatchQueue.main.sync { + label.setNeedsDisplay() + } } return imageAttachment @@ -595,10 +597,9 @@ extension Label { @objc private func textLinkTapped(_ gesture: UITapGestureRecognizer) { for clause in clauses { - guard let range = clause.range else { return } // This determines if we tapped on the desired range of text. - if gesture.didTapAttributedTextInLabel(self, inRange: range) { + if let range = clause.range, gesture.didTapAttributedTextInLabel(self, inRange: range) { clause.performAction() return } From 62418f51326628741fd9d8396b5ed1789fc7b3a1 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 3 Sep 2019 10:07:15 -0400 Subject: [PATCH 34/57] Moved hasAttachmentImage to a function. --- MVMCoreUI/Atoms/Views/Label.swift | 66 +++++++++++++++---------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 8ede8588..1c3264cd 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -16,11 +16,8 @@ public typealias ActionBlock = () -> () //------------------------------------------------------ // MARK: - General Properties //------------------------------------------------------ - - public var makeWholeViewClickable = false - /// Indication that attributed text attachment will affect range location of attributed text. - public var hasAttachmentImageInsideText = false + public var makeWholeViewClickable = false /// Set this property if you want updateView to update the font based on this standard and the size passed in. public var standardFontSize: CGFloat = 0.0 @@ -241,7 +238,7 @@ public typealias ActionBlock = () -> () else { continue } let range = NSRange(location: location, length: length) - + switch attributeType { case "underline": attributedString.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: range) @@ -249,6 +246,7 @@ public typealias ActionBlock = () -> () case "strikethrough": attributedString.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.thick.rawValue, range: range) attributedString.addAttribute(.baselineOffset, value: 0, range: range) + case "color": if let colorHex = attribute.optionalStringForKey(KeyTextColor), !colorHex.isEmpty { attributedString.removeAttribute(.foregroundColor, range: range) @@ -267,23 +265,9 @@ public typealias ActionBlock = () -> () } let mutableString = NSMutableAttributedString() - let space = NSAttributedString(string: " ") - let attachment = NSAttributedString(attachment: imageAttachment) - - if location == 0 { - mutableString.append(attachment) - mutableString.append(space) - } else { - mutableString.append(space) - mutableString.append(attachment) - } - + mutableString.append(NSAttributedString(attachment: imageAttachment)) attributedString.insert(mutableString, at: location) - if location < attributedString.length { - (label as? Label)?.hasAttachmentImageInsideText = true - } - case "font": if let fontStyle = attribute.optionalStringForKey("style") { let styles = MFStyler.styleGetAttributedString("0", withStyle: fontStyle) @@ -379,17 +363,17 @@ public typealias ActionBlock = () -> () attributedString.addAttribute(.font, value: fontObj.withSize(stylerSize) as Any, range: range) } } - + // Loop the original attributed string, resize the image attachments. originalAttributedString.enumerateAttribute(.attachment, in: NSRange(location: 0, length: originalAttributedString.length), options: []) { value, range, stop in if let attachment = value as? NSTextAttachment, let stylerSize = MFStyler.sizeObjectGeneric(forCurrentDevice: attachment.bounds.width)?.getValueBased(onSize: size) { - + let dimension = round(stylerSize) attachment.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension) } } - + attributedText = attributedString } else if !MVMCoreGetterUtility.fequal(a: Float(standardFontSize), b: 0.0), let sizeObject = sizeObject ?? MFStyler.sizeObjectGeneric(forCurrentDevice: standardFontSize) { font = font.withSize(sizeObject.getValueBased(onSize: size)) @@ -415,8 +399,8 @@ public typealias ActionBlock = () -> () } /** - Appends an external link image to the end of the attributed string. - Will provide one whitespace to the left of the icon + Appends an external link image to the end of the attributed string. + Will provide one whitespace to the left of the icon */ @objc public func appendExternalLinkIcon() { @@ -433,13 +417,13 @@ public typealias ActionBlock = () -> () Insert external link icon anywhere within text of Label. - Note: Each icon insertion adds 2 additional characters to the overall text length. - This means that you MUST insert icons and links in the order they would appear. + This means that you MUST insert icons and links in the order they would appear. - parameter index: Location within the associated text to insert an external Link Icon */ public func insertExternalLinkIcon(at index: Int) { guard let attributedText = attributedText, index <= attributedText.string.count && index >= 0 else { return } - + let mutableString = NSMutableAttributedString(attributedString: attributedText) mutableString.insert(NSAttributedString(string: " "), at: index) mutableString.insert(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)), at: index + (index == 0 ? 0 : 1)) @@ -473,10 +457,10 @@ public typealias ActionBlock = () -> () DispatchQueue.global(qos: .default).async { - guard let url = URL(string: url), - let data = try? Data(contentsOf: url) - else { return } - + guard let url = URL(string: url), + let data = try? Data(contentsOf: url) + else { return } + imageAttachment.image = UIImage(data: data) DispatchQueue.main.sync { label.setNeedsDisplay() @@ -485,6 +469,23 @@ public typealias ActionBlock = () -> () return imageAttachment } + + /// Call to detect in the attributedText contains an NSTextAttachment. + func textContainsTextAttachment() -> Bool { + + guard let attributedText = attributedText else { return false } + + var containsAttachment = false + + attributedText.enumerateAttribute(.attachment, in: NSRange(location: 0, length: attributedText.length), options: []) { value, range, stop in + if value is NSTextAttachment { + containsAttachment = true + return + } + } + + return containsAttachment + } } // MARK: - Atomization @@ -495,7 +496,6 @@ extension Label { attributedText = nil textAlignment = .left originalAttributedString = nil - hasAttachmentImageInsideText = false styleB2(true) } @@ -625,7 +625,7 @@ extension UITapGestureRecognizer { 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) From 87cc0842de6e7b0edab11c94f09a4e4707b218d3 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 3 Sep 2019 10:36:16 -0400 Subject: [PATCH 35/57] removed programmatic space insert. --- MVMCoreUI/Atoms/Views/Label.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 1c3264cd..53efc5a6 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -425,8 +425,7 @@ public typealias ActionBlock = () -> () guard let attributedText = attributedText, index <= attributedText.string.count && index >= 0 else { return } let mutableString = NSMutableAttributedString(attributedString: attributedText) - mutableString.insert(NSAttributedString(string: " "), at: index) - mutableString.insert(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)), at: index + (index == 0 ? 0 : 1)) + mutableString.insert(NSAttributedString(attachment: Label.getTextAttachmentImage(dimension: font.pointSize)), at: index) self.attributedText = mutableString } From 255cde58e67fe0ace988c75dd600f1bd86734290 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 3 Sep 2019 14:56:48 -0400 Subject: [PATCH 36/57] Aligning with text to image change. --- MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m index 8583cc2e..fa26a7f7 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m @@ -235,7 +235,7 @@ if (color) { self.button.layer.borderColor = color.CGColor; [self.button setTitleColor:color forState:UIControlStateNormal]; - [self.closeButton setTitleColor:color forState:UIControlStateNormal]; + [self.closeButton setTintColor:color]; } }]; } From 658ed16bbdbe9b08bf41cc346358a64d1d9f8a71 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 3 Sep 2019 15:14:12 -0400 Subject: [PATCH 37/57] accordion list item --- MVMCoreUI.xcodeproj/project.pbxproj | 4 ++ .../AccordionMoleculeTableViewCell.swift | 40 +++++++++++++++++++ .../Items/MoleculeTableViewCell.swift | 18 ++++++--- .../MVMCoreUIMoleculeMappingObject.m | 1 + .../OtherHandlers/MoleculeDelegateProtocol.h | 4 ++ .../Templates/MoleculeListTemplate.swift | 30 ++++++++++++++ 6 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 2913a9a6..9768fcf8 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ D224798C231450C8003FCCF9 /* HeadlineBodySwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D224798B231450C8003FCCF9 /* HeadlineBodySwitch.swift */; }; D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */; }; D22479962316AF6E003FCCF9 /* HeadlineBodyTextButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479952316AF6D003FCCF9 /* HeadlineBodyTextButton.swift */; }; + D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */; }; D22D1F1A220341F60077CEC0 /* MVMCoreUICheckBox.h in Headers */ = {isa = PBXBuildFile; fileRef = D22D1F18220341F50077CEC0 /* MVMCoreUICheckBox.h */; settings = {ATTRIBUTES = (Public, ); }; }; D22D1F1B220341F60077CEC0 /* MVMCoreUICheckBox.m in Sources */ = {isa = PBXBuildFile; fileRef = D22D1F19220341F50077CEC0 /* MVMCoreUICheckBox.m */; }; D22D1F1E220343560077CEC0 /* MVMCoreUICheckMarkView.h in Headers */ = {isa = PBXBuildFile; fileRef = D22D1F1C220343560077CEC0 /* MVMCoreUICheckMarkView.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -208,6 +209,7 @@ D224798B231450C8003FCCF9 /* HeadlineBodySwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodySwitch.swift; sourceTree = ""; }; D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutConstraintExtension.swift; sourceTree = ""; }; D22479952316AF6D003FCCF9 /* HeadlineBodyTextButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyTextButton.swift; sourceTree = ""; }; + D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccordionMoleculeTableViewCell.swift; sourceTree = ""; }; D22D1F18220341F50077CEC0 /* MVMCoreUICheckBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUICheckBox.h; sourceTree = ""; }; D22D1F19220341F50077CEC0 /* MVMCoreUICheckBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUICheckBox.m; sourceTree = ""; }; D22D1F1C220343560077CEC0 /* MVMCoreUICheckMarkView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUICheckMarkView.h; sourceTree = ""; }; @@ -448,6 +450,7 @@ children = ( D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */, D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */, + D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */, ); path = Items; sourceTree = ""; @@ -994,6 +997,7 @@ DBC4391922442197001AB423 /* DashLine.swift in Sources */, D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */, D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */, + D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */, D22D1F1F220343560077CEC0 /* MVMCoreUICheckMarkView.m in Sources */, D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */, D29DF11721E6805F003B2FB9 /* UIColor+MFConvenience.m in Sources */, diff --git a/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift new file mode 100644 index 00000000..630dfb7d --- /dev/null +++ b/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift @@ -0,0 +1,40 @@ +// +// AccordionMoleculeTableViewCell.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 8/30/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers public class AccordionMoleculeTableViewCell: MoleculeTableViewCell { + let accordionButton = createAccordionButton() + + static func createAccordionButton() -> MFCustomButton { + let accordionButton = MFCustomButton(type: .custom) + accordionButton.setTitle("+", for: .normal) + accordionButton.setTitleColor(.black, for: .normal) + accordionButton.frame = CGRect(x: 0, y: 0, width: 20, height: 20) + return accordionButton + } + + override public func setupView() { + customAccessoryView = true + super.setupView() + accessoryView = accordionButton + } + + public override func didSelectCell(atIndex indexPath: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + accordionButton.isSelected = !accordionButton.isSelected + accordionButton.setTitle(accordionButton.isSelected ? "-" : "+", for: .normal) + guard let molecules = json?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] else { + return + } + if accordionButton.isSelected { + delegateObject?.moleculeDelegate?.addMolecules?(molecules, senderIndexPath: indexPath) + } else { + delegateObject?.moleculeDelegate?.removeMolecules?(molecules, senderIndexPath: indexPath) + } + } +} diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index c1054e33..167e0ea8 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -32,6 +32,9 @@ import UIKit case Between = "between" } + /// For subclasses that want to use a custom accessory view. + open var customAccessoryView = false + // MARK: - Inits public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -103,10 +106,12 @@ import UIKit } // Add the caret if there is an action and it's not declared hidden. - if let _ = json?.optionalDictionaryForKey("actionMap"), !json!.boolForKey("hideArrow") { - addCaretViewAccessory() - } else { - accessoryView = nil + if !customAccessoryView { + if let _ = json?.optionalDictionaryForKey("actionMap"), !json!.boolForKey("hideArrow") { + addCaretViewAccessory() + } else { + accessoryView = nil + } } // override the separator @@ -152,9 +157,10 @@ import UIKit public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { guard let molecule = molecule?.optionalDictionaryForKey(KeyMolecule) else { - return nil + return "\(self)<>" } - return MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) + let moleculeName = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) ?? "" + return "\(self)<\(moleculeName)>" } public static func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index fe84278b..9175781b 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -43,6 +43,7 @@ @"progressBar": ProgressBar.class, @"checkbox": MVMCoreUICheckBox.class, @"listItem": MoleculeTableViewCell.class, + @"accordionListItem": AccordionMoleculeTableViewCell.class, @"switch": MVMCoreUISwitch.class, @"leftRightLabelView": LeftRightLabelView.class, @"actionDetailWithImage": ActionDetailWithImage.class, diff --git a/MVMCoreUI/OtherHandlers/MoleculeDelegateProtocol.h b/MVMCoreUI/OtherHandlers/MoleculeDelegateProtocol.h index fa91e0fc..cfa1504f 100644 --- a/MVMCoreUI/OtherHandlers/MoleculeDelegateProtocol.h +++ b/MVMCoreUI/OtherHandlers/MoleculeDelegateProtocol.h @@ -16,4 +16,8 @@ /// Notifies the delegate that the molecule layout update. Should be called when the layout may change due to an async method. - (void)moleculeLayoutUpdated:(nonnull UIView *)molecule; +/// Asks the delegate to add or remove molecules. +- (void)addMolecules:(nonnull NSArray *)molecules senderIndexPath:(nonnull NSIndexPath *)indexPath; +- (void)removeMolecules:(nonnull NSArray *)molecules senderIndexPath:(nonnull NSIndexPath *)indexPath; + @end diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index abec1b01..7ad011b3 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -117,6 +117,36 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { } } + open override func addMolecules(_ molecules: [[AnyHashable: Any]], senderIndexPath indexPath: IndexPath) { + var indexPaths: [IndexPath] = [] + var moleculeList: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])] = [] + for (index, molecule) in molecules.enumerated() { + if let info = getMoleculeInfo(with: molecule) { + moleculeList.append(info) + indexPaths.append(IndexPath(row: indexPath.row + 1 + index, section: 0)) + tableView?.register(info.class, forCellReuseIdentifier: info.identifier) + } + } + moleculesInfo?.insert(contentsOf: moleculeList, at: indexPath.row + 1) + tableView?.insertRows(at: indexPaths, with: .automatic) + } + + open override func removeMolecules(_ molecules: [[AnyHashable: Any]], senderIndexPath indexPath: IndexPath) { + guard let moleculesList = moleculesInfo else { + return + } + var indexPaths: [IndexPath] = [] + for (index, moleculeInfo) in moleculesList.enumerated() { + if molecules.contains(where: { (molecule) -> Bool in + return NSDictionary(dictionary: molecule).isEqual(to: moleculeInfo.molecule) + }) { + indexPaths.append(IndexPath(row: index, section: 0)) + moleculesInfo?.remove(at: index) + } + } + tableView?.deleteRows(at: indexPaths, with: .automatic) + } + // MARK: - Convenience /// Returns the (identifier, class) of the molecule for the given map. func getMoleculeInfo(with molecule: [AnyHashable: Any]?) -> (identifier: String, class: AnyClass, molecule: [AnyHashable: Any])? { From e75b0d6d9a9b1441fc062de526ac93c9bc990365 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 3 Sep 2019 15:49:43 -0400 Subject: [PATCH 38/57] Set UIImageRenderingModeAlwaysTemplate to allow the tint change. --- MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m index 41237640..66aeaa06 100644 --- a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m @@ -181,7 +181,8 @@ static const CGFloat VertialShadowOffset = 6; + (nonnull MFCustomButton *)addCloseButtonToView:(UIView *)view action:(ButtonTapBlock)actionBlock verticalCentered:(BOOL)verticalCentered { MFCustomButton *button = [[MFCustomButton alloc] initWithFrame:CGRectZero]; button.translatesAutoresizingMaskIntoConstraints = NO; - [button setImage:[MVMCoreUIUtility imageNamed:@"closeXBlack"] forState:UIControlStateNormal]; + UIImage *image = [[MVMCoreUIUtility imageNamed:@"closeXBlack"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [button setImage:image forState:UIControlStateNormal]; button.titleLabel.font = [MFStyler fontForHeadlineAlternative]; //accessibility From 32b2ab825b07f52ae9633311cd380a11ee5d06b2 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 3 Sep 2019 15:52:23 -0400 Subject: [PATCH 39/57] hide separator flag --- MVMCoreUI/Atoms/Views/SeparatorView.h | 3 +++ MVMCoreUI/Atoms/Views/SeparatorView.m | 4 ++++ .../Molecules/Items/AccordionMoleculeTableViewCell.swift | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/MVMCoreUI/Atoms/Views/SeparatorView.h b/MVMCoreUI/Atoms/Views/SeparatorView.h index 89a9197d..40489b16 100644 --- a/MVMCoreUI/Atoms/Views/SeparatorView.h +++ b/MVMCoreUI/Atoms/Views/SeparatorView.h @@ -41,4 +41,7 @@ typedef enum : NSUInteger { - (void)setAsLight; - (void)setAsMedium; +/// Returns if the separator should be visible based on the type. +- (BOOL)shouldBeVisible; + @end diff --git a/MVMCoreUI/Atoms/Views/SeparatorView.m b/MVMCoreUI/Atoms/Views/SeparatorView.m index a666d450..9f85c311 100644 --- a/MVMCoreUI/Atoms/Views/SeparatorView.m +++ b/MVMCoreUI/Atoms/Views/SeparatorView.m @@ -162,6 +162,10 @@ [self setNeedsLayout]; [self layoutIfNeeded]; } + +- (BOOL)shouldBeVisible { + return ![[self.json string:KeyType] isEqualToString:@"none"]; +} #pragma mark - Molecule diff --git a/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift index 630dfb7d..12ce5c31 100644 --- a/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift @@ -31,10 +31,15 @@ import UIKit guard let molecules = json?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] else { return } + if accordionButton.isSelected { delegateObject?.moleculeDelegate?.addMolecules?(molecules, senderIndexPath: indexPath) } else { delegateObject?.moleculeDelegate?.removeMolecules?(molecules, senderIndexPath: indexPath) } + + if (json?.boolForKey("hideSeparatorWhenExpanded") ?? false) && (self.bottomSeparatorView?.shouldBeVisible() ?? false) { + bottomSeparatorView?.isHidden = accordionButton.isSelected + } } } From 9b336dc2ece0421fb5352d644db4dc0d54f1e1c1 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 3 Sep 2019 16:09:01 -0400 Subject: [PATCH 40/57] remove unneeded method call and set default tint as black. --- MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m index 66aeaa06..175714bc 100644 --- a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m @@ -183,7 +183,7 @@ static const CGFloat VertialShadowOffset = 6; button.translatesAutoresizingMaskIntoConstraints = NO; UIImage *image = [[MVMCoreUIUtility imageNamed:@"closeXBlack"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; [button setImage:image forState:UIControlStateNormal]; - button.titleLabel.font = [MFStyler fontForHeadlineAlternative]; + [button setTintColor:UIColor.blackColor]; //accessibility button.accessibilityLabel = [MVMCoreUIUtility hardcodedStringWithKey:@"AccCloseButton"]; From b32cbd856617f07e96e995aeef42f517eff15282 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 3 Sep 2019 16:09:55 -0400 Subject: [PATCH 41/57] objc. --- MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m index 175714bc..94c6ca85 100644 --- a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m @@ -183,7 +183,7 @@ static const CGFloat VertialShadowOffset = 6; button.translatesAutoresizingMaskIntoConstraints = NO; UIImage *image = [[MVMCoreUIUtility imageNamed:@"closeXBlack"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; [button setImage:image forState:UIControlStateNormal]; - [button setTintColor:UIColor.blackColor]; + [button setTintColor:[UIColor blackColor]]; //accessibility button.accessibilityLabel = [MVMCoreUIUtility hardcodedStringWithKey:@"AccCloseButton"]; From ea13603b7d61444ac433391908826bf999fcccad Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 3 Sep 2019 16:52:10 -0400 Subject: [PATCH 42/57] font update --- MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift index 12ce5c31..b188d45b 100644 --- a/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift @@ -15,6 +15,7 @@ import UIKit let accordionButton = MFCustomButton(type: .custom) accordionButton.setTitle("+", for: .normal) accordionButton.setTitleColor(.black, for: .normal) + accordionButton.titleLabel?.font = UIFont.systemFont(ofSize: 40, weight: .ultraLight) accordionButton.frame = CGRect(x: 0, y: 0, width: 20, height: 20) return accordionButton } From 2fd55f0affd3aa5a10243f2ad2d3860f2b68433c Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 3 Sep 2019 17:12:17 -0400 Subject: [PATCH 43/57] border the button --- .../HorizontalCombinationViews/TwoButtonView.swift | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift b/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift index 575c01ec..28ad6dc4 100644 --- a/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift +++ b/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift @@ -42,7 +42,8 @@ import UIKit open override func setupView() { super.setupView() - setupButton() + setupWithTwoButtons() + secondaryButton?.bordered = true } // MARK: - MVMCoreUIMoleculeViewProtocol @@ -60,10 +61,6 @@ import UIKit } // MARK: - Constraining - func setupButton() { - setupWithTwoButtons() - } - func createPrimaryButton() { if primaryButton == nil { primaryButton = PrimaryButton.button() From 81490ae3cfc3ebdb632867fbf64c455942cd7fdf Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 4 Sep 2019 09:04:02 -0400 Subject: [PATCH 44/57] Moved line. --- MVMCoreUI/Atoms/Views/Label.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 53efc5a6..0bf1dad5 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -460,8 +460,8 @@ public typealias ActionBlock = () -> () let data = try? Data(contentsOf: url) else { return } - imageAttachment.image = UIImage(data: data) DispatchQueue.main.sync { + imageAttachment.image = UIImage(data: data) label.setNeedsDisplay() } } From 9b5b256594631526bf843dcf9a901a86e43cc3cf Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 4 Sep 2019 09:55:05 -0400 Subject: [PATCH 45/57] Fixes Alert view color issue. --- MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m | 1 + 1 file changed, 1 insertion(+) diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m index fa26a7f7..eab759e8 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m @@ -173,6 +173,7 @@ if (closeButton && !self.closeButton) { self.closeButton = [self addCloseButtonWithAnimationDelegate:animationDelegate]; + [self.closeButton setTintColor:[UIColor whiteColor]]; } else if (!closeButton && self.closeButton) { [self.closeButton removeFromSuperview]; self.closeButton = nil; From 8a74886928a46500923b86586e88e7c6c3a080b3 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 4 Sep 2019 09:58:46 -0400 Subject: [PATCH 46/57] fixed commed. --- 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 0bf1dad5..4346dfa0 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -416,8 +416,8 @@ public typealias ActionBlock = () -> () /** Insert external link icon anywhere within text of Label. - - Note: Each icon insertion adds 2 additional characters to the overall text length. - This means that you MUST insert icons and links in the order they would appear. + - Note: Each icon insertion adds 1 additional characters to the overall text length. + Therefore, you MUST insert icons and links in the order they would appear. - parameter index: Location within the associated text to insert an external Link Icon */ public func insertExternalLinkIcon(at index: Int) { From 1bf69cb505e7c9136c696ea0085279e057e611a9 Mon Sep 17 00:00:00 2001 From: "Thirukamu, Ravivarma" Date: Wed, 4 Sep 2019 10:59:03 -0400 Subject: [PATCH 47/57] changing mftextfield background to clear color. --- MVMCoreUI/Atoms/TextFields/MFTextField.xib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atoms/TextFields/MFTextField.xib b/MVMCoreUI/Atoms/TextFields/MFTextField.xib index e839533f..9f3cf5c4 100644 --- a/MVMCoreUI/Atoms/TextFields/MFTextField.xib +++ b/MVMCoreUI/Atoms/TextFields/MFTextField.xib @@ -38,7 +38,7 @@ - + From 6883f1a61c1a74439fecff42b7b622d82ad908d6 Mon Sep 17 00:00:00 2001 From: "Thirukamu, Ravivarma" Date: Wed, 4 Sep 2019 11:07:18 -0400 Subject: [PATCH 48/57] Revert "changing mftextfield background to clear color." This reverts commit 1bf69cb505e7c9136c696ea0085279e057e611a9. --- MVMCoreUI/Atoms/TextFields/MFTextField.xib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atoms/TextFields/MFTextField.xib b/MVMCoreUI/Atoms/TextFields/MFTextField.xib index 9f3cf5c4..e839533f 100644 --- a/MVMCoreUI/Atoms/TextFields/MFTextField.xib +++ b/MVMCoreUI/Atoms/TextFields/MFTextField.xib @@ -38,7 +38,7 @@ - + From 1a23ca6e2759a5ec6b8fd797c15c73a3ae12d2c0 Mon Sep 17 00:00:00 2001 From: "Thirukamu, Ravivarma" Date: Wed, 4 Sep 2019 11:17:04 -0400 Subject: [PATCH 49/57] Adding outlet view in h file for global access. --- MVMCoreUI/Atoms/TextFields/MFTextField.h | 1 + MVMCoreUI/Atoms/TextFields/MFTextField.xib | 1 + 2 files changed, 2 insertions(+) diff --git a/MVMCoreUI/Atoms/TextFields/MFTextField.h b/MVMCoreUI/Atoms/TextFields/MFTextField.h index 72adf682..6b047c6c 100644 --- a/MVMCoreUI/Atoms/TextFields/MFTextField.h +++ b/MVMCoreUI/Atoms/TextFields/MFTextField.h @@ -33,6 +33,7 @@ @property (nullable, weak, nonatomic) UIView *view; @property (nullable, weak, nonatomic) IBOutlet UIView *textFieldContainerView; +@property (nullable, weak, nonatomic) IBOutlet UIView *backgroundView; @property (nullable, weak, nonatomic) IBOutlet UITextField *textField; @property (nullable, weak, nonatomic) IBOutlet Label *formLabel; @property (nullable, weak, nonatomic) IBOutlet UIView *separatorView;//make it public so outsider class can know the posistion of it. diff --git a/MVMCoreUI/Atoms/TextFields/MFTextField.xib b/MVMCoreUI/Atoms/TextFields/MFTextField.xib index e839533f..cb9821f1 100644 --- a/MVMCoreUI/Atoms/TextFields/MFTextField.xib +++ b/MVMCoreUI/Atoms/TextFields/MFTextField.xib @@ -11,6 +11,7 @@ + From a3757adacdd1a99f36b0faf9db964a018ce15eca Mon Sep 17 00:00:00 2001 From: "Robinson, Blake" Date: Wed, 4 Sep 2019 11:25:23 -0400 Subject: [PATCH 50/57] Adds nil check on contentColor to account for future possibility of contentColor having a value in this situation, which would a different tintColor on the button. --- MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m index eab759e8..b7e3a80a 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m @@ -173,7 +173,16 @@ if (closeButton && !self.closeButton) { self.closeButton = [self addCloseButtonWithAnimationDelegate:animationDelegate]; - [self.closeButton setTintColor:[UIColor whiteColor]]; + //Based on the way the code is ordered now in lines 68-70, contentColor should + //still be nil when setupCloseButton is called, making a nil check superflous. + //Since this ordering could change, however, it would be best to handle a situation + //in which the contentColor is black, for example, and the closeButton + //would need to be black as well. + if (self.contentColor == nil) { + [self.closeButton setTintColor:[UIColor whiteColor]]; + } else { + [self.closeButton setTintColor:self.contentColor]; + } } else if (!closeButton && self.closeButton) { [self.closeButton removeFromSuperview]; self.closeButton = nil; From 3ff48cf700d010c88dad456bcdd1c3365b99669b Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 4 Sep 2019 13:45:41 -0400 Subject: [PATCH 51/57] Style --- .../Items/MoleculeTableViewCell.swift | 51 +++++++++++++++++-- .../HeadlineBody.swift | 24 +++++++-- MVMCoreUI/Styles/MFStyler.h | 1 + MVMCoreUI/Styles/MFStyler.m | 11 +++- 4 files changed, 76 insertions(+), 11 deletions(-) diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index 167e0ea8..210eac6f 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -15,7 +15,6 @@ import UIKit // In updateView, will set padding to default. open var updateViewHorizontalDefaults = true - open var updateViewVerticalDefaults = true // For the accessory view convenience. public var caretView: CaretView? @@ -35,6 +34,45 @@ import UIKit /// For subclasses that want to use a custom accessory view. open var customAccessoryView = false + public var topMarginPadding: CGFloat = 24 + public var bottomMarginPadding: CGFloat = 24 + + // MARK: - Styling + func style(with styleString: String?) { + guard let styleString = styleString else { + return + } + switch styleString { + case "standard": + styleStandard() + case "header": + styleHeader() + case "none": + styleNone() + default: break + } + } + + func styleStandard() { + topMarginPadding = 24 + bottomMarginPadding = 24 + bottomSeparatorView?.show() + bottomSeparatorView?.setAsLight() + } + + func styleHeader() { + topMarginPadding = 48 + bottomMarginPadding = 16 + bottomSeparatorView?.show() + bottomSeparatorView?.setAsRegular() + } + + func styleNone() { + topMarginPadding = 0 + bottomMarginPadding = 0 + bottomSeparatorView?.hide() + } + // MARK: - Inits public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -48,7 +86,7 @@ import UIKit // MARK: - MFViewProtocol public func updateView(_ size: CGFloat) { - MFStyler.setDefaultMarginsFor(self, size: size, horizontal: updateViewHorizontalDefaults, vertical: updateViewVerticalDefaults) + 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. @@ -94,11 +132,14 @@ import UIKit public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { self.json = json; + style(with: json?.optionalStringForKey("style")) + if let useHorizontalMargins = json?.optionalBoolForKey("useHorizontalMargins") { updateViewHorizontalDefaults = useHorizontalMargins } - if let useVerticalMargins = json?.optionalBoolForKey("useVerticalMargins") { - updateViewVerticalDefaults = useVerticalMargins + if json?.optionalBoolForKey("useVerticalMargins") ?? false { + topMarginPadding = 0 + bottomMarginPadding = 0 } if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) { @@ -143,8 +184,8 @@ import UIKit public func reset() { molecule?.reset?() - updateViewVerticalDefaults = true updateViewHorizontalDefaults = true + styleStandard() backgroundColor = .white } diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift index ac0e416e..1077ac0e 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift @@ -18,6 +18,24 @@ open class HeadlineBody: ViewConstrainingView { var leftConstraintMessage: NSLayoutConstraint? var rightConstraintMessage: NSLayoutConstraint? + func hasText() -> Bool { + return headlineLabel.hasText || messageLabel.hasText + } + + // MARK: - Styling + func style(with styleString: String?) { + guard let styleString = styleString else { + return + } + switch styleString { + case "header": + stylePageHeader() + case "item": + styleListItem() + default: break + } + } + func styleLandingPageHeader() { headlineLabel.styleH1(true) messageLabel.styleB2(true) @@ -35,10 +53,6 @@ open class HeadlineBody: ViewConstrainingView { messageLabel.styleB2(true) spaceBetweenLabelsConstant = 0 } - - func hasText() -> Bool { - return headlineLabel.hasText || messageLabel.hasText - } // MARK: - MVMCoreViewProtocol open override func updateView(_ size: CGFloat) { @@ -109,6 +123,8 @@ open class HeadlineBody: ViewConstrainingView { open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + style(with: json?.optionalStringForKey("style")) + let headlineJSON = json?.optionalDictionaryForKey("headline") headlineLabel.setWithJSON(headlineJSON, delegateObject: delegateObject, additionalData: additionalData) let bodyJSON = json?.optionalDictionaryForKey("body") diff --git a/MVMCoreUI/Styles/MFStyler.h b/MVMCoreUI/Styles/MFStyler.h index 2ab3c2f2..267a0377 100644 --- a/MVMCoreUI/Styles/MFStyler.h +++ b/MVMCoreUI/Styles/MFStyler.h @@ -93,6 +93,7 @@ B3 -> Legal + (CGFloat)defaultVerticalPaddingForSize:(CGFloat)size; + (void)setDefaultMarginsForView:(nullable UIView *)view size:(CGFloat)size; + (void)setDefaultMarginsForView:(nullable UIView *)view size:(CGFloat)size horizontal:(BOOL)horizontal vertical:(BOOL)vertical; ++ (void)setMarginsForView:(nullable UIView *)view size:(CGFloat)size defaultHorizontal:(BOOL)horizontal top:(CGFloat)top bottom:(CGFloat)bottom; //------------------------------------------------- // Returns the fonts for these styles. Scales them as needed by default diff --git a/MVMCoreUI/Styles/MFStyler.m b/MVMCoreUI/Styles/MFStyler.m index dfc9909a..abe6c960 100644 --- a/MVMCoreUI/Styles/MFStyler.m +++ b/MVMCoreUI/Styles/MFStyler.m @@ -96,13 +96,20 @@ CGFloat const LabelWithInternalButtonLineSpace = 2; } + (void)setDefaultMarginsForView:(nullable UIView *)view size:(CGFloat)size horizontal:(BOOL)horizontal vertical:(BOOL)vertical { + CGFloat horizontalPadding = horizontal ? [MFStyler defaultHorizontalPaddingForSize:size] : 0; + CGFloat verticalPadding = vertical ? PaddingDefaultVerticalSpacing3 : 0; [MVMCoreDispatchUtility performBlockOnMainThread:^{ - CGFloat horizontalPadding = horizontal ? [MFStyler defaultHorizontalPaddingForSize:size] : 0; - CGFloat verticalPadding = vertical ? PaddingDefaultVerticalSpacing3 : 0; [MVMCoreUIUtility setMarginsForView:view leading:horizontalPadding top:verticalPadding trailing:horizontalPadding bottom:verticalPadding]; }]; } ++ (void)setMarginsForView:(nullable UIView *)view size:(CGFloat)size defaultHorizontal:(BOOL)horizontal top:(CGFloat)top bottom:(CGFloat)bottom { + CGFloat horizontalPadding = horizontal ? [MFStyler defaultHorizontalPaddingForSize:size] : 0; + [MVMCoreDispatchUtility performBlockOnMainThread:^{ + [MVMCoreUIUtility setMarginsForView:view leading:horizontalPadding top:top trailing:horizontalPadding bottom:bottom]; + }]; +} + #pragma mark - 2.0 fonts + (nullable UIFont *)fontH1:(BOOL)genericScaling { From e5a66dc1a3e652dca7572f7cbf0dcba65d499b43 Mon Sep 17 00:00:00 2001 From: "Murugan, Vimal" Date: Thu, 5 Sep 2019 14:53:42 +0530 Subject: [PATCH 52/57] width update for calculate correct height --- .../TopLabelsAndBottomButtonsTableViewController.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m index ca75b778..a2e66bc7 100644 --- a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m +++ b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m @@ -289,8 +289,7 @@ UIView *headerView = self.headerView; UIView *tableHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 0)]; - [MVMCoreUIUtility sizeViewToFit:headerView]; - + [MVMCoreUIUtility sizeViewToFit:headerView forWidth:[NSNumber numberWithFloat:[MVMCoreUISplitViewController getDetailViewWidth]]]; CGRect frame = tableHeader.frame; frame.size.height = CGRectGetHeight(headerView.frame); tableHeader.frame = frame; From a3e60ef4ac9f88aee52a7b4dcb673d58ace6d6ba Mon Sep 17 00:00:00 2001 From: "Murugan, Vimal" Date: Thu, 5 Sep 2019 18:53:18 +0530 Subject: [PATCH 53/57] controller reference updated for getting correct width --- .../TopLabelsAndBottomButtonsTableViewController.m | 2 +- MVMCoreUI/Utility/MVMCoreUIUtility.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m index a2e66bc7..8862170b 100644 --- a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m +++ b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m @@ -289,7 +289,7 @@ UIView *headerView = self.headerView; UIView *tableHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 0)]; - [MVMCoreUIUtility sizeViewToFit:headerView forWidth:[NSNumber numberWithFloat:[MVMCoreUISplitViewController getDetailViewWidth]]]; + [MVMCoreUIUtility sizeViewToFit:headerView]; CGRect frame = tableHeader.frame; frame.size.height = CGRectGetHeight(headerView.frame); tableHeader.frame = frame; diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.m b/MVMCoreUI/Utility/MVMCoreUIUtility.m index e8523a61..4f150783 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.m @@ -119,7 +119,7 @@ #pragma mark - Sizing + (CGFloat)getWidth { - UIViewController *controller = [MVMCoreUISession sharedGlobal].splitViewController ?: [MVMCoreUISession sharedGlobal].navigationController; + UIViewController *controller = [MVMCoreUISession sharedGlobal].splitViewController.navigationController ?: [MVMCoreUISession sharedGlobal].navigationController; if (controller) { return CGRectGetWidth(controller.view.bounds); } else { From 11db27de8853f277d356e879e97bd9cd7b7fc2f0 Mon Sep 17 00:00:00 2001 From: "Murugan, Vimal" Date: Thu, 5 Sep 2019 18:54:35 +0530 Subject: [PATCH 54/57] space updated --- .../TopLabelsAndBottomButtonsTableViewController.m | 1 + 1 file changed, 1 insertion(+) diff --git a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m index 8862170b..f48a7fd9 100644 --- a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m +++ b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m @@ -290,6 +290,7 @@ UIView *headerView = self.headerView; UIView *tableHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 0)]; [MVMCoreUIUtility sizeViewToFit:headerView]; + CGRect frame = tableHeader.frame; frame.size.height = CGRectGetHeight(headerView.frame); tableHeader.frame = frame; From 63322a7d24a241ea05781e1ebd354b3819742fbf Mon Sep 17 00:00:00 2001 From: "Murugan, Vimal" Date: Thu, 5 Sep 2019 19:00:07 +0530 Subject: [PATCH 55/57] updated the file --- .../TopLabelsAndBottomButtonsTableViewController.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m index f48a7fd9..ca75b778 100644 --- a/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m +++ b/MVMCoreUI/LegacyControllers/TopLabelsAndBottomButtonsTableViewController.m @@ -289,8 +289,8 @@ UIView *headerView = self.headerView; UIView *tableHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 0)]; - [MVMCoreUIUtility sizeViewToFit:headerView]; - + [MVMCoreUIUtility sizeViewToFit:headerView]; + CGRect frame = tableHeader.frame; frame.size.height = CGRectGetHeight(headerView.frame); tableHeader.frame = frame; From 5adce500533c509d03f0db7273f9b7cd0bd9a31b Mon Sep 17 00:00:00 2001 From: "Robinson, Blake" Date: Thu, 5 Sep 2019 10:28:50 -0400 Subject: [PATCH 56/57] Removed comment and used ternary operator based on code review --- MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m index b7e3a80a..e51ffc83 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m @@ -173,16 +173,7 @@ if (closeButton && !self.closeButton) { self.closeButton = [self addCloseButtonWithAnimationDelegate:animationDelegate]; - //Based on the way the code is ordered now in lines 68-70, contentColor should - //still be nil when setupCloseButton is called, making a nil check superflous. - //Since this ordering could change, however, it would be best to handle a situation - //in which the contentColor is black, for example, and the closeButton - //would need to be black as well. - if (self.contentColor == nil) { - [self.closeButton setTintColor:[UIColor whiteColor]]; - } else { - [self.closeButton setTintColor:self.contentColor]; - } + [self.closeButton setTintColor:self.contentColor ?:[UIColor whiteColor]]; } else if (!closeButton && self.closeButton) { [self.closeButton removeFromSuperview]; self.closeButton = nil; From 33754802bb7aac8d27503fc8a773dfdfc5657dfb Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 5 Sep 2019 11:20:55 -0400 Subject: [PATCH 57/57] Latest changes. Now including clause changes. --- MVMCoreUI/Atoms/Views/Label.swift | 36 +++++++++++++------ .../Atoms/Views/LabelWithInternalButton.swift | 4 +-- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 5624bb20..ed99fcac 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -56,13 +56,22 @@ public typealias ActionBlock = () -> () public struct ActionableClause { var range: NSRange? var actionBlock: ActionBlock? - var hash: Int = 0 + var accessibilityID: Int = 0 func performAction() { actionBlock?() } } + //------------------------------------------------------ + // MARK: - Convenience Setter For objective-C + //------------------------------------------------------ + + /// Sets the clauses array to empty. + @objc public func setEmptyClauses() { + clauses = [] + } + //------------------------------------------------------ // MARK: - Initialization //------------------------------------------------------ @@ -73,6 +82,7 @@ public typealias ActionBlock = () -> () numberOfLines = 0 lineBreakMode = .byWordWrapping translatesAutoresizingMaskIntoConstraints = false + clauses = [] accessibilityCustomActions = [] let tapGesture = UITapGestureRecognizer(target: self, action: #selector(textLinkTapped(_:))) @@ -295,9 +305,8 @@ public typealias ActionBlock = () -> () guard let actionLabel = label as? Label else { continue } actionLabel.addActionAttributes(range: range, string: attributedString) - let accessibleAction = actionLabel.customAccessibilityAction(range: range) let actionBlock = actionLabel.createActionBlockFrom(actionMap: json, additionalData: additionalData, delegateObject: delegate) - actionLabel.clauses.append(ActionableClause(range: range, actionBlock: actionBlock, hash: accessibleAction?.hash ?? -1)) + actionLabel.appendActionableClause(range: range, actionBlock: actionBlock) default: continue @@ -402,7 +411,7 @@ public typealias ActionBlock = () -> () /** Appends an external link image to the end of the attributed string. - Will provide one whitespace to the left of the icon + Will provide one whitespace to the left of the icon; adds 2 chars to the end of the string. */ @objc public func appendExternalLinkIcon() { @@ -419,7 +428,7 @@ public typealias ActionBlock = () -> () Insert external link icon anywhere within text of Label. - Note: Each icon insertion adds 1 additional characters to the overall text length. - Therefore, you MUST insert icons and links in the order they would appear. + Therefore, you **MUST** insert icons and links in the order they would appear. - parameter index: Location within the associated text to insert an external Link Icon */ public func insertExternalLinkIcon(at index: Int) { @@ -487,6 +496,12 @@ public typealias ActionBlock = () -> () return containsAttachment } + + func appendActionableClause(range: NSRange, actionBlock: @escaping ActionBlock) { + + let accessibleAction = customAccessibilityAction(range: range) + clauses.append(ActionableClause(range: range, actionBlock: actionBlock, accessibilityID: accessibleAction?.hash ?? -1)) + } } // MARK: - Atomization @@ -499,6 +514,7 @@ extension Label { originalAttributedString = nil styleB2(true) accessibilityCustomActions = [] + clauses = [] } @objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { @@ -527,7 +543,7 @@ extension Label { // MARK: - Multi-Action Functionality extension Label { - /// Reseting to default Label values. + /// Applied to existing text. Removes underlines of tappable links and assoated actionable clauses. @objc public func clearActionableClauses() { guard let attributedText = attributedText else { return } @@ -576,8 +592,7 @@ extension Label { @objc public func addTappableLinkAttribute(range: NSRange, actionBlock: @escaping ActionBlock) { setActionAttributes(range: range) - let accessibleAction = customAccessibilityAction(range: range) - clauses.append(ActionableClause(range: range, actionBlock: actionBlock, hash: accessibleAction?.hash ?? -1)) + appendActionableClause(range: range, actionBlock: actionBlock) } /** @@ -592,9 +607,8 @@ extension Label { @objc public func addTappableLinkAttribute(range: NSRange, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) { setActionAttributes(range: range) - let accessibleAction = customAccessibilityAction(range: range) let actionBlock = createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject) - clauses.append(ActionableClause(range: range, actionBlock: actionBlock, hash: accessibleAction?.hash ?? -1)) + appendActionableClause(range: range, actionBlock: actionBlock) } @objc private func textLinkTapped(_ gesture: UITapGestureRecognizer) { @@ -668,7 +682,7 @@ extension Label { @objc public func accessibilityCustomAction(_ action: UIAccessibilityCustomAction) { for clause in clauses { - if action.hash == clause.hash { + if action.hash == clause.accessibilityID { clause.performAction() return } diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index 39b996a2..bc1c2219 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -67,11 +67,11 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt guard let label = label else { return } let accessibleAction = UIAccessibilityCustomAction(name: actionText ?? "", target: label, selector: #selector(label.accessibilityCustomAction(_:))) - label.clauses = [Label.ActionableClause(range: actionRange, actionBlock: newActionBlock, hash: accessibleAction.hash)] + label.clauses = [Label.ActionableClause(range: actionRange, actionBlock: newActionBlock, accessibilityID: accessibleAction.hash)] label.accessibilityCustomActions = [accessibleAction] if label.accessibilityHint == nil { - label.accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "plan_selector_int_swipe_action_hint") + label.accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "swipe_to_select_with_action_hint") } } }