@venomousone/rn-videokit 0.1.0

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.
Files changed (145) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +248 -0
  3. package/lib/module/components/VideoKit.js +347 -0
  4. package/lib/module/components/VideoKit.js.map +1 -0
  5. package/lib/module/components/controls/FullscreenButton.js +38 -0
  6. package/lib/module/components/controls/FullscreenButton.js.map +1 -0
  7. package/lib/module/components/controls/Icon.js +71 -0
  8. package/lib/module/components/controls/Icon.js.map +1 -0
  9. package/lib/module/components/controls/PlayPauseButton.js +33 -0
  10. package/lib/module/components/controls/PlayPauseButton.js.map +1 -0
  11. package/lib/module/components/controls/Scrubber.js +146 -0
  12. package/lib/module/components/controls/Scrubber.js.map +1 -0
  13. package/lib/module/components/controls/SpeedButton.js +96 -0
  14. package/lib/module/components/controls/SpeedButton.js.map +1 -0
  15. package/lib/module/components/controls/TimeDisplay.js +28 -0
  16. package/lib/module/components/controls/TimeDisplay.js.map +1 -0
  17. package/lib/module/components/controls/VolumeButton.js +31 -0
  18. package/lib/module/components/controls/VolumeButton.js.map +1 -0
  19. package/lib/module/components/core/VideoPlayer.js +114 -0
  20. package/lib/module/components/core/VideoPlayer.js.map +1 -0
  21. package/lib/module/components/core/VideoPlayerContext.js +119 -0
  22. package/lib/module/components/core/VideoPlayerContext.js.map +1 -0
  23. package/lib/module/components/core/index.js +5 -0
  24. package/lib/module/components/core/index.js.map +1 -0
  25. package/lib/module/components/index.js +14 -0
  26. package/lib/module/components/index.js.map +1 -0
  27. package/lib/module/components/overlays/BufferingOverlay.js +24 -0
  28. package/lib/module/components/overlays/BufferingOverlay.js.map +1 -0
  29. package/lib/module/components/overlays/DoubleTapSeek.js +95 -0
  30. package/lib/module/components/overlays/DoubleTapSeek.js.map +1 -0
  31. package/lib/module/components/overlays/ErrorOverlay.js +60 -0
  32. package/lib/module/components/overlays/ErrorOverlay.js.map +1 -0
  33. package/lib/module/components/overlays/GestureIndicator.js +118 -0
  34. package/lib/module/components/overlays/GestureIndicator.js.map +1 -0
  35. package/lib/module/components/overlays/LoadingPoster.js +22 -0
  36. package/lib/module/components/overlays/LoadingPoster.js.map +1 -0
  37. package/lib/module/hooks/index.js +6 -0
  38. package/lib/module/hooks/index.js.map +1 -0
  39. package/lib/module/hooks/useVideoBrightness.js +33 -0
  40. package/lib/module/hooks/useVideoBrightness.js.map +1 -0
  41. package/lib/module/hooks/useVideoControls.js +64 -0
  42. package/lib/module/hooks/useVideoControls.js.map +1 -0
  43. package/lib/module/hooks/useVideoOrientation.js +24 -0
  44. package/lib/module/hooks/useVideoOrientation.js.map +1 -0
  45. package/lib/module/hooks/useVideoPlayer.js +59 -0
  46. package/lib/module/hooks/useVideoPlayer.js.map +1 -0
  47. package/lib/module/hooks/useVideoVolume.js +42 -0
  48. package/lib/module/hooks/useVideoVolume.js.map +1 -0
  49. package/lib/module/index.js +7 -0
  50. package/lib/module/index.js.map +1 -0
  51. package/lib/module/package.json +1 -0
  52. package/lib/module/types/index.js +4 -0
  53. package/lib/module/types/index.js.map +1 -0
  54. package/lib/module/utils/clamp.js +8 -0
  55. package/lib/module/utils/clamp.js.map +1 -0
  56. package/lib/module/utils/formatTime.js +12 -0
  57. package/lib/module/utils/formatTime.js.map +1 -0
  58. package/lib/module/utils/index.js +5 -0
  59. package/lib/module/utils/index.js.map +1 -0
  60. package/lib/typescript/package.json +1 -0
  61. package/lib/typescript/src/components/VideoKit.d.ts +3 -0
  62. package/lib/typescript/src/components/VideoKit.d.ts.map +1 -0
  63. package/lib/typescript/src/components/controls/FullscreenButton.d.ts +6 -0
  64. package/lib/typescript/src/components/controls/FullscreenButton.d.ts.map +1 -0
  65. package/lib/typescript/src/components/controls/Icon.d.ts +10 -0
  66. package/lib/typescript/src/components/controls/Icon.d.ts.map +1 -0
  67. package/lib/typescript/src/components/controls/PlayPauseButton.d.ts +2 -0
  68. package/lib/typescript/src/components/controls/PlayPauseButton.d.ts.map +1 -0
  69. package/lib/typescript/src/components/controls/Scrubber.d.ts +7 -0
  70. package/lib/typescript/src/components/controls/Scrubber.d.ts.map +1 -0
  71. package/lib/typescript/src/components/controls/SpeedButton.d.ts +2 -0
  72. package/lib/typescript/src/components/controls/SpeedButton.d.ts.map +1 -0
  73. package/lib/typescript/src/components/controls/TimeDisplay.d.ts +2 -0
  74. package/lib/typescript/src/components/controls/TimeDisplay.d.ts.map +1 -0
  75. package/lib/typescript/src/components/controls/VolumeButton.d.ts +2 -0
  76. package/lib/typescript/src/components/controls/VolumeButton.d.ts.map +1 -0
  77. package/lib/typescript/src/components/core/VideoPlayer.d.ts +14 -0
  78. package/lib/typescript/src/components/core/VideoPlayer.d.ts.map +1 -0
  79. package/lib/typescript/src/components/core/VideoPlayerContext.d.ts +48 -0
  80. package/lib/typescript/src/components/core/VideoPlayerContext.d.ts.map +1 -0
  81. package/lib/typescript/src/components/core/index.d.ts +3 -0
  82. package/lib/typescript/src/components/core/index.d.ts.map +1 -0
  83. package/lib/typescript/src/components/index.d.ts +6 -0
  84. package/lib/typescript/src/components/index.d.ts.map +1 -0
  85. package/lib/typescript/src/components/overlays/BufferingOverlay.d.ts +2 -0
  86. package/lib/typescript/src/components/overlays/BufferingOverlay.d.ts.map +1 -0
  87. package/lib/typescript/src/components/overlays/DoubleTapSeek.d.ts +5 -0
  88. package/lib/typescript/src/components/overlays/DoubleTapSeek.d.ts.map +1 -0
  89. package/lib/typescript/src/components/overlays/ErrorOverlay.d.ts +6 -0
  90. package/lib/typescript/src/components/overlays/ErrorOverlay.d.ts.map +1 -0
  91. package/lib/typescript/src/components/overlays/GestureIndicator.d.ts +9 -0
  92. package/lib/typescript/src/components/overlays/GestureIndicator.d.ts.map +1 -0
  93. package/lib/typescript/src/components/overlays/LoadingPoster.d.ts +6 -0
  94. package/lib/typescript/src/components/overlays/LoadingPoster.d.ts.map +1 -0
  95. package/lib/typescript/src/hooks/index.d.ts +4 -0
  96. package/lib/typescript/src/hooks/index.d.ts.map +1 -0
  97. package/lib/typescript/src/hooks/useVideoBrightness.d.ts +5 -0
  98. package/lib/typescript/src/hooks/useVideoBrightness.d.ts.map +1 -0
  99. package/lib/typescript/src/hooks/useVideoControls.d.ts +11 -0
  100. package/lib/typescript/src/hooks/useVideoControls.d.ts.map +1 -0
  101. package/lib/typescript/src/hooks/useVideoOrientation.d.ts +6 -0
  102. package/lib/typescript/src/hooks/useVideoOrientation.d.ts.map +1 -0
  103. package/lib/typescript/src/hooks/useVideoPlayer.d.ts +7 -0
  104. package/lib/typescript/src/hooks/useVideoPlayer.d.ts.map +1 -0
  105. package/lib/typescript/src/hooks/useVideoVolume.d.ts +6 -0
  106. package/lib/typescript/src/hooks/useVideoVolume.d.ts.map +1 -0
  107. package/lib/typescript/src/index.d.ts +6 -0
  108. package/lib/typescript/src/index.d.ts.map +1 -0
  109. package/lib/typescript/src/types/index.d.ts +96 -0
  110. package/lib/typescript/src/types/index.d.ts.map +1 -0
  111. package/lib/typescript/src/utils/clamp.d.ts +2 -0
  112. package/lib/typescript/src/utils/clamp.d.ts.map +1 -0
  113. package/lib/typescript/src/utils/formatTime.d.ts +2 -0
  114. package/lib/typescript/src/utils/formatTime.d.ts.map +1 -0
  115. package/lib/typescript/src/utils/index.d.ts +3 -0
  116. package/lib/typescript/src/utils/index.d.ts.map +1 -0
  117. package/package.json +191 -0
  118. package/src/components/VideoKit.tsx +415 -0
  119. package/src/components/controls/FullscreenButton.tsx +29 -0
  120. package/src/components/controls/Icon.tsx +71 -0
  121. package/src/components/controls/PlayPauseButton.tsx +25 -0
  122. package/src/components/controls/Scrubber.tsx +157 -0
  123. package/src/components/controls/SpeedButton.tsx +86 -0
  124. package/src/components/controls/TimeDisplay.tsx +21 -0
  125. package/src/components/controls/VolumeButton.tsx +23 -0
  126. package/src/components/core/VideoPlayer.tsx +148 -0
  127. package/src/components/core/VideoPlayerContext.tsx +133 -0
  128. package/src/components/core/index.ts +5 -0
  129. package/src/components/index.ts +25 -0
  130. package/src/components/overlays/BufferingOverlay.tsx +21 -0
  131. package/src/components/overlays/DoubleTapSeek.tsx +91 -0
  132. package/src/components/overlays/ErrorOverlay.tsx +49 -0
  133. package/src/components/overlays/GestureIndicator.tsx +114 -0
  134. package/src/components/overlays/LoadingPoster.tsx +21 -0
  135. package/src/hooks/index.ts +3 -0
  136. package/src/hooks/useVideoBrightness.ts +34 -0
  137. package/src/hooks/useVideoControls.ts +65 -0
  138. package/src/hooks/useVideoOrientation.ts +22 -0
  139. package/src/hooks/useVideoPlayer.ts +69 -0
  140. package/src/hooks/useVideoVolume.ts +36 -0
  141. package/src/index.ts +15 -0
  142. package/src/types/index.ts +137 -0
  143. package/src/utils/clamp.ts +4 -0
  144. package/src/utils/formatTime.ts +9 -0
  145. package/src/utils/index.ts +2 -0
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+
3
+ import React from 'react';
4
+ import Svg, { Path, Polygon, Rect } from 'react-native-svg';
5
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
+ const PATHS = {
7
+ 'play': /*#__PURE__*/_jsx(Svg, {
8
+ viewBox: "0 0 24 24",
9
+ children: /*#__PURE__*/_jsx(Polygon, {
10
+ points: "5,3 19,12 5,21",
11
+ fill: "currentColor"
12
+ })
13
+ }),
14
+ 'pause': /*#__PURE__*/_jsxs(Svg, {
15
+ viewBox: "0 0 24 24",
16
+ children: [/*#__PURE__*/_jsx(Rect, {
17
+ x: "6",
18
+ y: "4",
19
+ width: "4",
20
+ height: "16",
21
+ fill: "currentColor"
22
+ }), /*#__PURE__*/_jsx(Rect, {
23
+ x: "14",
24
+ y: "4",
25
+ width: "4",
26
+ height: "16",
27
+ fill: "currentColor"
28
+ })]
29
+ }),
30
+ 'volume': /*#__PURE__*/_jsx(Svg, {
31
+ viewBox: "0 0 24 24",
32
+ children: /*#__PURE__*/_jsx(Path, {
33
+ d: "M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02z",
34
+ fill: "currentColor"
35
+ })
36
+ }),
37
+ 'mute': /*#__PURE__*/_jsx(Svg, {
38
+ viewBox: "0 0 24 24",
39
+ children: /*#__PURE__*/_jsx(Path, {
40
+ d: "M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z",
41
+ fill: "currentColor"
42
+ })
43
+ }),
44
+ 'fullscreen': /*#__PURE__*/_jsx(Svg, {
45
+ viewBox: "0 0 24 24",
46
+ children: /*#__PURE__*/_jsx(Path, {
47
+ d: "M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z",
48
+ fill: "currentColor"
49
+ })
50
+ }),
51
+ 'fullscreen-exit': /*#__PURE__*/_jsx(Svg, {
52
+ viewBox: "0 0 24 24",
53
+ children: /*#__PURE__*/_jsx(Path, {
54
+ d: "M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z",
55
+ fill: "currentColor"
56
+ })
57
+ })
58
+ };
59
+ export function Icon({
60
+ name,
61
+ size = 24,
62
+ color = '#fff'
63
+ }) {
64
+ const element = PATHS[name];
65
+ return /*#__PURE__*/React.cloneElement(element, {
66
+ width: size,
67
+ height: size,
68
+ color
69
+ });
70
+ }
71
+ //# sourceMappingURL=Icon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["React","Svg","Path","Polygon","Rect","jsx","_jsx","jsxs","_jsxs","PATHS","viewBox","children","points","fill","x","y","width","height","d","Icon","name","size","color","element","cloneElement"],"sourceRoot":"../../../../src","sources":["components/controls/Icon.tsx"],"mappings":";;AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,OAAOC,GAAG,IAAIC,IAAI,EAAEC,OAAO,EAAEC,IAAI,QAAQ,kBAAkB;AAAC,SAAAC,GAAA,IAAAC,IAAA,EAAAC,IAAA,IAAAC,KAAA;AAgB5D,MAAMC,KAA2C,GAAG;EAClD,MAAM,eACJH,IAAA,CAACL,GAAG;IAACS,OAAO,EAAC,WAAW;IAAAC,QAAA,eACtBL,IAAA,CAACH,OAAO;MAACS,MAAM,EAAC,gBAAgB;MAACC,IAAI,EAAC;IAAc,CAAE;EAAC,CACpD,CACN;EACD,OAAO,eACLL,KAAA,CAACP,GAAG;IAACS,OAAO,EAAC,WAAW;IAAAC,QAAA,gBACtBL,IAAA,CAACF,IAAI;MAACU,CAAC,EAAC,GAAG;MAACC,CAAC,EAAC,GAAG;MAACC,KAAK,EAAC,GAAG;MAACC,MAAM,EAAC,IAAI;MAACJ,IAAI,EAAC;IAAc,CAAE,CAAC,eAC9DP,IAAA,CAACF,IAAI;MAACU,CAAC,EAAC,IAAI;MAACC,CAAC,EAAC,GAAG;MAACC,KAAK,EAAC,GAAG;MAACC,MAAM,EAAC,IAAI;MAACJ,IAAI,EAAC;IAAc,CAAE,CAAC;EAAA,CAC5D,CACN;EACD,QAAQ,eACNP,IAAA,CAACL,GAAG;IAACS,OAAO,EAAC,WAAW;IAAAC,QAAA,eACtBL,IAAA,CAACJ,IAAI;MACHgB,CAAC,EAAC,yFAAyF;MAC3FL,IAAI,EAAC;IAAc,CACpB;EAAC,CACC,CACN;EACD,MAAM,eACJP,IAAA,CAACL,GAAG;IAACS,OAAO,EAAC,WAAW;IAAAC,QAAA,eACtBL,IAAA,CAACJ,IAAI;MACHgB,CAAC,EAAC,iWAAiW;MACnWL,IAAI,EAAC;IAAc,CACpB;EAAC,CACC,CACN;EACD,YAAY,eACVP,IAAA,CAACL,GAAG;IAACS,OAAO,EAAC,WAAW;IAAAC,QAAA,eACtBL,IAAA,CAACJ,IAAI;MACHgB,CAAC,EAAC,gFAAgF;MAClFL,IAAI,EAAC;IAAc,CACpB;EAAC,CACC,CACN;EACD,iBAAiB,eACfP,IAAA,CAACL,GAAG;IAACS,OAAO,EAAC,WAAW;IAAAC,QAAA,eACtBL,IAAA,CAACJ,IAAI;MACHgB,CAAC,EAAC,+EAA+E;MACjFL,IAAI,EAAC;IAAc,CACpB;EAAC,CACC;AAET,CAAC;AAED,OAAO,SAASM,IAAIA,CAAC;EAAEC,IAAI;EAAEC,IAAI,GAAG,EAAE;EAAEC,KAAK,GAAG;AAAc,CAAC,EAAE;EAC/D,MAAMC,OAAO,GAAGd,KAAK,CAACW,IAAI,CAAC;EAC3B,oBAAOpB,KAAK,CAACwB,YAAY,CAACD,OAAO,EAAE;IACjCP,KAAK,EAAEK,IAAI;IACXJ,MAAM,EAAEI,IAAI;IACZC;EACF,CAAQ,CAAC;AACX","ignoreList":[]}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+
3
+ import { StyleSheet, TouchableOpacity } from 'react-native';
4
+ import { Icon } from "./Icon.js";
5
+ import { useVideoStore } from "../core/VideoPlayerContext.js";
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ export function PlayPauseButton() {
8
+ const status = useVideoStore(s => s.status);
9
+ const setStatus = useVideoStore(s => s.setStatus);
10
+ const isPlaying = status === 'playing';
11
+ const toggle = () => {
12
+ setStatus(isPlaying ? 'paused' : 'playing');
13
+ };
14
+ return /*#__PURE__*/_jsx(TouchableOpacity, {
15
+ onPress: toggle,
16
+ style: styles.btn,
17
+ hitSlop: 12,
18
+ children: /*#__PURE__*/_jsx(Icon, {
19
+ name: isPlaying ? 'pause' : 'play',
20
+ size: 22
21
+ })
22
+ });
23
+ }
24
+ const styles = StyleSheet.create({
25
+ btn: {
26
+ padding: 4
27
+ },
28
+ icon: {
29
+ fontSize: 20,
30
+ color: '#fff'
31
+ }
32
+ });
33
+ //# sourceMappingURL=PlayPauseButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["StyleSheet","TouchableOpacity","Icon","useVideoStore","jsx","_jsx","PlayPauseButton","status","s","setStatus","isPlaying","toggle","onPress","style","styles","btn","hitSlop","children","name","size","create","padding","icon","fontSize","color"],"sourceRoot":"../../../../src","sources":["components/controls/PlayPauseButton.tsx"],"mappings":";;AAAA,SAASA,UAAU,EAAEC,gBAAgB,QAAQ,cAAc;AAC3D,SAASC,IAAI,QAAQ,WAAQ;AAC7B,SAASC,aAAa,QAAQ,+BAA4B;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAE3D,OAAO,SAASC,eAAeA,CAAA,EAAG;EAChC,MAAMC,MAAM,GAAGJ,aAAa,CAAEK,CAAC,IAAKA,CAAC,CAACD,MAAM,CAAC;EAC7C,MAAME,SAAS,GAAGN,aAAa,CAAEK,CAAC,IAAKA,CAAC,CAACC,SAAS,CAAC;EAEnD,MAAMC,SAAS,GAAGH,MAAM,KAAK,SAAS;EAEtC,MAAMI,MAAM,GAAGA,CAAA,KAAM;IACnBF,SAAS,CAACC,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;EAC7C,CAAC;EAED,oBACEL,IAAA,CAACJ,gBAAgB;IAACW,OAAO,EAAED,MAAO;IAACE,KAAK,EAAEC,MAAM,CAACC,GAAI;IAACC,OAAO,EAAE,EAAG;IAAAC,QAAA,eAChEZ,IAAA,CAACH,IAAI;MAACgB,IAAI,EAAER,SAAS,GAAG,OAAO,GAAG,MAAO;MAACS,IAAI,EAAE;IAAG,CAAE;EAAC,CACtC,CAAC;AAEvB;AAEA,MAAML,MAAM,GAAGd,UAAU,CAACoB,MAAM,CAAC;EAC/BL,GAAG,EAAE;IAAEM,OAAO,EAAE;EAAE,CAAC;EACnBC,IAAI,EAAE;IAAEC,QAAQ,EAAE,EAAE;IAAEC,KAAK,EAAE;EAAO;AACtC,CAAC,CAAC","ignoreList":[]}
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+
3
+ import { useCallback, useEffect, useRef } from 'react';
4
+ import { StyleSheet, View } from 'react-native';
5
+ import { Gesture, GestureDetector } from 'react-native-gesture-handler';
6
+ import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
7
+ import { useVideoPlayerContext, useVideoStore
8
+ // useVideoTheme,
9
+ } from "../core/VideoPlayerContext.js";
10
+ import { clamp } from "../../utils/clamp.js";
11
+ import { scheduleOnRN } from 'react-native-worklets';
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ export function Scrubber({
14
+ onScrubStart,
15
+ onScrubEnd
16
+ }) {
17
+ const {
18
+ videoRef
19
+ } = useVideoPlayerContext();
20
+ const currentTime = useVideoStore(s => s.currentTime);
21
+ const duration = useVideoStore(s => s.duration);
22
+ const buffered = useVideoStore(s => s.buffered);
23
+ const {
24
+ duration: d,
25
+ status,
26
+ setStatus
27
+ } = useVideoStore(s => s);
28
+ // const { accentColor = '#fff', trackHeight = 3 } = useVideoTheme();
29
+
30
+ // Shared values for Reanimated
31
+ const trackWidth = useSharedValue(1);
32
+ const thumbX = useSharedValue(0);
33
+ const isDragging = useSharedValue(false);
34
+ const isDraggingRef = useRef(false);
35
+ const dragStartX = useSharedValue(0);
36
+ const dragStartThumb = useSharedValue(0);
37
+
38
+ // Sync playback progress → thumb position (when not dragging)
39
+ useEffect(() => {
40
+ if (!isDraggingRef.current && duration > 0) {
41
+ thumbX.value = withTiming(currentTime / duration * trackWidth.value, {
42
+ duration: 200
43
+ });
44
+ }
45
+ }, [currentTime, duration, thumbX, trackWidth]);
46
+ const handleScrubStart = useCallback(() => {
47
+ isDraggingRef.current = true;
48
+ onScrubStart?.();
49
+ }, [onScrubStart]);
50
+ const handleScrubEnd = useCallback(x => {
51
+ if (d > 0) {
52
+ const seekTime = clamp(x / trackWidth.value * d, 0, d);
53
+ videoRef?.current?.seek(seekTime);
54
+ if (status === 'playing') {
55
+ setTimeout(() => setStatus('playing'), 150);
56
+ }
57
+ }
58
+ isDraggingRef.current = false;
59
+ onScrubEnd?.();
60
+ }, [videoRef, trackWidth, onScrubEnd, setStatus, d, status]);
61
+ const panGesture = Gesture.Pan().minDistance(0).onStart(e => {
62
+ 'worklet';
63
+
64
+ isDragging.value = true;
65
+ dragStartX.value = e.x;
66
+ dragStartThumb.value = thumbX.value;
67
+ scheduleOnRN(handleScrubStart);
68
+ }).onUpdate(e => {
69
+ 'worklet';
70
+
71
+ const delta = e.x - dragStartX.value;
72
+ thumbX.value = clamp(dragStartThumb.value + delta, 0, trackWidth.value);
73
+ }).onEnd(() => {
74
+ 'worklet';
75
+
76
+ isDragging.value = false;
77
+ scheduleOnRN(handleScrubEnd, thumbX.value);
78
+ });
79
+ const fillStyle = useAnimatedStyle(() => ({
80
+ width: thumbX.value
81
+ }));
82
+ const thumbStyle = useAnimatedStyle(() => ({
83
+ transform: [{
84
+ translateX: thumbX.value
85
+ }]
86
+ }));
87
+ const bufferedWidth = duration > 0 ? clamp(buffered / duration * 100, 0, 100) : 0;
88
+ return /*#__PURE__*/_jsx(GestureDetector, {
89
+ gesture: panGesture,
90
+ children: /*#__PURE__*/_jsx(View, {
91
+ style: styles.trackHitArea,
92
+ onLayout: e => {
93
+ trackWidth.value = e.nativeEvent.layout.width;
94
+ },
95
+ children: /*#__PURE__*/_jsxs(View, {
96
+ style: styles.track,
97
+ children: [/*#__PURE__*/_jsx(View, {
98
+ style: [styles.bufferedFill, {
99
+ width: `${bufferedWidth}%`
100
+ }]
101
+ }), /*#__PURE__*/_jsx(Animated.View, {
102
+ style: [styles.playedFill, fillStyle]
103
+ }), /*#__PURE__*/_jsx(Animated.View, {
104
+ style: [styles.thumb, thumbStyle]
105
+ })]
106
+ })
107
+ })
108
+ });
109
+ }
110
+ const TRACK_HEIGHT = 3;
111
+ const THUMB_SIZE = 14;
112
+ const styles = StyleSheet.create({
113
+ trackHitArea: {
114
+ height: 28,
115
+ justifyContent: 'center',
116
+ paddingHorizontal: THUMB_SIZE / 2
117
+ },
118
+ track: {
119
+ height: TRACK_HEIGHT,
120
+ backgroundColor: 'rgba(255,255,255,0.3)',
121
+ borderRadius: TRACK_HEIGHT / 2,
122
+ overflow: 'visible'
123
+ },
124
+ bufferedFill: {
125
+ position: 'absolute',
126
+ height: TRACK_HEIGHT,
127
+ backgroundColor: 'rgba(255,255,255,0.4)',
128
+ borderRadius: TRACK_HEIGHT / 2
129
+ },
130
+ playedFill: {
131
+ position: 'absolute',
132
+ height: TRACK_HEIGHT,
133
+ backgroundColor: '#fff',
134
+ borderRadius: TRACK_HEIGHT / 2
135
+ },
136
+ thumb: {
137
+ position: 'absolute',
138
+ top: -(THUMB_SIZE / 2 - TRACK_HEIGHT / 2),
139
+ left: -THUMB_SIZE / 2,
140
+ width: THUMB_SIZE,
141
+ height: THUMB_SIZE,
142
+ borderRadius: THUMB_SIZE / 2,
143
+ backgroundColor: '#fff'
144
+ }
145
+ });
146
+ //# sourceMappingURL=Scrubber.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useCallback","useEffect","useRef","StyleSheet","View","Gesture","GestureDetector","Animated","useAnimatedStyle","useSharedValue","withTiming","useVideoPlayerContext","useVideoStore","clamp","scheduleOnRN","jsx","_jsx","jsxs","_jsxs","Scrubber","onScrubStart","onScrubEnd","videoRef","currentTime","s","duration","buffered","d","status","setStatus","trackWidth","thumbX","isDragging","isDraggingRef","dragStartX","dragStartThumb","current","value","handleScrubStart","handleScrubEnd","x","seekTime","seek","setTimeout","panGesture","Pan","minDistance","onStart","e","onUpdate","delta","onEnd","fillStyle","width","thumbStyle","transform","translateX","bufferedWidth","gesture","children","style","styles","trackHitArea","onLayout","nativeEvent","layout","track","bufferedFill","playedFill","thumb","TRACK_HEIGHT","THUMB_SIZE","create","height","justifyContent","paddingHorizontal","backgroundColor","borderRadius","overflow","position","top","left"],"sourceRoot":"../../../../src","sources":["components/controls/Scrubber.tsx"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+
3
+ import { useState } from 'react';
4
+ import { Modal, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
5
+ import { useVideoStore } from "../core/VideoPlayerContext.js";
6
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
7
+ const SPEEDS = [0.5, 0.75, 1, 1.25, 1.5, 2];
8
+ export function SpeedButton() {
9
+ const speed = useVideoStore(s => s.speed);
10
+ const {
11
+ setSpeed
12
+ } = useVideoStore(s => s);
13
+ const [open, setOpen] = useState(false);
14
+ return /*#__PURE__*/_jsxs(_Fragment, {
15
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
16
+ onPress: () => setOpen(true),
17
+ style: styles.btn,
18
+ hitSlop: 12,
19
+ children: /*#__PURE__*/_jsx(Text, {
20
+ style: styles.label,
21
+ children: speed === 1 ? '1×' : `${speed}×`
22
+ })
23
+ }), /*#__PURE__*/_jsx(Modal, {
24
+ transparent: true,
25
+ visible: open,
26
+ onRequestClose: () => setOpen(false),
27
+ children: /*#__PURE__*/_jsx(TouchableOpacity, {
28
+ style: styles.backdrop,
29
+ activeOpacity: 1,
30
+ onPress: () => setOpen(false),
31
+ children: /*#__PURE__*/_jsxs(View, {
32
+ style: styles.sheet,
33
+ children: [/*#__PURE__*/_jsx(Text, {
34
+ style: styles.title,
35
+ children: "Playback Speed"
36
+ }), SPEEDS.map(s => /*#__PURE__*/_jsx(TouchableOpacity, {
37
+ style: [styles.option, speed === s && styles.optionActive],
38
+ onPress: () => {
39
+ setSpeed(s);
40
+ setOpen(false);
41
+ },
42
+ children: /*#__PURE__*/_jsx(Text, {
43
+ style: [styles.optionText, speed === s && styles.optionTextActive],
44
+ children: s === 1 ? 'Normal' : `${s}×`
45
+ })
46
+ }, s))]
47
+ })
48
+ })
49
+ })]
50
+ });
51
+ }
52
+ const styles = StyleSheet.create({
53
+ btn: {
54
+ padding: 4
55
+ },
56
+ label: {
57
+ color: '#fff',
58
+ fontSize: 12,
59
+ fontWeight: '700'
60
+ },
61
+ backdrop: {
62
+ flex: 1,
63
+ backgroundColor: 'rgba(0,0,0,0.5)',
64
+ justifyContent: 'flex-end'
65
+ },
66
+ sheet: {
67
+ backgroundColor: '#1a1a1a',
68
+ borderTopLeftRadius: 16,
69
+ borderTopRightRadius: 16,
70
+ padding: 20,
71
+ paddingBottom: 36,
72
+ gap: 4
73
+ },
74
+ title: {
75
+ color: '#aaa',
76
+ fontSize: 13,
77
+ fontWeight: '600',
78
+ marginBottom: 8
79
+ },
80
+ option: {
81
+ paddingVertical: 12,
82
+ paddingHorizontal: 16,
83
+ borderRadius: 8
84
+ },
85
+ optionActive: {
86
+ backgroundColor: 'rgba(255,255,255,0.1)'
87
+ },
88
+ optionText: {
89
+ color: '#fff',
90
+ fontSize: 15
91
+ },
92
+ optionTextActive: {
93
+ fontWeight: '700'
94
+ }
95
+ });
96
+ //# sourceMappingURL=SpeedButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useState","Modal","StyleSheet","Text","TouchableOpacity","View","useVideoStore","jsx","_jsx","jsxs","_jsxs","Fragment","_Fragment","SPEEDS","SpeedButton","speed","s","setSpeed","open","setOpen","children","onPress","style","styles","btn","hitSlop","label","transparent","visible","onRequestClose","backdrop","activeOpacity","sheet","title","map","option","optionActive","optionText","optionTextActive","create","padding","color","fontSize","fontWeight","flex","backgroundColor","justifyContent","borderTopLeftRadius","borderTopRightRadius","paddingBottom","gap","marginBottom","paddingVertical","paddingHorizontal","borderRadius"],"sourceRoot":"../../../../src","sources":["components/controls/SpeedButton.tsx"],"mappings":";;AAAA,SAASA,QAAQ,QAAQ,OAAO;AAChC,SAASC,KAAK,EAAEC,UAAU,EAAEC,IAAI,EAAEC,gBAAgB,EAAEC,IAAI,QAAQ,cAAc;AAC9E,SAASC,aAAa,QAAQ,+BAA4B;AAAC,SAAAC,GAAA,IAAAC,IAAA,EAAAC,IAAA,IAAAC,KAAA,EAAAC,QAAA,IAAAC,SAAA;AAE3D,MAAMC,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;AAE3C,OAAO,SAASC,WAAWA,CAAA,EAAG;EAC5B,MAAMC,KAAK,GAAGT,aAAa,CAAEU,CAAC,IAAKA,CAAC,CAACD,KAAK,CAAC;EAC3C,MAAM;IAAEE;EAAS,CAAC,GAAGX,aAAa,CAAEU,CAAC,IAAKA,CAAC,CAAC;EAC5C,MAAM,CAACE,IAAI,EAAEC,OAAO,CAAC,GAAGnB,QAAQ,CAAC,KAAK,CAAC;EAEvC,oBACEU,KAAA,CAAAE,SAAA;IAAAQ,QAAA,gBACEZ,IAAA,CAACJ,gBAAgB;MACfiB,OAAO,EAAEA,CAAA,KAAMF,OAAO,CAAC,IAAI,CAAE;MAC7BG,KAAK,EAAEC,MAAM,CAACC,GAAI;MAClBC,OAAO,EAAE,EAAG;MAAAL,QAAA,eAEZZ,IAAA,CAACL,IAAI;QAACmB,KAAK,EAAEC,MAAM,CAACG,KAAM;QAAAN,QAAA,EAAEL,KAAK,KAAK,CAAC,GAAG,IAAI,GAAG,GAAGA,KAAK;MAAG,CAAO;IAAC,CACpD,CAAC,eAEnBP,IAAA,CAACP,KAAK;MAAC0B,WAAW;MAACC,OAAO,EAAEV,IAAK;MAACW,cAAc,EAAEA,CAAA,KAAMV,OAAO,CAAC,KAAK,CAAE;MAAAC,QAAA,eACrEZ,IAAA,CAACJ,gBAAgB;QACfkB,KAAK,EAAEC,MAAM,CAACO,QAAS;QACvBC,aAAa,EAAE,CAAE;QACjBV,OAAO,EAAEA,CAAA,KAAMF,OAAO,CAAC,KAAK,CAAE;QAAAC,QAAA,eAE9BV,KAAA,CAACL,IAAI;UAACiB,KAAK,EAAEC,MAAM,CAACS,KAAM;UAAAZ,QAAA,gBACxBZ,IAAA,CAACL,IAAI;YAACmB,KAAK,EAAEC,MAAM,CAACU,KAAM;YAAAb,QAAA,EAAC;UAAc,CAAM,CAAC,EAC/CP,MAAM,CAACqB,GAAG,CAAElB,CAAC,iBACZR,IAAA,CAACJ,gBAAgB;YAEfkB,KAAK,EAAE,CAACC,MAAM,CAACY,MAAM,EAAEpB,KAAK,KAAKC,CAAC,IAAIO,MAAM,CAACa,YAAY,CAAE;YAC3Df,OAAO,EAAEA,CAAA,KAAM;cACbJ,QAAQ,CAACD,CAAC,CAAC;cACXG,OAAO,CAAC,KAAK,CAAC;YAChB,CAAE;YAAAC,QAAA,eAEFZ,IAAA,CAACL,IAAI;cACHmB,KAAK,EAAE,CACLC,MAAM,CAACc,UAAU,EACjBtB,KAAK,KAAKC,CAAC,IAAIO,MAAM,CAACe,gBAAgB,CACtC;cAAAlB,QAAA,EAEDJ,CAAC,KAAK,CAAC,GAAG,QAAQ,GAAG,GAAGA,CAAC;YAAG,CACzB;UAAC,GAdFA,CAeW,CACnB,CAAC;QAAA,CACE;MAAC,CACS;IAAC,CACd,CAAC;EAAA,CACR,CAAC;AAEP;AAEA,MAAMO,MAAM,GAAGrB,UAAU,CAACqC,MAAM,CAAC;EAC/Bf,GAAG,EAAE;IAAEgB,OAAO,EAAE;EAAE,CAAC;EACnBd,KAAK,EAAE;IAAEe,KAAK,EAAE,MAAM;IAAEC,QAAQ,EAAE,EAAE;IAAEC,UAAU,EAAE;EAAM,CAAC;EACzDb,QAAQ,EAAE;IACRc,IAAI,EAAE,CAAC;IACPC,eAAe,EAAE,iBAAiB;IAClCC,cAAc,EAAE;EAClB,CAAC;EACDd,KAAK,EAAE;IACLa,eAAe,EAAE,SAAS;IAC1BE,mBAAmB,EAAE,EAAE;IACvBC,oBAAoB,EAAE,EAAE;IACxBR,OAAO,EAAE,EAAE;IACXS,aAAa,EAAE,EAAE;IACjBC,GAAG,EAAE;EACP,CAAC;EACDjB,KAAK,EAAE;IACLQ,KAAK,EAAE,MAAM;IACbC,QAAQ,EAAE,EAAE;IACZC,UAAU,EAAE,KAAK;IACjBQ,YAAY,EAAE;EAChB,CAAC;EACDhB,MAAM,EAAE;IACNiB,eAAe,EAAE,EAAE;IACnBC,iBAAiB,EAAE,EAAE;IACrBC,YAAY,EAAE;EAChB,CAAC;EACDlB,YAAY,EAAE;IAAES,eAAe,EAAE;EAAwB,CAAC;EAC1DR,UAAU,EAAE;IAAEI,KAAK,EAAE,MAAM;IAAEC,QAAQ,EAAE;EAAG,CAAC;EAC3CJ,gBAAgB,EAAE;IAAEK,UAAU,EAAE;EAAM;AACxC,CAAC,CAAC","ignoreList":[]}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+
3
+ import { StyleSheet, Text } from 'react-native';
4
+ import { useVideoStore } from "../core/VideoPlayerContext.js";
5
+ import { formatTime } from "../../utils/formatTime.js";
6
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
+ export function TimeDisplay() {
8
+ const currentTime = useVideoStore(s => s.currentTime);
9
+ const duration = useVideoStore(s => s.duration);
10
+ return /*#__PURE__*/_jsxs(Text, {
11
+ style: styles.text,
12
+ children: [formatTime(currentTime), /*#__PURE__*/_jsx(Text, {
13
+ style: styles.separator,
14
+ children: " / "
15
+ }), formatTime(duration)]
16
+ });
17
+ }
18
+ const styles = StyleSheet.create({
19
+ text: {
20
+ color: '#fff',
21
+ fontSize: 12,
22
+ fontWeight: '500'
23
+ },
24
+ separator: {
25
+ color: 'rgba(255,255,255,0.5)'
26
+ }
27
+ });
28
+ //# sourceMappingURL=TimeDisplay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["StyleSheet","Text","useVideoStore","formatTime","jsx","_jsx","jsxs","_jsxs","TimeDisplay","currentTime","s","duration","style","styles","text","children","separator","create","color","fontSize","fontWeight"],"sourceRoot":"../../../../src","sources":["components/controls/TimeDisplay.tsx"],"mappings":";;AAAA,SAASA,UAAU,EAAEC,IAAI,QAAQ,cAAc;AAC/C,SAASC,aAAa,QAAQ,+BAA4B;AAC1D,SAASC,UAAU,QAAQ,2BAAwB;AAAC,SAAAC,GAAA,IAAAC,IAAA,EAAAC,IAAA,IAAAC,KAAA;AAEpD,OAAO,SAASC,WAAWA,CAAA,EAAG;EAC5B,MAAMC,WAAW,GAAGP,aAAa,CAAEQ,CAAC,IAAKA,CAAC,CAACD,WAAW,CAAC;EACvD,MAAME,QAAQ,GAAGT,aAAa,CAAEQ,CAAC,IAAKA,CAAC,CAACC,QAAQ,CAAC;EAEjD,oBACEJ,KAAA,CAACN,IAAI;IAACW,KAAK,EAAEC,MAAM,CAACC,IAAK;IAAAC,QAAA,GACtBZ,UAAU,CAACM,WAAW,CAAC,eACxBJ,IAAA,CAACJ,IAAI;MAACW,KAAK,EAAEC,MAAM,CAACG,SAAU;MAAAD,QAAA,EAAC;IAAG,CAAM,CAAC,EACxCZ,UAAU,CAACQ,QAAQ,CAAC;EAAA,CACjB,CAAC;AAEX;AAEA,MAAME,MAAM,GAAGb,UAAU,CAACiB,MAAM,CAAC;EAC/BH,IAAI,EAAE;IAAEI,KAAK,EAAE,MAAM;IAAEC,QAAQ,EAAE,EAAE;IAAEC,UAAU,EAAE;EAAM,CAAC;EACxDJ,SAAS,EAAE;IAAEE,KAAK,EAAE;EAAwB;AAC9C,CAAC,CAAC","ignoreList":[]}
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+
3
+ import { StyleSheet, TouchableOpacity } from 'react-native';
4
+ import { useVideoStore } from "../core/VideoPlayerContext.js";
5
+ import { Icon } from "./Icon.js";
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ export function VolumeButton() {
8
+ const muted = useVideoStore(s => s.muted);
9
+ const {
10
+ setMuted
11
+ } = useVideoStore(s => s);
12
+ return /*#__PURE__*/_jsx(TouchableOpacity, {
13
+ onPress: () => setMuted(!muted),
14
+ style: styles.btn,
15
+ hitSlop: 12,
16
+ children: /*#__PURE__*/_jsx(Icon, {
17
+ size: 22,
18
+ name: muted ? 'mute' : 'volume'
19
+ })
20
+ });
21
+ }
22
+ const styles = StyleSheet.create({
23
+ btn: {
24
+ padding: 4
25
+ },
26
+ icon: {
27
+ fontSize: 18,
28
+ color: '#fff'
29
+ }
30
+ });
31
+ //# sourceMappingURL=VolumeButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["StyleSheet","TouchableOpacity","useVideoStore","Icon","jsx","_jsx","VolumeButton","muted","s","setMuted","onPress","style","styles","btn","hitSlop","children","size","name","create","padding","icon","fontSize","color"],"sourceRoot":"../../../../src","sources":["components/controls/VolumeButton.tsx"],"mappings":";;AAAA,SAASA,UAAU,EAAEC,gBAAgB,QAAQ,cAAc;AAC3D,SAASC,aAAa,QAAQ,+BAA4B;AAC1D,SAASC,IAAI,QAAQ,WAAQ;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAE9B,OAAO,SAASC,YAAYA,CAAA,EAAG;EAC7B,MAAMC,KAAK,GAAGL,aAAa,CAAEM,CAAC,IAAKA,CAAC,CAACD,KAAK,CAAC;EAC3C,MAAM;IAAEE;EAAS,CAAC,GAAGP,aAAa,CAAEM,CAAC,IAAKA,CAAC,CAAC;EAE5C,oBACEH,IAAA,CAACJ,gBAAgB;IACfS,OAAO,EAAEA,CAAA,KAAMD,QAAQ,CAAC,CAACF,KAAK,CAAE;IAChCI,KAAK,EAAEC,MAAM,CAACC,GAAI;IAClBC,OAAO,EAAE,EAAG;IAAAC,QAAA,eAEZV,IAAA,CAACF,IAAI;MAACa,IAAI,EAAE,EAAG;MAACC,IAAI,EAAEV,KAAK,GAAG,MAAM,GAAG;IAAS,CAAE;EAAC,CACnC,CAAC;AAEvB;AAEA,MAAMK,MAAM,GAAGZ,UAAU,CAACkB,MAAM,CAAC;EAC/BL,GAAG,EAAE;IAAEM,OAAO,EAAE;EAAE,CAAC;EACnBC,IAAI,EAAE;IAAEC,QAAQ,EAAE,EAAE;IAAEC,KAAK,EAAE;EAAO;AACtC,CAAC,CAAC","ignoreList":[]}
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+
3
+ import React, { useCallback, useRef } from 'react';
4
+ import { StyleSheet } from 'react-native';
5
+ import Video from 'react-native-video';
6
+ import { useVideoPlayerContext, useVideoStore } from "./VideoPlayerContext.js";
7
+ import { jsx as _jsx } from "react/jsx-runtime";
8
+ export function VideoPlayer({
9
+ source,
10
+ autoPlay,
11
+ loop,
12
+ poster,
13
+ onProgress,
14
+ onEnd,
15
+ onError,
16
+ onBuffer
17
+ }) {
18
+ const {
19
+ videoRef
20
+ } = useVideoPlayerContext();
21
+ const {
22
+ setStatus,
23
+ setCurrentTime,
24
+ setDuration,
25
+ setBuffered,
26
+ setError,
27
+ status
28
+ } = useVideoStore(s => s); // state as reactive subscriptions
29
+ const muted = useVideoStore(s => s.muted);
30
+ const speed = useVideoStore(s => s.speed);
31
+ const isPaused = useVideoStore(s => s.status === 'paused' || s.status === 'idle' || s.status === 'error');
32
+ const handleLoad = useCallback(data => {
33
+ setDuration(data.duration);
34
+ setStatus(autoPlay ? 'playing' : 'paused');
35
+ }, [autoPlay, setDuration, setStatus]);
36
+ const handleProgress = useCallback(data => {
37
+ setCurrentTime(data.currentTime);
38
+ setBuffered(data.playableDuration);
39
+ onProgress?.({
40
+ currentTime: data.currentTime,
41
+ playableDuration: data.playableDuration,
42
+ seekableDuration: data.seekableDuration
43
+ });
44
+ }, [onProgress, setCurrentTime, setBuffered]);
45
+ const bufferTimerRef = useRef(undefined);
46
+ const handleBuffer = useCallback(({
47
+ isBuffering
48
+ }) => {
49
+ clearTimeout(bufferTimerRef.current);
50
+ if (isBuffering) {
51
+ setStatus('buffering');
52
+ onBuffer?.(true);
53
+ } else {
54
+ // debounce the recovery — ignore spurious false events
55
+ bufferTimerRef.current = setTimeout(() => {
56
+ setStatus('playing');
57
+ onBuffer?.(false);
58
+ }, 300);
59
+ }
60
+ }, [onBuffer, setStatus]);
61
+ const handleError = useCallback(e => {
62
+ const msg = e.error?.errorString ?? 'Playback error';
63
+ setError(msg);
64
+ setStatus('error');
65
+ onError?.(new Error(msg));
66
+ }, [onError, setError, setStatus]);
67
+ const handleEnd = useCallback(() => {
68
+ setStatus('paused');
69
+ onEnd?.();
70
+ }, [onEnd, setStatus]);
71
+ return /*#__PURE__*/_jsx(Video, {
72
+ ref: videoRef,
73
+ source: {
74
+ bufferConfig: {
75
+ minBufferMs: 2500,
76
+ maxBufferMs: 10000,
77
+ bufferForPlaybackMs: 1000,
78
+ bufferForPlaybackAfterRebufferMs: 2000
79
+ },
80
+ ...source
81
+ },
82
+ poster: poster,
83
+ paused: isPaused,
84
+ muted: muted,
85
+ rate: speed,
86
+ repeat: loop,
87
+ style: StyleSheet.absoluteFill,
88
+ resizeMode: "contain",
89
+ controls: false,
90
+ progressUpdateInterval: 250,
91
+ onLoad: handleLoad,
92
+ onProgress: handleProgress,
93
+ onBuffer: handleBuffer,
94
+ onError: handleError,
95
+ onEnd: handleEnd,
96
+ pointerEvents: "none",
97
+ onLoadStart: () => {
98
+ setStatus('loading');
99
+ },
100
+ onReadyForDisplay: () => {
101
+ // only auto-play if we haven't been manually paused
102
+ if (status === 'loading' || status === 'buffering') {
103
+ setStatus(autoPlay ? 'playing' : 'paused');
104
+ }
105
+ },
106
+ bufferConfig: {
107
+ minBufferMs: 2500,
108
+ maxBufferMs: 10000,
109
+ bufferForPlaybackMs: 1000,
110
+ bufferForPlaybackAfterRebufferMs: 2000
111
+ }
112
+ });
113
+ }
114
+ //# sourceMappingURL=VideoPlayer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["React","useCallback","useRef","StyleSheet","Video","useVideoPlayerContext","useVideoStore","jsx","_jsx","VideoPlayer","source","autoPlay","loop","poster","onProgress","onEnd","onError","onBuffer","videoRef","setStatus","setCurrentTime","setDuration","setBuffered","setError","status","s","muted","speed","isPaused","handleLoad","data","duration","handleProgress","currentTime","playableDuration","seekableDuration","bufferTimerRef","undefined","handleBuffer","isBuffering","clearTimeout","current","setTimeout","handleError","e","msg","error","errorString","Error","handleEnd","ref","bufferConfig","minBufferMs","maxBufferMs","bufferForPlaybackMs","bufferForPlaybackAfterRebufferMs","paused","rate","repeat","style","absoluteFill","resizeMode","controls","progressUpdateInterval","onLoad","pointerEvents","onLoadStart","onReadyForDisplay"],"sourceRoot":"../../../../src","sources":["components/core/VideoPlayer.tsx"],"mappings":"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","ignoreList":[]}