mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-04-27 02:14:45 +00:00
better video player
This commit is contained in:
parent
5ce4d0b41d
commit
5ca5dfbd24
2 changed files with 49 additions and 20 deletions
|
@ -9,6 +9,7 @@ import SwiftUI
|
||||||
var player: AVPlayer?
|
var player: AVPlayer?
|
||||||
private let url: URL
|
private let url: URL
|
||||||
let forceAutoPlay: Bool
|
let forceAutoPlay: Bool
|
||||||
|
var isPlaying: Bool = false
|
||||||
|
|
||||||
public init(url: URL, forceAutoPlay: Bool = false) {
|
public init(url: URL, forceAutoPlay: Bool = false) {
|
||||||
self.url = url
|
self.url = url
|
||||||
|
@ -17,12 +18,13 @@ import SwiftUI
|
||||||
|
|
||||||
func preparePlayer(autoPlay: Bool) {
|
func preparePlayer(autoPlay: Bool) {
|
||||||
player = .init(url: url)
|
player = .init(url: url)
|
||||||
player?.isMuted = !forceAutoPlay
|
|
||||||
player?.audiovisualBackgroundPlaybackPolicy = .pauses
|
player?.audiovisualBackgroundPlaybackPolicy = .pauses
|
||||||
if autoPlay || forceAutoPlay {
|
if autoPlay || forceAutoPlay {
|
||||||
player?.play()
|
player?.play()
|
||||||
|
isPlaying = true
|
||||||
} else {
|
} else {
|
||||||
player?.pause()
|
player?.pause()
|
||||||
|
isPlaying = false
|
||||||
}
|
}
|
||||||
guard let player else { return }
|
guard let player else { return }
|
||||||
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime,
|
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime,
|
||||||
|
@ -37,10 +39,12 @@ import SwiftUI
|
||||||
}
|
}
|
||||||
|
|
||||||
func pause() {
|
func pause() {
|
||||||
|
isPlaying = false
|
||||||
player?.pause()
|
player?.pause()
|
||||||
}
|
}
|
||||||
|
|
||||||
func play() {
|
func play() {
|
||||||
|
isPlaying = true
|
||||||
player?.seek(to: CMTime.zero)
|
player?.seek(to: CMTime.zero)
|
||||||
player?.play()
|
player?.play()
|
||||||
}
|
}
|
||||||
|
@ -50,6 +54,7 @@ import SwiftUI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
public struct MediaUIAttachmentVideoView: View {
|
public struct MediaUIAttachmentVideoView: View {
|
||||||
@Environment(\.scenePhase) private var scenePhase
|
@Environment(\.scenePhase) private var scenePhase
|
||||||
@Environment(\.isCompact) private var isCompact
|
@Environment(\.isCompact) private var isCompact
|
||||||
|
@ -57,37 +62,44 @@ public struct MediaUIAttachmentVideoView: View {
|
||||||
@Environment(Theme.self) private var theme
|
@Environment(Theme.self) private var theme
|
||||||
|
|
||||||
@State var viewModel: MediaUIAttachmentVideoViewModel
|
@State var viewModel: MediaUIAttachmentVideoViewModel
|
||||||
|
@State var isFullScreen: Bool = false
|
||||||
|
|
||||||
public init(viewModel: MediaUIAttachmentVideoViewModel) {
|
public init(viewModel: MediaUIAttachmentVideoViewModel) {
|
||||||
_viewModel = .init(wrappedValue: viewModel)
|
_viewModel = .init(wrappedValue: viewModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var body: some View {
|
public var body: some View {
|
||||||
ZStack {
|
videoView
|
||||||
VideoPlayer(player: viewModel.player)
|
.onAppear {
|
||||||
.accessibilityAddTraits(.startsMediaSession)
|
try? AVAudioSession.sharedInstance().setCategory(.playback)
|
||||||
|
viewModel.preparePlayer(autoPlay: isFullScreen ? true : preferences.autoPlayVideo)
|
||||||
if !preferences.autoPlayVideo, !viewModel.forceAutoPlay {
|
|
||||||
Image(systemName: "play.fill")
|
|
||||||
.font(isCompact ? .body : .largeTitle)
|
|
||||||
.foregroundColor(theme.tintColor)
|
|
||||||
.padding(.all, isCompact ? 6 : nil)
|
|
||||||
.background(Circle().fill(.thinMaterial))
|
|
||||||
.padding(theme.statusDisplayStyle == .compact ? 0 : 10)
|
|
||||||
}
|
|
||||||
}.onAppear {
|
|
||||||
viewModel.preparePlayer(autoPlay: preferences.autoPlayVideo)
|
|
||||||
}
|
}
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
|
try? AVAudioSession.sharedInstance().setCategory(.ambient)
|
||||||
viewModel.pause()
|
viewModel.pause()
|
||||||
}
|
}
|
||||||
|
.onTapGesture {
|
||||||
|
isFullScreen = true
|
||||||
|
}
|
||||||
|
.fullScreenCover(isPresented: $isFullScreen) {
|
||||||
|
NavigationStack {
|
||||||
|
videoView
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItem(placement: .topBarLeading) {
|
||||||
|
Button { isFullScreen.toggle() } label: {
|
||||||
|
Image(systemName: "xmark.circle")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.cornerRadius(4)
|
.cornerRadius(4)
|
||||||
.onChange(of: scenePhase) { _, newValue in
|
.onChange(of: scenePhase) { _, newValue in
|
||||||
switch newValue {
|
switch newValue {
|
||||||
case .background, .inactive:
|
case .background, .inactive:
|
||||||
viewModel.pause()
|
viewModel.pause()
|
||||||
case .active:
|
case .active:
|
||||||
if preferences.autoPlayVideo || viewModel.forceAutoPlay {
|
if preferences.autoPlayVideo || viewModel.forceAutoPlay || isFullScreen {
|
||||||
viewModel.play()
|
viewModel.play()
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -95,4 +107,25 @@ public struct MediaUIAttachmentVideoView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var videoView: some View {
|
||||||
|
VideoPlayer(player: viewModel.player, videoOverlay: {
|
||||||
|
if !preferences.autoPlayVideo,
|
||||||
|
!viewModel.forceAutoPlay,
|
||||||
|
!isFullScreen,
|
||||||
|
!viewModel.isPlaying {
|
||||||
|
Button(action: {
|
||||||
|
viewModel.play()
|
||||||
|
}, label: {
|
||||||
|
Image(systemName: "play.fill")
|
||||||
|
.font(isCompact ? .body : .largeTitle)
|
||||||
|
.foregroundColor(theme.tintColor)
|
||||||
|
.padding(.all, isCompact ? 6 : nil)
|
||||||
|
.background(Circle().fill(.thinMaterial))
|
||||||
|
.padding(theme.statusDisplayStyle == .compact ? 0 : 10)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.accessibilityAddTraits(.startsMediaSession)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,15 +41,11 @@ public struct MediaUIView: View, @unchecked Sendable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
try? AVAudioSession.sharedInstance().setCategory(.playback)
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) {
|
||||||
scrolledItem = initialItem
|
scrolledItem = initialItem
|
||||||
isFocused = true
|
isFocused = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onDisappear {
|
|
||||||
try? AVAudioSession.sharedInstance().setCategory(.ambient)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue