Loading Video.js +10 −0 Changes for Video.js: 10 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -220,6 +220,16 @@ Video.propTypes = { src: PropTypes.object, seek: PropTypes.number, fullscreen: PropTypes.bool, onVideoLoadStart: PropTypes.func, onVideoLoad: PropTypes.func, onVideoError: PropTypes.func, onVideoProgress: PropTypes.func, onVideoSeek: PropTypes.func, onVideoEnd: PropTypes.func, onVideoFullscreenPlayerWillPresent: PropTypes.func, onVideoFullscreenPlayerDidPresent: PropTypes.func, onVideoFullscreenPlayerWillDismiss: PropTypes.func, onVideoFullscreenPlayerDidDismiss: PropTypes.func, /* Wrapper component */ source: PropTypes.oneOfType([ Loading ios/RCTVideo.h +15 −0 Changes for ios/RCTVideo.h: 15 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -9,6 +9,21 @@ @interface RCTVideo : UIView <RCTVideoPlayerViewControllerDelegate> @property (nonatomic, copy) RCTBubblingEventBlock onVideoLoadStart; @property (nonatomic, copy) RCTBubblingEventBlock onVideoLoad; @property (nonatomic, copy) RCTBubblingEventBlock onVideoError; @property (nonatomic, copy) RCTBubblingEventBlock onVideoProgress; @property (nonatomic, copy) RCTBubblingEventBlock onVideoSeek; @property (nonatomic, copy) RCTBubblingEventBlock onVideoEnd; @property (nonatomic, copy) RCTBubblingEventBlock onVideoFullscreenPlayerWillPresent; @property (nonatomic, copy) RCTBubblingEventBlock onVideoFullscreenPlayerDidPresent; @property (nonatomic, copy) RCTBubblingEventBlock onVideoFullscreenPlayerWillDismiss; @property (nonatomic, copy) RCTBubblingEventBlock onVideoFullscreenPlayerDidDismiss; @property (nonatomic, copy) RCTBubblingEventBlock onReadyForDisplay; @property (nonatomic, copy) RCTBubblingEventBlock onPlaybackStalled; @property (nonatomic, copy) RCTBubblingEventBlock onPlaybackResume; @property (nonatomic, copy) RCTBubblingEventBlock onPlaybackRateChange; - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER; - (AVPlayerViewController*)createPlayerViewController:(AVPlayer*)player withPlayerItem:(AVPlayerItem*)playerItem; Loading ios/RCTVideo.m +26 −30 Changes for ios/RCTVideo.m: 26 added lines, 30 removed lines. Original line number Diff line number Diff line Loading @@ -185,15 +185,14 @@ static NSString *const playbackRate = @"rate"; const Float64 duration = CMTimeGetSeconds(playerDuration); const Float64 currentTimeSecs = CMTimeGetSeconds(currentTime); if( currentTimeSecs >= 0) { [_eventDispatcher sendInputEventWithName:@"onVideoProgress" body:@{ self.onVideoProgress(@{ @"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(currentTime)], @"playableDuration": [self calculatePlayableDuration], @"atValue": [NSNumber numberWithLongLong:currentTime.value], @"atTimescale": [NSNumber numberWithInt:currentTime.timescale], @"target": self.reactTag, @"seekableDuration": [NSNumber numberWithFloat:CMTimeGetSeconds([self playerItemSeekableTimeRange].duration)], }]; }); } } Loading Loading @@ -275,12 +274,16 @@ static NSString *const playbackRate = @"rate"; queue:NULL usingBlock:^(CMTime time) { [weakSelf sendProgressUpdate]; } ]; [_eventDispatcher sendInputEventWithName:@"onVideoLoadStart" body:@{@"src": @{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ //Perform on next run loop, otherwise onVideoLoadStart is nil self.onVideoLoadStart(@{@"src": @{ @"uri": [source objectForKey:@"uri"], @"type": [source objectForKey:@"type"], @"isNetwork": [NSNumber numberWithBool:(bool)[source objectForKey:@"isNetwork"]]}, @"target": self.reactTag}]; @"target": self.reactTag }); }); } - (AVPlayerItem*)playerItemForSource:(NSDictionary *)source Loading Loading @@ -339,8 +342,7 @@ static NSString *const playbackRate = @"rate"; orientation = @"portrait"; } [_eventDispatcher sendInputEventWithName:@"onVideoLoad" body:@{@"duration": [NSNumber numberWithFloat:duration], self.onVideoLoad(@{@"duration": [NSNumber numberWithFloat:duration], @"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(_playerItem.currentTime)], @"canPlayReverse": [NSNumber numberWithBool:_playerItem.canPlayReverse], @"canPlayFastForward": [NSNumber numberWithBool:_playerItem.canPlayFastForward], Loading @@ -353,16 +355,14 @@ static NSString *const playbackRate = @"rate"; @"height": height, @"orientation": orientation }, @"target": self.reactTag}]; @"target": self.reactTag}); [self attachListeners]; [self applyModifiers]; } else if(_playerItem.status == AVPlayerItemStatusFailed) { [_eventDispatcher sendInputEventWithName:@"onVideoError" body:@{@"error": @{ @"code": [NSNumber numberWithInteger: _playerItem.error.code], self.onVideoError(@{@"error": @{@"code": [NSNumber numberWithInteger: _playerItem.error.code], @"domain": _playerItem.error.domain}, @"target": self.reactTag}]; @"target": self.reactTag}); } } else if ([keyPath isEqualToString:playbackBufferEmptyKeyPath]) { _playerBufferEmpty = YES; Loading @@ -376,19 +376,16 @@ static NSString *const playbackRate = @"rate"; } else if (object == _playerLayer) { if([keyPath isEqualToString:readyForDisplayKeyPath] && [change objectForKey:NSKeyValueChangeNewKey]) { if([change objectForKey:NSKeyValueChangeNewKey]) { [_eventDispatcher sendInputEventWithName:@"onReadyForDisplay" body:@{@"target": self.reactTag}]; self.onReadyForDisplay(@{@"target": self.reactTag}); } } } else if (object == _player) { if([keyPath isEqualToString:playbackRate]) { [_eventDispatcher sendInputEventWithName:@"onPlaybackRateChange" body:@{@"playbackRate": [NSNumber numberWithFloat:_player.rate], @"target": self.reactTag}]; self.onPlaybackRateChange(@{@"playbackRate": [NSNumber numberWithFloat:_player.rate], @"target": self.reactTag}); if(_playbackStalled && _player.rate > 0) { [_eventDispatcher sendInputEventWithName:@"onPlaybackResume" body:@{@"playbackRate": [NSNumber numberWithFloat:_player.rate], @"target": self.reactTag}]; self.onPlaybackResume(@{@"playbackRate": [NSNumber numberWithFloat:_player.rate], @"target": self.reactTag}); _playbackStalled = NO; } } Loading @@ -412,13 +409,13 @@ static NSString *const playbackRate = @"rate"; - (void)playbackStalled:(NSNotification *)notification { [_eventDispatcher sendInputEventWithName:@"onPlaybackStalled" body:@{@"target": self.reactTag}]; self.onPlaybackStalled(@{@"target": self.reactTag}); _playbackStalled = YES; } - (void)playerItemDidReachEnd:(NSNotification *)notification { [_eventDispatcher sendInputEventWithName:@"onVideoEnd" body:@{@"target": self.reactTag}]; self.onVideoEnd(@{@"target": self.reactTag}); if (_repeat) { AVPlayerItem *item = [notification object]; Loading Loading @@ -490,10 +487,9 @@ static NSString *const playbackRate = @"rate"; if (CMTimeCompare(current, cmSeekTime) != 0) { [_player seekToTime:cmSeekTime toleranceBefore:tolerance toleranceAfter:tolerance completionHandler:^(BOOL finished) { [_eventDispatcher sendInputEventWithName:@"onVideoSeek" body:@{@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(item.currentTime)], self.onVideoSeek(@{@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(item.currentTime)], @"seekTime": [NSNumber numberWithFloat:seekTime], @"target": self.reactTag}]; @"target": self.reactTag}); }]; _pendingSeek = false; Loading Loading @@ -575,11 +571,11 @@ static NSString *const playbackRate = @"rate"; if( viewController ) { _presentingViewController = viewController; [_eventDispatcher sendInputEventWithName:@"onVideoFullscreenPlayerWillPresent" body:@{@"target": self.reactTag}]; self.onVideoFullscreenPlayerWillPresent(@{@"target": self.reactTag}); [viewController presentViewController:_playerViewController animated:true completion:^{ _playerViewController.showsPlaybackControls = YES; _fullscreenPlayerPresented = fullscreen; [_eventDispatcher sendInputEventWithName:@"onVideoFullscreenPlayerDidPresent" body:@{@"target": self.reactTag}]; self.onVideoFullscreenPlayerDidPresent(@{@"target": self.reactTag}); }]; } } Loading Loading @@ -659,7 +655,7 @@ static NSString *const playbackRate = @"rate"; { if (_playerViewController == playerViewController && _fullscreenPlayerPresented) { [_eventDispatcher sendInputEventWithName:@"onVideoFullscreenPlayerWillDismiss" body:@{@"target": self.reactTag}]; self.onVideoFullscreenPlayerWillDismiss(@{@"target": self.reactTag}); } } Loading @@ -670,7 +666,7 @@ static NSString *const playbackRate = @"rate"; _fullscreenPlayerPresented = false; _presentingViewController = nil; [self applyModifiers]; [_eventDispatcher sendInputEventWithName:@"onVideoFullscreenPlayerDidDismiss" body:@{@"target": self.reactTag}]; self.onVideoFullscreenPlayerDidDismiss(@{@"target": self.reactTag}); } } Loading ios/RCTVideoManager.m +15 −22 Changes for ios/RCTVideoManager.m: 15 added lines, 22 removed lines. Original line number Diff line number Diff line Loading @@ -14,28 +14,6 @@ RCT_EXPORT_MODULE(); return [[RCTVideo alloc] initWithEventDispatcher:self.bridge.eventDispatcher]; } /* Should support: onLoadStart, onLoad, and onError to stay consistent with Image */ - (NSArray *)customDirectEventTypes { return @[ @"onVideoLoadStart", @"onVideoLoad", @"onVideoError", @"onVideoProgress", @"onVideoSeek", @"onVideoEnd", @"onVideoFullscreenPlayerWillPresent", @"onVideoFullscreenPlayerDidPresent", @"onVideoFullscreenPlayerWillDismiss", @"onVideoFullscreenPlayerDidDismiss", @"onReadyForDisplay", @"onPlaybackStalled", @"onPlaybackResume", @"onPlaybackRateChange" ]; } - (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); Loading @@ -55,6 +33,21 @@ RCT_EXPORT_VIEW_PROPERTY(seek, float); RCT_EXPORT_VIEW_PROPERTY(currentTime, float); RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL); RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float); /* Should support: onLoadStart, onLoad, and onError to stay consistent with Image */ RCT_EXPORT_VIEW_PROPERTY(onVideoLoadStart, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoLoad, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoError, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoProgress, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoSeek, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoEnd, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoFullscreenPlayerWillPresent, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoFullscreenPlayerDidPresent, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoFullscreenPlayerWillDismiss, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoFullscreenPlayerDidDismiss, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onReadyForDisplay, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onPlaybackStalled, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onPlaybackResume, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onPlaybackRateChange, RCTBubblingEventBlock); - (NSDictionary *)constantsToExport { Loading Loading
Video.js +10 −0 Changes for Video.js: 10 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -220,6 +220,16 @@ Video.propTypes = { src: PropTypes.object, seek: PropTypes.number, fullscreen: PropTypes.bool, onVideoLoadStart: PropTypes.func, onVideoLoad: PropTypes.func, onVideoError: PropTypes.func, onVideoProgress: PropTypes.func, onVideoSeek: PropTypes.func, onVideoEnd: PropTypes.func, onVideoFullscreenPlayerWillPresent: PropTypes.func, onVideoFullscreenPlayerDidPresent: PropTypes.func, onVideoFullscreenPlayerWillDismiss: PropTypes.func, onVideoFullscreenPlayerDidDismiss: PropTypes.func, /* Wrapper component */ source: PropTypes.oneOfType([ Loading
ios/RCTVideo.h +15 −0 Changes for ios/RCTVideo.h: 15 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -9,6 +9,21 @@ @interface RCTVideo : UIView <RCTVideoPlayerViewControllerDelegate> @property (nonatomic, copy) RCTBubblingEventBlock onVideoLoadStart; @property (nonatomic, copy) RCTBubblingEventBlock onVideoLoad; @property (nonatomic, copy) RCTBubblingEventBlock onVideoError; @property (nonatomic, copy) RCTBubblingEventBlock onVideoProgress; @property (nonatomic, copy) RCTBubblingEventBlock onVideoSeek; @property (nonatomic, copy) RCTBubblingEventBlock onVideoEnd; @property (nonatomic, copy) RCTBubblingEventBlock onVideoFullscreenPlayerWillPresent; @property (nonatomic, copy) RCTBubblingEventBlock onVideoFullscreenPlayerDidPresent; @property (nonatomic, copy) RCTBubblingEventBlock onVideoFullscreenPlayerWillDismiss; @property (nonatomic, copy) RCTBubblingEventBlock onVideoFullscreenPlayerDidDismiss; @property (nonatomic, copy) RCTBubblingEventBlock onReadyForDisplay; @property (nonatomic, copy) RCTBubblingEventBlock onPlaybackStalled; @property (nonatomic, copy) RCTBubblingEventBlock onPlaybackResume; @property (nonatomic, copy) RCTBubblingEventBlock onPlaybackRateChange; - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER; - (AVPlayerViewController*)createPlayerViewController:(AVPlayer*)player withPlayerItem:(AVPlayerItem*)playerItem; Loading
ios/RCTVideo.m +26 −30 Changes for ios/RCTVideo.m: 26 added lines, 30 removed lines. Original line number Diff line number Diff line Loading @@ -185,15 +185,14 @@ static NSString *const playbackRate = @"rate"; const Float64 duration = CMTimeGetSeconds(playerDuration); const Float64 currentTimeSecs = CMTimeGetSeconds(currentTime); if( currentTimeSecs >= 0) { [_eventDispatcher sendInputEventWithName:@"onVideoProgress" body:@{ self.onVideoProgress(@{ @"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(currentTime)], @"playableDuration": [self calculatePlayableDuration], @"atValue": [NSNumber numberWithLongLong:currentTime.value], @"atTimescale": [NSNumber numberWithInt:currentTime.timescale], @"target": self.reactTag, @"seekableDuration": [NSNumber numberWithFloat:CMTimeGetSeconds([self playerItemSeekableTimeRange].duration)], }]; }); } } Loading Loading @@ -275,12 +274,16 @@ static NSString *const playbackRate = @"rate"; queue:NULL usingBlock:^(CMTime time) { [weakSelf sendProgressUpdate]; } ]; [_eventDispatcher sendInputEventWithName:@"onVideoLoadStart" body:@{@"src": @{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ //Perform on next run loop, otherwise onVideoLoadStart is nil self.onVideoLoadStart(@{@"src": @{ @"uri": [source objectForKey:@"uri"], @"type": [source objectForKey:@"type"], @"isNetwork": [NSNumber numberWithBool:(bool)[source objectForKey:@"isNetwork"]]}, @"target": self.reactTag}]; @"target": self.reactTag }); }); } - (AVPlayerItem*)playerItemForSource:(NSDictionary *)source Loading Loading @@ -339,8 +342,7 @@ static NSString *const playbackRate = @"rate"; orientation = @"portrait"; } [_eventDispatcher sendInputEventWithName:@"onVideoLoad" body:@{@"duration": [NSNumber numberWithFloat:duration], self.onVideoLoad(@{@"duration": [NSNumber numberWithFloat:duration], @"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(_playerItem.currentTime)], @"canPlayReverse": [NSNumber numberWithBool:_playerItem.canPlayReverse], @"canPlayFastForward": [NSNumber numberWithBool:_playerItem.canPlayFastForward], Loading @@ -353,16 +355,14 @@ static NSString *const playbackRate = @"rate"; @"height": height, @"orientation": orientation }, @"target": self.reactTag}]; @"target": self.reactTag}); [self attachListeners]; [self applyModifiers]; } else if(_playerItem.status == AVPlayerItemStatusFailed) { [_eventDispatcher sendInputEventWithName:@"onVideoError" body:@{@"error": @{ @"code": [NSNumber numberWithInteger: _playerItem.error.code], self.onVideoError(@{@"error": @{@"code": [NSNumber numberWithInteger: _playerItem.error.code], @"domain": _playerItem.error.domain}, @"target": self.reactTag}]; @"target": self.reactTag}); } } else if ([keyPath isEqualToString:playbackBufferEmptyKeyPath]) { _playerBufferEmpty = YES; Loading @@ -376,19 +376,16 @@ static NSString *const playbackRate = @"rate"; } else if (object == _playerLayer) { if([keyPath isEqualToString:readyForDisplayKeyPath] && [change objectForKey:NSKeyValueChangeNewKey]) { if([change objectForKey:NSKeyValueChangeNewKey]) { [_eventDispatcher sendInputEventWithName:@"onReadyForDisplay" body:@{@"target": self.reactTag}]; self.onReadyForDisplay(@{@"target": self.reactTag}); } } } else if (object == _player) { if([keyPath isEqualToString:playbackRate]) { [_eventDispatcher sendInputEventWithName:@"onPlaybackRateChange" body:@{@"playbackRate": [NSNumber numberWithFloat:_player.rate], @"target": self.reactTag}]; self.onPlaybackRateChange(@{@"playbackRate": [NSNumber numberWithFloat:_player.rate], @"target": self.reactTag}); if(_playbackStalled && _player.rate > 0) { [_eventDispatcher sendInputEventWithName:@"onPlaybackResume" body:@{@"playbackRate": [NSNumber numberWithFloat:_player.rate], @"target": self.reactTag}]; self.onPlaybackResume(@{@"playbackRate": [NSNumber numberWithFloat:_player.rate], @"target": self.reactTag}); _playbackStalled = NO; } } Loading @@ -412,13 +409,13 @@ static NSString *const playbackRate = @"rate"; - (void)playbackStalled:(NSNotification *)notification { [_eventDispatcher sendInputEventWithName:@"onPlaybackStalled" body:@{@"target": self.reactTag}]; self.onPlaybackStalled(@{@"target": self.reactTag}); _playbackStalled = YES; } - (void)playerItemDidReachEnd:(NSNotification *)notification { [_eventDispatcher sendInputEventWithName:@"onVideoEnd" body:@{@"target": self.reactTag}]; self.onVideoEnd(@{@"target": self.reactTag}); if (_repeat) { AVPlayerItem *item = [notification object]; Loading Loading @@ -490,10 +487,9 @@ static NSString *const playbackRate = @"rate"; if (CMTimeCompare(current, cmSeekTime) != 0) { [_player seekToTime:cmSeekTime toleranceBefore:tolerance toleranceAfter:tolerance completionHandler:^(BOOL finished) { [_eventDispatcher sendInputEventWithName:@"onVideoSeek" body:@{@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(item.currentTime)], self.onVideoSeek(@{@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(item.currentTime)], @"seekTime": [NSNumber numberWithFloat:seekTime], @"target": self.reactTag}]; @"target": self.reactTag}); }]; _pendingSeek = false; Loading Loading @@ -575,11 +571,11 @@ static NSString *const playbackRate = @"rate"; if( viewController ) { _presentingViewController = viewController; [_eventDispatcher sendInputEventWithName:@"onVideoFullscreenPlayerWillPresent" body:@{@"target": self.reactTag}]; self.onVideoFullscreenPlayerWillPresent(@{@"target": self.reactTag}); [viewController presentViewController:_playerViewController animated:true completion:^{ _playerViewController.showsPlaybackControls = YES; _fullscreenPlayerPresented = fullscreen; [_eventDispatcher sendInputEventWithName:@"onVideoFullscreenPlayerDidPresent" body:@{@"target": self.reactTag}]; self.onVideoFullscreenPlayerDidPresent(@{@"target": self.reactTag}); }]; } } Loading Loading @@ -659,7 +655,7 @@ static NSString *const playbackRate = @"rate"; { if (_playerViewController == playerViewController && _fullscreenPlayerPresented) { [_eventDispatcher sendInputEventWithName:@"onVideoFullscreenPlayerWillDismiss" body:@{@"target": self.reactTag}]; self.onVideoFullscreenPlayerWillDismiss(@{@"target": self.reactTag}); } } Loading @@ -670,7 +666,7 @@ static NSString *const playbackRate = @"rate"; _fullscreenPlayerPresented = false; _presentingViewController = nil; [self applyModifiers]; [_eventDispatcher sendInputEventWithName:@"onVideoFullscreenPlayerDidDismiss" body:@{@"target": self.reactTag}]; self.onVideoFullscreenPlayerDidDismiss(@{@"target": self.reactTag}); } } Loading
ios/RCTVideoManager.m +15 −22 Changes for ios/RCTVideoManager.m: 15 added lines, 22 removed lines. Original line number Diff line number Diff line Loading @@ -14,28 +14,6 @@ RCT_EXPORT_MODULE(); return [[RCTVideo alloc] initWithEventDispatcher:self.bridge.eventDispatcher]; } /* Should support: onLoadStart, onLoad, and onError to stay consistent with Image */ - (NSArray *)customDirectEventTypes { return @[ @"onVideoLoadStart", @"onVideoLoad", @"onVideoError", @"onVideoProgress", @"onVideoSeek", @"onVideoEnd", @"onVideoFullscreenPlayerWillPresent", @"onVideoFullscreenPlayerDidPresent", @"onVideoFullscreenPlayerWillDismiss", @"onVideoFullscreenPlayerDidDismiss", @"onReadyForDisplay", @"onPlaybackStalled", @"onPlaybackResume", @"onPlaybackRateChange" ]; } - (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); Loading @@ -55,6 +33,21 @@ RCT_EXPORT_VIEW_PROPERTY(seek, float); RCT_EXPORT_VIEW_PROPERTY(currentTime, float); RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL); RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float); /* Should support: onLoadStart, onLoad, and onError to stay consistent with Image */ RCT_EXPORT_VIEW_PROPERTY(onVideoLoadStart, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoLoad, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoError, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoProgress, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoSeek, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoEnd, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoFullscreenPlayerWillPresent, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoFullscreenPlayerDidPresent, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoFullscreenPlayerWillDismiss, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoFullscreenPlayerDidDismiss, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onReadyForDisplay, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onPlaybackStalled, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onPlaybackResume, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onPlaybackRateChange, RCTBubblingEventBlock); - (NSDictionary *)constantsToExport { Loading