From 0a2f16ed671c719ebfc18837441b351a9a6fd100 Mon Sep 17 00:00:00 2001 From: Doug Date: Mon, 14 Oct 2024 09:14:37 +0100 Subject: [PATCH] Add a toggle in the developer options to optimise the media uploads. --- .../Sources/Application/AppSettings.swift | 5 +- .../RoomFlowCoordinator.swift | 3 +- .../SettingsFlowCoordinator.swift | 1 + .../UserSessionFlowCoordinator.swift | 3 +- .../View/MediaUploadPreviewScreen.swift | 2 +- .../RoomDetailsEditScreenCoordinator.swift | 2 + .../RoomDetailsEditScreenViewModel.swift | 6 +- .../View/RoomDetailsEditScreen.swift | 2 + .../DeveloperOptionsScreenModels.swift | 1 + .../View/DeveloperOptionsScreen.swift | 6 ++ .../UserDetailsEditScreenCoordinator.swift | 2 + .../UserDetailsEditScreenViewModel.swift | 6 +- .../View/UserDetailsEditScreen.swift | 1 + .../StartChatScreenCoordinator.swift | 4 +- .../Media/MediaUploadingPreprocessor.swift | 5 +- .../UITests/UITestsAppCoordinator.swift | 6 +- .../MediaUploadingPreprocessorTests.swift | 87 ++++++++++++++----- .../RoomDetailsEditScreenViewModelTests.swift | 1 + 18 files changed, 109 insertions(+), 34 deletions(-) diff --git a/ElementX/Sources/Application/AppSettings.swift b/ElementX/Sources/Application/AppSettings.swift index 1f97ab1f36..fe6d11d335 100644 --- a/ElementX/Sources/Application/AppSettings.swift +++ b/ElementX/Sources/Application/AppSettings.swift @@ -42,9 +42,9 @@ final class AppSettings { // Feature flags case slidingSyncDiscovery + case optimizeMediaUploads case publicSearchEnabled case fuzzyRoomListSearchEnabled - case pinningEnabled case enableOnlySignedDeviceIsolationMode case identityPinningViolationNotificationsEnabled case knockingEnabled @@ -281,6 +281,9 @@ final class AppSettings { @UserPreference(key: UserDefaultsKeys.slidingSyncDiscovery, defaultValue: .native, storageType: .userDefaults(store)) var slidingSyncDiscovery: SlidingSyncDiscovery + @UserPreference(key: UserDefaultsKeys.optimizeMediaUploads, defaultValue: false, storageType: .userDefaults(store)) + var optimizeMediaUploads + @UserPreference(key: UserDefaultsKeys.identityPinningViolationNotificationsEnabled, defaultValue: isDevelopmentBuild, storageType: .userDefaults(store)) var identityPinningViolationNotificationsEnabled diff --git a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift index 0df9e11bc5..fb48a3cd71 100644 --- a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift @@ -810,6 +810,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { let roomDetailsEditParameters = RoomDetailsEditScreenCoordinatorParameters(roomProxy: roomProxy, mediaProvider: userSession.mediaProvider, + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: appSettings), navigationStackCoordinator: stackCoordinator, userIndicatorController: userIndicatorController, orientationManager: appMediator.windowManager) @@ -895,7 +896,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { let parameters = MediaUploadPreviewScreenCoordinatorParameters(userIndicatorController: userIndicatorController, roomProxy: roomProxy, - mediaUploadingPreprocessor: MediaUploadingPreprocessor(), + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: appSettings), title: url.lastPathComponent, url: url) diff --git a/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift index e78d5ab59f..7e031a0005 100644 --- a/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift @@ -165,6 +165,7 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { let coordinator = UserDetailsEditScreenCoordinator(parameters: .init(orientationManager: parameters.windowManager, clientProxy: parameters.userSession.clientProxy, mediaProvider: parameters.userSession.mediaProvider, + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: parameters.appSettings), navigationStackCoordinator: navigationStackCoordinator, userIndicatorController: parameters.userIndicatorController)) diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift index a352e2a3f7..ff14107d35 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift @@ -542,7 +542,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { userSession: userSession, userIndicatorController: ServiceLocator.shared.userIndicatorController, navigationStackCoordinator: startChatNavigationStackCoordinator, - userDiscoveryService: userDiscoveryService) + userDiscoveryService: userDiscoveryService, + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: appSettings)) let coordinator = StartChatScreenCoordinator(parameters: parameters) coordinator.actions.sink { [weak self] action in diff --git a/ElementX/Sources/Screens/MediaUploadPreviewScreen/View/MediaUploadPreviewScreen.swift b/ElementX/Sources/Screens/MediaUploadPreviewScreen/View/MediaUploadPreviewScreen.swift index c902a1ba48..30db52e56c 100644 --- a/ElementX/Sources/Screens/MediaUploadPreviewScreen/View/MediaUploadPreviewScreen.swift +++ b/ElementX/Sources/Screens/MediaUploadPreviewScreen/View/MediaUploadPreviewScreen.swift @@ -116,7 +116,7 @@ private class PreviewItem: NSObject, QLPreviewItem { struct MediaUploadPreviewScreen_Previews: PreviewProvider, TestablePreview { static let viewModel = MediaUploadPreviewScreenViewModel(userIndicatorController: UserIndicatorControllerMock.default, roomProxy: JoinedRoomProxyMock(), - mediaUploadingPreprocessor: MediaUploadingPreprocessor(), + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings), title: "some random file name", url: URL.picturesDirectory) static var previews: some View { diff --git a/ElementX/Sources/Screens/RoomDetailsEditScreen/RoomDetailsEditScreenCoordinator.swift b/ElementX/Sources/Screens/RoomDetailsEditScreen/RoomDetailsEditScreenCoordinator.swift index 0bec89382e..9d4dffcf52 100644 --- a/ElementX/Sources/Screens/RoomDetailsEditScreen/RoomDetailsEditScreenCoordinator.swift +++ b/ElementX/Sources/Screens/RoomDetailsEditScreen/RoomDetailsEditScreenCoordinator.swift @@ -11,6 +11,7 @@ import SwiftUI struct RoomDetailsEditScreenCoordinatorParameters { let roomProxy: JoinedRoomProxyProtocol let mediaProvider: MediaProviderProtocol + let mediaUploadingPreprocessor: MediaUploadingPreprocessor weak var navigationStackCoordinator: NavigationStackCoordinator? let userIndicatorController: UserIndicatorControllerProtocol let orientationManager: OrientationManagerProtocol @@ -35,6 +36,7 @@ final class RoomDetailsEditScreenCoordinator: CoordinatorProtocol { viewModel = RoomDetailsEditScreenViewModel(roomProxy: parameters.roomProxy, mediaProvider: parameters.mediaProvider, + mediaUploadingPreprocessor: parameters.mediaUploadingPreprocessor, userIndicatorController: parameters.userIndicatorController) } diff --git a/ElementX/Sources/Screens/RoomDetailsEditScreen/RoomDetailsEditScreenViewModel.swift b/ElementX/Sources/Screens/RoomDetailsEditScreen/RoomDetailsEditScreenViewModel.swift index 26fa1f0a26..cc16d6a709 100644 --- a/ElementX/Sources/Screens/RoomDetailsEditScreen/RoomDetailsEditScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomDetailsEditScreen/RoomDetailsEditScreenViewModel.swift @@ -14,7 +14,7 @@ class RoomDetailsEditScreenViewModel: RoomDetailsEditScreenViewModelType, RoomDe private let actionsSubject: PassthroughSubject = .init() private let roomProxy: JoinedRoomProxyProtocol private let userIndicatorController: UserIndicatorControllerProtocol - private let mediaPreprocessor: MediaUploadingPreprocessor = .init() + private let mediaUploadingPreprocessor: MediaUploadingPreprocessor var actions: AnyPublisher { actionsSubject.eraseToAnyPublisher() @@ -22,8 +22,10 @@ class RoomDetailsEditScreenViewModel: RoomDetailsEditScreenViewModelType, RoomDe init(roomProxy: JoinedRoomProxyProtocol, mediaProvider: MediaProviderProtocol, + mediaUploadingPreprocessor: MediaUploadingPreprocessor, userIndicatorController: UserIndicatorControllerProtocol) { self.roomProxy = roomProxy + self.mediaUploadingPreprocessor = mediaUploadingPreprocessor self.userIndicatorController = userIndicatorController let roomAvatar = roomProxy.avatarURL @@ -76,7 +78,7 @@ class RoomDetailsEditScreenViewModel: RoomDetailsEditScreenViewModelType, RoomDe title: L10n.commonLoading, persistent: true)) - let mediaResult = await mediaPreprocessor.processMedia(at: url) + let mediaResult = await mediaUploadingPreprocessor.processMedia(at: url) switch mediaResult { case .success(.image): diff --git a/ElementX/Sources/Screens/RoomDetailsEditScreen/View/RoomDetailsEditScreen.swift b/ElementX/Sources/Screens/RoomDetailsEditScreen/View/RoomDetailsEditScreen.swift index 3f4cd5fd35..9705d0ce3b 100644 --- a/ElementX/Sources/Screens/RoomDetailsEditScreen/View/RoomDetailsEditScreen.swift +++ b/ElementX/Sources/Screens/RoomDetailsEditScreen/View/RoomDetailsEditScreen.swift @@ -154,6 +154,7 @@ struct RoomDetailsEditScreen_Previews: PreviewProvider, TestablePreview { return RoomDetailsEditScreenViewModel(roomProxy: roomProxy, mediaProvider: MediaProviderMock(configuration: .init()), + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings), userIndicatorController: UserIndicatorControllerMock.default) }() @@ -164,6 +165,7 @@ struct RoomDetailsEditScreen_Previews: PreviewProvider, TestablePreview { return RoomDetailsEditScreenViewModel(roomProxy: roomProxy, mediaProvider: MediaProviderMock(configuration: .init()), + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings), userIndicatorController: UserIndicatorControllerMock.default) }() diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift index 7e186b3a05..1d282d462d 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift @@ -46,6 +46,7 @@ protocol DeveloperOptionsProtocol: AnyObject { var hideUnreadMessagesBadge: Bool { get set } var fuzzyRoomListSearchEnabled: Bool { get set } var hideTimelineMedia: Bool { get set } + var optimizeMediaUploads: Bool { get set } var enableOnlySignedDeviceIsolationMode: Bool { get set } var elementCallBaseURLOverride: URL? { get set } var identityPinningViolationNotificationsEnabled: Bool { get set } diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift index 42a3000faa..22f7044896 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift @@ -62,6 +62,12 @@ struct DeveloperOptionsScreen: View { } } + Section("Media") { + Toggle(isOn: $context.optimizeMediaUploads) { + Text("Optimise for upload") + } + } + Section { Toggle(isOn: $context.enableOnlySignedDeviceIsolationMode) { Text("Exclude insecure devices when sending/receiving messages") diff --git a/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/UserDetailsEditScreenCoordinator.swift b/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/UserDetailsEditScreenCoordinator.swift index b4eb6e3361..bcb06ec35d 100644 --- a/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/UserDetailsEditScreenCoordinator.swift +++ b/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/UserDetailsEditScreenCoordinator.swift @@ -12,6 +12,7 @@ struct UserDetailsEditScreenCoordinatorParameters { let orientationManager: OrientationManagerProtocol let clientProxy: ClientProxyProtocol let mediaProvider: MediaProviderProtocol + let mediaUploadingPreprocessor: MediaUploadingPreprocessor weak var navigationStackCoordinator: NavigationStackCoordinator? let userIndicatorController: UserIndicatorControllerProtocol } @@ -26,6 +27,7 @@ final class UserDetailsEditScreenCoordinator: CoordinatorProtocol { viewModel = UserDetailsEditScreenViewModel(clientProxy: parameters.clientProxy, mediaProvider: parameters.mediaProvider, + mediaUploadingPreprocessor: parameters.mediaUploadingPreprocessor, userIndicatorController: parameters.userIndicatorController) } diff --git a/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/UserDetailsEditScreenViewModel.swift b/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/UserDetailsEditScreenViewModel.swift index f83b911fda..0b03ed0d15 100644 --- a/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/UserDetailsEditScreenViewModel.swift +++ b/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/UserDetailsEditScreenViewModel.swift @@ -14,7 +14,7 @@ class UserDetailsEditScreenViewModel: UserDetailsEditScreenViewModelType, UserDe private let actionsSubject: PassthroughSubject = .init() private let clientProxy: ClientProxyProtocol private let userIndicatorController: UserIndicatorControllerProtocol - private let mediaPreprocessor: MediaUploadingPreprocessor = .init() + private let mediaUploadingPreprocessor: MediaUploadingPreprocessor var actions: AnyPublisher { actionsSubject.eraseToAnyPublisher() @@ -22,8 +22,10 @@ class UserDetailsEditScreenViewModel: UserDetailsEditScreenViewModelType, UserDe init(clientProxy: ClientProxyProtocol, mediaProvider: MediaProviderProtocol, + mediaUploadingPreprocessor: MediaUploadingPreprocessor, userIndicatorController: UserIndicatorControllerProtocol) { self.clientProxy = clientProxy + self.mediaUploadingPreprocessor = mediaUploadingPreprocessor self.userIndicatorController = userIndicatorController super.init(initialViewState: UserDetailsEditScreenViewState(userID: clientProxy.userID, @@ -88,7 +90,7 @@ class UserDetailsEditScreenViewModel: UserDetailsEditScreenViewModelType, UserDe title: L10n.commonLoading, persistent: true)) - let mediaResult = await mediaPreprocessor.processMedia(at: url) + let mediaResult = await mediaUploadingPreprocessor.processMedia(at: url) switch mediaResult { case .success(.image): diff --git a/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/View/UserDetailsEditScreen.swift b/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/View/UserDetailsEditScreen.swift index 9049acea55..953f3f96d3 100644 --- a/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/View/UserDetailsEditScreen.swift +++ b/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/View/UserDetailsEditScreen.swift @@ -117,6 +117,7 @@ struct UserDetailsEditScreen: View { struct UserDetailsEditScreen_Previews: PreviewProvider, TestablePreview { static let viewModel = UserDetailsEditScreenViewModel(clientProxy: ClientProxyMock(.init(userID: "@stefan:matrix.org")), mediaProvider: MediaProviderMock(configuration: .init()), + mediaUploadingPreprocessor: .init(appSettings: ServiceLocator.shared.settings), userIndicatorController: UserIndicatorControllerMock.default) static var previews: some View { diff --git a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift index 56791a1a4a..2bc682ef4e 100644 --- a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift +++ b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift @@ -14,6 +14,7 @@ struct StartChatScreenCoordinatorParameters { let userIndicatorController: UserIndicatorControllerProtocol weak var navigationStackCoordinator: NavigationStackCoordinator? let userDiscoveryService: UserDiscoveryServiceProtocol + let mediaUploadingPreprocessor: MediaUploadingPreprocessor } enum StartChatScreenCoordinatorAction { @@ -134,7 +135,6 @@ final class StartChatScreenCoordinator: CoordinatorProtocol { // MARK: - Private - let mediaUploadingPreprocessor = MediaUploadingPreprocessor() private func displayMediaPickerWithSource(_ source: MediaPickerScreenSource) { let stackCoordinator = NavigationStackCoordinator() @@ -159,7 +159,7 @@ final class StartChatScreenCoordinator: CoordinatorProtocol { Task { [weak self] in guard let self else { return } do { - let media = try await mediaUploadingPreprocessor.processMedia(at: url).get() + let media = try await parameters.mediaUploadingPreprocessor.processMedia(at: url).get() var parameters = createRoomParameters.value parameters.avatarImageMedia = media createRoomParameters.send(parameters) diff --git a/ElementX/Sources/Services/Media/MediaUploadingPreprocessor.swift b/ElementX/Sources/Services/Media/MediaUploadingPreprocessor.swift index cec36f19c7..ef88c3d797 100644 --- a/ElementX/Sources/Services/Media/MediaUploadingPreprocessor.swift +++ b/ElementX/Sources/Services/Media/MediaUploadingPreprocessor.swift @@ -82,6 +82,8 @@ private struct VideoProcessingInfo { } struct MediaUploadingPreprocessor { + let appSettings: AppSettings + enum Constants { static let maximumThumbnailSize = CGSize(width: 800, height: 600) static let thumbnailCompressionQuality = 0.8 @@ -368,8 +370,9 @@ struct MediaUploadingPreprocessor { /// - Returns: the URL for the resulting video and its media info as a `VideoProcessingResult` private func convertVideoToMP4(_ url: URL, targetFileSize: UInt = 0) async -> Result { let asset = AVURLAsset(url: url) + let presetName = appSettings.optimizeMediaUploads ? AVAssetExportPreset640x480 : AVAssetExportPreset1920x1080 - guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPreset1920x1080) else { + guard let exportSession = AVAssetExportSession(asset: asset, presetName: presetName) else { return .failure(.failedConvertingVideo) } diff --git a/ElementX/Sources/UITests/UITestsAppCoordinator.swift b/ElementX/Sources/UITests/UITestsAppCoordinator.swift index 1c125258bc..fb12887859 100644 --- a/ElementX/Sources/UITests/UITestsAppCoordinator.swift +++ b/ElementX/Sources/UITests/UITestsAppCoordinator.swift @@ -581,7 +581,8 @@ class MockScreen: Identifiable { userSession: userSession, userIndicatorController: UserIndicatorControllerMock(), navigationStackCoordinator: navigationStackCoordinator, - userDiscoveryService: userDiscoveryMock) + userDiscoveryService: userDiscoveryMock, + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings)) let coordinator = StartChatScreenCoordinator(parameters: parameters) navigationStackCoordinator.setRootCoordinator(coordinator) return navigationStackCoordinator @@ -595,7 +596,8 @@ class MockScreen: Identifiable { userSession: userSession, userIndicatorController: UserIndicatorControllerMock(), navigationStackCoordinator: navigationStackCoordinator, - userDiscoveryService: userDiscoveryMock)) + userDiscoveryService: userDiscoveryMock, + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings))) navigationStackCoordinator.setRootCoordinator(coordinator) return navigationStackCoordinator case .createRoom: diff --git a/UnitTests/Sources/MediaUploadingPreprocessorTests.swift b/UnitTests/Sources/MediaUploadingPreprocessorTests.swift index e33bc64b7a..8f4e7c8443 100644 --- a/UnitTests/Sources/MediaUploadingPreprocessorTests.swift +++ b/UnitTests/Sources/MediaUploadingPreprocessorTests.swift @@ -10,7 +10,19 @@ import XCTest @testable import ElementX final class MediaUploadingPreprocessorTests: XCTestCase { - let mediaUploadingPreprocessor = MediaUploadingPreprocessor() + var appSettings: AppSettings! + var mediaUploadingPreprocessor: MediaUploadingPreprocessor! + + override func setUp() { + AppSettings.resetAllSettings() + appSettings = AppSettings() + ServiceLocator.shared.register(appSettings: appSettings) + mediaUploadingPreprocessor = MediaUploadingPreprocessor(appSettings: appSettings) + } + + override func tearDown() { + AppSettings.resetAllSettings() + } func testAudioFileProcessing() async { guard let url = Bundle(for: Self.self).url(forResource: "test_audio.mp3", withExtension: nil) else { @@ -70,6 +82,23 @@ final class MediaUploadingPreprocessorTests: XCTestCase { XCTAssertEqual(videoInfo.thumbnailInfo?.size ?? 0, 34206, accuracy: 100) XCTAssertEqual(videoInfo.thumbnailInfo?.width, 800) XCTAssertEqual(videoInfo.thumbnailInfo?.height, 450) + + // Repeat with optimised media setting + appSettings.optimizeMediaUploads = true + + guard case let .success(optimizedResult) = await mediaUploadingPreprocessor.processMedia(at: url), + case let .video(_, _, optimizedVideoInfo) = optimizedResult else { + XCTFail("Failed processing asset") + return + } + + // Check optimised video info + XCTAssertEqual(optimizedVideoInfo.mimetype, "video/mp4") + XCTAssertEqual(optimizedVideoInfo.blurhash, "K32PJbx^I7jYaebHMvV?o$") + XCTAssertEqual(optimizedVideoInfo.size ?? 0, 4_090_898, accuracy: 100) // Note: This is slightly stupid because it is larger now 🤦‍♂️ + XCTAssertEqual(optimizedVideoInfo.width, 640) + XCTAssertEqual(optimizedVideoInfo.height, 360) + XCTAssertEqual(optimizedVideoInfo.duration ?? 0, 30, accuracy: 100) } func testPortraitMp4VideoProcessing() async { @@ -110,6 +139,23 @@ final class MediaUploadingPreprocessorTests: XCTestCase { XCTAssertEqual(videoInfo.thumbnailInfo?.size ?? 0, 83220, accuracy: 100) XCTAssertEqual(videoInfo.thumbnailInfo?.width, 337) XCTAssertEqual(videoInfo.thumbnailInfo?.height, 600) + + // Repeat with optimised media setting + appSettings.optimizeMediaUploads = true + + guard case let .success(optimizedResult) = await mediaUploadingPreprocessor.processMedia(at: url), + case let .video(_, _, optimizedVideoInfo) = optimizedResult else { + XCTFail("Failed processing asset") + return + } + + // Check optimised video info + XCTAssertEqual(optimizedVideoInfo.mimetype, "video/mp4") + XCTAssertEqual(optimizedVideoInfo.blurhash, "K7BDNJD*0L%#sl_2~C9ZE1") + XCTAssertEqual(optimizedVideoInfo.size ?? 0, 6_520_897, accuracy: 100) + XCTAssertEqual(optimizedVideoInfo.width, 360) + XCTAssertEqual(optimizedVideoInfo.height, 640) + XCTAssertEqual(optimizedVideoInfo.duration ?? 0, 30, accuracy: 100) } func testLandscapeImageProcessing() async { @@ -185,28 +231,10 @@ final class MediaUploadingPreprocessorTests: XCTestCase { XCTAssertEqual(originalImage.size, convertedImage.size) // Check that the GPS data has been stripped - guard let imageSource = CGImageSourceCreateWithData(originalImageData as NSData, nil) else { - XCTFail("Invalid test asset") - return - } - - guard let originalMetadata: NSDictionary = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) else { - XCTFail("Test asset is expected to contain metadata") - return - } - + let originalMetadata = metadata(from: originalImageData) XCTAssertNotNil(originalMetadata.value(forKeyPath: "\(kCGImagePropertyGPSDictionary)")) - guard let convertedImageSource = CGImageSourceCreateWithData(convertedImageData as NSData, nil) else { - XCTFail("Invalid converted asset") - return - } - - guard let convertedMetadata: NSDictionary = CGImageSourceCopyPropertiesAtIndex(convertedImageSource, 0, nil) else { - XCTFail("Test asset is expected to contain metadata") - return - } - + let convertedMetadata = metadata(from: convertedImageData) XCTAssertNil(convertedMetadata.value(forKeyPath: "\(kCGImagePropertyGPSDictionary)")) // Check that the thumbnail is generated correctly @@ -223,5 +251,22 @@ final class MediaUploadingPreprocessorTests: XCTestCase { XCTAssert(thumbnail.size.width <= MediaUploadingPreprocessor.Constants.maximumThumbnailSize.height) XCTAssert(thumbnail.size.height <= MediaUploadingPreprocessor.Constants.maximumThumbnailSize.width) } + + let thumbnailMetadata = metadata(from: thumbnailData) + XCTAssertNil(thumbnailMetadata.value(forKeyPath: "\(kCGImagePropertyGPSDictionary)")) + } + + private func metadata(from imageData: Data) -> NSDictionary { + guard let imageSource = CGImageSourceCreateWithData(imageData as NSData, nil) else { + XCTFail("Invalid asset") + return [:] + } + + guard let convertedMetadata: NSDictionary = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) else { + XCTFail("Test asset is expected to contain metadata") + return [:] + } + + return convertedMetadata } } diff --git a/UnitTests/Sources/RoomDetailsEditScreenViewModelTests.swift b/UnitTests/Sources/RoomDetailsEditScreenViewModelTests.swift index a21ec8c104..2088df6e3e 100644 --- a/UnitTests/Sources/RoomDetailsEditScreenViewModelTests.swift +++ b/UnitTests/Sources/RoomDetailsEditScreenViewModelTests.swift @@ -112,6 +112,7 @@ class RoomDetailsEditScreenViewModelTests: XCTestCase { userIndicatorController = UserIndicatorControllerMock.default viewModel = .init(roomProxy: JoinedRoomProxyMock(roomProxyConfiguration), mediaProvider: MediaProviderMock(configuration: .init()), + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings), userIndicatorController: userIndicatorController) } }