mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Add the UserStatus and a status field on UserProfile/RoomMember/TimelineItemSender.
This commit is contained in:
@@ -294,6 +294,7 @@
|
||||
"common_no_space_name" = "No space name";
|
||||
"common_not_encrypted" = "Not encrypted";
|
||||
"common_offline" = "Offline";
|
||||
"common_on_a_call" = "On a call";
|
||||
"common_open_source_licenses" = "Open source licenses";
|
||||
"common_optic_id_ios" = "Optic ID";
|
||||
"common_or" = "or";
|
||||
|
||||
@@ -294,6 +294,7 @@
|
||||
"common_no_space_name" = "No space name";
|
||||
"common_not_encrypted" = "Not encrypted";
|
||||
"common_offline" = "Offline";
|
||||
"common_on_a_call" = "On a call";
|
||||
"common_open_source_licenses" = "Open source licenses";
|
||||
"common_optic_id_ios" = "Optic ID";
|
||||
"common_or" = "or";
|
||||
|
||||
@@ -644,6 +644,8 @@ internal nonisolated enum L10n {
|
||||
internal static var commonNotEncrypted: String { return L10n.tr("Localizable", "common_not_encrypted") }
|
||||
/// Offline
|
||||
internal static var commonOffline: String { return L10n.tr("Localizable", "common_offline") }
|
||||
/// On a call
|
||||
internal static var commonOnACall: String { return L10n.tr("Localizable", "common_on_a_call") }
|
||||
/// Open source licenses
|
||||
internal static var commonOpenSourceLicenses: String { return L10n.tr("Localizable", "common_open_source_licenses") }
|
||||
/// Optic ID
|
||||
|
||||
@@ -10045,6 +10045,11 @@ nonisolated class RoomMemberProxyMock: RoomMemberProxyProtocol, @unchecked Senda
|
||||
nonisolated(unsafe) var displayName: String?
|
||||
nonisolated(unsafe) var disambiguatedDisplayName: String?
|
||||
nonisolated(unsafe) var avatarURL: URL?
|
||||
var status: UserStatus {
|
||||
get { return underlyingStatus }
|
||||
set(value) { underlyingStatus = value }
|
||||
}
|
||||
nonisolated(unsafe) var underlyingStatus: UserStatus!
|
||||
var membership: MembershipState {
|
||||
get { return underlyingMembership }
|
||||
set(value) { underlyingMembership = value }
|
||||
|
||||
@@ -13,6 +13,7 @@ nonisolated struct RoomMemberProxyMockConfiguration {
|
||||
var userID: String
|
||||
var displayName: String?
|
||||
var avatarURL: URL?
|
||||
var status = UserStatus()
|
||||
|
||||
var membership: MembershipState
|
||||
var isIgnored = false
|
||||
@@ -23,14 +24,12 @@ nonisolated struct RoomMemberProxyMockConfiguration {
|
||||
extension RoomMemberProxyMock {
|
||||
convenience init(with configuration: RoomMemberProxyMockConfiguration) {
|
||||
self.init()
|
||||
|
||||
userID = configuration.userID
|
||||
displayName = configuration.displayName
|
||||
|
||||
if let displayName = configuration.displayName {
|
||||
disambiguatedDisplayName = "\(displayName) (\(userID))"
|
||||
}
|
||||
|
||||
disambiguatedDisplayName = configuration.displayName.map { "\($0) (\(userID))" }
|
||||
avatarURL = configuration.avatarURL
|
||||
status = configuration.status
|
||||
|
||||
membership = configuration.membership
|
||||
isIgnored = configuration.isIgnored
|
||||
@@ -93,6 +92,20 @@ extension RoomMemberProxyMock {
|
||||
membership: .join))
|
||||
}
|
||||
|
||||
static var mockErin: RoomMemberProxyMock {
|
||||
RoomMemberProxyMock(with: .init(userID: "@erin:matrix.org",
|
||||
displayName: "Erin",
|
||||
status: .mockFocussing,
|
||||
membership: .join))
|
||||
}
|
||||
|
||||
static var mockFrank: RoomMemberProxyMock {
|
||||
RoomMemberProxyMock(with: .init(userID: "@frank:matrix.org",
|
||||
displayName: "Frank",
|
||||
status: .mockCall,
|
||||
membership: .join))
|
||||
}
|
||||
|
||||
static var mockVerbose: RoomMemberProxyMock {
|
||||
RoomMemberProxyMock(with: .init(userID: "@charliev:matrix.org",
|
||||
displayName: "Charlie is the best display name",
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
import Foundation
|
||||
|
||||
extension UserProfile {
|
||||
/// Mocks
|
||||
static var mockAlice: UserProfile {
|
||||
.init(userID: "@alice:matrix.org", displayName: "Alice", avatarURL: "mxc://matrix.org/UcCimidcvpFvWkPzvjXMQPHA")
|
||||
}
|
||||
@@ -30,7 +29,33 @@ extension UserProfile {
|
||||
.init(userID: "@dan:matrix.org", displayName: "Dan", avatarURL: .mockMXCUserAvatar)
|
||||
}
|
||||
|
||||
static var mockErin: UserProfile {
|
||||
.init(userID: "@erin:matrix.org", displayName: "Erin", status: .mockFocussing)
|
||||
}
|
||||
|
||||
static var mockFrank: UserProfile {
|
||||
.init(userID: "@frank:matrix.org", displayName: "Frank", status: .mockCall)
|
||||
}
|
||||
|
||||
static var mockVerbose: UserProfile {
|
||||
.init(userID: "@charlie:matrix.org", displayName: "Charlie is the best display name", avatarURL: nil)
|
||||
}
|
||||
}
|
||||
|
||||
nonisolated extension UserStatus {
|
||||
static var mockCall: UserStatus {
|
||||
.init(userSet: nil, call: .init(startDate: nil))
|
||||
}
|
||||
|
||||
static var mockFocussing: UserStatus {
|
||||
.init(userSet: .init(text: "Focussing", emoji: "🧑💻"), call: nil)
|
||||
}
|
||||
|
||||
static var mockHoliday: UserStatus {
|
||||
.init(userSet: .init(text: "Holiday", emoji: "🏝️"), call: nil)
|
||||
}
|
||||
|
||||
static func mock(text: String, emoji: Character) -> UserStatus {
|
||||
.init(userSet: .init(text: text, emoji: emoji), call: nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user