init: init proj
This commit is contained in:
163
DDYSClient/Views/Player/VideoPlayerView.swift
Normal file
163
DDYSClient/Views/Player/VideoPlayerView.swift
Normal file
@@ -0,0 +1,163 @@
|
||||
import SwiftUI
|
||||
import AVFoundation
|
||||
import AVKit
|
||||
|
||||
// MARK: - 自定义 AVPlayerView 包装
|
||||
|
||||
#if os(macOS)
|
||||
import AppKit
|
||||
|
||||
struct NativePlayerView: NSViewRepresentable {
|
||||
let player: AVPlayer
|
||||
|
||||
func makeNSView(context: Context) -> AVPlayerView {
|
||||
let view = AVPlayerView()
|
||||
view.player = player
|
||||
view.controlsStyle = .floating
|
||||
view.showsFullScreenToggleButton = true
|
||||
return view
|
||||
}
|
||||
|
||||
func updateNSView(_ nsView: AVPlayerView, context: Context) {
|
||||
nsView.player = player
|
||||
}
|
||||
}
|
||||
#else
|
||||
import UIKit
|
||||
|
||||
struct NativePlayerView: UIViewControllerRepresentable {
|
||||
let player: AVPlayer
|
||||
|
||||
func makeUIViewController(context: Context) -> AVPlayerViewController {
|
||||
let vc = AVPlayerViewController()
|
||||
vc.player = player
|
||||
vc.allowsPictureInPicturePlayback = true
|
||||
return vc
|
||||
}
|
||||
|
||||
func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) {
|
||||
uiViewController.player = player
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// MARK: - VideoPlayerView
|
||||
|
||||
struct VideoPlayerView: View {
|
||||
let url: String
|
||||
let title: String
|
||||
let episodeName: String?
|
||||
let contentId: String
|
||||
let episodeId: Int
|
||||
|
||||
@State private var viewModel = PlayerViewModel()
|
||||
|
||||
#if os(iOS)
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
#endif
|
||||
|
||||
var body: some View {
|
||||
#if os(macOS)
|
||||
macOSPlayer
|
||||
#else
|
||||
iOSPlayer
|
||||
#endif
|
||||
}
|
||||
|
||||
#if os(iOS)
|
||||
private var iOSPlayer: some View {
|
||||
ZStack {
|
||||
Color.black.ignoresSafeArea()
|
||||
|
||||
if let player = viewModel.player {
|
||||
NativePlayerView(player: player)
|
||||
.ignoresSafeArea()
|
||||
} else {
|
||||
ProgressView()
|
||||
.tint(.white)
|
||||
.foregroundStyle(.white)
|
||||
}
|
||||
|
||||
VStack {
|
||||
HStack {
|
||||
Button {
|
||||
viewModel.stop()
|
||||
dismiss()
|
||||
} label: {
|
||||
Image(systemName: "xmark.circle.fill")
|
||||
.font(.title2)
|
||||
.foregroundStyle(.white)
|
||||
}
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text(title)
|
||||
.font(.headline)
|
||||
.foregroundStyle(.white)
|
||||
if let episodeName {
|
||||
Text(episodeName)
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.white.opacity(0.8))
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Menu {
|
||||
ForEach([0.5, 0.75, 1.0, 1.25, 1.5, 2.0], id: \.self) { rate in
|
||||
Button {
|
||||
viewModel.setRate(Float(rate))
|
||||
} label: {
|
||||
HStack {
|
||||
Text("\(rate, specifier: "%.2g")x")
|
||||
if viewModel.playbackRate == Float(rate) {
|
||||
Image(systemName: "checkmark")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
Text("\(viewModel.playbackRate, specifier: "%.2g")x")
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.white)
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.vertical, 4)
|
||||
.background(.white.opacity(0.2), in: Capsule())
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.background(.black.opacity(0.4))
|
||||
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
.statusBarHidden()
|
||||
.persistentSystemOverlays(.hidden)
|
||||
.onAppear {
|
||||
viewModel.play(url: url, contentId: contentId, episodeId: episodeId)
|
||||
}
|
||||
.onDisappear {
|
||||
viewModel.stop()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if os(macOS)
|
||||
private var macOSPlayer: some View {
|
||||
Group {
|
||||
if let player = viewModel.player {
|
||||
NativePlayerView(player: player)
|
||||
} else {
|
||||
ProgressView()
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
}
|
||||
}
|
||||
.frame(minWidth: 640, minHeight: 400)
|
||||
.onAppear {
|
||||
viewModel.play(url: url, contentId: contentId, episodeId: episodeId)
|
||||
}
|
||||
.onDisappear {
|
||||
viewModel.stop()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user