@movementinfra/expo-twostep-video 0.1.14 → 0.1.16
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/README.md +80 -7
- package/build/ExpoTwoStepVideo.types.d.ts +55 -0
- package/build/ExpoTwoStepVideo.types.d.ts.map +1 -1
- package/build/ExpoTwoStepVideo.types.js.map +1 -1
- package/build/ExpoTwoStepVideoModule.d.ts +17 -0
- package/build/ExpoTwoStepVideoModule.d.ts.map +1 -1
- package/build/ExpoTwoStepVideoModule.js.map +1 -1
- package/build/ExpoTwoStepVideoModule.web.d.ts +4 -0
- package/build/ExpoTwoStepVideoModule.web.d.ts.map +1 -1
- package/build/ExpoTwoStepVideoModule.web.js +15 -0
- package/build/ExpoTwoStepVideoModule.web.js.map +1 -1
- package/build/ExpoTwoStepVideoView.d.ts.map +1 -1
- package/build/ExpoTwoStepVideoView.js +112 -2
- package/build/ExpoTwoStepVideoView.js.map +1 -1
- package/build/components/DoubleTapSkip.d.ts +9 -0
- package/build/components/DoubleTapSkip.d.ts.map +1 -0
- package/build/components/DoubleTapSkip.js +139 -0
- package/build/components/DoubleTapSkip.js.map +1 -0
- package/build/components/PlayheadBar.d.ts +10 -0
- package/build/components/PlayheadBar.d.ts.map +1 -0
- package/build/components/PlayheadBar.js +156 -0
- package/build/components/PlayheadBar.js.map +1 -0
- package/build/index.d.ts +83 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +91 -0
- package/build/index.js.map +1 -1
- package/ios/ExpoTwoStepVideoModule.swift +77 -1
- package/ios/ExpoTwoStepVideoView.swift +155 -36
- package/ios/TwoStepVideo/Core/MediaPicker.swift +355 -0
- package/ios/TwoStepVideo/TwoStepVideo.swift +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ Professional video editing for React Native, powered by native AVFoundation.
|
|
|
7
7
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
|
+
- **Native video picker** with album support, iCloud downloading, and rich metadata
|
|
10
11
|
- **Trim videos** with frame-accurate precision
|
|
11
12
|
- **Mirror videos** horizontally, vertically, or both
|
|
12
13
|
- **Speed adjustment** - slow motion (0.25x) to fast forward (4x)
|
|
@@ -36,10 +37,15 @@ npx expo install expo-twostep-video
|
|
|
36
37
|
```typescript
|
|
37
38
|
import * as TwoStepVideo from 'expo-twostep-video';
|
|
38
39
|
|
|
39
|
-
//
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
// Pick a video from the library
|
|
41
|
+
const videos = await TwoStepVideo.pickVideo();
|
|
42
|
+
if (videos.length === 0) return; // User cancelled
|
|
43
|
+
|
|
44
|
+
const video = videos[0];
|
|
45
|
+
console.log(`Selected: ${video.fileName} (${video.duration}s)`);
|
|
46
|
+
|
|
47
|
+
// Load the video for editing
|
|
48
|
+
const asset = await TwoStepVideo.loadAsset({ uri: video.uri });
|
|
43
49
|
|
|
44
50
|
// Trim to 10 seconds
|
|
45
51
|
const composition = await TwoStepVideo.trimVideo({
|
|
@@ -57,11 +63,66 @@ const result = await TwoStepVideo.exportVideo({
|
|
|
57
63
|
console.log('Exported to:', result.uri);
|
|
58
64
|
|
|
59
65
|
// Cleanup
|
|
66
|
+
TwoStepVideo.cleanupPickedVideo(video.path);
|
|
60
67
|
TwoStepVideo.releaseAll();
|
|
61
68
|
```
|
|
62
69
|
|
|
63
70
|
## API Reference
|
|
64
71
|
|
|
72
|
+
### Picking Videos from Library
|
|
73
|
+
|
|
74
|
+
Native photo library picker with full album support, iCloud downloading, and rich metadata:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// Pick a single video
|
|
78
|
+
const videos = await TwoStepVideo.pickVideo();
|
|
79
|
+
|
|
80
|
+
if (videos.length > 0) {
|
|
81
|
+
const video = videos[0];
|
|
82
|
+
console.log('File:', video.fileName);
|
|
83
|
+
console.log('Size:', video.width, 'x', video.height);
|
|
84
|
+
console.log('Duration:', video.duration, 'seconds');
|
|
85
|
+
console.log('File size:', video.fileSize, 'bytes');
|
|
86
|
+
console.log('Created:', video.creationDate); // ISO 8601
|
|
87
|
+
|
|
88
|
+
// Load for editing
|
|
89
|
+
const asset = await TwoStepVideo.loadAsset({ uri: video.uri });
|
|
90
|
+
|
|
91
|
+
// ... edit video ...
|
|
92
|
+
|
|
93
|
+
// Clean up temp file when done
|
|
94
|
+
TwoStepVideo.cleanupPickedVideo(video.path);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Pick multiple videos
|
|
98
|
+
const videos = await TwoStepVideo.pickVideo({ selectionLimit: 5 });
|
|
99
|
+
|
|
100
|
+
// Clean up all picked videos
|
|
101
|
+
TwoStepVideo.cleanupAllPickedVideos();
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Returned metadata (`PickedVideo`):**
|
|
105
|
+
|
|
106
|
+
| Field | Type | Description |
|
|
107
|
+
|-------|------|-------------|
|
|
108
|
+
| `uri` | `string` | File URI to temp copy |
|
|
109
|
+
| `path` | `string` | Absolute file path (for cleanup) |
|
|
110
|
+
| `fileName` | `string` | Original filename |
|
|
111
|
+
| `width` | `number` | Video width in pixels |
|
|
112
|
+
| `height` | `number` | Video height in pixels |
|
|
113
|
+
| `duration` | `number` | Duration in seconds |
|
|
114
|
+
| `fileSize` | `number` | File size in bytes |
|
|
115
|
+
| `creationDate` | `string?` | Original capture date (ISO 8601) |
|
|
116
|
+
| `modificationDate` | `string?` | Last modified date (ISO 8601) |
|
|
117
|
+
| `assetIdentifier` | `string?` | PHAsset ID for `loadAssetFromPhotos` |
|
|
118
|
+
| `type` | `string` | Always `"video"` |
|
|
119
|
+
|
|
120
|
+
**Features:**
|
|
121
|
+
- Native iOS picker with albums, favorites, and search
|
|
122
|
+
- Automatic iCloud video downloading with native progress UI
|
|
123
|
+
- Natural permission flow (prompts when needed)
|
|
124
|
+
- Comprehensive metadata including original creation date
|
|
125
|
+
|
|
65
126
|
### Loading Videos
|
|
66
127
|
|
|
67
128
|
```typescript
|
|
@@ -218,10 +279,15 @@ const subscription = TwoStepVideo.addExportProgressListener((event) => {
|
|
|
218
279
|
### Memory Management
|
|
219
280
|
|
|
220
281
|
```typescript
|
|
282
|
+
// Release loaded assets and compositions
|
|
221
283
|
TwoStepVideo.releaseAsset(asset.id);
|
|
222
284
|
TwoStepVideo.releaseComposition(composition.id);
|
|
223
285
|
TwoStepVideo.releaseAll(); // Release everything
|
|
224
|
-
|
|
286
|
+
|
|
287
|
+
// Clean up files
|
|
288
|
+
TwoStepVideo.cleanupFile(result.uri); // Delete exported temp file
|
|
289
|
+
TwoStepVideo.cleanupPickedVideo(video.path); // Delete picked video temp file
|
|
290
|
+
TwoStepVideo.cleanupAllPickedVideos(); // Delete all picked video temp files
|
|
225
291
|
```
|
|
226
292
|
|
|
227
293
|
## Video Scrubber Component
|
|
@@ -388,18 +454,25 @@ TwoStepVideo.Mirror.BOTH // Flip both
|
|
|
388
454
|
|
|
389
455
|
```typescript
|
|
390
456
|
import type {
|
|
457
|
+
// Picker types
|
|
458
|
+
PickedVideo,
|
|
459
|
+
PickVideoOptions,
|
|
460
|
+
// Asset types
|
|
391
461
|
VideoAsset,
|
|
392
462
|
VideoComposition,
|
|
393
463
|
ExportResult,
|
|
394
464
|
LoopResult,
|
|
465
|
+
// View types
|
|
395
466
|
TwoStepVideoViewRef,
|
|
396
467
|
TwoStepVideoViewProps,
|
|
397
468
|
PanZoomState,
|
|
398
|
-
|
|
399
|
-
VideoQuality,
|
|
469
|
+
// Scrubber types
|
|
400
470
|
VideoScrubberProps,
|
|
401
471
|
VideoScrubberRef,
|
|
402
472
|
VideoScrubberTheme,
|
|
473
|
+
// Constants
|
|
474
|
+
MirrorAxis,
|
|
475
|
+
VideoQuality,
|
|
403
476
|
} from 'expo-twostep-video';
|
|
404
477
|
```
|
|
405
478
|
|
|
@@ -1,4 +1,38 @@
|
|
|
1
1
|
import type { StyleProp, ViewStyle } from 'react-native';
|
|
2
|
+
/**
|
|
3
|
+
* Options for the video picker
|
|
4
|
+
*/
|
|
5
|
+
export type PickVideoOptions = {
|
|
6
|
+
/** Maximum number of videos to select (default 1) */
|
|
7
|
+
selectionLimit?: number;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Result from picking a video from the photo library
|
|
11
|
+
*/
|
|
12
|
+
export type PickedVideo = {
|
|
13
|
+
/** File URI (file:// path to temp copy) */
|
|
14
|
+
uri: string;
|
|
15
|
+
/** Absolute file path */
|
|
16
|
+
path: string;
|
|
17
|
+
/** Original filename */
|
|
18
|
+
fileName: string;
|
|
19
|
+
/** Video width in pixels */
|
|
20
|
+
width: number;
|
|
21
|
+
/** Video height in pixels */
|
|
22
|
+
height: number;
|
|
23
|
+
/** Duration in seconds */
|
|
24
|
+
duration: number;
|
|
25
|
+
/** File size in bytes */
|
|
26
|
+
fileSize: number;
|
|
27
|
+
/** Date the video was originally created/captured (ISO 8601 string) */
|
|
28
|
+
creationDate?: string;
|
|
29
|
+
/** Date the video was last modified (ISO 8601 string) */
|
|
30
|
+
modificationDate?: string;
|
|
31
|
+
/** PHAsset local identifier (for use with loadAssetFromPhotos) */
|
|
32
|
+
assetIdentifier?: string;
|
|
33
|
+
/** Media type (always "video" for this picker) */
|
|
34
|
+
type: 'video';
|
|
35
|
+
};
|
|
2
36
|
/**
|
|
3
37
|
* Playback status event payload
|
|
4
38
|
*/
|
|
@@ -35,6 +69,17 @@ export type PanZoomState = {
|
|
|
35
69
|
* Pan/Zoom change event payload
|
|
36
70
|
*/
|
|
37
71
|
export type PanZoomChangeEvent = PanZoomState;
|
|
72
|
+
/**
|
|
73
|
+
* Double-tap skip event payload
|
|
74
|
+
*/
|
|
75
|
+
export type DoubleTapSkipEvent = {
|
|
76
|
+
/** Direction of skip: 'forward' or 'backward' */
|
|
77
|
+
direction: 'forward' | 'backward';
|
|
78
|
+
/** Seconds skipped */
|
|
79
|
+
skipInterval: number;
|
|
80
|
+
/** New playback time after skip */
|
|
81
|
+
newTime: number;
|
|
82
|
+
};
|
|
38
83
|
/**
|
|
39
84
|
* Options for creating a pan/zoom composition
|
|
40
85
|
*/
|
|
@@ -86,6 +131,16 @@ export type TwoStepVideoViewProps = {
|
|
|
86
131
|
onPanZoomChange?: (event: {
|
|
87
132
|
nativeEvent: PanZoomChangeEvent;
|
|
88
133
|
}) => void;
|
|
134
|
+
/** Called when user double-taps to skip (native gesture) */
|
|
135
|
+
onDoubleTapSkip?: (event: {
|
|
136
|
+
nativeEvent: DoubleTapSkipEvent;
|
|
137
|
+
}) => void;
|
|
138
|
+
/** Show playhead bar overlay at bottom of video (default: true) */
|
|
139
|
+
showPlayheadBar?: boolean;
|
|
140
|
+
/** Enable double-tap to skip forward/backward (default: true) */
|
|
141
|
+
enableDoubleTapSkip?: boolean;
|
|
142
|
+
/** Seconds to skip on double-tap (default: 5) */
|
|
143
|
+
doubleTapSkipInterval?: number;
|
|
89
144
|
/** View style */
|
|
90
145
|
style?: StyleProp<ViewStyle>;
|
|
91
146
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoTwoStepVideo.types.d.ts","sourceRoot":"","sources":["../src/ExpoTwoStepVideo.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"ExpoTwoStepVideo.types.d.ts","sourceRoot":"","sources":["../src/ExpoTwoStepVideo.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoTwoStepVideo.types.js","sourceRoot":"","sources":["../src/ExpoTwoStepVideo.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { StyleProp, ViewStyle } from 'react-native';\n\n/**\n * Playback status event payload\n */\nexport type PlaybackStatusEvent = {\n status: 'ready' | 'playing' | 'paused' | 'ended' | 'seeked';\n time?: number;\n};\n\n/**\n * Progress event payload\n */\nexport type ProgressEvent = {\n currentTime: number;\n duration: number;\n progress: number;\n};\n\n/**\n * Error event payload\n */\nexport type ErrorEvent = {\n error: string;\n};\n\n/**\n * Pan/Zoom state representing the current view transform\n */\nexport type PanZoomState = {\n /** Horizontal pan position (-1.0 to 1.0, 0 = center) */\n panX: number;\n /** Vertical pan position (-1.0 to 1.0, 0 = center) */\n panY: number;\n /** Zoom level (1.0 = no zoom, 2.0 = 2x zoom, etc.) */\n zoomLevel: number;\n};\n\n/**\n * Pan/Zoom change event payload\n */\nexport type PanZoomChangeEvent = PanZoomState;\n\n/**\n * Options for creating a pan/zoom composition\n */\nexport type PanZoomVideoOptions = {\n /** ID of the loaded asset */\n assetId: string;\n /** Horizontal pan position (-1.0 to 1.0, 0 = center) */\n panX?: number;\n /** Vertical pan position (-1.0 to 1.0, 0 = center) */\n panY?: number;\n /** Zoom level (1.0 = no zoom, 2.0 = 2x zoom, etc.) */\n zoomLevel?: number;\n /** Optional start time in seconds */\n startTime?: number;\n /** Optional end time in seconds */\n endTime?: number;\n};\n\n/**\n * Video player view props\n */\nexport type TwoStepVideoViewProps = {\n /** ID of a composition to play (from trimVideo, mirrorVideo, etc.) */\n compositionId?: string;\n /** ID of an asset to play (from loadAsset) */\n assetId?: string;\n /** Enable continuous looping - video will restart automatically when it ends */\n loop?: boolean;\n /** Minimum zoom level (default: 1.0) */\n minZoom?: number;\n /** Maximum zoom level (default: 5.0) */\n maxZoom?: number;\n /** Called when playback status changes */\n onPlaybackStatusChange?: (event: { nativeEvent: PlaybackStatusEvent }) => void;\n /** Called periodically with playback progress */\n onProgress?: (event: { nativeEvent: ProgressEvent }) => void;\n /** Called when playback reaches the end (not called if loop is true) */\n onEnd?: (event: { nativeEvent: Record<string, never> }) => void;\n /** Called when an error occurs */\n onError?: (event: { nativeEvent: ErrorEvent }) => void;\n /** Called when pan/zoom gesture changes */\n onPanZoomChange?: (event: { nativeEvent: PanZoomChangeEvent }) => void;\n /** View style */\n style?: StyleProp<ViewStyle>;\n};\n\n/**\n * Base ref handle for video player views (common playback controls)\n */\nexport type BaseVideoViewRef = {\n /** Start playback */\n play: () => Promise<void>;\n /** Pause playback */\n pause: () => Promise<void>;\n /** Seek to a specific time in seconds */\n seek: (time: number) => Promise<void>;\n /** Restart playback from the beginning */\n replay: () => Promise<void>;\n};\n\n/**\n * Ref handle for video player view (with pan/zoom support)\n */\nexport type TwoStepVideoViewRef = BaseVideoViewRef & {\n /** Get the current pan/zoom state */\n getPanZoomState: () => Promise<PanZoomState>;\n /** Set the pan/zoom state programmatically */\n setPanZoomState: (state: Partial<PanZoomState>) => Promise<void>;\n /** Reset pan/zoom to default state (zoom=1, pan=0,0) */\n resetPanZoom: () => Promise<void>;\n};\n\n/**\n * Video player controller view props (with native controls)\n */\nexport type TwoStepPlayerControllerViewProps = TwoStepVideoViewProps & {\n /** Show native playback controls (default: true) */\n showsPlaybackControls?: boolean;\n};\n\n/**\n * Ref handle for video player controller view (with fullscreen support)\n * Note: Pan/zoom gestures are not available on this view as it uses AVPlayerViewController\n */\nexport type TwoStepPlayerControllerViewRef = BaseVideoViewRef & {\n /** Enter fullscreen mode */\n enterFullscreen: () => Promise<void>;\n /** Exit fullscreen mode */\n exitFullscreen: () => Promise<void>;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"ExpoTwoStepVideo.types.js","sourceRoot":"","sources":["../src/ExpoTwoStepVideo.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { StyleProp, ViewStyle } from 'react-native';\n\n// MARK: - Media Picker Types\n\n/**\n * Options for the video picker\n */\nexport type PickVideoOptions = {\n /** Maximum number of videos to select (default 1) */\n selectionLimit?: number;\n};\n\n/**\n * Result from picking a video from the photo library\n */\nexport type PickedVideo = {\n /** File URI (file:// path to temp copy) */\n uri: string;\n /** Absolute file path */\n path: string;\n /** Original filename */\n fileName: string;\n /** Video width in pixels */\n width: number;\n /** Video height in pixels */\n height: number;\n /** Duration in seconds */\n duration: number;\n /** File size in bytes */\n fileSize: number;\n /** Date the video was originally created/captured (ISO 8601 string) */\n creationDate?: string;\n /** Date the video was last modified (ISO 8601 string) */\n modificationDate?: string;\n /** PHAsset local identifier (for use with loadAssetFromPhotos) */\n assetIdentifier?: string;\n /** Media type (always \"video\" for this picker) */\n type: 'video';\n};\n\n/**\n * Playback status event payload\n */\nexport type PlaybackStatusEvent = {\n status: 'ready' | 'playing' | 'paused' | 'ended' | 'seeked';\n time?: number;\n};\n\n/**\n * Progress event payload\n */\nexport type ProgressEvent = {\n currentTime: number;\n duration: number;\n progress: number;\n};\n\n/**\n * Error event payload\n */\nexport type ErrorEvent = {\n error: string;\n};\n\n/**\n * Pan/Zoom state representing the current view transform\n */\nexport type PanZoomState = {\n /** Horizontal pan position (-1.0 to 1.0, 0 = center) */\n panX: number;\n /** Vertical pan position (-1.0 to 1.0, 0 = center) */\n panY: number;\n /** Zoom level (1.0 = no zoom, 2.0 = 2x zoom, etc.) */\n zoomLevel: number;\n};\n\n/**\n * Pan/Zoom change event payload\n */\nexport type PanZoomChangeEvent = PanZoomState;\n\n/**\n * Double-tap skip event payload\n */\nexport type DoubleTapSkipEvent = {\n /** Direction of skip: 'forward' or 'backward' */\n direction: 'forward' | 'backward';\n /** Seconds skipped */\n skipInterval: number;\n /** New playback time after skip */\n newTime: number;\n};\n\n/**\n * Options for creating a pan/zoom composition\n */\nexport type PanZoomVideoOptions = {\n /** ID of the loaded asset */\n assetId: string;\n /** Horizontal pan position (-1.0 to 1.0, 0 = center) */\n panX?: number;\n /** Vertical pan position (-1.0 to 1.0, 0 = center) */\n panY?: number;\n /** Zoom level (1.0 = no zoom, 2.0 = 2x zoom, etc.) */\n zoomLevel?: number;\n /** Optional start time in seconds */\n startTime?: number;\n /** Optional end time in seconds */\n endTime?: number;\n};\n\n/**\n * Video player view props\n */\nexport type TwoStepVideoViewProps = {\n /** ID of a composition to play (from trimVideo, mirrorVideo, etc.) */\n compositionId?: string;\n /** ID of an asset to play (from loadAsset) */\n assetId?: string;\n /** Enable continuous looping - video will restart automatically when it ends */\n loop?: boolean;\n /** Minimum zoom level (default: 1.0) */\n minZoom?: number;\n /** Maximum zoom level (default: 5.0) */\n maxZoom?: number;\n /** Called when playback status changes */\n onPlaybackStatusChange?: (event: { nativeEvent: PlaybackStatusEvent }) => void;\n /** Called periodically with playback progress */\n onProgress?: (event: { nativeEvent: ProgressEvent }) => void;\n /** Called when playback reaches the end (not called if loop is true) */\n onEnd?: (event: { nativeEvent: Record<string, never> }) => void;\n /** Called when an error occurs */\n onError?: (event: { nativeEvent: ErrorEvent }) => void;\n /** Called when pan/zoom gesture changes */\n onPanZoomChange?: (event: { nativeEvent: PanZoomChangeEvent }) => void;\n /** Called when user double-taps to skip (native gesture) */\n onDoubleTapSkip?: (event: { nativeEvent: DoubleTapSkipEvent }) => void;\n /** Show playhead bar overlay at bottom of video (default: true) */\n showPlayheadBar?: boolean;\n /** Enable double-tap to skip forward/backward (default: true) */\n enableDoubleTapSkip?: boolean;\n /** Seconds to skip on double-tap (default: 5) */\n doubleTapSkipInterval?: number;\n /** View style */\n style?: StyleProp<ViewStyle>;\n};\n\n/**\n * Base ref handle for video player views (common playback controls)\n */\nexport type BaseVideoViewRef = {\n /** Start playback */\n play: () => Promise<void>;\n /** Pause playback */\n pause: () => Promise<void>;\n /** Seek to a specific time in seconds */\n seek: (time: number) => Promise<void>;\n /** Restart playback from the beginning */\n replay: () => Promise<void>;\n};\n\n/**\n * Ref handle for video player view (with pan/zoom support)\n */\nexport type TwoStepVideoViewRef = BaseVideoViewRef & {\n /** Get the current pan/zoom state */\n getPanZoomState: () => Promise<PanZoomState>;\n /** Set the pan/zoom state programmatically */\n setPanZoomState: (state: Partial<PanZoomState>) => Promise<void>;\n /** Reset pan/zoom to default state (zoom=1, pan=0,0) */\n resetPanZoom: () => Promise<void>;\n};\n\n/**\n * Video player controller view props (with native controls)\n */\nexport type TwoStepPlayerControllerViewProps = TwoStepVideoViewProps & {\n /** Show native playback controls (default: true) */\n showsPlaybackControls?: boolean;\n};\n\n/**\n * Ref handle for video player controller view (with fullscreen support)\n * Note: Pan/zoom gestures are not available on this view as it uses AVPlayerViewController\n */\nexport type TwoStepPlayerControllerViewRef = BaseVideoViewRef & {\n /** Enter fullscreen mode */\n enterFullscreen: () => Promise<void>;\n /** Exit fullscreen mode */\n exitFullscreen: () => Promise<void>;\n};\n"]}
|
|
@@ -34,6 +34,19 @@ interface ExportProgressEvent {
|
|
|
34
34
|
assetId?: string;
|
|
35
35
|
compositionId?: string;
|
|
36
36
|
}
|
|
37
|
+
interface PickedVideoResult {
|
|
38
|
+
uri: string;
|
|
39
|
+
path: string;
|
|
40
|
+
fileName: string;
|
|
41
|
+
width: number;
|
|
42
|
+
height: number;
|
|
43
|
+
duration: number;
|
|
44
|
+
fileSize: number;
|
|
45
|
+
creationDate?: string;
|
|
46
|
+
modificationDate?: string;
|
|
47
|
+
assetIdentifier?: string;
|
|
48
|
+
type: 'video';
|
|
49
|
+
}
|
|
37
50
|
declare class ExpoTwoStepVideoModule extends NativeModule<{
|
|
38
51
|
onExportProgress: (event: ExportProgressEvent) => void;
|
|
39
52
|
}> {
|
|
@@ -61,6 +74,10 @@ declare class ExpoTwoStepVideoModule extends NativeModule<{
|
|
|
61
74
|
releaseAsset(assetId: string): void;
|
|
62
75
|
releaseComposition(compositionId: string): void;
|
|
63
76
|
releaseAll(): void;
|
|
77
|
+
pickVideo(selectionLimit?: number): Promise<PickedVideoResult[]>;
|
|
78
|
+
cleanupPickedVideo(path: string): void;
|
|
79
|
+
cleanupAllPickedVideos(): void;
|
|
80
|
+
getPickedVideoPaths(): string[];
|
|
64
81
|
}
|
|
65
82
|
declare const _default: ExpoTwoStepVideoModule;
|
|
66
83
|
export default _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoTwoStepVideoModule.d.ts","sourceRoot":"","sources":["../src/ExpoTwoStepVideoModule.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ExpoTwoStepVideoModule.d.ts","sourceRoot":"","sources":["../src/ExpoTwoStepVideoModule.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoTwoStepVideoModule.js","sourceRoot":"","sources":["../src/ExpoTwoStepVideoModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"ExpoTwoStepVideoModule.js","sourceRoot":"","sources":["../src/ExpoTwoStepVideoModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAwGtE,yDAAyD;AACzD,2EAA2E;AAC3E,eAAe,mBAAmB,CAAyB,kBAAkB,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo-modules-core';\n\ninterface TimeSegment {\n start: number;\n end: number;\n}\n\ninterface ThumbnailSize {\n width: number;\n height: number;\n}\n\ninterface AssetResult {\n id: string;\n duration: number;\n width: number;\n height: number;\n frameRate: number;\n hasAudio: boolean;\n}\n\ninterface CompositionResult {\n id: string;\n duration: number;\n}\n\ninterface LoopResult {\n id: string;\n duration: number;\n loopCount: number;\n totalPlays: number;\n}\n\ninterface ExportResult {\n uri: string;\n path: string;\n}\n\ninterface ExportProgressEvent {\n progress: number;\n assetId?: string;\n compositionId?: string;\n}\n\ninterface PickedVideoResult {\n uri: string;\n path: string;\n fileName: string;\n width: number;\n height: number;\n duration: number;\n fileSize: number;\n creationDate?: string;\n modificationDate?: string;\n assetIdentifier?: string;\n type: 'video';\n}\n\ndeclare class ExpoTwoStepVideoModule extends NativeModule<{\n onExportProgress: (event: ExportProgressEvent) => void;\n}> {\n // Constants\n QUALITY_LOW: string;\n QUALITY_MEDIUM: string;\n QUALITY_HIGH: string;\n QUALITY_HIGHEST: string;\n MIRROR_HORIZONTAL: string;\n MIRROR_VERTICAL: string;\n MIRROR_BOTH: string;\n\n // Asset loading\n loadAsset(uri: string): Promise<AssetResult>;\n loadAssetFromPhotos(localIdentifier: string): Promise<AssetResult>;\n validateVideoUri(uri: string): Promise<boolean>;\n\n // Editing operations\n trimVideo(assetId: string, startTime: number, endTime: number): Promise<CompositionResult>;\n trimVideoMultiple(assetId: string, segments: TimeSegment[]): Promise<CompositionResult>;\n mirrorVideo(assetId: string, axis: string, startTime?: number, endTime?: number): Promise<CompositionResult>;\n adjustSpeed(assetId: string, speed: number, startTime?: number, endTime?: number): Promise<CompositionResult>;\n transformVideo(assetId: string, speed?: number, mirrorAxis?: string, startTime?: number, endTime?: number): Promise<CompositionResult>;\n loopSegment(assetId: string, startTime: number, endTime: number, loopCount: number): Promise<LoopResult>;\n panZoomVideo(assetId: string, panX: number, panY: number, zoomLevel: number, startTime?: number, endTime?: number): Promise<CompositionResult>;\n\n // Thumbnails\n generateThumbnails(assetId: string, times: number[], size?: ThumbnailSize): Promise<string[]>;\n\n // Export\n exportVideo(compositionId: string, outputUri?: string, quality?: string): Promise<ExportResult>;\n exportAsset(assetId: string, outputUri?: string, quality?: string): Promise<ExportResult>;\n\n // Cleanup\n cleanupFile(uri: string): void;\n releaseAsset(assetId: string): void;\n releaseComposition(compositionId: string): void;\n releaseAll(): void;\n\n // Media picker\n pickVideo(selectionLimit?: number): Promise<PickedVideoResult[]>;\n cleanupPickedVideo(path: string): void;\n cleanupAllPickedVideos(): void;\n getPickedVideoPaths(): string[];\n}\n\n// This call loads the native module object from the JSI.\n// The module name must match Name(\"ExpoTwoStepVideo\") in the Swift module.\nexport default requireNativeModule<ExpoTwoStepVideoModule>('ExpoTwoStepVideo');\n"]}
|
|
@@ -9,6 +9,10 @@ declare const _default: {
|
|
|
9
9
|
addListener: () => {
|
|
10
10
|
remove: () => void;
|
|
11
11
|
};
|
|
12
|
+
pickVideo: () => Promise<never[]>;
|
|
13
|
+
cleanupPickedVideo: () => void;
|
|
14
|
+
cleanupAllPickedVideos: () => void;
|
|
15
|
+
getPickedVideoPaths: () => never[];
|
|
12
16
|
};
|
|
13
17
|
export default _default;
|
|
14
18
|
//# sourceMappingURL=ExpoTwoStepVideoModule.web.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoTwoStepVideoModule.web.d.ts","sourceRoot":"","sources":["../src/ExpoTwoStepVideoModule.web.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ExpoTwoStepVideoModule.web.d.ts","sourceRoot":"","sources":["../src/ExpoTwoStepVideoModule.web.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AACA,wBAwBE"}
|
|
@@ -8,5 +8,20 @@ export default {
|
|
|
8
8
|
MIRROR_VERTICAL: 'vertical',
|
|
9
9
|
MIRROR_BOTH: 'both',
|
|
10
10
|
addListener: () => ({ remove: () => { } }),
|
|
11
|
+
// Media picker stubs
|
|
12
|
+
pickVideo: async () => {
|
|
13
|
+
console.warn('TwoStepVideo.pickVideo is not supported on web');
|
|
14
|
+
return [];
|
|
15
|
+
},
|
|
16
|
+
cleanupPickedVideo: () => {
|
|
17
|
+
console.warn('TwoStepVideo.cleanupPickedVideo is not supported on web');
|
|
18
|
+
},
|
|
19
|
+
cleanupAllPickedVideos: () => {
|
|
20
|
+
console.warn('TwoStepVideo.cleanupAllPickedVideos is not supported on web');
|
|
21
|
+
},
|
|
22
|
+
getPickedVideoPaths: () => {
|
|
23
|
+
console.warn('TwoStepVideo.getPickedVideoPaths is not supported on web');
|
|
24
|
+
return [];
|
|
25
|
+
},
|
|
11
26
|
};
|
|
12
27
|
//# sourceMappingURL=ExpoTwoStepVideoModule.web.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoTwoStepVideoModule.web.js","sourceRoot":"","sources":["../src/ExpoTwoStepVideoModule.web.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,eAAe;IACb,WAAW,EAAE,KAAK;IAClB,cAAc,EAAE,QAAQ;IACxB,YAAY,EAAE,MAAM;IACpB,eAAe,EAAE,SAAS;IAC1B,iBAAiB,EAAE,YAAY;IAC/B,eAAe,EAAE,UAAU;IAC3B,WAAW,EAAE,MAAM;IACnB,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"ExpoTwoStepVideoModule.web.js","sourceRoot":"","sources":["../src/ExpoTwoStepVideoModule.web.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,eAAe;IACb,WAAW,EAAE,KAAK;IAClB,cAAc,EAAE,QAAQ;IACxB,YAAY,EAAE,MAAM;IACpB,eAAe,EAAE,SAAS;IAC1B,iBAAiB,EAAE,YAAY;IAC/B,eAAe,EAAE,UAAU;IAC3B,WAAW,EAAE,MAAM;IACnB,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC;IACzC,qBAAqB;IACrB,SAAS,EAAE,KAAK,IAAI,EAAE;QACpB,OAAO,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;QAC/D,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,kBAAkB,EAAE,GAAG,EAAE;QACvB,OAAO,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;IAC1E,CAAC;IACD,sBAAsB,EAAE,GAAG,EAAE;QAC3B,OAAO,CAAC,IAAI,CAAC,6DAA6D,CAAC,CAAC;IAC9E,CAAC;IACD,mBAAmB,EAAE,GAAG,EAAE;QACxB,OAAO,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;QACzE,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAC","sourcesContent":["// Web is not supported - this is a stub\nexport default {\n QUALITY_LOW: 'low',\n QUALITY_MEDIUM: 'medium',\n QUALITY_HIGH: 'high',\n QUALITY_HIGHEST: 'highest',\n MIRROR_HORIZONTAL: 'horizontal',\n MIRROR_VERTICAL: 'vertical',\n MIRROR_BOTH: 'both',\n addListener: () => ({ remove: () => {} }),\n // Media picker stubs\n pickVideo: async () => {\n console.warn('TwoStepVideo.pickVideo is not supported on web');\n return [];\n },\n cleanupPickedVideo: () => {\n console.warn('TwoStepVideo.cleanupPickedVideo is not supported on web');\n },\n cleanupAllPickedVideos: () => {\n console.warn('TwoStepVideo.cleanupAllPickedVideos is not supported on web');\n },\n getPickedVideoPaths: () => {\n console.warn('TwoStepVideo.getPickedVideoPaths is not supported on web');\n return [];\n },\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoTwoStepVideoView.d.ts","sourceRoot":"","sources":["../src/ExpoTwoStepVideoView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ExpoTwoStepVideoView.d.ts","sourceRoot":"","sources":["../src/ExpoTwoStepVideoView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAAoC,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAqBxH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,QAAA,MAAM,gBAAgB,mGAmKrB,CAAC;AAoCF,eAAe,gBAAgB,CAAC"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { requireNativeView } from 'expo';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import { forwardRef, useImperativeHandle, useRef } from 'react';
|
|
3
|
+
import { forwardRef, useCallback, useImperativeHandle, useRef, useState } from 'react';
|
|
4
|
+
import { View, Animated, Text, StyleSheet } from 'react-native';
|
|
5
|
+
import PlayheadBar from './components/PlayheadBar';
|
|
4
6
|
const NativeView = requireNativeView('ExpoTwoStepVideo');
|
|
5
7
|
/**
|
|
6
8
|
* Video player view that can play compositions and assets directly
|
|
@@ -25,7 +27,18 @@ const NativeView = requireNativeView('ExpoTwoStepVideo');
|
|
|
25
27
|
* ```
|
|
26
28
|
*/
|
|
27
29
|
const TwoStepVideoView = forwardRef((props, ref) => {
|
|
30
|
+
const { showPlayheadBar = true, enableDoubleTapSkip = true, doubleTapSkipInterval = 5, onProgress, onPlaybackStatusChange, onDoubleTapSkip, style, ...nativeProps } = props;
|
|
28
31
|
const nativeRef = useRef(null);
|
|
32
|
+
const currentTimeRef = useRef(0);
|
|
33
|
+
const durationRef = useRef(0);
|
|
34
|
+
const isPlayingRef = useRef(false);
|
|
35
|
+
const wasPlayingRef = useRef(false);
|
|
36
|
+
// Force re-render for overlay state
|
|
37
|
+
const [currentTime, setCurrentTime] = React.useState(0);
|
|
38
|
+
const [duration, setDuration] = React.useState(0);
|
|
39
|
+
// Double-tap feedback animation state
|
|
40
|
+
const [skipFeedback, setSkipFeedback] = useState(null);
|
|
41
|
+
const feedbackOpacity = useRef(new Animated.Value(0)).current;
|
|
29
42
|
useImperativeHandle(ref, () => ({
|
|
30
43
|
play: async () => {
|
|
31
44
|
await nativeRef.current?.play();
|
|
@@ -50,7 +63,104 @@ const TwoStepVideoView = forwardRef((props, ref) => {
|
|
|
50
63
|
await nativeRef.current?.resetPanZoom();
|
|
51
64
|
},
|
|
52
65
|
}));
|
|
53
|
-
|
|
66
|
+
const handleProgress = useCallback((event) => {
|
|
67
|
+
currentTimeRef.current = event.nativeEvent.currentTime;
|
|
68
|
+
durationRef.current = event.nativeEvent.duration;
|
|
69
|
+
setCurrentTime(event.nativeEvent.currentTime);
|
|
70
|
+
setDuration(event.nativeEvent.duration);
|
|
71
|
+
onProgress?.(event);
|
|
72
|
+
}, [onProgress]);
|
|
73
|
+
const handlePlaybackStatusChange = useCallback((event) => {
|
|
74
|
+
isPlayingRef.current = event.nativeEvent.status === 'playing';
|
|
75
|
+
onPlaybackStatusChange?.(event);
|
|
76
|
+
}, [onPlaybackStatusChange]);
|
|
77
|
+
// Handle native double-tap skip event - show visual feedback
|
|
78
|
+
const handleDoubleTapSkip = useCallback((event) => {
|
|
79
|
+
const { direction, skipInterval, newTime } = event.nativeEvent;
|
|
80
|
+
// Update local time state
|
|
81
|
+
currentTimeRef.current = newTime;
|
|
82
|
+
setCurrentTime(newTime);
|
|
83
|
+
// Show visual feedback
|
|
84
|
+
setSkipFeedback({ direction, interval: skipInterval });
|
|
85
|
+
feedbackOpacity.setValue(1);
|
|
86
|
+
Animated.timing(feedbackOpacity, {
|
|
87
|
+
toValue: 0,
|
|
88
|
+
duration: 600,
|
|
89
|
+
delay: 200,
|
|
90
|
+
useNativeDriver: true,
|
|
91
|
+
}).start(() => {
|
|
92
|
+
setSkipFeedback(null);
|
|
93
|
+
});
|
|
94
|
+
// Forward the event to parent if provided
|
|
95
|
+
onDoubleTapSkip?.(event);
|
|
96
|
+
}, [feedbackOpacity, onDoubleTapSkip]);
|
|
97
|
+
// PlayheadBar callbacks
|
|
98
|
+
const handleSeekStart = useCallback(() => {
|
|
99
|
+
wasPlayingRef.current = isPlayingRef.current;
|
|
100
|
+
if (isPlayingRef.current) {
|
|
101
|
+
nativeRef.current?.pause();
|
|
102
|
+
}
|
|
103
|
+
}, []);
|
|
104
|
+
const handlePlayheadSeek = useCallback((time) => {
|
|
105
|
+
nativeRef.current?.seek(time);
|
|
106
|
+
currentTimeRef.current = time;
|
|
107
|
+
setCurrentTime(time);
|
|
108
|
+
}, []);
|
|
109
|
+
const handleSeekEnd = useCallback(() => {
|
|
110
|
+
if (wasPlayingRef.current) {
|
|
111
|
+
nativeRef.current?.play();
|
|
112
|
+
}
|
|
113
|
+
}, []);
|
|
114
|
+
return (<View style={[style, { overflow: 'hidden' }]} pointerEvents="box-none">
|
|
115
|
+
<NativeView ref={nativeRef} {...nativeProps} enableDoubleTapSkip={enableDoubleTapSkip} doubleTapSkipInterval={doubleTapSkipInterval} onProgress={handleProgress} onPlaybackStatusChange={handlePlaybackStatusChange} onDoubleTapSkip={handleDoubleTapSkip} style={{ flex: 1 }}/>
|
|
116
|
+
{/* Double-tap skip visual feedback (shows on native event) */}
|
|
117
|
+
{skipFeedback && (<View style={styles.feedbackContainer} pointerEvents="none">
|
|
118
|
+
<View style={[styles.feedbackHalf, skipFeedback.direction === 'backward' && styles.feedbackActive]}>
|
|
119
|
+
{skipFeedback.direction === 'backward' && (<Animated.View style={[styles.feedbackCircle, { opacity: feedbackOpacity }]}>
|
|
120
|
+
<Text style={styles.arrowText}>{'<<'}</Text>
|
|
121
|
+
<Text style={styles.skipText}>{skipFeedback.interval}s</Text>
|
|
122
|
+
</Animated.View>)}
|
|
123
|
+
</View>
|
|
124
|
+
<View style={[styles.feedbackHalf, skipFeedback.direction === 'forward' && styles.feedbackActive]}>
|
|
125
|
+
{skipFeedback.direction === 'forward' && (<Animated.View style={[styles.feedbackCircle, { opacity: feedbackOpacity }]}>
|
|
126
|
+
<Text style={styles.arrowText}>{'>>'}</Text>
|
|
127
|
+
<Text style={styles.skipText}>{skipFeedback.interval}s</Text>
|
|
128
|
+
</Animated.View>)}
|
|
129
|
+
</View>
|
|
130
|
+
</View>)}
|
|
131
|
+
{showPlayheadBar && (<PlayheadBar currentTime={currentTime} duration={duration} onSeekStart={handleSeekStart} onSeek={handlePlayheadSeek} onSeekEnd={handleSeekEnd}/>)}
|
|
132
|
+
</View>);
|
|
133
|
+
});
|
|
134
|
+
const styles = StyleSheet.create({
|
|
135
|
+
feedbackContainer: {
|
|
136
|
+
...StyleSheet.absoluteFillObject,
|
|
137
|
+
flexDirection: 'row',
|
|
138
|
+
},
|
|
139
|
+
feedbackHalf: {
|
|
140
|
+
flex: 1,
|
|
141
|
+
justifyContent: 'center',
|
|
142
|
+
alignItems: 'center',
|
|
143
|
+
},
|
|
144
|
+
feedbackActive: {},
|
|
145
|
+
feedbackCircle: {
|
|
146
|
+
width: 64,
|
|
147
|
+
height: 64,
|
|
148
|
+
borderRadius: 32,
|
|
149
|
+
backgroundColor: 'rgba(0,0,0,0.4)',
|
|
150
|
+
justifyContent: 'center',
|
|
151
|
+
alignItems: 'center',
|
|
152
|
+
},
|
|
153
|
+
arrowText: {
|
|
154
|
+
color: '#FFFFFF',
|
|
155
|
+
fontSize: 20,
|
|
156
|
+
fontWeight: '700',
|
|
157
|
+
},
|
|
158
|
+
skipText: {
|
|
159
|
+
color: '#FFFFFF',
|
|
160
|
+
fontSize: 12,
|
|
161
|
+
fontWeight: '600',
|
|
162
|
+
marginTop: 2,
|
|
163
|
+
},
|
|
54
164
|
});
|
|
55
165
|
TwoStepVideoView.displayName = 'TwoStepVideoView';
|
|
56
166
|
export default TwoStepVideoView;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoTwoStepVideoView.js","sourceRoot":"","sources":["../src/ExpoTwoStepVideoView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AACzC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAoBhE,MAAM,UAAU,GAAyC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;AAE/F;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,gBAAgB,GAAG,UAAU,CACjC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IACb,MAAM,SAAS,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IAE9C,mBAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QAC9B,IAAI,EAAE,KAAK,IAAI,EAAE;YACf,MAAM,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;QAClC,CAAC;QACD,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,MAAM,SAAS,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;QACnC,CAAC;QACD,IAAI,EAAE,KAAK,EAAE,IAAY,EAAE,EAAE;YAC3B,MAAM,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC;QACD,MAAM,EAAE,KAAK,IAAI,EAAE;YACjB,MAAM,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QACpC,CAAC;QACD,eAAe,EAAE,KAAK,IAAI,EAAE;YAC1B,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,eAAe,EAAE,CAAC;YACzD,OAAO,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;QACrD,CAAC;QACD,eAAe,EAAE,KAAK,EAAE,KAA4B,EAAE,EAAE;YACtD,MAAM,SAAS,CAAC,OAAO,EAAE,eAAe,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QACpF,CAAC;QACD,YAAY,EAAE,KAAK,IAAI,EAAE;YACvB,MAAM,SAAS,CAAC,OAAO,EAAE,YAAY,EAAE,CAAC;QAC1C,CAAC;KACF,CAAC,CAAC,CAAC;IAEJ,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,KAAK,CAAC,EAAG,CAAC;AACnD,CAAC,CACF,CAAC;AAEF,gBAAgB,CAAC,WAAW,GAAG,kBAAkB,CAAC;AAElD,eAAe,gBAAgB,CAAC","sourcesContent":["import { requireNativeView } from 'expo';\nimport * as React from 'react';\nimport { forwardRef, useImperativeHandle, useRef } from 'react';\n\nimport { PanZoomState, TwoStepVideoViewProps, TwoStepVideoViewRef } from './ExpoTwoStepVideo.types';\n\n// Internal props type that includes the native ref\ntype NativeViewProps = TwoStepVideoViewProps & {\n ref?: React.Ref<NativeViewRef>;\n};\n\n// Native view ref with native methods\ntype NativeViewRef = {\n play: () => Promise<void>;\n pause: () => Promise<void>;\n seek: (time: number) => Promise<void>;\n replay: () => Promise<void>;\n getPanZoomState: () => Promise<PanZoomState>;\n setPanZoomState: (panX?: number, panY?: number, zoomLevel?: number) => Promise<void>;\n resetPanZoom: () => Promise<void>;\n};\n\nconst NativeView: React.ComponentType<NativeViewProps> = requireNativeView('ExpoTwoStepVideo');\n\n/**\n * Video player view that can play compositions and assets directly\n *\n * @example\n * ```tsx\n * const playerRef = useRef<TwoStepVideoViewRef>(null);\n *\n * // Play a composition (from mirrorVideo, trimVideo, etc.)\n * <TwoStepVideoView\n * ref={playerRef}\n * compositionId={composition.id}\n * onPlaybackStatusChange={(e) => console.log(e.nativeEvent.status)}\n * onProgress={(e) => setProgress(e.nativeEvent.progress)}\n * style={{ width: '100%', height: 300 }}\n * />\n *\n * // Control playback\n * playerRef.current?.play();\n * playerRef.current?.pause();\n * playerRef.current?.seek(5.0);\n * ```\n */\nconst TwoStepVideoView = forwardRef<TwoStepVideoViewRef, TwoStepVideoViewProps>(\n (props, ref) => {\n const nativeRef = useRef<NativeViewRef>(null);\n\n useImperativeHandle(ref, () => ({\n play: async () => {\n await nativeRef.current?.play();\n },\n pause: async () => {\n await nativeRef.current?.pause();\n },\n seek: async (time: number) => {\n await nativeRef.current?.seek(time);\n },\n replay: async () => {\n await nativeRef.current?.replay();\n },\n getPanZoomState: async () => {\n const state = await nativeRef.current?.getPanZoomState();\n return state ?? { panX: 0, panY: 0, zoomLevel: 1 };\n },\n setPanZoomState: async (state: Partial<PanZoomState>) => {\n await nativeRef.current?.setPanZoomState(state.panX, state.panY, state.zoomLevel);\n },\n resetPanZoom: async () => {\n await nativeRef.current?.resetPanZoom();\n },\n }));\n\n return <NativeView ref={nativeRef} {...props} />;\n }\n);\n\nTwoStepVideoView.displayName = 'TwoStepVideoView';\n\nexport default TwoStepVideoView;\n"]}
|
|
1
|
+
{"version":3,"file":"ExpoTwoStepVideoView.js","sourceRoot":"","sources":["../src/ExpoTwoStepVideoView.tsx"],"names":[],"mappings":"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","sourcesContent":["import { requireNativeView } from 'expo';\nimport * as React from 'react';\nimport { forwardRef, useCallback, useImperativeHandle, useRef, useState } from 'react';\nimport { View, Animated, Text, StyleSheet } from 'react-native';\n\nimport { DoubleTapSkipEvent, PanZoomState, TwoStepVideoViewProps, TwoStepVideoViewRef } from './ExpoTwoStepVideo.types';\nimport PlayheadBar from './components/PlayheadBar';\n\n// Internal props type that includes the native ref\ntype NativeViewProps = TwoStepVideoViewProps & {\n ref?: React.Ref<NativeViewRef>;\n};\n\n// Native view ref with native methods\ntype NativeViewRef = {\n play: () => Promise<void>;\n pause: () => Promise<void>;\n seek: (time: number) => Promise<void>;\n replay: () => Promise<void>;\n getPanZoomState: () => Promise<PanZoomState>;\n setPanZoomState: (panX?: number, panY?: number, zoomLevel?: number) => Promise<void>;\n resetPanZoom: () => Promise<void>;\n};\n\nconst NativeView: React.ComponentType<NativeViewProps> = requireNativeView('ExpoTwoStepVideo');\n\n/**\n * Video player view that can play compositions and assets directly\n *\n * @example\n * ```tsx\n * const playerRef = useRef<TwoStepVideoViewRef>(null);\n *\n * // Play a composition (from mirrorVideo, trimVideo, etc.)\n * <TwoStepVideoView\n * ref={playerRef}\n * compositionId={composition.id}\n * onPlaybackStatusChange={(e) => console.log(e.nativeEvent.status)}\n * onProgress={(e) => setProgress(e.nativeEvent.progress)}\n * style={{ width: '100%', height: 300 }}\n * />\n *\n * // Control playback\n * playerRef.current?.play();\n * playerRef.current?.pause();\n * playerRef.current?.seek(5.0);\n * ```\n */\nconst TwoStepVideoView = forwardRef<TwoStepVideoViewRef, TwoStepVideoViewProps>(\n (props, ref) => {\n const {\n showPlayheadBar = true,\n enableDoubleTapSkip = true,\n doubleTapSkipInterval = 5,\n onProgress,\n onPlaybackStatusChange,\n onDoubleTapSkip,\n style,\n ...nativeProps\n } = props;\n\n const nativeRef = useRef<NativeViewRef>(null);\n const currentTimeRef = useRef(0);\n const durationRef = useRef(0);\n const isPlayingRef = useRef(false);\n const wasPlayingRef = useRef(false);\n\n // Force re-render for overlay state\n const [currentTime, setCurrentTime] = React.useState(0);\n const [duration, setDuration] = React.useState(0);\n\n // Double-tap feedback animation state\n const [skipFeedback, setSkipFeedback] = useState<{ direction: 'forward' | 'backward'; interval: number } | null>(null);\n const feedbackOpacity = useRef(new Animated.Value(0)).current;\n\n useImperativeHandle(ref, () => ({\n play: async () => {\n await nativeRef.current?.play();\n },\n pause: async () => {\n await nativeRef.current?.pause();\n },\n seek: async (time: number) => {\n await nativeRef.current?.seek(time);\n },\n replay: async () => {\n await nativeRef.current?.replay();\n },\n getPanZoomState: async () => {\n const state = await nativeRef.current?.getPanZoomState();\n return state ?? { panX: 0, panY: 0, zoomLevel: 1 };\n },\n setPanZoomState: async (state: Partial<PanZoomState>) => {\n await nativeRef.current?.setPanZoomState(state.panX, state.panY, state.zoomLevel);\n },\n resetPanZoom: async () => {\n await nativeRef.current?.resetPanZoom();\n },\n }));\n\n const handleProgress = useCallback(\n (event: { nativeEvent: { currentTime: number; duration: number; progress: number } }) => {\n currentTimeRef.current = event.nativeEvent.currentTime;\n durationRef.current = event.nativeEvent.duration;\n setCurrentTime(event.nativeEvent.currentTime);\n setDuration(event.nativeEvent.duration);\n onProgress?.(event);\n },\n [onProgress]\n );\n\n const handlePlaybackStatusChange = useCallback(\n (event: { nativeEvent: { status: string; time?: number } }) => {\n isPlayingRef.current = event.nativeEvent.status === 'playing';\n onPlaybackStatusChange?.(event as any);\n },\n [onPlaybackStatusChange]\n );\n\n // Handle native double-tap skip event - show visual feedback\n const handleDoubleTapSkip = useCallback(\n (event: { nativeEvent: DoubleTapSkipEvent }) => {\n const { direction, skipInterval, newTime } = event.nativeEvent;\n\n // Update local time state\n currentTimeRef.current = newTime;\n setCurrentTime(newTime);\n\n // Show visual feedback\n setSkipFeedback({ direction, interval: skipInterval });\n feedbackOpacity.setValue(1);\n Animated.timing(feedbackOpacity, {\n toValue: 0,\n duration: 600,\n delay: 200,\n useNativeDriver: true,\n }).start(() => {\n setSkipFeedback(null);\n });\n\n // Forward the event to parent if provided\n onDoubleTapSkip?.(event);\n },\n [feedbackOpacity, onDoubleTapSkip]\n );\n\n // PlayheadBar callbacks\n const handleSeekStart = useCallback(() => {\n wasPlayingRef.current = isPlayingRef.current;\n if (isPlayingRef.current) {\n nativeRef.current?.pause();\n }\n }, []);\n\n const handlePlayheadSeek = useCallback((time: number) => {\n nativeRef.current?.seek(time);\n currentTimeRef.current = time;\n setCurrentTime(time);\n }, []);\n\n const handleSeekEnd = useCallback(() => {\n if (wasPlayingRef.current) {\n nativeRef.current?.play();\n }\n }, []);\n\n return (\n <View style={[style, { overflow: 'hidden' }]} pointerEvents=\"box-none\">\n <NativeView\n ref={nativeRef}\n {...nativeProps}\n enableDoubleTapSkip={enableDoubleTapSkip}\n doubleTapSkipInterval={doubleTapSkipInterval}\n onProgress={handleProgress}\n onPlaybackStatusChange={handlePlaybackStatusChange}\n onDoubleTapSkip={handleDoubleTapSkip}\n style={{ flex: 1 }}\n />\n {/* Double-tap skip visual feedback (shows on native event) */}\n {skipFeedback && (\n <View style={styles.feedbackContainer} pointerEvents=\"none\">\n <View style={[styles.feedbackHalf, skipFeedback.direction === 'backward' && styles.feedbackActive]}>\n {skipFeedback.direction === 'backward' && (\n <Animated.View style={[styles.feedbackCircle, { opacity: feedbackOpacity }]}>\n <Text style={styles.arrowText}>{'<<'}</Text>\n <Text style={styles.skipText}>{skipFeedback.interval}s</Text>\n </Animated.View>\n )}\n </View>\n <View style={[styles.feedbackHalf, skipFeedback.direction === 'forward' && styles.feedbackActive]}>\n {skipFeedback.direction === 'forward' && (\n <Animated.View style={[styles.feedbackCircle, { opacity: feedbackOpacity }]}>\n <Text style={styles.arrowText}>{'>>'}</Text>\n <Text style={styles.skipText}>{skipFeedback.interval}s</Text>\n </Animated.View>\n )}\n </View>\n </View>\n )}\n {showPlayheadBar && (\n <PlayheadBar\n currentTime={currentTime}\n duration={duration}\n onSeekStart={handleSeekStart}\n onSeek={handlePlayheadSeek}\n onSeekEnd={handleSeekEnd}\n />\n )}\n </View>\n );\n }\n);\n\nconst styles = StyleSheet.create({\n feedbackContainer: {\n ...StyleSheet.absoluteFillObject,\n flexDirection: 'row',\n },\n feedbackHalf: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n },\n feedbackActive: {},\n feedbackCircle: {\n width: 64,\n height: 64,\n borderRadius: 32,\n backgroundColor: 'rgba(0,0,0,0.4)',\n justifyContent: 'center',\n alignItems: 'center',\n },\n arrowText: {\n color: '#FFFFFF',\n fontSize: 20,\n fontWeight: '700',\n },\n skipText: {\n color: '#FFFFFF',\n fontSize: 12,\n fontWeight: '600',\n marginTop: 2,\n },\n});\n\nTwoStepVideoView.displayName = 'TwoStepVideoView';\n\nexport default TwoStepVideoView;\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export type DoubleTapSkipProps = {
|
|
3
|
+
currentTime: number;
|
|
4
|
+
duration: number;
|
|
5
|
+
skipInterval: number;
|
|
6
|
+
onSeek: (time: number) => void;
|
|
7
|
+
};
|
|
8
|
+
export default function DoubleTapSkip({ currentTime, duration, skipInterval, onSeek, }: DoubleTapSkipProps): React.JSX.Element;
|
|
9
|
+
//# sourceMappingURL=DoubleTapSkip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DoubleTapSkip.d.ts","sourceRoot":"","sources":["../../src/components/DoubleTapSkip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAU/B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC,CAAC;AAIF,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EACpC,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,MAAM,GACP,EAAE,kBAAkB,qBAiGpB"}
|