diff --git a/DesignKit/Sources/Buttons/ElementCapsuleButtonStyle.swift b/DesignKit/Sources/Buttons/ElementCapsuleButtonStyle.swift index ac957bdca..a358d0db1 100644 --- a/DesignKit/Sources/Buttons/ElementCapsuleButtonStyle.swift +++ b/DesignKit/Sources/Buttons/ElementCapsuleButtonStyle.swift @@ -40,6 +40,7 @@ public struct ElementCapsuleButtonStyle: ButtonStyle { .multilineTextAlignment(.center) .background(background) .opacity(configuration.isPressed ? 0.6 : 1) + .contentShape(Capsule()) } @ViewBuilder diff --git a/DesignKit/Sources/TextFields/ElementTextFieldStyle.swift b/DesignKit/Sources/TextFields/ElementTextFieldStyle.swift index 72e9075cb..fa6e7f672 100644 --- a/DesignKit/Sources/TextFields/ElementTextFieldStyle.swift +++ b/DesignKit/Sources/TextFields/ElementTextFieldStyle.swift @@ -62,6 +62,7 @@ public struct ElementTextFieldStyle: TextFieldStyle { configuration .textFieldStyle(BorderedInputFieldStyle(isEditing: isFocused, isError: isError, returnKey: nil)) .focused($isFocused) + .onTapGesture { isFocused = true } // Set focus with taps in the space between the border and text field. if let footerText { Text(footerText) diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 9bc44cf0f..1113bcfa7 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -47,7 +47,6 @@ 13C77FDF17C4C6627CFFC205 /* RoomTimelineItemFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D25A35764C7B3DB78954AB5 /* RoomTimelineItemFactoryProtocol.swift */; }; 14132418A748C988B85B025E /* OnboardingPageIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09199C43BAB209C0BD89A836 /* OnboardingPageIndicator.swift */; }; 149D1942DC005D0485FB8D93 /* LoggingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1943ADE6A62ED5129D7C8 /* LoggingTests.swift */; }; - 1504CE9A609A348D90B69E47 /* VideoPlayerViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3004DFA1B10951962787D90 /* VideoPlayerViewModelTests.swift */; }; 152AE2B8650FB23AFD2E28B9 /* MockAuthenticationServiceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65C2B80DD0BF6F10BB5FA922 /* MockAuthenticationServiceProxy.swift */; }; 1555A7643D85187D4851040C /* TemplateScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4549FCB53F43DB0B278374BC /* TemplateScreen.swift */; }; 157E5FDDF419C0B2CA7E2C28 /* TimelineItemBubbledStylerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98A2932515EA11D3DD8A3506 /* TimelineItemBubbledStylerView.swift */; }; @@ -61,7 +60,6 @@ 191161FE9E0DA89704301F37 /* Untranslated.strings in Resources */ = {isa = PBXBuildFile; fileRef = D2F7194F440375338F8E2487 /* Untranslated.strings */; }; 1950A80CD198BED283DFC2CE /* ClientProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18F2958E6D247AE2516BEEE8 /* ClientProxy.swift */; }; 19839F3526CE8C35AAF241AD /* ServerSelectionViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F52BF30D12BA3BD3D3DBB8F /* ServerSelectionViewModelProtocol.swift */; }; - 19ED6CF7FDBB1158692D101C /* VideoPlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D783758EAE6A88C93564EB /* VideoPlayerViewModel.swift */; }; 1A70A2199394B5EC660934A5 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = A678E40E917620059695F067 /* MatrixRustSDK */; }; 1A8BDEB96C3B2F033FA563F8 /* EmojiPickerHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB785716B9212C093704E767 /* EmojiPickerHeaderView.swift */; }; 1AE4AEA0FA8DEF52671832E0 /* RoomTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */; }; @@ -183,7 +181,6 @@ 5D9F0695DC6C0057F85C12B6 /* UserNotificationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1113CA0A67B4AA227AAFB63B /* UserNotificationController.swift */; }; 5E0F2E612718BB4397A6D40A /* TextRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9E785D5137510481733A3E8 /* TextRoomTimelineView.swift */; }; 5E25568E1CDAD983517E58B5 /* MediaSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179423E34EE846E048E49CBF /* MediaSourceProxy.swift */; }; - 5E540CAEF764D7FBD8D80776 /* VideoPlayerModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A3FC45B7643298BF361CEB1 /* VideoPlayerModels.swift */; }; 5F06AD3C66884CE793AE6119 /* FileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DF593C3F7AF4B2FBAEB05D /* FileManager.swift */; }; 5F1FDE49DFD0C680386E48F9 /* TemplateViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B80895CE021B49847BD7D74 /* TemplateViewModelProtocol.swift */; }; 5F5488FBC9CFEB6F433D74A4 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7109E709A7738E6BCC4553E6 /* Localizable.strings */; }; @@ -388,12 +385,10 @@ C7B251DC896C0867C51B616D /* AnalyticsPrompt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 541542F5AC323709D8563458 /* AnalyticsPrompt.swift */; }; C7CFDB4929DDD9A3B5BA085D /* BugReportViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB7ED3A898B07976F3AA90F /* BugReportViewModelTests.swift */; }; C8E82786DE1B6A400DA9BA25 /* RoomTimelineItemProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289FA233E896FBC5956C67E0 /* RoomTimelineItemProperties.swift */; }; - C94A6048C654B01163AE1BF1 /* VideoPlayerViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5282B7A2DCD076AD2CF27F46 /* VideoPlayerViewModelProtocol.swift */; }; CA45758F08DF42D41D8A4B29 /* FilePreviewViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF38B69D2C331A499276F400 /* FilePreviewViewModelTests.swift */; }; CB137BFB3E083C33E398A6CB /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 0DD568A494247444A4B56031 /* Kingfisher */; }; CB498F4E27AA0545DCEF0F6F /* DeviceKit in Frameworks */ = {isa = PBXBuildFile; productRef = 4003BC24B24C9E63D3304177 /* DeviceKit */; }; CB99B0FA38A4AC596F38CC13 /* KeychainControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5E94DCFEE803E5ABAE8ACCE /* KeychainControllerProtocol.swift */; }; - CBF64DE774298D773DBD5354 /* VideoPlayerScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DB634B42CFE667112369D57 /* VideoPlayerScreen.swift */; }; CC2A6B71E12DDF1EE6ECD299 /* RoomMembersCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F118CF7C5548099AACF7E90C /* RoomMembersCoordinator.swift */; }; CC736DA1AA8F8B9FD8785009 /* ScreenshotDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5C4AF6E3885730CD560311C /* ScreenshotDetector.swift */; }; CCAA0671B46EAFD0BB528E2C /* apple_emojis_data.json in Resources */ = {isa = PBXBuildFile; fileRef = 8FC26871038FB0E4AAE22605 /* apple_emojis_data.json */; }; @@ -409,7 +404,6 @@ D05A193AE63030F2CFCE2E9C /* UITestScreenIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC6FE34A0A47D010BBB4D4D4 /* UITestScreenIdentifier.swift */; }; D0619D2E6B9C511190FBEB95 /* RoomMessageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607974D08BD2AF83725D817A /* RoomMessageProtocol.swift */; }; D2D70B5DB1A5E4AF0CD88330 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 033DB41C51865A2E83174E87 /* target.yml */; }; - D3E603A5E9D529CF293E1BF9 /* VideoPlayerCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1651A532305027D3F605E2B /* VideoPlayerCoordinator.swift */; }; D59F046B15AA8E971053C1A6 /* RoomDetailsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 813B198AE8833FD12E5A9C78 /* RoomDetailsCoordinator.swift */; }; D5C805F49B2C75DC3793E780 /* EmojiItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A243E04B58DC6E41FDCD82 /* EmojiItem.swift */; }; D5EA4C6C80579279770D5804 /* ImageRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A45283CF1DB96E583BECA6 /* ImageRoomTimelineView.swift */; }; @@ -475,7 +469,7 @@ FA9C427FFB11B1AA2DCC5602 /* RoomProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */; }; FBCD77D557AACBE9B445133A /* MediaProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = E12C9E0B61A77C7F0EE7918C /* MediaProxy.swift */; }; FBF09B6C900415800DDF2A21 /* EmojiProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C113E0CB7E15E9765B1817A /* EmojiProvider.swift */; }; - FCB9B475F908765531335859 /* NavigationSplitCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A63A32A0627A03F00A2900FE /* NavigationSplitCoordinator.swift */; }; + FCB9B475F908765531335859 /* NavigationSplitCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A63A32A0627A03F00A2900FE /* NavigationSplitCoordinatorTests.swift */; }; FCD3F2B82CAB29A07887A127 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 2B43F2AF7456567FE37270A7 /* KeychainAccess */; }; FE4593FC2A02AAF92E089565 /* ElementAnimations.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF1593DD87F974F8509BB619 /* ElementAnimations.swift */; }; FE79E2BCCF69E8BF4D21E15A /* RoomMessageFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA154570F693D93513E584C1 /* RoomMessageFactory.swift */; }; @@ -557,7 +551,6 @@ 0C88046D6A070D9827181C4D /* OnboardingUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingUITests.swift; sourceTree = ""; }; 0CB569EAA5017B5B23970655 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/Localizable.strings; sourceTree = ""; }; 0D8F620C8B314840D8602E3F /* NSE.appex */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.app-extension"; path = NSE.appex; sourceTree = BUILT_PRODUCTS_DIR; }; - 0DB634B42CFE667112369D57 /* VideoPlayerScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerScreen.swift; sourceTree = ""; }; 0DD16CE9A66C9040B066AD60 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = vi; path = vi.lproj/Localizable.stringsdict; sourceTree = ""; }; 0DE6C5C756E1393202BA95CD /* UserNotificationControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationControllerTests.swift; sourceTree = ""; }; 0E7062F88E9D5F79C8A80524 /* th */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = th; path = th.lproj/Localizable.stringsdict; sourceTree = ""; }; @@ -590,7 +583,6 @@ 18FE0CDF1FFA92EA7EE17B0B /* RoomTimelineControllerFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineControllerFactoryProtocol.swift; sourceTree = ""; }; 1941C8817E6B6971BA4415F5 /* VideoRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineView.swift; sourceTree = ""; }; 1A18F6CE4D694D21E4EA9B25 /* Strings+Untranslated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Strings+Untranslated.swift"; sourceTree = ""; }; - 1A3FC45B7643298BF361CEB1 /* VideoPlayerModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerModels.swift; sourceTree = ""; }; 1A63815AD6A5C306453342F2 /* ImageRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRoomTimelineItem.swift; sourceTree = ""; }; 1BC4437C107D52ED19357DFC /* OnboardingViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewModelProtocol.swift; sourceTree = ""; }; 1C429043E986008B97736636 /* ab */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ab; path = ab.lproj/Localizable.strings; sourceTree = ""; }; @@ -712,7 +704,6 @@ 505208F28007C0FEC14E1FF0 /* HomeScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenViewModelTests.swift; sourceTree = ""; }; 51DF91C374901E94D93276F1 /* es-MX */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "es-MX"; path = "es-MX.lproj/Localizable.stringsdict"; sourceTree = ""; }; 5221DFDF809142A2D6AC82B9 /* RoomScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreen.swift; sourceTree = ""; }; - 5282B7A2DCD076AD2CF27F46 /* VideoPlayerViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerViewModelProtocol.swift; sourceTree = ""; }; 529513218340CC8419273165 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; 52D7074991B3267B26D89B22 /* MockRoomTimelineController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRoomTimelineController.swift; sourceTree = ""; }; 53482ECA4B6633961EC224F5 /* ScrollViewAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollViewAdapter.swift; sourceTree = ""; }; @@ -859,7 +850,6 @@ A1ED7E89865201EE7D53E6DA /* SeparatorRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorRoomTimelineItem.swift; sourceTree = ""; }; A2AC3C656E960E15B5905E05 /* UnsupportedRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsupportedRoomTimelineView.swift; sourceTree = ""; }; A2B6433F516F1E6DFA0E2D89 /* vls */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vls; path = vls.lproj/Localizable.strings; sourceTree = ""; }; - A3004DFA1B10951962787D90 /* VideoPlayerViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerViewModelTests.swift; sourceTree = ""; }; A30A1758E2B73EF38E7C42F8 /* ServerSelectionModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionModels.swift; sourceTree = ""; }; A34A814CBD56230BC74FFCF4 /* MXLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXLogger.swift; sourceTree = ""; }; A40C19719687984FD9478FBE /* Task.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Task.swift; sourceTree = ""; }; @@ -869,7 +859,7 @@ A4B5B19A10D3F7C2BC5315DF /* VideoRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineItem.swift; sourceTree = ""; }; A4CF2FC815D26B337E78DA45 /* RoomMembersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersViewModel.swift; sourceTree = ""; }; A5B0B1226DA8DB55918B34CD /* FileCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileCache.swift; sourceTree = ""; }; - A63A32A0627A03F00A2900FE /* NavigationSplitCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationSplitCoordinator.swift; sourceTree = ""; }; + A63A32A0627A03F00A2900FE /* NavigationSplitCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationSplitCoordinatorTests.swift; sourceTree = ""; }; A64F0DB78E0AC23C91AD89EF /* mk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = mk; path = mk.lproj/Localizable.strings; sourceTree = ""; }; A65F140F9FE5E8D4DAEFF354 /* RoomProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomProxy.swift; sourceTree = ""; }; A6B891A6DA826E2461DBB40F /* PHGPostHogConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHGPostHogConfiguration.swift; sourceTree = ""; }; @@ -968,10 +958,8 @@ D06DFD894157A4C93A02D8B5 /* lo */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lo; path = lo.lproj/Localizable.strings; sourceTree = ""; }; D09A267106B9585D3D0CFC0D /* ClientError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientError.swift; sourceTree = ""; }; D0A45283CF1DB96E583BECA6 /* ImageRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRoomTimelineView.swift; sourceTree = ""; }; - D1651A532305027D3F605E2B /* VideoPlayerCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerCoordinator.swift; sourceTree = ""; }; D1A9CCCF53495CF3D7B19FCE /* MockSessionVerificationControllerProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockSessionVerificationControllerProxy.swift; sourceTree = ""; }; D263254AFE5B7993FFBBF324 /* NSE.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NSE.entitlements; sourceTree = ""; }; - D2D783758EAE6A88C93564EB /* VideoPlayerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerViewModel.swift; sourceTree = ""; }; D31DC8105C6233E5FFD9B84C /* element-x-ios */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "element-x-ios"; path = .; sourceTree = SOURCE_ROOT; }; D33116993D54FADC0C721C1F /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = ""; }; D3D455BC2423D911A62ACFB2 /* NSELogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSELogger.swift; sourceTree = ""; }; @@ -1252,18 +1240,6 @@ path = Resources; sourceTree = ""; }; - 285079C24A5189C48284CC47 /* VideoPlayer */ = { - isa = PBXGroup; - children = ( - D1651A532305027D3F605E2B /* VideoPlayerCoordinator.swift */, - 1A3FC45B7643298BF361CEB1 /* VideoPlayerModels.swift */, - D2D783758EAE6A88C93564EB /* VideoPlayerViewModel.swift */, - 5282B7A2DCD076AD2CF27F46 /* VideoPlayerViewModelProtocol.swift */, - 5E01022071DDDC48EF453374 /* View */, - ); - path = VideoPlayer; - sourceTree = ""; - }; 2D6DC9871FD7173E51D67C73 /* Cache */ = { isa = PBXGroup; children = ( @@ -1601,14 +1577,6 @@ path = EmojiMart; sourceTree = ""; }; - 5E01022071DDDC48EF453374 /* View */ = { - isa = PBXGroup; - children = ( - 0DB634B42CFE667112369D57 /* VideoPlayerScreen.swift */, - ); - path = View; - sourceTree = ""; - }; 605F8221E52991786397FCC9 /* View */ = { isa = PBXGroup; children = ( @@ -1723,7 +1691,7 @@ A05707BF550D770168A406DB /* LoginViewModelTests.swift */, F31F59030205A6F65B057E1A /* MatrixEntityRegexTests.swift */, F875D71347DC81EAE7687446 /* NavigationRootCoordinatorTests.swift */, - A63A32A0627A03F00A2900FE /* NavigationSplitCoordinator.swift */, + A63A32A0627A03F00A2900FE /* NavigationSplitCoordinatorTests.swift */, 9C698E30698EC59302A8EEBD /* NavigationStackCoordinatorTests.swift */, 00A941F289F6AB876BA3361A /* OnboardingViewModelTests.swift */, 6FB31A32C93D94930B253FBF /* PermalinkBuilderTests.swift */, @@ -1740,7 +1708,6 @@ 1734A445A58ED855B977A0A8 /* TracingConfigurationTests.swift */, EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */, 0DE6C5C756E1393202BA95CD /* UserNotificationControllerTests.swift */, - A3004DFA1B10951962787D90 /* VideoPlayerViewModelTests.swift */, 53280D2292E6C9C7821773FD /* UserSession */, 7583EAC171059A86B767209F /* MediaProvider */, 7DBC911559934065993A5FF4 /* NotificationManager */, @@ -2361,7 +2328,6 @@ 679E9837ECA8D6776079D16E /* RoomScreen */, D958761758AA1110476DE6A3 /* SessionVerification */, 70B74A432C241E56A7ACE610 /* Settings */, - 285079C24A5189C48284CC47 /* VideoPlayer */, ); path = Screens; sourceTree = ""; @@ -2923,7 +2889,7 @@ DC68E866D6E664B0D2B06E74 /* MockImageCache.swift in Sources */, E9631F628251F77A24AA4BB4 /* MockMediaProxy.swift in Sources */, 981853650217B6C8ECDD998C /* NavigationRootCoordinatorTests.swift in Sources */, - FCB9B475F908765531335859 /* NavigationSplitCoordinator.swift in Sources */, + FCB9B475F908765531335859 /* NavigationSplitCoordinatorTests.swift in Sources */, 4BB282209EA82015D0DF8F89 /* NavigationStackCoordinatorTests.swift in Sources */, 1B2DADC008EE211AF1DA5292 /* NotificationManagerTests.swift in Sources */, F9F6D2883BBEBB9A3789A137 /* OnboardingViewModelTests.swift in Sources */, @@ -2946,7 +2912,6 @@ 08248D02BACA75CDC3B39A96 /* UserNotificationCenterSpy.swift in Sources */, 8196A2E71ACC902DD69F24EE /* UserNotificationControllerTests.swift in Sources */, 81A7C020CB5F6232242A8414 /* UserSessionTests.swift in Sources */, - 1504CE9A609A348D90B69E47 /* VideoPlayerViewModelTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3249,11 +3214,6 @@ 978BB24F2A5D31EE59EEC249 /* UserSessionProtocol.swift in Sources */, 7E91BAC17963ED41208F489B /* UserSessionStore.swift in Sources */, AC69B6DF15FC451AB2945036 /* UserSessionStoreProtocol.swift in Sources */, - D3E603A5E9D529CF293E1BF9 /* VideoPlayerCoordinator.swift in Sources */, - 5E540CAEF764D7FBD8D80776 /* VideoPlayerModels.swift in Sources */, - CBF64DE774298D773DBD5354 /* VideoPlayerScreen.swift in Sources */, - 19ED6CF7FDBB1158692D101C /* VideoPlayerViewModel.swift in Sources */, - C94A6048C654B01163AE1BF1 /* VideoPlayerViewModelProtocol.swift in Sources */, 36C10EDEDC0466E3A9D63132 /* VideoRoomTimelineItem.swift in Sources */, 64F43D7390DA2A0AFD6BA911 /* VideoRoomTimelineView.swift in Sources */, 6FC10A00D268FCD48B631E37 /* ViewFrameReader.swift in Sources */, diff --git a/ElementX/Sources/Application/Navigation/NavigationCoordinators.swift b/ElementX/Sources/Application/Navigation/NavigationCoordinators.swift index e5cb52f71..8923283ef 100644 --- a/ElementX/Sources/Application/Navigation/NavigationCoordinators.swift +++ b/ElementX/Sources/Application/Navigation/NavigationCoordinators.swift @@ -90,6 +90,28 @@ class NavigationSplitCoordinator: CoordinatorProtocol, ObservableObject, CustomS sheetModule?.coordinator } + @Published fileprivate var fullScreenCoverModule: NavigationModule? { + didSet { + if let oldValue { + logPresentationChange("Remove fullscreen cover", oldValue) + oldValue.coordinator.stop() + oldValue.dismissalCallback?() + } + + if let fullScreenCoverModule { + logPresentationChange("Set fullscreen cover", fullScreenCoverModule) + fullScreenCoverModule.coordinator.start() + } + + updateCompactLayoutComponents() + } + } + + /// The currently displayed fullscreen cover coordinator + var fullScreenCoverCoordinator: (any CoordinatorProtocol)? { + fullScreenCoverModule?.coordinator + } + @Published fileprivate var compactLayoutRootModule: NavigationModule? var compactLayoutRootCoordinator: (any CoordinatorProtocol)? { @@ -148,6 +170,19 @@ class NavigationSplitCoordinator: CoordinatorProtocol, ObservableObject, CustomS sheetModule = NavigationModule(coordinator, dismissalCallback: dismissalCallback) } + + /// Present a fullscreen cover on top of the split view + /// - Parameters: + /// - coordinator: the coordinator to display + /// - dismissalCallback: called when the fullscreen cover has been dismissed, programatically or otherwise + func setFullScreenCoverCoordinator(_ coordinator: (any CoordinatorProtocol)?, dismissalCallback: (() -> Void)? = nil) { + guard let coordinator else { + fullScreenCoverModule = nil + return + } + + fullScreenCoverModule = NavigationModule(coordinator, dismissalCallback: dismissalCallback) + } // MARK: - CoordinatorProtocol @@ -301,6 +336,11 @@ private struct NavigationSplitCoordinatorView: View { // through the NavigationSplitCoordinator as well. .sheet(item: $navigationSplitCoordinator.sheetModule) { module in module.coordinator.toPresentable() + .tint(.element.accent) + } + .fullScreenCover(item: $navigationSplitCoordinator.fullScreenCoverModule) { module in + module.coordinator.toPresentable() + .tint(.element.accent) } } @@ -389,6 +429,31 @@ class NavigationStackCoordinator: ObservableObject, CoordinatorProtocol, CustomS return sheetModule?.coordinator } + @Published fileprivate var fullScreenCoverModule: NavigationModule? { + didSet { + if let oldValue { + logPresentationChange("Remove fullscreen cover", oldValue) + oldValue.coordinator.stop() + oldValue.dismissalCallback?() + } + + if let fullScreenCoverModule { + logPresentationChange("Set fullscreen cover", fullScreenCoverModule) + fullScreenCoverModule.coordinator.start() + } + } + } + + // The currently presented fullscreen cover coordinator + // Fullscreen covers will be presented through the NavigationSplitCoordinator if provided + var fullScreenCoverCoordinator: (any CoordinatorProtocol)? { + if let navigationSplitCoordinator { + return navigationSplitCoordinator.fullScreenCoverCoordinator + } + + return fullScreenCoverModule?.coordinator + } + @Published fileprivate var stackModules = [NavigationModule]() { didSet { let diffs = stackModules.difference(from: oldValue) @@ -488,6 +553,25 @@ class NavigationStackCoordinator: ObservableObject, CoordinatorProtocol, CustomS sheetModule = NavigationModule(coordinator, dismissalCallback: dismissalCallback) } + /// Present a fullscreen cover on top of the stack. If this NavigationStackCoordinator is embedded within a NavigationSplitCoordinator + /// then the presentation will be proxied to the split + /// - Parameters: + /// - coordinator: the coordinator to display + /// - dismissalCallback: called when the fullscreen cover has been dismissed, programatically or otherwise + func setFullScreenCoverCoordinator(_ coordinator: (any CoordinatorProtocol)?, dismissalCallback: (() -> Void)? = nil) { + if let navigationSplitCoordinator { + navigationSplitCoordinator.setFullScreenCoverCoordinator(coordinator, dismissalCallback: dismissalCallback) + return + } + + guard let coordinator else { + fullScreenCoverModule = nil + return + } + + fullScreenCoverModule = NavigationModule(coordinator, dismissalCallback: dismissalCallback) + } + // MARK: - CoordinatorProtocol func toPresentable() -> AnyView { @@ -524,6 +608,11 @@ private struct NavigationStackCoordinatorView: View { } .sheet(item: $navigationStackCoordinator.sheetModule) { module in module.coordinator.toPresentable() + .tint(.element.accent) + } + .fullScreenCover(item: $navigationStackCoordinator.fullScreenCoverModule) { module in + module.coordinator.toPresentable() + .tint(.element.accent) } } } diff --git a/ElementX/Sources/Screens/Authentication/LoginScreen/LoginHomeserver.swift b/ElementX/Sources/Screens/Authentication/LoginScreen/LoginHomeserver.swift index 786576593..3321f307e 100644 --- a/ElementX/Sources/Screens/Authentication/LoginScreen/LoginHomeserver.swift +++ b/ElementX/Sources/Screens/Authentication/LoginScreen/LoginHomeserver.swift @@ -64,10 +64,7 @@ extension LoginHomeserver { /// A mock homeserver that supports only supports authentication via a single SSO provider. static var mockOIDC: LoginHomeserver { - guard let issuerURL = URL(string: "https://auth.company.com") else { - fatalError("This shoud never fail parsing") - } - + let issuerURL = URL(staticString: "https://auth.company.com") return LoginHomeserver(address: "company.com", loginMode: .oidc(issuerURL)) } diff --git a/ElementX/Sources/Screens/FilePreview/View/FilePreviewScreen.swift b/ElementX/Sources/Screens/FilePreview/View/FilePreviewScreen.swift index 838b35044..4c03d0715 100644 --- a/ElementX/Sources/Screens/FilePreview/View/FilePreviewScreen.swift +++ b/ElementX/Sources/Screens/FilePreview/View/FilePreviewScreen.swift @@ -22,19 +22,27 @@ struct FilePreviewScreen: View { @ObservedObject var context: FilePreviewViewModel.Context var body: some View { - PreviewController(fileURL: context.viewState.fileURL, title: context.viewState.title) - .ignoresSafeArea(.all, edges: [.horizontal, .bottom]) - .navigationTitle(ElementL10n.attachmentTypeFile) + PreviewView(context: context, + fileURL: context.viewState.fileURL, + title: context.viewState.title) + .ignoresSafeArea() } } -private struct PreviewController: UIViewControllerRepresentable { +private struct PreviewView: UIViewControllerRepresentable { + let context: FilePreviewViewModel.Context let fileURL: URL let title: String? func makeUIViewController(context: Context) -> UINavigationController { let controller = QLPreviewController() controller.dataSource = context.coordinator + + let doneButton = UIBarButtonItem(title: "Done", + style: .done, + target: context.coordinator, + action: #selector(Coordinator.done)) + controller.navigationItem.rightBarButtonItem = doneButton return UINavigationController(rootViewController: controller) } @@ -42,22 +50,28 @@ private struct PreviewController: UIViewControllerRepresentable { func updateUIViewController(_ uiViewController: UINavigationController, context: Context) { } func makeCoordinator() -> Coordinator { - Coordinator(parent: self) + Coordinator(view: self) } + + class Coordinator: NSObject, QLPreviewControllerDataSource { + let view: PreviewView - class Coordinator: QLPreviewControllerDataSource { - let parent: PreviewController - - init(parent: PreviewController) { - self.parent = parent + init(view: PreviewView) { + self.view = view } + @objc func done() { + Task { await view.context.send(viewAction: .cancel) } + } + + // MARK: - QLPreviewControllerDataSource + func numberOfPreviewItems(in controller: QLPreviewController) -> Int { 1 } func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem { - PreviewItem(previewItemURL: parent.fileURL, previewItemTitle: parent.title) + PreviewItem(previewItemURL: view.fileURL, previewItemTitle: view.title) } } } diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenCoordinator.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenCoordinator.swift index 3fff580cd..9b5071095 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenCoordinator.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenCoordinator.swift @@ -55,9 +55,7 @@ final class RoomScreenCoordinator: CoordinatorProtocol { switch result { case .displayRoomDetails: self.displayRoomDetails() - case .displayVideo(let videoURL): - self.displayVideo(for: videoURL) - case .displayFile(let fileURL, let title): + case .displayVideo(let fileURL, let title), .displayFile(let fileURL, let title): self.displayFile(for: fileURL, with: title) case .displayEmojiPicker(let itemId): self.displayEmojiPickerScreen(for: itemId) @@ -81,25 +79,14 @@ final class RoomScreenCoordinator: CoordinatorProtocol { // MARK: - Private - private func displayVideo(for videoURL: URL) { - let params = VideoPlayerCoordinatorParameters(videoURL: videoURL) - let coordinator = VideoPlayerCoordinator(parameters: params) - - coordinator.callback = { [weak self] _ in - self?.navigationStackCoordinator.pop() - } - - navigationStackCoordinator.push(coordinator) - } - private func displayFile(for fileURL: URL, with title: String?) { let params = FilePreviewCoordinatorParameters(fileURL: fileURL, title: title) let coordinator = FilePreviewCoordinator(parameters: params) coordinator.callback = { [weak self] _ in - self?.navigationStackCoordinator.pop() + self?.navigationStackCoordinator.setFullScreenCoverCoordinator(nil) } - navigationStackCoordinator.push(coordinator) + navigationStackCoordinator.setFullScreenCoverCoordinator(coordinator) } private func displayEmojiPickerScreen(for itemId: String) { diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift index a40d3e298..fec098a41 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift @@ -19,7 +19,7 @@ import UIKit enum RoomScreenViewModelAction { case displayRoomDetails - case displayVideo(videoURL: URL) + case displayVideo(videoURL: URL, title: String?) case displayFile(fileURL: URL, title: String?) case displayEmojiPicker(itemId: String) } diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift index 11e261583..e3fb1e45d 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift @@ -140,8 +140,8 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol let action = await timelineController.processItemTap(itemId) switch action { - case .displayVideo(let videoURL): - callback?(.displayVideo(videoURL: videoURL)) + case .displayVideo(let videoURL, let title): + callback?(.displayVideo(videoURL: videoURL, title: title)) case .displayFile(let fileURL, let title): callback?(.displayFile(fileURL: fileURL, title: title)) case .none: diff --git a/ElementX/Sources/Screens/VideoPlayer/VideoPlayerCoordinator.swift b/ElementX/Sources/Screens/VideoPlayer/VideoPlayerCoordinator.swift deleted file mode 100644 index ae3f2ee29..000000000 --- a/ElementX/Sources/Screens/VideoPlayer/VideoPlayerCoordinator.swift +++ /dev/null @@ -1,83 +0,0 @@ -// -// Copyright 2022 New Vector Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import AVKit -import SwiftUI - -struct VideoPlayerCoordinatorParameters { - let videoURL: URL -} - -enum VideoPlayerCoordinatorAction { - case cancel -} - -final class VideoPlayerCoordinator: CoordinatorProtocol { - private let parameters: VideoPlayerCoordinatorParameters - private var viewModel: VideoPlayerViewModelProtocol - - var callback: ((VideoPlayerCoordinatorAction) -> Void)? - - init(parameters: VideoPlayerCoordinatorParameters) { - self.parameters = parameters - - viewModel = VideoPlayerViewModel(videoURL: parameters.videoURL, - autoplay: UIApplication.shared.applicationState == .active) - } - - // MARK: - Public - - func start() { - configureAudioSession(.sharedInstance()) - - viewModel.callback = { [weak self] action in - guard let self else { return } - MXLog.debug("VideoPlayerViewModel did complete with result: \(action).") - switch action { - case .cancel: - self.callback?(.cancel) - } - } - } - - func stop() { - deconfigureAudioSession(.sharedInstance()) - } - - func toPresentable() -> AnyView { - AnyView(VideoPlayerScreen(context: viewModel.context)) - } - - // MARK: - Private - - private func configureAudioSession(_ session: AVAudioSession) { - do { - try session.setCategory(.playback, - mode: .default) - try session.setActive(true) - } catch { - MXLog.debug("Configure audio session failed: \(error)") - } - } - - private func deconfigureAudioSession(_ session: AVAudioSession) { - do { - try session.setActive(false, options: .notifyOthersOnDeactivation) - } catch { - MXLog.debug("Deconfigure audio session failed: \(error)") - } - } -} diff --git a/ElementX/Sources/Screens/VideoPlayer/VideoPlayerModels.swift b/ElementX/Sources/Screens/VideoPlayer/VideoPlayerModels.swift deleted file mode 100644 index c2aaa51f6..000000000 --- a/ElementX/Sources/Screens/VideoPlayer/VideoPlayerModels.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright 2022 New Vector Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation - -enum VideoPlayerViewModelAction { - case cancel -} - -struct VideoPlayerViewState: BindableState { - let videoURL: URL - let autoplay: Bool -} - -enum VideoPlayerViewAction { - case cancel -} diff --git a/ElementX/Sources/Screens/VideoPlayer/VideoPlayerViewModel.swift b/ElementX/Sources/Screens/VideoPlayer/VideoPlayerViewModel.swift deleted file mode 100644 index abb18c176..000000000 --- a/ElementX/Sources/Screens/VideoPlayer/VideoPlayerViewModel.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright 2022 New Vector Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import SwiftUI - -typealias VideoPlayerViewModelType = StateStoreViewModel - -class VideoPlayerViewModel: VideoPlayerViewModelType, VideoPlayerViewModelProtocol { - var callback: ((VideoPlayerViewModelAction) -> Void)? - - init(videoURL: URL, autoplay: Bool = true) { - super.init(initialViewState: VideoPlayerViewState(videoURL: videoURL, - autoplay: autoplay)) - } - - override func process(viewAction: VideoPlayerViewAction) async { - switch viewAction { - case .cancel: - callback?(.cancel) - } - } -} diff --git a/ElementX/Sources/Screens/VideoPlayer/VideoPlayerViewModelProtocol.swift b/ElementX/Sources/Screens/VideoPlayer/VideoPlayerViewModelProtocol.swift deleted file mode 100644 index 8e0311d70..000000000 --- a/ElementX/Sources/Screens/VideoPlayer/VideoPlayerViewModelProtocol.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright 2022 New Vector Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation - -@MainActor -protocol VideoPlayerViewModelProtocol { - var callback: ((VideoPlayerViewModelAction) -> Void)? { get set } - var context: VideoPlayerViewModelType.Context { get } -} diff --git a/ElementX/Sources/Screens/VideoPlayer/View/VideoPlayerScreen.swift b/ElementX/Sources/Screens/VideoPlayer/View/VideoPlayerScreen.swift deleted file mode 100644 index 859c895bb..000000000 --- a/ElementX/Sources/Screens/VideoPlayer/View/VideoPlayerScreen.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright 2022 New Vector Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import AVKit -import SwiftUI - -struct VideoPlayerScreen: View { - @ObservedObject var context: VideoPlayerViewModel.Context - - var body: some View { - VideoPlayer(player: player()) - .ignoresSafeArea(.all, edges: [.horizontal, .bottom]) - .navigationTitle(ElementL10n.a11yVideo) - } - - private func player() -> AVPlayer { - let player = AVPlayer(url: context.viewState.videoURL) - if context.viewState.autoplay { - player.play() - } - return player - } -} - -// MARK: - Previews - -struct VideoPlayer_Previews: PreviewProvider { - static var previews: some View { - Group { - let viewModel = VideoPlayerViewModel(videoURL: URL(staticString: "https://storage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"), - autoplay: false) - VideoPlayerScreen(context: viewModel.context) - } - .tint(.element.accent) - } -} diff --git a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift index 7ae617ec6..057fb429c 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift @@ -127,7 +127,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol { return .none } if let videoURL = item.cachedVideoURL { - return .displayVideo(videoURL: videoURL) + return .displayVideo(videoURL: videoURL, title: item.text) } return .none case let item as FileRoomTimelineItem: diff --git a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerProtocol.swift b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerProtocol.swift index e9ec828cb..f265c7543 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerProtocol.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerProtocol.swift @@ -26,7 +26,7 @@ enum RoomTimelineControllerCallback { } enum RoomTimelineControllerAction { - case displayVideo(videoURL: URL) + case displayVideo(videoURL: URL, title: String?) case displayFile(fileURL: URL, title: String?) case none } diff --git a/UnitTests/Sources/MediaProvider/MediaProviderTests.swift b/UnitTests/Sources/MediaProvider/MediaProviderTests.swift index fbe4c08a0..65bea2111 100644 --- a/UnitTests/Sources/MediaProvider/MediaProviderTests.swift +++ b/UnitTests/Sources/MediaProvider/MediaProviderTests.swift @@ -168,7 +168,7 @@ final class MediaProviderTests: XCTestCase { } func test_whenFileFromSourceWithSource_correctValuesAreReturned() throws { - let expectedURL = try XCTUnwrap(URL(string: "some_url")) + let expectedURL = URL(filePath: "/some/file/path") fileCache.fileURLToReturn = expectedURL let url = mediaProvider.fileFromSource(MediaSourceProxy(urlString: "test/test1"), fileExtension: "png") XCTAssertEqual(fileCache.fileKey, "test1") @@ -177,7 +177,7 @@ final class MediaProviderTests: XCTestCase { } func test_whenLoadFileFromSourceAndFileFromSourceExists_urlIsReturned() async throws { - let expectedURL = try XCTUnwrap(URL(string: "some_url")) + let expectedURL = URL(filePath: "/some/file/path") let expectedResult: Result = .success(expectedURL) fileCache.fileURLToReturn = expectedURL let result = await mediaProvider.loadFileFromSource(MediaSourceProxy(urlString: "test/test1"), fileExtension: "png") @@ -185,7 +185,7 @@ final class MediaProviderTests: XCTestCase { } func test_whenLoadFileFromSourceAndNoFileFromSourceExists_mediaLoadedFromSource() async throws { - let expectedURL = try XCTUnwrap(URL(string: "some_url")) + let expectedURL = URL(filePath: "/some/file/path") let expectedResult: Result = .success(expectedURL) mediaProxy.mediaContentData = try loadTestImage().pngData() fileCache.storeURLToReturn = expectedURL @@ -217,14 +217,14 @@ final class MediaProviderTests: XCTestCase { } func test_whenFileFromURLString_correctURLIsReturned() throws { - let expectedURL = try XCTUnwrap(URL(string: "some_url")) + let expectedURL = URL(filePath: "/some/file/path") fileCache.fileURLToReturn = expectedURL let url = mediaProvider.fileFromURLString("test/test1", fileExtension: "png") XCTAssertEqual(url?.absoluteString, expectedURL.absoluteString) } func test_whenLoadFileFromURLString_correctURLIsReturned() async throws { - let expectedURL = try XCTUnwrap(URL(string: "some_url")) + let expectedURL = URL(filePath: "/some/file/path") let expectedResult: Result = .success(expectedURL) fileCache.fileURLToReturn = expectedURL let result = await mediaProvider.loadFileFromURLString("test/test1", fileExtension: "png") diff --git a/UnitTests/Sources/NavigationSplitCoordinator.swift b/UnitTests/Sources/NavigationSplitCoordinatorTests.swift similarity index 100% rename from UnitTests/Sources/NavigationSplitCoordinator.swift rename to UnitTests/Sources/NavigationSplitCoordinatorTests.swift diff --git a/UnitTests/Sources/VideoPlayerViewModelTests.swift b/UnitTests/Sources/VideoPlayerViewModelTests.swift deleted file mode 100644 index 3cc58f800..000000000 --- a/UnitTests/Sources/VideoPlayerViewModelTests.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright 2022 New Vector Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import XCTest - -@testable import ElementX - -@MainActor -class VideoPlayerScreenViewModelTests: XCTestCase { - var viewModel: VideoPlayerViewModelProtocol! - var context: VideoPlayerViewModelType.Context! - - @MainActor override func setUpWithError() throws { - viewModel = VideoPlayerViewModel(videoURL: URL(staticString: "https://storage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"), autoplay: true) - context = viewModel.context - } - - @MainActor func testCancel() async throws { - var correctResult = false - viewModel.callback = { result in - switch result { - case .cancel: - correctResult = true - } - } - - context.send(viewAction: .cancel) - await Task.yield() - XCTAssert(correctResult) - } -} diff --git a/changelog.d/418.change b/changelog.d/418.change new file mode 100644 index 000000000..17ab2af96 --- /dev/null +++ b/changelog.d/418.change @@ -0,0 +1 @@ +Use QuickLook previews for video and present previews full screen (doesn't address gestures yet). \ No newline at end of file