Add the UserStatus and a status field on UserProfile/RoomMember/TimelineItemSender.

This commit is contained in:
Doug
2026-07-10 12:40:14 +01:00
committed by Doug
parent 5743f263b6
commit 2c4775f357
11 changed files with 122 additions and 9 deletions
@@ -13,6 +13,8 @@ nonisolated struct RoomMemberDetails: Identifiable, Hashable {
let id: String
let name: String?
let avatarURL: URL?
let status: UserStatus
let permalink: URL?
var isInvited: Bool
@@ -34,6 +36,7 @@ nonisolated extension RoomMemberDetails {
id = proxy.userID
name = proxy.displayName
avatarURL = proxy.avatarURL
status = proxy.status
permalink = proxy.permalink
isActive = proxy.isActive
isInvited = proxy.membership == .invite
@@ -36,6 +36,10 @@ final nonisolated class RoomMemberProxy: RoomMemberProxyProtocol {
member.avatarUrl.flatMap(URL.init(string:))
}
var status: UserStatus {
UserStatus()
}
var membership: MembershipState {
member.membership
}
@@ -15,8 +15,8 @@ nonisolated protocol RoomMemberProxyProtocol: AnyObject, Sendable {
var displayName: String? { get }
var disambiguatedDisplayName: String? { get }
var avatarURL: URL? { get }
var status: UserStatus { get }
var membership: MembershipState { get }
@@ -16,12 +16,18 @@ nonisolated struct TimelineItemSender: Identifiable, Hashable {
let displayName: String?
let isDisplayNameAmbiguous: Bool
let avatarURL: URL?
let status: UserStatus
init(id: String, displayName: String? = nil, isDisplayNameAmbiguous: Bool = false, avatarURL: URL? = nil) {
init(id: String,
displayName: String? = nil,
isDisplayNameAmbiguous: Bool = false,
avatarURL: URL? = nil,
status: UserStatus = .init()) {
self.id = id
self.displayName = displayName
self.isDisplayNameAmbiguous = isDisplayNameAmbiguous
self.avatarURL = avatarURL
self.status = status
}
init(senderID: String, senderProfile: ProfileDetails) {
@@ -13,35 +13,41 @@ nonisolated struct UserProfile: Hashable, Identifiable {
let id: String
let displayName: String?
let avatarURL: URL?
let status: UserStatus
init(userID: String, displayName: String? = nil, avatarURL: URL? = nil) {
init(userID: String, displayName: String? = nil, avatarURL: URL? = nil, status: UserStatus = .init()) {
id = userID
self.displayName = displayName
self.avatarURL = avatarURL
self.status = status
}
init(member: RoomMemberDetails) {
id = member.id
displayName = member.isBanned ? nil : member.name
avatarURL = member.isBanned ? nil : member.avatarURL
status = member.status
}
init(sender: TimelineItemSender) {
id = sender.id
displayName = sender.displayName
avatarURL = sender.avatarURL
status = sender.status
}
init(sdkUserProfile: MatrixRustSDK.UserProfile) {
id = sdkUserProfile.userId
displayName = sdkUserProfile.displayName
avatarURL = sdkUserProfile.avatarUrl.flatMap(URL.init(string:))
status = .init()
}
init(sdkRoomHero: MatrixRustSDK.RoomHero) {
id = sdkRoomHero.userId
displayName = sdkRoomHero.displayName
avatarURL = sdkRoomHero.avatarUrl.flatMap(URL.init(string:))
status = .init()
}
init(member: RoomMemberProxyProtocol) {
@@ -55,6 +61,53 @@ nonisolated struct UserProfile: Hashable, Identifiable {
}
}
nonisolated struct UserStatus: Hashable {
/// The status manually set by the user (if any).
let userSet: UserSet?
/// The status automatically set by Element Call (while in a call).
let call: Call?
/// The status that should be displayed on the user's profile.
var displayed: DisplayedStatus? {
// The user-set status takes precedence over the call indicator.
userSet.map { .userSet($0) } ?? call.map { .inCall($0) }
}
nonisolated struct UserSet: Hashable {
let text: String
let emoji: Character
}
nonisolated struct Call: Hashable {
let startDate: Date?
}
nonisolated enum DisplayedStatus: Hashable {
case userSet(UserSet)
case inCall(Call)
var text: String {
switch self {
case .userSet(let userSet): userSet.text
case .inCall: L10n.commonOnACall
}
}
var emoji: Character {
switch self {
case .userSet(let userSet): userSet.emoji
case .inCall: "🎧"
}
}
}
}
nonisolated extension UserStatus {
init() {
self.init(userSet: nil, call: nil)
}
}
struct SearchUsersResults {
let results: [UserProfile]
let limited: Bool