1
0
mirror of git://jb55.com/damus synced 2024-09-30 00:40:45 +00:00

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

@ -389,6 +389,7 @@
504323A92A3495B6006AE6DC /* RelayModelCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504323A82A3495B6006AE6DC /* RelayModelCache.swift */; };
5053ACA72A56DF3B00851AE3 /* DeveloperSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5053ACA62A56DF3B00851AE3 /* DeveloperSettingsView.swift */; };
50A16FFB2AA6C06600DFEC1F /* AVPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFA2AA6C06600DFEC1F /* AVPlayerView.swift */; };
50A16FFD2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFC2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift */; };
50A16FFF2AA76A0900DFEC1F /* VideoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFE2AA76A0900DFEC1F /* VideoController.swift */; };
50A50A8D29A09E1C00C01BE7 /* RequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A50A8C29A09E1C00C01BE7 /* RequestTests.swift */; };
50A60D142A28BEEE00186190 /* RelayLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A60D132A28BEEE00186190 /* RelayLog.swift */; };
@ -1066,6 +1067,7 @@
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>"; };
50A16FFA2AA6C06600DFEC1F /* AVPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVPlayerView.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>"; };
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>"; };
@ -1362,6 +1364,7 @@
isa = PBXGroup;
children = (
4C1A9A2929DDF54400516EAC /* DamusVideoPlayer.swift */,
50A16FFC2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift */,
50A16FFE2AA76A0900DFEC1F /* VideoController.swift */,
4CCF9AAE2A1FDBDB00E03CFB /* VideoPlayer.swift */,
50A16FFA2AA6C06600DFEC1F /* AVPlayerView.swift */,
@ -2733,6 +2736,7 @@
4CB88393296F798300DC99E7 /* ReactionsModel.swift in Sources */,
5C42E78C29DB76D90086AAC1 /* EmptyUserSearchView.swift in Sources */,
4CB88396296F7F8B00DC99E7 /* ReactionView.swift in Sources */,
50A16FFD2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift in Sources */,
4CFF8F6B29CD0079008DB934 /* RepostedEvent.swift in Sources */,
4C8682872814DE470026224F /* ProfileView.swift in Sources */,
5C0707D12A1ECB38004E7B51 /* DamusLogoGradient.swift in Sources */,

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()
}
}