Skip to content

Commit

Permalink
Render Room and Message Pills (#3809)
Browse files Browse the repository at this point in the history
* added a way to render the room and the message

pills, but is WIP

* permalinks now get converted into pills!

* fixed an issue where room address mentions

were not adding a URL properly but a string

* updated tests

* c

* Revert "c"

This reverts commit 5c80252.

* updated tests

* more tests

* created APIs to get a specific RoomSummary

given the id or the alias

* small mention builder improvement

* pr suggestions
  • Loading branch information
Velin92 authored Feb 25, 2025
1 parent 944fe37 commit a2242c6
Show file tree
Hide file tree
Showing 100 changed files with 1,015 additions and 245 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ class MediaEventsTimelineFlowCoordinator: FlowCoordinatorProtocol {
appMediator: appMediator,
emojiProvider: emojiProvider,
userIndicatorController: userIndicatorController,
timelineControllerFactory: timelineControllerFactory)
timelineControllerFactory: timelineControllerFactory,
clientProxy: userSession.clientProxy)

let coordinator = MediaEventsTimelineScreenCoordinator(parameters: parameters)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ class PinnedEventsTimelineFlowCoordinator: FlowCoordinatorProtocol {
voiceMessageMediaManager: userSession.voiceMessageMediaManager,
appMediator: appMediator,
emojiProvider: emojiProvider,
timelineControllerFactory: timelineControllerFactory))
timelineControllerFactory: timelineControllerFactory,
clientProxy: userSession.clientProxy))

coordinator.actions
.sink { [weak self] action in
Expand Down
140 changes: 140 additions & 0 deletions ElementX/Sources/Mocks/Generated/GeneratedMocks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3225,6 +3225,146 @@ class ClientProxyMock: ClientProxyProtocol, @unchecked Sendable {
return roomPreviewForIdentifierViaReturnValue
}
}
//MARK: - roomSummaryForIdentifier

var roomSummaryForIdentifierUnderlyingCallsCount = 0
var roomSummaryForIdentifierCallsCount: Int {
get {
if Thread.isMainThread {
return roomSummaryForIdentifierUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = roomSummaryForIdentifierUnderlyingCallsCount
}

return returnValue!
}
}
set {
if Thread.isMainThread {
roomSummaryForIdentifierUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
roomSummaryForIdentifierUnderlyingCallsCount = newValue
}
}
}
}
var roomSummaryForIdentifierCalled: Bool {
return roomSummaryForIdentifierCallsCount > 0
}
var roomSummaryForIdentifierReceivedIdentifier: String?
var roomSummaryForIdentifierReceivedInvocations: [String] = []

var roomSummaryForIdentifierUnderlyingReturnValue: RoomSummary?
var roomSummaryForIdentifierReturnValue: RoomSummary? {
get {
if Thread.isMainThread {
return roomSummaryForIdentifierUnderlyingReturnValue
} else {
var returnValue: RoomSummary?? = nil
DispatchQueue.main.sync {
returnValue = roomSummaryForIdentifierUnderlyingReturnValue
}

return returnValue!
}
}
set {
if Thread.isMainThread {
roomSummaryForIdentifierUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
roomSummaryForIdentifierUnderlyingReturnValue = newValue
}
}
}
}
var roomSummaryForIdentifierClosure: ((String) -> RoomSummary?)?

func roomSummaryForIdentifier(_ identifier: String) -> RoomSummary? {
roomSummaryForIdentifierCallsCount += 1
roomSummaryForIdentifierReceivedIdentifier = identifier
DispatchQueue.main.async {
self.roomSummaryForIdentifierReceivedInvocations.append(identifier)
}
if let roomSummaryForIdentifierClosure = roomSummaryForIdentifierClosure {
return roomSummaryForIdentifierClosure(identifier)
} else {
return roomSummaryForIdentifierReturnValue
}
}
//MARK: - roomSummaryForAlias

var roomSummaryForAliasUnderlyingCallsCount = 0
var roomSummaryForAliasCallsCount: Int {
get {
if Thread.isMainThread {
return roomSummaryForAliasUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = roomSummaryForAliasUnderlyingCallsCount
}

return returnValue!
}
}
set {
if Thread.isMainThread {
roomSummaryForAliasUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
roomSummaryForAliasUnderlyingCallsCount = newValue
}
}
}
}
var roomSummaryForAliasCalled: Bool {
return roomSummaryForAliasCallsCount > 0
}
var roomSummaryForAliasReceivedAlias: String?
var roomSummaryForAliasReceivedInvocations: [String] = []

var roomSummaryForAliasUnderlyingReturnValue: RoomSummary?
var roomSummaryForAliasReturnValue: RoomSummary? {
get {
if Thread.isMainThread {
return roomSummaryForAliasUnderlyingReturnValue
} else {
var returnValue: RoomSummary?? = nil
DispatchQueue.main.sync {
returnValue = roomSummaryForAliasUnderlyingReturnValue
}

return returnValue!
}
}
set {
if Thread.isMainThread {
roomSummaryForAliasUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
roomSummaryForAliasUnderlyingReturnValue = newValue
}
}
}
}
var roomSummaryForAliasClosure: ((String) -> RoomSummary?)?

func roomSummaryForAlias(_ alias: String) -> RoomSummary? {
roomSummaryForAliasCallsCount += 1
roomSummaryForAliasReceivedAlias = alias
DispatchQueue.main.async {
self.roomSummaryForAliasReceivedInvocations.append(alias)
}
if let roomSummaryForAliasClosure = roomSummaryForAliasClosure {
return roomSummaryForAliasClosure(alias)
} else {
return roomSummaryForAliasReturnValue
}
}
//MARK: - loadUserDisplayName

var loadUserDisplayNameUnderlyingCallsCount = 0
Expand Down
36 changes: 35 additions & 1 deletion ElementX/Sources/Mocks/RoomSummaryProviderMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,31 @@ extension RoomSummaryProviderMock {
}
}

extension RoomSummary {
static func mock(id: String,
name: String,
canonicalAlias: String? = nil) -> RoomSummary {
RoomSummary(roomListItem: RoomListItemSDKMock(),
id: id,
joinRequestType: nil,
name: name,
isDirect: false,
avatarURL: nil,
heroes: [],
lastMessage: AttributedString("I do not wish to take the trouble to understand mysticism"),
lastMessageFormattedTimestamp: "14:56",
unreadMessagesCount: 0,
unreadMentionsCount: 0,
unreadNotificationsCount: 0,
notificationMode: .allMessages,
canonicalAlias: canonicalAlias,
alternativeAliases: [],
hasOngoingCall: false,
isMarkedUnread: false,
isFavourite: false)
}
}

extension Array where Element == RoomSummary {
static let mockRooms: [Element] = [
RoomSummary(roomListItem: RoomListItemSDKMock(),
Expand All @@ -83,6 +108,7 @@ extension Array where Element == RoomSummary {
unreadNotificationsCount: 0,
notificationMode: .allMessages,
canonicalAlias: nil,
alternativeAliases: [],
hasOngoingCall: false,
isMarkedUnread: false,
isFavourite: false),
Expand All @@ -99,7 +125,8 @@ extension Array where Element == RoomSummary {
unreadMentionsCount: 0,
unreadNotificationsCount: 2,
notificationMode: .mute,
canonicalAlias: nil,
canonicalAlias: "#foundation-and-empire:matrix.org",
alternativeAliases: [],
hasOngoingCall: false,
isMarkedUnread: false,
isFavourite: false),
Expand All @@ -117,6 +144,7 @@ extension Array where Element == RoomSummary {
unreadNotificationsCount: 0,
notificationMode: .mentionsAndKeywordsOnly,
canonicalAlias: nil,
alternativeAliases: [],
hasOngoingCall: false,
isMarkedUnread: false,
isFavourite: false),
Expand All @@ -134,6 +162,7 @@ extension Array where Element == RoomSummary {
unreadNotificationsCount: 2,
notificationMode: .allMessages,
canonicalAlias: nil,
alternativeAliases: [],
hasOngoingCall: false,
isMarkedUnread: false,
isFavourite: false),
Expand All @@ -151,6 +180,7 @@ extension Array where Element == RoomSummary {
unreadNotificationsCount: 1,
notificationMode: .allMessages,
canonicalAlias: nil,
alternativeAliases: [],
hasOngoingCall: true,
isMarkedUnread: false,
isFavourite: false),
Expand All @@ -168,6 +198,7 @@ extension Array where Element == RoomSummary {
unreadNotificationsCount: 0,
notificationMode: .mute,
canonicalAlias: nil,
alternativeAliases: [],
hasOngoingCall: true,
isMarkedUnread: false,
isFavourite: false),
Expand All @@ -185,6 +216,7 @@ extension Array where Element == RoomSummary {
unreadNotificationsCount: 0,
notificationMode: nil,
canonicalAlias: nil,
alternativeAliases: [],
hasOngoingCall: false,
isMarkedUnread: false,
isFavourite: false)
Expand Down Expand Up @@ -235,6 +267,7 @@ extension Array where Element == RoomSummary {
unreadNotificationsCount: 0,
notificationMode: nil,
canonicalAlias: "#footest:somewhere.org",
alternativeAliases: [],
hasOngoingCall: false,
isMarkedUnread: false,
isFavourite: false),
Expand All @@ -252,6 +285,7 @@ extension Array where Element == RoomSummary {
unreadNotificationsCount: 0,
notificationMode: nil,
canonicalAlias: nil,
alternativeAliases: [],
hasOngoingCall: false,
isMarkedUnread: false,
isFavourite: false)
Expand Down
15 changes: 10 additions & 5 deletions ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,8 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
case .atRoom:
attributedString.addAttribute(.MatrixAllUsersMention, value: true, range: match.range)
case .roomAlias(let alias):
if let url = try? matrixToRoomAliasPermalink(roomAlias: alias) {
if let urlString = try? matrixToRoomAliasPermalink(roomAlias: alias),
let url = URL(string: urlString) {
attributedString.addAttribute(.link, value: url, range: match.range)
}
case .matrixURI(let uri):
Expand Down Expand Up @@ -282,13 +283,13 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
case .user(let userID):
mentionBuilder.handleUserMention(for: attributedString, in: range, url: url, userID: userID, userDisplayName: nil)
case .room(let roomID):
attributedString.addAttributes([.MatrixRoomID: roomID], range: range)
mentionBuilder.handleRoomIDMention(for: attributedString, in: range, url: url, roomID: roomID)
case .roomAlias(let alias):
attributedString.addAttributes([.MatrixRoomAlias: alias], range: range)
mentionBuilder.handleRoomAliasMention(for: attributedString, in: range, url: url, roomAlias: alias)
case .eventOnRoomId(let roomID, let eventID):
attributedString.addAttributes([.MatrixEventOnRoomID: EventOnRoomIDAttribute.Value(roomID: roomID, eventID: eventID)], range: range)
mentionBuilder.handleEventOnRoomIDMention(for: attributedString, in: range, url: url, eventID: eventID, roomID: roomID)
case .eventOnRoomAlias(let alias, let eventID):
attributedString.addAttributes([.MatrixEventOnRoomAlias: EventOnRoomAliasAttribute.Value(alias: alias, eventID: eventID)], range: range)
mentionBuilder.handleEventOnRoomAliasMention(for: attributedString, in: range, url: url, eventID: eventID, roomAlias: alias)
}
}
}
Expand Down Expand Up @@ -364,6 +365,10 @@ extension NSAttributedString.Key {

protocol MentionBuilderProtocol {
func handleUserMention(for attributedString: NSMutableAttributedString, in range: NSRange, url: URL, userID: String, userDisplayName: String?)
func handleRoomIDMention(for attributedString: NSMutableAttributedString, in range: NSRange, url: URL, roomID: String)
func handleRoomAliasMention(for attributedString: NSMutableAttributedString, in range: NSRange, url: URL, roomAlias: String)
func handleEventOnRoomAliasMention(for attributedString: NSMutableAttributedString, in range: NSRange, url: URL, eventID: String, roomAlias: String)
func handleEventOnRoomIDMention(for attributedString: NSMutableAttributedString, in range: NSRange, url: URL, eventID: String, roomID: String)
func handleAllUsersMention(for attributedString: NSMutableAttributedString, in range: NSRange)
}

Expand Down
Loading

0 comments on commit a2242c6

Please sign in to comment.