@room in user suggestions (#1880)

* for now I am using a local RTE solution, need to fix one test

* fixed a test

* new rte version

* pr suggestions

* @room added to the suggestions

* removed empty space

* revert

* code improvement

* project updated

* package
This commit is contained in:
Mauro
2023-10-12 18:15:47 +02:00
committed by GitHub
parent 2c5662a278
commit ad0b2f114f
21 changed files with 241 additions and 76 deletions
@@ -20,11 +20,23 @@ import WysiwygComposer
enum SuggestionItem: Identifiable, Equatable {
case user(item: MentionSuggestionItem)
case allUsers(item: MentionSuggestionItem)
var id: String {
switch self {
case .user(let user):
return user.id
case .allUsers:
return PillConstants.atRoom
}
}
var name: String? {
switch self {
case .user(let user):
return user.displayName
case .allUsers:
return PillConstants.everyone
}
}
}
@@ -33,6 +45,10 @@ struct MentionSuggestionItem: Identifiable, Equatable {
let id: String
let displayName: String?
let avatarURL: URL?
static func allUsersMention(roomAvatar: URL?) -> Self {
MentionSuggestionItem(id: PillConstants.atRoom, displayName: PillConstants.everyone, avatarURL: roomAvatar)
}
}
extension WysiwygComposer.SuggestionPattern {
@@ -18,50 +18,70 @@ import Combine
import Foundation
final class CompletionSuggestionService: CompletionSuggestionServiceProtocol {
private var canMentionAllUsers = false
let areSuggestionsEnabled: Bool
let suggestionsPublisher: AnyPublisher<[SuggestionItem], Never>
private(set) var suggestionsPublisher: AnyPublisher<[SuggestionItem], Never> = Empty().eraseToAnyPublisher()
private let suggestionTriggerSubject = CurrentValueSubject<SuggestionPattern?, Never>(nil)
init(roomProxy: RoomProxyProtocol, areSuggestionsEnabled: Bool) {
self.areSuggestionsEnabled = areSuggestionsEnabled
guard areSuggestionsEnabled else {
suggestionsPublisher = Empty().eraseToAnyPublisher()
return
}
suggestionsPublisher = suggestionTriggerSubject
.combineLatest(roomProxy.members)
.map { suggestionTrigger, members -> [SuggestionItem] in
guard let suggestionTrigger else {
.map { [weak self] suggestionPattern, members -> [SuggestionItem] in
guard let suggestionPattern else {
return []
}
switch suggestionTrigger.type {
switch suggestionPattern.type {
case .user:
return members.filter { member in
guard !member.isAccountOwner && member.membership == .join else {
return false
var membersSuggestion = members
.compactMap { member -> SuggestionItem? in
guard !member.isAccountOwner,
member.membership == .join,
Self.isIncluded(searchText: suggestionPattern.text, userID: member.userID, displayName: member.displayName) else {
return nil
}
return SuggestionItem.user(item: .init(id: member.userID, displayName: member.displayName, avatarURL: member.avatarURL))
}
let containedInUserID = member.userID.localizedStandardContains(suggestionTrigger.text.lowercased())
let containedInDisplayName: Bool
if let displayName = member.displayName {
containedInDisplayName = displayName.localizedStandardContains(suggestionTrigger.text.lowercased())
} else {
containedInDisplayName = false
}
return containedInUserID || containedInDisplayName
if self?.canMentionAllUsers == true,
Self.isIncluded(searchText: suggestionPattern.text, userID: PillConstants.atRoom, displayName: PillConstants.everyone) {
membersSuggestion
.append(SuggestionItem.allUsers(item: .allUsersMention(roomAvatar: roomProxy.avatarURL)))
}
.map { SuggestionItem.user(item: .init(id: $0.userID, displayName: $0.displayName, avatarURL: $0.avatarURL)) }
return membersSuggestion
}
}
.debounce(for: 0.5, scheduler: DispatchQueue.main)
.eraseToAnyPublisher()
Task {
switch await roomProxy.canUserTriggerRoomNotification(userID: roomProxy.ownUserID) {
case .success(let value):
canMentionAllUsers = value
case .failure:
canMentionAllUsers = false
}
}
}
func setSuggestionTrigger(_ suggestionTrigger: SuggestionPattern?) {
suggestionTriggerSubject.value = suggestionTrigger
}
private static func isIncluded(searchText: String, userID: String, displayName: String?) -> Bool {
let containedInUserID = userID.localizedStandardContains(searchText.lowercased())
let containedInDisplayName: Bool
if let displayName {
containedInDisplayName = displayName.localizedStandardContains(searchText.lowercased())
} else {
containedInDisplayName = false
}
return containedInUserID || containedInDisplayName
}
}
@@ -166,8 +166,8 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
wysiwygViewModel.mentionReplacer = ComposerMentionReplacer { urlString, string in
let attributedString: NSMutableAttributedString
// This is the all room mention case
if urlString == "#" {
// This is the all room mention special case
if urlString == PillConstants.composerAtRoomURLString {
attributedString = NSMutableAttributedString(string: string, attributes: [.MatrixAllUsersMention: true])
} else {
attributedString = NSMutableAttributedString(string: string, attributes: [.link: URL(string: urlString) as Any])
@@ -188,6 +188,8 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
return
}
wysiwygViewModel.setMention(url: url.absoluteString, name: item.displayName ?? item.id, mentionType: .user)
case .allUsers:
wysiwygViewModel.setAtRoomMention()
}
}
@@ -68,7 +68,7 @@ struct CompletionSuggestionView: View {
onTap(item)
} label: {
switch item {
case .user(let mention):
case .user(let mention), .allUsers(let mention):
MentionSuggestionItemView(imageProvider: imageProvider, item: mention)
}
}