react-native-video-provider 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AuVideo.podspec +28 -0
- package/LICENSE +20 -0
- package/README.md +183 -0
- package/android/build.gradle +59 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/auvideo/AuVideoModule.kt +259 -0
- package/android/src/main/java/com/auvideo/AuVideoPackage.kt +35 -0
- package/android/src/main/java/com/auvideo/AuVideoSurfaceView.kt +40 -0
- package/android/src/main/java/com/auvideo/AuVideoSurfaceViewManager.kt +38 -0
- package/android/src/main/java/com/auvideo/PlayerCore.kt +366 -0
- package/android/src/main/java/com/auvideo/SurfaceRegistry.kt +26 -0
- package/android/src/main/res/layout/au_video_player_view.xml +10 -0
- package/ios/AuVideo.h +10 -0
- package/ios/AuVideo.mm +232 -0
- package/ios/AuVideoOrientation.swift +59 -0
- package/ios/AuVideoPlayerCore.swift +415 -0
- package/ios/AuVideoSurfaceRegistry.swift +30 -0
- package/ios/AuVideoSurfaceView.h +15 -0
- package/ios/AuVideoSurfaceView.mm +63 -0
- package/lib/module/AuVideoSurfaceNativeComponent.ts +8 -0
- package/lib/module/NativeAuVideo.js +5 -0
- package/lib/module/NativeAuVideo.js.map +1 -0
- package/lib/module/components/FloatingPlayer.js +119 -0
- package/lib/module/components/FloatingPlayer.js.map +1 -0
- package/lib/module/components/FullscreenPlayer.js +59 -0
- package/lib/module/components/FullscreenPlayer.js.map +1 -0
- package/lib/module/components/GestureOverlay.js +56 -0
- package/lib/module/components/GestureOverlay.js.map +1 -0
- package/lib/module/components/MiniPlayer.js +89 -0
- package/lib/module/components/MiniPlayer.js.map +1 -0
- package/lib/module/components/VideoControls.js +191 -0
- package/lib/module/components/VideoControls.js.map +1 -0
- package/lib/module/components/VideoPlayer.js +65 -0
- package/lib/module/components/VideoPlayer.js.map +1 -0
- package/lib/module/components/VideoSurface.js +35 -0
- package/lib/module/components/VideoSurface.js.map +1 -0
- package/lib/module/core/VideoManager.js +436 -0
- package/lib/module/core/VideoManager.js.map +1 -0
- package/lib/module/hooks/useFullscreen.js +19 -0
- package/lib/module/hooks/useFullscreen.js.map +1 -0
- package/lib/module/hooks/usePiP.js +17 -0
- package/lib/module/hooks/usePiP.js.map +1 -0
- package/lib/module/hooks/usePlayback.js +21 -0
- package/lib/module/hooks/usePlayback.js.map +1 -0
- package/lib/module/hooks/useVideo.js +17 -0
- package/lib/module/hooks/useVideo.js.map +1 -0
- package/lib/module/hooks/useVideoEvents.js +26 -0
- package/lib/module/hooks/useVideoEvents.js.map +1 -0
- package/lib/module/index.js +19 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/provider/VideoContext.js +14 -0
- package/lib/module/provider/VideoContext.js.map +1 -0
- package/lib/module/provider/VideoProvider.js +36 -0
- package/lib/module/provider/VideoProvider.js.map +1 -0
- package/lib/module/state/createVideoStore.js +33 -0
- package/lib/module/state/createVideoStore.js.map +1 -0
- package/lib/module/types/events.js +4 -0
- package/lib/module/types/events.js.map +1 -0
- package/lib/module/types/index.js +2 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/module/types/video.js +2 -0
- package/lib/module/types/video.js.map +1 -0
- package/lib/module/utils/Emitter.js +39 -0
- package/lib/module/utils/Emitter.js.map +1 -0
- package/lib/module/utils/formatTime.js +15 -0
- package/lib/module/utils/formatTime.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/AuVideoSurfaceNativeComponent.d.ts +8 -0
- package/lib/typescript/src/AuVideoSurfaceNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/NativeAuVideo.d.ts +85 -0
- package/lib/typescript/src/NativeAuVideo.d.ts.map +1 -0
- package/lib/typescript/src/components/FloatingPlayer.d.ts +12 -0
- package/lib/typescript/src/components/FloatingPlayer.d.ts.map +1 -0
- package/lib/typescript/src/components/FullscreenPlayer.d.ts +12 -0
- package/lib/typescript/src/components/FullscreenPlayer.d.ts.map +1 -0
- package/lib/typescript/src/components/GestureOverlay.d.ts +14 -0
- package/lib/typescript/src/components/GestureOverlay.d.ts.map +1 -0
- package/lib/typescript/src/components/MiniPlayer.d.ts +16 -0
- package/lib/typescript/src/components/MiniPlayer.d.ts.map +1 -0
- package/lib/typescript/src/components/VideoControls.d.ts +17 -0
- package/lib/typescript/src/components/VideoControls.d.ts.map +1 -0
- package/lib/typescript/src/components/VideoPlayer.d.ts +27 -0
- package/lib/typescript/src/components/VideoPlayer.d.ts.map +1 -0
- package/lib/typescript/src/components/VideoSurface.d.ts +18 -0
- package/lib/typescript/src/components/VideoSurface.d.ts.map +1 -0
- package/lib/typescript/src/core/VideoManager.d.ts +88 -0
- package/lib/typescript/src/core/VideoManager.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useFullscreen.d.ts +7 -0
- package/lib/typescript/src/hooks/useFullscreen.d.ts.map +1 -0
- package/lib/typescript/src/hooks/usePiP.d.ts +6 -0
- package/lib/typescript/src/hooks/usePiP.d.ts.map +1 -0
- package/lib/typescript/src/hooks/usePlayback.d.ts +13 -0
- package/lib/typescript/src/hooks/usePlayback.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useVideo.d.ts +13 -0
- package/lib/typescript/src/hooks/useVideo.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useVideoEvents.d.ts +14 -0
- package/lib/typescript/src/hooks/useVideoEvents.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +18 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/provider/VideoContext.d.ts +8 -0
- package/lib/typescript/src/provider/VideoContext.d.ts.map +1 -0
- package/lib/typescript/src/provider/VideoProvider.d.ts +18 -0
- package/lib/typescript/src/provider/VideoProvider.d.ts.map +1 -0
- package/lib/typescript/src/state/createVideoStore.d.ts +6 -0
- package/lib/typescript/src/state/createVideoStore.d.ts.map +1 -0
- package/lib/typescript/src/types/events.d.ts +46 -0
- package/lib/typescript/src/types/events.d.ts.map +1 -0
- package/lib/typescript/src/types/index.d.ts +3 -0
- package/lib/typescript/src/types/index.d.ts.map +1 -0
- package/lib/typescript/src/types/video.d.ts +70 -0
- package/lib/typescript/src/types/video.d.ts.map +1 -0
- package/lib/typescript/src/utils/Emitter.d.ts +15 -0
- package/lib/typescript/src/utils/Emitter.d.ts.map +1 -0
- package/lib/typescript/src/utils/formatTime.d.ts +2 -0
- package/lib/typescript/src/utils/formatTime.d.ts.map +1 -0
- package/package.json +154 -0
- package/src/AuVideoSurfaceNativeComponent.ts +8 -0
- package/src/NativeAuVideo.ts +106 -0
- package/src/components/FloatingPlayer.tsx +130 -0
- package/src/components/FullscreenPlayer.tsx +64 -0
- package/src/components/GestureOverlay.tsx +76 -0
- package/src/components/MiniPlayer.tsx +93 -0
- package/src/components/VideoControls.tsx +213 -0
- package/src/components/VideoPlayer.tsx +77 -0
- package/src/components/VideoSurface.tsx +39 -0
- package/src/core/VideoManager.ts +441 -0
- package/src/hooks/useFullscreen.ts +14 -0
- package/src/hooks/usePiP.ts +13 -0
- package/src/hooks/usePlayback.ts +26 -0
- package/src/hooks/useVideo.ts +16 -0
- package/src/hooks/useVideoEvents.ts +33 -0
- package/src/index.ts +54 -0
- package/src/provider/VideoContext.ts +12 -0
- package/src/provider/VideoProvider.tsx +41 -0
- package/src/state/createVideoStore.ts +33 -0
- package/src/types/events.ts +22 -0
- package/src/types/index.ts +11 -0
- package/src/types/video.ts +85 -0
- package/src/utils/Emitter.ts +51 -0
- package/src/utils/formatTime.ts +12 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type PropsWithChildren } from 'react';
|
|
2
|
+
import type { VideoProviderConfig } from '../types/video.js';
|
|
3
|
+
export interface VideoProviderProps extends PropsWithChildren {
|
|
4
|
+
config?: VideoProviderConfig;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Wrap the app once. Creates the singleton native player silently and
|
|
8
|
+
* mounts the fullscreen/floating hosts above the app so `enterFullscreen()`
|
|
9
|
+
* and `showFloating()` work from any screen.
|
|
10
|
+
*
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <VideoProvider>
|
|
13
|
+
* <Navigation />
|
|
14
|
+
* </VideoProvider>
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function VideoProvider({ children, config }: VideoProviderProps): import("react").JSX.Element;
|
|
18
|
+
//# sourceMappingURL=VideoProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VideoProvider.d.ts","sourceRoot":"","sources":["../../../../src/provider/VideoProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAEnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAgB,CAAC;AAK1D,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAC9B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,kBAAkB,+BAkBrE"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type StoreApi } from 'zustand/vanilla';
|
|
2
|
+
import type { VideoState } from '../types/video.js';
|
|
3
|
+
export declare const initialVideoState: VideoState;
|
|
4
|
+
export type VideoStore = StoreApi<VideoState>;
|
|
5
|
+
export declare function createVideoStore(): VideoStore;
|
|
6
|
+
//# sourceMappingURL=createVideoStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createVideoStore.d.ts","sourceRoot":"","sources":["../../../../src/state/createVideoStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAgB,CAAC;AAEjD,eAAO,MAAM,iBAAiB,EAAE,UAuB/B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;AAE9C,wBAAgB,gBAAgB,IAAI,UAAU,CAE7C"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { PlayerMode, VideoError, VideoSource } from './video.js';
|
|
2
|
+
export interface VideoEventMap {
|
|
3
|
+
onLoad: {
|
|
4
|
+
videoId: string;
|
|
5
|
+
duration: number;
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
};
|
|
9
|
+
onReady: {
|
|
10
|
+
videoId: string;
|
|
11
|
+
};
|
|
12
|
+
onPlay: undefined;
|
|
13
|
+
onPause: undefined;
|
|
14
|
+
onBuffer: {
|
|
15
|
+
buffering: boolean;
|
|
16
|
+
};
|
|
17
|
+
onSeek: {
|
|
18
|
+
position: number;
|
|
19
|
+
};
|
|
20
|
+
onProgress: {
|
|
21
|
+
position: number;
|
|
22
|
+
duration: number;
|
|
23
|
+
buffered: number;
|
|
24
|
+
};
|
|
25
|
+
onEnd: undefined;
|
|
26
|
+
onError: VideoError;
|
|
27
|
+
onEnterFullscreen: undefined;
|
|
28
|
+
onExitFullscreen: undefined;
|
|
29
|
+
onAttach: {
|
|
30
|
+
surfaceId: string;
|
|
31
|
+
};
|
|
32
|
+
onDetach: {
|
|
33
|
+
surfaceId: string;
|
|
34
|
+
};
|
|
35
|
+
onModeChanged: {
|
|
36
|
+
mode: PlayerMode;
|
|
37
|
+
};
|
|
38
|
+
onVideoChanged: {
|
|
39
|
+
video: VideoSource | null;
|
|
40
|
+
};
|
|
41
|
+
onPipChanged: {
|
|
42
|
+
active: boolean;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export type VideoEventName = keyof VideoEventMap;
|
|
46
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../../src/types/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAS,CAAC;AAEnE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7E,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7B,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,SAAS,CAAC;IACnB,QAAQ,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IACjC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7B,UAAU,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACrE,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,UAAU,CAAC;IACpB,iBAAiB,EAAE,SAAS,CAAC;IAC7B,gBAAgB,EAAE,SAAS,CAAC;IAC5B,QAAQ,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAChC,QAAQ,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAChC,aAAa,EAAE;QAAE,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC;IACpC,cAAc,EAAE;QAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAAA;KAAE,CAAC;IAC9C,YAAY,EAAE;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;CACnC;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/types/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,WAAW,EACX,UAAU,EACV,UAAU,EACV,cAAc,EACd,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,YAAS,CAAC;AACjB,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAU,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export interface VideoSource {
|
|
2
|
+
/**
|
|
3
|
+
* Stable identity of the video. The engine uses this for same-video
|
|
4
|
+
* handoff: setting a source whose `id` matches the current one never
|
|
5
|
+
* reloads, rebuffers or resets position.
|
|
6
|
+
*/
|
|
7
|
+
id: string;
|
|
8
|
+
uri: string;
|
|
9
|
+
headers?: Record<string, string>;
|
|
10
|
+
title?: string;
|
|
11
|
+
artist?: string;
|
|
12
|
+
artworkUri?: string;
|
|
13
|
+
/** Seconds. Applied only when the item is (re)loaded. */
|
|
14
|
+
startPosition?: number;
|
|
15
|
+
}
|
|
16
|
+
export type ResizeMode = 'contain' | 'cover' | 'stretch';
|
|
17
|
+
export type PlayerMode = 'inline' | 'fullscreen' | 'floating' | 'pip' | 'background' | 'hidden';
|
|
18
|
+
export type PlaybackStatus = 'idle' | 'loading' | 'ready' | 'playing' | 'paused' | 'buffering' | 'ended' | 'error';
|
|
19
|
+
export interface VideoError {
|
|
20
|
+
code: string;
|
|
21
|
+
message: string;
|
|
22
|
+
}
|
|
23
|
+
export interface VideoState {
|
|
24
|
+
currentVideo: VideoSource | null;
|
|
25
|
+
status: PlaybackStatus;
|
|
26
|
+
playing: boolean;
|
|
27
|
+
paused: boolean;
|
|
28
|
+
buffering: boolean;
|
|
29
|
+
loading: boolean;
|
|
30
|
+
/** Seconds */
|
|
31
|
+
position: number;
|
|
32
|
+
/** Seconds. 0 until loaded. */
|
|
33
|
+
duration: number;
|
|
34
|
+
/** Seconds of buffered media ahead of position. */
|
|
35
|
+
buffered: number;
|
|
36
|
+
rate: number;
|
|
37
|
+
volume: number;
|
|
38
|
+
muted: boolean;
|
|
39
|
+
repeat: boolean;
|
|
40
|
+
resizeMode: ResizeMode;
|
|
41
|
+
fullscreen: boolean;
|
|
42
|
+
pip: boolean;
|
|
43
|
+
floating: boolean;
|
|
44
|
+
mode: PlayerMode;
|
|
45
|
+
/** Surface the player is currently requested/attached to. */
|
|
46
|
+
surfaceId: string | null;
|
|
47
|
+
videoWidth: number;
|
|
48
|
+
videoHeight: number;
|
|
49
|
+
error: VideoError | null;
|
|
50
|
+
}
|
|
51
|
+
export interface SetSourceOptions {
|
|
52
|
+
/** Start playing as soon as ready (or immediately on handoff). Default true. */
|
|
53
|
+
autoplay?: boolean;
|
|
54
|
+
/** Attach the player to this surface as part of setting the source. */
|
|
55
|
+
surfaceId?: string;
|
|
56
|
+
}
|
|
57
|
+
export interface VideoProviderConfig {
|
|
58
|
+
/**
|
|
59
|
+
* Render the built-in fullscreen host (a Modal that unlocks rotation).
|
|
60
|
+
* Set false if you render your own fullscreen surface. Default true.
|
|
61
|
+
*/
|
|
62
|
+
fullscreenHost?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Render the built-in draggable floating player host. Default true.
|
|
65
|
+
*/
|
|
66
|
+
floatingHost?: boolean;
|
|
67
|
+
/** Pause playback when the active surface unmounts. Default false. */
|
|
68
|
+
pauseOnDetach?: boolean;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=video.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../../../src/types/video.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yDAAyD;IACzD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAEzD,MAAM,MAAM,UAAU,GACpB,QAAQ,GAAG,YAAY,GAAG,UAAU,GAAG,KAAK,GAAG,YAAY,GAAG,QAAQ,CAAC;AAEzE,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,SAAS,GACT,OAAO,GACP,SAAS,GACT,QAAQ,GACR,WAAW,GACX,OAAO,GACP,OAAO,CAAC;AAEZ,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,GAAG,EAAE,OAAO,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,UAAU,CAAC;IACjB,6DAA6D;IAC7D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,sEAAsE;IACtE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type Listener<P> = (payload: P) => void;
|
|
2
|
+
export interface Subscription {
|
|
3
|
+
remove(): void;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Minimal typed event emitter. Listener errors are isolated so one broken
|
|
7
|
+
* subscriber cannot break playback state propagation.
|
|
8
|
+
*/
|
|
9
|
+
export declare class Emitter<Events extends object> {
|
|
10
|
+
private listeners;
|
|
11
|
+
addListener<K extends keyof Events>(event: K, listener: Listener<Events[K]>): Subscription;
|
|
12
|
+
emit<K extends keyof Events>(event: K, payload: Events[K]): void;
|
|
13
|
+
removeAll(): void;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=Emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Emitter.d.ts","sourceRoot":"","sources":["../../../../src/utils/Emitter.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,CAAC;AAE/C,MAAM,WAAW,YAAY;IAC3B,MAAM,IAAI,IAAI,CAAC;CAChB;AAED;;;GAGG;AACH,qBAAa,OAAO,CAAC,MAAM,SAAS,MAAM;IACxC,OAAO,CAAC,SAAS,CAAiD;IAElE,WAAW,CAAC,CAAC,SAAS,MAAM,MAAM,EAChC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAC5B,YAAY;IAcf,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI;IAiBhE,SAAS,IAAI,IAAI;CAGlB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatTime.d.ts","sourceRoot":"","sources":["../../../../src/utils/formatTime.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAWvD"}
|
package/package.json
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-native-video-provider",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Singleton-engine video library for React Native (one native player, many surfaces)",
|
|
5
|
+
"main": "./lib/module/index.js",
|
|
6
|
+
"types": "./lib/typescript/src/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"react-native-video-provider-source": "./src/index.ts",
|
|
10
|
+
"types": "./lib/typescript/src/index.d.ts",
|
|
11
|
+
"default": "./lib/module/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"src",
|
|
17
|
+
"lib",
|
|
18
|
+
"android",
|
|
19
|
+
"ios",
|
|
20
|
+
"cpp",
|
|
21
|
+
"*.podspec",
|
|
22
|
+
"react-native.config.js",
|
|
23
|
+
"!ios/build",
|
|
24
|
+
"!android/build",
|
|
25
|
+
"!android/gradle",
|
|
26
|
+
"!android/gradlew",
|
|
27
|
+
"!android/gradlew.bat",
|
|
28
|
+
"!android/local.properties",
|
|
29
|
+
"!**/__tests__",
|
|
30
|
+
"!**/__fixtures__",
|
|
31
|
+
"!**/__mocks__",
|
|
32
|
+
"!**/.*"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"example": "yarn workspace react-native-video-provider-example",
|
|
36
|
+
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
|
|
37
|
+
"prepare": "bob build",
|
|
38
|
+
"typecheck": "tsc",
|
|
39
|
+
"test": "jest",
|
|
40
|
+
"lint": "eslint \"**/*.{js,ts,tsx}\""
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"react-native",
|
|
44
|
+
"ios",
|
|
45
|
+
"android"
|
|
46
|
+
],
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "git",
|
|
49
|
+
"url": "git+https://github.com/grdp99/react-native-au-video.git"
|
|
50
|
+
},
|
|
51
|
+
"author": "Gurdeep Singh <grdp99@gmail.com> (https://gurdeep.net)",
|
|
52
|
+
"license": "MIT",
|
|
53
|
+
"bugs": {
|
|
54
|
+
"url": "https://github.com/grdp99/react-native-au-video/issues"
|
|
55
|
+
},
|
|
56
|
+
"homepage": "https://github.com/grdp99/react-native-au-video#readme",
|
|
57
|
+
"publishConfig": {
|
|
58
|
+
"registry": "https://registry.npmjs.org/"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@eslint/compat": "^2.1.0",
|
|
62
|
+
"@eslint/eslintrc": "^3.3.5",
|
|
63
|
+
"@eslint/js": "^10.0.1",
|
|
64
|
+
"@react-native/babel-preset": "0.85.0",
|
|
65
|
+
"@react-native/eslint-config": "0.85.0",
|
|
66
|
+
"@types/jest": "^29.5.14",
|
|
67
|
+
"@types/react": "^19.2.0",
|
|
68
|
+
"del-cli": "^7.0.0",
|
|
69
|
+
"eslint": "^9.39.4",
|
|
70
|
+
"eslint-config-prettier": "^10.1.8",
|
|
71
|
+
"eslint-plugin-ft-flow": "^3.0.11",
|
|
72
|
+
"eslint-plugin-prettier": "^5.5.6",
|
|
73
|
+
"jest": "^29.7.0",
|
|
74
|
+
"prettier": "^3.8.3",
|
|
75
|
+
"react": "19.2.3",
|
|
76
|
+
"react-native": "0.85.0",
|
|
77
|
+
"react-native-builder-bob": "^0.43.0",
|
|
78
|
+
"turbo": "^2.9.16",
|
|
79
|
+
"typescript": "^6.0.3"
|
|
80
|
+
},
|
|
81
|
+
"dependencies": {
|
|
82
|
+
"zustand": "^5.0.0"
|
|
83
|
+
},
|
|
84
|
+
"peerDependencies": {
|
|
85
|
+
"react": "*",
|
|
86
|
+
"react-native": "*"
|
|
87
|
+
},
|
|
88
|
+
"workspaces": [
|
|
89
|
+
"example"
|
|
90
|
+
],
|
|
91
|
+
"packageManager": "yarn@4.11.0",
|
|
92
|
+
"react-native-builder-bob": {
|
|
93
|
+
"source": "src",
|
|
94
|
+
"output": "lib",
|
|
95
|
+
"targets": [
|
|
96
|
+
[
|
|
97
|
+
"module",
|
|
98
|
+
{
|
|
99
|
+
"esm": true
|
|
100
|
+
}
|
|
101
|
+
],
|
|
102
|
+
[
|
|
103
|
+
"typescript",
|
|
104
|
+
{
|
|
105
|
+
"project": "tsconfig.build.json"
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
"jest": {
|
|
111
|
+
"testEnvironment": "node",
|
|
112
|
+
"testMatch": [
|
|
113
|
+
"<rootDir>/src/**/__tests__/**/*.test.ts"
|
|
114
|
+
],
|
|
115
|
+
"transform": {
|
|
116
|
+
"^.+\\.(js|jsx|ts|tsx)$": "babel-jest"
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
"codegenConfig": {
|
|
120
|
+
"name": "AuVideoSpec",
|
|
121
|
+
"type": "all",
|
|
122
|
+
"jsSrcsDir": "src",
|
|
123
|
+
"android": {
|
|
124
|
+
"javaPackageName": "com.auvideo"
|
|
125
|
+
},
|
|
126
|
+
"ios": {
|
|
127
|
+
"modulesProvider": {
|
|
128
|
+
"AuVideo": "AuVideo"
|
|
129
|
+
},
|
|
130
|
+
"componentProvider": {
|
|
131
|
+
"AuVideoSurfaceView": "AuVideoSurfaceView"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
"prettier": {
|
|
136
|
+
"quoteProps": "consistent",
|
|
137
|
+
"singleQuote": true,
|
|
138
|
+
"tabWidth": 2,
|
|
139
|
+
"trailingComma": "es5",
|
|
140
|
+
"useTabs": false
|
|
141
|
+
},
|
|
142
|
+
"create-react-native-library": {
|
|
143
|
+
"type": "turbo-module",
|
|
144
|
+
"languages": "kotlin-objc",
|
|
145
|
+
"tools": [
|
|
146
|
+
"eslint"
|
|
147
|
+
],
|
|
148
|
+
"version": "0.63.0"
|
|
149
|
+
},
|
|
150
|
+
"directories": {
|
|
151
|
+
"doc": "docs",
|
|
152
|
+
"example": "example"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { codegenNativeComponent, type ViewProps } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export interface NativeProps extends ViewProps {
|
|
4
|
+
/** Unique id this surface registers under in the native surface registry. */
|
|
5
|
+
surfaceId: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default codegenNativeComponent<NativeProps>('AuVideoSurfaceView');
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TurboModuleRegistry,
|
|
3
|
+
type TurboModule,
|
|
4
|
+
type CodegenTypes,
|
|
5
|
+
} from 'react-native';
|
|
6
|
+
|
|
7
|
+
export type NativeVideoSource = {
|
|
8
|
+
id: string;
|
|
9
|
+
uri: string;
|
|
10
|
+
/** HTTP headers, string -> string */
|
|
11
|
+
headers?: CodegenTypes.UnsafeObject;
|
|
12
|
+
title?: string;
|
|
13
|
+
artist?: string;
|
|
14
|
+
artworkUri?: string;
|
|
15
|
+
/** Seconds. Applied only when the item is (re)loaded. */
|
|
16
|
+
startPosition?: number;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type NativeStatusEvent = {
|
|
20
|
+
/** idle | loading | ready | playing | paused | buffering | ended | error */
|
|
21
|
+
status: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type NativeLoadEvent = {
|
|
25
|
+
videoId: string;
|
|
26
|
+
duration: number;
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type NativeProgressEvent = {
|
|
32
|
+
position: number;
|
|
33
|
+
duration: number;
|
|
34
|
+
buffered: number;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type NativeSeekEvent = {
|
|
38
|
+
position: number;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type NativeErrorEvent = {
|
|
42
|
+
code: string;
|
|
43
|
+
message: string;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export type NativeSurfaceEvent = {
|
|
47
|
+
surfaceId: string;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type NativePipEvent = {
|
|
51
|
+
active: boolean;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export interface Spec extends TurboModule {
|
|
55
|
+
/** Idempotent. Creates the singleton native player if needed. */
|
|
56
|
+
nativeInit(): void;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Load a source into the engine. If the currently loaded source has the
|
|
60
|
+
* same `id`, this is a no-op (same-video handoff) and playback continues.
|
|
61
|
+
*/
|
|
62
|
+
setSource(source: NativeVideoSource, autoplay: boolean): void;
|
|
63
|
+
|
|
64
|
+
/** Warm a source without rendering or interrupting current playback. */
|
|
65
|
+
preload(source: NativeVideoSource): void;
|
|
66
|
+
|
|
67
|
+
play(): void;
|
|
68
|
+
pause(): void;
|
|
69
|
+
stop(): void;
|
|
70
|
+
seekTo(position: number): void;
|
|
71
|
+
setRate(rate: number): void;
|
|
72
|
+
setVolume(volume: number): void;
|
|
73
|
+
setMuted(muted: boolean): void;
|
|
74
|
+
setRepeat(repeat: boolean): void;
|
|
75
|
+
/** contain | cover | stretch */
|
|
76
|
+
setResizeMode(mode: string): void;
|
|
77
|
+
|
|
78
|
+
/** Re-parent the player view into the surface registered under this id. */
|
|
79
|
+
attach(surfaceId: string): void;
|
|
80
|
+
detach(): void;
|
|
81
|
+
|
|
82
|
+
/** Unlock rotation + immersive mode. Does not move the player. */
|
|
83
|
+
enterFullscreen(): void;
|
|
84
|
+
/** Restore the previous orientation lock. */
|
|
85
|
+
exitFullscreen(): void;
|
|
86
|
+
|
|
87
|
+
enterPip(): Promise<boolean>;
|
|
88
|
+
exitPip(): void;
|
|
89
|
+
|
|
90
|
+
getPosition(): Promise<number>;
|
|
91
|
+
|
|
92
|
+
/** Tear down the native player entirely. */
|
|
93
|
+
releasePlayer(): void;
|
|
94
|
+
|
|
95
|
+
readonly onStatusChange: CodegenTypes.EventEmitter<NativeStatusEvent>;
|
|
96
|
+
readonly onLoad: CodegenTypes.EventEmitter<NativeLoadEvent>;
|
|
97
|
+
readonly onProgress: CodegenTypes.EventEmitter<NativeProgressEvent>;
|
|
98
|
+
readonly onSeek: CodegenTypes.EventEmitter<NativeSeekEvent>;
|
|
99
|
+
readonly onEnd: CodegenTypes.EventEmitter<void>;
|
|
100
|
+
readonly onError: CodegenTypes.EventEmitter<NativeErrorEvent>;
|
|
101
|
+
readonly onAttach: CodegenTypes.EventEmitter<NativeSurfaceEvent>;
|
|
102
|
+
readonly onDetach: CodegenTypes.EventEmitter<NativeSurfaceEvent>;
|
|
103
|
+
readonly onPipChange: CodegenTypes.EventEmitter<NativePipEvent>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export default TurboModuleRegistry.getEnforcing<Spec>('AuVideo');
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { useRef } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Animated,
|
|
4
|
+
PanResponder,
|
|
5
|
+
Pressable,
|
|
6
|
+
StyleSheet,
|
|
7
|
+
Text,
|
|
8
|
+
useWindowDimensions,
|
|
9
|
+
} from 'react-native';
|
|
10
|
+
import { FLOATING_SURFACE_ID } from '../core/VideoManager';
|
|
11
|
+
import { usePlayback } from '../hooks/usePlayback';
|
|
12
|
+
import { useVideoManager } from '../provider/VideoContext';
|
|
13
|
+
import { VideoSurface } from './VideoSurface';
|
|
14
|
+
|
|
15
|
+
export interface FloatingPlayerProps {
|
|
16
|
+
/** Width of the floating window. Default 200. */
|
|
17
|
+
width?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Built-in draggable in-app floating window, rendered by VideoProvider and
|
|
22
|
+
* shown by `showFloating()`. Same engine, same position — expand returns
|
|
23
|
+
* to fullscreen, ✕ hides the window (playback continues; call pause()
|
|
24
|
+
* in onModeChanged if you want otherwise).
|
|
25
|
+
*/
|
|
26
|
+
export function FloatingPlayer({ width = 200 }: FloatingPlayerProps) {
|
|
27
|
+
const manager = useVideoManager();
|
|
28
|
+
const floating = usePlayback((s) => s.floating);
|
|
29
|
+
const screen = useWindowDimensions();
|
|
30
|
+
|
|
31
|
+
const height = (width * 9) / 16;
|
|
32
|
+
const pan = useRef(
|
|
33
|
+
new Animated.ValueXY({
|
|
34
|
+
x: screen.width - width - 12,
|
|
35
|
+
y: screen.height - height - 96,
|
|
36
|
+
})
|
|
37
|
+
).current;
|
|
38
|
+
|
|
39
|
+
const responder = useRef(
|
|
40
|
+
PanResponder.create({
|
|
41
|
+
onMoveShouldSetPanResponder: (_e, g) =>
|
|
42
|
+
Math.abs(g.dx) > 4 || Math.abs(g.dy) > 4,
|
|
43
|
+
onPanResponderGrant: () => {
|
|
44
|
+
pan.extractOffset();
|
|
45
|
+
},
|
|
46
|
+
onPanResponderMove: Animated.event([null, { dx: pan.x, dy: pan.y }], {
|
|
47
|
+
useNativeDriver: false,
|
|
48
|
+
}),
|
|
49
|
+
onPanResponderRelease: () => {
|
|
50
|
+
pan.flattenOffset();
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
).current;
|
|
54
|
+
|
|
55
|
+
if (!floating) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<Animated.View
|
|
61
|
+
style={[
|
|
62
|
+
styles.window,
|
|
63
|
+
{ width, height, transform: pan.getTranslateTransform() },
|
|
64
|
+
]}
|
|
65
|
+
{...responder.panHandlers}
|
|
66
|
+
>
|
|
67
|
+
<VideoSurface
|
|
68
|
+
surfaceId={FLOATING_SURFACE_ID}
|
|
69
|
+
autoAttach
|
|
70
|
+
style={styles.surface}
|
|
71
|
+
/>
|
|
72
|
+
<Pressable
|
|
73
|
+
style={[styles.button, styles.closeButton]}
|
|
74
|
+
hitSlop={8}
|
|
75
|
+
onPress={() => manager.hideFloating()}
|
|
76
|
+
>
|
|
77
|
+
<Text style={styles.icon}>✕</Text>
|
|
78
|
+
</Pressable>
|
|
79
|
+
<Pressable
|
|
80
|
+
style={[styles.button, styles.expandButton]}
|
|
81
|
+
hitSlop={8}
|
|
82
|
+
onPress={() => {
|
|
83
|
+
manager.hideFloating();
|
|
84
|
+
manager.enterFullscreen();
|
|
85
|
+
}}
|
|
86
|
+
>
|
|
87
|
+
<Text style={styles.icon}>⤢</Text>
|
|
88
|
+
</Pressable>
|
|
89
|
+
</Animated.View>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const styles = StyleSheet.create({
|
|
94
|
+
window: {
|
|
95
|
+
position: 'absolute',
|
|
96
|
+
top: 0,
|
|
97
|
+
left: 0,
|
|
98
|
+
borderRadius: 8,
|
|
99
|
+
overflow: 'hidden',
|
|
100
|
+
backgroundColor: '#000',
|
|
101
|
+
elevation: 8,
|
|
102
|
+
shadowColor: '#000',
|
|
103
|
+
shadowOpacity: 0.4,
|
|
104
|
+
shadowRadius: 8,
|
|
105
|
+
shadowOffset: { width: 0, height: 4 },
|
|
106
|
+
},
|
|
107
|
+
surface: {
|
|
108
|
+
flex: 1,
|
|
109
|
+
},
|
|
110
|
+
button: {
|
|
111
|
+
position: 'absolute',
|
|
112
|
+
top: 4,
|
|
113
|
+
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
114
|
+
borderRadius: 12,
|
|
115
|
+
width: 24,
|
|
116
|
+
height: 24,
|
|
117
|
+
alignItems: 'center',
|
|
118
|
+
justifyContent: 'center',
|
|
119
|
+
},
|
|
120
|
+
closeButton: {
|
|
121
|
+
right: 4,
|
|
122
|
+
},
|
|
123
|
+
expandButton: {
|
|
124
|
+
left: 4,
|
|
125
|
+
},
|
|
126
|
+
icon: {
|
|
127
|
+
color: '#fff',
|
|
128
|
+
fontSize: 12,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Modal, StatusBar, StyleSheet, View } from 'react-native';
|
|
2
|
+
import { FULLSCREEN_SURFACE_ID } from '../core/VideoManager';
|
|
3
|
+
import { usePlayback } from '../hooks/usePlayback';
|
|
4
|
+
import { useVideoManager } from '../provider/VideoContext';
|
|
5
|
+
import { VideoControls } from './VideoControls';
|
|
6
|
+
import { VideoSurface } from './VideoSurface';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Built-in fullscreen host, rendered by VideoProvider. While visible,
|
|
10
|
+
* rotation is unlocked natively (all orientations allowed); on exit the
|
|
11
|
+
* previous orientation lock is restored and the player re-attaches to the
|
|
12
|
+
* surface it came from.
|
|
13
|
+
*
|
|
14
|
+
* Rendered automatically — you normally never mount this yourself. Apps
|
|
15
|
+
* that want fullscreen "inside" a navigation screen can instead render a
|
|
16
|
+
* plain <VideoSurface> there and call attach().
|
|
17
|
+
*/
|
|
18
|
+
export function FullscreenPlayer() {
|
|
19
|
+
const manager = useVideoManager();
|
|
20
|
+
const fullscreen = usePlayback((s) => s.fullscreen);
|
|
21
|
+
|
|
22
|
+
if (!fullscreen) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Modal
|
|
28
|
+
visible
|
|
29
|
+
transparent={false}
|
|
30
|
+
animationType="fade"
|
|
31
|
+
presentationStyle="fullScreen"
|
|
32
|
+
statusBarTranslucent
|
|
33
|
+
navigationBarTranslucent
|
|
34
|
+
supportedOrientations={[
|
|
35
|
+
'portrait',
|
|
36
|
+
'portrait-upside-down',
|
|
37
|
+
'landscape',
|
|
38
|
+
'landscape-left',
|
|
39
|
+
'landscape-right',
|
|
40
|
+
]}
|
|
41
|
+
onRequestClose={() => manager.exitFullscreen()}
|
|
42
|
+
>
|
|
43
|
+
<StatusBar hidden />
|
|
44
|
+
<View style={styles.container}>
|
|
45
|
+
<VideoSurface
|
|
46
|
+
surfaceId={FULLSCREEN_SURFACE_ID}
|
|
47
|
+
autoAttach
|
|
48
|
+
style={styles.surface}
|
|
49
|
+
/>
|
|
50
|
+
<VideoControls onClose={() => manager.exitFullscreen()} />
|
|
51
|
+
</View>
|
|
52
|
+
</Modal>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const styles = StyleSheet.create({
|
|
57
|
+
container: {
|
|
58
|
+
flex: 1,
|
|
59
|
+
backgroundColor: '#000',
|
|
60
|
+
},
|
|
61
|
+
surface: {
|
|
62
|
+
flex: 1,
|
|
63
|
+
},
|
|
64
|
+
});
|