@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.
@@ -0,0 +1,139 @@
1
+ import * as React from 'react';
2
+ import { useRef, useCallback } from 'react';
3
+ import { View, StyleSheet, TouchableWithoutFeedback, Animated, Text, } from 'react-native';
4
+ const DOUBLE_TAP_DELAY = 300;
5
+ export default function DoubleTapSkip({ currentTime, duration, skipInterval, onSeek, }) {
6
+ const currentTimeRef = useRef(currentTime);
7
+ currentTimeRef.current = currentTime;
8
+ const durationRef = useRef(duration);
9
+ durationRef.current = duration;
10
+ const lastTapLeft = useRef(0);
11
+ const lastTapRight = useRef(0);
12
+ const leftTimeoutRef = useRef(null);
13
+ const rightTimeoutRef = useRef(null);
14
+ const leftOpacity = useRef(new Animated.Value(0)).current;
15
+ const rightOpacity = useRef(new Animated.Value(0)).current;
16
+ const showFeedback = useCallback((opacity) => {
17
+ opacity.setValue(1);
18
+ Animated.timing(opacity, {
19
+ toValue: 0,
20
+ duration: 600,
21
+ delay: 200,
22
+ useNativeDriver: true,
23
+ }).start();
24
+ }, []);
25
+ const handleLeftTap = useCallback(() => {
26
+ const now = Date.now();
27
+ if (now - lastTapLeft.current < DOUBLE_TAP_DELAY) {
28
+ // Double tap detected
29
+ if (leftTimeoutRef.current) {
30
+ clearTimeout(leftTimeoutRef.current);
31
+ leftTimeoutRef.current = null;
32
+ }
33
+ const newTime = Math.max(0, currentTimeRef.current - skipInterval);
34
+ onSeek(newTime);
35
+ showFeedback(leftOpacity);
36
+ lastTapLeft.current = 0;
37
+ }
38
+ else {
39
+ lastTapLeft.current = now;
40
+ leftTimeoutRef.current = setTimeout(() => {
41
+ lastTapLeft.current = 0;
42
+ leftTimeoutRef.current = null;
43
+ }, DOUBLE_TAP_DELAY);
44
+ }
45
+ }, [skipInterval, onSeek, showFeedback, leftOpacity]);
46
+ const handleRightTap = useCallback(() => {
47
+ const now = Date.now();
48
+ if (now - lastTapRight.current < DOUBLE_TAP_DELAY) {
49
+ // Double tap detected
50
+ if (rightTimeoutRef.current) {
51
+ clearTimeout(rightTimeoutRef.current);
52
+ rightTimeoutRef.current = null;
53
+ }
54
+ const newTime = Math.min(durationRef.current, currentTimeRef.current + skipInterval);
55
+ onSeek(newTime);
56
+ showFeedback(rightOpacity);
57
+ lastTapRight.current = 0;
58
+ }
59
+ else {
60
+ lastTapRight.current = now;
61
+ rightTimeoutRef.current = setTimeout(() => {
62
+ lastTapRight.current = 0;
63
+ rightTimeoutRef.current = null;
64
+ }, DOUBLE_TAP_DELAY);
65
+ }
66
+ }, [skipInterval, onSeek, showFeedback, rightOpacity]);
67
+ return (<View style={styles.container} pointerEvents="box-none">
68
+ {/* Left side - positioned as a smaller hit zone to allow pinch gestures elsewhere */}
69
+ <View style={styles.half} pointerEvents="box-none">
70
+ <TouchableWithoutFeedback onPress={handleLeftTap}>
71
+ <View style={styles.hitZone}>
72
+ <Animated.View style={[styles.feedback, { opacity: leftOpacity }]}>
73
+ <View style={styles.feedbackCircle}>
74
+ <Text style={styles.arrowText}>{'<<'}</Text>
75
+ <Text style={styles.skipText}>{skipInterval}s</Text>
76
+ </View>
77
+ </Animated.View>
78
+ </View>
79
+ </TouchableWithoutFeedback>
80
+ </View>
81
+ {/* Right side - positioned as a smaller hit zone to allow pinch gestures elsewhere */}
82
+ <View style={styles.half} pointerEvents="box-none">
83
+ <TouchableWithoutFeedback onPress={handleRightTap}>
84
+ <View style={styles.hitZone}>
85
+ <Animated.View style={[styles.feedback, { opacity: rightOpacity }]}>
86
+ <View style={styles.feedbackCircle}>
87
+ <Text style={styles.arrowText}>{'>>'}</Text>
88
+ <Text style={styles.skipText}>{skipInterval}s</Text>
89
+ </View>
90
+ </Animated.View>
91
+ </View>
92
+ </TouchableWithoutFeedback>
93
+ </View>
94
+ </View>);
95
+ }
96
+ const HIT_ZONE_SIZE = 120;
97
+ const styles = StyleSheet.create({
98
+ container: {
99
+ ...StyleSheet.absoluteFillObject,
100
+ flexDirection: 'row',
101
+ },
102
+ half: {
103
+ flex: 1,
104
+ justifyContent: 'center',
105
+ alignItems: 'center',
106
+ },
107
+ hitZone: {
108
+ // Smaller hit zone allows pinch gestures in other areas
109
+ width: HIT_ZONE_SIZE,
110
+ height: HIT_ZONE_SIZE,
111
+ borderRadius: HIT_ZONE_SIZE / 2,
112
+ justifyContent: 'center',
113
+ alignItems: 'center',
114
+ },
115
+ feedback: {
116
+ justifyContent: 'center',
117
+ alignItems: 'center',
118
+ },
119
+ feedbackCircle: {
120
+ width: 64,
121
+ height: 64,
122
+ borderRadius: 32,
123
+ backgroundColor: 'rgba(0,0,0,0.4)',
124
+ justifyContent: 'center',
125
+ alignItems: 'center',
126
+ },
127
+ arrowText: {
128
+ color: '#FFFFFF',
129
+ fontSize: 20,
130
+ fontWeight: '700',
131
+ },
132
+ skipText: {
133
+ color: '#FFFFFF',
134
+ fontSize: 12,
135
+ fontWeight: '600',
136
+ marginTop: 2,
137
+ },
138
+ });
139
+ //# sourceMappingURL=DoubleTapSkip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DoubleTapSkip.js","sourceRoot":"","sources":["../../src/components/DoubleTapSkip.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react';\nimport { useRef, useCallback } from 'react';\nimport {\n View,\n StyleSheet,\n TouchableWithoutFeedback,\n Animated,\n Text,\n} from 'react-native';\n\nexport type DoubleTapSkipProps = {\n currentTime: number;\n duration: number;\n skipInterval: number;\n onSeek: (time: number) => void;\n};\n\nconst DOUBLE_TAP_DELAY = 300;\n\nexport default function DoubleTapSkip({\n currentTime,\n duration,\n skipInterval,\n onSeek,\n}: DoubleTapSkipProps) {\n const currentTimeRef = useRef(currentTime);\n currentTimeRef.current = currentTime;\n\n const durationRef = useRef(duration);\n durationRef.current = duration;\n\n const lastTapLeft = useRef(0);\n const lastTapRight = useRef(0);\n const leftTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const rightTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const leftOpacity = useRef(new Animated.Value(0)).current;\n const rightOpacity = useRef(new Animated.Value(0)).current;\n\n const showFeedback = useCallback((opacity: Animated.Value) => {\n opacity.setValue(1);\n Animated.timing(opacity, {\n toValue: 0,\n duration: 600,\n delay: 200,\n useNativeDriver: true,\n }).start();\n }, []);\n\n const handleLeftTap = useCallback(() => {\n const now = Date.now();\n if (now - lastTapLeft.current < DOUBLE_TAP_DELAY) {\n // Double tap detected\n if (leftTimeoutRef.current) {\n clearTimeout(leftTimeoutRef.current);\n leftTimeoutRef.current = null;\n }\n const newTime = Math.max(0, currentTimeRef.current - skipInterval);\n onSeek(newTime);\n showFeedback(leftOpacity);\n lastTapLeft.current = 0;\n } else {\n lastTapLeft.current = now;\n leftTimeoutRef.current = setTimeout(() => {\n lastTapLeft.current = 0;\n leftTimeoutRef.current = null;\n }, DOUBLE_TAP_DELAY);\n }\n }, [skipInterval, onSeek, showFeedback, leftOpacity]);\n\n const handleRightTap = useCallback(() => {\n const now = Date.now();\n if (now - lastTapRight.current < DOUBLE_TAP_DELAY) {\n // Double tap detected\n if (rightTimeoutRef.current) {\n clearTimeout(rightTimeoutRef.current);\n rightTimeoutRef.current = null;\n }\n const newTime = Math.min(durationRef.current, currentTimeRef.current + skipInterval);\n onSeek(newTime);\n showFeedback(rightOpacity);\n lastTapRight.current = 0;\n } else {\n lastTapRight.current = now;\n rightTimeoutRef.current = setTimeout(() => {\n lastTapRight.current = 0;\n rightTimeoutRef.current = null;\n }, DOUBLE_TAP_DELAY);\n }\n }, [skipInterval, onSeek, showFeedback, rightOpacity]);\n\n return (\n <View style={styles.container} pointerEvents=\"box-none\">\n {/* Left side - positioned as a smaller hit zone to allow pinch gestures elsewhere */}\n <View style={styles.half} pointerEvents=\"box-none\">\n <TouchableWithoutFeedback onPress={handleLeftTap}>\n <View style={styles.hitZone}>\n <Animated.View style={[styles.feedback, { opacity: leftOpacity }]}>\n <View style={styles.feedbackCircle}>\n <Text style={styles.arrowText}>{'<<'}</Text>\n <Text style={styles.skipText}>{skipInterval}s</Text>\n </View>\n </Animated.View>\n </View>\n </TouchableWithoutFeedback>\n </View>\n {/* Right side - positioned as a smaller hit zone to allow pinch gestures elsewhere */}\n <View style={styles.half} pointerEvents=\"box-none\">\n <TouchableWithoutFeedback onPress={handleRightTap}>\n <View style={styles.hitZone}>\n <Animated.View style={[styles.feedback, { opacity: rightOpacity }]}>\n <View style={styles.feedbackCircle}>\n <Text style={styles.arrowText}>{'>>'}</Text>\n <Text style={styles.skipText}>{skipInterval}s</Text>\n </View>\n </Animated.View>\n </View>\n </TouchableWithoutFeedback>\n </View>\n </View>\n );\n}\n\nconst HIT_ZONE_SIZE = 120;\n\nconst styles = StyleSheet.create({\n container: {\n ...StyleSheet.absoluteFillObject,\n flexDirection: 'row',\n },\n half: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n },\n hitZone: {\n // Smaller hit zone allows pinch gestures in other areas\n width: HIT_ZONE_SIZE,\n height: HIT_ZONE_SIZE,\n borderRadius: HIT_ZONE_SIZE / 2,\n justifyContent: 'center',\n alignItems: 'center',\n },\n feedback: {\n justifyContent: 'center',\n alignItems: 'center',\n },\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"]}
@@ -0,0 +1,10 @@
1
+ import * as React from 'react';
2
+ export type PlayheadBarProps = {
3
+ currentTime: number;
4
+ duration: number;
5
+ onSeekStart: () => void;
6
+ onSeek: (time: number) => void;
7
+ onSeekEnd: () => void;
8
+ };
9
+ export default function PlayheadBar({ currentTime, duration, onSeekStart, onSeek, onSeekEnd, }: PlayheadBarProps): React.JSX.Element;
10
+ //# sourceMappingURL=PlayheadBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlayheadBar.d.ts","sourceRoot":"","sources":["../../src/components/PlayheadBar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAU/B,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB,CAAC;AAOF,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,WAAW,EACX,QAAQ,EACR,WAAW,EACX,MAAM,EACN,SAAS,GACV,EAAE,gBAAgB,qBAuIlB"}
@@ -0,0 +1,156 @@
1
+ import * as React from 'react';
2
+ import { useRef, useCallback, useEffect, useState } from 'react';
3
+ import { View, StyleSheet, PanResponder, Animated, } from 'react-native';
4
+ const COLLAPSED_HEIGHT = 2;
5
+ const EXPANDED_HEIGHT = 4;
6
+ const THUMB_SIZE = 14;
7
+ const HIT_SLOP_HEIGHT = 30;
8
+ export default function PlayheadBar({ currentTime, duration, onSeekStart, onSeek, onSeekEnd, }) {
9
+ const [progressPercent, setProgressPercent] = useState(0);
10
+ const containerWidthRef = useRef(0);
11
+ const currentTimeRef = useRef(currentTime);
12
+ const durationRef = useRef(duration);
13
+ const isScrubbing = useRef(false);
14
+ // These animations use non-native driver (height) or native driver (scale/translate)
15
+ const barHeight = useRef(new Animated.Value(COLLAPSED_HEIGHT)).current;
16
+ const thumbScale = useRef(new Animated.Value(0)).current;
17
+ const thumbTranslateX = useRef(new Animated.Value(0)).current;
18
+ useEffect(() => {
19
+ currentTimeRef.current = currentTime;
20
+ if (!isScrubbing.current && duration > 0) {
21
+ const p = currentTime / duration;
22
+ setProgressPercent(p * 100);
23
+ thumbTranslateX.setValue(p * containerWidthRef.current);
24
+ }
25
+ }, [currentTime, duration, thumbTranslateX]);
26
+ useEffect(() => {
27
+ durationRef.current = duration;
28
+ }, [duration]);
29
+ const expand = useCallback(() => {
30
+ Animated.parallel([
31
+ Animated.timing(barHeight, {
32
+ toValue: EXPANDED_HEIGHT,
33
+ duration: 150,
34
+ useNativeDriver: false,
35
+ }),
36
+ Animated.timing(thumbScale, {
37
+ toValue: 1,
38
+ duration: 150,
39
+ useNativeDriver: true,
40
+ }),
41
+ ]).start();
42
+ }, [barHeight, thumbScale]);
43
+ const collapse = useCallback(() => {
44
+ Animated.parallel([
45
+ Animated.timing(barHeight, {
46
+ toValue: COLLAPSED_HEIGHT,
47
+ duration: 150,
48
+ useNativeDriver: false,
49
+ }),
50
+ Animated.timing(thumbScale, {
51
+ toValue: 0,
52
+ duration: 150,
53
+ useNativeDriver: true,
54
+ }),
55
+ ]).start();
56
+ }, [barHeight, thumbScale]);
57
+ const updateProgress = useCallback((p) => {
58
+ setProgressPercent(p * 100);
59
+ thumbTranslateX.setValue(p * containerWidthRef.current);
60
+ }, [thumbTranslateX]);
61
+ const clampProgress = useCallback((pageX) => {
62
+ const width = containerWidthRef.current;
63
+ if (width <= 0 || durationRef.current <= 0)
64
+ return 0;
65
+ const clamped = Math.max(0, Math.min(1, pageX / width));
66
+ return clamped;
67
+ }, []);
68
+ const panResponder = useRef(PanResponder.create({
69
+ onStartShouldSetPanResponder: () => true,
70
+ onMoveShouldSetPanResponder: () => true,
71
+ onPanResponderGrant: (evt) => {
72
+ isScrubbing.current = true;
73
+ expand();
74
+ onSeekStart();
75
+ const p = clampProgress(evt.nativeEvent.locationX);
76
+ updateProgress(p);
77
+ onSeek(p * durationRef.current);
78
+ },
79
+ onPanResponderMove: (evt) => {
80
+ const width = containerWidthRef.current;
81
+ if (width <= 0)
82
+ return;
83
+ const p = Math.max(0, Math.min(1, evt.nativeEvent.locationX / width));
84
+ updateProgress(p);
85
+ onSeek(p * durationRef.current);
86
+ },
87
+ onPanResponderRelease: () => {
88
+ isScrubbing.current = false;
89
+ collapse();
90
+ onSeekEnd();
91
+ },
92
+ onPanResponderTerminate: () => {
93
+ isScrubbing.current = false;
94
+ collapse();
95
+ onSeekEnd();
96
+ },
97
+ })).current;
98
+ const onLayout = useCallback((e) => {
99
+ const width = e.nativeEvent.layout.width;
100
+ containerWidthRef.current = width;
101
+ // Update thumb position when container width changes
102
+ if (durationRef.current > 0) {
103
+ const p = currentTimeRef.current / durationRef.current;
104
+ thumbTranslateX.setValue(p * width);
105
+ }
106
+ }, [thumbTranslateX]);
107
+ return (<View style={styles.container} pointerEvents="box-none">
108
+ <View style={styles.hitArea} onLayout={onLayout} {...panResponder.panHandlers}>
109
+ <Animated.View style={[styles.track, { height: barHeight }]}>
110
+ {/* Use percentage-based width without Animated to avoid native driver issues */}
111
+ <View style={[styles.filled, { width: `${progressPercent}%` }]}/>
112
+ </Animated.View>
113
+ <Animated.View style={[
114
+ styles.thumb,
115
+ {
116
+ transform: [
117
+ { translateX: thumbTranslateX },
118
+ { scale: thumbScale },
119
+ ],
120
+ },
121
+ ]}/>
122
+ </View>
123
+ </View>);
124
+ }
125
+ const styles = StyleSheet.create({
126
+ container: {
127
+ position: 'absolute',
128
+ bottom: 0,
129
+ left: 0,
130
+ right: 0,
131
+ },
132
+ hitArea: {
133
+ height: HIT_SLOP_HEIGHT,
134
+ justifyContent: 'flex-end',
135
+ },
136
+ track: {
137
+ width: '100%',
138
+ backgroundColor: 'rgba(255,255,255,0.25)',
139
+ overflow: 'hidden',
140
+ },
141
+ filled: {
142
+ height: '100%',
143
+ backgroundColor: 'rgba(255,255,255,0.7)',
144
+ },
145
+ thumb: {
146
+ position: 'absolute',
147
+ bottom: -(THUMB_SIZE / 2) + COLLAPSED_HEIGHT / 2,
148
+ // Position at left edge minus half thumb width, translateX moves it
149
+ left: -(THUMB_SIZE / 2),
150
+ width: THUMB_SIZE,
151
+ height: THUMB_SIZE,
152
+ borderRadius: THUMB_SIZE / 2,
153
+ backgroundColor: '#FFFFFF',
154
+ },
155
+ });
156
+ //# sourceMappingURL=PlayheadBar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlayheadBar.js","sourceRoot":"","sources":["../../src/components/PlayheadBar.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react';\nimport { useRef, useCallback, useEffect, useState } from 'react';\nimport {\n View,\n StyleSheet,\n PanResponder,\n Animated,\n LayoutChangeEvent,\n} from 'react-native';\n\nexport type PlayheadBarProps = {\n currentTime: number;\n duration: number;\n onSeekStart: () => void;\n onSeek: (time: number) => void;\n onSeekEnd: () => void;\n};\n\nconst COLLAPSED_HEIGHT = 2;\nconst EXPANDED_HEIGHT = 4;\nconst THUMB_SIZE = 14;\nconst HIT_SLOP_HEIGHT = 30;\n\nexport default function PlayheadBar({\n currentTime,\n duration,\n onSeekStart,\n onSeek,\n onSeekEnd,\n}: PlayheadBarProps) {\n const [progressPercent, setProgressPercent] = useState(0);\n const containerWidthRef = useRef(0);\n const currentTimeRef = useRef(currentTime);\n const durationRef = useRef(duration);\n const isScrubbing = useRef(false);\n\n // These animations use non-native driver (height) or native driver (scale/translate)\n const barHeight = useRef(new Animated.Value(COLLAPSED_HEIGHT)).current;\n const thumbScale = useRef(new Animated.Value(0)).current;\n const thumbTranslateX = useRef(new Animated.Value(0)).current;\n\n useEffect(() => {\n currentTimeRef.current = currentTime;\n if (!isScrubbing.current && duration > 0) {\n const p = currentTime / duration;\n setProgressPercent(p * 100);\n thumbTranslateX.setValue(p * containerWidthRef.current);\n }\n }, [currentTime, duration, thumbTranslateX]);\n\n useEffect(() => {\n durationRef.current = duration;\n }, [duration]);\n\n const expand = useCallback(() => {\n Animated.parallel([\n Animated.timing(barHeight, {\n toValue: EXPANDED_HEIGHT,\n duration: 150,\n useNativeDriver: false,\n }),\n Animated.timing(thumbScale, {\n toValue: 1,\n duration: 150,\n useNativeDriver: true,\n }),\n ]).start();\n }, [barHeight, thumbScale]);\n\n const collapse = useCallback(() => {\n Animated.parallel([\n Animated.timing(barHeight, {\n toValue: COLLAPSED_HEIGHT,\n duration: 150,\n useNativeDriver: false,\n }),\n Animated.timing(thumbScale, {\n toValue: 0,\n duration: 150,\n useNativeDriver: true,\n }),\n ]).start();\n }, [barHeight, thumbScale]);\n\n const updateProgress = useCallback((p: number) => {\n setProgressPercent(p * 100);\n thumbTranslateX.setValue(p * containerWidthRef.current);\n }, [thumbTranslateX]);\n\n const clampProgress = useCallback((pageX: number): number => {\n const width = containerWidthRef.current;\n if (width <= 0 || durationRef.current <= 0) return 0;\n const clamped = Math.max(0, Math.min(1, pageX / width));\n return clamped;\n }, []);\n\n const panResponder = useRef(\n PanResponder.create({\n onStartShouldSetPanResponder: () => true,\n onMoveShouldSetPanResponder: () => true,\n onPanResponderGrant: (evt) => {\n isScrubbing.current = true;\n expand();\n onSeekStart();\n\n const p = clampProgress(evt.nativeEvent.locationX);\n updateProgress(p);\n onSeek(p * durationRef.current);\n },\n onPanResponderMove: (evt) => {\n const width = containerWidthRef.current;\n if (width <= 0) return;\n const p = Math.max(0, Math.min(1, evt.nativeEvent.locationX / width));\n updateProgress(p);\n onSeek(p * durationRef.current);\n },\n onPanResponderRelease: () => {\n isScrubbing.current = false;\n collapse();\n onSeekEnd();\n },\n onPanResponderTerminate: () => {\n isScrubbing.current = false;\n collapse();\n onSeekEnd();\n },\n })\n ).current;\n\n const onLayout = useCallback((e: LayoutChangeEvent) => {\n const width = e.nativeEvent.layout.width;\n containerWidthRef.current = width;\n // Update thumb position when container width changes\n if (durationRef.current > 0) {\n const p = currentTimeRef.current / durationRef.current;\n thumbTranslateX.setValue(p * width);\n }\n }, [thumbTranslateX]);\n\n return (\n <View style={styles.container} pointerEvents=\"box-none\">\n <View\n style={styles.hitArea}\n onLayout={onLayout}\n {...panResponder.panHandlers}\n >\n <Animated.View style={[styles.track, { height: barHeight }]}>\n {/* Use percentage-based width without Animated to avoid native driver issues */}\n <View style={[styles.filled, { width: `${progressPercent}%` }]} />\n </Animated.View>\n <Animated.View\n style={[\n styles.thumb,\n {\n transform: [\n { translateX: thumbTranslateX },\n { scale: thumbScale },\n ],\n },\n ]}\n />\n </View>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n },\n hitArea: {\n height: HIT_SLOP_HEIGHT,\n justifyContent: 'flex-end',\n },\n track: {\n width: '100%',\n backgroundColor: 'rgba(255,255,255,0.25)',\n overflow: 'hidden',\n },\n filled: {\n height: '100%',\n backgroundColor: 'rgba(255,255,255,0.7)',\n },\n thumb: {\n position: 'absolute',\n bottom: -(THUMB_SIZE / 2) + COLLAPSED_HEIGHT / 2,\n // Position at left edge minus half thumb width, translateX moves it\n left: -(THUMB_SIZE / 2),\n width: THUMB_SIZE,\n height: THUMB_SIZE,\n borderRadius: THUMB_SIZE / 2,\n backgroundColor: '#FFFFFF',\n },\n});\n"]}
package/build/index.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * Built on native AVFoundation with Expo Modules
4
4
  */
5
5
  import { type EventSubscription } from 'expo-modules-core';
6
- import type { PanZoomVideoOptions } from './ExpoTwoStepVideo.types';
6
+ import type { PanZoomVideoOptions, PickVideoOptions, PickedVideo } from './ExpoTwoStepVideo.types';
7
7
  /**
8
8
  * Quality presets for video export
9
9
  */
@@ -412,7 +412,84 @@ export declare function transformVideo(options: TransformVideoOptions): Promise<
412
412
  * ```
413
413
  */
414
414
  export declare function loopSegment(options: LoopSegmentOptions): Promise<LoopResult>;
415
- export type { PanZoomVideoOptions } from './ExpoTwoStepVideo.types';
415
+ export type { PanZoomVideoOptions, PickVideoOptions, PickedVideo, DoubleTapSkipEvent } from './ExpoTwoStepVideo.types';
416
+ /**
417
+ * Pick video(s) from the photo library using native PHPickerViewController
418
+ *
419
+ * This provides a native photo library picker that:
420
+ * - Supports albums and favorites
421
+ * - Handles iCloud video downloading automatically (with native progress UI)
422
+ * - Returns comprehensive metadata including creation date
423
+ * - No editing UI - just clean selection
424
+ *
425
+ * @param options - Picker options (optional)
426
+ * @returns Promise resolving to array of picked videos (empty if cancelled)
427
+ *
428
+ * @example
429
+ * ```typescript
430
+ * // Pick a single video
431
+ * const videos = await TwoStepVideo.pickVideo();
432
+ * if (videos.length > 0) {
433
+ * const video = videos[0];
434
+ * console.log(`Selected: ${video.fileName}`);
435
+ * console.log(`Duration: ${video.duration}s`);
436
+ * console.log(`Size: ${video.width}x${video.height}`);
437
+ * console.log(`File size: ${video.fileSize} bytes`);
438
+ * console.log(`Created: ${video.creationDate}`);
439
+ *
440
+ * // Load the video for editing
441
+ * const asset = await TwoStepVideo.loadAsset({ uri: video.uri });
442
+ *
443
+ * // Clean up the temp file when done
444
+ * TwoStepVideo.cleanupPickedVideo(video.path);
445
+ * }
446
+ *
447
+ * // Pick multiple videos
448
+ * const videos = await TwoStepVideo.pickVideo({ selectionLimit: 5 });
449
+ * ```
450
+ */
451
+ export declare function pickVideo(options?: PickVideoOptions): Promise<PickedVideo[]>;
452
+ /**
453
+ * Clean up a specific picked video file from temp storage
454
+ * Call this when you're done with a video that was picked from the library
455
+ *
456
+ * @param path - File path to clean up (use the `path` property from PickedVideo)
457
+ *
458
+ * @example
459
+ * ```typescript
460
+ * const videos = await TwoStepVideo.pickVideo();
461
+ * const video = videos[0];
462
+ *
463
+ * // ... use the video ...
464
+ *
465
+ * // Clean up when done
466
+ * TwoStepVideo.cleanupPickedVideo(video.path);
467
+ * ```
468
+ */
469
+ export declare function cleanupPickedVideo(path: string): void;
470
+ /**
471
+ * Clean up all picked video files from temp storage
472
+ * Useful for cleanup when unmounting screens or releasing all resources
473
+ *
474
+ * @example
475
+ * ```typescript
476
+ * // In a cleanup effect
477
+ * useEffect(() => {
478
+ * return () => {
479
+ * TwoStepVideo.cleanupAllPickedVideos();
480
+ * TwoStepVideo.releaseAll();
481
+ * };
482
+ * }, []);
483
+ * ```
484
+ */
485
+ export declare function cleanupAllPickedVideos(): void;
486
+ /**
487
+ * Get list of currently tracked picked video paths
488
+ * Useful for debugging or manual cleanup
489
+ *
490
+ * @returns Array of file paths for picked videos in temp storage
491
+ */
492
+ export declare function getPickedVideoPaths(): string[];
416
493
  /**
417
494
  * Apply pan and zoom transformation to a video
418
495
  *
@@ -580,6 +657,10 @@ declare const _default: {
580
657
  readonly VERTICAL: string;
581
658
  readonly BOTH: string;
582
659
  };
660
+ pickVideo: typeof pickVideo;
661
+ cleanupPickedVideo: typeof cleanupPickedVideo;
662
+ cleanupAllPickedVideos: typeof cleanupAllPickedVideos;
663
+ getPickedVideoPaths: typeof getPickedVideoPaths;
583
664
  loadAsset: typeof loadAsset;
584
665
  loadAssetFromPhotos: typeof loadAssetFromPhotos;
585
666
  validateVideoUri: typeof validateVideoUri;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAG3D,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAInG;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAEjE;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,UAAU,GAAG,MAAM,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,0BAA0B;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,uBAAuB;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,0BAA0B;IAC1B,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,mCAAmC;IACnC,IAAI,CAAC,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,+BAA+B;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,IAAI,EAAE,UAAU,CAAC;IACjB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2BAA2B;IAC3B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;CACpB;AAID;;GAEG;AACH,eAAO,MAAM,OAAO;;;;;CAKV,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,MAAM;;;;CAIT,CAAC;AAIX;;;;;;;;;;;;;GAaG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAE9E;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAEtF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEpE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAMpF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAE/F;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAOxF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAOxF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAQ9F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,CAOlF;AAGD,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAIvH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,SAAS,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAElF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAErD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAS1F;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,MAAM,EAAE,CAAC,CAMnB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,YAAY,CAAC,CAM1F;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAMpF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE7C;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAElD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAE9D;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,GAC7C,iBAAiB,CAEnB;AAID;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAY1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAID,wBAuCE;AAIF,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,YAAY,EACV,gBAAgB,EAChB,qBAAqB,EACrB,mBAAmB,EACnB,gCAAgC,EAChC,8BAA8B,EAC9B,mBAAmB,EACnB,aAAa,EACb,UAAU,EACV,YAAY,EACZ,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,uBAAuB,CAAC"}
package/build/index.js CHANGED
@@ -239,6 +239,92 @@ export async function transformVideo(options) {
239
239
  export async function loopSegment(options) {
240
240
  return await ExpoTwoStepVideoModule.loopSegment(options.assetId, options.startTime, options.endTime, options.loopCount);
241
241
  }
242
+ // MARK: - Media Picker Functions
243
+ /**
244
+ * Pick video(s) from the photo library using native PHPickerViewController
245
+ *
246
+ * This provides a native photo library picker that:
247
+ * - Supports albums and favorites
248
+ * - Handles iCloud video downloading automatically (with native progress UI)
249
+ * - Returns comprehensive metadata including creation date
250
+ * - No editing UI - just clean selection
251
+ *
252
+ * @param options - Picker options (optional)
253
+ * @returns Promise resolving to array of picked videos (empty if cancelled)
254
+ *
255
+ * @example
256
+ * ```typescript
257
+ * // Pick a single video
258
+ * const videos = await TwoStepVideo.pickVideo();
259
+ * if (videos.length > 0) {
260
+ * const video = videos[0];
261
+ * console.log(`Selected: ${video.fileName}`);
262
+ * console.log(`Duration: ${video.duration}s`);
263
+ * console.log(`Size: ${video.width}x${video.height}`);
264
+ * console.log(`File size: ${video.fileSize} bytes`);
265
+ * console.log(`Created: ${video.creationDate}`);
266
+ *
267
+ * // Load the video for editing
268
+ * const asset = await TwoStepVideo.loadAsset({ uri: video.uri });
269
+ *
270
+ * // Clean up the temp file when done
271
+ * TwoStepVideo.cleanupPickedVideo(video.path);
272
+ * }
273
+ *
274
+ * // Pick multiple videos
275
+ * const videos = await TwoStepVideo.pickVideo({ selectionLimit: 5 });
276
+ * ```
277
+ */
278
+ export async function pickVideo(options) {
279
+ return await ExpoTwoStepVideoModule.pickVideo(options?.selectionLimit);
280
+ }
281
+ /**
282
+ * Clean up a specific picked video file from temp storage
283
+ * Call this when you're done with a video that was picked from the library
284
+ *
285
+ * @param path - File path to clean up (use the `path` property from PickedVideo)
286
+ *
287
+ * @example
288
+ * ```typescript
289
+ * const videos = await TwoStepVideo.pickVideo();
290
+ * const video = videos[0];
291
+ *
292
+ * // ... use the video ...
293
+ *
294
+ * // Clean up when done
295
+ * TwoStepVideo.cleanupPickedVideo(video.path);
296
+ * ```
297
+ */
298
+ export function cleanupPickedVideo(path) {
299
+ ExpoTwoStepVideoModule.cleanupPickedVideo(path);
300
+ }
301
+ /**
302
+ * Clean up all picked video files from temp storage
303
+ * Useful for cleanup when unmounting screens or releasing all resources
304
+ *
305
+ * @example
306
+ * ```typescript
307
+ * // In a cleanup effect
308
+ * useEffect(() => {
309
+ * return () => {
310
+ * TwoStepVideo.cleanupAllPickedVideos();
311
+ * TwoStepVideo.releaseAll();
312
+ * };
313
+ * }, []);
314
+ * ```
315
+ */
316
+ export function cleanupAllPickedVideos() {
317
+ ExpoTwoStepVideoModule.cleanupAllPickedVideos();
318
+ }
319
+ /**
320
+ * Get list of currently tracked picked video paths
321
+ * Useful for debugging or manual cleanup
322
+ *
323
+ * @returns Array of file paths for picked videos in temp storage
324
+ */
325
+ export function getPickedVideoPaths() {
326
+ return ExpoTwoStepVideoModule.getPickedVideoPaths();
327
+ }
242
328
  /**
243
329
  * Apply pan and zoom transformation to a video
244
330
  *
@@ -428,6 +514,11 @@ export default {
428
514
  // Constants
429
515
  Quality,
430
516
  Mirror,
517
+ // Media picker
518
+ pickVideo,
519
+ cleanupPickedVideo,
520
+ cleanupAllPickedVideos,
521
+ getPickedVideoPaths,
431
522
  // Core functions
432
523
  loadAsset,
433
524
  loadAssetFromPhotos,