Rename VideoController to DamusVideoCoordinator
This commit renames this class to better represent what it does. This reduces some of the term overloading between this class and other video controller classes/structs. (Such as AVPlayerController) Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit is contained in:
@@ -388,7 +388,7 @@
|
||||
5053ACA72A56DF3B00851AE3 /* DeveloperSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5053ACA62A56DF3B00851AE3 /* DeveloperSettingsView.swift */; };
|
||||
50A16FFB2AA6C06600DFEC1F /* DamusAVPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFA2AA6C06600DFEC1F /* DamusAVPlayerView.swift */; };
|
||||
50A16FFD2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFC2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift */; };
|
||||
50A16FFF2AA76A0900DFEC1F /* VideoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFE2AA76A0900DFEC1F /* VideoController.swift */; };
|
||||
50A16FFF2AA76A0900DFEC1F /* DamusVideoCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFE2AA76A0900DFEC1F /* DamusVideoCoordinator.swift */; };
|
||||
50A50A8D29A09E1C00C01BE7 /* RequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A50A8C29A09E1C00C01BE7 /* RequestTests.swift */; };
|
||||
50A60D142A28BEEE00186190 /* RelayLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A60D132A28BEEE00186190 /* RelayLog.swift */; };
|
||||
50B5685329F97CB400A23243 /* CredentialHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50B5685229F97CB400A23243 /* CredentialHandler.swift */; };
|
||||
@@ -784,7 +784,7 @@
|
||||
D73E5ED72C6A97F4007EB227 /* MutinyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7389B62B9E692E00781E0A /* MutinyButton.swift */; };
|
||||
D73E5ED82C6A97F4007EB227 /* DamusVideoPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1A9A2929DDF54400516EAC /* DamusVideoPlayer.swift */; };
|
||||
D73E5ED92C6A97F4007EB227 /* DamusVideoPlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFC2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift */; };
|
||||
D73E5EDA2C6A97F4007EB227 /* VideoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFE2AA76A0900DFEC1F /* VideoController.swift */; };
|
||||
D73E5EDA2C6A97F4007EB227 /* DamusVideoCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFE2AA76A0900DFEC1F /* DamusVideoCoordinator.swift */; };
|
||||
D73E5EDB2C6A97F4007EB227 /* DamusAVPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFA2AA6C06600DFEC1F /* DamusAVPlayerView.swift */; };
|
||||
D73E5EDC2C6A97F4007EB227 /* ReactionsSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C15C7142A55DE7A00D0A0DB /* ReactionsSettingsView.swift */; };
|
||||
D73E5EDD2C6A97F4007EB227 /* NotificationSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1A9A1C29DDCF9B00516EAC /* NotificationSettingsView.swift */; };
|
||||
@@ -1832,7 +1832,7 @@
|
||||
5053ACA62A56DF3B00851AE3 /* DeveloperSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperSettingsView.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>"; };
|
||||
50A16FFE2AA76A0900DFEC1F /* VideoController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoController.swift; sourceTree = "<group>"; };
|
||||
50A16FFE2AA76A0900DFEC1F /* DamusVideoCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusVideoCoordinator.swift; sourceTree = "<group>"; };
|
||||
50A50A8C29A09E1C00C01BE7 /* RequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestTests.swift; sourceTree = "<group>"; };
|
||||
50A60D132A28BEEE00186190 /* RelayLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayLog.swift; sourceTree = "<group>"; };
|
||||
50B5685229F97CB400A23243 /* CredentialHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialHandler.swift; sourceTree = "<group>"; };
|
||||
@@ -2294,7 +2294,7 @@
|
||||
children = (
|
||||
4C1A9A2929DDF54400516EAC /* DamusVideoPlayer.swift */,
|
||||
50A16FFC2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift */,
|
||||
50A16FFE2AA76A0900DFEC1F /* VideoController.swift */,
|
||||
50A16FFE2AA76A0900DFEC1F /* DamusVideoCoordinator.swift */,
|
||||
50A16FFA2AA6C06600DFEC1F /* DamusAVPlayerView.swift */,
|
||||
);
|
||||
path = Video;
|
||||
@@ -3899,7 +3899,7 @@
|
||||
5C14C29F2BBBA5C600079FD2 /* RelayNipList.swift in Sources */,
|
||||
D78DB85B2C20FE5000F0AB12 /* VectorMath.swift in Sources */,
|
||||
D7CB5D3E2B116DAD00AD4105 /* NotificationsManager.swift in Sources */,
|
||||
50A16FFF2AA76A0900DFEC1F /* VideoController.swift in Sources */,
|
||||
50A16FFF2AA76A0900DFEC1F /* DamusVideoCoordinator.swift in Sources */,
|
||||
F7908E97298B1FDF00AB113A /* NIPURLBuilder.swift in Sources */,
|
||||
4C285C8228385570008A31F1 /* CarouselView.swift in Sources */,
|
||||
3A3040F129A8FF97008A0F29 /* LocalizationUtil.swift in Sources */,
|
||||
@@ -4452,7 +4452,7 @@
|
||||
D73E5ED72C6A97F4007EB227 /* MutinyButton.swift in Sources */,
|
||||
D73E5ED82C6A97F4007EB227 /* DamusVideoPlayer.swift in Sources */,
|
||||
D73E5ED92C6A97F4007EB227 /* DamusVideoPlayerViewModel.swift in Sources */,
|
||||
D73E5EDA2C6A97F4007EB227 /* VideoController.swift in Sources */,
|
||||
D73E5EDA2C6A97F4007EB227 /* DamusVideoCoordinator.swift in Sources */,
|
||||
D73E5EDB2C6A97F4007EB227 /* DamusAVPlayerView.swift in Sources */,
|
||||
D73E5EDC2C6A97F4007EB227 /* ReactionsSettingsView.swift in Sources */,
|
||||
D73E5EDD2C6A97F4007EB227 /* NotificationSettingsView.swift in Sources */,
|
||||
|
||||
@@ -186,7 +186,7 @@ struct ImageCarousel<Content: View>: View {
|
||||
model.open_sheet = true
|
||||
}
|
||||
case .video(let url):
|
||||
DamusVideoPlayer(url: url, video_size: $model.video_size, controller: state.video, style: .preview(on_tap: { model.open_sheet = true }))
|
||||
DamusVideoPlayer(url: url, video_size: $model.video_size, coordinator: state.video, style: .preview(on_tap: { model.open_sheet = true }))
|
||||
.onChange(of: model.video_size) { size in
|
||||
guard let size else { return }
|
||||
|
||||
@@ -257,14 +257,14 @@ struct ImageCarousel<Content: View>: View {
|
||||
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
|
||||
.fullScreenCover(isPresented: $model.open_sheet) {
|
||||
if let content {
|
||||
FullScreenCarouselView<Content>(video_controller: state.video, urls: urls, settings: state.settings, selectedIndex: $model.selectedIndex) {
|
||||
FullScreenCarouselView<Content>(video_coordinator: state.video, urls: urls, settings: state.settings, selectedIndex: $model.selectedIndex) {
|
||||
content({ // Dismiss closure
|
||||
model.open_sheet = false
|
||||
})
|
||||
}
|
||||
}
|
||||
else {
|
||||
FullScreenCarouselView<AnyView>(video_controller: state.video, urls: urls, settings: state.settings, selectedIndex: $model.selectedIndex)
|
||||
FullScreenCarouselView<AnyView>(video_coordinator: state.video, urls: urls, settings: state.settings, selectedIndex: $model.selectedIndex)
|
||||
}
|
||||
}
|
||||
.frame(height: height)
|
||||
|
||||
@@ -686,7 +686,7 @@ struct ContentView: View {
|
||||
wallet: WalletModel(settings: settings),
|
||||
nav: self.navigationCoordinator,
|
||||
music: MusicController(onChange: music_changed),
|
||||
video: VideoController(),
|
||||
video: DamusVideoCoordinator(),
|
||||
ndb: ndb,
|
||||
quote_reposts: .init(our_pubkey: pubkey),
|
||||
emoji_provider: DefaultEmojiProvider(showAllVariations: true)
|
||||
|
||||
@@ -34,13 +34,13 @@ class DamusState: HeadlessDamusState {
|
||||
let wallet: WalletModel
|
||||
let nav: NavigationCoordinator
|
||||
let music: MusicController?
|
||||
let video: VideoController
|
||||
let video: DamusVideoCoordinator
|
||||
let ndb: Ndb
|
||||
var purple: DamusPurple
|
||||
var push_notification_client: PushNotificationClient
|
||||
let emoji_provider: EmojiProvider
|
||||
|
||||
init(pool: RelayPool, keypair: Keypair, likes: EventCounter, boosts: EventCounter, contacts: Contacts, mutelist_manager: MutelistManager, profiles: Profiles, dms: DirectMessagesModel, previews: PreviewCache, zaps: Zaps, lnurls: LNUrls, settings: UserSettingsStore, relay_filters: RelayFilters, relay_model_cache: RelayModelCache, drafts: Drafts, events: EventCache, bookmarks: BookmarksManager, postbox: PostBox, bootstrap_relays: [RelayURL], replies: ReplyCounter, wallet: WalletModel, nav: NavigationCoordinator, music: MusicController?, video: VideoController, ndb: Ndb, purple: DamusPurple? = nil, quote_reposts: EventCounter, emoji_provider: EmojiProvider) {
|
||||
init(pool: RelayPool, keypair: Keypair, likes: EventCounter, boosts: EventCounter, contacts: Contacts, mutelist_manager: MutelistManager, profiles: Profiles, dms: DirectMessagesModel, previews: PreviewCache, zaps: Zaps, lnurls: LNUrls, settings: UserSettingsStore, relay_filters: RelayFilters, relay_model_cache: RelayModelCache, drafts: Drafts, events: EventCache, bookmarks: BookmarksManager, postbox: PostBox, bootstrap_relays: [RelayURL], replies: ReplyCounter, wallet: WalletModel, nav: NavigationCoordinator, music: MusicController?, video: DamusVideoCoordinator, ndb: Ndb, purple: DamusPurple? = nil, quote_reposts: EventCounter, emoji_provider: EmojiProvider) {
|
||||
self.pool = pool
|
||||
self.keypair = keypair
|
||||
self.likes = likes
|
||||
@@ -141,7 +141,7 @@ class DamusState: HeadlessDamusState {
|
||||
wallet: WalletModel(settings: settings),
|
||||
nav: navigationCoordinator,
|
||||
music: MusicController(onChange: { _ in }),
|
||||
video: VideoController(),
|
||||
video: DamusVideoCoordinator(),
|
||||
ndb: ndb,
|
||||
quote_reposts: .init(our_pubkey: pubkey),
|
||||
emoji_provider: DefaultEmojiProvider(showAllVariations: true)
|
||||
@@ -209,7 +209,7 @@ class DamusState: HeadlessDamusState {
|
||||
wallet: WalletModel(settings: UserSettingsStore()),
|
||||
nav: NavigationCoordinator(),
|
||||
music: nil,
|
||||
video: VideoController(),
|
||||
video: DamusVideoCoordinator(),
|
||||
ndb: .empty,
|
||||
quote_reposts: .init(our_pubkey: empty_pub),
|
||||
emoji_provider: DefaultEmojiProvider(showAllVariations: true)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import SwiftUI
|
||||
|
||||
struct FullScreenCarouselView<Content: View>: View {
|
||||
let video_controller: VideoController
|
||||
let video_coordinator: DamusVideoCoordinator
|
||||
let urls: [MediaUrl]
|
||||
|
||||
@Environment(\.presentationMode) var presentationMode
|
||||
@@ -19,8 +19,8 @@ struct FullScreenCarouselView<Content: View>: View {
|
||||
@Binding var selectedIndex: Int
|
||||
let content: (() -> Content)?
|
||||
|
||||
init(video_controller: VideoController, urls: [MediaUrl], showMenu: Bool = true, settings: UserSettingsStore, selectedIndex: Binding<Int>, @ViewBuilder content: @escaping () -> Content) {
|
||||
self.video_controller = video_controller
|
||||
init(video_coordinator: DamusVideoCoordinator, urls: [MediaUrl], showMenu: Bool = true, settings: UserSettingsStore, selectedIndex: Binding<Int>, @ViewBuilder content: @escaping () -> Content) {
|
||||
self.video_coordinator = video_coordinator
|
||||
self.urls = urls
|
||||
self._showMenu = State(initialValue: showMenu)
|
||||
self.settings = settings
|
||||
@@ -28,8 +28,8 @@ struct FullScreenCarouselView<Content: View>: View {
|
||||
self.content = content
|
||||
}
|
||||
|
||||
init(video_controller: VideoController, urls: [MediaUrl], showMenu: Bool = true, settings: UserSettingsStore, selectedIndex: Binding<Int>) {
|
||||
self.video_controller = video_controller
|
||||
init(video_coordinator: DamusVideoCoordinator, urls: [MediaUrl], showMenu: Bool = true, settings: UserSettingsStore, selectedIndex: Binding<Int>) {
|
||||
self.video_coordinator = video_coordinator
|
||||
self.urls = urls
|
||||
self._showMenu = State(initialValue: showMenu)
|
||||
self.settings = settings
|
||||
@@ -59,7 +59,7 @@ struct FullScreenCarouselView<Content: View>: View {
|
||||
ForEach(urls.indices, id: \.self) { index in
|
||||
VStack {
|
||||
if case .video = urls[safe: index] {
|
||||
ImageContainerView(video_controller: video_controller, url: urls[index], settings: settings, imageDict: $imageDict)
|
||||
ImageContainerView(video_coordinator: video_coordinator, url: urls[index], settings: settings, imageDict: $imageDict)
|
||||
.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)
|
||||
@@ -71,7 +71,7 @@ struct FullScreenCarouselView<Content: View>: View {
|
||||
}
|
||||
else {
|
||||
ZoomableScrollView {
|
||||
ImageContainerView(video_controller: video_controller, url: urls[index], settings: settings, imageDict: $imageDict)
|
||||
ImageContainerView(video_coordinator: video_coordinator, url: urls[index], settings: settings, imageDict: $imageDict)
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.padding(.top, Theme.safeAreaInsets?.top)
|
||||
.padding(.bottom, Theme.safeAreaInsets?.bottom)
|
||||
@@ -148,7 +148,7 @@ fileprivate struct FullScreenCarouselPreviewView<Content: View>: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
FullScreenCarouselView(video_controller: test_damus_state.video, urls: [test_video_url, url], settings: test_damus_state.settings, selectedIndex: $selectedIndex) {
|
||||
FullScreenCarouselView(video_coordinator: test_damus_state.video, urls: [test_video_url, url], settings: test_damus_state.settings, selectedIndex: $selectedIndex) {
|
||||
self.custom_content?()
|
||||
}
|
||||
.environmentObject(OrientationTracker())
|
||||
|
||||
@@ -10,7 +10,7 @@ import Kingfisher
|
||||
|
||||
|
||||
struct ImageContainerView: View {
|
||||
let video_controller: VideoController
|
||||
let video_coordinator: DamusVideoCoordinator
|
||||
let url: MediaUrl
|
||||
let settings: UserSettingsStore
|
||||
|
||||
@@ -51,7 +51,7 @@ struct ImageContainerView: View {
|
||||
case .image(let url):
|
||||
Img(url: url)
|
||||
case .video(let url):
|
||||
DamusVideoPlayer(url: url, video_size: .constant(nil), controller: video_controller, style: .full, visibility_tracking_method: .generic)
|
||||
DamusVideoPlayer(url: url, video_size: .constant(nil), coordinator: video_coordinator, style: .full, visibility_tracking_method: .generic)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,9 +64,9 @@ struct ImageContainerView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
@State var imageDict: [URL: UIImage] = [:]
|
||||
Group {
|
||||
ImageContainerView(video_controller: test_damus_state.video, url: .image(test_image_url), settings: test_damus_state.settings, imageDict: $imageDict)
|
||||
ImageContainerView(video_coordinator: test_damus_state.video, url: .image(test_image_url), settings: test_damus_state.settings, imageDict: $imageDict)
|
||||
.previewDisplayName("Image")
|
||||
ImageContainerView(video_controller: test_damus_state.video, url: .video(test_video_url), settings: test_damus_state.settings, imageDict: $imageDict)
|
||||
ImageContainerView(video_coordinator: test_damus_state.video, url: .video(test_video_url), settings: test_damus_state.settings, imageDict: $imageDict)
|
||||
.previewDisplayName("Video")
|
||||
}
|
||||
.environmentObject(OrientationTracker())
|
||||
|
||||
53
damus/Views/Video/DamusVideoCoordinator.swift
Normal file
53
damus/Views/Video/DamusVideoCoordinator.swift
Normal file
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// DamusVideoCoordinator.swift
|
||||
// damus
|
||||
//
|
||||
// Created by Bryan Montz on 9/3/23.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
struct VideoMetadata {
|
||||
let has_audio: Bool
|
||||
let size: CGSize
|
||||
}
|
||||
|
||||
/// DamusVideoCoordinator is responsible for coordinating the various video players in the damus app.
|
||||
/// The goals of this object are to:
|
||||
/// - ensure some video playing states (such as mute state) are consistent across different video player view instances of the same video
|
||||
/// - ensure only one video is playing at a time
|
||||
/// - Provide global video playback controls to control the currently playing video
|
||||
///
|
||||
/// This is used as a singleton object (one per DamusState), which gets passed around to video players, which can then interact with the coordinator to ensure an app-wide coherent experience
|
||||
///
|
||||
/// A good analogy here is that video players and their models/states are like individual car drivers, and this coordinator is like a traffic control person that ensures cars don't crash each other.
|
||||
final class DamusVideoCoordinator: ObservableObject {
|
||||
private var mute_states: [URL: Bool] = [:]
|
||||
private var metadatas: [URL: VideoMetadata] = [:]
|
||||
|
||||
@Published var focused_model_id: UUID?
|
||||
|
||||
func toggle_should_mute_video(url: URL) {
|
||||
let state = mute_states[url] ?? true
|
||||
mute_states[url] = !state
|
||||
|
||||
objectWillChange.send()
|
||||
}
|
||||
|
||||
func should_mute_video(url: URL) -> Bool {
|
||||
mute_states[url] ?? true
|
||||
}
|
||||
|
||||
func set_metadata(_ metadata: VideoMetadata, url: URL) {
|
||||
metadatas[url] = metadata
|
||||
}
|
||||
|
||||
func metadata(for url: URL) -> VideoMetadata? {
|
||||
metadatas[url]
|
||||
}
|
||||
|
||||
func size_for_url(_ url: URL) -> CGSize? {
|
||||
metadatas[url]?.size
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ struct DamusVideoPlayer: View {
|
||||
let visibility_tracking_method: VisibilityTrackingMethod
|
||||
@State var isVisible: Bool = false
|
||||
|
||||
init(url: URL, video_size: Binding<CGSize?>, controller: VideoController, style: Style, visibility_tracking_method: VisibilityTrackingMethod = .y_scroll) {
|
||||
init(url: URL, video_size: Binding<CGSize?>, coordinator: DamusVideoCoordinator, style: Style, visibility_tracking_method: VisibilityTrackingMethod = .y_scroll) {
|
||||
self.url = url
|
||||
let mute: Bool?
|
||||
if case .full = style {
|
||||
@@ -33,7 +33,7 @@ struct DamusVideoPlayer: View {
|
||||
else {
|
||||
mute = nil
|
||||
}
|
||||
_model = StateObject(wrappedValue: DamusVideoPlayerViewModel(url: url, video_size: video_size, controller: controller, mute: mute))
|
||||
_model = StateObject(wrappedValue: DamusVideoPlayerViewModel(url: url, video_size: video_size, coordinator: coordinator, mute: mute))
|
||||
self.visibility_tracking_method = visibility_tracking_method
|
||||
self.style = style
|
||||
}
|
||||
@@ -166,11 +166,11 @@ struct DamusVideoPlayer: View {
|
||||
struct DamusVideoPlayer_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
DamusVideoPlayer(url: URL(string: "http://cdn.jb55.com/s/zaps-build.mp4")!, video_size: .constant(nil), controller: VideoController(), style: .full)
|
||||
DamusVideoPlayer(url: URL(string: "http://cdn.jb55.com/s/zaps-build.mp4")!, video_size: .constant(nil), coordinator: DamusVideoCoordinator(), 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))
|
||||
DamusVideoPlayer(url: URL(string: "http://cdn.jb55.com/s/zaps-build.mp4")!, video_size: .constant(nil), coordinator: DamusVideoCoordinator(), style: .preview(on_tap: nil))
|
||||
.environmentObject(OrientationTracker())
|
||||
.previewDisplayName("Preview video player")
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ final class DamusVideoPlayerViewModel: ObservableObject {
|
||||
private let url: URL
|
||||
private let player_item: AVPlayerItem
|
||||
let player: AVPlayer
|
||||
fileprivate let controller: VideoController
|
||||
fileprivate let coordinator: DamusVideoCoordinator
|
||||
let player_view_controller = AVPlayerViewController()
|
||||
let id = UUID()
|
||||
|
||||
@@ -47,28 +47,28 @@ final class DamusVideoPlayerViewModel: ObservableObject {
|
||||
didSet {
|
||||
if is_scrolled_into_view && !oldValue {
|
||||
// we have just scrolled from out of view into view
|
||||
controller.focused_model_id = id
|
||||
coordinator.focused_model_id = id
|
||||
} else if !is_scrolled_into_view && oldValue {
|
||||
// we have just scrolled from in view to out of view
|
||||
if controller.focused_model_id == id {
|
||||
controller.focused_model_id = nil
|
||||
if coordinator.focused_model_id == id {
|
||||
coordinator.focused_model_id = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init(url: URL, video_size: Binding<CGSize?>, controller: VideoController, mute: Bool? = nil) {
|
||||
init(url: URL, video_size: Binding<CGSize?>, coordinator: DamusVideoCoordinator, mute: Bool? = nil) {
|
||||
self.url = url
|
||||
player_item = AVPlayerItem(url: url)
|
||||
player = AVPlayer(playerItem: player_item)
|
||||
self.controller = controller
|
||||
self.coordinator = coordinator
|
||||
_video_size = video_size
|
||||
|
||||
Task {
|
||||
await load()
|
||||
}
|
||||
|
||||
is_muted = mute ?? controller.should_mute_video(url: url)
|
||||
is_muted = mute ?? coordinator.should_mute_video(url: url)
|
||||
player.isMuted = is_muted
|
||||
|
||||
NotificationCenter.default.addObserver(
|
||||
@@ -78,7 +78,7 @@ final class DamusVideoPlayerViewModel: ObservableObject {
|
||||
object: player_item
|
||||
)
|
||||
|
||||
controller.$focused_model_id
|
||||
coordinator.$focused_model_id
|
||||
.sink { [weak self] model_id in
|
||||
model_id == self?.id ? self?.player.play() : self?.player.pause()
|
||||
}
|
||||
@@ -111,7 +111,7 @@ final class DamusVideoPlayerViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
private func load() async {
|
||||
if let meta = controller.metadata(for: url) {
|
||||
if let meta = coordinator.metadata(for: url) {
|
||||
has_audio = meta.has_audio
|
||||
video_size = meta.size
|
||||
} else {
|
||||
@@ -124,7 +124,7 @@ final class DamusVideoPlayerViewModel: ObservableObject {
|
||||
func did_tap_mute_button() {
|
||||
is_muted.toggle()
|
||||
player.isMuted = is_muted
|
||||
controller.toggle_should_mute_video(url: url)
|
||||
coordinator.toggle_should_mute_video(url: url)
|
||||
}
|
||||
|
||||
func set_view_is_visible(_ is_visible: Bool) {
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
//
|
||||
// VideoController.swift
|
||||
// damus
|
||||
//
|
||||
// Created by Bryan Montz on 9/3/23.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
struct VideoMetadata {
|
||||
let has_audio: Bool
|
||||
let size: CGSize
|
||||
}
|
||||
|
||||
final class VideoController: ObservableObject {
|
||||
private var mute_states: [URL: Bool] = [:]
|
||||
private var metadatas: [URL: VideoMetadata] = [:]
|
||||
|
||||
@Published var focused_model_id: UUID?
|
||||
|
||||
func toggle_should_mute_video(url: URL) {
|
||||
let state = mute_states[url] ?? true
|
||||
mute_states[url] = !state
|
||||
|
||||
objectWillChange.send()
|
||||
}
|
||||
|
||||
func should_mute_video(url: URL) -> Bool {
|
||||
mute_states[url] ?? true
|
||||
}
|
||||
|
||||
func set_metadata(_ metadata: VideoMetadata, url: URL) {
|
||||
metadatas[url] = metadata
|
||||
}
|
||||
|
||||
func metadata(for url: URL) -> VideoMetadata? {
|
||||
metadatas[url]
|
||||
}
|
||||
|
||||
func size_for_url(_ url: URL) -> CGSize? {
|
||||
metadatas[url]?.size
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user