1 // Copyright 2023-present 650 Industries. All rights reserved. 2 3 import ExpoModulesCore 4 5 public final class VideoModule: Module { definitionnull6 public func definition() -> ModuleDefinition { 7 Name("ExpoVideo") 8 9 View(VideoView.self) { 10 Prop("player") { (view, player: VideoPlayer?) in 11 view.player = player?.pointer 12 } 13 14 Prop("nativeControls") { (view, nativeControls: Bool?) in 15 view.playerViewController.showsPlaybackControls = nativeControls ?? true 16 } 17 18 Prop("contentFit") { (view, contentFit: VideoContentFit?) in 19 view.playerViewController.videoGravity = contentFit?.toVideoGravity() ?? .resizeAspect 20 } 21 22 Prop("contentPosition") { (view, contentPosition: CGVector?) in 23 let layer = view.playerViewController.view.layer 24 25 layer.frame = CGRect( 26 x: contentPosition?.dx ?? 0, 27 y: contentPosition?.dy ?? 0, 28 width: layer.frame.width, 29 height: layer.frame.height 30 ) 31 } 32 33 Prop("allowsFullscreen") { (view, allowsFullscreen: Bool?) in 34 view.playerViewController.setValue(allowsFullscreen ?? true, forKey: "allowsEnteringFullScreen") 35 } 36 37 Prop("showsTimecodes") { (view, showsTimecodes: Bool?) in 38 view.playerViewController.showsTimecodes = showsTimecodes ?? true 39 } 40 41 Prop("requiresLinearPlayback") { (view, requiresLinearPlayback: Bool?) in 42 view.playerViewController.requiresLinearPlayback = requiresLinearPlayback ?? false 43 } 44 45 AsyncFunction("enterFullscreen") { view in 46 view.enterFullscreen() 47 } 48 49 AsyncFunction("exitFullscreen") { view in 50 view.exitFullscreen() 51 } 52 } 53 54 Class(VideoPlayer.self) { 55 Constructor { (source: String?) -> VideoPlayer in 56 if let source, let url = URL(string: source) { 57 let item = AVPlayerItem(url: url) 58 return VideoPlayer(AVPlayer(playerItem: item)) 59 } 60 return VideoPlayer(AVPlayer()) 61 } 62 63 Property("isPlaying") { (player: VideoPlayer) in 64 return player.pointer.timeControlStatus == .playing 65 } 66 67 Property("isMuted") { (player: VideoPlayer) -> Bool in 68 return player.pointer.isMuted 69 } 70 .set { (player, isMuted: Bool) in 71 player.pointer.isMuted = isMuted 72 } 73 74 Property("currentTime") { (player: VideoPlayer) -> Double in 75 return player.pointer.currentTime().seconds 76 } 77 78 Function("play") { player in 79 player.pointer.play() 80 } 81 82 Function("pause") { player in 83 player.pointer.pause() 84 } 85 86 Function("replace") { (player, source: String) in 87 guard let url = URL(string: source) else { 88 player.pointer.replaceCurrentItem(with: nil) 89 return 90 } 91 let newPlayerItem = AVPlayerItem(url: url) 92 93 player.pointer.replaceCurrentItem(with: newPlayerItem) 94 player.pointer.play() 95 } 96 97 Function("seekBy") { (player, seconds: Double) in 98 let newTime = player.pointer.currentTime() + CMTime(seconds: seconds, preferredTimescale: .max) 99 100 player.pointer.seek(to: newTime) 101 } 102 103 Function("replay") { player in 104 player.pointer.seek(to: CMTime.zero) 105 } 106 } 107 } 108 } 109