video: switch player to use new view model

pass VideoController through containing views

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:29:45 -05:00
committed by William Casarin
parent f1f3abfb98
commit 3569da5687
4 changed files with 69 additions and 67 deletions

View File

@@ -17,79 +17,85 @@ func globalCoordinate(localX x: CGFloat, localY y: CGFloat,
}
struct DamusVideoPlayer: View {
var url: URL
@ObservedObject var model: VideoPlayerModel
@Binding var video_size: CGSize?
let url: URL
@StateObject var model: DamusVideoPlayerViewModel
@EnvironmentObject private var orientationTracker: OrientationTracker
var mute_icon: String {
if model.has_audio == false || model.muted {
return "speaker.slash"
} else {
return "speaker"
}
}
var mute_icon_color: Color {
switch self.model.has_audio {
case .none:
return .white
case .some(let has_audio):
return has_audio ? .white : .red
}
}
var MuteIcon: some View {
ZStack {
Circle()
.opacity(0.2)
.frame(width: 32, height: 32)
.foregroundColor(.black)
Image(systemName: mute_icon)
.padding()
.foregroundColor(mute_icon_color)
}
init(url: URL, video_size: Binding<CGSize?>, controller: VideoController) {
self.url = url
_model = StateObject(wrappedValue: DamusVideoPlayerViewModel(url: url, video_size: video_size, controller: controller))
}
var body: some View {
GeometryReader { geo in
let localFrame = geo.frame(in: .local)
let centerY = globalCoordinate(localX: 0, localY: localFrame.midY, localGeometry: geo).y
let delta = localFrame.height / 2
ZStack(alignment: .bottomTrailing) {
VideoPlayer(url: url, model: model)
if model.has_audio == true {
MuteIcon
.zIndex(11.0)
.onTapGesture {
self.model.muted = !self.model.muted
}
ZStack {
AVPlayerView(player: model.player)
if model.is_loading {
ProgressView()
.progressViewStyle(.circular)
.tint(.white)
.scaleEffect(CGSize(width: 1.5, height: 1.5))
}
}
.onChange(of: model.size) { size in
guard let size else {
return
if model.has_audio {
mute_button
}
video_size = size
}
.onChange(of: centerY) { _ in
/// pause video when it is scrolled beyond visible range
let isBelowTop = centerY + delta > 100, /// 100 =~ approx. bottom (y) of ContentView's TabView
isAboveBottom = centerY - delta < orientationTracker.deviceMajorAxis
if isBelowTop && isAboveBottom {
model.start()
} else {
model.stop()
update_is_visible(centerY: centerY)
}
.onAppear {
update_is_visible(centerY: centerY)
}
}
.onDisappear {
model.view_did_disappear()
}
}
private func update_is_visible(centerY: CGFloat) {
let isBelowTop = centerY > 100, /// 100 =~ approx. bottom (y) of ContentView's TabView
isAboveBottom = centerY < orientationTracker.deviceMajorAxis
model.set_view_is_visible(isBelowTop && isAboveBottom)
}
private var mute_icon: String {
!model.has_audio || model.is_muted ? "speaker.slash" : "speaker"
}
private var mute_icon_color: Color {
model.has_audio ? .white : .red
}
private var mute_button: some View {
HStack {
Spacer()
VStack {
Spacer()
Button {
model.did_tap_mute_button()
} label: {
ZStack {
Circle()
.opacity(0.2)
.frame(width: 32, height: 32)
.foregroundColor(.black)
Image(systemName: mute_icon)
.padding()
.foregroundColor(mute_icon_color)
}
}
}
}
}
}
struct DamusVideoPlayer_Previews: PreviewProvider {
@StateObject static var model: VideoPlayerModel = VideoPlayerModel()
static var previews: some View {
DamusVideoPlayer(url: URL(string: "http://cdn.jb55.com/s/zaps-build.mp4")!, model: model, video_size: .constant(nil))
DamusVideoPlayer(url: URL(string: "http://cdn.jb55.com/s/zaps-build.mp4")!, video_size: .constant(nil), controller: VideoController())
}
}