Periphery cleanup (#5893)

This commit is contained in:
Mauro
2026-07-20 11:16:11 +02:00
committed by GitHub
parent 175aca596e
commit 9093631f8b
275 changed files with 381 additions and 2268 deletions
@@ -23,8 +23,6 @@ nonisolated struct NotificationToneManager: NotificationToneManagerProtocol {
/// The source file could not be accessed due to sandbox restrictions.
case couldNotAccessSandboxedResource
/// `AVAudioConverter` could not be initialised for the given format pair.
case converterSetupFailed
/// A tone with the same filename already exists in the library.
case fileAlreadyExists
/// An `AVAudioPCMBuffer` could not be allocated.
@@ -57,7 +57,11 @@ class AnalyticsService: AnalyticsServiceProtocol {
MXLog.info("Started.")
}
func reset() {
/// Resets any IDs and event queues in the analytics client. This method should
/// be called on sign-out to ensure the next
/// account used isn't associated with the previous one.
/// Note: **MUST** be called before stopping PostHog or the reset is ignored.
private func reset() {
client.reset()
MXLog.info("Reset.")
}
@@ -37,12 +37,6 @@ protocol AnalyticsServiceProtocol: AnyObject {
/// Starts the analytics client if the user has opted in, otherwise does nothing.
func startIfEnabled()
/// Resets any IDs and event queues in the analytics client. This method should
/// be called on sign-out to maintain opt-in status, whilst ensuring the next
/// account used isn't associated with the previous one.
/// Note: **MUST** be called before stopping PostHog or the reset is ignored.
func reset()
/// Resets the consent state for analytics.
func resetConsentState()
@@ -101,10 +101,6 @@ class Signposter {
globalTags[tagName] = value
}
func removeGlobalTag(_ tagName: TagName) {
globalTags[tagName] = nil
}
// MARK: - Private
func sha512(_ string: String) -> String {
@@ -42,7 +42,6 @@ class AudioPlayer: NSObject, AudioPlayerProtocol {
private let audioSession = AVAudioSession.sharedInstance()
// periphery:ignore - when set to nil is automatically cancelled
@CancellableTask private var releaseAudioSessionTask: Task<Void, Never>?
private let releaseAudioSessionTimeoutInterval = 5.0
@@ -40,7 +40,6 @@ protocol AudioPlayerProtocol: AnyObject {
var currentTime: TimeInterval { get }
var playbackURL: URL? { get }
var state: MediaPlayerState { get }
var playbackSpeed: Float { get }
var actions: AnyPublisher<AudioPlayerAction, Never> { get }
@@ -84,11 +84,6 @@ nonisolated class AudioRecorder: AudioRecorderProtocol, @unchecked Sendable {
}
}
func cancelRecording() async {
await stopRecording()
await deleteRecording()
}
func deleteRecording() async {
await withCheckedContinuation { continuation in
deleteRecording {
@@ -35,7 +35,6 @@ enum AuthenticationServiceError: Error, Equatable {
case accountDeactivated
case failedLoggingIn
case sessionTokenRefreshNotSupported
case failedUsingWebCredentials
}
protocol AuthenticationServiceProtocol: QRCodeLoginServiceProtocol {
@@ -82,23 +82,8 @@ final class ClassicAppMXAccount: NSObject, NSCoding {
static let homeserverURL = "homeserverurl" // String?
static let userID = "userid" // String?
static let accessToken = "accesstoken" // String?
static let accessTokenExpiresAt = "accessTokenExpiresAt" // UInt64
static let refreshToken = "refreshToken" // String?
static let identityServerURL = "identityserverurl" // String?
static let identityServerAccessToken = "identityserveraccesstoken" // String?
static let deviceID = "deviceId" // String?
static let allowedCertificate = "allowedCertificate" // Data?
static let threePIDs = "threePIDs" // [MXThirdPartyIdentifier]?
static let device = "device" // MXDevice?
static let antivirusServerURL = "antivirusserverurl" // String?
static let pushGatewayURL = "pushgatewayurl" // String?
static let hasPusherForPushNotifications = "_enablePushNotifications" // Bool
static let hasPusherForPushKitNotifications = "enablePushKitNotifications" // Bool
static let enableInAppNotifications = "enableInAppNotifications" // Bool
static let isDisabled = "disabled" // Bool
static let isSoftLogout = "isSoftLogout" // Bool
static let isWarnedAboutEncryption = "warnedAboutEncryption" // Bool
static let others = "others" // NSMutableDictionary
}
required init?(coder: NSCoder) {
@@ -126,6 +111,7 @@ final class ClassicAppMXAccount: NSObject, NSCoding {
/// `MXUser` represents a user in Matrix.
final class ClassicAppMXUser: NSObject, NSCoding {
// periphery:ignore - documents the schema, parsed but not consumed yet
/// The user id.
let userID: String
/// The user display name.
@@ -139,10 +125,6 @@ final class ClassicAppMXUser: NSObject, NSCoding {
static let userID = "userId" // String
static let displayName = "displayname" // String?
static let avatarURL = "avatarUrl" // String?
static let statusMessage = "statusMsg" // String?
static let currentlyActive = "currentlyActive" // Bool
static let lastActiveLocalTimestamp = "lastActiveLocalTS" // UInt64
static let latestUpdateTimestamp = "latestUpdateTS" // UInt64
}
required init?(coder aDecoder: NSCoder) {
@@ -21,7 +21,6 @@ class ClientProxy: ClientProxyProtocol {
let mediaLoader: MediaLoaderProtocol
let contentScanner: ContentScannerProxyProtocol?
private let clientQueue: DispatchQueue
private var roomListService: RoomListService
// periphery: ignore - only for retain
@@ -217,8 +216,6 @@ class ClientProxy: ClientProxyProtocol {
client.enableAutomaticBackpagination()
}
clientQueue = .init(label: "ClientProxyQueue", attributes: .concurrent)
mediaLoader = MediaLoader(client: client)
// Route media downloads through a content scanner when one has been configured for the server,
@@ -247,7 +244,6 @@ class ClientProxy: ClientProxyProtocol {
capabilities = HomeserverCapabilitiesProxy(underlyingCapabilities: client.homeserverCapabilities())
let configuredAppService = try await ClientProxyServices(client: client,
actionsSubject: actionsSubject,
notificationSettings: notificationSettings,
appSettings: appSettings)
@@ -746,6 +742,7 @@ class ClientProxy: ClientProxyProtocol {
}
}
// periphery:ignore - might be useful to have
func setUserStatus(_ status: UserStatus.Raw) async -> Result<Void, ClientProxyError> {
do {
try await client.setUserStatus(status: status.rustValue)
@@ -757,6 +754,7 @@ class ClientProxy: ClientProxyProtocol {
}
}
// periphery:ignore - might be useful to have
func removeUserStatus() async -> Result<Void, ClientProxyError> {
do {
try await client.clearUserStatus()
@@ -1450,6 +1448,7 @@ private final class ClientDelegateWrapper: ClientDelegate {
authErrorCallback(isSoftLogout)
}
// periphery:ignore - required by the SDK's delegate protocol
func didRefreshTokens() {
MXLog.info("Delegating session updates to the ClientSessionDelegate.")
}
@@ -1480,7 +1479,6 @@ private struct ClientProxyServices {
let eventStringBuilder: RoomEventStringBuilder
init(client: ClientProtocol,
actionsSubject: PassthroughSubject<ClientProxyAction, Never>,
notificationSettings: NotificationSettingsProxyProtocol,
appSettings: AppSettings) async throws {
let syncService = try await client
@@ -35,7 +35,6 @@ enum ClientProxyError: Error {
case invalidMedia
case invalidServerName
case invalidResponse
case failedUploadingMedia(ErrorKind)
case roomPreviewIsPrivate
case failedRetrievingUserIdentity
@@ -160,7 +159,6 @@ protocol ClientProxyProtocol: AnyObject {
var capabilities: HomeserverCapabilitiesProxyProtocol { get }
var isReportRoomSupported: Bool { get async }
var isLiveKitRTCSupported: Bool { get async }
var isLoginWithQRCodeSupported: Bool { get async }
@@ -36,6 +36,7 @@ struct ElementCallWidgetMessage: Codable {
let action: Action
var data: Data = .init()
// periphery:ignore - part of the encoded payload
let widgetId: String
var requestId = "widgetapi-\(UUID())"
@@ -33,8 +33,6 @@ enum EmojiProviderState {
}
protocol EmojiProviderProtocol {
var state: EmojiProviderState { get }
func categories(searchString: String?) async -> [EmojiCategory]
func frequentlyUsedSystemEmojis() -> [String]
@@ -18,7 +18,7 @@ class LinkMetadataProvider: LinkMetadataProviderProtocol {
do {
let metadata = try await LPMetadataProvider().startFetchingMetadata(for: url)
let item = LinkMetadataProviderItem(url: url, metadata: metadata)
let item = LinkMetadataProviderItem(metadata: metadata)
metadataItems[url] = item
return .success(item)
} catch {
@@ -10,7 +10,6 @@ import Foundation
import LinkPresentation
struct LinkMetadataProviderItem {
let url: URL
let metadata: LPLinkMetadata?
}
@@ -12,6 +12,7 @@ struct LiveLocationShare: Hashable, Identifiable {
let userID: String
let geoURI: GeoURI?
let timestamp: Date
// periphery:ignore - used via the synthesized Hashable conformance
let timeoutDate: Date
var id: String {
@@ -20,7 +20,6 @@ enum MediaProviderError: Error {
// sourcery: AutoMockable
nonisolated protocol MediaProviderProtocol: Sendable {
func imageFromSource(_ source: MediaSourceProxy?, size: CGSize?) -> UIImage?
func loadImageFromSource(_ source: MediaSourceProxy, size: CGSize?) async -> Result<UIImage, MediaProviderError>
func loadImageDataFromSource(_ source: MediaSourceProxy) async -> Result<Data, MediaProviderError>
func loadImageRetryingOnReconnection(_ source: MediaSourceProxy, size: CGSize?) -> Task<UIImage, Error>
@@ -8,10 +8,6 @@
import Foundation
enum MediaPlayerProviderError: Error {
case unsupportedMediaType
}
protocol MediaPlayerProviderProtocol {
var player: AudioPlayerProtocol { get }
@@ -9,7 +9,7 @@ import Foundation
import MatrixRustSDK
/// The rule used for users wishing to join a room.
public nonisolated enum JoinRule: Equatable, Hashable, Sendable {
nonisolated enum JoinRule: Equatable, Hashable, Sendable {
/// Anyone can join the room without any prior action.
case `public`
/// A user who wishes to join the room must first receive an invite.
@@ -52,7 +52,7 @@ public nonisolated enum JoinRule: Equatable, Hashable, Sendable {
}
/// An allow rule which defines a condition that allows joining a room.
public nonisolated enum AllowRule: Equatable, Hashable, Sendable {
nonisolated enum AllowRule: Equatable, Hashable, Sendable {
/// Only a member of the `room_id` Room can join the one this rule is used in.
case roomMembership(roomID: String)
/// A custom allow rule implementation, containing its JSON representation as a `String`.
@@ -18,7 +18,6 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
private let analyticsService: AnalyticsServiceProtocol
private let eventStringBuilder: RoomEventStringBuilder
// periphery:ignore - required for instance retention in the rust codebase
private var roomInfoObservationToken: TaskHandle?
// periphery:ignore - required for instance retention in the rust codebase
private var typingNotificationObservationToken: TaskHandle?
@@ -43,12 +42,6 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
/// The predecessor is set on room creation and never changes, so we lazily store it.
lazy var predecessorRoom = room.predecessorRoom()
/// The successor may change over time, so we access it dynamically.
/// It's suggested to observe it through the `infoPublisher`
var successorRoom: SuccessorRoom? {
room.successorRoom()
}
let timeline: TimelineProxyProtocol
private let infoSubject: CurrentValueSubject<RoomInfoProxyProtocol, Never>
@@ -301,16 +294,6 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
}
}
func redact(_ eventID: String) async -> Result<Void, RoomProxyError> {
do {
try await room.redact(eventId: eventID, reason: nil)
return .success(())
} catch {
MXLog.error("Failed redacting eventID: \(eventID) with error: \(error)")
return .failure(.sdkError(error))
}
}
func reportContent(_ eventID: String, reason: String?) async -> Result<Void, RoomProxyError> {
do {
try await room.reportContent(eventId: eventID, reason: reason)
@@ -442,16 +425,6 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
}
}
func edit(eventID: String, newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, RoomProxyError> {
do {
try await room.edit(eventId: eventID, newContent: newContent)
return .success(())
} catch {
MXLog.error("Failed editing event id \(eventID), in room \(id) with error: \(error)")
return .failure(.sdkError(error))
}
}
func sendTypingNotification(isTyping: Bool) async -> Result<Void, RoomProxyError> {
do {
try await room.typingNotice(isTyping: isTyping)
@@ -581,15 +554,6 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
// MARK: - Power Levels
func powerLevels() async -> Result<RoomPowerLevelsProxyProtocol?, RoomProxyError> {
do {
return try await .success(RoomPowerLevelsProxy(room.getPowerLevels()))
} catch {
MXLog.error("Failed building the current power level settings: \(error)")
return .failure(.sdkError(error))
}
}
func applyPowerLevelChanges(_ changes: RoomPowerLevelChanges) async -> Result<Void, RoomProxyError> {
do {
return try await .success(room.applyPowerLevelChanges(changes: changes))
@@ -609,15 +573,6 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
}
}
func suggestedRole(for userID: String) async -> Result<RoomMemberRole, RoomProxyError> {
do {
return try await .success(room.suggestedRoleForUser(userId: userID))
} catch {
MXLog.error("Failed getting a user's role: \(error)")
return .failure(.sdkError(error))
}
}
func updatePowerLevelsForUsers(_ updates: [(userID: String, powerLevel: Int64)]) async -> Result<Void, RoomProxyError> {
do {
let updates = updates.map { UserPowerLevelUpdate(userId: $0.userID, powerLevel: $0.powerLevel) }
@@ -16,6 +16,8 @@ nonisolated struct RoomInfoProxy: RoomInfoProxyProtocol {
roomInfo.id
}
// periphery:ignore - might be useful to have
var creators: [String] {
roomInfo.creators ?? []
}
@@ -24,6 +26,8 @@ nonisolated struct RoomInfoProxy: RoomInfoProxyProtocol {
roomInfo.displayName
}
// periphery:ignore - might be useful to have
var rawName: String? {
roomInfo.rawName
}
@@ -78,6 +82,8 @@ nonisolated struct RoomInfoProxy: RoomInfoProxyProtocol {
roomInfo.membership
}
// periphery:ignore - might be useful to have
var inviter: RoomMemberProxyProtocol? {
roomInfo.inviter.map(RoomMemberProxy.init)
}
@@ -90,6 +96,8 @@ nonisolated struct RoomInfoProxy: RoomInfoProxyProtocol {
Int(roomInfo.activeMembersCount)
}
// periphery:ignore - might be useful to have
var invitedMembersCount: Int {
Int(roomInfo.invitedMembersCount)
}
@@ -98,14 +106,20 @@ nonisolated struct RoomInfoProxy: RoomInfoProxyProtocol {
Int(roomInfo.joinedMembersCount)
}
// periphery:ignore - might be useful to have
var highlightCount: Int {
Int(roomInfo.highlightCount)
}
// periphery:ignore - might be useful to have
var notificationCount: Int {
Int(roomInfo.notificationCount)
}
// periphery:ignore - might be useful to have
var cachedUserDefinedNotificationMode: RoomNotificationMode? {
roomInfo.cachedUserDefinedNotificationMode
}
@@ -129,18 +143,26 @@ nonisolated struct RoomInfoProxy: RoomInfoProxyProtocol {
roomInfo.activeRoomCallParticipants
}
// periphery:ignore - might be useful to have
var isMarkedUnread: Bool {
roomInfo.isMarkedUnread
}
// periphery:ignore - might be useful to have
var unreadMessagesCount: UInt {
UInt(roomInfo.numUnreadMessages)
}
// periphery:ignore - might be useful to have
var unreadNotificationsCount: UInt {
UInt(roomInfo.numUnreadNotifications)
}
// periphery:ignore - might be useful to have
var unreadMentionsCount: UInt {
UInt(roomInfo.numUnreadMentions)
}
@@ -27,8 +27,10 @@ nonisolated protocol BaseRoomInfoProxyProtocol: Sendable {
// 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.
@@ -43,20 +45,29 @@ nonisolated protocol RoomInfoProxyProtocol: BaseRoomInfoProxyProtocol {
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 }
@@ -56,6 +56,7 @@ final nonisolated class RoomMemberProxy: RoomMemberProxyProtocol {
.init(rustPowerLevel: member.powerLevel)
}
// periphery:ignore - might be useful to have
var isServiceMember: Bool {
member.isServiceMember
}
@@ -26,6 +26,7 @@ nonisolated protocol RoomMemberProxyProtocol: AnyObject, Sendable {
var powerLevel: RoomPowerLevel { get }
// periphery:ignore - might be useful to have
var isServiceMember: Bool { get }
}
@@ -20,10 +20,6 @@ nonisolated enum RoomPowerLevel: Hashable, Comparable {
self = .value(value)
}
init(value: Int64) {
self = .value(Int(value))
}
var rustPowerLevel: PowerLevel {
switch self {
case .infinite: .infinite
@@ -24,17 +24,6 @@ protocol RoomPowerLevelsProxyProtocol: Sendable {
func canOwnUserPinOrUnpin() -> Bool
func canOwnUserJoinCall() -> Bool
func canOwnUserEditRolesAndPermissions() -> Bool
func canUser(userID: String, sendMessage messageType: MessageLikeEventType) -> Result<Bool, RoomProxyError>
func canUser(userID: String, sendStateEvent event: StateEventType) -> Result<Bool, RoomProxyError>
func canUserInvite(userID: String) -> Result<Bool, RoomProxyError>
func canUserRedactOther(userID: String) -> Result<Bool, RoomProxyError>
func canUserRedactOwn(userID: String) -> Result<Bool, RoomProxyError>
func canUserKick(userID: String) -> Result<Bool, RoomProxyError>
func canUserBan(userID: String) -> Result<Bool, RoomProxyError>
func canUserTriggerRoomNotification(userID: String) -> Result<Bool, RoomProxyError>
func canUserPinOrUnpin(userID: String) -> Result<Bool, RoomProxyError>
func canUserJoinCall(userID: String) -> Result<Bool, RoomProxyError>
}
// MARK: - Helpers
@@ -70,94 +70,4 @@ nonisolated struct RoomPowerLevelsProxy: RoomPowerLevelsProxyProtocol {
func canOwnUserEditRolesAndPermissions() -> Bool {
powerLevels.canOwnUserSendState(stateEvent: .roomPowerLevels)
}
func canUser(userID: String, sendMessage messageType: MessageLikeEventType) -> Result<Bool, RoomProxyError> {
do {
return try .success(powerLevels.canUserSendMessage(userId: userID, message: messageType))
} catch {
MXLog.error("Failed checking if the user can send message with error: \(error)")
return .failure(.sdkError(error))
}
}
func canUser(userID: String, sendStateEvent event: StateEventType) -> Result<Bool, RoomProxyError> {
do {
return try .success(powerLevels.canUserSendState(userId: userID, stateEvent: event))
} catch {
MXLog.error("Failed checking if the user can send \(event) with error: \(error)")
return .failure(.sdkError(error))
}
}
func canUserInvite(userID: String) -> Result<Bool, RoomProxyError> {
do {
return try .success(powerLevels.canUserInvite(userId: userID))
} catch {
MXLog.error("Failed checking if the user can invite with error: \(error)")
return .failure(.sdkError(error))
}
}
func canUserRedactOther(userID: String) -> Result<Bool, RoomProxyError> {
do {
return try .success(powerLevels.canUserRedactOther(userId: userID))
} catch {
MXLog.error("Failed checking if the user can redact others with error: \(error)")
return .failure(.sdkError(error))
}
}
func canUserRedactOwn(userID: String) -> Result<Bool, RoomProxyError> {
do {
return try .success(powerLevels.canUserRedactOwn(userId: userID))
} catch {
MXLog.error("Failed checking if the user can redact self with error: \(error)")
return .failure(.sdkError(error))
}
}
func canUserKick(userID: String) -> Result<Bool, RoomProxyError> {
do {
return try .success(powerLevels.canUserKick(userId: userID))
} catch {
MXLog.error("Failed checking if the user can kick with error: \(error)")
return .failure(.sdkError(error))
}
}
func canUserBan(userID: String) -> Result<Bool, RoomProxyError> {
do {
return try .success(powerLevels.canUserBan(userId: userID))
} catch {
MXLog.error("Failed checking if the user can ban with error: \(error)")
return .failure(.sdkError(error))
}
}
func canUserTriggerRoomNotification(userID: String) -> Result<Bool, RoomProxyError> {
do {
return try .success(powerLevels.canUserTriggerRoomNotification(userId: userID))
} catch {
MXLog.error("Failed checking if the user can trigger room notification with error: \(error)")
return .failure(.sdkError(error))
}
}
func canUserPinOrUnpin(userID: String) -> Result<Bool, RoomProxyError> {
do {
return try .success(powerLevels.canUserPinUnpin(userId: userID))
} catch {
MXLog.error("Failed checking if the user can pin or unnpin: \(error)")
return .failure(.sdkError(error))
}
}
func canUserJoinCall(userID: String) -> Result<Bool, RoomProxyError> {
do {
return try .success(powerLevels.canUserSendState(userId: userID, stateEvent: .callMember))
} catch {
MXLog.error("Failed checking if the user can trigger room notification with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -17,7 +17,6 @@ enum RoomProxyError: Error {
case invalidURL
case invalidMedia
case eventNotFound
case missingTransactionID
case failedCreatingPinnedTimeline
case timelineError(TimelineProxyError)
case liveLocationSessionIsNotActive
@@ -57,22 +56,11 @@ protocol BannedRoomProxyProtocol: RoomProxyProtocol {
func forgetRoom() async -> Result<Void, RoomProxyError>
}
enum JoinedRoomProxyAction: Equatable {
case roomInfoUpdate
}
enum KnockRequestsState {
case loading
case loaded([KnockRequestProxyProtocol])
}
struct RTCDeclinedEvent {
/// The sender of the decline event
let sender: String
/// The rtc.notification event that is beeing declined
let notificationEventID: String
}
// sourcery: AutoMockable
protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
var infoPublisher: CurrentValuePublisher<RoomInfoProxyProtocol, Never> { get }
@@ -89,8 +77,6 @@ protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
var predecessorRoom: PredecessorRoom? { get }
var successorRoom: SuccessorRoom? { get }
func subscribeForUpdates() async
func subscribeToRoomInfoUpdates()
@@ -111,8 +97,6 @@ protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
func enableEncryption() async -> Result<Void, RoomProxyError>
func redact(_ eventID: String) async -> Result<Void, RoomProxyError>
func reportContent(_ eventID: String, reason: String?) async -> Result<Void, RoomProxyError>
func reportRoom(reason: String) async -> Result<Void, RoomProxyError>
@@ -135,8 +119,6 @@ protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
func markAsRead(receiptType: ReceiptType) async -> Result<Void, RoomProxyError>
func edit(eventID: String, newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, RoomProxyError>
/// https://spec.matrix.org/v1.9/client-server-api/#typing-notifications
@discardableResult func sendTypingNotification(isTyping: Bool) async -> Result<Void, RoomProxyError>
@@ -167,10 +149,8 @@ protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
// MARK: - Power Levels
func powerLevels() async -> Result<RoomPowerLevelsProxyProtocol?, RoomProxyError>
func applyPowerLevelChanges(_ changes: RoomPowerLevelChanges) async -> Result<Void, RoomProxyError>
func resetPowerLevels() async -> Result<Void, RoomProxyError>
func suggestedRole(for userID: String) async -> Result<RoomMemberRole, RoomProxyError>
func updatePowerLevelsForUsers(_ updates: [(userID: String, powerLevel: Int64)]) async -> Result<Void, RoomProxyError>
// MARK: - Moderation
@@ -106,6 +106,7 @@ nonisolated struct RoomEventStringBuilder {
shouldPrefixSenderName: false)
}
// periphery:ignore - might be useful to have
static func threadListEventStringBuilder(userID: String) -> Self {
RoomEventStringBuilder(stateEventStringBuilder: .init(userID: userID),
messageEventStringBuilder: .init(attributedStringBuilder: AttributedStringBuilder(cacheKey: "threadList", mentionBuilder: PlainMentionBuilder()),
@@ -21,13 +21,6 @@ nonisolated struct RoomSummary {
default: false
}
}
var isKnock: Bool {
switch self {
case .knock: true
default: false
}
}
}
enum LastMessageState { case sending, failed }
@@ -26,7 +26,6 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
private var roomList: RoomListProtocol?
private var cancellables = Set<AnyCancellable>()
private var roomListServiceStateCancellable: AnyCancellable?
private var listUpdatesSubscriptionResult: RoomListEntriesWithDynamicAdaptersResult?
private var stateUpdatesTaskHandle: TaskHandle?
@@ -13,19 +13,21 @@ class RoomThreadListProxy: RoomThreadListServiceProxyProtocol {
private let threadListService: ThreadListServiceProtocol
private let eventStringBuilder: RoomEventStringBuilder
// periphery:ignore - required for instance retention in the rust codebase
private var itemUpdatesHandle: TaskHandle?
private let itemsSubject = CurrentValueSubject<[RoomThreadListItem], Never>([])
var itemsPublisher: CurrentValuePublisher<[RoomThreadListItem], Never> {
itemsSubject.asCurrentValuePublisher()
}
// periphery:ignore - required for instance retention in the rust codebase
private var paginationStateHandle: TaskHandle?
private let paginationStateSubject: CurrentValueSubject<RoomThreadListPaginationState, Never>
var paginationStatePublisher: CurrentValuePublisher<RoomThreadListPaginationState, Never> {
paginationStateSubject.asCurrentValuePublisher()
}
init(threadListService: ThreadListServiceProtocol, eventStringBuilder: RoomEventStringBuilder, paginationToken: String? = nil) {
init(threadListService: ThreadListServiceProtocol, eventStringBuilder: RoomEventStringBuilder) {
self.threadListService = threadListService
self.eventStringBuilder = eventStringBuilder
@@ -29,6 +29,7 @@ final class RoomDirectorySearchProxy: RoomDirectorySearchProxyProtocol {
/// main actor in FIFO order, guaranteeing one in-flight update at a time.
private let updatesContinuation: AsyncStream<[RoomDirectorySearchEntryUpdate]>.Continuation
// periphery:ignore - required for instance retention in the rust codebase
private var searchEntriesSubscription: TaskHandle?
deinit {
@@ -12,7 +12,6 @@ class SearchServiceProxy: SearchServiceProxyProtocol {
private let searchService: SearchServiceProtocol
private let timelineItemFactory: RoomTimelineItemFactoryProtocol
// periphery:ignore - required for instance retention in the rust codebase
private var resultsHandle: TaskHandle?
private let resultsSubject = CurrentValueSubject<[SearchServiceResult], Never>([])
@@ -19,10 +19,9 @@ class SecureBackupController: SecureBackupControllerProtocol {
// periphery:ignore - retaining purpose
private var backupStateListenerTaskHandle: TaskHandle?
// periphery:ignore - retaining purpose
// periphery:ignore - required for instance retention in the rust codebase
private var recoveryStateListenerTaskHandle: TaskHandle?
// periphery:ignore - auto cancels when reassigned
/// Used to dedupe remote backup state requests
@CancellableTask private var remoteBackupStateTask: Task<Void, Error>?
@@ -105,6 +105,7 @@ final class LeaveSpaceHandleProxy {
@Observable class LeaveSpaceRoomDetails {
let spaceServiceRoom: SpaceServiceRoom
let canLeave: Bool
// periphery:ignore - might be useful to have
let areCreatorsPrivileged: Bool
var isSelected: Bool
@@ -16,18 +16,21 @@ class SpaceRoomListProxy: SpaceRoomListProxyProtocol {
private let spaceRoomList: SpaceRoomListProtocol
// periphery:ignore - required for instance retention in the rust codebase
private var spaceServiceRoomHandle: TaskHandle?
private let spaceServiceRoomSubject: CurrentValueSubject<SpaceServiceRoom, Never>
var spaceServiceRoomPublisher: CurrentValuePublisher<SpaceServiceRoom, Never> {
spaceServiceRoomSubject.asCurrentValuePublisher()
}
// periphery:ignore - required for instance retention in the rust codebase
private var spaceRoomsHandle: TaskHandle?
private let spaceRoomsSubject = CurrentValueSubject<[SpaceServiceRoom], Never>([])
var spaceRoomsPublisher: CurrentValuePublisher<[SpaceServiceRoom], Never> {
spaceRoomsSubject.asCurrentValuePublisher()
}
// periphery:ignore - required for instance retention in the rust codebase
private var paginationStateHandle: TaskHandle?
private let paginationStateSubject: CurrentValueSubject<SpaceRoomListPaginationState, Never>
var paginationStatePublisher: CurrentValuePublisher<SpaceRoomListPaginationState, Never> {
@@ -13,12 +13,14 @@ import MatrixRustSDK
class SpaceServiceProxy: SpaceServiceProxyProtocol {
private let spaceService: SpaceServiceProtocol
// periphery:ignore - required for instance retention in the rust codebase
private var topLevelSpacesHandle: TaskHandle?
private let spacesSubject = CurrentValueSubject<[SpaceServiceRoom], Never>([])
var topLevelSpacesPublisher: CurrentValuePublisher<[SpaceServiceRoom], Never> {
spacesSubject.asCurrentValuePublisher()
}
// periphery:ignore - required for instance retention in the rust codebase
private var spaceFilterHandle: TaskHandle?
private let spaceFilterSubject = CurrentValueSubject<[SpaceServiceFilter], Never>([])
var spaceFilterPublisher: CurrentValuePublisher<[SpaceServiceFilter], Never> {
@@ -19,6 +19,7 @@ enum SpaceServiceRoomVisibility: Equatable {
struct SpaceServiceRoom {
var id: String
var name: String
// periphery:ignore - might be useful to have
var rawName: String?
var avatarURL: URL?
@@ -33,7 +34,9 @@ struct SpaceServiceRoom {
var canonicalAlias: String?
var joinRule: JoinRule?
// periphery:ignore - might be useful to have
var worldReadable: Bool?
// periphery:ignore - might be useful to have
var guestCanJoin: Bool
var state: Membership?
var via: [String]
@@ -126,11 +126,6 @@ enum TimelineFixtures {
singleMessageChunkProxies.buildRoomTimelineItems()
}
/// A single text item.
static var incomingMessage: RoomTimelineItemProtocol {
incomingMessageProxy.buildRoomTimelineItem()
}
/// A large chunk of events, containing 40 text items which should fill an iPad
/// with enough items so that it won't perform another back pagination.
static var largeChunk: [RoomTimelineItemProtocol] {
@@ -44,7 +44,6 @@ enum TimelineControllerError: Error {
/// timeline items, grouping together state events, donating intents to the larger system etc.
@MainActor
protocol TimelineControllerProtocol: Sendable {
var roomID: String { get }
var timelineKind: TimelineKind { get }
/// The currently known items, use only for setting up the intial state.
@@ -26,6 +26,7 @@ nonisolated enum TimelineItemIdentifier: Hashable {
self.init(rustValue.id)
}
// periphery:ignore - might be useful to have
var rustValue: TimelineUniqueId {
.init(id: value)
}
@@ -69,6 +70,7 @@ nonisolated enum TimelineItemIdentifier: Hashable {
return eventID
}
// periphery:ignore - might be useful to have
var transactionID: String? {
guard case let .event(_, .transactionID(transactionID)) = self else { return nil }
return transactionID
@@ -205,25 +205,6 @@ private nonisolated extension TimelineItemProxy {
}
}
private extension VirtualTimelineItem {
var description: String {
switch self {
case .dateDivider(let timestamp):
return "DayDiviver(\(timestamp))"
case .readMarker:
return "ReadMarker"
case .timelineStart:
return "TimelineStart"
}
}
}
private extension Array where Element == TimelineDiff {
var debugDescription: String {
"[" + map(\.debugDescription).joined(separator: ",") + "]"
}
}
extension TimelineDiff: @retroactive CustomDebugStringConvertible {
public var debugDescription: String {
switch self {
@@ -236,8 +236,11 @@ nonisolated struct SendHandleProxy: Hashable {
nonisolated struct VideoInfoProxy: Hashable {
let source: MediaSourceProxy
private(set) var duration: TimeInterval
// periphery:ignore - used via the synthesized Hashable conformance
private(set) var size: CGSize?
// periphery:ignore - used via the synthesized Hashable conformance
private(set) var aspectRatio: CGFloat?
// periphery:ignore - used via the synthesized Hashable conformance
private(set) var mimeType: String?
private(set) var fileSize: UInt?
@@ -281,6 +284,7 @@ nonisolated struct ImageInfoProxy: Hashable {
let source: MediaSourceProxy
private(set) var size: CGSize?
private(set) var aspectRatio: CGFloat?
// periphery:ignore - used via the synthesized Hashable conformance
private(set) var mimeType: String?
private(set) var fileSize: UInt?
@@ -8,5 +8,4 @@
import Foundation
// periphery: ignore - markdown protocol
nonisolated protocol DecorationTimelineItemProtocol: RoomTimelineItemProtocol { }
@@ -11,6 +11,7 @@ import UIKit
nonisolated struct EmoteRoomTimelineItemContent: Hashable {
let body: String
var formattedBody: AttributedString?
// periphery:ignore - used via the synthesized Hashable conformance
/// The original textual representation of the formatted body directly from the event (usually HTML code)
var formattedBodyHTMLString: String?
}
@@ -11,9 +11,6 @@ import Foundation
nonisolated struct CallNotificationRoomTimelineItem: RoomTimelineItemProtocol, Equatable {
let id: TimelineItemIdentifier
let timestamp: Date
let isEditable: Bool
let canBeRepliedTo: Bool
let isDM: Bool
let isDeclinedByMe: Bool
let isDeclined: Bool
@@ -25,6 +25,7 @@ nonisolated struct Poll: Hashable {
let kind: Kind
let maxSelections: Int
let options: [Option]
// periphery:ignore - used via the synthesized Hashable conformance
let votes: [String: [String]]
let endDate: Date?
/// Whether the poll has been created by the account owner
@@ -857,8 +857,6 @@ nonisolated struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
let isVoiceCall = callIntent == CallIntent.audio.rawValue
return CallNotificationRoomTimelineItem(id: eventItemProxy.id,
timestamp: eventItemProxy.timestamp,
isEditable: eventItemProxy.isEditable,
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
isDM: isDM,
isDeclinedByMe: declinedBy.contains(userID),
isDeclined: !declinedBy.isEmpty,
@@ -48,10 +48,10 @@ struct RoomTimelineItemView: View {
RedactedRoomTimelineView(timelineItem: item)
case .encrypted(let item):
EncryptedRoomTimelineView(timelineItem: item)
case .readMarker(let item):
ReadMarkerRoomTimelineView(timelineItem: item)
case .paginationIndicator(let item):
PaginationIndicatorRoomTimelineView(timelineItem: item)
case .readMarker:
ReadMarkerRoomTimelineView()
case .paginationIndicator:
PaginationIndicatorRoomTimelineView()
case .sticker(let item):
StickerRoomTimelineView(timelineItem: item)
case .unsupported(let item):
@@ -71,8 +71,8 @@ struct RoomTimelineItemView: View {
title: L10n.commonVoiceMessage,
duration: 0)
VoiceMessageRoomTimelineView(timelineItem: item, playerState: playerState)
case .callInvite(let item):
CallInviteRoomTimelineView(timelineItem: item)
case .callInvite:
CallInviteRoomTimelineView()
case .callNotification(let item):
CallNotificationRoomTimelineView(timelineItem: item)
case .liveLocation(let item):
@@ -86,7 +86,7 @@ struct RoomTimelineItemView: View {
if let item = context?.viewState.linkMetadataProvider?.metadataItems[url] {
linkMetadata[url] = item
} else {
linkMetadata[url] = LinkMetadataProviderItem(url: url, metadata: nil)
linkMetadata[url] = LinkMetadataProviderItem(metadata: nil)
}
}
return linkMetadata
@@ -653,16 +653,4 @@ extension Array where Element == TimelineItemProxy {
return nil
}
func firstEventTimelineItemUsingEventOrTransactionID(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID) -> EventTimelineItem? {
for item in self {
if case let .event(eventTimelineItem) = item,
case let .event(_, identifier) = eventTimelineItem.id,
identifier == eventOrTransactionID {
return eventTimelineItem.item
}
}
return nil
}
}
@@ -46,8 +46,6 @@ enum TimelineAllowedMessageType {
enum TimelineProxyError: Error {
case sdkError(Error)
case failedRedacting
}
/// Element X proxies generally wrap the counterpart RustSDK objects while providing platform specific
@@ -127,6 +127,7 @@ nonisolated extension UserStatus.Raw {
emoji = Character(rustStatus.emoji)
}
// periphery:ignore - might be useful to have
var rustValue: MatrixRustSDK.UserStatus {
.init(emoji: String(emoji), text: text)
}
@@ -137,6 +138,7 @@ nonisolated extension UserStatus.Call {
joinedDate = rustCall.callJoinedTs.map { Date(timeIntervalSince1970: Double($0)) }
}
// periphery:ignore - might be useful to have
var rustValue: MatrixRustSDK.UserCall {
.init(callJoinedTs: joinedDate.map { UInt64($0.timeIntervalSince1970) })
}
@@ -146,6 +148,7 @@ nonisolated extension UserStatus.Call {
struct SearchUsersResults {
let results: [UserProfile]
// periphery:ignore - documents the schema, parsed but not consumed yet
let limited: Bool
}
@@ -21,8 +21,6 @@ class VoiceMessageRecorder: VoiceMessageRecorderProtocol {
actionsSubject.eraseToAnyPublisher()
}
private let mp4accMimeType = "audio/m4a"
var isRecording: Bool {
audioRecorder.isRecording
}