Add black gradient behind compact overlay buttons

This commit is contained in:
Ethan Pippin 2021-12-30 01:28:08 -07:00
parent 4219ecc8dc
commit a25a62a2be
1 changed files with 170 additions and 168 deletions

View File

@ -36,167 +36,176 @@ struct VLCPlayerCompactOverlayView: View, VideoPlayerOverlay {
private var mainBody: some View { private var mainBody: some View {
VStack { VStack {
VStack(alignment: .EpisodeSeriesAlignmentGuide) { // MARK: Top Bar
ZStack {
// MARK: Top Bar LinearGradient(gradient: Gradient(colors: [.black, .clear]),
HStack(alignment: .center) { startPoint: .top,
endPoint: .bottom)
.ignoresSafeArea()
.frame(height: 80)
VStack(alignment: .EpisodeSeriesAlignmentGuide) {
HStack { HStack(alignment: .center) {
Button {
viewModel.playerOverlayDelegate?.didSelectClose() HStack {
} label: { Button {
Image(systemName: "chevron.backward") viewModel.playerOverlayDelegate?.didSelectClose()
.padding() } label: {
.padding(.trailing, -10) Image(systemName: "chevron.backward")
.padding()
.padding(.trailing, -10)
}
Text(viewModel.title)
.font(.system(size: 28, weight: .regular, design: .default))
.alignmentGuide(.EpisodeSeriesAlignmentGuide) { context in
context[.leading]
}
} }
Text(viewModel.title) Spacer()
.font(.system(size: 28, weight: .regular, design: .default))
HStack(spacing: 20) {
if viewModel.showAdjacentItems {
Button {
viewModel.playerOverlayDelegate?.didSelectPreviousItem()
} label: {
Image(systemName: "chevron.left.circle")
}
.disabled(viewModel.previousItemVideoPlayerViewModel == nil)
.foregroundColor(viewModel.nextItemVideoPlayerViewModel == nil ? .gray : .white)
Button {
viewModel.playerOverlayDelegate?.didSelectNextItem()
} label: {
Image(systemName: "chevron.right.circle")
}
.disabled(viewModel.nextItemVideoPlayerViewModel == nil)
.foregroundColor(viewModel.nextItemVideoPlayerViewModel == nil ? .gray : .white)
}
if viewModel.shouldShowGoogleCast {
Button {
viewModel.playerOverlayDelegate?.didSelectGoogleCast()
} label: {
Image(systemName: "rectangle.badge.plus")
}
}
if viewModel.shouldShowAirplay {
Button {
viewModel.playerOverlayDelegate?.didSelectAirplay()
} label: {
Image(systemName: "airplayvideo")
}
}
// Button {
// viewModel.screenFilled = !viewModel.screenFilled
// } label: {
// if viewModel.screenFilled {
// Image(systemName: "rectangle.arrowtriangle.2.inward")
// .rotationEffect(Angle(degrees: 90))
// } else {
// Image(systemName: "rectangle.arrowtriangle.2.outward")
// .rotationEffect(Angle(degrees: 90))
// }
// }
if !viewModel.subtitleStreams.isEmpty {
Button {
viewModel.playerOverlayDelegate?.didSelectCaptions()
} label: {
if viewModel.subtitlesEnabled {
Image(systemName: "captions.bubble.fill")
} else {
Image(systemName: "captions.bubble")
}
}
.disabled(viewModel.selectedSubtitleStreamIndex == -1)
.foregroundColor(viewModel.selectedSubtitleStreamIndex == -1 ? .gray : .white)
}
// MARK: Settings Menu
Menu {
Menu {
ForEach(viewModel.audioStreams, id: \.self) { audioStream in
Button {
viewModel.selectedAudioStreamIndex = audioStream.index ?? -1
} label: {
if audioStream.index == viewModel.selectedAudioStreamIndex {
Label.init(audioStream.displayTitle ?? "No Title", systemImage: "checkmark")
} else {
Text(audioStream.displayTitle ?? "No Title")
}
}
}
} label: {
HStack {
Image(systemName: "speaker.wave.3")
Text("Audio")
}
}
Menu {
ForEach(viewModel.subtitleStreams, id: \.self) { subtitleStream in
Button {
viewModel.selectedSubtitleStreamIndex = subtitleStream.index ?? -1
} label: {
if subtitleStream.index == viewModel.selectedSubtitleStreamIndex {
Label.init(subtitleStream.displayTitle ?? "No Title", systemImage: "checkmark")
} else {
Text(subtitleStream.displayTitle ?? "No Title")
}
}
}
} label: {
HStack {
Image(systemName: "captions.bubble")
Text("Subtitles")
}
}
Menu {
ForEach(PlaybackSpeed.allCases, id: \.self) { speed in
Button {
viewModel.playbackSpeed = speed
} label: {
if speed == viewModel.playbackSpeed {
Label(speed.displayTitle, systemImage: "checkmark")
} else {
Text(speed.displayTitle)
}
}
}
} label: {
HStack {
Image(systemName: "speedometer")
Text("Playback Speed")
}
}
} label: {
Image(systemName: "ellipsis.circle")
}
}
}
.font(.system(size: 24))
.frame(height: 50)
if let seriesTitle = viewModel.subtitle {
Text(seriesTitle)
.font(.subheadline)
.foregroundColor(Color.gray)
.alignmentGuide(.EpisodeSeriesAlignmentGuide) { context in .alignmentGuide(.EpisodeSeriesAlignmentGuide) { context in
context[.leading] context[.leading]
} }
.offset(y: -10)
} }
Spacer()
HStack(spacing: 20) {
if viewModel.showAdjacentItems {
Button {
viewModel.playerOverlayDelegate?.didSelectPreviousItem()
} label: {
Image(systemName: "chevron.left.circle")
}
.disabled(viewModel.previousItemVideoPlayerViewModel == nil)
.foregroundColor(viewModel.nextItemVideoPlayerViewModel == nil ? .gray : .white)
Button {
viewModel.playerOverlayDelegate?.didSelectNextItem()
} label: {
Image(systemName: "chevron.right.circle")
}
.disabled(viewModel.nextItemVideoPlayerViewModel == nil)
.foregroundColor(viewModel.nextItemVideoPlayerViewModel == nil ? .gray : .white)
}
if viewModel.shouldShowGoogleCast {
Button {
viewModel.playerOverlayDelegate?.didSelectGoogleCast()
} label: {
Image(systemName: "rectangle.badge.plus")
}
}
if viewModel.shouldShowAirplay {
Button {
viewModel.playerOverlayDelegate?.didSelectAirplay()
} label: {
Image(systemName: "airplayvideo")
}
}
// Button {
// viewModel.screenFilled = !viewModel.screenFilled
// } label: {
// if viewModel.screenFilled {
// Image(systemName: "rectangle.arrowtriangle.2.inward")
// .rotationEffect(Angle(degrees: 90))
// } else {
// Image(systemName: "rectangle.arrowtriangle.2.outward")
// .rotationEffect(Angle(degrees: 90))
// }
// }
if !viewModel.subtitleStreams.isEmpty {
Button {
viewModel.playerOverlayDelegate?.didSelectCaptions()
} label: {
if viewModel.subtitlesEnabled {
Image(systemName: "captions.bubble.fill")
} else {
Image(systemName: "captions.bubble")
}
}
.disabled(viewModel.selectedSubtitleStreamIndex == -1)
.foregroundColor(viewModel.selectedSubtitleStreamIndex == -1 ? .gray : .white)
}
// MARK: Settings Menu
Menu {
Menu {
ForEach(viewModel.audioStreams, id: \.self) { audioStream in
Button {
viewModel.selectedAudioStreamIndex = audioStream.index ?? -1
} label: {
if audioStream.index == viewModel.selectedAudioStreamIndex {
Label.init(audioStream.displayTitle ?? "No Title", systemImage: "checkmark")
} else {
Text(audioStream.displayTitle ?? "No Title")
}
}
}
} label: {
HStack {
Image(systemName: "speaker.wave.3")
Text("Audio")
}
}
Menu {
ForEach(viewModel.subtitleStreams, id: \.self) { subtitleStream in
Button {
viewModel.selectedSubtitleStreamIndex = subtitleStream.index ?? -1
} label: {
if subtitleStream.index == viewModel.selectedSubtitleStreamIndex {
Label.init(subtitleStream.displayTitle ?? "No Title", systemImage: "checkmark")
} else {
Text(subtitleStream.displayTitle ?? "No Title")
}
}
}
} label: {
HStack {
Image(systemName: "captions.bubble")
Text("Subtitles")
}
}
Menu {
ForEach(PlaybackSpeed.allCases, id: \.self) { speed in
Button {
viewModel.playbackSpeed = speed
} label: {
if speed == viewModel.playbackSpeed {
Label(speed.displayTitle, systemImage: "checkmark")
} else {
Text(speed.displayTitle)
}
}
}
} label: {
HStack {
Image(systemName: "speedometer")
Text("Playback Speed")
}
}
} label: {
Image(systemName: "ellipsis.circle")
}
}
}
.font(.system(size: 24))
.frame(height: 50)
if let seriesTitle = viewModel.subtitle {
Text(seriesTitle)
.font(.subheadline)
.foregroundColor(Color.gray)
.alignmentGuide(.EpisodeSeriesAlignmentGuide) { context in
context[.leading]
}
.offset(y: -10)
} }
} }
@ -205,11 +214,11 @@ struct VLCPlayerCompactOverlayView: View, VideoPlayerOverlay {
// MARK: Bottom Bar // MARK: Bottom Bar
ZStack { ZStack {
// VisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterialDark)) LinearGradient(gradient: Gradient(colors: [.clear, .black]),
// .cornerRadius(25) startPoint: .top,
// .mask { endPoint: .bottom)
// Rectangle() .ignoresSafeArea()
// } .frame(height: 70)
HStack { HStack {
@ -266,8 +275,9 @@ struct VLCPlayerCompactOverlayView: View, VideoPlayerOverlay {
.frame(minWidth: 70, maxWidth: 70) .frame(minWidth: 70, maxWidth: 70)
} }
.padding(.horizontal) .padding(.horizontal)
// .frame(maxWidth: 800, maxHeight: 50)
} }
.frame(maxWidth: 800, maxHeight: 50) .frame(maxHeight: 50)
} }
.ignoresSafeArea(edges: .top) .ignoresSafeArea(edges: .top)
.tint(Color.white) .tint(Color.white)
@ -283,16 +293,10 @@ struct VLCPlayerCompactOverlayView: View, VideoPlayerOverlay {
} }
} }
struct VisualEffectView: UIViewRepresentable {
var effect: UIVisualEffect?
func makeUIView(context: UIViewRepresentableContext<Self>) -> UIVisualEffectView { UIVisualEffectView() }
func updateUIView(_ uiView: UIVisualEffectView, context: UIViewRepresentableContext<Self>) { uiView.effect = effect }
}
struct VLCPlayerCompactOverlayView_Previews: PreviewProvider { struct VLCPlayerCompactOverlayView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
ZStack { ZStack {
Color.black Color.red
.ignoresSafeArea() .ignoresSafeArea()
VLCPlayerCompactOverlayView(viewModel: VideoPlayerViewModel(item: BaseItemDto(runTimeTicks: 720 * 10_000_000), VLCPlayerCompactOverlayView(viewModel: VideoPlayerViewModel(item: BaseItemDto(runTimeTicks: 720 * 10_000_000),
@ -317,5 +321,3 @@ struct VLCPlayerCompactOverlayView_Previews: PreviewProvider {
.previewInterfaceOrientation(.landscapeLeft) .previewInterfaceOrientation(.landscapeLeft)
} }
} }