mirror of
https://github.com/zoriya/react-native-video.git
synced 2025-12-06 07:16:12 +00:00
Rework event handler to use add/remove styyle
This commit is contained in:
@@ -87,17 +87,17 @@ import { VideoPlayer } from 'react-native-video';
|
|||||||
|
|
||||||
const player = new VideoPlayer('https://example.com/video.mp4');
|
const player = new VideoPlayer('https://example.com/video.mp4');
|
||||||
|
|
||||||
player.onLoad = (data) => {
|
player.addEventListener('onLoad', (data) => {
|
||||||
console.log('Video loaded! Duration:', data.duration);
|
console.log('Video loaded! Duration:', data.duration);
|
||||||
};
|
});
|
||||||
|
|
||||||
player.onProgress = (data) => {
|
player.addEventListener('onProgress', (data) => {
|
||||||
console.log('Current time:', data.currentTime);
|
console.log('Current time:', data.currentTime);
|
||||||
};
|
});
|
||||||
|
|
||||||
player.onError = (error) => {
|
player.addEventListener('onError', (error) => {
|
||||||
console.error('Player Error:', error.code, error.message);
|
console.error('Player Error:', error.code, error.message);
|
||||||
};
|
});
|
||||||
|
|
||||||
player.play();
|
player.play();
|
||||||
```
|
```
|
||||||
@@ -105,4 +105,4 @@ player.play();
|
|||||||
## Clearing Events
|
## Clearing Events
|
||||||
|
|
||||||
- The `player.clearEvent(eventName)` method can be used to clear a specific native event handler.
|
- The `player.clearEvent(eventName)` method can be used to clear a specific native event handler.
|
||||||
- When a player instance is no longer needed and `player.release()` is called, all event listeners are automatically cleared
|
- When a player instance is no longer needed and `player.release()` is called, all event listeners are automatically cleared
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ import { VideoPlayerEvents } from './VideoPlayerEvents';
|
|||||||
class VideoPlayer extends VideoPlayerEvents implements VideoPlayerBase {
|
class VideoPlayer extends VideoPlayerEvents implements VideoPlayerBase {
|
||||||
protected player: VideoPlayerImpl;
|
protected player: VideoPlayerImpl;
|
||||||
|
|
||||||
public onError?: (error: VideoRuntimeError) => void = undefined;
|
|
||||||
|
|
||||||
constructor(source: VideoSource | VideoConfig | VideoPlayerSource) {
|
constructor(source: VideoSource | VideoConfig | VideoPlayerSource) {
|
||||||
const hybridSource = createSource(source);
|
const hybridSource = createSource(source);
|
||||||
const player = createPlayer(hybridSource);
|
const player = createPlayer(hybridSource);
|
||||||
@@ -57,8 +55,10 @@ class VideoPlayer extends VideoPlayerEvents implements VideoPlayerBase {
|
|||||||
private throwError(error: unknown) {
|
private throwError(error: unknown) {
|
||||||
const parsedError = tryParseNativeVideoError(error);
|
const parsedError = tryParseNativeVideoError(error);
|
||||||
|
|
||||||
if (parsedError instanceof VideoRuntimeError && this.onError) {
|
if (
|
||||||
this.onError(parsedError);
|
parsedError instanceof VideoRuntimeError
|
||||||
|
&& this.triggerEvent('onError', parsedError)
|
||||||
|
) {
|
||||||
// We don't throw errors if onError is provided
|
// We don't throw errors if onError is provided
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import type { VideoPlayerEventEmitter } from '../spec/nitro/VideoPlayerEventEmitter.nitro';
|
import type { VideoPlayerEventEmitter } from '../spec/nitro/VideoPlayerEventEmitter.nitro';
|
||||||
import type { VideoPlayerEvents as VideoPlayerEventsInterface } from './types/Events';
|
import type { AllPlayerEvents as PlayerEvents } from './types/Events';
|
||||||
|
|
||||||
export class VideoPlayerEvents implements VideoPlayerEventsInterface {
|
export class VideoPlayerEvents {
|
||||||
protected eventEmitter: VideoPlayerEventEmitter;
|
protected eventEmitter: VideoPlayerEventEmitter;
|
||||||
|
protected eventListeners: Partial<Record<keyof PlayerEvents, Set<(...params: any[]) => void>>> = {};
|
||||||
|
|
||||||
protected readonly supportedEvents: (keyof VideoPlayerEventsInterface)[] = [
|
protected readonly supportedEvents: (keyof PlayerEvents)[] = [
|
||||||
'onAudioBecomingNoisy',
|
'onAudioBecomingNoisy',
|
||||||
'onAudioFocusChange',
|
'onAudioFocusChange',
|
||||||
'onBandwidthUpdate',
|
'onBandwidthUpdate',
|
||||||
@@ -28,6 +29,37 @@ export class VideoPlayerEvents implements VideoPlayerEventsInterface {
|
|||||||
|
|
||||||
constructor(eventEmitter: VideoPlayerEventEmitter) {
|
constructor(eventEmitter: VideoPlayerEventEmitter) {
|
||||||
this.eventEmitter = eventEmitter;
|
this.eventEmitter = eventEmitter;
|
||||||
|
for (let event of this.supportedEvents){
|
||||||
|
// @ts-expect-error we narrow the type of the event
|
||||||
|
this.eventEmitter[event] = this.triggerEvent.bind(this, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected triggerEvent<Event extends keyof PlayerEvents>(
|
||||||
|
event: Event,
|
||||||
|
...params: Parameters<PlayerEvents[Event]>
|
||||||
|
): boolean {
|
||||||
|
if (!this.eventListeners[event]?.size)
|
||||||
|
return false;
|
||||||
|
for (let fn of this.eventListeners[event]) {
|
||||||
|
fn(...params);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
addEventListener<Event extends keyof PlayerEvents>(
|
||||||
|
event: Event,
|
||||||
|
callback: PlayerEvents[Event]
|
||||||
|
) {
|
||||||
|
this.eventListeners[event] ??= new Set<PlayerEvents[Event]>();
|
||||||
|
this.eventListeners[event].add(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeEventListener<Event extends keyof PlayerEvents>(
|
||||||
|
event: Event,
|
||||||
|
callback: PlayerEvents[Event]
|
||||||
|
) {
|
||||||
|
this.eventListeners[event]!.delete(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,177 +75,7 @@ export class VideoPlayerEvents implements VideoPlayerEventsInterface {
|
|||||||
* Clears a specific event from the event emitter.
|
* Clears a specific event from the event emitter.
|
||||||
* @param event - The name of the event to clear.
|
* @param event - The name of the event to clear.
|
||||||
*/
|
*/
|
||||||
clearEvent(event: keyof VideoPlayerEventsInterface) {
|
clearEvent(event: keyof PlayerEvents) {
|
||||||
this.eventEmitter[event] = VideoPlayerEvents.NOOP;
|
this.eventListeners[event]?.clear();
|
||||||
}
|
|
||||||
|
|
||||||
static NOOP = () => {};
|
|
||||||
|
|
||||||
set onAudioBecomingNoisy(
|
|
||||||
value: VideoPlayerEventsInterface['onAudioBecomingNoisy']
|
|
||||||
) {
|
|
||||||
this.eventEmitter.onAudioBecomingNoisy = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onAudioBecomingNoisy(): VideoPlayerEventsInterface['onAudioBecomingNoisy'] {
|
|
||||||
return this.eventEmitter.onAudioBecomingNoisy;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onAudioFocusChange(
|
|
||||||
value: VideoPlayerEventsInterface['onAudioFocusChange']
|
|
||||||
) {
|
|
||||||
this.eventEmitter.onAudioFocusChange = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onAudioFocusChange(): VideoPlayerEventsInterface['onAudioFocusChange'] {
|
|
||||||
return this.eventEmitter.onAudioFocusChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onBandwidthUpdate(
|
|
||||||
value: VideoPlayerEventsInterface['onBandwidthUpdate']
|
|
||||||
) {
|
|
||||||
this.eventEmitter.onBandwidthUpdate = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onBandwidthUpdate(): VideoPlayerEventsInterface['onBandwidthUpdate'] {
|
|
||||||
return this.eventEmitter.onBandwidthUpdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onBuffer(value: VideoPlayerEventsInterface['onBuffer']) {
|
|
||||||
this.eventEmitter.onBuffer = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onBuffer(): VideoPlayerEventsInterface['onBuffer'] {
|
|
||||||
return this.eventEmitter.onBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onControlsVisibleChange(
|
|
||||||
value: VideoPlayerEventsInterface['onControlsVisibleChange']
|
|
||||||
) {
|
|
||||||
this.eventEmitter.onControlsVisibleChange = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onControlsVisibleChange(): VideoPlayerEventsInterface['onControlsVisibleChange'] {
|
|
||||||
return this.eventEmitter.onControlsVisibleChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onEnd(value: VideoPlayerEventsInterface['onEnd']) {
|
|
||||||
this.eventEmitter.onEnd = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onEnd(): VideoPlayerEventsInterface['onEnd'] {
|
|
||||||
return this.eventEmitter.onEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onExternalPlaybackChange(
|
|
||||||
value: VideoPlayerEventsInterface['onExternalPlaybackChange']
|
|
||||||
) {
|
|
||||||
this.eventEmitter.onExternalPlaybackChange = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onExternalPlaybackChange(): VideoPlayerEventsInterface['onExternalPlaybackChange'] {
|
|
||||||
return this.eventEmitter.onExternalPlaybackChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onLoad(value: VideoPlayerEventsInterface['onLoad']) {
|
|
||||||
this.eventEmitter.onLoad = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onLoad(): VideoPlayerEventsInterface['onLoad'] {
|
|
||||||
return this.eventEmitter.onLoad;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onLoadStart(value: VideoPlayerEventsInterface['onLoadStart']) {
|
|
||||||
this.eventEmitter.onLoadStart = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onLoadStart(): VideoPlayerEventsInterface['onLoadStart'] {
|
|
||||||
return this.eventEmitter.onLoadStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onPlaybackStateChange(
|
|
||||||
value: VideoPlayerEventsInterface['onPlaybackStateChange']
|
|
||||||
) {
|
|
||||||
this.eventEmitter.onPlaybackStateChange = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onPlaybackStateChange(): VideoPlayerEventsInterface['onPlaybackStateChange'] {
|
|
||||||
return this.eventEmitter.onPlaybackStateChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onPlaybackRateChange(
|
|
||||||
value: VideoPlayerEventsInterface['onPlaybackRateChange']
|
|
||||||
) {
|
|
||||||
this.eventEmitter.onPlaybackRateChange = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onPlaybackRateChange(): VideoPlayerEventsInterface['onPlaybackRateChange'] {
|
|
||||||
return this.eventEmitter.onPlaybackRateChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onProgress(value: VideoPlayerEventsInterface['onProgress']) {
|
|
||||||
this.eventEmitter.onProgress = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onProgress(): VideoPlayerEventsInterface['onProgress'] {
|
|
||||||
return this.eventEmitter.onProgress;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onReadyToDisplay(value: VideoPlayerEventsInterface['onReadyToDisplay']) {
|
|
||||||
this.eventEmitter.onReadyToDisplay = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onReadyToDisplay(): VideoPlayerEventsInterface['onReadyToDisplay'] {
|
|
||||||
return this.eventEmitter.onReadyToDisplay;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onSeek(value: VideoPlayerEventsInterface['onSeek']) {
|
|
||||||
this.eventEmitter.onSeek = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onSeek(): VideoPlayerEventsInterface['onSeek'] {
|
|
||||||
return this.eventEmitter.onSeek;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onStatusChange(value: VideoPlayerEventsInterface['onStatusChange']) {
|
|
||||||
this.eventEmitter.onStatusChange = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onStatusChange(): VideoPlayerEventsInterface['onStatusChange'] {
|
|
||||||
return this.eventEmitter.onStatusChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onTimedMetadata(value: VideoPlayerEventsInterface['onTimedMetadata']) {
|
|
||||||
this.eventEmitter.onTimedMetadata = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onTimedMetadata(): VideoPlayerEventsInterface['onTimedMetadata'] {
|
|
||||||
return this.eventEmitter.onTimedMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onTextTrackDataChanged(
|
|
||||||
value: VideoPlayerEventsInterface['onTextTrackDataChanged']
|
|
||||||
) {
|
|
||||||
this.eventEmitter.onTextTrackDataChanged = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onTextTrackDataChanged(): VideoPlayerEventsInterface['onTextTrackDataChanged'] {
|
|
||||||
return this.eventEmitter.onTextTrackDataChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onTrackChange(value: VideoPlayerEventsInterface['onTrackChange']) {
|
|
||||||
this.eventEmitter.onTrackChange = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onTrackChange(): VideoPlayerEventsInterface['onTrackChange'] {
|
|
||||||
return this.eventEmitter.onTrackChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
set onVolumeChange(value: VideoPlayerEventsInterface['onVolumeChange']) {
|
|
||||||
this.eventEmitter.onVolumeChange = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onVolumeChange(): VideoPlayerEventsInterface['onVolumeChange'] {
|
|
||||||
return this.eventEmitter.onVolumeChange;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,6 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { VideoPlayer } from '../VideoPlayer';
|
import { VideoPlayer } from '../VideoPlayer';
|
||||||
import { type VideoPlayerEvents } from '../types/Events';
|
import { type AllPlayerEvents } from '../types/Events';
|
||||||
|
|
||||||
// Omit undefined from events
|
|
||||||
type NonUndefined<T> = T extends undefined ? never : T;
|
|
||||||
|
|
||||||
// Valid events names
|
|
||||||
type Events = keyof VideoPlayerEvents | 'onError';
|
|
||||||
|
|
||||||
// Valid events params
|
|
||||||
type EventsParams<T extends Events> = T extends keyof VideoPlayerEvents
|
|
||||||
? // (Native) Events from VideoPlayerEvents
|
|
||||||
Parameters<VideoPlayerEvents[T]>
|
|
||||||
: // (JS) Events from Video Player
|
|
||||||
Parameters<NonUndefined<VideoPlayer[T]>>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attaches an event listener to a `VideoPlayer` instance for a specified event.
|
* Attaches an event listener to a `VideoPlayer` instance for a specified event.
|
||||||
@@ -22,22 +9,15 @@ type EventsParams<T extends Events> = T extends keyof VideoPlayerEvents
|
|||||||
* @param event - The name of the event to attach the callback to
|
* @param event - The name of the event to attach the callback to
|
||||||
* @param callback - The callback for the event
|
* @param callback - The callback for the event
|
||||||
*/
|
*/
|
||||||
export const useEvent = <T extends Events>(
|
export const useEvent = <T extends keyof AllPlayerEvents>(
|
||||||
player: VideoPlayer,
|
player: VideoPlayer,
|
||||||
event: T,
|
event: T,
|
||||||
callback: (...args: EventsParams<T>) => void
|
callback: AllPlayerEvents[T]
|
||||||
) => {
|
) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// @ts-expect-error we narrow the type of the event
|
player.addEventListener(event, callback);
|
||||||
player[event] = callback;
|
|
||||||
|
|
||||||
return () => {
|
return () => player.removeEventListener(event, callback);
|
||||||
if (event === 'onError') {
|
;
|
||||||
// onError is not native event, so we can set it to undefined
|
|
||||||
player.onError = undefined;
|
|
||||||
} else {
|
|
||||||
player.clearEvent(event);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [player, event, callback]);
|
}, [player, event, callback]);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { VideoPlayerSource } from '../../spec/nitro/VideoPlayerSource.nitro';
|
import type { VideoPlayerSource } from '../../spec/nitro/VideoPlayerSource.nitro';
|
||||||
import type { TextTrack } from './TextTrack';
|
import type { TextTrack } from './TextTrack';
|
||||||
|
import type { VideoRuntimeError } from './VideoError';
|
||||||
import type { VideoOrientation } from './VideoOrientation';
|
import type { VideoOrientation } from './VideoOrientation';
|
||||||
import type { VideoPlayerStatus } from './VideoPlayerStatus';
|
import type { VideoPlayerStatus } from './VideoPlayerStatus';
|
||||||
|
|
||||||
@@ -92,6 +93,11 @@ export interface VideoPlayerEvents {
|
|||||||
onStatusChange: (status: VideoPlayerStatus) => void;
|
onStatusChange: (status: VideoPlayerStatus) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AllPlayerEvents extends VideoPlayerEvents {
|
||||||
|
onError: (error: VideoRuntimeError) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface VideoViewEvents {
|
export interface VideoViewEvents {
|
||||||
/**
|
/**
|
||||||
* Called when the video view's picture in picture state changes.
|
* Called when the video view's picture in picture state changes.
|
||||||
|
|||||||
Reference in New Issue
Block a user