mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
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:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user