Update the SDK. (#3565)

* Update the SDK.

* Add mockMXC URLs to fix all the crashes during tests.

* Refactor Voice Messages to not use a MediaSource for local files.
This commit is contained in:
Doug
2024-11-28 08:34:38 +00:00
committed by GitHub
parent e70a95cfa2
commit 751be7b3a7
75 changed files with 222 additions and 590 deletions
+1 -5
View File
@@ -983,7 +983,6 @@
D02AA6208C7ACB9BE6332394 /* UNNotificationContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE148A4FFEE853C5A281500C /* UNNotificationContent.swift */; }; D02AA6208C7ACB9BE6332394 /* UNNotificationContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE148A4FFEE853C5A281500C /* UNNotificationContent.swift */; };
D02DEB36D32A72A1B365E452 /* SessionVerificationScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 796CBD0C56FA0D3AEDAB255B /* SessionVerificationScreenCoordinator.swift */; }; D02DEB36D32A72A1B365E452 /* SessionVerificationScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 796CBD0C56FA0D3AEDAB255B /* SessionVerificationScreenCoordinator.swift */; };
D050D7756E92CA061ED0ABF0 /* SecureBackupLogoutConfirmationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74E08B8A66948E9690F38B94 /* SecureBackupLogoutConfirmationScreenViewModelProtocol.swift */; }; D050D7756E92CA061ED0ABF0 /* SecureBackupLogoutConfirmationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74E08B8A66948E9690F38B94 /* SecureBackupLogoutConfirmationScreenViewModelProtocol.swift */; };
D0550B8E0AE2C0CDBE52C88F /* MediaPlayerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE87C931165F5E201CACBB87 /* MediaPlayerProtocol.swift */; };
D0A965852D6C04138FA55181 /* SecureBackupLogoutConfirmationScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCF239C619971FDE48132550 /* SecureBackupLogoutConfirmationScreenModels.swift */; }; D0A965852D6C04138FA55181 /* SecureBackupLogoutConfirmationScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCF239C619971FDE48132550 /* SecureBackupLogoutConfirmationScreenModels.swift */; };
D10BA4F041DC58580A440A32 /* RoomRolesAndPermissionsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B1DC3B3FB40A7F4AE9B7BF /* RoomRolesAndPermissionsScreen.swift */; }; D10BA4F041DC58580A440A32 /* RoomRolesAndPermissionsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B1DC3B3FB40A7F4AE9B7BF /* RoomRolesAndPermissionsScreen.swift */; };
D12F440F7973F1489F61389D /* NotificationSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F64447FF544298A6A3BEF85 /* NotificationSettingsScreenModels.swift */; }; D12F440F7973F1489F61389D /* NotificationSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F64447FF544298A6A3BEF85 /* NotificationSettingsScreenModels.swift */; };
@@ -2414,7 +2413,6 @@
FDEDD4D2DE0646DA724985D5 /* QRCodeLoginScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeLoginScreenModels.swift; sourceTree = "<group>"; }; FDEDD4D2DE0646DA724985D5 /* QRCodeLoginScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeLoginScreenModels.swift; sourceTree = "<group>"; };
FDF73F49E6B6683F7E2D26F0 /* SecureBackupScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreenCoordinator.swift; sourceTree = "<group>"; }; FDF73F49E6B6683F7E2D26F0 /* SecureBackupScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreenCoordinator.swift; sourceTree = "<group>"; };
FE1E6FAA3719E9B7A2D5510B /* FormattingToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormattingToolbar.swift; sourceTree = "<group>"; }; FE1E6FAA3719E9B7A2D5510B /* FormattingToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormattingToolbar.swift; sourceTree = "<group>"; };
FE87C931165F5E201CACBB87 /* MediaPlayerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPlayerProtocol.swift; sourceTree = "<group>"; };
FF720BA68256297680980481 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; }; FF720BA68256297680980481 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
FFECCE59967018204876D0A5 /* LocationMarkerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationMarkerView.swift; sourceTree = "<group>"; }; FFECCE59967018204876D0A5 /* LocationMarkerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationMarkerView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@@ -3785,7 +3783,6 @@
6709362D60732DED2069AE0F /* MediaPlayer */ = { 6709362D60732DED2069AE0F /* MediaPlayer */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FE87C931165F5E201CACBB87 /* MediaPlayerProtocol.swift */,
E8A1F98AE670377B20679FF5 /* MediaPlayerProvider.swift */, E8A1F98AE670377B20679FF5 /* MediaPlayerProvider.swift */,
F5E23D8EE6CBACF32F1EC874 /* MediaPlayerProviderProtocol.swift */, F5E23D8EE6CBACF32F1EC874 /* MediaPlayerProviderProtocol.swift */,
); );
@@ -6894,7 +6891,6 @@
208C19811613F9A10F8A7B75 /* MediaLoader.swift in Sources */, 208C19811613F9A10F8A7B75 /* MediaLoader.swift in Sources */,
A2434D4DFB49A68E5CD0F53C /* MediaLoaderProtocol.swift in Sources */, A2434D4DFB49A68E5CD0F53C /* MediaLoaderProtocol.swift in Sources */,
4E0D9E09B52CEC4C0E6211A8 /* MediaPickerScreenCoordinator.swift in Sources */, 4E0D9E09B52CEC4C0E6211A8 /* MediaPickerScreenCoordinator.swift in Sources */,
D0550B8E0AE2C0CDBE52C88F /* MediaPlayerProtocol.swift in Sources */,
F66BCCC825D6CA51724A94D0 /* MediaPlayerProvider.swift in Sources */, F66BCCC825D6CA51724A94D0 /* MediaPlayerProvider.swift in Sources */,
762DAF94846C7AC8550F1CC1 /* MediaPlayerProviderProtocol.swift in Sources */, 762DAF94846C7AC8550F1CC1 /* MediaPlayerProviderProtocol.swift in Sources */,
B6EC2148FA5443C9289BEEBA /* MediaProvider.swift in Sources */, B6EC2148FA5443C9289BEEBA /* MediaProvider.swift in Sources */,
@@ -8195,7 +8191,7 @@
repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift"; repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift";
requirement = { requirement = {
kind = exactVersion; kind = exactVersion;
version = 1.0.75; version = 1.0.76;
}; };
}; };
701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = { 701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = {
@@ -149,8 +149,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/element-hq/matrix-rust-components-swift", "location" : "https://github.com/element-hq/matrix-rust-components-swift",
"state" : { "state" : {
"revision" : "6b14c048543bac9effe5e44fa90333bfa7dd9435", "revision" : "dfb54791b10d17c5e2604c716c8e939bed221435",
"version" : "1.0.75" "version" : "1.0.76"
} }
}, },
{ {
@@ -1200,12 +1200,7 @@ class AudioConverterMock: AudioConverterProtocol {
} }
} }
class AudioPlayerMock: AudioPlayerProtocol { class AudioPlayerMock: AudioPlayerProtocol {
var actions: AnyPublisher<AudioPlayerAction, Never> { var sourceURL: URL?
get { return underlyingActions }
set(value) { underlyingActions = value }
}
var underlyingActions: AnyPublisher<AudioPlayerAction, Never>!
var mediaSource: MediaSourceProxy?
var duration: TimeInterval { var duration: TimeInterval {
get { return underlyingDuration } get { return underlyingDuration }
set(value) { underlyingDuration = value } set(value) { underlyingDuration = value }
@@ -1216,24 +1211,29 @@ class AudioPlayerMock: AudioPlayerProtocol {
set(value) { underlyingCurrentTime = value } set(value) { underlyingCurrentTime = value }
} }
var underlyingCurrentTime: TimeInterval! var underlyingCurrentTime: TimeInterval!
var url: URL? var playbackURL: URL?
var state: MediaPlayerState { var state: MediaPlayerState {
get { return underlyingState } get { return underlyingState }
set(value) { underlyingState = value } set(value) { underlyingState = value }
} }
var underlyingState: MediaPlayerState! var underlyingState: MediaPlayerState!
var actions: AnyPublisher<AudioPlayerAction, Never> {
get { return underlyingActions }
set(value) { underlyingActions = value }
}
var underlyingActions: AnyPublisher<AudioPlayerAction, Never>!
//MARK: - load //MARK: - load
var loadMediaSourceUsingAutoplayUnderlyingCallsCount = 0 var loadSourceURLPlaybackURLAutoplayUnderlyingCallsCount = 0
var loadMediaSourceUsingAutoplayCallsCount: Int { var loadSourceURLPlaybackURLAutoplayCallsCount: Int {
get { get {
if Thread.isMainThread { if Thread.isMainThread {
return loadMediaSourceUsingAutoplayUnderlyingCallsCount return loadSourceURLPlaybackURLAutoplayUnderlyingCallsCount
} else { } else {
var returnValue: Int? = nil var returnValue: Int? = nil
DispatchQueue.main.sync { DispatchQueue.main.sync {
returnValue = loadMediaSourceUsingAutoplayUnderlyingCallsCount returnValue = loadSourceURLPlaybackURLAutoplayUnderlyingCallsCount
} }
return returnValue! return returnValue!
@@ -1241,28 +1241,28 @@ class AudioPlayerMock: AudioPlayerProtocol {
} }
set { set {
if Thread.isMainThread { if Thread.isMainThread {
loadMediaSourceUsingAutoplayUnderlyingCallsCount = newValue loadSourceURLPlaybackURLAutoplayUnderlyingCallsCount = newValue
} else { } else {
DispatchQueue.main.sync { DispatchQueue.main.sync {
loadMediaSourceUsingAutoplayUnderlyingCallsCount = newValue loadSourceURLPlaybackURLAutoplayUnderlyingCallsCount = newValue
} }
} }
} }
} }
var loadMediaSourceUsingAutoplayCalled: Bool { var loadSourceURLPlaybackURLAutoplayCalled: Bool {
return loadMediaSourceUsingAutoplayCallsCount > 0 return loadSourceURLPlaybackURLAutoplayCallsCount > 0
} }
var loadMediaSourceUsingAutoplayReceivedArguments: (mediaSource: MediaSourceProxy, url: URL, autoplay: Bool)? var loadSourceURLPlaybackURLAutoplayReceivedArguments: (sourceURL: URL, playbackURL: URL, autoplay: Bool)?
var loadMediaSourceUsingAutoplayReceivedInvocations: [(mediaSource: MediaSourceProxy, url: URL, autoplay: Bool)] = [] var loadSourceURLPlaybackURLAutoplayReceivedInvocations: [(sourceURL: URL, playbackURL: URL, autoplay: Bool)] = []
var loadMediaSourceUsingAutoplayClosure: ((MediaSourceProxy, URL, Bool) -> Void)? var loadSourceURLPlaybackURLAutoplayClosure: ((URL, URL, Bool) -> Void)?
func load(mediaSource: MediaSourceProxy, using url: URL, autoplay: Bool) { func load(sourceURL: URL, playbackURL: URL, autoplay: Bool) {
loadMediaSourceUsingAutoplayCallsCount += 1 loadSourceURLPlaybackURLAutoplayCallsCount += 1
loadMediaSourceUsingAutoplayReceivedArguments = (mediaSource: mediaSource, url: url, autoplay: autoplay) loadSourceURLPlaybackURLAutoplayReceivedArguments = (sourceURL: sourceURL, playbackURL: playbackURL, autoplay: autoplay)
DispatchQueue.main.async { DispatchQueue.main.async {
self.loadMediaSourceUsingAutoplayReceivedInvocations.append((mediaSource: mediaSource, url: url, autoplay: autoplay)) self.loadSourceURLPlaybackURLAutoplayReceivedInvocations.append((sourceURL: sourceURL, playbackURL: playbackURL, autoplay: autoplay))
} }
loadMediaSourceUsingAutoplayClosure?(mediaSource, url, autoplay) loadSourceURLPlaybackURLAutoplayClosure?(sourceURL, playbackURL, autoplay)
} }
//MARK: - reset //MARK: - reset
@@ -9812,320 +9812,13 @@ class MediaLoaderMock: MediaLoaderProtocol {
} }
} }
} }
class MediaPlayerMock: MediaPlayerProtocol {
var mediaSource: MediaSourceProxy?
var duration: TimeInterval {
get { return underlyingDuration }
set(value) { underlyingDuration = value }
}
var underlyingDuration: TimeInterval!
var currentTime: TimeInterval {
get { return underlyingCurrentTime }
set(value) { underlyingCurrentTime = value }
}
var underlyingCurrentTime: TimeInterval!
var url: URL?
var state: MediaPlayerState {
get { return underlyingState }
set(value) { underlyingState = value }
}
var underlyingState: MediaPlayerState!
//MARK: - load
var loadMediaSourceUsingAutoplayUnderlyingCallsCount = 0
var loadMediaSourceUsingAutoplayCallsCount: Int {
get {
if Thread.isMainThread {
return loadMediaSourceUsingAutoplayUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = loadMediaSourceUsingAutoplayUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
loadMediaSourceUsingAutoplayUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
loadMediaSourceUsingAutoplayUnderlyingCallsCount = newValue
}
}
}
}
var loadMediaSourceUsingAutoplayCalled: Bool {
return loadMediaSourceUsingAutoplayCallsCount > 0
}
var loadMediaSourceUsingAutoplayReceivedArguments: (mediaSource: MediaSourceProxy, url: URL, autoplay: Bool)?
var loadMediaSourceUsingAutoplayReceivedInvocations: [(mediaSource: MediaSourceProxy, url: URL, autoplay: Bool)] = []
var loadMediaSourceUsingAutoplayClosure: ((MediaSourceProxy, URL, Bool) -> Void)?
func load(mediaSource: MediaSourceProxy, using url: URL, autoplay: Bool) {
loadMediaSourceUsingAutoplayCallsCount += 1
loadMediaSourceUsingAutoplayReceivedArguments = (mediaSource: mediaSource, url: url, autoplay: autoplay)
DispatchQueue.main.async {
self.loadMediaSourceUsingAutoplayReceivedInvocations.append((mediaSource: mediaSource, url: url, autoplay: autoplay))
}
loadMediaSourceUsingAutoplayClosure?(mediaSource, url, autoplay)
}
//MARK: - reset
var resetUnderlyingCallsCount = 0
var resetCallsCount: Int {
get {
if Thread.isMainThread {
return resetUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = resetUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
resetUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
resetUnderlyingCallsCount = newValue
}
}
}
}
var resetCalled: Bool {
return resetCallsCount > 0
}
var resetClosure: (() -> Void)?
func reset() {
resetCallsCount += 1
resetClosure?()
}
//MARK: - play
var playUnderlyingCallsCount = 0
var playCallsCount: Int {
get {
if Thread.isMainThread {
return playUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = playUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
playUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
playUnderlyingCallsCount = newValue
}
}
}
}
var playCalled: Bool {
return playCallsCount > 0
}
var playClosure: (() -> Void)?
func play() {
playCallsCount += 1
playClosure?()
}
//MARK: - pause
var pauseUnderlyingCallsCount = 0
var pauseCallsCount: Int {
get {
if Thread.isMainThread {
return pauseUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = pauseUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
pauseUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
pauseUnderlyingCallsCount = newValue
}
}
}
}
var pauseCalled: Bool {
return pauseCallsCount > 0
}
var pauseClosure: (() -> Void)?
func pause() {
pauseCallsCount += 1
pauseClosure?()
}
//MARK: - stop
var stopUnderlyingCallsCount = 0
var stopCallsCount: Int {
get {
if Thread.isMainThread {
return stopUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = stopUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
stopUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
stopUnderlyingCallsCount = newValue
}
}
}
}
var stopCalled: Bool {
return stopCallsCount > 0
}
var stopClosure: (() -> Void)?
func stop() {
stopCallsCount += 1
stopClosure?()
}
//MARK: - seek
var seekToUnderlyingCallsCount = 0
var seekToCallsCount: Int {
get {
if Thread.isMainThread {
return seekToUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = seekToUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
seekToUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
seekToUnderlyingCallsCount = newValue
}
}
}
}
var seekToCalled: Bool {
return seekToCallsCount > 0
}
var seekToReceivedProgress: Double?
var seekToReceivedInvocations: [Double] = []
var seekToClosure: ((Double) async -> Void)?
func seek(to progress: Double) async {
seekToCallsCount += 1
seekToReceivedProgress = progress
DispatchQueue.main.async {
self.seekToReceivedInvocations.append(progress)
}
await seekToClosure?(progress)
}
}
class MediaPlayerProviderMock: MediaPlayerProviderProtocol { class MediaPlayerProviderMock: MediaPlayerProviderProtocol {
var player: AudioPlayerProtocol {
//MARK: - player get { return underlyingPlayer }
set(value) { underlyingPlayer = value }
var playerForUnderlyingCallsCount = 0
var playerForCallsCount: Int {
get {
if Thread.isMainThread {
return playerForUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = playerForUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
playerForUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
playerForUnderlyingCallsCount = newValue
}
}
}
} }
var playerForCalled: Bool { var underlyingPlayer: AudioPlayerProtocol!
return playerForCallsCount > 0
}
var playerForReceivedMediaSource: MediaSourceProxy?
var playerForReceivedInvocations: [MediaSourceProxy] = []
var playerForUnderlyingReturnValue: Result<MediaPlayerProtocol, MediaPlayerProviderError>!
var playerForReturnValue: Result<MediaPlayerProtocol, MediaPlayerProviderError>! {
get {
if Thread.isMainThread {
return playerForUnderlyingReturnValue
} else {
var returnValue: Result<MediaPlayerProtocol, MediaPlayerProviderError>? = nil
DispatchQueue.main.sync {
returnValue = playerForUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
playerForUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
playerForUnderlyingReturnValue = newValue
}
}
}
}
var playerForClosure: ((MediaSourceProxy) -> Result<MediaPlayerProtocol, MediaPlayerProviderError>)?
func player(for mediaSource: MediaSourceProxy) -> Result<MediaPlayerProtocol, MediaPlayerProviderError> {
playerForCallsCount += 1
playerForReceivedMediaSource = mediaSource
DispatchQueue.main.async {
self.playerForReceivedInvocations.append(mediaSource)
}
if let playerForClosure = playerForClosure {
return playerForClosure(mediaSource)
} else {
return playerForReturnValue
}
}
//MARK: - playerState //MARK: - playerState
var playerStateForUnderlyingCallsCount = 0 var playerStateForUnderlyingCallsCount = 0
@@ -18,7 +18,8 @@ extension MediaProviderMock {
return nil return nil
} }
if mediaSource?.url == .picturesDirectory { // At some stage it would be nice to return different images, but for now they can be the same.
if mediaSource?.url == .mockMXCImage || mediaSource?.url == .mockMXCAvatar {
return Asset.Images.appLogo.image return Asset.Images.appLogo.image
} }
@@ -43,14 +43,14 @@ extension RoomMemberProxyMock {
static var mockMe: RoomMemberProxyMock { static var mockMe: RoomMemberProxyMock {
RoomMemberProxyMock(with: .init(userID: "@me:matrix.org", RoomMemberProxyMock(with: .init(userID: "@me:matrix.org",
displayName: "Me", displayName: "Me",
avatarURL: URL.picturesDirectory, avatarURL: .mockMXCAvatar,
membership: .join)) membership: .join))
} }
static var mockMeAdmin: RoomMemberProxyMock { static var mockMeAdmin: RoomMemberProxyMock {
RoomMemberProxyMock(with: .init(userID: "@me:matrix.org", RoomMemberProxyMock(with: .init(userID: "@me:matrix.org",
displayName: "Me", displayName: "Me",
avatarURL: URL.picturesDirectory, avatarURL: .mockMXCAvatar,
membership: .join, membership: .join,
powerLevel: 100, powerLevel: 100,
role: .administrator)) role: .administrator))
@@ -83,7 +83,7 @@ extension RoomMemberProxyMock {
static var mockDan: RoomMemberProxyMock { static var mockDan: RoomMemberProxyMock {
RoomMemberProxyMock(with: .init(userID: "@dan:matrix.org", RoomMemberProxyMock(with: .init(userID: "@dan:matrix.org",
displayName: "Dan", displayName: "Dan",
avatarURL: URL.picturesDirectory, avatarURL: .mockMXCAvatar,
membership: .join)) membership: .join))
} }
@@ -91,7 +91,7 @@ extension Array where Element == RoomSummary {
joinRequestType: nil, joinRequestType: nil,
name: "Foundation and Empire", name: "Foundation and Empire",
isDirect: false, isDirect: false,
avatarURL: URL.picturesDirectory, avatarURL: .mockMXCAvatar,
heroes: [], heroes: [],
lastMessage: AttributedString("How do you see the Emperor then? You think he keeps office hours?"), lastMessage: AttributedString("How do you see the Emperor then? You think he keeps office hours?"),
lastMessageFormattedTimestamp: "2:56 PM", lastMessageFormattedTimestamp: "2:56 PM",
@@ -226,7 +226,7 @@ extension Array where Element == RoomSummary {
joinRequestType: .invite(inviter: RoomMemberProxyMock.mockCharlie), joinRequestType: .invite(inviter: RoomMemberProxyMock.mockCharlie),
name: "First room", name: "First room",
isDirect: false, isDirect: false,
avatarURL: URL.picturesDirectory, avatarURL: .mockMXCAvatar,
heroes: [], heroes: [],
lastMessage: nil, lastMessage: nil,
lastMessageFormattedTimestamp: nil, lastMessageFormattedTimestamp: nil,
@@ -100,4 +100,12 @@ extension URL: @retroactive ExpressibleByStringLiteral {
} }
return nil return nil
} }
// MARK: Mocks
static var mockMXCAudio: URL { "mxc://matrix.org/1234567890FiLe" }
static var mockMXCFile: URL { "mxc://matrix.org/1234567890FiLe" }
static var mockMXCImage: URL { "mxc://matrix.org/1234567890ImAgE" }
static var mockMXCVideo: URL { "mxc://matrix.org/1234567890ViDeO" }
static var mockMXCAvatar: URL { "mxc://matrix.org/1234567890AvAtAr" }
} }
@@ -190,7 +190,7 @@ struct AvatarHeaderView_Previews: PreviewProvider, TestablePreview {
name: "Test Room", name: "Test Room",
avatar: .room(id: "@test:matrix.org", avatar: .room(id: "@test:matrix.org",
name: "Test Room", name: "Test Room",
avatarURL: .picturesDirectory), avatarURL: .mockMXCAvatar),
canonicalAlias: "#test:matrix.org", canonicalAlias: "#test:matrix.org",
isEncrypted: true, isEncrypted: true,
isPublic: true), isPublic: true),
@@ -97,7 +97,7 @@ struct RoomAvatarImage_Previews: PreviewProvider, TestablePreview {
RoomAvatarImage(avatar: .room(id: "!2:server.com", RoomAvatarImage(avatar: .room(id: "!2:server.com",
name: "Room", name: "Room",
avatarURL: .picturesDirectory), avatarURL: .mockMXCAvatar),
avatarSize: .room(on: .home), avatarSize: .room(on: .home),
mediaProvider: MediaProviderMock(configuration: .init())) mediaProvider: MediaProviderMock(configuration: .init()))
@@ -109,7 +109,7 @@ struct RoomAvatarImage_Previews: PreviewProvider, TestablePreview {
RoomAvatarImage(avatar: .heroes([.init(userID: "@user:server.com", RoomAvatarImage(avatar: .heroes([.init(userID: "@user:server.com",
displayName: "User", displayName: "User",
avatarURL: .picturesDirectory)]), avatarURL: .mockMXCAvatar)]),
avatarSize: .room(on: .home), avatarSize: .room(on: .home),
mediaProvider: MediaProviderMock(configuration: .init())) mediaProvider: MediaProviderMock(configuration: .init()))
@@ -41,7 +41,7 @@ struct RoomHeaderView_Previews: PreviewProvider, TestablePreview {
RoomHeaderView(roomName: "Some Room name", RoomHeaderView(roomName: "Some Room name",
roomAvatar: .room(id: "1", roomAvatar: .room(id: "1",
name: "Some Room Name", name: "Some Room Name",
avatarURL: URL.picturesDirectory), avatarURL: .mockMXCAvatar),
mediaProvider: MediaProviderMock(configuration: .init())) mediaProvider: MediaProviderMock(configuration: .init()))
.previewLayout(.sizeThatFits) .previewLayout(.sizeThatFits)
.padding() .padding()
@@ -46,7 +46,7 @@ struct GlobalSearchScreenListRow_Previews: PreviewProvider, TestablePreview {
description: "The best place in the whole wide world", description: "The best place in the whole wide world",
avatar: .room(id: "123", avatar: .room(id: "123",
name: "Tech central", name: "Tech central",
avatarURL: .picturesDirectory)), avatarURL: .mockMXCAvatar)),
context: viewModel.context) context: viewModel.context)
} }
} }
@@ -145,7 +145,7 @@ struct HomeScreenInviteCell_Previews: PreviewProvider, TestablePreview {
HomeScreenInviteCell(room: .roomInvite(), HomeScreenInviteCell(room: .roomInvite(),
context: viewModel().context) context: viewModel().context)
HomeScreenInviteCell(room: .roomInvite(alias: "#footest:somewhere.org", avatarURL: .picturesDirectory), HomeScreenInviteCell(room: .roomInvite(alias: "#footest:somewhere.org", avatarURL: .mockMXCAvatar),
context: viewModel().context) context: viewModel().context)
HomeScreenInviteCell(room: .roomInvite(alias: "#footest:somewhere.org"), HomeScreenInviteCell(room: .roomInvite(alias: "#footest:somewhere.org"),
@@ -119,7 +119,7 @@ struct HomeScreenKnockedCell_Previews: PreviewProvider, TestablePreview {
HomeScreenKnockedCell(room: .roomKnocked(), HomeScreenKnockedCell(room: .roomKnocked(),
context: viewModel().context) context: viewModel().context)
HomeScreenKnockedCell(room: .roomKnocked(alias: "#footest:somewhere.org", avatarURL: .picturesDirectory), HomeScreenKnockedCell(room: .roomKnocked(alias: "#footest:somewhere.org", avatarURL: .mockMXCAvatar),
context: viewModel().context) context: viewModel().context)
HomeScreenKnockedCell(room: .roomKnocked(alias: "#footest:somewhere.org"), HomeScreenKnockedCell(room: .roomKnocked(alias: "#footest:somewhere.org"),
@@ -237,11 +237,11 @@ struct JoinRoomScreen_Previews: PreviewProvider, TestablePreview {
switch mode { switch mode {
case .knocked: case .knocked:
clientProxy.roomForIdentifierClosure = { _ in clientProxy.roomForIdentifierClosure = { _ in
.knocked(KnockedRoomProxyMock(.init(avatarURL: URL.homeDirectory))) .knocked(KnockedRoomProxyMock(.init(avatarURL: .mockMXCAvatar)))
} }
case .invited: case .invited:
clientProxy.roomForIdentifierClosure = { _ in clientProxy.roomForIdentifierClosure = { _ in
.invited(InvitedRoomProxyMock(.init(avatarURL: URL.homeDirectory))) .invited(InvitedRoomProxyMock(.init(avatarURL: .mockMXCAvatar)))
} }
default: default:
break break
@@ -251,7 +251,7 @@ struct JoinRoomScreen_Previews: PreviewProvider, TestablePreview {
canonicalAlias: "#3🌞problem:matrix.org", canonicalAlias: "#3🌞problem:matrix.org",
// swiftlint:disable:next line_length // swiftlint:disable:next line_length
topic: "“Science and technology were the only keys to opening the door to the future, and people approached science with the faith and sincerity of elementary school students.”", topic: "“Science and technology were the only keys to opening the door to the future, and people approached science with the faith and sincerity of elementary school students.”",
avatarURL: URL.homeDirectory, avatarURL: .mockMXCAvatar,
memberCount: UInt(100), memberCount: UInt(100),
isHistoryWorldReadable: false, isHistoryWorldReadable: false,
isJoined: membership.isJoined, isJoined: membership.isJoined,
@@ -84,7 +84,7 @@ struct RoomDirectorySearchScreen_Previews: PreviewProvider, TestablePreview {
topic: nil, topic: nil,
avatar: .room(id: "test_2", avatar: .room(id: "test_2",
name: "Test 2", name: "Test 2",
avatarURL: .documentsDirectory), avatarURL: .mockMXCAvatar),
canBeJoined: false)] canBeJoined: false)]
let roomDirectorySearchProxy = RoomDirectorySearchProxyMock(configuration: .init(results: results)) let roomDirectorySearchProxy = RoomDirectorySearchProxyMock(configuration: .init(results: results))
@@ -88,13 +88,13 @@ struct RoomMembersListMemberCell_Previews: PreviewProvider, TestablePreview {
.mockAdmin, .mockAdmin,
.mockModerator, .mockModerator,
.init(with: .init(userID: "@nodisplayname:matrix.org", membership: .join)), .init(with: .init(userID: "@nodisplayname:matrix.org", membership: .join)),
.init(with: .init(userID: "@avatar:matrix.org", displayName: "Avatar", avatarURL: .picturesDirectory, membership: .join)) .init(with: .init(userID: "@avatar:matrix.org", displayName: "Avatar", avatarURL: .mockMXCAvatar, membership: .join))
] ]
static let bannedMembers: [RoomMemberProxyMock] = [ static let bannedMembers: [RoomMemberProxyMock] = [
.init(with: .init(userID: "@nodisplayname:matrix.org", membership: .ban)), .init(with: .init(userID: "@nodisplayname:matrix.org", membership: .ban)),
.init(with: .init(userID: "@fake:matrix.org", displayName: "President", membership: .ban)), .init(with: .init(userID: "@fake:matrix.org", displayName: "President", membership: .ban)),
.init(with: .init(userID: "@badavatar:matrix.org", avatarURL: .picturesDirectory, membership: .ban)) .init(with: .init(userID: "@badavatar:matrix.org", avatarURL: .mockMXCAvatar, membership: .ban))
] ]
static let viewModel = RoomMembersListScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Some room", static let viewModel = RoomMembersListScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Some room",
@@ -118,7 +118,7 @@ struct CompletionSuggestion_Previews: PreviewProvider, TestablePreview {
VStack(spacing: 8) { VStack(spacing: 8) {
CompletionSuggestionView(mediaProvider: MediaProviderMock(configuration: .init()), CompletionSuggestionView(mediaProvider: MediaProviderMock(configuration: .init()),
items: [.user(item: MentionSuggestionItem(id: "@user_mention_1:matrix.org", displayName: "User 1", avatarURL: nil, range: .init())), items: [.user(item: MentionSuggestionItem(id: "@user_mention_1:matrix.org", displayName: "User 1", avatarURL: nil, range: .init())),
.user(item: MentionSuggestionItem(id: "@user_mention_2:matrix.org", displayName: "User 2", avatarURL: URL.documentsDirectory, range: .init()))]) { _ in } .user(item: MentionSuggestionItem(id: "@user_mention_2:matrix.org", displayName: "User 2", avatarURL: .mockMXCAvatar, range: .init()))]) { _ in }
} }
VStack(spacing: 8) { VStack(spacing: 8) {
CompletionSuggestionView(mediaProvider: MediaProviderMock(configuration: .init()), CompletionSuggestionView(mediaProvider: MediaProviderMock(configuration: .init()),
@@ -304,7 +304,7 @@ struct ComposerToolbar_Previews: PreviewProvider, TestablePreview {
analyticsService: ServiceLocator.shared.analytics, analyticsService: ServiceLocator.shared.analytics,
composerDraftService: ComposerDraftServiceMock()) composerDraftService: ComposerDraftServiceMock())
static let suggestions: [SuggestionItem] = [.user(item: MentionSuggestionItem(id: "@user_mention_1:matrix.org", displayName: "User 1", avatarURL: nil, range: .init())), static let suggestions: [SuggestionItem] = [.user(item: MentionSuggestionItem(id: "@user_mention_1:matrix.org", displayName: "User 1", avatarURL: nil, range: .init())),
.user(item: MentionSuggestionItem(id: "@user_mention_2:matrix.org", displayName: "User 2", avatarURL: URL.documentsDirectory, range: .init()))] .user(item: MentionSuggestionItem(id: "@user_mention_2:matrix.org", displayName: "User 2", avatarURL: .mockMXCAvatar, range: .init()))]
static var previews: some View { static var previews: some View {
ComposerToolbar.mock(focused: true) ComposerToolbar.mock(focused: true)
@@ -38,7 +38,7 @@ struct MentionSuggestionItemView_Previews: PreviewProvider, TestablePreview {
static let mockMediaProvider = MediaProviderMock(configuration: .init()) static let mockMediaProvider = MediaProviderMock(configuration: .init())
static var previews: some View { static var previews: some View {
MentionSuggestionItemView(mediaProvider: mockMediaProvider, item: .init(id: "test", displayName: "Test", avatarURL: URL.documentsDirectory, range: .init())) MentionSuggestionItemView(mediaProvider: mockMediaProvider, item: .init(id: "test", displayName: "Test", avatarURL: .mockMXCAvatar, range: .init()))
MentionSuggestionItemView(mediaProvider: mockMediaProvider, item: .init(id: "test2", displayName: nil, avatarURL: nil, range: .init())) MentionSuggestionItemView(mediaProvider: mockMediaProvider, item: .init(id: "test2", displayName: nil, avatarURL: nil, range: .init()))
} }
} }
@@ -408,10 +408,7 @@ class TimelineInteractionHandler {
return return
} }
guard case .success(let mediaPlayer) = mediaPlayerProvider.player(for: source), let audioPlayer = mediaPlayer as? AudioPlayerProtocol else { let audioPlayer = mediaPlayerProvider.player
MXLog.error("Cannot play a voice message without an audio player")
return
}
// Stop any recording in progress // Stop any recording in progress
if voiceMessageRecorder.isRecording { if voiceMessageRecorder.isRecording {
@@ -430,7 +427,7 @@ class TimelineInteractionHandler {
// Detach all other states // Detach all other states
await mediaPlayerProvider.detachAllStates(except: audioPlayerState) await mediaPlayerProvider.detachAllStates(except: audioPlayerState)
guard audioPlayer.mediaSource == source, audioPlayer.state != .error else { guard audioPlayer.sourceURL == source.url, audioPlayer.state != .error else {
// Load content // Load content
do { do {
MXLog.info("Loading voice message audio content from source for itemID \(itemID)") MXLog.info("Loading voice message audio content from source for itemID \(itemID)")
@@ -438,7 +435,7 @@ class TimelineInteractionHandler {
// Make sure that the player is still attached, as it may have been detached while waiting for the voice message to be loaded. // Make sure that the player is still attached, as it may have been detached while waiting for the voice message to be loaded.
if audioPlayerState.isAttached { if audioPlayerState.isAttached {
audioPlayer.load(mediaSource: source, using: url, autoplay: true) audioPlayer.load(sourceURL: source.url, playbackURL: url, autoplay: true)
} }
} catch { } catch {
MXLog.error("Failed to load voice message: \(error)") MXLog.error("Failed to load voice message: \(error)")
@@ -66,7 +66,7 @@ struct ReadReceiptCell_Previews: PreviewProvider, TestablePreview {
ReadReceiptCell(readReceipt: .init(userID: "@test:matrix.org", ReadReceiptCell(readReceipt: .init(userID: "@test:matrix.org",
formattedTimestamp: "10:00"), formattedTimestamp: "10:00"),
memberState: .init(displayName: "Test", memberState: .init(displayName: "Test",
avatarURL: URL.documentsDirectory), avatarURL: .mockMXCAvatar),
mediaProvider: MediaProviderMock(configuration: .init())) mediaProvider: MediaProviderMock(configuration: .init()))
.previewDisplayName("With Image") .previewDisplayName("With Image")
ReadReceiptCell(readReceipt: .init(userID: "@test:matrix.org", ReadReceiptCell(readReceipt: .init(userID: "@test:matrix.org",
@@ -22,7 +22,7 @@ private enum InternalAudioPlayerState {
} }
class AudioPlayer: NSObject, AudioPlayerProtocol { class AudioPlayer: NSObject, AudioPlayerProtocol {
var mediaSource: MediaSourceProxy? var sourceURL: URL?
private var playerItem: AVPlayerItem? private var playerItem: AVPlayerItem?
private var internalAudioPlayer: AVQueuePlayer? private var internalAudioPlayer: AVQueuePlayer?
@@ -46,7 +46,7 @@ class AudioPlayer: NSObject, AudioPlayerProtocol {
private let releaseAudioSessionTimeoutInterval = 5.0 private let releaseAudioSessionTimeoutInterval = 5.0
private(set) var url: URL? private(set) var playbackURL: URL?
private var deinitInProgress = false private var deinitInProgress = false
@@ -86,13 +86,13 @@ class AudioPlayer: NSObject, AudioPlayerProtocol {
unloadContent() unloadContent()
} }
func load(mediaSource: MediaSourceProxy, using url: URL, autoplay: Bool) { func load(sourceURL: URL, playbackURL: URL, autoplay: Bool) {
unloadContent() unloadContent()
setInternalState(.loading) setInternalState(.loading)
self.mediaSource = mediaSource self.sourceURL = sourceURL
self.url = url self.playbackURL = playbackURL
self.autoplay = autoplay self.autoplay = autoplay
playerItem = AVPlayerItem(url: url) playerItem = AVPlayerItem(url: playbackURL)
internalAudioPlayer = AVQueuePlayer(playerItem: playerItem) internalAudioPlayer = AVQueuePlayer(playerItem: playerItem)
addObservers() addObservers()
} }
@@ -162,8 +162,8 @@ class AudioPlayer: NSObject, AudioPlayerProtocol {
} }
private func unloadContent() { private func unloadContent() {
mediaSource = nil sourceURL = nil
url = nil playbackURL = nil
internalAudioPlayer?.replaceCurrentItem(with: nil) internalAudioPlayer?.replaceCurrentItem(with: nil)
internalAudioPlayer = nil internalAudioPlayer = nil
playerItem = nil playerItem = nil
@@ -12,6 +12,17 @@ enum AudioPlayerError: Error {
case genericError case genericError
} }
// There used to be a MediaPlayerProtocol that AudioPlayerProtocol inherited from.
// This should be called something else but we already have an AudioPlayerState,
// AudioPlayerPlaybackState and InternalAudioPlayerState so who knows what to call this.
enum MediaPlayerState {
case loading
case playing
case paused
case stopped
case error
}
enum AudioPlayerAction { enum AudioPlayerAction {
case didStartLoading case didStartLoading
case didFinishLoading case didFinishLoading
@@ -22,8 +33,21 @@ enum AudioPlayerAction {
case didFailWithError(error: Error) case didFailWithError(error: Error)
} }
protocol AudioPlayerProtocol: MediaPlayerProtocol { protocol AudioPlayerProtocol: AnyObject {
var sourceURL: URL? { get }
var duration: TimeInterval { get }
var currentTime: TimeInterval { get }
var playbackURL: URL? { get }
var state: MediaPlayerState { get }
var actions: AnyPublisher<AudioPlayerAction, Never> { get } var actions: AnyPublisher<AudioPlayerAction, Never> { get }
func load(sourceURL: URL, playbackURL: URL, autoplay: Bool)
func reset()
func play()
func pause()
func stop()
func seek(to progress: Double) async
} }
// sourcery: AutoMockable // sourcery: AutoMockable
@@ -134,7 +134,7 @@ class AudioPlayerState: ObservableObject, Identifiable {
MXLog.info("updating duration: \(duration) -> \(audioPlayerDuration)") MXLog.info("updating duration: \(duration) -> \(audioPlayerDuration)")
duration = audioPlayerDuration duration = audioPlayerDuration
} }
fileURL = audioPlayer?.url fileURL = audioPlayer?.playbackURL
playbackState = .readyToPlay playbackState = .readyToPlay
case .didStartPlaying: case .didStartPlaying:
if let audioPlayer { if let audioPlayer {
@@ -68,7 +68,7 @@ struct RoomPreviewDetails {
let topic: String? let topic: String?
let avatarURL: URL? let avatarURL: URL?
let memberCount: UInt let memberCount: UInt
let isHistoryWorldReadable: Bool let isHistoryWorldReadable: Bool?
let isJoined: Bool let isJoined: Bool
let isInvited: Bool let isInvited: Bool
let isPublic: Bool let isPublic: Bool
@@ -24,7 +24,10 @@ struct MediaSourceProxy: Hashable {
} }
init(url: URL, mimeType: String?) { init(url: URL, mimeType: String?) {
underlyingSource = mediaSourceFromUrl(url: url.absoluteString) guard let mediaSource = try? MediaSource.fromUrl(url: url.absoluteString) else {
fatalError("Unable to create MediaSource from URL: \(url.absoluteString)")
}
underlyingSource = mediaSource
self.url = URL(string: underlyingSource.url()) self.url = URL(string: underlyingSource.url())
self.mimeType = mimeType self.mimeType = mimeType
} }
@@ -1,34 +0,0 @@
//
// Copyright 2023, 2024 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only
// Please see LICENSE in the repository root for full details.
//
import Foundation
enum MediaPlayerState {
case loading
case playing
case paused
case stopped
case error
}
protocol MediaPlayerProtocol: AnyObject {
var mediaSource: MediaSourceProxy? { get }
var duration: TimeInterval { get }
var currentTime: TimeInterval { get }
var url: URL? { get }
var state: MediaPlayerState { get }
func load(mediaSource: MediaSourceProxy, using url: URL, autoplay: Bool)
func reset()
func play()
func pause()
func stop()
func seek(to progress: Double) async
}
// sourcery: AutoMockable
extension MediaPlayerProtocol { }
@@ -11,24 +11,12 @@ class MediaPlayerProvider: MediaPlayerProviderProtocol {
private lazy var audioPlayer = AudioPlayer() private lazy var audioPlayer = AudioPlayer()
private var audioPlayerStates: [String: AudioPlayerState] = [:] private var audioPlayerStates: [String: AudioPlayerState] = [:]
var player: AudioPlayerProtocol { audioPlayer }
deinit { deinit {
audioPlayerStates = [:] audioPlayerStates = [:]
} }
func player(for mediaSource: MediaSourceProxy) -> Result<MediaPlayerProtocol, MediaPlayerProviderError> {
guard let mimeType = mediaSource.mimeType else {
MXLog.error("Unknown mime type")
return .failure(.unsupportedMediaType)
}
if mimeType.starts(with: "audio/") {
return .success(audioPlayer)
} else {
MXLog.error("Unsupported media type: \(mediaSource.mimeType ?? "unknown")")
return .failure(.unsupportedMediaType)
}
}
// MARK: - AudioPlayer // MARK: - AudioPlayer
func playerState(for id: AudioPlayerStateIdentifier) -> AudioPlayerState? { func playerState(for id: AudioPlayerStateIdentifier) -> AudioPlayerState? {
@@ -13,7 +13,7 @@ enum MediaPlayerProviderError: Error {
@MainActor @MainActor
protocol MediaPlayerProviderProtocol { protocol MediaPlayerProviderProtocol {
func player(for mediaSource: MediaSourceProxy) -> Result<MediaPlayerProtocol, MediaPlayerProviderError> var player: AudioPlayerProtocol { get }
func playerState(for id: AudioPlayerStateIdentifier) -> AudioPlayerState? func playerState(for id: AudioPlayerStateIdentifier) -> AudioPlayerState?
func register(audioPlayerState: AudioPlayerState) func register(audioPlayerState: AudioPlayerState)
@@ -243,7 +243,7 @@ struct VideoInfoProxy: Hashable {
} }
static var mockVideo: VideoInfoProxy { static var mockVideo: VideoInfoProxy {
.init(source: .init(url: .picturesDirectory, mimeType: nil), .init(source: .init(url: .mockMXCVideo, mimeType: nil),
duration: 100, duration: 100,
size: .init(width: 1920, height: 1080), size: .init(width: 1920, height: 1080),
aspectRatio: 1.78, aspectRatio: 1.78,
@@ -292,14 +292,14 @@ struct ImageInfoProxy: Hashable {
} }
static var mockImage: ImageInfoProxy { static var mockImage: ImageInfoProxy {
.init(source: .init(url: .picturesDirectory, mimeType: "image/png"), .init(source: .init(url: .mockMXCImage, mimeType: "image/png"),
size: .init(width: 100, height: 100), size: .init(width: 100, height: 100),
aspectRatio: 1, aspectRatio: 1,
mimeType: "image/png") mimeType: "image/png")
} }
static var mockThumbnail: ImageInfoProxy { static var mockThumbnail: ImageInfoProxy {
.init(source: .init(url: .picturesDirectory, mimeType: nil), .init(source: .init(url: .mockMXCImage, mimeType: nil),
size: nil, size: nil,
aspectRatio: nil, aspectRatio: nil,
mimeType: nil) mimeType: nil)
@@ -101,13 +101,12 @@ class VoiceMessageRecorder: VoiceMessageRecorderProtocol {
await previewAudioPlayerState.attachAudioPlayer(audioPlayer) await previewAudioPlayerState.attachAudioPlayer(audioPlayer)
} }
if audioPlayer.url == url { if audioPlayer.playbackURL == url {
audioPlayer.play() audioPlayer.play()
return .success(()) return .success(())
} }
let pendingMediaSource = MediaSourceProxy(url: url, mimeType: mp4accMimeType) audioPlayer.load(sourceURL: url, playbackURL: url, autoplay: true)
audioPlayer.load(mediaSource: pendingMediaSource, using: url, autoplay: true)
return .success(()) return .success(())
} }
@@ -242,10 +241,7 @@ class VoiceMessageRecorder: VoiceMessageRecorderProtocol {
previewAudioPlayerState = await AudioPlayerState(id: .recorderPreview, title: L10n.commonVoiceMessage, duration: recordingDuration, waveform: EstimatedWaveform(data: [])) previewAudioPlayerState = await AudioPlayerState(id: .recorderPreview, title: L10n.commonVoiceMessage, duration: recordingDuration, waveform: EstimatedWaveform(data: []))
// Build the preview audio player // Build the preview audio player
let mediaSource = MediaSourceProxy(url: url, mimeType: mp4accMimeType) let audioPlayer = await mediaPlayerProvider.player
guard case .success(let mediaPlayer) = await mediaPlayerProvider.player(for: mediaSource), let audioPlayer = mediaPlayer as? AudioPlayerProtocol else {
return .failure(.previewNotAvailable)
}
previewAudioPlayer = audioPlayer previewAudioPlayer = audioPlayer
return .success(()) return .success(())
@@ -253,7 +253,7 @@ class MockScreen: Identifiable {
let timelineController = MockRoomTimelineController() let timelineController = MockRoomTimelineController()
timelineController.timelineItems = RoomTimelineItemFixtures.smallChunk timelineController.timelineItems = RoomTimelineItemFixtures.smallChunk
let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(), let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(),
roomProxy: JoinedRoomProxyMock(.init(name: "New room", avatarURL: URL.picturesDirectory)), roomProxy: JoinedRoomProxyMock(.init(name: "New room", avatarURL: .mockMXCAvatar)),
timelineController: timelineController, timelineController: timelineController,
mediaProvider: MediaProviderMock(configuration: .init()), mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -272,7 +272,7 @@ class MockScreen: Identifiable {
let timelineController = MockRoomTimelineController() let timelineController = MockRoomTimelineController()
timelineController.timelineItems = RoomTimelineItemFixtures.default timelineController.timelineItems = RoomTimelineItemFixtures.default
let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(), let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(),
roomProxy: JoinedRoomProxyMock(.init(name: "New room", avatarURL: URL.picturesDirectory)), roomProxy: JoinedRoomProxyMock(.init(name: "New room", avatarURL: .mockMXCAvatar)),
timelineController: timelineController, timelineController: timelineController,
mediaProvider: MediaProviderMock(configuration: .init()), mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -291,7 +291,7 @@ class MockScreen: Identifiable {
let timelineController = MockRoomTimelineController() let timelineController = MockRoomTimelineController()
timelineController.timelineItems = RoomTimelineItemFixtures.smallChunkWithReadReceipts timelineController.timelineItems = RoomTimelineItemFixtures.smallChunkWithReadReceipts
let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(), let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(),
roomProxy: JoinedRoomProxyMock(.init(name: "New room", avatarURL: URL.picturesDirectory)), roomProxy: JoinedRoomProxyMock(.init(name: "New room", avatarURL: .mockMXCAvatar)),
timelineController: timelineController, timelineController: timelineController,
mediaProvider: MediaProviderMock(configuration: .init()), mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -313,7 +313,7 @@ class MockScreen: Identifiable {
timelineController.backPaginationResponses = [RoomTimelineItemFixtures.singleMessageChunk] timelineController.backPaginationResponses = [RoomTimelineItemFixtures.singleMessageChunk]
timelineController.incomingItems = [RoomTimelineItemFixtures.incomingMessage] timelineController.incomingItems = [RoomTimelineItemFixtures.incomingMessage]
let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(), let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(),
roomProxy: JoinedRoomProxyMock(.init(name: "Small timeline", avatarURL: URL.picturesDirectory)), roomProxy: JoinedRoomProxyMock(.init(name: "Small timeline", avatarURL: .mockMXCAvatar)),
timelineController: timelineController, timelineController: timelineController,
mediaProvider: MediaProviderMock(configuration: .init()), mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -335,7 +335,7 @@ class MockScreen: Identifiable {
timelineController.timelineItems = RoomTimelineItemFixtures.smallChunk timelineController.timelineItems = RoomTimelineItemFixtures.smallChunk
timelineController.backPaginationResponses = [RoomTimelineItemFixtures.largeChunk] timelineController.backPaginationResponses = [RoomTimelineItemFixtures.largeChunk]
let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(), let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(),
roomProxy: JoinedRoomProxyMock(.init(name: "Small timeline, paginating", avatarURL: URL.picturesDirectory)), roomProxy: JoinedRoomProxyMock(.init(name: "Small timeline, paginating", avatarURL: .mockMXCAvatar)),
timelineController: timelineController, timelineController: timelineController,
mediaProvider: MediaProviderMock(configuration: .init()), mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -357,7 +357,7 @@ class MockScreen: Identifiable {
timelineController.timelineItems = RoomTimelineItemFixtures.largeChunk timelineController.timelineItems = RoomTimelineItemFixtures.largeChunk
timelineController.backPaginationResponses = [RoomTimelineItemFixtures.largeChunk] timelineController.backPaginationResponses = [RoomTimelineItemFixtures.largeChunk]
let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(), let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(),
roomProxy: JoinedRoomProxyMock(.init(name: "Large timeline", avatarURL: URL.picturesDirectory)), roomProxy: JoinedRoomProxyMock(.init(name: "Large timeline", avatarURL: .mockMXCAvatar)),
timelineController: timelineController, timelineController: timelineController,
mediaProvider: MediaProviderMock(configuration: .init()), mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -380,7 +380,7 @@ class MockScreen: Identifiable {
timelineController.backPaginationResponses = [RoomTimelineItemFixtures.largeChunk] timelineController.backPaginationResponses = [RoomTimelineItemFixtures.largeChunk]
timelineController.incomingItems = [RoomTimelineItemFixtures.incomingMessage] timelineController.incomingItems = [RoomTimelineItemFixtures.incomingMessage]
let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(), let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(),
roomProxy: JoinedRoomProxyMock(.init(name: "Large timeline", avatarURL: URL.picturesDirectory)), roomProxy: JoinedRoomProxyMock(.init(name: "Large timeline", avatarURL: .mockMXCAvatar)),
timelineController: timelineController, timelineController: timelineController,
mediaProvider: MediaProviderMock(configuration: .init()), mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -402,7 +402,7 @@ class MockScreen: Identifiable {
timelineController.timelineItems = RoomTimelineItemFixtures.largeChunk timelineController.timelineItems = RoomTimelineItemFixtures.largeChunk
timelineController.incomingItems = [RoomTimelineItemFixtures.incomingMessage] timelineController.incomingItems = [RoomTimelineItemFixtures.incomingMessage]
let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(), let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(),
roomProxy: JoinedRoomProxyMock(.init(name: "Large timeline", avatarURL: URL.picturesDirectory)), roomProxy: JoinedRoomProxyMock(.init(name: "Large timeline", avatarURL: .mockMXCAvatar)),
timelineController: timelineController, timelineController: timelineController,
mediaProvider: MediaProviderMock(configuration: .init()), mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -423,7 +423,7 @@ class MockScreen: Identifiable {
let timelineController = MockRoomTimelineController() let timelineController = MockRoomTimelineController()
timelineController.timelineItems = RoomTimelineItemFixtures.permalinkChunk timelineController.timelineItems = RoomTimelineItemFixtures.permalinkChunk
let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(), let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(),
roomProxy: JoinedRoomProxyMock(.init(name: "Timeline highlight", avatarURL: URL.picturesDirectory)), roomProxy: JoinedRoomProxyMock(.init(name: "Timeline highlight", avatarURL: .mockMXCAvatar)),
timelineController: timelineController, timelineController: timelineController,
mediaProvider: MediaProviderMock(configuration: .init()), mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -458,7 +458,7 @@ class MockScreen: Identifiable {
timelineController.timelineItems = RoomTimelineItemFixtures.disclosedPolls timelineController.timelineItems = RoomTimelineItemFixtures.disclosedPolls
timelineController.incomingItems = [] timelineController.incomingItems = []
let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(), let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(),
roomProxy: JoinedRoomProxyMock(.init(name: "Polls timeline", avatarURL: URL.picturesDirectory)), roomProxy: JoinedRoomProxyMock(.init(name: "Polls timeline", avatarURL: .mockMXCAvatar)),
timelineController: timelineController, timelineController: timelineController,
mediaProvider: MediaProviderMock(configuration: .init()), mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -480,7 +480,7 @@ class MockScreen: Identifiable {
timelineController.timelineItems = RoomTimelineItemFixtures.undisclosedPolls timelineController.timelineItems = RoomTimelineItemFixtures.undisclosedPolls
timelineController.incomingItems = [] timelineController.incomingItems = []
let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(), let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(),
roomProxy: JoinedRoomProxyMock(.init(name: "Polls timeline", avatarURL: URL.picturesDirectory)), roomProxy: JoinedRoomProxyMock(.init(name: "Polls timeline", avatarURL: .mockMXCAvatar)),
timelineController: timelineController, timelineController: timelineController,
mediaProvider: MediaProviderMock(configuration: .init()), mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -502,7 +502,7 @@ class MockScreen: Identifiable {
timelineController.timelineItems = RoomTimelineItemFixtures.outgoingPolls timelineController.timelineItems = RoomTimelineItemFixtures.outgoingPolls
timelineController.incomingItems = [] timelineController.incomingItems = []
let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(), let parameters = RoomScreenCoordinatorParameters(clientProxy: ClientProxyMock(),
roomProxy: JoinedRoomProxyMock(.init(name: "Polls timeline", avatarURL: URL.picturesDirectory)), roomProxy: JoinedRoomProxyMock(.init(name: "Polls timeline", avatarURL: .mockMXCAvatar)),
timelineController: timelineController, timelineController: timelineController,
mediaProvider: MediaProviderMock(configuration: .init()), mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:4dcc4ffc59ec9fc2f68bdce87a7f3d7bff27b1a2f7113df0669d1170e7a68045 oid sha256:f6e63d693948eb3139609c45c2511a6db5213ba6d312082deba2dcca31bb836d
size 88606 size 92248
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:4dcc4ffc59ec9fc2f68bdce87a7f3d7bff27b1a2f7113df0669d1170e7a68045 oid sha256:f6e63d693948eb3139609c45c2511a6db5213ba6d312082deba2dcca31bb836d
size 88606 size 92248
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:aceb415158105cb684244cc5d468ac24915aa4a2c1e0f03e4b95915dea604f44 oid sha256:141cf3859c4b421be24e2409abc2d6bb4b53ff3c9878811cdbb6b67c901251a7
size 46009 size 49837
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:aceb415158105cb684244cc5d468ac24915aa4a2c1e0f03e4b95915dea604f44 oid sha256:141cf3859c4b421be24e2409abc2d6bb4b53ff3c9878811cdbb6b67c901251a7
size 46009 size 49837
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:1b8ef13343f827c0dc3e9aaf74ce28f8a3e96bb0f4b9aa457e6a9ff40b3ad632 oid sha256:ad795840c41305dbe8028cfea18b8fe25d3be2ab9524bc3322ed77726df25bcb
size 98059 size 101810
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:516b16553d506445d965c708a5f56e5b9c53b23488809a2513a56c2368a2d633 oid sha256:70452fc6801a7a7778992bc40ef49c929744d76f0285e2f1aec33c09a5ae3242
size 98477 size 102228
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:b4bc7dbfbb1c7c58641f7d19bcb648e792220c19919b9001b09bdc8ccda0c86f oid sha256:26b773b1dd1468c8298fc18062e9cc8749698536c19ca643acb1551f9293fb91
size 53599 size 57194
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:fd4bca95fba0ed2e11a1212c1ac3d1a638815274c370a1bdb4a3dd825c89de6d oid sha256:6a952ed17097a7d8d6b16d3a330e1eaf3fdea80dac026618d456b561ff10c39a
size 54013 size 57608
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:d5b3a8bd64746aad774b15fc3e3500bbab4144d64ed4f8714f9b2527c70a494c oid sha256:8927edf5a98a3beae9d1dd2a61985b5402b72ab5688a2960a8c65b726b28e7a8
size 1990774 size 2016923
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:b6be25a2a046c3d1088ae6f87e4e1e0033062225c624095d679f1083ffe538b6 oid sha256:c9390f013722ba23d3b9ade888bc484e7b276e223f135d6641371d60da690397
size 1945746 size 1971897
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:46447c25230d95f04d122924d938f6f4b5eacd633140e586c3c276322f8e8b75 oid sha256:2347df221ddac84740cf5436620bb07bf3e7f24aea85e6dceec11f8d374a66d0
size 1791354 size 1817511
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:e0070dcdfe989211600c14fdb7b96af79cfb2b50ae8c3d560f7fe738b368be48 oid sha256:630995e1d62ff737c63bda878adec6756c0baa5a0136fb898f9cbf07ef52aa43
size 1982637 size 1987392
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:41f91af2b20ff571cdf281d4dedaf1f6749a8fdaf33508a1b70511ef6e477af4 oid sha256:177f9b216f7716c511037ad044d08c499bc1d33b576d46dbda7d6c67bb513f1e
size 1995837 size 2022040
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:daf1b08dbe20c63aa66d1c16e3bc41fdc92a54ad4f143ccfcd9ca8382964a0fe oid sha256:a13076406c868e7b86d89782752c1fe70776151623c18d6fe47e59671120e0d7
size 1946727 size 1972878
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:08e0296e33a657e0c42f95cb2e4963cb8f32c3a37979262cd76bc4c3ac3a7132 oid sha256:69ad1bad58cd73c5626fdf52923f6a0955221f5673b4485c131048d64b215c84
size 1799819 size 1825976
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:8283d5d60db3b91caa096216e4dbb1d5e5342375080c81e5814acbb01b41c8c9 oid sha256:a81a307b980a5e1d950c98d2fe2981d0cf138da722d76007dd2f61693d85c208
size 2000079 size 2004686
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:616a8a5fe92ef87797d9a69bd5d7581e685edad21b002bf079d1a02fdb782987 oid sha256:329b0b5fd32c1e395f969a006d2b56d399292abdee46d6e15df89bf3a8005d89
size 827638 size 851720
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:6d7390ef83a9fb7e8887aff95c03282d4fbcf3826cf3e254d523373a2c434df0 oid sha256:9f6a60932fcba3f2bcd0127af134fd7005cc74a3ba02bfa1717466c35e92ad8c
size 798961 size 823057
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:3f9518a386e4c12c9e1527eb5f841fb0ca56fc8658529b58d6d459376caca39b oid sha256:438018482d1792510fd3d07df8f9ba72ca7ddf3f1e69d7ab0b0adcdbe7a8b0f8
size 705027 size 729066
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:19d3b48e373ed4e263c9cb0f6e5a3566a9c6612f19da8468be420eca0a10cd92 oid sha256:72ccc0e3a37d2f8728fc59240b0a11099594e8576a4d89b2ad462ba422a2d38f
size 819795 size 824019
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:6ecca9bbfa7a1d245a96fc27aacfb5d60931ba1437639ebd8e9ff1756bd705c6 oid sha256:2fb7e4c00fd1d30189f80d8abcf05dd3048039ce61a387f98691bfb618c9218e
size 835366 size 859617
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:450d28a2af4b81f2db2e8a1fb28405d029439cabf5f48688b448391dd7e43b05 oid sha256:bd08e040f1aff5e3ca2b50965a2bb368557134e8e3bc5bd6e390a1b4a328ae67
size 800675 size 824771
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:858759589a323ce04e894f398c230c0454f64a3c3148b183f9ecdbeb29955b89 oid sha256:03f9fedddcc22df3d14c21cb5314cdd8fdf17592032f57bb762b7c1fe1bbf5ca
size 714177 size 738216
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:eb3a1c2ac88a74a4f9c402a46a8512abc2596937b92c3d17fa30a7cdf10ce22a oid sha256:d9482f0f3428f1826ef0e5d7e83d65aa895fc88c8db8a756c8c93c2767300f99
size 835796 size 840024
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:189a2f7d717020e1fdc38c758446fe00ecc6279fc29295df48fee6b11e2c0e45 oid sha256:d00776a5033ba2bf44c909bd5c41a422ba3f8675bab60cee885788440f38a34a
size 72244 size 76078
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:189a2f7d717020e1fdc38c758446fe00ecc6279fc29295df48fee6b11e2c0e45 oid sha256:d00776a5033ba2bf44c909bd5c41a422ba3f8675bab60cee885788440f38a34a
size 72244 size 76078
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:a707341b7229847083f074c637678863b24e8bab3da2be830313c33236e1006d oid sha256:87252ee182a5c1c0c8827b9fbb4679fcac0ad6829d92702f37a94d42ff069e91
size 31580 size 35403
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:a707341b7229847083f074c637678863b24e8bab3da2be830313c33236e1006d oid sha256:87252ee182a5c1c0c8827b9fbb4679fcac0ad6829d92702f37a94d42ff069e91
size 31580 size 35403
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:290f71a4d1e5bab703e3a4483acdbd3605ff9df65c18bbfdc7cca3297e516584 oid sha256:7b6f71e4c5caef9d16e44bb90c0e2051db32467c190479271e9e9f50f249bad4
size 76118 size 79950
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:290f71a4d1e5bab703e3a4483acdbd3605ff9df65c18bbfdc7cca3297e516584 oid sha256:7b6f71e4c5caef9d16e44bb90c0e2051db32467c190479271e9e9f50f249bad4
size 76118 size 79950
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:da24b677846f3088c15a2dc4a6d3de517bf499ce62bc0ad58586912179019286 oid sha256:951bde2a3cc7a130218d8123e8d91469efdd14f66ff251154f0b803d9e378ffb
size 35184 size 39094
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:da24b677846f3088c15a2dc4a6d3de517bf499ce62bc0ad58586912179019286 oid sha256:951bde2a3cc7a130218d8123e8d91469efdd14f66ff251154f0b803d9e378ffb
size 35184 size 39094
@@ -91,7 +91,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
func testSuggestions() { func testSuggestions() {
let suggestions: [SuggestionItem] = [.user(item: MentionSuggestionItem(id: "@user_mention_1:matrix.org", displayName: "User 1", avatarURL: nil, range: .init())), let suggestions: [SuggestionItem] = [.user(item: MentionSuggestionItem(id: "@user_mention_1:matrix.org", displayName: "User 1", avatarURL: nil, range: .init())),
.user(item: MentionSuggestionItem(id: "@user_mention_2:matrix.org", displayName: "User 2", avatarURL: URL.documentsDirectory, range: .init()))] .user(item: MentionSuggestionItem(id: "@user_mention_2:matrix.org", displayName: "User 2", avatarURL: .mockMXCAvatar, range: .init()))]
let mockCompletionSuggestionService = CompletionSuggestionServiceMock(configuration: .init(suggestions: suggestions)) let mockCompletionSuggestionService = CompletionSuggestionServiceMock(configuration: .init(suggestions: suggestions))
viewModel = ComposerToolbarViewModel(wysiwygViewModel: wysiwygViewModel, viewModel = ComposerToolbarViewModel(wysiwygViewModel: wysiwygViewModel,
completionSuggestionService: mockCompletionSuggestionService, completionSuggestionService: mockCompletionSuggestionService,
@@ -15,50 +15,13 @@ class MediaPlayerProviderTests: XCTestCase {
private var mediaPlayerProvider: MediaPlayerProvider! private var mediaPlayerProvider: MediaPlayerProvider!
private let oggMimeType = "audio/ogg" private let oggMimeType = "audio/ogg"
private let someURL = URL("/some/url") private let someURL = URL.mockMXCAudio
private let someOtherURL = URL("/some/other/url") private let someOtherURL = URL.mockMXCFile
override func setUp() async throws { override func setUp() async throws {
mediaPlayerProvider = MediaPlayerProvider() mediaPlayerProvider = MediaPlayerProvider()
} }
func testPlayerForWrongMediaType() async throws {
let mediaSourceWithoutMimeType = MediaSourceProxy(url: someURL, mimeType: nil)
switch mediaPlayerProvider.player(for: mediaSourceWithoutMimeType) {
case .failure(.unsupportedMediaType):
// Ok
break
default:
XCTFail("An error is expected")
}
let mediaSourceVideo = MediaSourceProxy(url: someURL, mimeType: "video/mp4")
switch mediaPlayerProvider.player(for: mediaSourceVideo) {
case .failure(.unsupportedMediaType):
// Ok
break
default:
XCTFail("An error is expected")
}
}
func testPlayerFor() async throws {
let mediaSource = MediaSourceProxy(url: someURL, mimeType: oggMimeType)
guard case .success(let playerA) = mediaPlayerProvider.player(for: mediaSource) else {
XCTFail("A valid player is expected")
return
}
// calling it again with another mediasource must returns the same player
let otherMediaSource = MediaSourceProxy(url: someOtherURL, mimeType: oggMimeType)
guard case .success(let playerB) = mediaPlayerProvider.player(for: otherMediaSource) else {
XCTFail("A valid player is expected")
return
}
XCTAssert(playerA === playerB)
}
func testPlayerStates() async throws { func testPlayerStates() async throws {
let audioPlayerStateId = AudioPlayerStateIdentifier.timelineItemIdentifier(.randomEvent) let audioPlayerStateId = AudioPlayerStateIdentifier.timelineItemIdentifier(.randomEvent)
// By default, there should be no player state // By default, there should be no player state
@@ -15,7 +15,7 @@ final class MediaLoaderTests: XCTestCase {
mediaLoadingClient.getMediaContentMediaSourceReturnValue = Data() mediaLoadingClient.getMediaContentMediaSourceReturnValue = Data()
let mediaLoader = MediaLoader(client: mediaLoadingClient) let mediaLoader = MediaLoader(client: mediaLoadingClient)
let mediaSource = MediaSourceProxy(url: URL.documentsDirectory, mimeType: nil) let mediaSource = MediaSourceProxy(url: .mockMXCFile, mimeType: nil)
do { do {
for _ in 1...10 { for _ in 1...10 {
@@ -33,7 +33,7 @@ final class MediaLoaderTests: XCTestCase {
mediaLoadingClient.getMediaThumbnailMediaSourceWidthHeightReturnValue = Data() mediaLoadingClient.getMediaThumbnailMediaSourceWidthHeightReturnValue = Data()
let mediaLoader = MediaLoader(client: mediaLoadingClient) let mediaLoader = MediaLoader(client: mediaLoadingClient)
let mediaSource = MediaSourceProxy(url: URL.documentsDirectory, mimeType: nil) let mediaSource = MediaSourceProxy(url: .mockMXCImage, mimeType: nil)
do { do {
for _ in 1...10 { for _ in 1...10 {
@@ -36,7 +36,7 @@ final class MediaProviderTests: XCTestCase {
return return
} }
let loadTask = mediaProvider.loadImageRetryingOnReconnection(MediaSourceProxy(url: URL.picturesDirectory, mimeType: "image/jpeg")) let loadTask = mediaProvider.loadImageRetryingOnReconnection(MediaSourceProxy(url: .mockMXCImage, mimeType: "image/jpeg"))
let connectivitySubject = CurrentValueSubject<NetworkMonitorReachability, Never>(.unreachable) let connectivitySubject = CurrentValueSubject<NetworkMonitorReachability, Never>(.unreachable)
@@ -59,7 +59,7 @@ final class MediaProviderTests: XCTestCase {
} }
func testLoadingRetriedOnReconnectionCancelsAfterSecondFailure() async throws { func testLoadingRetriedOnReconnectionCancelsAfterSecondFailure() async throws {
let loadTask = mediaProvider.loadImageRetryingOnReconnection(MediaSourceProxy(url: URL.picturesDirectory, mimeType: "image/jpeg")) let loadTask = mediaProvider.loadImageRetryingOnReconnection(MediaSourceProxy(url: .mockMXCImage, mimeType: "image/jpeg"))
let connectivitySubject = CurrentValueSubject<NetworkMonitorReachability, Never>(.reachable) let connectivitySubject = CurrentValueSubject<NetworkMonitorReachability, Never>(.reachable)
@@ -79,7 +79,7 @@ final class MediaProviderTests: XCTestCase {
func test_whenImageFromSourceWithSourceNotNilAndImageCacheContainsImage_ImageIsReturned() throws { func test_whenImageFromSourceWithSourceNotNilAndImageCacheContainsImage_ImageIsReturned() throws {
let avatarSize = Avatars.Size.room(on: .timeline) let avatarSize = Avatars.Size.room(on: .timeline)
let url = URL.picturesDirectory let url = URL.mockMXCImage
let key = "\(url.absoluteString){\(avatarSize.scaledValue),\(avatarSize.scaledValue)}" let key = "\(url.absoluteString){\(avatarSize.scaledValue),\(avatarSize.scaledValue)}"
let imageForKey = UIImage() let imageForKey = UIImage()
imageCache.retrievedImagesInMemory[key] = imageForKey imageCache.retrievedImagesInMemory[key] = imageForKey
@@ -89,14 +89,14 @@ final class MediaProviderTests: XCTestCase {
} }
func test_whenImageFromSourceWithSourceNotNilAndImageNotCached_nilReturned() throws { func test_whenImageFromSourceWithSourceNotNilAndImageNotCached_nilReturned() throws {
let image = mediaProvider.imageFromSource(MediaSourceProxy(url: URL.picturesDirectory, mimeType: "image/jpeg"), let image = mediaProvider.imageFromSource(MediaSourceProxy(url: .mockMXCImage, mimeType: "image/jpeg"),
size: Avatars.Size.room(on: .timeline).scaledSize) size: Avatars.Size.room(on: .timeline).scaledSize)
XCTAssertNil(image) XCTAssertNil(image)
} }
func test_whenLoadImageFromSourceAndImageCacheContainsImage_successIsReturned() async throws { func test_whenLoadImageFromSourceAndImageCacheContainsImage_successIsReturned() async throws {
let avatarSize = Avatars.Size.room(on: .timeline) let avatarSize = Avatars.Size.room(on: .timeline)
let url = URL.picturesDirectory let url = URL.mockMXCImage
let key = "\(url.absoluteString){\(avatarSize.scaledValue),\(avatarSize.scaledValue)}" let key = "\(url.absoluteString){\(avatarSize.scaledValue),\(avatarSize.scaledValue)}"
let imageForKey = UIImage() let imageForKey = UIImage()
imageCache.retrievedImagesInMemory[key] = imageForKey imageCache.retrievedImagesInMemory[key] = imageForKey
@@ -107,7 +107,7 @@ final class MediaProviderTests: XCTestCase {
func test_whenLoadImageFromSourceAndImageNotCachedAndRetrieveImageSucceeds_successIsReturned() async throws { func test_whenLoadImageFromSourceAndImageNotCachedAndRetrieveImageSucceeds_successIsReturned() async throws {
let avatarSize = Avatars.Size.room(on: .timeline) let avatarSize = Avatars.Size.room(on: .timeline)
let url = URL.picturesDirectory let url = URL.mockMXCImage
let key = "\(url.absoluteString){\(avatarSize.scaledValue),\(avatarSize.scaledValue)}" let key = "\(url.absoluteString){\(avatarSize.scaledValue),\(avatarSize.scaledValue)}"
let imageForKey = UIImage() let imageForKey = UIImage()
imageCache.retrievedImages[key] = imageForKey imageCache.retrievedImages[key] = imageForKey
@@ -122,7 +122,7 @@ final class MediaProviderTests: XCTestCase {
mediaLoader.loadMediaThumbnailForSourceWidthHeightReturnValue = expectedImage.pngData() mediaLoader.loadMediaThumbnailForSourceWidthHeightReturnValue = expectedImage.pngData()
let result = await mediaProvider.loadImageFromSource(MediaSourceProxy(url: URL.picturesDirectory, mimeType: "image/jpeg"), let result = await mediaProvider.loadImageFromSource(MediaSourceProxy(url: .mockMXCImage, mimeType: "image/jpeg"),
size: avatarSize.scaledSize) size: avatarSize.scaledSize)
switch result { switch result {
case .success(let image): case .success(let image):
@@ -134,7 +134,7 @@ final class MediaProviderTests: XCTestCase {
func test_whenLoadImageFromSourceAndImageNotCachedAndRetrieveImageFails_imageIsStored() async throws { func test_whenLoadImageFromSourceAndImageNotCachedAndRetrieveImageFails_imageIsStored() async throws {
let avatarSize = Avatars.Size.room(on: .timeline) let avatarSize = Avatars.Size.room(on: .timeline)
let url = URL.picturesDirectory let url = URL.mockMXCImage
let key = "\(url.absoluteString){\(avatarSize.scaledValue),\(avatarSize.scaledValue)}" let key = "\(url.absoluteString){\(avatarSize.scaledValue),\(avatarSize.scaledValue)}"
let expectedImage = try loadTestImage() let expectedImage = try loadTestImage()
@@ -151,7 +151,7 @@ final class MediaProviderTests: XCTestCase {
mediaLoader.loadMediaContentForSourceReturnValue = expectedImage.pngData() mediaLoader.loadMediaContentForSourceReturnValue = expectedImage.pngData()
let result = await mediaProvider.loadImageFromSource(MediaSourceProxy(url: URL.picturesDirectory, mimeType: "image/jpeg"), let result = await mediaProvider.loadImageFromSource(MediaSourceProxy(url: .mockMXCImage, mimeType: "image/jpeg"),
size: nil) size: nil)
switch result { switch result {
case .success(let image): case .success(let image):
@@ -164,7 +164,7 @@ final class MediaProviderTests: XCTestCase {
func test_whenLoadImageFromSourceAndImageNotCachedAndRetrieveImageFailsAndLoadImageThumbnailFails_errorIsThrown() async throws { func test_whenLoadImageFromSourceAndImageNotCachedAndRetrieveImageFailsAndLoadImageThumbnailFails_errorIsThrown() async throws {
mediaLoader.loadMediaThumbnailForSourceWidthHeightThrowableError = MediaProviderTestsError.error mediaLoader.loadMediaThumbnailForSourceWidthHeightThrowableError = MediaProviderTestsError.error
let result = await mediaProvider.loadImageFromSource(MediaSourceProxy(url: URL.picturesDirectory, mimeType: "image/jpeg"), let result = await mediaProvider.loadImageFromSource(MediaSourceProxy(url: .mockMXCImage, mimeType: "image/jpeg"),
size: Avatars.Size.room(on: .timeline).scaledSize) size: Avatars.Size.room(on: .timeline).scaledSize)
switch result { switch result {
case .success: case .success:
@@ -177,7 +177,7 @@ final class MediaProviderTests: XCTestCase {
func test_whenLoadImageFromSourceAndImageNotCachedAndRetrieveImageFailsAndNoAvatarSizeAndLoadImageContentFails_errorIsThrown() async throws { func test_whenLoadImageFromSourceAndImageNotCachedAndRetrieveImageFailsAndNoAvatarSizeAndLoadImageContentFails_errorIsThrown() async throws {
mediaLoader.loadMediaContentForSourceThrowableError = MediaProviderTestsError.error mediaLoader.loadMediaContentForSourceThrowableError = MediaProviderTestsError.error
let result = await mediaProvider.loadImageFromSource(MediaSourceProxy(url: URL.picturesDirectory, mimeType: "image/jpeg"), let result = await mediaProvider.loadImageFromSource(MediaSourceProxy(url: .mockMXCImage, mimeType: "image/jpeg"),
size: nil) size: nil)
switch result { switch result {
case .success: case .success:
@@ -190,7 +190,7 @@ final class MediaProviderTests: XCTestCase {
func test_whenLoadImageFromSourceAndImageNotCachedAndRetrieveImageFailsAndImageThumbnailIsLoadedWithCorruptedData_errorIsThrown() async throws { func test_whenLoadImageFromSourceAndImageNotCachedAndRetrieveImageFailsAndImageThumbnailIsLoadedWithCorruptedData_errorIsThrown() async throws {
mediaLoader.loadMediaThumbnailForSourceWidthHeightReturnValue = Data() mediaLoader.loadMediaThumbnailForSourceWidthHeightReturnValue = Data()
let result = await mediaProvider.loadImageFromSource(MediaSourceProxy(url: URL.picturesDirectory, mimeType: "image/jpeg"), let result = await mediaProvider.loadImageFromSource(MediaSourceProxy(url: .mockMXCImage, mimeType: "image/jpeg"),
size: Avatars.Size.room(on: .timeline).scaledSize) size: Avatars.Size.room(on: .timeline).scaledSize)
switch result { switch result {
case .success: case .success:
@@ -58,7 +58,7 @@ class RoomDetailsEditScreenViewModelTests: XCTestCase {
} }
func testAvatarDidChange() { func testAvatarDidChange() {
setupViewModel(roomProxyConfiguration: .init(name: "Some room", avatarURL: .picturesDirectory, members: [.mockMeAdmin])) setupViewModel(roomProxyConfiguration: .init(name: "Some room", avatarURL: .mockMXCAvatar, members: [.mockMeAdmin]))
context.send(viewAction: .removeImage) context.send(viewAction: .removeImage)
XCTAssertTrue(context.viewState.avatarDidChange) XCTAssertTrue(context.viewState.avatarDidChange)
XCTAssertTrue(context.viewState.canSave) XCTAssertTrue(context.viewState.canSave)
@@ -100,7 +100,7 @@ class RoomDetailsEditScreenViewModelTests: XCTestCase {
} }
func testDeleteAvatar() { func testDeleteAvatar() {
setupViewModel(roomProxyConfiguration: .init(name: "Some room", avatarURL: .picturesDirectory, members: [.mockMeAdmin])) setupViewModel(roomProxyConfiguration: .init(name: "Some room", avatarURL: .mockMXCAvatar, members: [.mockMeAdmin]))
XCTAssertNotNil(context.viewState.avatarURL) XCTAssertNotNil(context.viewState.avatarURL)
context.send(viewAction: .removeImage) context.send(viewAction: .removeImage)
XCTAssertNil(context.viewState.avatarURL) XCTAssertNil(context.viewState.avatarURL)
@@ -184,13 +184,13 @@ class RoomScreenViewModelTests: XCTestCase {
try await deferred.fulfill() try await deferred.fulfill()
configuration.name = "NewName" configuration.name = "NewName"
configuration.avatarURL = .documentsDirectory configuration.avatarURL = .mockMXCAvatar
configuration.hasOngoingCall = true configuration.hasOngoingCall = true
roomProxyMock.canUserJoinCallUserIDReturnValue = .success(true) roomProxyMock.canUserJoinCallUserIDReturnValue = .success(true)
deferred = deferFulfillment(viewModel.context.$viewState) { viewState in deferred = deferFulfillment(viewModel.context.$viewState) { viewState in
viewState.roomTitle == "NewName" && viewState.roomTitle == "NewName" &&
viewState.roomAvatar == .room(id: "TestID", name: "NewName", avatarURL: .documentsDirectory) && viewState.roomAvatar == .room(id: "TestID", name: "NewName", avatarURL: .mockMXCAvatar) &&
viewState.canJoinCall && viewState.canJoinCall &&
viewState.hasOngoingCall viewState.hasOngoingCall
} }
@@ -15,7 +15,7 @@ class UserProfileScreenViewModelTests: XCTestCase {
var context: UserProfileScreenViewModelType.Context { viewModel.context } var context: UserProfileScreenViewModelType.Context { viewModel.context }
func testInitialState() async throws { func testInitialState() async throws {
let profile = UserProfileProxy(userID: "@alice:matrix.org", displayName: "Alice", avatarURL: .picturesDirectory) let profile = UserProfileProxy(userID: "@alice:matrix.org", displayName: "Alice", avatarURL: .mockMXCAvatar)
let clientProxy = ClientProxyMock(.init()) let clientProxy = ClientProxyMock(.init())
clientProxy.profileForReturnValue = .success(profile) clientProxy.profileForReturnValue = .success(profile)
@@ -35,7 +35,7 @@ class UserProfileScreenViewModelTests: XCTestCase {
} }
func testInitialStateAccountOwner() async throws { func testInitialStateAccountOwner() async throws {
let profile = UserProfileProxy(userID: RoomMemberProxyMock.mockMe.userID, displayName: "Me", avatarURL: .picturesDirectory) let profile = UserProfileProxy(userID: RoomMemberProxyMock.mockMe.userID, displayName: "Me", avatarURL: .mockMXCAvatar)
let clientProxy = ClientProxyMock(.init()) let clientProxy = ClientProxyMock(.init())
clientProxy.profileForReturnValue = .success(profile) clientProxy.profileForReturnValue = .success(profile)
@@ -16,7 +16,7 @@ class VoiceMessageCacheTests: XCTestCase {
private var mediaSource: MediaSourceProxy! private var mediaSource: MediaSourceProxy!
private var fileManager: FileManager! private var fileManager: FileManager!
private let someURL = URL("/some/url") private let someURL = URL.mockMXCAudio
private let testFilename = "test-file" private let testFilename = "test-file"
private let mpeg4aacFileExtension = "m4a" private let mpeg4aacFileExtension = "m4a"
private let testTemporaryDirectory = URL.temporaryDirectory.appendingPathComponent("test-voice-messsage-cache") private let testTemporaryDirectory = URL.temporaryDirectory.appendingPathComponent("test-voice-messsage-cache")
@@ -16,7 +16,7 @@ class VoiceMessageMediaManagerTests: XCTestCase {
private var voiceMessageCache: VoiceMessageCacheMock! private var voiceMessageCache: VoiceMessageCacheMock!
private var mediaProvider: MediaProviderMock! private var mediaProvider: MediaProviderMock!
private let someURL = URL("/some/url") private let someURL = URL.mockMXCAudio
private let audioOGGMimeType = "audio/ogg" private let audioOGGMimeType = "audio/ogg"
override func setUp() async throws { override func setUp() async throws {
@@ -43,9 +43,7 @@ class VoiceMessageRecorderTests: XCTestCase {
audioPlayer.state = .stopped audioPlayer.state = .stopped
mediaPlayerProvider = MediaPlayerProviderMock() mediaPlayerProvider = MediaPlayerProviderMock()
mediaPlayerProvider.playerForClosure = { _ in mediaPlayerProvider.player = audioPlayer
.success(self.audioPlayer)
}
audioConverter = AudioConverterMock() audioConverter = AudioConverterMock()
voiceMessageCache = VoiceMessageCacheMock() voiceMessageCache = VoiceMessageCacheMock()
voiceMessageCache.urlForRecording = FileManager.default.temporaryDirectory.appendingPathComponent("test-voice-message").appendingPathExtension("m4a") voiceMessageCache.urlForRecording = FileManager.default.temporaryDirectory.appendingPathComponent("test-voice-message").appendingPathExtension("m4a")
@@ -121,11 +119,10 @@ class VoiceMessageRecorderTests: XCTestCase {
return return
} }
XCTAssertEqual(voiceMessageRecorder.previewAudioPlayerState?.isAttached, true) XCTAssertEqual(voiceMessageRecorder.previewAudioPlayerState?.isAttached, true)
XCTAssert(audioPlayer.loadMediaSourceUsingAutoplayCalled) XCTAssert(audioPlayer.loadSourceURLPlaybackURLAutoplayCalled)
XCTAssertEqual(audioPlayer.loadMediaSourceUsingAutoplayReceivedArguments?.url, recordingURL) XCTAssertEqual(audioPlayer.loadSourceURLPlaybackURLAutoplayReceivedArguments?.sourceURL, recordingURL)
XCTAssertEqual(audioPlayer.loadMediaSourceUsingAutoplayReceivedArguments?.mediaSource.mimeType, "audio/m4a") XCTAssertEqual(audioPlayer.loadSourceURLPlaybackURLAutoplayReceivedArguments?.playbackURL, recordingURL)
XCTAssertEqual(audioPlayer.loadMediaSourceUsingAutoplayReceivedArguments?.mediaSource.url, recordingURL) XCTAssertEqual(audioPlayer.loadSourceURLPlaybackURLAutoplayReceivedArguments?.autoplay, true)
XCTAssertEqual(audioPlayer.loadMediaSourceUsingAutoplayReceivedArguments?.autoplay, true)
XCTAssertFalse(audioPlayer.playCalled) XCTAssertFalse(audioPlayer.playCalled)
} }
@@ -141,7 +138,7 @@ class VoiceMessageRecorderTests: XCTestCase {
func testResumePlayback() async throws { func testResumePlayback() async throws {
try await setRecordingComplete() try await setRecordingComplete()
audioPlayer.url = recordingURL audioPlayer.playbackURL = recordingURL
guard case .success = await voiceMessageRecorder.startPlayback() else { guard case .success = await voiceMessageRecorder.startPlayback() else {
XCTFail("Playback should start") XCTFail("Playback should start")
@@ -149,7 +146,7 @@ class VoiceMessageRecorderTests: XCTestCase {
} }
XCTAssertEqual(voiceMessageRecorder.previewAudioPlayerState?.isAttached, true) XCTAssertEqual(voiceMessageRecorder.previewAudioPlayerState?.isAttached, true)
// The media must not have been reloaded // The media must not have been reloaded
XCTAssertFalse(audioPlayer.loadMediaSourceUsingAutoplayCalled) XCTAssertFalse(audioPlayer.loadSourceURLPlaybackURLAutoplayCalled)
XCTAssertTrue(audioPlayer.playCalled) XCTAssertTrue(audioPlayer.playCalled)
} }
+1 -1
View File
@@ -61,7 +61,7 @@ packages:
# Element/Matrix dependencies # Element/Matrix dependencies
MatrixRustSDK: MatrixRustSDK:
url: https://github.com/element-hq/matrix-rust-components-swift url: https://github.com/element-hq/matrix-rust-components-swift
exactVersion: 1.0.75 exactVersion: 1.0.76
# path: ../matrix-rust-sdk # path: ../matrix-rust-sdk
Compound: Compound:
url: https://github.com/element-hq/compound-ios url: https://github.com/element-hq/compound-ios