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/24] 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/24] 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 7a86febc7c8f7ce60fb46b0b182dfd7cf44231c5 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 25 Jul 2019 15:15:32 -0400 Subject: [PATCH 03/24] 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 04/24] 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 05/24] 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 06/24] 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 07/24] 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 08/24] 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 09/24] 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 10/24] 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 11/24] 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 12/24] 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 13/24] 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 abde89f06fb5d5cb587b86a33a1fed568362cd3f Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 14 Aug 2019 12:58:46 -0400 Subject: [PATCH 14/24] 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 15/24] 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 16/24] 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 17/24] 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 c7501f9cd6629b31fec20fc29128f5dbe9f985d3 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 27 Aug 2019 16:28:19 -0400 Subject: [PATCH 18/24] 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 19/24] 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 38912a4f859a7c07255b89d06552d65335cb5918 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 29 Aug 2019 16:21:30 -0400 Subject: [PATCH 20/24] 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 21/24] 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 22/24] 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 81490ae3cfc3ebdb632867fbf64c455942cd7fdf Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 4 Sep 2019 09:04:02 -0400 Subject: [PATCH 23/24] 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 8a74886928a46500923b86586e88e7c6c3a080b3 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 4 Sep 2019 09:58:46 -0400 Subject: [PATCH 24/24] 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) {