Render pills in RTE (#1874)

* for now this can only work locally

* works

* added a test

* updated RTE

* revert package

* pr suggestion

* reverting package versions

* better naming
This commit is contained in:
Mauro
2023-10-11 16:40:52 +02:00
committed by GitHub
parent ff4d59bac7
commit c358150449
13 changed files with 136 additions and 36 deletions
@@ -37,7 +37,7 @@ struct MentionBuilder: MentionBuilderProtocol {
return
}
var attachmentAttributes: [NSAttributedString.Key: Any] = [.link: url, .MatrixUserID: userID]
var attachmentAttributes: [NSAttributedString.Key: Any] = [.link: url, .MatrixUserID: userID, .font: font]
if let blockquote {
// mentions can be in blockquotes, so if the replaced string was in one, we keep the attribute
attachmentAttributes[.MatrixBlockquote] = blockquote
@@ -61,7 +61,7 @@ struct MentionBuilder: MentionBuilderProtocol {
return
}
var attachmentAttributes: [NSAttributedString.Key: Any] = [:]
var attachmentAttributes: [NSAttributedString.Key: Any] = [.font: font]
if let blockquote {
// mentions can be in blockquotes, so if the replaced string was in one, we keep the attribute
attachmentAttributes[.MatrixBlockquote] = blockquote
@@ -16,7 +16,7 @@
import SwiftUI
final class MessageTextView: UITextView {
final class MessageTextView: UITextView, PillAttachmentViewProviderDelegate {
var roomContext: RoomScreenViewModel.Context?
var updateClosure: (() -> Void)?
@@ -44,6 +44,10 @@ final class MessageTextView: UITextView {
invalidateTextAttachmentsDisplay(update: false)
super.layoutSubviews()
}
func registerPillView(_ pillView: UIView) {
// No need to be implemented in this view
}
}
struct MessageText: UIViewRepresentable {
@@ -18,8 +18,17 @@ import SwiftUI
import SwiftUIIntrospect
import UIKit
import WysiwygComposer
protocol PillAttachmentViewProviderDelegate: AnyObject {
var roomContext: RoomScreenViewModel.Context? { get }
func registerPillView(_ pillView: UIView)
func invalidateTextAttachmentsDisplay(update: Bool)
}
final class PillAttachmentViewProvider: NSTextAttachmentViewProvider {
private weak var messageTextView: MessageTextView?
private weak var delegate: PillAttachmentViewProviderDelegate?
// MARK: - Override
@@ -27,7 +36,7 @@ final class PillAttachmentViewProvider: NSTextAttachmentViewProvider {
super.init(textAttachment: textAttachment, parentView: parentView, textLayoutManager: textLayoutManager, location: location)
// Keep a reference to the parent text view for size adjustments and pills flushing.
messageTextView = parentView?.superview as? MessageTextView
delegate = parentView?.superview as? PillAttachmentViewProviderDelegate
tracksTextAttachmentViewBounds = true
}
@@ -46,7 +55,7 @@ final class PillAttachmentViewProvider: NSTextAttachmentViewProvider {
// The mock viewModel simulates the loading logic for testing purposes
context = PillContext.mock(type: .loadUser(isOwn: false))
imageProvider = MockMediaProvider()
} else if let roomContext = messageTextView?.roomContext {
} else if let roomContext = delegate?.roomContext {
context = PillContext(roomContext: roomContext, data: textAttachmentData)
imageProvider = roomContext.imageProvider
} else {
@@ -55,12 +64,34 @@ final class PillAttachmentViewProvider: NSTextAttachmentViewProvider {
}
let view = PillView(imageProvider: imageProvider, context: context) { [weak self] in
self?.messageTextView?.invalidateTextAttachmentsDisplay(update: true)
self?.delegate?.invalidateTextAttachmentsDisplay(update: true)
}
let controller = UIHostingController(rootView: view)
controller.view.backgroundColor = .clear
// This allows the text view to handle it as a link
controller.view.isUserInteractionEnabled = false
self.view = controller.view
delegate?.registerPillView(controller.view)
}
}
final class ComposerMentionDisplayHelper: MentionDisplayHelper {
weak var roomContext: RoomScreenViewModel.Context?
init(roomContext: RoomScreenViewModel.Context) {
self.roomContext = roomContext
}
@MainActor
static var mock: Self {
Self(roomContext: RoomScreenViewModel.mock.context)
}
}
extension WysiwygTextView: PillAttachmentViewProviderDelegate {
var roomContext: RoomScreenViewModel.Context? {
(mentionDisplayHelper as? ComposerMentionDisplayHelper)?.roomContext
}
func invalidateTextAttachmentsDisplay(update: Bool) { }
}
@@ -17,7 +17,7 @@
import Foundation
import UIKit
enum PillType: Codable {
enum PillType: Codable, Equatable {
/// A pill that mentions a user
case user(userID: String)
/// A pill that mentions all users in a room
@@ -29,7 +29,7 @@ struct PillTextAttachmentData {
/// Pill type
let type: PillType
/// Font for the display name
let font: UIFont
}