diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 8ca484e3..dc3b4597 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -9,12 +9,19 @@ import MVMCore +public typealias ActionBlock = () -> Void @objc open class Label: UILabel, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol { //------------------------------------------------------ // MARK: - Properties //------------------------------------------------------ + var actionBlock: ActionBlock? + var actionText: String? + var frontText: String? + + var makeWholeViewClickable = false + // Set this property if you want updateView to update the font based on this standard and the size passed in. @objc public var standardFontSize: CGFloat = 0.0 @@ -303,6 +310,71 @@ import MVMCore } } +// MARK: - UIControl Override extension Label { - + + override open func touchesEnded(_ touches: Set, with event: UIEvent?) { + + if areTouches(inActionString: touches) { + if let action = actionBlock { + action() + } + } + } + + private func areTouches(inActionString touches: Set?) -> Bool { + + if UIAccessibility.isVoiceOverRunning || makeWholeViewClickable { + return true + } + + let location: CGPoint? = touches?.first?.location(in: self) + let index: Int = NSRange(location: frontText?.count ?? 0, length: actionText?.count ?? 0).location + let rangeArray = getRangeArrayOfWords(in: actionText, withInitalIndex: index) + let rectArray = getRectArray(from: rangeArray) as? [NSValue] ?? [] + + for rect in rectArray { + let wordRect: CGRect = rect.cgRectValue + + if let position = location, wordRect.contains(position) { + return true + + } else if wordRect.origin == .zero && wordRect.size.height == 0 && wordRect.size.width == 0 { + // Incase word rect is not found for any reason, make the whole label to be clicable to avoid non functioning link in production. + return true + } + } + + return false + } + + private func getRangeArrayOfWords(in string: String?, withInitalIndex index: Int) -> [Any]? { + + var index = index + let words = string?.components(separatedBy: " ") ?? [] + var rangeArray = [AnyHashable]() + + for word in words { + let finalWord = word + " " + let length: Int = finalWord.count + let wordRange = NSRange(location: index, length: length) + let rangeValue = NSValue(range: wordRange) + rangeArray.append(rangeValue) + index += length + } + + return rangeArray + } + + private func getRectArray(from rangeArray: [Any]?) -> [Any]? { + + var rectArray = [AnyHashable]() + + for range in rangeArray as? [NSValue] ?? [] { + let rectValue = NSValue(cgRect: boundingRect(forCharacterRange: range.rangeValue)) + rectArray.append(rectValue) + } + + return rectArray + } } diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index 071e0242..883819e3 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -9,7 +9,6 @@ import MVMCore -public typealias ActionBlock = () -> Void private typealias ActionableStringTuple = (front: String?, action: String?, end: String?) public typealias ActionObjectDelegate = NSObjectProtocol & MVMCoreActionDelegateProtocol public typealias ButtonObjectDelegate = NSObjectProtocol & ButtonDelegateProtocol @@ -21,7 +20,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt // MARK: - Properties //------------------------------------------------------ - public var actionBlock: ActionBlock? public weak var label: Label? public var attributedText: NSAttributedString? { @@ -66,7 +64,11 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt return NSRange(location: frontText?.count ?? 0, length: actionText?.count ?? 0) } - public var makeWholeViewClickable = false + public var makeWholeViewClickable = false { + willSet(newBool) { + label?.makeWholeViewClickable = newBool + } + } override open var isEnabled: Bool { didSet { @@ -74,10 +76,25 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt } } - public var frontText: String? - public var actionText: String? + public var frontText: String? { + willSet(newFrontText) { + label?.frontText = newFrontText + } + } + public var actionText: String? { + willSet(newActionText) { + label?.actionText = newActionText + } + } + public var backText: String? + public var actionBlock: ActionBlock? { + willSet(newActionBlock) { + label?.actionBlock = newActionBlock + } + } + private var text: String? { willSet(newText) { attributedText = NSAttributedString(string: newText ?? "") @@ -169,10 +186,9 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt private func setup() { if self.label == nil { - let label = Label(frame: CGRect.zero) + let label = Label(frame: .zero) - backgroundColor = .clear - label.isUserInteractionEnabled = false + label.isUserInteractionEnabled = true label.setContentCompressionResistancePriority(.required, for: .vertical) addSubview(label) NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[label]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["label": label])) @@ -237,10 +253,8 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt } if let b2Font = MFStyler.fontB2(), - let actions = actionMap, - actions.keys.count > 0, - let actionString = actions.optionalStringForKey(KeyTitle), - !actionString.isEmpty { + let actions = actionMap, actions.keys.count > 0, + let actionString = actions.optionalStringForKey(KeyTitle), !actionString.isEmpty { let actionStringOnLine = actionString + (addNewLine ? "\n" : " ") actionText = actionStringOnLine @@ -270,50 +284,13 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt } //------------------------------------------------------ - // MARK: - UIControl Override + // MARK: - UIControl //------------------------------------------------------ - override open func touchesEnded(_ touches: Set, with event: UIEvent?) { - - if areTouches(inActionString: touches) { - sendActions(for: .touchUpInside) - if let action = actionBlock { - action() - } - } else { - sendActions(for: .touchUpOutside) - } - } - - private func areTouches(inActionString touches: Set?) -> Bool { - - if UIAccessibility.isVoiceOverRunning || makeWholeViewClickable { - return true - } - - let location: CGPoint? = touches?.first?.location(in: label) - let actionString = actionText - let index: Int = actionRange.location - let rangeArray = getRangeArrayOfWords(in: actionString, withInitalIndex: index) - let rectArray = getRectArray(fromRangeArray: rangeArray) - var result = false - - for aValueOfRect in rectArray as? [NSValue] ?? [] { - let wordRect: CGRect = aValueOfRect.cgRectValue - - if let position = location, wordRect.contains(position) { - result = true - break - } else if wordRect.origin.x == 0 && wordRect.origin.y == 0 && wordRect.size.height == 0 && wordRect.size.width == 0 { - // Incase word rect is not found for any reason, make the whole label to be clicable to avoid non functioning link in production. - result = true - break - } - } - - return result - } - +// override open func sendAction(_ action: Selector, to target: Any?, for event: UIEvent?) { +// <#code#> +// } + //------------------------------------------------------ // MARK: - Helper //------------------------------------------------------ @@ -331,40 +308,6 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt return "\(frontText ?? "")\(actionText ?? "")\(backText ?? "")" } - private func getRangeArrayOfWords(in string: String?, withInitalIndex index: Int) -> [Any]? { - - var index = index - let words = string?.components(separatedBy: " ") - var rangeArray = [AnyHashable]() - - for subString in words ?? [] { - let finalSubString = subString + " " - let wordIndex: Int = index - let length: Int = finalSubString.count - let subStringRange = NSRange(location: wordIndex, length: length) - let rangeValue = NSValue(range: subStringRange) - rangeArray.append(rangeValue) - index += length - } - - return rangeArray - } - - private func getRectArray(fromRangeArray rangeArray: [Any]?) -> [Any]? { - - var rectArray = [AnyHashable]() - - for aValueOfRange in rangeArray as? [NSValue] ?? [] { - let wordRange: NSRange = aValueOfRange.rangeValue - if let rect: CGRect = label?.boundingRect(forCharacterRange: wordRange) { - let rectValue = NSValue(cgRect: rect) - rectArray.append(rectValue) - } - } - - return rectArray - } - @objc public func setCurlyBracedText(_ text: String) { setText(text, startTag: "{", endTag: "}") @@ -375,10 +318,8 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt let actionableTuple: ActionableStringTuple = rangeOfText(text, startTag: startTag, endTag: endTag) if let text = text, - let leftTag = startTag, - text.contains(leftTag), - let rightTag = endTag, - text.contains(rightTag), + let leftTag = startTag, text.contains(leftTag), + let rightTag = endTag, text.contains(rightTag), let front = actionableTuple.front, let middle = actionableTuple.action, let end = actionableTuple.end {