video: add DamusVideoPlayerViewModel

Closes: https://github.com/damus-io/damus/pull/1539
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
Bryan Montz
2023-09-06 11:25:07 -05:00
committed by William Casarin
parent dec07df2c1
commit f1f3abfb98
2 changed files with 109 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
//
// DamusVideoPlayerViewModel.swift
// damus
//
// Created by Bryan Montz on 9/5/23.
//
import AVFoundation
import Combine
import Foundation
import SwiftUI
@MainActor
final class DamusVideoPlayerViewModel: ObservableObject {
private let url: URL
private let player_item: AVPlayerItem
let player: AVPlayer
private let controller: VideoController
let id = UUID()
@Published var has_audio = false
@Binding var video_size: CGSize?
@Published var is_muted = true
@Published var is_loading = true
private var cancellables = Set<AnyCancellable>()
private var is_scrolled_into_view = false {
didSet {
if is_scrolled_into_view && !oldValue {
// we have just scrolled from out of view into view
controller.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
}
}
}
}
init(url: URL, video_size: Binding<CGSize?>, controller: VideoController) {
self.url = url
player_item = AVPlayerItem(url: url)
player = AVPlayer(playerItem: player_item)
self.controller = controller
_video_size = video_size
Task {
await load()
}
is_muted = controller.should_mute_video(url: url)
player.isMuted = is_muted
NotificationCenter.default.addObserver(
self,
selector: #selector(did_play_to_end),
name: Notification.Name.AVPlayerItemDidPlayToEndTime,
object: player_item
)
controller.$focused_model_id
.sink { [weak self] model_id in
model_id == self?.id ? self?.player.play() : self?.player.pause()
}
.store(in: &cancellables)
}
private func load() async {
if let meta = controller.metadata(for: url) {
has_audio = meta.has_audio
video_size = meta.size
} else {
has_audio = await video_has_audio(player: player)
if let video_size = await get_video_size(player: player) {
self.video_size = video_size
let meta = VideoMetadata(has_audio: has_audio, size: video_size)
controller.set_metadata(meta, url: url)
}
}
is_loading = false
}
func did_tap_mute_button() {
is_muted.toggle()
player.isMuted = is_muted
controller.toggle_should_mute_video(url: url)
}
func set_view_is_visible(_ is_visible: Bool) {
is_scrolled_into_view = is_visible
}
func view_did_disappear() {
set_view_is_visible(false)
}
@objc private func did_play_to_end() {
player.seek(to: CMTime.zero)
player.play()
}
}