VideoPlayView.swift 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. //
  2. // VideoPlayView.swift
  3. // LoopKitUI
  4. //
  5. // Created by Rick Pasetto on 5/12/22.
  6. // Copyright © 2022 LoopKit Authors. All rights reserved.
  7. //
  8. import SwiftUI
  9. public struct VideoPlayView<ThumbnailContent: View>: View {
  10. let thumbnail: () -> ThumbnailContent
  11. let includeThumbnailBorder: Bool
  12. let centerThumbnail: Bool
  13. let url: URL?
  14. let hasBeenPlayed: Binding<Bool>
  15. private var _autoPlay: Bool = true
  16. private var _overrideMuteSwitch: Bool = true
  17. @State private var isActive: Bool = false
  18. // This from right out of the Design spec
  19. private let frameColor = Color(UIColor(red: 0.784, green: 0.784, blue: 0.784, alpha: 1))
  20. public init(url: URL?, thumbnail: @autoclosure @escaping () -> ThumbnailContent, includeThumbnailBorder: Bool = true, centerThumbnail: Bool = true) {
  21. self.url = url
  22. self.thumbnail = thumbnail
  23. self.includeThumbnailBorder = includeThumbnailBorder
  24. self.centerThumbnail = centerThumbnail
  25. self.hasBeenPlayed = .false
  26. }
  27. public init(url: URL?, thumbnail: @autoclosure @escaping () -> ThumbnailContent, hasBeenPlayed: Binding<Bool>, includeThumbnailBorder: Bool = true, centerThumbnail: Bool = true) {
  28. self.url = url
  29. self.thumbnail = thumbnail
  30. self.includeThumbnailBorder = includeThumbnailBorder
  31. self.centerThumbnail = centerThumbnail
  32. self.hasBeenPlayed = hasBeenPlayed
  33. }
  34. private init(_ other: Self, url: URL?? = nil, thumbnail: (() -> ThumbnailContent)? = nil, hasBeenPlayed: Binding<Bool>? = nil, autoPlay: Bool? = nil, overrideMuteSwitch: Bool? = nil, includeThumbnailBorder: Bool? = nil, centerThumbnail: Bool? = nil) {
  35. self.url = url ?? other.url
  36. self.thumbnail = thumbnail ?? other.thumbnail
  37. self.hasBeenPlayed = hasBeenPlayed ?? other.hasBeenPlayed
  38. self.includeThumbnailBorder = includeThumbnailBorder ?? other.includeThumbnailBorder
  39. self.centerThumbnail = centerThumbnail ?? other.centerThumbnail
  40. self._autoPlay = autoPlay ?? other._autoPlay
  41. self._overrideMuteSwitch = overrideMuteSwitch ?? other._overrideMuteSwitch
  42. }
  43. public var body: some View {
  44. PopoverLink(destination: videoView, isActive: $isActive) {
  45. if includeThumbnailBorder {
  46. placeholderImage
  47. .padding()
  48. .border(frameColor, width: 1)
  49. } else {
  50. placeholderImage
  51. }
  52. }
  53. .fullScreen()
  54. }
  55. private var placeholderImage: some View {
  56. HStack {
  57. if centerThumbnail {
  58. Spacer()
  59. }
  60. ZStack {
  61. thumbnail()
  62. Image(frameworkImage: "play-button", decorative: true)
  63. }
  64. if centerThumbnail {
  65. Spacer()
  66. }
  67. }
  68. .aspectRatio(CGSize(width: 16, height: 9), contentMode: .fit)
  69. .frame(maxWidth: .infinity)
  70. }
  71. @ViewBuilder
  72. private var videoView: some View {
  73. VideoView(url: url, autoPlay: _autoPlay, overrideMuteSwitch: _overrideMuteSwitch, isActive: $isActive)
  74. .onDisappear { hasBeenPlayed.wrappedValue = true }
  75. }
  76. public func autoPlay(_ enabled: Bool) -> Self {
  77. Self.init(self, autoPlay: enabled)
  78. }
  79. public func overrideMuteSwitch(_ enabled: Bool) -> Self {
  80. Self.init(self, overrideMuteSwitch: enabled)
  81. }
  82. public func includeThumbnailBorder(_ value: Bool) -> Self {
  83. Self.init(self, includeThumbnailBorder: value)
  84. }
  85. public func centerThumbnail(_ value: Bool) -> Self {
  86. Self.init(self, centerThumbnail: value)
  87. }
  88. }
  89. fileprivate extension Binding where Value == Bool {
  90. static var `true` = Binding(get: { true }, set: { _ in })
  91. static var `false` = Binding(get: { false }, set: { _ in })
  92. }