How to replace detected link with custom title for that link in MessageKit using Swift?

237 Views Asked by At

These are my datasSource and delegate methods for my chat:

func messageForItem(at indexPath: IndexPath, in _: MessagesCollectionView) -> MessageType {
    viewModel.message(at: indexPath) //here is returnd object that conform to protocl MessageType, one of its properties is messgaeKind where is defined attributedText(attributedString)
}

func enabledDetectors(for _: MessageType, at _: IndexPath, in _: MessagesCollectionView) -> [DetectorType] {
    [.url, .phoneNumber]
}

func detectorAttributes(
    for _: DetectorType,
    and message: MessageType,
    at _: IndexPath
) -> [NSAttributedString.Key: Any] {
    [.underlineStyle: 1, .foregroundColor: isFromCurrentSender(message: message) ? UIColor.white : UIColor.black]
}

And this is how it looks now:

enter image description here

I have tried to replace attributedString for messageKind like this:

//This is part of MessageType object. One of required properties is `var kind: MessageKind`:
var kind: MessageKind {
    return .attributedText(attributedString.prettyLinked)
}


**attributedString** - ✅ it works, links are detected

Moze tez byc kilka linkow w wiadomosci, pierwszy https://joytst.page.link/g9XaJeuffcH7koXk9?title=Głosowanie%20ze%20spacją i drugi tez obok https://joytst.page.link/g9XaJeuffcH7koXk9?title=Głosowanie i jeszcze koniec wiadomosci!{
    NSColor = "UIExtendedSRGBColorSpace 0.2 0.2 0.2 1";
    NSFont = "<UICTFont: 0x109215210> font-family: \"Poppins-Regular\"; font-weight: normal; font-style: normal; font-size: 16.00pt";
}

attributedString.prettyLinked - ❌ it doesn't work, links are not detected

Moze tez byc kilka linkow w wiadomosci, pierwszy {
    NSColor = "UIExtendedSRGBColorSpace 0.2 0.2 0.2 1";
    NSFont = "<UICTFont: 0x109215210> font-family: \"Poppins-Regular\"; font-weight: normal; font-style: normal; font-size: 16.00pt";
}super link {
    NSLink = "https://joytst.page.link/g9XaJeuffcH7koXk9?title=G\U0142osowanie%20ze%20spacj\U0105";
} i drugi tez obok {
    NSColor = "UIExtendedSRGBColorSpace 0.2 0.2 0.2 1";
    NSFont = "<UICTFont: 0x109215210> font-family: \"Poppins-Regular\"; font-weight: normal; font-style: normal; font-size: 16.00pt";
}super link {
    NSLink = "https://joytst.page.link/g9XaJeuffcH7koXk9?title=G\U0142osowanie";
} i jeszcze koniec wiadomosci!{
    NSColor = "UIExtendedSRGBColorSpace 0.2 0.2 0.2 1";
    NSFont = "<UICTFont: 0x109215210> font-family: \"Poppins-Regular\"; font-weight: normal; font-style: normal; font-size: 16.00pt";
}

attributedString.prettyLinked - ✅ links are detected, but every link is www.apple.com (not the real link).⁉️

Moze tez byc kilka linkow w wiadomosci, pierwszy {
    NSColor = "UIExtendedSRGBColorSpace 0.2 0.2 0.2 1";
    NSFont = "<UICTFont: 0x12f3120c0> font-family: \"Poppins-Regular\"; font-weight: normal; font-style: normal; font-size: 16.00pt";
}http://www.apple.com{
    NSLink = "https://joytst.page.link/g9XaJeuffcH7koXk9?title=G\U0142osowanie%20ze%20spacj\U0105";
} i drugi tez obok {
    NSColor = "UIExtendedSRGBColorSpace 0.2 0.2 0.2 1";
    NSFont = "<UICTFont: 0x12f3120c0> font-family: \"Poppins-Regular\"; font-weight: normal; font-style: normal; font-size: 16.00pt";
}http://www.apple.com{
    NSLink = "https://joytst.page.link/g9XaJeuffcH7koXk9?title=G\U0142osowanie";
} i jeszcze koniec wiadomosci!{
    NSColor = "UIExtendedSRGBColorSpace 0.2 0.2 0.2 1";
    NSFont = "<UICTFont: 0x12f3120c0> font-family: \"Poppins-Regular\"; font-weight: normal; font-style: normal; font-size: 16.00pt";
}

where:

extension NSAttributedString {
    var prettyLinked: NSAttributedString {
        let mutableString = NSMutableAttributedString(attributedString: self)
        do {
            let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
            let fullRange = NSRange(location: 0, length: string.utf16.count)
            let matches = detector.matches(in: string, range: fullRange)
            matches.reversed().forEach { match in
                let range = match.range
                let link = (string as NSString).substring(with: range)
                let prettyLink = NSAttributedString(string: "super link ", attributes: [.link: link])
                mutableString.replaceCharacters(in: range, with: prettyLink)
            }
        } catch {}
        return NSAttributedString(attributedString: mutableString)
    }
}

The result is like:

enter image description here

But it is not tappable, after that change. Why?

What do I want to achieve is to replace that urls with any string, for example here is super link . And then didSelectUrl is called as always. Is it possible with MessageKit?

1

There are 1 best solutions below

7
Oleg On

Based on the source code: https://github.com/MessageKit/MessageKit/blob/main/Sources/Views/MessageLabel.swift#L54 the message displayed on MessageLabel (UILabel) and it keeps a list of urlAttributes itself to detect when you tap on a link in that view, so you need to set those attributes manually

public func setAttributes(_ attributes: [NSAttributedString.Key: Any], detector: DetectorType)

As the class track if the user tap on MessageLabel (View) and calls delegate?.didSelectURL(url) after recognizing which part of the text was tapped in this function:

private func handleGesture(for detectorType: DetectorType, value: MessageTextCheckingType)

(https://github.com/MessageKit/MessageKit/blob/main/Sources/Views/MessageLabel.swift#L477)