@therealtinhtute/baroiplayer 1.2.0 → 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (305) hide show
  1. package/README.md +91 -73
  2. package/dist/components/icons/index.d.ts +36 -0
  3. package/dist/components/icons/index.d.ts.map +1 -0
  4. package/dist/components/icons/svg-icons/ArrowLeftIcon.d.ts +4 -0
  5. package/dist/components/icons/svg-icons/ArrowLeftIcon.d.ts.map +1 -0
  6. package/dist/components/icons/svg-icons/ArrowRightIcon.d.ts +5 -0
  7. package/dist/components/icons/svg-icons/ArrowRightIcon.d.ts.map +1 -0
  8. package/dist/components/icons/svg-icons/AudioIcon.d.ts +5 -0
  9. package/dist/components/icons/svg-icons/AudioIcon.d.ts.map +1 -0
  10. package/dist/components/icons/svg-icons/BackwardIcon.d.ts +5 -0
  11. package/dist/components/icons/svg-icons/BackwardIcon.d.ts.map +1 -0
  12. package/dist/components/icons/svg-icons/CameraIcon.d.ts +5 -0
  13. package/dist/components/icons/svg-icons/CameraIcon.d.ts.map +1 -0
  14. package/dist/components/icons/svg-icons/CheckIcon.d.ts +5 -0
  15. package/dist/components/icons/svg-icons/CheckIcon.d.ts.map +1 -0
  16. package/dist/components/icons/svg-icons/EnablePiPIcon.d.ts +4 -0
  17. package/dist/components/icons/svg-icons/EnablePiPIcon.d.ts.map +1 -0
  18. package/dist/components/icons/svg-icons/ForwardIcon.d.ts +5 -0
  19. package/dist/components/icons/svg-icons/ForwardIcon.d.ts.map +1 -0
  20. package/dist/components/icons/svg-icons/FullscreenEnterIcon.d.ts +5 -0
  21. package/dist/components/icons/svg-icons/FullscreenEnterIcon.d.ts.map +1 -0
  22. package/dist/components/icons/svg-icons/FullscreenExitIcon.d.ts +5 -0
  23. package/dist/components/icons/svg-icons/FullscreenExitIcon.d.ts.map +1 -0
  24. package/dist/components/icons/svg-icons/LoadingIcon.d.ts +5 -0
  25. package/dist/components/icons/svg-icons/LoadingIcon.d.ts.map +1 -0
  26. package/dist/components/icons/svg-icons/PauseIcon.d.ts +5 -0
  27. package/dist/components/icons/svg-icons/PauseIcon.d.ts.map +1 -0
  28. package/dist/components/icons/svg-icons/PlayIcon.d.ts +5 -0
  29. package/dist/components/icons/svg-icons/PlayIcon.d.ts.map +1 -0
  30. package/dist/components/icons/svg-icons/PlaybackSpeedIcon.d.ts +5 -0
  31. package/dist/components/icons/svg-icons/PlaybackSpeedIcon.d.ts.map +1 -0
  32. package/dist/components/icons/svg-icons/QualityIcon.d.ts +5 -0
  33. package/dist/components/icons/svg-icons/QualityIcon.d.ts.map +1 -0
  34. package/dist/components/icons/svg-icons/SettingsIcon.d.ts +5 -0
  35. package/dist/components/icons/svg-icons/SettingsIcon.d.ts.map +1 -0
  36. package/dist/components/icons/svg-icons/SliderIcon.d.ts +5 -0
  37. package/dist/components/icons/svg-icons/SliderIcon.d.ts.map +1 -0
  38. package/dist/components/icons/svg-icons/SubtitleIcon.d.ts +5 -0
  39. package/dist/components/icons/svg-icons/SubtitleIcon.d.ts.map +1 -0
  40. package/dist/components/icons/svg-icons/SubtitleOffIcon.d.ts +5 -0
  41. package/dist/components/icons/svg-icons/SubtitleOffIcon.d.ts.map +1 -0
  42. package/dist/components/icons/svg-icons/UnPiPIcon.d.ts +4 -0
  43. package/dist/components/icons/svg-icons/UnPiPIcon.d.ts.map +1 -0
  44. package/dist/components/icons/svg-icons/VolumeMutedIcon.d.ts +5 -0
  45. package/dist/components/icons/svg-icons/VolumeMutedIcon.d.ts.map +1 -0
  46. package/dist/components/icons/svg-icons/VolumeOneIcon.d.ts +5 -0
  47. package/dist/components/icons/svg-icons/VolumeOneIcon.d.ts.map +1 -0
  48. package/dist/components/icons/svg-icons/VolumeThreeIcon.d.ts +5 -0
  49. package/dist/components/icons/svg-icons/VolumeThreeIcon.d.ts.map +1 -0
  50. package/dist/components/icons/svg-icons/VolumeTwoIcon.d.ts +5 -0
  51. package/dist/components/icons/svg-icons/VolumeTwoIcon.d.ts.map +1 -0
  52. package/dist/components/variants/gradient/gradient-audio.d.ts +13 -0
  53. package/dist/components/variants/gradient/gradient-audio.d.ts.map +1 -0
  54. package/dist/components/variants/gradient/gradient-controls.d.ts +4 -0
  55. package/dist/components/variants/gradient/gradient-controls.d.ts.map +1 -0
  56. package/dist/components/variants/gradient/gradient-glyphs.d.ts +30 -0
  57. package/dist/components/variants/gradient/gradient-glyphs.d.ts.map +1 -0
  58. package/dist/components/variants/gradient/gradient-video.d.ts +16 -0
  59. package/dist/components/variants/gradient/gradient-video.d.ts.map +1 -0
  60. package/dist/index.css +1 -1
  61. package/dist/index.d.ts +5 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +2 -112
  64. package/dist/index.js.map +1 -1
  65. package/dist/index.mjs +786 -6271
  66. package/dist/index.mjs.map +1 -1
  67. package/dist/package.json +3 -0
  68. package/package.json +110 -108
  69. package/src/components/variants/gradient/gradient-audio.tsx +47 -0
  70. package/src/components/variants/gradient/gradient-controls.tsx +254 -0
  71. package/src/components/variants/gradient/gradient-glyphs.test.tsx +69 -0
  72. package/src/components/variants/gradient/gradient-glyphs.tsx +129 -0
  73. package/src/components/variants/gradient/gradient-skin.css +211 -0
  74. package/src/components/variants/gradient/gradient-video.tsx +70 -0
  75. package/src/index.ts +5 -198
  76. package/src/test/accessibility-utils.ts +0 -59
  77. package/dist/context/media.js +0 -2
  78. package/dist/context/media.js.map +0 -1
  79. package/dist/context/media.mjs +0 -15
  80. package/dist/context/media.mjs.map +0 -1
  81. package/dist/context/store.js +0 -2
  82. package/dist/context/store.js.map +0 -1
  83. package/dist/context/store.mjs +0 -5
  84. package/dist/context/store.mjs.map +0 -1
  85. package/dist/context-BYwDoSRX.js +0 -1172
  86. package/dist/context-BYwDoSRX.js.map +0 -1
  87. package/dist/context-eNS62_ac.cjs +0 -23
  88. package/dist/context-eNS62_ac.cjs.map +0 -1
  89. package/dist/core-events-B1iM2F46.cjs +0 -2
  90. package/dist/core-events-B1iM2F46.cjs.map +0 -1
  91. package/dist/core-events-DunPHKRE.js +0 -484
  92. package/dist/core-events-DunPHKRE.js.map +0 -1
  93. package/dist/core-plugins-By-4-kGs.cjs +0 -2
  94. package/dist/core-plugins-By-4-kGs.cjs.map +0 -1
  95. package/dist/core-plugins-DSBWcTuX.js +0 -821
  96. package/dist/core-plugins-DSBWcTuX.js.map +0 -1
  97. package/dist/core.js +0 -37
  98. package/dist/core.js.map +0 -1
  99. package/dist/core.mjs +0 -1233
  100. package/dist/core.mjs.map +0 -1
  101. package/dist/enhanced-components-B_l3cist.js +0 -1142
  102. package/dist/enhanced-components-B_l3cist.js.map +0 -1
  103. package/dist/enhanced-components-BspFs9OO.cjs +0 -2
  104. package/dist/enhanced-components-BspFs9OO.cjs.map +0 -1
  105. package/dist/hooks-BXwI8QG6.cjs +0 -4
  106. package/dist/hooks-BXwI8QG6.cjs.map +0 -1
  107. package/dist/hooks-Bpi-jDiO.js +0 -1816
  108. package/dist/hooks-Bpi-jDiO.js.map +0 -1
  109. package/dist/minimal-components-C4z900Ro.js +0 -1926
  110. package/dist/minimal-components-C4z900Ro.js.map +0 -1
  111. package/dist/minimal-components-v4qBp6jv.cjs +0 -2
  112. package/dist/minimal-components-v4qBp6jv.cjs.map +0 -1
  113. package/dist/minimal-components.css +0 -1
  114. package/dist/mona-loading.gif +0 -0
  115. package/dist/performance-monitor-C5k6FDXw.js +0 -301
  116. package/dist/performance-monitor-C5k6FDXw.js.map +0 -1
  117. package/dist/performance-monitor-lJmuUjQQ.cjs +0 -2
  118. package/dist/performance-monitor-lJmuUjQQ.cjs.map +0 -1
  119. package/dist/utils-CFOue_9K.cjs +0 -9
  120. package/dist/utils-CFOue_9K.cjs.map +0 -1
  121. package/dist/utils-Dzpl2ArK.js +0 -2844
  122. package/dist/utils-Dzpl2ArK.js.map +0 -1
  123. package/dist/utils.js +0 -2
  124. package/dist/utils.js.map +0 -1
  125. package/dist/utils.mjs +0 -11
  126. package/dist/utils.mjs.map +0 -1
  127. package/src/adapters/videojs-adapter.tsx +0 -470
  128. package/src/assets/mona-loading.gif +0 -0
  129. package/src/components/AnimateLoading.tsx +0 -107
  130. package/src/components/LoadingState.tsx +0 -239
  131. package/src/components/__tests__/media-player-accessibility.test.tsx +0 -510
  132. package/src/components/__tests__/media-player-react19.test.tsx +0 -457
  133. package/src/components/accessibility/keyboard-help-overlay.tsx +0 -207
  134. package/src/components/audio-player.tsx +0 -85
  135. package/src/components/basic/index.ts +0 -37
  136. package/src/components/enhanced/advanced-features.tsx +0 -311
  137. package/src/components/enhanced/debug-panel.tsx +0 -448
  138. package/src/components/enhanced/enhanced-controls.tsx +0 -597
  139. package/src/components/enhanced/enhanced-media-player.tsx +0 -566
  140. package/src/components/enhanced/error-handling.tsx +0 -338
  141. package/src/components/enhanced/index.ts +0 -39
  142. package/src/components/enhanced/media-player-enhanced.tsx +0 -383
  143. package/src/components/examples/basic-video-player.tsx +0 -50
  144. package/src/components/examples/custom-controls-example.tsx +0 -63
  145. package/src/components/examples/enhanced-controls-example.tsx +0 -100
  146. package/src/components/examples/enhanced-media-player-example.tsx +0 -302
  147. package/src/components/examples/loading-states-demo.tsx +0 -142
  148. package/src/components/examples/react-19-demo.tsx +0 -353
  149. package/src/components/examples/volume-orientation-demo.tsx +0 -106
  150. package/src/components/icon-demo.tsx +0 -196
  151. package/src/components/legacy.tsx +0 -87
  152. package/src/components/media-metadata-display.tsx +0 -99
  153. package/src/components/media-player-audio.tsx +0 -39
  154. package/src/components/media-player-controls.tsx +0 -223
  155. package/src/components/media-player-error.tsx +0 -163
  156. package/src/components/media-player-fullscreen.tsx +0 -109
  157. package/src/components/media-player-hls.tsx +0 -111
  158. package/src/components/media-player-loading.tsx +0 -76
  159. package/src/components/media-player-play.tsx +0 -75
  160. package/src/components/media-player-root.tsx +0 -338
  161. package/src/components/media-player-seek.tsx +0 -168
  162. package/src/components/media-player-time.tsx +0 -99
  163. package/src/components/media-player-tooltip.tsx +0 -58
  164. package/src/components/media-player-video.tsx +0 -54
  165. package/src/components/media-player-volume.tsx +0 -155
  166. package/src/components/media-player.tsx +0 -292
  167. package/src/components/media-suspense.tsx +0 -344
  168. package/src/components/player-settings-form.tsx +0 -158
  169. package/src/components/react-player-wrapper.tsx +0 -651
  170. package/src/components/simple-video-player.tsx +0 -62
  171. package/src/components/ui/blur-poster.tsx +0 -93
  172. package/src/components/ui/empty-state.tsx +0 -91
  173. package/src/components/ui/enhanced-seek-bar.tsx +0 -254
  174. package/src/components/ui/error-state.tsx +0 -124
  175. package/src/components/ui/fullscreen-button.tsx +0 -81
  176. package/src/components/ui/loading-skeleton.tsx +0 -107
  177. package/src/components/ui/media-resource-preloader.tsx +0 -458
  178. package/src/components/ui/offline-message.tsx +0 -98
  179. package/src/components/ui/play-button.tsx +0 -99
  180. package/src/components/ui/seek-bar.tsx +0 -191
  181. package/src/components/ui/time-display.tsx +0 -61
  182. package/src/components/ui/volume-control.tsx +0 -190
  183. package/src/components/unified/base-media-player.tsx +0 -252
  184. package/src/components/unified/media-player.tsx +0 -75
  185. package/src/components/variants/minimal/AccessibleMinimalPlayer.tsx +0 -587
  186. package/src/components/variants/minimal/EnhancedMinimalMediaPlayer.tsx +0 -573
  187. package/src/components/variants/minimal/MinimalControls.tsx +0 -124
  188. package/src/components/variants/minimal/MinimalLoading.tsx +0 -28
  189. package/src/components/variants/minimal/MinimalMediaPlayer.tsx +0 -318
  190. package/src/components/variants/minimal/MinimalOverlay.tsx +0 -58
  191. package/src/components/variants/minimal/MinimalPlayButton.tsx +0 -56
  192. package/src/components/variants/minimal/MinimalSeekBar.tsx +0 -140
  193. package/src/components/variants/minimal/MinimalVolumeControl.tsx +0 -75
  194. package/src/components/variants/minimal/SimpleMinimalPlayer.tsx +0 -206
  195. package/src/components/variants/minimal/components/CenterPlayButton.tsx +0 -22
  196. package/src/components/variants/minimal/components/ControlBar.tsx +0 -142
  197. package/src/components/variants/minimal/components/EnhancedSettingsMenu.tsx +0 -412
  198. package/src/components/variants/minimal/components/PlaybackControls.tsx +0 -46
  199. package/src/components/variants/minimal/components/RightControls.tsx +0 -164
  200. package/src/components/variants/minimal/components/SeekBar.tsx +0 -127
  201. package/src/components/variants/minimal/components/SettingsDropdown.tsx +0 -68
  202. package/src/components/variants/minimal/components/SubtitleDisplay.tsx +0 -21
  203. package/src/components/variants/minimal/components/TimeDisplay.tsx +0 -15
  204. package/src/components/variants/minimal/components/VideoElement.tsx +0 -33
  205. package/src/components/variants/minimal/components/VolumeControl.tsx +0 -220
  206. package/src/components/variants/minimal/index.ts +0 -23
  207. package/src/components/video-player.tsx +0 -100
  208. package/src/context/__tests__/media-store.test.ts +0 -509
  209. package/src/context/error-handling.ts +0 -398
  210. package/src/context/media-context.tsx +0 -254
  211. package/src/context/media-provider.tsx +0 -264
  212. package/src/context/media-store.ts +0 -387
  213. package/src/context/persistence.ts +0 -462
  214. package/src/core/events/event-system.ts +0 -448
  215. package/src/core/events/hooks.ts +0 -325
  216. package/src/core/events/index.ts +0 -22
  217. package/src/core/events/middleware.ts +0 -286
  218. package/src/core/index.ts +0 -22
  219. package/src/core/optimization/bundle-optimizer.tsx +0 -312
  220. package/src/core/performance/cicd.ts +0 -98
  221. package/src/core/performance/index.ts +0 -38
  222. package/src/core/performance/media-loading-optimizer.ts +0 -544
  223. package/src/core/performance/performance-budgets.ts +0 -437
  224. package/src/core/performance/performance-monitor.tsx +0 -488
  225. package/src/core/performance/performance-testing.ts +0 -461
  226. package/src/core/plugins/__tests__/registry.test.ts +0 -595
  227. package/src/core/plugins/base-plugin.ts +0 -225
  228. package/src/core/plugins/enhanced-plugin-system.ts +0 -435
  229. package/src/core/plugins/examples/analytics-plugin.ts +0 -241
  230. package/src/core/plugins/index.ts +0 -39
  231. package/src/core/plugins/registry.ts +0 -546
  232. package/src/core/plugins/types.ts +0 -169
  233. package/src/core/plugins/utils.ts +0 -317
  234. package/src/core/progressive-loading.tsx +0 -331
  235. package/src/core/providers/enhanced-hls-provider.ts +0 -307
  236. package/src/core/providers/lazy-provider.tsx +0 -14
  237. package/src/core/providers/service-provider.tsx +0 -164
  238. package/src/core/utils.tsx +0 -34
  239. package/src/features/media-session/media-session-manager.ts +0 -411
  240. package/src/features/picture-in-picture/pip-manager.ts +0 -428
  241. package/src/features/playlist/playlist-manager.ts +0 -626
  242. package/src/features/subtitles/subtitle-manager.ts +0 -435
  243. package/src/features/subtitles/subtitle-parser.ts +0 -284
  244. package/src/features/thumbnails/thumbnail-generator.ts +0 -528
  245. package/src/hooks/__tests__/currentTime-fix.test.ts +0 -149
  246. package/src/hooks/__tests__/use-media-player.test.ts +0 -712
  247. package/src/hooks/__tests__/use-media-state.test.tsx +0 -316
  248. package/src/hooks/accessibility/index.ts +0 -27
  249. package/src/hooks/accessibility/use-accessibility-preferences.ts +0 -190
  250. package/src/hooks/accessibility/use-focus-management.ts +0 -183
  251. package/src/hooks/accessibility/use-keyboard-shortcuts.ts +0 -152
  252. package/src/hooks/accessibility/use-screen-reader.ts +0 -212
  253. package/src/hooks/core/index.ts +0 -47
  254. package/src/hooks/legacy.ts +0 -21
  255. package/src/hooks/use-buffer-health.ts +0 -218
  256. package/src/hooks/use-enhanced-media-player.ts +0 -575
  257. package/src/hooks/use-focus-trap.tsx +0 -162
  258. package/src/hooks/use-intelligent-preloading.ts +0 -387
  259. package/src/hooks/use-keyboard-controls.ts +0 -115
  260. package/src/hooks/use-keyboard-shortcuts.ts +0 -255
  261. package/src/hooks/use-media-actions.ts +0 -184
  262. package/src/hooks/use-media-metadata.ts +0 -91
  263. package/src/hooks/use-media-optimistic.ts +0 -264
  264. package/src/hooks/use-media-player.ts +0 -343
  265. package/src/hooks/use-media-state.ts +0 -194
  266. package/src/hooks/use-memory-optimization.ts +0 -360
  267. package/src/hooks/use-network-status.ts +0 -124
  268. package/src/hooks/use-optimistic-controls.ts +0 -95
  269. package/src/hooks/use-optimized-media.ts +0 -283
  270. package/src/hooks/use-smart-preload.ts +0 -229
  271. package/src/hooks/use-touch-gestures.ts +0 -461
  272. package/src/hooks/useEnhancedSubtitles.ts +0 -258
  273. package/src/hooks/useKeyboardShortcuts.ts +0 -106
  274. package/src/hooks/useMediaControls.ts +0 -52
  275. package/src/hooks/useScreenshot.ts +0 -61
  276. package/src/hooks/useSubtitles.ts +0 -91
  277. package/src/hooks/useVideoPlayer.ts +0 -278
  278. package/src/icons/components/FullscreenIcon.tsx +0 -36
  279. package/src/icons/components/SettingsIcon.tsx +0 -37
  280. package/src/icons/components/animated/LoadingIcon.tsx +0 -27
  281. package/src/icons/components/animated/PlayPauseIcon.tsx +0 -42
  282. package/src/icons/components/media/PauseIcon.tsx +0 -38
  283. package/src/icons/components/media/PlayIcon.tsx +0 -37
  284. package/src/icons/components/volume/VolumeIcon.tsx +0 -38
  285. package/src/icons/components/volume/VolumeOffIcon.tsx +0 -38
  286. package/src/icons/index.ts +0 -56
  287. package/src/icons/provider.tsx +0 -58
  288. package/src/icons/types.ts +0 -60
  289. package/src/index-enhanced.ts +0 -35
  290. package/src/index-legacy.ts +0 -324
  291. package/src/index.css +0 -102
  292. package/src/lib/__tests__/async-utils.test.ts +0 -291
  293. package/src/lib/async-utils.ts +0 -194
  294. package/src/lib/deprecation.ts +0 -51
  295. package/src/lib/format-time.ts +0 -37
  296. package/src/lib/index.ts +0 -4
  297. package/src/lib/utils.ts +0 -6
  298. package/src/styles/globals.css +0 -462
  299. package/src/styles/minimal-player.css +0 -621
  300. package/src/styles/pixel-art.css +0 -41
  301. package/src/styles/videojs.css +0 -100
  302. package/src/types/events.ts +0 -47
  303. package/src/types/formats.ts +0 -79
  304. package/src/types/index.ts +0 -203
  305. package/src/types/videojs-plugins.d.ts +0 -14
@@ -1,461 +0,0 @@
1
- "use client"
2
-
3
- import { useDeviceInfo, useHapticFeedback } from "@rp/ui/hooks/use-mobile"
4
- import * as React from "react"
5
-
6
- // Gesture types
7
- export type GestureType =
8
- | "tap"
9
- | "double-tap"
10
- | "long-press"
11
- | "swipe-left"
12
- | "swipe-right"
13
- | "swipe-up"
14
- | "swipe-down"
15
- | "pinch-in"
16
- | "pinch-out"
17
-
18
- // Gesture event data
19
- export interface GestureEvent {
20
- type: GestureType
21
- startPoint: { x: number; y: number }
22
- currentPoint: { x: number; y: number }
23
- velocity?: { x: number; y: number }
24
- scale?: number
25
- rotation?: number
26
- distance?: number
27
- duration: number
28
- preventDefault: () => void
29
- target: HTMLElement
30
- }
31
-
32
- // Gesture configuration
33
- export interface GestureConfig {
34
- enabledGestures?: GestureType[]
35
- tapThreshold?: number // ms
36
- doubleTapThreshold?: number // ms
37
- longPressThreshold?: number // ms
38
- swipeThreshold?: number // px
39
- swipeVelocityThreshold?: number // px/ms
40
- pinchThreshold?: number // scale difference
41
- rotationThreshold?: number // degrees
42
- enableHapticFeedback?: boolean
43
- }
44
-
45
- // Default configuration
46
- const defaultConfig: Required<GestureConfig> = {
47
- enabledGestures: [
48
- "tap",
49
- "double-tap",
50
- "long-press",
51
- "swipe-left",
52
- "swipe-right",
53
- "swipe-up",
54
- "swipe-down",
55
- "pinch-in",
56
- "pinch-out"
57
- ],
58
- tapThreshold: 200,
59
- doubleTapThreshold: 300,
60
- longPressThreshold: 500,
61
- swipeThreshold: 50,
62
- swipeVelocityThreshold: 0.5,
63
- pinchThreshold: 0.1,
64
- rotationThreshold: 15,
65
- enableHapticFeedback: true
66
- }
67
-
68
- // Touch point interface
69
- interface TouchPoint {
70
- id: number
71
- x: number
72
- y: number
73
- timestamp: number
74
- }
75
-
76
- // Gesture state
77
- interface GestureState {
78
- isTracking: boolean
79
- touches: TouchPoint[]
80
- startTouches: TouchPoint[]
81
- lastTap?: { timestamp: number; point: { x: number; y: number } }
82
- longPressTimer?: NodeJS.Timeout
83
- initialDistance?: number
84
- initialScale?: number
85
- lastScale?: number
86
- }
87
-
88
- // Touch gesture hook
89
- export function useTouchGestures(
90
- ref: React.RefObject<HTMLElement>,
91
- onGesture: (event: GestureEvent) => void,
92
- config: GestureConfig = {}
93
- ) {
94
- const mergedConfig = { ...defaultConfig, ...config }
95
- const { isTouchDevice } = useDeviceInfo()
96
- const { triggerHaptic } = useHapticFeedback()
97
- const gestureState = React.useRef<GestureState>({
98
- isTracking: false,
99
- touches: [],
100
- startTouches: []
101
- })
102
-
103
- // Helper functions
104
- const getTouchPoint = (touch: Touch): TouchPoint => ({
105
- id: touch.identifier,
106
- x: touch.clientX,
107
- y: touch.clientY,
108
- timestamp: Date.now()
109
- })
110
-
111
- const getDistance = (p1: TouchPoint, p2: TouchPoint): number =>
112
- Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2))
113
-
114
- const getVelocity = (start: TouchPoint, end: TouchPoint): { x: number; y: number } => {
115
- const timeDiff = Math.max(end.timestamp - start.timestamp, 1)
116
- return {
117
- x: (end.x - start.x) / timeDiff,
118
- y: (end.y - start.y) / timeDiff
119
- }
120
- }
121
-
122
- const createGestureEvent = (
123
- type: GestureType,
124
- startPoint: TouchPoint,
125
- currentPoint: TouchPoint,
126
- additionalData: Partial<GestureEvent> = {}
127
- ): GestureEvent => ({
128
- type,
129
- startPoint: { x: startPoint.x, y: startPoint.y },
130
- currentPoint: { x: currentPoint.x, y: currentPoint.y },
131
- duration: currentPoint.timestamp - startPoint.timestamp,
132
- target: ref.current!,
133
- preventDefault: () => {},
134
- ...additionalData
135
- })
136
-
137
- // Handle touch start
138
- const handleTouchStart = React.useCallback(
139
- (e: TouchEvent) => {
140
- if (!mergedConfig.enabledGestures.length) return
141
-
142
- const touches = Array.from(e.touches).map(getTouchPoint)
143
- const state = gestureState.current
144
-
145
- state.isTracking = true
146
- state.touches = touches
147
- state.startTouches = [...touches]
148
-
149
- // Clear any existing long press timer
150
- if (state.longPressTimer) {
151
- clearTimeout(state.longPressTimer)
152
- }
153
-
154
- // Set up long press detection for single touch
155
- if (touches.length === 1 && mergedConfig.enabledGestures.includes("long-press")) {
156
- state.longPressTimer = setTimeout(() => {
157
- if (state.touches.length === 1 && touches[0]) {
158
- const gestureEvent = createGestureEvent("long-press", touches[0], touches[0])
159
- onGesture(gestureEvent)
160
-
161
- if (mergedConfig.enableHapticFeedback) {
162
- triggerHaptic("heavy")
163
- }
164
- }
165
- }, mergedConfig.longPressThreshold)
166
- }
167
-
168
- // Handle multi-touch gestures
169
- if (touches.length === 2 && touches[0] && touches[1]) {
170
- state.initialDistance = getDistance(touches[0], touches[1])
171
- state.initialScale = 1
172
- state.lastScale = 1
173
- }
174
- },
175
- [mergedConfig, onGesture, triggerHaptic]
176
- )
177
-
178
- // Handle touch move
179
- const handleTouchMove = React.useCallback(
180
- (e: TouchEvent) => {
181
- const state = gestureState.current
182
- if (!state.isTracking) return
183
-
184
- const touches = Array.from(e.touches).map(getTouchPoint)
185
- state.touches = touches
186
-
187
- // Handle pinch gesture
188
- if (touches.length === 2 && state.initialDistance && touches[0] && touches[1]) {
189
- const currentDistance = getDistance(touches[0], touches[1])
190
- const scale = currentDistance / state.initialDistance
191
- const scaleDiff = Math.abs(scale - (state.lastScale || 1))
192
-
193
- if (scaleDiff > mergedConfig.pinchThreshold) {
194
- const gestureType = scale > (state.lastScale || 1) ? "pinch-out" : "pinch-in"
195
-
196
- if (mergedConfig.enabledGestures.includes(gestureType)) {
197
- const centerPoint = {
198
- x: (touches[0].x + touches[1].x) / 2,
199
- y: (touches[0].y + touches[1].y) / 2,
200
- id: -1,
201
- timestamp: Date.now()
202
- }
203
-
204
- const startCenterPoint = {
205
- x: ((state.startTouches[0]?.x ?? 0) + (state.startTouches[1]?.x ?? 0)) / 2,
206
- y: ((state.startTouches[0]?.y ?? 0) + (state.startTouches[1]?.y ?? 0)) / 2,
207
- id: -1,
208
- timestamp: state.startTouches[0]?.timestamp ?? Date.now()
209
- }
210
-
211
- const gestureEvent = createGestureEvent(gestureType, startCenterPoint, centerPoint, {
212
- scale,
213
- distance: currentDistance
214
- })
215
-
216
- onGesture(gestureEvent)
217
- state.lastScale = scale
218
- }
219
- }
220
- }
221
-
222
- // Clear long press timer on move
223
- if (state.longPressTimer && touches.length === 1 && state.startTouches[0] && touches[0]) {
224
- const startTouch = state.startTouches[0]
225
- const currentTouch = touches[0]
226
- const distance = getDistance(startTouch, currentTouch)
227
-
228
- if (distance > mergedConfig.swipeThreshold) {
229
- clearTimeout(state.longPressTimer)
230
- state.longPressTimer = undefined
231
- }
232
- }
233
- },
234
- [mergedConfig, onGesture]
235
- )
236
-
237
- // Handle touch end
238
- const handleTouchEnd = React.useCallback(
239
- (e: TouchEvent) => {
240
- const state = gestureState.current
241
- if (!state.isTracking) return
242
-
243
- const endTouches = Array.from(e.changedTouches).map(getTouchPoint)
244
- const currentTime = Date.now()
245
-
246
- // Clear long press timer
247
- if (state.longPressTimer) {
248
- clearTimeout(state.longPressTimer)
249
- state.longPressTimer = undefined
250
- }
251
-
252
- // Handle single touch gestures
253
- if (
254
- state.startTouches.length === 1 &&
255
- endTouches.length === 1 &&
256
- state.startTouches[0] &&
257
- endTouches[0]
258
- ) {
259
- const startTouch = state.startTouches[0]
260
- const endTouch = endTouches[0]
261
- const distance = getDistance(startTouch, endTouch)
262
- const duration = endTouch.timestamp - startTouch.timestamp
263
-
264
- // Check for swipe gestures
265
- if (distance > mergedConfig.swipeThreshold) {
266
- const velocity = getVelocity(startTouch, endTouch)
267
- const absVelX = Math.abs(velocity.x)
268
- const absVelY = Math.abs(velocity.y)
269
-
270
- if (
271
- absVelX > mergedConfig.swipeVelocityThreshold ||
272
- absVelY > mergedConfig.swipeVelocityThreshold
273
- ) {
274
- let gestureType: GestureType
275
-
276
- if (absVelX > absVelY) {
277
- gestureType = velocity.x > 0 ? "swipe-right" : "swipe-left"
278
- } else {
279
- gestureType = velocity.y > 0 ? "swipe-down" : "swipe-up"
280
- }
281
-
282
- if (mergedConfig.enabledGestures.includes(gestureType)) {
283
- const gestureEvent = createGestureEvent(gestureType, startTouch, endTouch, {
284
- velocity,
285
- distance
286
- })
287
-
288
- onGesture(gestureEvent)
289
-
290
- if (mergedConfig.enableHapticFeedback) {
291
- triggerHaptic("light")
292
- }
293
- }
294
- }
295
- }
296
- // Check for tap gestures
297
- else if (duration < mergedConfig.tapThreshold && distance < mergedConfig.swipeThreshold) {
298
- // Check for double tap
299
- if (
300
- state.lastTap &&
301
- currentTime - state.lastTap.timestamp < mergedConfig.doubleTapThreshold &&
302
- getDistance(
303
- { ...state.lastTap.point, id: -1, timestamp: state.lastTap.timestamp },
304
- endTouch
305
- ) < mergedConfig.swipeThreshold
306
- ) {
307
- if (mergedConfig.enabledGestures.includes("double-tap")) {
308
- const gestureEvent = createGestureEvent("double-tap", startTouch, endTouch)
309
- onGesture(gestureEvent)
310
-
311
- if (mergedConfig.enableHapticFeedback) {
312
- triggerHaptic("medium")
313
- }
314
- }
315
-
316
- state.lastTap = undefined
317
- } else {
318
- // Single tap
319
- if (mergedConfig.enabledGestures.includes("tap")) {
320
- const gestureEvent = createGestureEvent("tap", startTouch, endTouch)
321
- onGesture(gestureEvent)
322
-
323
- if (mergedConfig.enableHapticFeedback) {
324
- triggerHaptic("light")
325
- }
326
- }
327
-
328
- state.lastTap = {
329
- timestamp: currentTime,
330
- point: { x: endTouch.x, y: endTouch.y }
331
- }
332
- }
333
- }
334
- }
335
-
336
- // Reset gesture state
337
- if (e.touches.length === 0) {
338
- state.isTracking = false
339
- state.touches = []
340
- state.startTouches = []
341
- state.initialDistance = undefined
342
- state.initialScale = undefined
343
- state.lastScale = undefined
344
- }
345
- },
346
- [mergedConfig, onGesture, triggerHaptic]
347
- )
348
-
349
- // Attach event listeners
350
- React.useEffect(() => {
351
- const element = ref.current
352
- if (!element || !isTouchDevice) return
353
-
354
- element.addEventListener("touchstart", handleTouchStart, { passive: false })
355
- element.addEventListener("touchmove", handleTouchMove, { passive: false })
356
- element.addEventListener("touchend", handleTouchEnd, { passive: false })
357
- element.addEventListener("touchcancel", handleTouchEnd, { passive: false })
358
-
359
- return () => {
360
- element.removeEventListener("touchstart", handleTouchStart)
361
- element.removeEventListener("touchmove", handleTouchMove)
362
- element.removeEventListener("touchend", handleTouchEnd)
363
- element.removeEventListener("touchcancel", handleTouchEnd)
364
- }
365
- }, [handleTouchStart, handleTouchMove, handleTouchEnd, isTouchDevice])
366
-
367
- return {
368
- isGestureEnabled: isTouchDevice && mergedConfig.enabledGestures.length > 0
369
- }
370
- }
371
-
372
- // Media player specific gesture hook with predefined actions
373
- export function useMediaGestures(
374
- ref: React.RefObject<HTMLElement>,
375
- actions: {
376
- onPlayPause?: () => void
377
- onSeek?: (direction: "forward" | "backward", amount: number) => void
378
- onVolumeChange?: (direction: "up" | "down", amount: number) => void
379
- onToggleFullscreen?: () => void
380
- onZoom?: (scale: number) => void
381
- }
382
- ) {
383
- const handleGesture = React.useCallback(
384
- (event: GestureEvent) => {
385
- const { type, velocity, distance, scale } = event
386
-
387
- switch (type) {
388
- case "double-tap":
389
- // Double tap to play/pause
390
- actions.onPlayPause?.()
391
- break
392
-
393
- case "swipe-left":
394
- // Swipe left to seek backward
395
- const backwardAmount = Math.min((distance || 0) / 10, 30) // Max 30 seconds
396
- actions.onSeek?.("backward", backwardAmount)
397
- break
398
-
399
- case "swipe-right":
400
- // Swipe right to seek forward
401
- const forwardAmount = Math.min((distance || 0) / 10, 30) // Max 30 seconds
402
- actions.onSeek?.("forward", forwardAmount)
403
- break
404
-
405
- case "swipe-up":
406
- // Swipe up on right side for volume up
407
- if (event.startPoint.x > (ref.current?.clientWidth || 0) / 2) {
408
- const volumeAmount = Math.min((distance || 0) / 100, 0.2) // Max 20%
409
- actions.onVolumeChange?.("up", volumeAmount)
410
- }
411
- break
412
-
413
- case "swipe-down":
414
- // Swipe down on right side for volume down
415
- if (event.startPoint.x > (ref.current?.clientWidth || 0) / 2) {
416
- const volumeAmount = Math.min((distance || 0) / 100, 0.2) // Max 20%
417
- actions.onVolumeChange?.("down", volumeAmount)
418
- }
419
- break
420
-
421
- case "pinch-out":
422
- // Pinch out to zoom in (for video zoom functionality)
423
- actions.onZoom?.(scale || 1)
424
- break
425
-
426
- case "pinch-in":
427
- // Pinch in to zoom out
428
- actions.onZoom?.(scale || 1)
429
- break
430
-
431
- case "long-press":
432
- // Long press for fullscreen toggle
433
- actions.onToggleFullscreen?.()
434
- break
435
-
436
- default:
437
- break
438
- }
439
- },
440
- [actions, ref]
441
- )
442
-
443
- const gestureConfig: GestureConfig = {
444
- enabledGestures: [
445
- "tap",
446
- "double-tap",
447
- "long-press",
448
- "swipe-left",
449
- "swipe-right",
450
- "swipe-up",
451
- "swipe-down",
452
- "pinch-in",
453
- "pinch-out"
454
- ],
455
- enableHapticFeedback: true,
456
- swipeThreshold: 30,
457
- swipeVelocityThreshold: 0.3
458
- }
459
-
460
- return useTouchGestures(ref, handleGesture, gestureConfig)
461
- }
@@ -1,258 +0,0 @@
1
- import { useCallback, useEffect, useMemo, useState } from "react"
2
-
3
- interface SubtitleCue {
4
- start: number
5
- end: number
6
- text: string
7
- }
8
-
9
- export interface SubtitleTrack {
10
- id: string
11
- label: string
12
- language?: string
13
- src?: string
14
- }
15
-
16
- export interface UseEnhancedSubtitlesOptions {
17
- subtitleSrc?: string
18
- subtitleTracks?: SubtitleTrack[]
19
- defaultFontSize?: "small" | "medium" | "large"
20
- onLoadError?: (error: Error) => void
21
- }
22
-
23
- export function useEnhancedSubtitles({
24
- subtitleSrc,
25
- subtitleTracks = [],
26
- defaultFontSize = "medium",
27
- onLoadError
28
- }: UseEnhancedSubtitlesOptions = {}) {
29
- const [subtitlesEnabled, setSubtitlesEnabled] = useState(false)
30
- const [subtitleCues, setSubtitleCues] = useState<SubtitleCue[]>([])
31
- const [currentSubtitle, setCurrentSubtitle] = useState("")
32
- const [currentTrackId, setCurrentTrackId] = useState<string | null>(null)
33
- const [fontSize, setFontSize] = useState<"small" | "medium" | "large">(defaultFontSize)
34
- const [loadError, setLoadError] = useState<Error | null>(null)
35
- const [isLoading, setIsLoading] = useState(false)
36
-
37
- // Size mapping for subtitle font sizes
38
- const sizeMap = {
39
- small: "text-sm",
40
- medium: "text-base",
41
- large: "text-lg"
42
- }
43
-
44
- // Determine if subtitles are available
45
- const hasSubtitles = !!(subtitleSrc || (subtitleTracks && subtitleTracks.length > 0))
46
-
47
- // Parse VTT/WebVTT timestamp
48
- const parseVTTTime = (timeStr: string): number => {
49
- const parts = timeStr.split(":")
50
- const seconds = parts[2] ? parseFloat(parts[2]) : 0
51
- const minutes = parts[1] ? parseInt(parts[1], 10) * 60 : 0
52
- const hours = parts[0] ? parseInt(parts[0], 10) * 3600 : 0
53
- return hours + minutes + seconds
54
- }
55
-
56
- // Parse SRT timestamp
57
- const parseSRTTime = (timeStr: string): number => {
58
- // SRT format: 00:00:00,000 (hours:minutes:seconds,milliseconds)
59
- const [time, ms] = timeStr.split(",")
60
- const parts = (time || "").split(":")
61
- const milliseconds = ms ? parseInt(ms, 10) / 1000 : 0
62
- const seconds = parts[2] ? parseInt(parts[2], 10) : 0
63
- const minutes = parts[1] ? parseInt(parts[1], 10) * 60 : 0
64
- const hours = parts[0] ? parseInt(parts[0], 10) * 3600 : 0
65
- return hours + minutes + seconds + milliseconds
66
- }
67
-
68
- // Load and parse subtitle file
69
- const loadSubtitles = async (url: string) => {
70
- setIsLoading(true)
71
- setLoadError(null)
72
-
73
- try {
74
- const response = await fetch(url)
75
- if (!response.ok) {
76
- throw new Error(`Failed to load subtitles: ${response.status} ${response.statusText}`)
77
- }
78
-
79
- const text = await response.text()
80
- const cues: SubtitleCue[] = []
81
- const lines = text.split("\n")
82
- let i = 0
83
-
84
- // Detect format (VTT or SRT)
85
- const isVTT = text.includes("WEBVTT") || url.endsWith(".vtt")
86
- const isSRT = url.endsWith(".srt") || /^\d+$/.test(lines[0]?.trim() || "")
87
-
88
- if (isVTT) {
89
- // Parse VTT format
90
- while (i < lines.length) {
91
- if (lines[i]?.includes("-->")) {
92
- const [startStr, endStr] = (lines[i] || "").split("-->").map((s) => s.trim())
93
- const start = parseVTTTime(startStr || "")
94
- const end = parseVTTTime(endStr || "")
95
-
96
- i++
97
- let subtitleText = ""
98
- while (i < lines.length && lines[i]?.trim() !== "") {
99
- subtitleText += (subtitleText ? " " : "") + lines[i]?.trim()
100
- i++
101
- }
102
-
103
- if (subtitleText) {
104
- cues.push({ start, end, text: subtitleText })
105
- }
106
- }
107
- i++
108
- }
109
- } else if (isSRT) {
110
- // Parse SRT format
111
- while (i < lines.length) {
112
- // Skip the sequence number
113
- if (/^\d+$/.test(lines[i]?.trim() || "")) {
114
- i++
115
- // Parse timestamp line
116
- if (lines[i]?.includes("-->")) {
117
- const [startStr, endStr] = (lines[i] || "").split("-->").map((s) => s.trim())
118
- const start = parseSRTTime(startStr || "")
119
- const end = parseSRTTime(endStr || "")
120
-
121
- i++
122
- let subtitleText = ""
123
- while (i < lines.length && lines[i]?.trim() !== "") {
124
- subtitleText += (subtitleText ? " " : "") + lines[i]?.trim()
125
- i++
126
- }
127
-
128
- if (subtitleText) {
129
- cues.push({ start, end, text: subtitleText })
130
- }
131
- }
132
- }
133
- i++
134
- }
135
- } else {
136
- throw new Error("Unsupported subtitle format. Only VTT and SRT are supported.")
137
- }
138
-
139
- if (cues.length === 0) {
140
- throw new Error("No subtitle cues found in file")
141
- }
142
-
143
- setSubtitleCues(cues)
144
- setIsLoading(false)
145
- } catch (error) {
146
- const err = error instanceof Error ? error : new Error("Failed to load subtitles")
147
- console.error("Failed to load subtitles:", err)
148
- setLoadError(err)
149
- setIsLoading(false)
150
- setSubtitleCues([])
151
- onLoadError?.(err)
152
- }
153
- }
154
-
155
- // Get current subtitle text based on time
156
- const getCurrentSubtitle = (currentTime: number) => {
157
- if (!subtitlesEnabled || subtitleCues.length === 0) return ""
158
-
159
- const currentCue = subtitleCues.find(
160
- (cue) => currentTime >= cue.start && currentTime <= cue.end
161
- )
162
- return currentCue?.text || ""
163
- }
164
-
165
- // Toggle subtitles on/off
166
- const toggleSubtitles = () => {
167
- setSubtitlesEnabled((prev) => {
168
- const newEnabled = !prev
169
-
170
- if (newEnabled && !loadError) {
171
- // Try to load subtitles if not already loaded
172
- if (subtitleCues.length === 0 && !isLoading) {
173
- // Load default subtitle source or first track
174
- const srcToLoad = subtitleSrc || subtitleTracks[0]?.src
175
- if (srcToLoad) {
176
- loadSubtitles(srcToLoad)
177
- if (subtitleTracks[0]) {
178
- setCurrentTrackId(subtitleTracks[0].id)
179
- }
180
- }
181
- }
182
- } else if (!newEnabled) {
183
- setCurrentSubtitle("")
184
- }
185
-
186
- return newEnabled
187
- })
188
- }
189
-
190
- // Select a specific subtitle track
191
- const selectSubtitleTrack = (trackId: string | null) => {
192
- if (!trackId) {
193
- // Turn off subtitles
194
- setSubtitlesEnabled(false)
195
- setCurrentTrackId(null)
196
- setCurrentSubtitle("")
197
- return
198
- }
199
-
200
- const track = subtitleTracks.find((t) => t.id === trackId)
201
- if (track?.src) {
202
- setCurrentTrackId(trackId)
203
- loadSubtitles(track.src)
204
- setSubtitlesEnabled(true)
205
- }
206
- }
207
-
208
- // Change subtitle font size
209
- const changeSubtitleFontSize = (size: "small" | "medium" | "large") => {
210
- setFontSize(size)
211
- }
212
-
213
- // Get CSS classes for subtitle display
214
- const getSubtitleStyles = {
215
- fontSize: sizeMap[fontSize],
216
- className: `${sizeMap[fontSize]} font-medium`
217
- }
218
-
219
- // Clear subtitle on disable
220
- useEffect(() => {
221
- if (!subtitlesEnabled) {
222
- setCurrentSubtitle("")
223
- }
224
- }, [subtitlesEnabled])
225
-
226
- // Auto-load default subtitles on mount if available
227
- useEffect(() => {
228
- if (subtitleSrc && !subtitleCues.length && !loadError && !isLoading) {
229
- // Don't auto-load, wait for user to enable
230
- // This prevents errors on initial load
231
- }
232
- }, [])
233
-
234
- return {
235
- // State
236
- subtitlesEnabled,
237
- currentSubtitle,
238
- subtitleCues,
239
- currentTrackId,
240
- fontSize,
241
- loadError,
242
- isLoading,
243
- hasSubtitles,
244
-
245
- // Actions
246
- toggleSubtitles,
247
- selectSubtitleTrack,
248
- changeSubtitleFontSize,
249
- setCurrentSubtitle,
250
-
251
- // Utilities
252
- getCurrentSubtitle,
253
- getSubtitleStyles,
254
-
255
- // Track info
256
- availableTracks: subtitleTracks
257
- }
258
- }