mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 01:20:12 +00:00
fb49f5b83b
Add the element-call-ios dependency and a developer option for native calls The package carries the call UI and the matrix-rust-rtc media stack, pinned by exact version the way the SDK is, with the local path kept commented out for working against a checkout. Its media xcframework has no Intel simulator slice and a package cannot say so for the projects that consume it, hence the excluded architecture at the project level. The developer option is off by default and nothing reads it yet. It is placed next to the Element Call URL override, which only applies to the web view that native calls replace.
179 lines
5.8 KiB
Swift
179 lines
5.8 KiB
Swift
//
|
|
// Copyright 2025 Element Creations Ltd.
|
|
// Copyright 2025 New Vector Ltd.
|
|
//
|
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
|
// Please see LICENSE files in the repository root for full details.
|
|
//
|
|
|
|
import Foundation
|
|
import MatrixRustSDK
|
|
|
|
nonisolated protocol BaseRoomInfoProxyProtocol: Sendable {
|
|
var id: String { get }
|
|
var displayName: String? { get }
|
|
var topic: String? { get }
|
|
var canonicalAlias: String? { get }
|
|
var avatarURL: URL? { get }
|
|
var activeMembersCount: Int { get }
|
|
var joinedMembersCount: Int { get }
|
|
var isDirect: Bool { get }
|
|
var isSpace: Bool { get }
|
|
|
|
var successor: SuccessorRoom? { get }
|
|
var heroes: [RoomHero] { get }
|
|
}
|
|
|
|
// sourcery: AutoMockable
|
|
nonisolated protocol RoomInfoProxyProtocol: BaseRoomInfoProxyProtocol {
|
|
var id: String { get }
|
|
// periphery:ignore - might be useful to have
|
|
var creators: [String] { get }
|
|
var displayName: String? { get }
|
|
// periphery:ignore - might be useful to have
|
|
var rawName: String? { get }
|
|
var topic: String? { get }
|
|
/// The room's avatar URL. Use this for editing and favour ``avatar`` for display.
|
|
var avatarURL: URL? { get }
|
|
|
|
var isEncrypted: Bool { get }
|
|
var isDirect: Bool { get }
|
|
var isDM: Bool { get }
|
|
var isSpace: Bool { get }
|
|
var isFavourite: Bool { get }
|
|
|
|
var canonicalAlias: String? { get }
|
|
var alternativeAliases: [String] { get }
|
|
var membership: Membership { get }
|
|
// periphery:ignore - might be useful to have
|
|
var inviter: RoomMemberProxyProtocol? { get }
|
|
|
|
var activeMembersCount: Int { get }
|
|
// periphery:ignore - might be useful to have
|
|
var invitedMembersCount: Int { get }
|
|
var joinedMembersCount: Int { get }
|
|
// periphery:ignore - might be useful to have
|
|
var highlightCount: Int { get }
|
|
// periphery:ignore - might be useful to have
|
|
var notificationCount: Int { get }
|
|
// periphery:ignore - might be useful to have
|
|
var cachedUserDefinedNotificationMode: RoomNotificationMode? { get }
|
|
var hasRoomCall: Bool { get }
|
|
var activeRoomCallIntent: CallIntent? { get }
|
|
var activeRoomCallParticipants: [String] { get }
|
|
// periphery:ignore - might be useful to have
|
|
var isMarkedUnread: Bool { get }
|
|
// periphery:ignore - might be useful to have
|
|
var unreadMessagesCount: UInt { get }
|
|
// periphery:ignore - might be useful to have
|
|
var unreadNotificationsCount: UInt { get }
|
|
// periphery:ignore - might be useful to have
|
|
var unreadMentionsCount: UInt { get }
|
|
var fullyReadEventID: String? { get }
|
|
var pinnedEventIDs: Set<String> { get }
|
|
var joinRule: JoinRule? { get }
|
|
var historyVisibility: RoomHistoryVisibility { get }
|
|
|
|
var powerLevels: RoomPowerLevelsProxyProtocol? { get }
|
|
}
|
|
|
|
extension BaseRoomInfoProxyProtocol {
|
|
/// The room's avatar info for use in a ``RoomAvatarImage``.
|
|
var avatar: RoomAvatar {
|
|
guard successor == nil else {
|
|
return .tombstoned
|
|
}
|
|
|
|
if isSpace {
|
|
return .space(id: id, name: displayName, avatarURL: avatarURL)
|
|
}
|
|
|
|
if isDirect, avatarURL == nil, heroes.count == 1 {
|
|
return .heroes(heroes.map(UserProfile.init))
|
|
}
|
|
|
|
return .room(id: id, name: displayName, avatarURL: avatarURL)
|
|
}
|
|
|
|
var statusEmoji: Character? {
|
|
guard case let .heroes(heroes) = avatar else { return nil }
|
|
return heroes.first?.status.displayed?.emoji
|
|
}
|
|
}
|
|
|
|
extension RoomInfoProxyProtocol {
|
|
/// A room might be non public but also not private given the fact that the join rule might be missing or unsupported.
|
|
var isPrivate: Bool? {
|
|
guard let joinRule else {
|
|
return nil
|
|
}
|
|
|
|
return switch joinRule {
|
|
case .invite, .knock, .restricted, .knockRestricted:
|
|
true
|
|
case .public:
|
|
false
|
|
case .custom: // We don't know how to handle this
|
|
nil
|
|
}
|
|
}
|
|
|
|
/// Checks if the other person left the room in a direct chat
|
|
var isUserAloneInDirectRoom: Bool {
|
|
isDirect && activeMembersCount == 1
|
|
}
|
|
|
|
/// The room's name, falling back to its identifier when it doesn't have one.
|
|
var displayNameOrID: String {
|
|
displayName ?? id
|
|
}
|
|
|
|
/// Find the first alias that matches the given homeserver
|
|
/// - Parameters:
|
|
/// - serverName: the homserver in question
|
|
/// - useFallback: whether to return any alias if none match
|
|
func firstAliasMatching(serverName: String?, useFallback: Bool) -> String? {
|
|
guard let serverName else { return nil }
|
|
|
|
// Check if the canonical alias matches the homeserver
|
|
if let canonicalAlias,
|
|
canonicalAlias.contains(serverName) {
|
|
return canonicalAlias
|
|
}
|
|
|
|
// Otherwise check the alternative aliases and return the first one that matches
|
|
if let matchingAlternativeAlias = alternativeAliases.first(where: { $0.contains(serverName) }) {
|
|
return matchingAlternativeAlias
|
|
}
|
|
|
|
guard useFallback else {
|
|
return nil
|
|
}
|
|
|
|
// Or just return the canonical alias if any
|
|
if let canonicalAlias {
|
|
return canonicalAlias
|
|
}
|
|
|
|
// And finally return whatever the first alternative alias is
|
|
return alternativeAliases.first
|
|
}
|
|
|
|
/// If present, the state of history sharing in this room.
|
|
var historySharingState: RoomHistorySharingState? {
|
|
guard isEncrypted else {
|
|
return nil
|
|
}
|
|
return switch historyVisibility {
|
|
case .joined, .invited:
|
|
.hidden
|
|
case .shared:
|
|
.shared
|
|
case .worldReadable:
|
|
.worldReadable
|
|
case .custom:
|
|
nil
|
|
}
|
|
}
|
|
}
|