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
@@ -40,11 +40,11 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
private var currentLinkData: WysiwygLinkData?
init(wysiwygViewModel: WysiwygComposerViewModel, completionSuggestionService: CompletionSuggestionServiceProtocol, mediaProvider: MediaProviderProtocol, appSettings: AppSettings) {
init(wysiwygViewModel: WysiwygComposerViewModel, completionSuggestionService: CompletionSuggestionServiceProtocol, mediaProvider: MediaProviderProtocol, appSettings: AppSettings, mentionDisplayHelper: MentionDisplayHelper) {
self.wysiwygViewModel = wysiwygViewModel
self.completionSuggestionService = completionSuggestionService
self.appSettings = appSettings
super.init(initialViewState: ComposerToolbarViewState(areSuggestionsEnabled: completionSuggestionService.areSuggestionsEnabled, bindings: .init()), imageProvider: mediaProvider)
context.$viewState
@@ -84,6 +84,10 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
completionSuggestionService.suggestionsPublisher
.weakAssign(to: \.state.suggestions, on: self)
.store(in: &cancellables)
if appSettings.mentionsEnabled {
setupMentionsHandling(mentionDisplayHelper: mentionDisplayHelper)
}
}
// MARK: - Public
@@ -155,6 +159,27 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
// MARK: - Private
private func setupMentionsHandling(mentionDisplayHelper: MentionDisplayHelper) {
wysiwygViewModel.textView.mentionDisplayHelper = mentionDisplayHelper
let attributedStringBuilder = AttributedStringBuilder(cacheKey: "Composer", permalinkBaseURL: appSettings.permalinkBaseURL, mentionBuilder: MentionBuilder(mentionsEnabled: appSettings.mentionsEnabled))
wysiwygViewModel.mentionReplacer = ComposerMentionReplacer { urlString, string in
let attributedString: NSMutableAttributedString
// This is the all room mention case
if urlString == "#" {
attributedString = NSMutableAttributedString(string: string, attributes: [.MatrixAllUsersMention: true])
} else {
attributedString = NSMutableAttributedString(string: string, attributes: [.link: URL(string: urlString) as Any])
}
attributedStringBuilder.detectPermalinks(attributedString)
// In RTE mentions don't need to be handled as links
attributedString.removeAttribute(.link, range: NSRange(location: 0, length: attributedString.length))
return attributedString
}
}
private func handleSuggestion(_ suggestion: SuggestionItem) {
switch suggestion {
case let .user(item):
@@ -177,6 +202,7 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
}
private func set(text: String) {
wysiwygViewModel.textView.flushPills()
wysiwygViewModel.setHtmlContent(text)
}
@@ -293,3 +319,25 @@ private extension LinkAction {
return url
}
}
private final class ComposerMentionReplacer: MentionReplacer {
let replacementForMentionClosure: (_ urlString: String, _ text: String) -> (NSAttributedString?)
init(replacementForMentionClosure: @escaping (String, String) -> (NSAttributedString?)) {
self.replacementForMentionClosure = replacementForMentionClosure
}
// There is no internal Markdown to RTE switch implemented yet in the room so this one is never called
func postProcessMarkdown(in attributedString: NSAttributedString) -> NSAttributedString {
attributedString
}
// There is no internal RTE to Markdown switch implemented yet in the room so this one is never called
func restoreMarkdown(in attributedString: NSAttributedString) -> String {
attributedString.string
}
func replacementForMention(_ url: String, text: String) -> NSAttributedString? {
replacementForMentionClosure(url, text)
}
}
@@ -197,7 +197,8 @@ struct ComposerToolbar_Previews: PreviewProvider, TestablePreview {
static let composerViewModel = ComposerToolbarViewModel(wysiwygViewModel: wysiwygViewModel,
completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init(suggestions: suggestions)),
mediaProvider: MockMediaProvider(),
appSettings: ServiceLocator.shared.settings)
appSettings: ServiceLocator.shared.settings,
mentionDisplayHelper: ComposerMentionDisplayHelper.mock)
static let suggestions: [SuggestionItem] = [.user(item: MentionSuggestionItem(id: "@user_mention_1:matrix.org", displayName: "User 1", avatarURL: nil)),
.user(item: MentionSuggestionItem(id: "@user_mention_2:matrix.org", displayName: "User 2", avatarURL: URL.documentsDirectory))]
@@ -223,7 +224,8 @@ extension ComposerToolbar {
let composerViewModel = ComposerToolbarViewModel(wysiwygViewModel: wysiwygViewModel,
completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()),
mediaProvider: MockMediaProvider(),
appSettings: ServiceLocator.shared.settings)
appSettings: ServiceLocator.shared.settings,
mentionDisplayHelper: ComposerMentionDisplayHelper.mock)
return ComposerToolbar(context: composerViewModel.context,
wysiwygViewModel: wysiwygViewModel,
keyCommandHandler: { _ in false })
@@ -118,7 +118,8 @@ struct RoomAttachmentPicker_Previews: PreviewProvider, TestablePreview {
static let viewModel = ComposerToolbarViewModel(wysiwygViewModel: WysiwygComposerViewModel(),
completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()),
mediaProvider: MockMediaProvider(),
appSettings: ServiceLocator.shared.settings)
appSettings: ServiceLocator.shared.settings,
mentionDisplayHelper: ComposerMentionDisplayHelper.mock)
static var previews: some View {
RoomAttachmentPicker(context: viewModel.context)
@@ -71,7 +71,8 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
composerViewModel = ComposerToolbarViewModel(wysiwygViewModel: wysiwygViewModel,
completionSuggestionService: parameters.completionSuggestionService,
mediaProvider: parameters.mediaProvider,
appSettings: parameters.appSettings)
appSettings: parameters.appSettings,
mentionDisplayHelper: ComposerMentionDisplayHelper(roomContext: viewModel.context))
}
// MARK: - Public