VideoView.swift 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. //
  2. // VideoView.swift
  3. // LoopKitUI
  4. //
  5. // Created by Rick Pasetto on 4/13/21.
  6. // Copyright © 2021 Tidepool Project. All rights reserved.
  7. //
  8. import SwiftUI
  9. import AVKit
  10. /// Opens a Swift `VideoPlayer` on the given URL in a new page
  11. public struct VideoView: View {
  12. @Environment(\.dismissAction) var dismissAction
  13. let url: URL?
  14. let autoPlay: Bool
  15. public var isActive: Binding<Bool>?
  16. private class PlayerHolder {
  17. private let prevCategory: AVAudioSession.Category?
  18. private var player: AVPlayer?
  19. init(overrideMuteSwitch: Bool) {
  20. if overrideMuteSwitch {
  21. prevCategory = AVAudioSession.sharedInstance().category
  22. } else {
  23. prevCategory = nil
  24. }
  25. }
  26. func destroy() {
  27. if let prevCategory = prevCategory {
  28. try? AVAudioSession.sharedInstance().setCategory(prevCategory)
  29. }
  30. }
  31. func player(for url: URL, autoPlay: Bool) -> AVPlayer {
  32. if let player = player {
  33. return player
  34. } else {
  35. let player = AVPlayer(url: url)
  36. if autoPlay, player.timeControlStatus == .paused {
  37. player.play()
  38. } else if !autoPlay, player.timeControlStatus == .playing {
  39. player.pause()
  40. }
  41. if prevCategory != nil {
  42. // Overrides mute switch (Silent mode) on the phone
  43. try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
  44. }
  45. self.player = player
  46. return player
  47. }
  48. }
  49. }
  50. private let playerHolder: PlayerHolder
  51. public init(url: URL?, autoPlay: Bool, overrideMuteSwitch: Bool = false, isActive: Binding<Bool>? = nil) {
  52. self.url = url
  53. self.autoPlay = autoPlay
  54. self.playerHolder = PlayerHolder(overrideMuteSwitch: overrideMuteSwitch)
  55. self.isActive = isActive
  56. }
  57. private func dismiss() {
  58. guard isActive != nil else {
  59. dismissAction()
  60. return
  61. }
  62. isActive?.wrappedValue = false
  63. }
  64. public var body: some View {
  65. HStack {
  66. Spacer()
  67. Button(LocalizedString("Done", comment: "Video player done button label"), action: dismiss)
  68. }
  69. .padding()
  70. if let url = url {
  71. VideoPlayer(player: playerHolder.player(for: url, autoPlay: autoPlay))
  72. .onDisappear {
  73. playerHolder.destroy()
  74. }
  75. } else {
  76. Spacer()
  77. Image(systemName: "questionmark.video")
  78. .resizable()
  79. .scaledToFit()
  80. .frame(width: 100, height: 100, alignment: .center)
  81. Spacer()
  82. }
  83. }
  84. }
  85. struct VideoView_Previews: PreviewProvider {
  86. static var previews: some View {
  87. VideoView(url: nil, autoPlay: true, overrideMuteSwitch: true)
  88. }
  89. }