From c791d7867185109239f010e10bfb2a3c01cba93a Mon Sep 17 00:00:00 2001 From: "Christiano, Kevin" Date: Fri, 29 Mar 2019 16:37:51 -0400 Subject: [PATCH] Working with ranges. Overall improvement of swift code. --- .../Atoms/Views/LabelWithInternalButton.swift | 254 +++++++++--------- 1 file changed, 122 insertions(+), 132 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index c87f0c54..10ad74dd 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -10,6 +10,7 @@ import MVMCore public typealias ActionBlock = () -> Void +private typealias ActionIndiciesTuple = (startIndex: String.Index?, endIndex: String.Index?, revisedText: String?) public typealias ActionObjectDelegate = (NSObject & MVMCoreActionDelegateProtocol) public typealias ButtonObjectDelegate = (NSObject & ButtonDelegateProtocol) public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProtocol & MVMCoreLoadDelegateProtocol & MVMCorePresentationDelegateProtocol & NSObjectProtocol @@ -23,15 +24,18 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt public var actionBlock: ActionBlock? public weak var label: MFLabel? - public var alternateAttributeForActionText: String? + // FIXME: I think there are scenarios where attributed text is being set with attributes but there is no text to set. public var attributedText: NSAttributedString? { didSet(newAttributedText) { - if newAttributedText != nil { - let mutableAttributedText = newAttributedText as? NSMutableAttributedString + if let newAttribText = newAttributedText, !newAttribText.string.isEmpty { + let mutableAttributedText = newAttribText as? NSMutableAttributedString let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = CGFloat(LabelWithInternalButtonLineSpace) - mutableAttributedText?.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: newAttributedText?.length ?? 0)) + + if newAttribText.length > 0 { + mutableAttributedText?.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: newAttribText.length)) + } if let mutableAttText = mutableAttributedText { label?.attributedText = mutableAttText @@ -41,10 +45,10 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt } // By default, it will follow most of the font standard in zepplin, and should need to be changed - public var normalTextFont: UIFont? - public var actionTextFont: UIFont? - public var normalTextColor: UIColor? - public var actionTextColor: UIColor? + public var normalTextFont: UIFont? = MFStyler.fontB2() + public var actionTextFont: UIFont? = MFStyler.fontB2() + public var normalTextColor: UIColor = .black + public var actionTextColor: UIColor = .black public var makeWholeViewClickable = false @@ -89,13 +93,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt setup() } - public init(frontText: String?, - actionText: String?, - backText: String?, - actionMap: [AnyHashable: Any]?, - additionalData: [AnyHashable: Any]?, - actionDelegate delegate: ActionObjectDelegate?, - buttonDelegate: ButtonObjectDelegate?) { + public init(frontText: String?, actionText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) { super.init(frame: CGRect.zero) setFrontText(frontText, actionText: actionText, actionMap: actionMap, backText: backText, additionalData: additionalData, delegate: delegate, buttonDelegate: buttonDelegate) @@ -103,6 +101,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt // MARK: - legacy public init(frontText: String?, actionText: String?, backText: String?, actionBlock block: ActionBlock?) { + super.init(frame: CGRect.zero) self.frontText = frontText self.actionText = actionText @@ -112,18 +111,9 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt setup() } - public convenience init(actionMap: [AnyHashable: Any]?, - additionalData: [AnyHashable: Any]?, - actionDelegate delegate: ActionObjectDelegate?, - buttonDelegate: ButtonObjectDelegate?) { + public convenience init(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) { - self.init(frontText: actionMap?.optionalStringForKey(KeyTitlePrefix), - actionText: actionMap?.optionalStringForKey(KeyTitle), - backText: actionMap?.optionalStringForKey(KeyTitlePostfix), - actionMap: actionMap, - additionalData: additionalData, - actionDelegate: delegate, - buttonDelegate: buttonDelegate) + self.init(frontText: actionMap?.optionalStringForKey(KeyTitlePrefix), actionText: actionMap?.optionalStringForKey(KeyTitle), backText: actionMap?.optionalStringForKey(KeyTitlePostfix), actionMap: actionMap, additionalData: additionalData, actionDelegate: delegate, buttonDelegate: buttonDelegate) } public convenience init(frontText: String?, backText: String?, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) { @@ -187,22 +177,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt label.sizeToFit() } - if normalTextColor == nil { - normalTextColor = .black - } - - if actionTextColor == nil { - actionTextColor = .black - } - - if normalTextFont == nil { - normalTextFont = MFStyler.fontB2() - } - - if actionTextFont == nil { - actionTextFont = MFStyler.fontB2() - } - //adding the underline setAlternateActionTextAttributes([NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)]) @@ -210,7 +184,8 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt self.label?.accessibilityTraits = .button } - private func setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) { + private func + setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?, buttonDelegate: ButtonObjectDelegate?) { weak var weakSelf: LabelWithInternalButton? = self weak var weakDelegate: ActionObjectDelegate? = delegate @@ -303,7 +278,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt @objc public func updateView(_ size: CGFloat) { - //reset font for app size change + // Reset font for app size change normalTextFont = MFStyler.fontB2() actionTextFont = MFStyler.fontB2() label?.attributedText = attributedText @@ -364,7 +339,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt frontText?.append(" ") } - if let actionTxt = actionText, !actionTxt.isEmpty { + if let actionTxt = actionText, !actionTxt.isEmpty, let backTxt = backText, !backTxt.isEmpty { actionText?.append(" ") } @@ -376,16 +351,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt return NSRange(location: frontText?.count ?? 0, length: actionText?.count ?? 0) } - private func getFrontRange() -> NSRange { - - return NSRange(location: 0, length: frontText?.count ?? 0) - } - - private func getBackRange() -> NSRange { - - return NSRange(location: (frontText?.count ?? 0) + (actionText?.count ?? 0), length: backText?.count ?? 0) - } - private func getRangeArrayOfWords(in string: String?, withInitalIndex index: Int) -> [Any]? { var index = index @@ -427,54 +392,42 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt private func setText(_ text: String?, startTag: String?, endTag: String?) { - let _text = text - let actionRange: NSRange = rangeOfText(_text, startTag: startTag, endTag: endTag) + guard let actionRange: ActionIndiciesTuple = rangeOfText(text, startTag: startTag, endTag: endTag) else { return } - frontText = (_text as NSString?)?.substring(with: NSRange(location: 0, length: actionRange.location)) - actionText = (_text as NSString?)?.substring(with: actionRange) - - if let frontTextCount = frontText?.count, let actiontextCount = actionText?.count { - backText = (_text as NSString?)?.substring(with: NSRange(location: frontTextCount + actiontextCount, length: (_text?.count ?? 0) - frontTextCount - actiontextCount)) + if let revisedText = actionRange.revisedText, let startBraceIndex = actionRange.startIndex, let endBraceIndex = actionRange.endIndex { + + frontText = String(revisedText[revisedText.startIndex.. NSRange { + + private func rangeOfText(_ text: String?, startTag: String?, endTag: String?) -> ActionIndiciesTuple? { - return rangeOfText(text, startTag: "{", endTag: "}") - } - - // TODO: Review this - private func rangeOfText(_ text: String?, startTag: String?, endTag: String?) -> NSRange { + var fullText = text ?? "" - var fullText = text - var range = NSRange(location: 0, length: 0) - let rangeOfLeftBrace: NSRange? = (fullText as NSString?)?.range(of: startTag ?? "") + guard let start = startTag, let end = endTag else { return nil } - if rangeOfLeftBrace?.location != NSNotFound { - - if let rangeOfLeftBrace = rangeOfLeftBrace { - fullText = (fullText as NSString?)?.replacingCharacters(in: rangeOfLeftBrace, with: "") - } - let rangeOfRightBrace: NSRange? = (fullText as NSString?)?.range(of: endTag ?? "") - - if rangeOfRightBrace?.location != NSNotFound { - - let length: Int = (rangeOfRightBrace?.location ?? 0) - (rangeOfLeftBrace?.location ?? 0) - - if length > 0 { - range = NSRange(location: rangeOfLeftBrace?.location ?? 0, length: length) - if let rangeOfRightBrace = rangeOfRightBrace { - fullText = (fullText as NSString?)?.replacingCharacters(in: rangeOfRightBrace, with: "") - } - } - } + if !fullText.contains(Character(start)) && !fullText.contains(Character(end)) { + return nil } - return range + var actionRange: ActionIndiciesTuple + + if let leftBrace = startTag, let rightBrace = endTag { + actionRange.startIndex = fullText.firstIndex(of: Character(leftBrace)) + fullText = fullText.replacingOccurrences(of: leftBrace, with: "") + + actionRange.endIndex = fullText.firstIndex(of: Character(rightBrace)) + fullText = fullText.replacingOccurrences(of: rightBrace, with: "") + } + + self.text = fullText + actionRange.revisedText = fullText + return actionRange } @objc public func setActionMap(_ actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, actionDelegate delegate: ActionObjectDelegate?) { @@ -520,21 +473,38 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt if let theseAttributes = attributes as? [NSAttributedString.Key: Any], let thisAttributedText = attributedText { let attributedString = NSMutableAttributedString(attributedString: thisAttributedText) - attributedString.addAttributes(theseAttributes, range: getActionRange()) + if !attributedString.string.isEmpty { + attributedString.addAttributes(theseAttributes, range: getActionRange()) + } attributedText = attributedString } } @objc public func setAlternateNormalTextAttributes(_ attributes: [AnyHashable: Any]?) { - if let thisAttributedText = attributedText, let theseAttributes = attributes as? [NSAttributedString.Key: Any] { - let attributedString = NSMutableAttributedString(attributedString: thisAttributedText) - attributedString.addAttributes(theseAttributes, range: getFrontRange()) - attributedString.addAttributes(theseAttributes, range: getBackRange()) + if let _attributedText = attributedText, let _attributes = attributes as? [NSAttributedString.Key: Any] { + let attributedString = NSMutableAttributedString(attributedString: _attributedText) + if !attributedString.string.isEmpty { + attributedString.addAttributes(_attributes, range: getFrontRange()) + attributedString.addAttributes(_attributes, range: getBackRange()) + } attributedText = attributedString } } + private func getFrontRange() -> NSRange { + + return NSRange(location: 0, length: frontText?.count ?? 0) + } + + private func getBackRange() -> NSRange { + + let textLocation: Int = (frontText?.count ?? 0) + (actionText?.count ?? 0) + let rangeLength: Int = backText?.count ?? 0 + + return NSRange(location: textLocation, length: rangeLength) + } + @objc public func setActionTextString(_ actionText: String?) { self.actionText = actionText @@ -588,10 +558,8 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt return UIAccessibilityCustomAction() } - } - extension LabelWithInternalButton: MVMCoreUIMoleculeViewProtocol { //------------------------------------------------------ // MARK: - Atomization @@ -600,48 +568,70 @@ extension LabelWithInternalButton: MVMCoreUIMoleculeViewProtocol { // Default values for view. @objc open func setAsMolecule() { - /* - - var frontText: String? - var actionText: String? - var backText: String? - var attributedText: NSAttributedString? - // By default, it will follow most of the font standard in zepplin, and should need to be changed - var normalTextFont: UIFont? - var actionTextFont: UIFont? - var normalTextColor: UIColor? - var actionTextColor: UIColor? - var alternateAttributeForActionText: String? - var makeWholeViewClickable = false - */ } @objc open func setWithJSON(_ json: [AnyHashable: Any]?, delegate: NSObject?, additionalData: [AnyHashable: Any]?) { // Configure class properties with JSON values - guard let jsonDictionary = json else { return } + guard let dictionary = json else { return } - if let backgroundColorHex = jsonDictionary[KeyBackgroundColor] as? String { - backgroundColor = UIColor.mfGet(forHex: backgroundColorHex) + if let backgroundColorHex = dictionary[KeyBackgroundColor] as? String { + self.backgroundColor = UIColor.mfGet(forHex: backgroundColorHex) } - // if let strokeColorHex = jsonDictionary["strokeColor"] as? String { - // strokeColor = UIColor.mfGet(forHex: strokeColorHex) - // } - // - // if let isHiddenValue = jsonDictionary[KeyIsHidden] as? Bool { - // isHidden = isHiddenValue - // } - // - // if let isOpaqueValue = jsonDictionary[KeyIsOpaque] as? Bool { - // isOpaque = isOpaqueValue - // } - // - // if let lineWidthValue = jsonDictionary["lineWidth"] as? CGFloat { - // lineWidth = lineWidthValue - // } + if let normalTextFont = dictionary["normalTextFont"] as? String, let normalSize = dictionary["normalSize"] as? CGFloat { + self.normalTextFont = UIFont(name: normalTextFont, size: normalSize) + } + if let actionTextFont = dictionary["actionTextFont"] as? String, let actionSize = dictionary["actionSize"] as? CGFloat { + self.actionTextFont = UIFont(name: actionTextFont, size: actionSize) + } + if let normalTextColorHex = dictionary["normalTextColor"] as? String { + self.normalTextColor = UIColor.mfGet(forHex: normalTextColorHex) + } + + if let actionTextColorHex = dictionary["actionTextColor"] as? String { + self.actionTextColor = UIColor.mfGet(forHex: actionTextColorHex) + } + + if let makeWholeViewClickable = dictionary["makeWholeViewClickable"] as? Bool { + self.makeWholeViewClickable = makeWholeViewClickable + } + + if let frontText = dictionary["frontText"] as? String { + self.frontText = frontText + } + + if let backText = dictionary["backText"] as? String { + self.backText = backText + } + + if let actionText = dictionary["actionText"] as? String { + self.actionText = actionText + } + + // Want this to be last because it has a didSet feature. + if let text = dictionary["text"] as? String { + self.text = text + } } - } + + +/* + public var actionBlock: ActionBlock? + + public var alternateAttributeForActionText: String? + + let mutableAttributedText = newAttributedText as? NSMutableAttributedString + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.lineSpacing = CGFloat(LabelWithInternalButtonLineSpace) + mutableAttributedText?.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: newAttributedText?.length ?? 0)) + + + override open var isEnabled: Bool { + didSet { + alpha = isEnabled ? 1 : DisableOppacity + } + */