Add playback controls to videos
This commit includes several UX changes to give users better control over video playback. It also, by design, work arounds a SwiftUI quirk* Here are the changes to the UX: 1. Videos on the feed only have a mute/unmute button 2. When the user clicks on the video, they are taken to a full screen carousel view (similar to when you click on an image) 3. The full-screen carousel view shows all video playback controls (through a specific SwiftUI hack) 4. If the carousel has multiple videos/images, the user can swipe between them normally as expected Other UI changes that were made: - The full screen carousel now uses dark mode (black background, white close button) * The SwiftUI quirk is that when video views are placed within a TabView with ".page" tab view style, the tabview consumes most of the user gestures, making the video playback controls unusable. Changelog-Changed: Improve UX around video playback Signed-off-by: Daniel D’Aquino <daniel@daquino.me> Link: 20240318222048.14226-3-daniel@daquino.me Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
committed by
William Casarin
parent
98eddf1337
commit
671b0b67ce
@@ -377,7 +377,7 @@
|
|||||||
4CFD502F2A2DA45800A229DB /* MediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFD502E2A2DA45800A229DB /* MediaView.swift */; };
|
4CFD502F2A2DA45800A229DB /* MediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFD502E2A2DA45800A229DB /* MediaView.swift */; };
|
||||||
4CFF8F5929C9FD1E008DB934 /* DamusPurpleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF8F5829C9FD1E008DB934 /* DamusPurpleView.swift */; };
|
4CFF8F5929C9FD1E008DB934 /* DamusPurpleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF8F5829C9FD1E008DB934 /* DamusPurpleView.swift */; };
|
||||||
4CFF8F6329CC9AD7008DB934 /* ImageContextMenuModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF8F6229CC9AD7008DB934 /* ImageContextMenuModifier.swift */; };
|
4CFF8F6329CC9AD7008DB934 /* ImageContextMenuModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF8F6229CC9AD7008DB934 /* ImageContextMenuModifier.swift */; };
|
||||||
4CFF8F6729CC9E3A008DB934 /* ImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF8F6629CC9E3A008DB934 /* ImageView.swift */; };
|
4CFF8F6729CC9E3A008DB934 /* FullScreenCarouselView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF8F6629CC9E3A008DB934 /* FullScreenCarouselView.swift */; };
|
||||||
4CFF8F6929CC9ED1008DB934 /* ImageContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF8F6829CC9ED1008DB934 /* ImageContainerView.swift */; };
|
4CFF8F6929CC9ED1008DB934 /* ImageContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF8F6829CC9ED1008DB934 /* ImageContainerView.swift */; };
|
||||||
4CFF8F6B29CD0079008DB934 /* RepostedEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF8F6A29CD0079008DB934 /* RepostedEvent.swift */; };
|
4CFF8F6B29CD0079008DB934 /* RepostedEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF8F6A29CD0079008DB934 /* RepostedEvent.swift */; };
|
||||||
4CFF8F6D29CD022E008DB934 /* WideEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF8F6C29CD022E008DB934 /* WideEventView.swift */; };
|
4CFF8F6D29CD022E008DB934 /* WideEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF8F6C29CD022E008DB934 /* WideEventView.swift */; };
|
||||||
@@ -388,7 +388,7 @@
|
|||||||
504323A72A34915F006AE6DC /* RelayModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504323A62A34915F006AE6DC /* RelayModel.swift */; };
|
504323A72A34915F006AE6DC /* RelayModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504323A62A34915F006AE6DC /* RelayModel.swift */; };
|
||||||
504323A92A3495B6006AE6DC /* RelayModelCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504323A82A3495B6006AE6DC /* RelayModelCache.swift */; };
|
504323A92A3495B6006AE6DC /* RelayModelCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504323A82A3495B6006AE6DC /* RelayModelCache.swift */; };
|
||||||
5053ACA72A56DF3B00851AE3 /* DeveloperSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5053ACA62A56DF3B00851AE3 /* DeveloperSettingsView.swift */; };
|
5053ACA72A56DF3B00851AE3 /* DeveloperSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5053ACA62A56DF3B00851AE3 /* DeveloperSettingsView.swift */; };
|
||||||
50A16FFB2AA6C06600DFEC1F /* AVPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFA2AA6C06600DFEC1F /* AVPlayerView.swift */; };
|
50A16FFB2AA6C06600DFEC1F /* DamusAVPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFA2AA6C06600DFEC1F /* DamusAVPlayerView.swift */; };
|
||||||
50A16FFD2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFC2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift */; };
|
50A16FFD2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFC2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift */; };
|
||||||
50A16FFF2AA76A0900DFEC1F /* VideoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFE2AA76A0900DFEC1F /* VideoController.swift */; };
|
50A16FFF2AA76A0900DFEC1F /* VideoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFE2AA76A0900DFEC1F /* VideoController.swift */; };
|
||||||
50A50A8D29A09E1C00C01BE7 /* RequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A50A8C29A09E1C00C01BE7 /* RequestTests.swift */; };
|
50A50A8D29A09E1C00C01BE7 /* RequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A50A8C29A09E1C00C01BE7 /* RequestTests.swift */; };
|
||||||
@@ -433,8 +433,6 @@
|
|||||||
B59CAD4D2B688D1000677E8B /* MutelistManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533694D2B66D791008A805E /* MutelistManager.swift */; };
|
B59CAD4D2B688D1000677E8B /* MutelistManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533694D2B66D791008A805E /* MutelistManager.swift */; };
|
||||||
B5A75C2A2B546D94007AFBC0 /* MuteItemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A75C292B546D94007AFBC0 /* MuteItemTests.swift */; };
|
B5A75C2A2B546D94007AFBC0 /* MuteItemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A75C292B546D94007AFBC0 /* MuteItemTests.swift */; };
|
||||||
B5B4D1432B37D47600844320 /* NdbExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5B4D1422B37D47600844320 /* NdbExtensions.swift */; };
|
B5B4D1432B37D47600844320 /* NdbExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5B4D1422B37D47600844320 /* NdbExtensions.swift */; };
|
||||||
BA0F0A6F2B36207E001641B2 /* CameraMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA0F0A6E2B36207E001641B2 /* CameraMediaView.swift */; };
|
|
||||||
BA10192F2B449556009C57DA /* CameraPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA10192E2B449556009C57DA /* CameraPreview.swift */; };
|
|
||||||
B5C60C202B530D5100C5ECA7 /* MuteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C60C1F2B530D5100C5ECA7 /* MuteItem.swift */; };
|
B5C60C202B530D5100C5ECA7 /* MuteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C60C1F2B530D5100C5ECA7 /* MuteItem.swift */; };
|
||||||
B5C60C212B530D5600C5ECA7 /* MuteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C60C1F2B530D5100C5ECA7 /* MuteItem.swift */; };
|
B5C60C212B530D5600C5ECA7 /* MuteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C60C1F2B530D5100C5ECA7 /* MuteItem.swift */; };
|
||||||
B5C60C232B532A8700C5ECA7 /* DamusDuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C60C222B532A8700C5ECA7 /* DamusDuration.swift */; };
|
B5C60C232B532A8700C5ECA7 /* DamusDuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C60C222B532A8700C5ECA7 /* DamusDuration.swift */; };
|
||||||
@@ -1300,7 +1298,7 @@
|
|||||||
4CFD502E2A2DA45800A229DB /* MediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaView.swift; sourceTree = "<group>"; };
|
4CFD502E2A2DA45800A229DB /* MediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaView.swift; sourceTree = "<group>"; };
|
||||||
4CFF8F5829C9FD1E008DB934 /* DamusPurpleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleView.swift; sourceTree = "<group>"; };
|
4CFF8F5829C9FD1E008DB934 /* DamusPurpleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleView.swift; sourceTree = "<group>"; };
|
||||||
4CFF8F6229CC9AD7008DB934 /* ImageContextMenuModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageContextMenuModifier.swift; sourceTree = "<group>"; };
|
4CFF8F6229CC9AD7008DB934 /* ImageContextMenuModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageContextMenuModifier.swift; sourceTree = "<group>"; };
|
||||||
4CFF8F6629CC9E3A008DB934 /* ImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageView.swift; sourceTree = "<group>"; };
|
4CFF8F6629CC9E3A008DB934 /* FullScreenCarouselView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenCarouselView.swift; sourceTree = "<group>"; };
|
||||||
4CFF8F6829CC9ED1008DB934 /* ImageContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageContainerView.swift; sourceTree = "<group>"; };
|
4CFF8F6829CC9ED1008DB934 /* ImageContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageContainerView.swift; sourceTree = "<group>"; };
|
||||||
4CFF8F6A29CD0079008DB934 /* RepostedEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepostedEvent.swift; sourceTree = "<group>"; };
|
4CFF8F6A29CD0079008DB934 /* RepostedEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepostedEvent.swift; sourceTree = "<group>"; };
|
||||||
4CFF8F6C29CD022E008DB934 /* WideEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WideEventView.swift; sourceTree = "<group>"; };
|
4CFF8F6C29CD022E008DB934 /* WideEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WideEventView.swift; sourceTree = "<group>"; };
|
||||||
@@ -1311,7 +1309,7 @@
|
|||||||
504323A62A34915F006AE6DC /* RelayModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayModel.swift; sourceTree = "<group>"; };
|
504323A62A34915F006AE6DC /* RelayModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayModel.swift; sourceTree = "<group>"; };
|
||||||
504323A82A3495B6006AE6DC /* RelayModelCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayModelCache.swift; sourceTree = "<group>"; };
|
504323A82A3495B6006AE6DC /* RelayModelCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayModelCache.swift; sourceTree = "<group>"; };
|
||||||
5053ACA62A56DF3B00851AE3 /* DeveloperSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperSettingsView.swift; sourceTree = "<group>"; };
|
5053ACA62A56DF3B00851AE3 /* DeveloperSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperSettingsView.swift; sourceTree = "<group>"; };
|
||||||
50A16FFA2AA6C06600DFEC1F /* AVPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVPlayerView.swift; sourceTree = "<group>"; };
|
50A16FFA2AA6C06600DFEC1F /* DamusAVPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusAVPlayerView.swift; sourceTree = "<group>"; };
|
||||||
50A16FFC2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusVideoPlayerViewModel.swift; sourceTree = "<group>"; };
|
50A16FFC2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusVideoPlayerViewModel.swift; sourceTree = "<group>"; };
|
||||||
50A16FFE2AA76A0900DFEC1F /* VideoController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoController.swift; sourceTree = "<group>"; };
|
50A16FFE2AA76A0900DFEC1F /* VideoController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoController.swift; sourceTree = "<group>"; };
|
||||||
50A50A8C29A09E1C00C01BE7 /* RequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestTests.swift; sourceTree = "<group>"; };
|
50A50A8C29A09E1C00C01BE7 /* RequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestTests.swift; sourceTree = "<group>"; };
|
||||||
@@ -1355,8 +1353,6 @@
|
|||||||
B57B4C652B312C3700A232C0 /* NostrAuth.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NostrAuth.swift; sourceTree = "<group>"; };
|
B57B4C652B312C3700A232C0 /* NostrAuth.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NostrAuth.swift; sourceTree = "<group>"; };
|
||||||
B5A75C292B546D94007AFBC0 /* MuteItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MuteItemTests.swift; sourceTree = "<group>"; usesTabs = 0; };
|
B5A75C292B546D94007AFBC0 /* MuteItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MuteItemTests.swift; sourceTree = "<group>"; usesTabs = 0; };
|
||||||
B5B4D1422B37D47600844320 /* NdbExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NdbExtensions.swift; sourceTree = "<group>"; usesTabs = 0; };
|
B5B4D1422B37D47600844320 /* NdbExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NdbExtensions.swift; sourceTree = "<group>"; usesTabs = 0; };
|
||||||
BA0F0A6E2B36207E001641B2 /* CameraMediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraMediaView.swift; sourceTree = "<group>"; };
|
|
||||||
BA10192E2B449556009C57DA /* CameraPreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraPreview.swift; sourceTree = "<group>"; };
|
|
||||||
B5C60C1F2B530D5100C5ECA7 /* MuteItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MuteItem.swift; sourceTree = "<group>"; usesTabs = 0; };
|
B5C60C1F2B530D5100C5ECA7 /* MuteItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MuteItem.swift; sourceTree = "<group>"; usesTabs = 0; };
|
||||||
B5C60C222B532A8700C5ECA7 /* DamusDuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusDuration.swift; sourceTree = "<group>"; usesTabs = 0; };
|
B5C60C222B532A8700C5ECA7 /* DamusDuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusDuration.swift; sourceTree = "<group>"; usesTabs = 0; };
|
||||||
BA3759892ABCCDE30018D73B /* ImageResizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageResizer.swift; sourceTree = "<group>"; };
|
BA3759892ABCCDE30018D73B /* ImageResizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageResizer.swift; sourceTree = "<group>"; };
|
||||||
@@ -1733,7 +1729,7 @@
|
|||||||
4C1A9A2929DDF54400516EAC /* DamusVideoPlayer.swift */,
|
4C1A9A2929DDF54400516EAC /* DamusVideoPlayer.swift */,
|
||||||
50A16FFC2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift */,
|
50A16FFC2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift */,
|
||||||
50A16FFE2AA76A0900DFEC1F /* VideoController.swift */,
|
50A16FFE2AA76A0900DFEC1F /* VideoController.swift */,
|
||||||
50A16FFA2AA6C06600DFEC1F /* AVPlayerView.swift */,
|
50A16FFA2AA6C06600DFEC1F /* DamusAVPlayerView.swift */,
|
||||||
);
|
);
|
||||||
path = Video;
|
path = Video;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -2659,7 +2655,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
4CFF8F6229CC9AD7008DB934 /* ImageContextMenuModifier.swift */,
|
4CFF8F6229CC9AD7008DB934 /* ImageContextMenuModifier.swift */,
|
||||||
4CFF8F6629CC9E3A008DB934 /* ImageView.swift */,
|
4CFF8F6629CC9E3A008DB934 /* FullScreenCarouselView.swift */,
|
||||||
6439E013296790CF0020672B /* ProfilePicImageView.swift */,
|
6439E013296790CF0020672B /* ProfilePicImageView.swift */,
|
||||||
4CFF8F6829CC9ED1008DB934 /* ImageContainerView.swift */,
|
4CFF8F6829CC9ED1008DB934 /* ImageContainerView.swift */,
|
||||||
4CFD502E2A2DA45800A229DB /* MediaView.swift */,
|
4CFD502E2A2DA45800A229DB /* MediaView.swift */,
|
||||||
@@ -2744,14 +2740,6 @@
|
|||||||
path = DamusNotificationService;
|
path = DamusNotificationService;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
E06336A72B7582D600A88E6B /* Assets */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
E06336A82B7582E000A88E6B /* img_with_location.jpeg */,
|
|
||||||
);
|
|
||||||
path = Assets;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
D7CBD1D22B8D21C100BFD889 /* Extensions */ = {
|
D7CBD1D22B8D21C100BFD889 /* Extensions */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -2760,6 +2748,14 @@
|
|||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
E06336A72B7582D600A88E6B /* Assets */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
E06336A82B7582E000A88E6B /* img_with_location.jpeg */,
|
||||||
|
);
|
||||||
|
path = Assets;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
F71694E82A66221E001F4053 /* Onboarding */ = {
|
F71694E82A66221E001F4053 /* Onboarding */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -3178,7 +3174,7 @@
|
|||||||
4C363A9A28283854006E126D /* Reply.swift in Sources */,
|
4C363A9A28283854006E126D /* Reply.swift in Sources */,
|
||||||
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */,
|
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */,
|
||||||
D7ADD3E02B538D4200F104C4 /* DamusPurpleURLSheetView.swift in Sources */,
|
D7ADD3E02B538D4200F104C4 /* DamusPurpleURLSheetView.swift in Sources */,
|
||||||
4CFF8F6729CC9E3A008DB934 /* ImageView.swift in Sources */,
|
4CFF8F6729CC9E3A008DB934 /* FullScreenCarouselView.swift in Sources */,
|
||||||
4CA927632A290EB10098A105 /* EventTop.swift in Sources */,
|
4CA927632A290EB10098A105 /* EventTop.swift in Sources */,
|
||||||
4C90BD18283A9EE5008EE7EF /* LoginView.swift in Sources */,
|
4C90BD18283A9EE5008EE7EF /* LoginView.swift in Sources */,
|
||||||
4CB8838B296F6E1E00DC99E7 /* NIP05Badge.swift in Sources */,
|
4CB8838B296F6E1E00DC99E7 /* NIP05Badge.swift in Sources */,
|
||||||
@@ -3416,7 +3412,7 @@
|
|||||||
4C3EA63D28FF52D600C48A62 /* bolt11.c in Sources */,
|
4C3EA63D28FF52D600C48A62 /* bolt11.c in Sources */,
|
||||||
4C9BB83129C0ED4F00FC4E37 /* DisplayName.swift in Sources */,
|
4C9BB83129C0ED4F00FC4E37 /* DisplayName.swift in Sources */,
|
||||||
7CFF6317299FEFE5005D382A /* SelectableText.swift in Sources */,
|
7CFF6317299FEFE5005D382A /* SelectableText.swift in Sources */,
|
||||||
50A16FFB2AA6C06600DFEC1F /* AVPlayerView.swift in Sources */,
|
50A16FFB2AA6C06600DFEC1F /* DamusAVPlayerView.swift in Sources */,
|
||||||
4CA352A82A76B37E003BB08B /* NewMutesNotify.swift in Sources */,
|
4CA352A82A76B37E003BB08B /* NewMutesNotify.swift in Sources */,
|
||||||
4CFF8F6929CC9ED1008DB934 /* ImageContainerView.swift in Sources */,
|
4CFF8F6929CC9ED1008DB934 /* ImageContainerView.swift in Sources */,
|
||||||
7527271E2A93FF0100214108 /* Block.swift in Sources */,
|
7527271E2A93FF0100214108 /* Block.swift in Sources */,
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ struct ImageCarousel: View {
|
|||||||
model.open_sheet = true
|
model.open_sheet = true
|
||||||
}
|
}
|
||||||
case .video(let url):
|
case .video(let url):
|
||||||
DamusVideoPlayer(url: url, video_size: $model.video_size, controller: state.video)
|
DamusVideoPlayer(url: url, video_size: $model.video_size, controller: state.video, style: .preview(on_tap: { model.open_sheet = true }))
|
||||||
.onChange(of: model.video_size) { size in
|
.onChange(of: model.video_size) { size in
|
||||||
guard let size else { return }
|
guard let size else { return }
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ struct ImageCarousel: View {
|
|||||||
}
|
}
|
||||||
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
|
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
|
||||||
.fullScreenCover(isPresented: $model.open_sheet) {
|
.fullScreenCover(isPresented: $model.open_sheet) {
|
||||||
ImageView(video_controller: state.video, urls: urls, settings: state.settings, selectedIndex: $model.selectedIndex)
|
FullScreenCarouselView(video_controller: state.video, urls: urls, settings: state.settings, selectedIndex: $model.selectedIndex)
|
||||||
}
|
}
|
||||||
.frame(height: height)
|
.frame(height: height)
|
||||||
.onChange(of: model.selectedIndex) { value in
|
.onChange(of: model.selectedIndex) { value in
|
||||||
@@ -296,7 +296,9 @@ public struct ImageFill {
|
|||||||
struct ImageCarousel_Previews: PreviewProvider {
|
struct ImageCarousel_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
let url: MediaUrl = .image(URL(string: "https://jb55.com/red-me.jpg")!)
|
let url: MediaUrl = .image(URL(string: "https://jb55.com/red-me.jpg")!)
|
||||||
ImageCarousel(state: test_damus_state, evid: test_note.id, urls: [url, url])
|
let test_video_url: MediaUrl = .video(URL(string: "http://cdn.jb55.com/s/zaps-build.mp4")!)
|
||||||
|
ImageCarousel(state: test_damus_state, evid: test_note.id, urls: [test_video_url, url])
|
||||||
|
.environmentObject(OrientationTracker())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
127
damus/Views/Images/FullScreenCarouselView.swift
Normal file
127
damus/Views/Images/FullScreenCarouselView.swift
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
//
|
||||||
|
// FullScreenCarouselView.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by William Casarin on 2023-03-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct FullScreenCarouselView: View {
|
||||||
|
let video_controller: VideoController
|
||||||
|
let urls: [MediaUrl]
|
||||||
|
|
||||||
|
@Environment(\.presentationMode) var presentationMode
|
||||||
|
|
||||||
|
@State var showMenu = true
|
||||||
|
|
||||||
|
let settings: UserSettingsStore
|
||||||
|
@Binding var selectedIndex: Int
|
||||||
|
|
||||||
|
var tabViewIndicator: some View {
|
||||||
|
HStack(spacing: 10) {
|
||||||
|
ForEach(urls.indices, id: \.self) { index in
|
||||||
|
Capsule()
|
||||||
|
.fill(index == selectedIndex ? Color.white : Color.damusMediumGrey)
|
||||||
|
.frame(width: 7, height: 7)
|
||||||
|
.onTapGesture {
|
||||||
|
selectedIndex = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
.clipShape(Capsule())
|
||||||
|
}
|
||||||
|
|
||||||
|
var background: some ShapeStyle {
|
||||||
|
if case .video = urls[safe: selectedIndex] {
|
||||||
|
return AnyShapeStyle(Color.black)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return AnyShapeStyle(.regularMaterial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var background_color: UIColor {
|
||||||
|
return .black
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ZStack {
|
||||||
|
Color(self.background_color)
|
||||||
|
.ignoresSafeArea()
|
||||||
|
|
||||||
|
TabView(selection: $selectedIndex) {
|
||||||
|
ForEach(urls.indices, id: \.self) { index in
|
||||||
|
VStack {
|
||||||
|
if case .video = urls[safe: index] {
|
||||||
|
ImageContainerView(video_controller: video_controller, url: urls[index], settings: settings)
|
||||||
|
.clipped() // SwiftUI hack from https://stackoverflow.com/a/74401288 to make playback controls show up within the TabView
|
||||||
|
.aspectRatio(contentMode: .fit)
|
||||||
|
.padding(.top, Theme.safeAreaInsets?.top)
|
||||||
|
.padding(.bottom, Theme.safeAreaInsets?.bottom)
|
||||||
|
.modifier(SwipeToDismissModifier(minDistance: 50, onDismiss: {
|
||||||
|
presentationMode.wrappedValue.dismiss()
|
||||||
|
}))
|
||||||
|
.ignoresSafeArea()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ZoomableScrollView {
|
||||||
|
ImageContainerView(video_controller: video_controller, url: urls[index], settings: settings)
|
||||||
|
.aspectRatio(contentMode: .fit)
|
||||||
|
.padding(.top, Theme.safeAreaInsets?.top)
|
||||||
|
.padding(.bottom, Theme.safeAreaInsets?.bottom)
|
||||||
|
}
|
||||||
|
.modifier(SwipeToDismissModifier(minDistance: 50, onDismiss: {
|
||||||
|
presentationMode.wrappedValue.dismiss()
|
||||||
|
}))
|
||||||
|
.ignoresSafeArea()
|
||||||
|
}
|
||||||
|
}.tag(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ignoresSafeArea()
|
||||||
|
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
|
||||||
|
.gesture(TapGesture(count: 2).onEnded {
|
||||||
|
// Prevents menu from hiding on double tap
|
||||||
|
})
|
||||||
|
.gesture(TapGesture(count: 1).onEnded {
|
||||||
|
showMenu.toggle()
|
||||||
|
})
|
||||||
|
.overlay(
|
||||||
|
GeometryReader { geo in
|
||||||
|
VStack {
|
||||||
|
if showMenu {
|
||||||
|
NavDismissBarView(showBackgroundCircle: false)
|
||||||
|
.foregroundColor(.white)
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
if (urls.count > 1) {
|
||||||
|
tabViewIndicator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.animation(.easeInOut, value: showMenu)
|
||||||
|
.padding(.bottom, geo.safeAreaInsets.bottom == 0 ? 12 : 0)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate struct ImageViewPreview: View {
|
||||||
|
@State var selectedIndex: Int = 0
|
||||||
|
let url: MediaUrl = .image(URL(string: "https://jb55.com/red-me.jpg")!)
|
||||||
|
let test_video_url: MediaUrl = .video(URL(string: "http://cdn.jb55.com/s/zaps-build.mp4")!)
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
FullScreenCarouselView(video_controller: test_damus_state.video, urls: [test_video_url, url], settings: test_damus_state.settings, selectedIndex: $selectedIndex)
|
||||||
|
.environmentObject(OrientationTracker())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ImageView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
ImageViewPreview()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,19 +43,26 @@ struct ImageContainerView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
switch url {
|
switch url {
|
||||||
case .image(let url):
|
case .image(let url):
|
||||||
Img(url: url)
|
Img(url: url)
|
||||||
case .video(let url):
|
case .video(let url):
|
||||||
DamusVideoPlayer(url: url, video_size: .constant(nil), controller: video_controller)
|
DamusVideoPlayer(url: url, video_size: .constant(nil), controller: video_controller, style: .full)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let test_image_url = URL(string: "https://jb55.com/red-me.jpg")!
|
let test_image_url = URL(string: "https://jb55.com/red-me.jpg")!
|
||||||
|
fileprivate let test_video_url = URL(string: "http://cdn.jb55.com/s/zaps-build.mp4")!
|
||||||
|
|
||||||
struct ImageContainerView_Previews: PreviewProvider {
|
struct ImageContainerView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
ImageContainerView(video_controller: test_damus_state.video, url: .image(test_image_url), settings: test_damus_state.settings)
|
Group {
|
||||||
|
ImageContainerView(video_controller: test_damus_state.video, url: .image(test_image_url), settings: test_damus_state.settings)
|
||||||
|
.previewDisplayName("Image")
|
||||||
|
ImageContainerView(video_controller: test_damus_state.video, url: .video(test_video_url), settings: test_damus_state.settings)
|
||||||
|
.previewDisplayName("Video")
|
||||||
|
}
|
||||||
|
.environmentObject(OrientationTracker())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
//
|
|
||||||
// ImageView.swift
|
|
||||||
// damus
|
|
||||||
//
|
|
||||||
// Created by William Casarin on 2023-03-23.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct ImageView: View {
|
|
||||||
let video_controller: VideoController
|
|
||||||
let urls: [MediaUrl]
|
|
||||||
|
|
||||||
@Environment(\.presentationMode) var presentationMode
|
|
||||||
|
|
||||||
@State var showMenu = true
|
|
||||||
|
|
||||||
let settings: UserSettingsStore
|
|
||||||
@Binding var selectedIndex: Int
|
|
||||||
|
|
||||||
var tabViewIndicator: some View {
|
|
||||||
HStack(spacing: 10) {
|
|
||||||
ForEach(urls.indices, id: \.self) { index in
|
|
||||||
Capsule()
|
|
||||||
.fill(index == selectedIndex ? Color(UIColor.label) : Color.secondary)
|
|
||||||
.frame(width: 7, height: 7)
|
|
||||||
.onTapGesture {
|
|
||||||
selectedIndex = index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
.background(.regularMaterial)
|
|
||||||
.clipShape(Capsule())
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
ZStack {
|
|
||||||
Color(.systemBackground)
|
|
||||||
.ignoresSafeArea()
|
|
||||||
|
|
||||||
TabView(selection: $selectedIndex) {
|
|
||||||
ForEach(urls.indices, id: \.self) { index in
|
|
||||||
ZoomableScrollView {
|
|
||||||
ImageContainerView(video_controller: video_controller, url: urls[index], settings: settings)
|
|
||||||
.aspectRatio(contentMode: .fit)
|
|
||||||
.padding(.top, Theme.safeAreaInsets?.top)
|
|
||||||
.padding(.bottom, Theme.safeAreaInsets?.bottom)
|
|
||||||
}
|
|
||||||
.modifier(SwipeToDismissModifier(minDistance: 50, onDismiss: {
|
|
||||||
presentationMode.wrappedValue.dismiss()
|
|
||||||
}))
|
|
||||||
.ignoresSafeArea()
|
|
||||||
.tag(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.ignoresSafeArea()
|
|
||||||
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
|
|
||||||
.gesture(TapGesture(count: 2).onEnded {
|
|
||||||
// Prevents menu from hiding on double tap
|
|
||||||
})
|
|
||||||
.gesture(TapGesture(count: 1).onEnded {
|
|
||||||
showMenu.toggle()
|
|
||||||
})
|
|
||||||
.overlay(
|
|
||||||
GeometryReader { geo in
|
|
||||||
VStack {
|
|
||||||
if showMenu {
|
|
||||||
NavDismissBarView()
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
if (urls.count > 1) {
|
|
||||||
tabViewIndicator
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.animation(.easeInOut, value: showMenu)
|
|
||||||
.padding(.bottom, geo.safeAreaInsets.bottom == 0 ? 12 : 0)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ImageView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
let url: MediaUrl = .image(URL(string: "https://jb55.com/red-me.jpg")!)
|
|
||||||
ImageView(video_controller: test_damus_state.video, urls: [url], settings: test_damus_state.settings, selectedIndex: Binding.constant(0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -42,16 +42,27 @@ struct ProfileImageContainerView: View {
|
|||||||
struct NavDismissBarView: View {
|
struct NavDismissBarView: View {
|
||||||
|
|
||||||
@Environment(\.presentationMode) var presentationMode
|
@Environment(\.presentationMode) var presentationMode
|
||||||
|
let showBackgroundCircle: Bool
|
||||||
|
|
||||||
|
init(showBackgroundCircle: Bool = true) {
|
||||||
|
self.showBackgroundCircle = showBackgroundCircle
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack {
|
HStack {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
presentationMode.wrappedValue.dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
}, label: {
|
}, label: {
|
||||||
Image("close")
|
if showBackgroundCircle {
|
||||||
.frame(width: 33, height: 33)
|
Image("close")
|
||||||
.background(.regularMaterial)
|
.frame(width: 33, height: 33)
|
||||||
.clipShape(Circle())
|
.background(.regularMaterial)
|
||||||
|
.clipShape(Circle())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Image("close")
|
||||||
|
.frame(width: 33, height: 33)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|||||||
@@ -9,12 +9,15 @@ import Foundation
|
|||||||
import AVKit
|
import AVKit
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct AVPlayerView: UIViewControllerRepresentable {
|
struct DamusAVPlayerView: UIViewControllerRepresentable {
|
||||||
|
|
||||||
let player: AVPlayer
|
let player: AVPlayer
|
||||||
|
var controller: AVPlayerViewController
|
||||||
|
let show_playback_controls: Bool
|
||||||
|
|
||||||
func makeUIViewController(context: Context) -> AVPlayerViewController {
|
func makeUIViewController(context: Context) -> AVPlayerViewController {
|
||||||
AVPlayerViewController()
|
self.controller.showsPlaybackControls = show_playback_controls
|
||||||
|
return self.controller
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) {
|
func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) {
|
||||||
@@ -20,10 +20,19 @@ struct DamusVideoPlayer: View {
|
|||||||
let url: URL
|
let url: URL
|
||||||
@StateObject var model: DamusVideoPlayerViewModel
|
@StateObject var model: DamusVideoPlayerViewModel
|
||||||
@EnvironmentObject private var orientationTracker: OrientationTracker
|
@EnvironmentObject private var orientationTracker: OrientationTracker
|
||||||
|
let style: Style
|
||||||
|
|
||||||
init(url: URL, video_size: Binding<CGSize?>, controller: VideoController) {
|
init(url: URL, video_size: Binding<CGSize?>, controller: VideoController, style: Style) {
|
||||||
self.url = url
|
self.url = url
|
||||||
_model = StateObject(wrappedValue: DamusVideoPlayerViewModel(url: url, video_size: video_size, controller: controller))
|
let mute: Bool?
|
||||||
|
if case .full = style {
|
||||||
|
mute = false
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mute = nil
|
||||||
|
}
|
||||||
|
_model = StateObject(wrappedValue: DamusVideoPlayerViewModel(url: url, video_size: video_size, controller: controller, mute: mute))
|
||||||
|
self.style = style
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -31,7 +40,15 @@ struct DamusVideoPlayer: View {
|
|||||||
let localFrame = geo.frame(in: .local)
|
let localFrame = geo.frame(in: .local)
|
||||||
let centerY = globalCoordinate(localX: 0, localY: localFrame.midY, localGeometry: geo).y
|
let centerY = globalCoordinate(localX: 0, localY: localFrame.midY, localGeometry: geo).y
|
||||||
ZStack {
|
ZStack {
|
||||||
AVPlayerView(player: model.player)
|
if case .full = self.style {
|
||||||
|
DamusAVPlayerView(player: model.player, controller: model.player_view_controller, show_playback_controls: true)
|
||||||
|
}
|
||||||
|
if case .preview(let on_tap) = self.style {
|
||||||
|
DamusAVPlayerView(player: model.player, controller: model.player_view_controller, show_playback_controls: false)
|
||||||
|
.simultaneousGesture(TapGesture().onEnded({
|
||||||
|
on_tap?()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
if model.is_loading {
|
if model.is_loading {
|
||||||
ProgressView()
|
ProgressView()
|
||||||
@@ -40,8 +57,10 @@ struct DamusVideoPlayer: View {
|
|||||||
.scaleEffect(CGSize(width: 1.5, height: 1.5))
|
.scaleEffect(CGSize(width: 1.5, height: 1.5))
|
||||||
}
|
}
|
||||||
|
|
||||||
if model.has_audio {
|
if case .preview = self.style {
|
||||||
mute_button
|
if model.has_audio {
|
||||||
|
mute_button
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if model.is_live {
|
if model.is_live {
|
||||||
live_indicator
|
live_indicator
|
||||||
@@ -115,9 +134,24 @@ struct DamusVideoPlayer: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Style {
|
||||||
|
/// A full video player with playback controls
|
||||||
|
case full
|
||||||
|
/// A style suitable for muted, auto-playing videos on a feed
|
||||||
|
case preview(on_tap: (() -> Void)?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
struct DamusVideoPlayer_Previews: PreviewProvider {
|
struct DamusVideoPlayer_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
DamusVideoPlayer(url: URL(string: "http://cdn.jb55.com/s/zaps-build.mp4")!, video_size: .constant(nil), controller: VideoController())
|
Group {
|
||||||
|
DamusVideoPlayer(url: URL(string: "http://cdn.jb55.com/s/zaps-build.mp4")!, video_size: .constant(nil), controller: VideoController(), style: .full)
|
||||||
|
.environmentObject(OrientationTracker())
|
||||||
|
.previewDisplayName("Full video player")
|
||||||
|
|
||||||
|
DamusVideoPlayer(url: URL(string: "http://cdn.jb55.com/s/zaps-build.mp4")!, video_size: .constant(nil), controller: VideoController(), style: .preview(on_tap: nil))
|
||||||
|
.environmentObject(OrientationTracker())
|
||||||
|
.previewDisplayName("Preview video player")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import AVFoundation
|
import AVFoundation
|
||||||
|
import AVKit
|
||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
@@ -27,7 +28,8 @@ final class DamusVideoPlayerViewModel: ObservableObject {
|
|||||||
private let url: URL
|
private let url: URL
|
||||||
private let player_item: AVPlayerItem
|
private let player_item: AVPlayerItem
|
||||||
let player: AVPlayer
|
let player: AVPlayer
|
||||||
private let controller: VideoController
|
fileprivate let controller: VideoController
|
||||||
|
let player_view_controller = AVPlayerViewController()
|
||||||
let id = UUID()
|
let id = UUID()
|
||||||
|
|
||||||
@Published var has_audio = false
|
@Published var has_audio = false
|
||||||
@@ -55,7 +57,7 @@ final class DamusVideoPlayerViewModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init(url: URL, video_size: Binding<CGSize?>, controller: VideoController) {
|
init(url: URL, video_size: Binding<CGSize?>, controller: VideoController, mute: Bool? = nil) {
|
||||||
self.url = url
|
self.url = url
|
||||||
player_item = AVPlayerItem(url: url)
|
player_item = AVPlayerItem(url: url)
|
||||||
player = AVPlayer(playerItem: player_item)
|
player = AVPlayer(playerItem: player_item)
|
||||||
@@ -66,7 +68,7 @@ final class DamusVideoPlayerViewModel: ObservableObject {
|
|||||||
await load()
|
await load()
|
||||||
}
|
}
|
||||||
|
|
||||||
is_muted = controller.should_mute_video(url: url)
|
is_muted = mute ?? controller.should_mute_video(url: url)
|
||||||
player.isMuted = is_muted
|
player.isMuted = is_muted
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(
|
NotificationCenter.default.addObserver(
|
||||||
|
|||||||
Reference in New Issue
Block a user