@zezosoft/zezo-ott-react-native-video-player 1.0.4 → 1.0.6

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 (73) hide show
  1. package/lib/module/AdsPlayer/store/adsPlayerStore.js +3 -3
  2. package/lib/module/AdsPlayer/store/adsPlayerStore.js.map +1 -1
  3. package/lib/module/VideoPlayer/store/videoPlayerStore.js +3 -3
  4. package/lib/module/VideoPlayer/store/videoPlayerStore.js.map +1 -1
  5. package/lib/typescript/src/AdsPlayer/store/adsPlayerStore.d.ts +2 -3
  6. package/lib/typescript/src/AdsPlayer/store/adsPlayerStore.d.ts.map +1 -1
  7. package/lib/typescript/src/VideoPlayer/store/videoPlayerStore.d.ts +2 -3
  8. package/lib/typescript/src/VideoPlayer/store/videoPlayerStore.d.ts.map +1 -1
  9. package/package.json +5 -3
  10. package/src/AdsPlayer/AdsPlayer.tsx +0 -311
  11. package/src/AdsPlayer/MediaControls/AdBottomControls.tsx +0 -191
  12. package/src/AdsPlayer/MediaControls/AdMediaControls.tsx +0 -104
  13. package/src/AdsPlayer/MediaControls/AdMediaControlsProvider.tsx +0 -62
  14. package/src/AdsPlayer/MediaControls/AdMiddleControls.tsx +0 -63
  15. package/src/AdsPlayer/MediaControls/AdTopControls.tsx +0 -191
  16. package/src/AdsPlayer/MediaControls/index.ts +0 -5
  17. package/src/AdsPlayer/components/RotatingLoader.tsx +0 -79
  18. package/src/AdsPlayer/index.ts +0 -4
  19. package/src/AdsPlayer/store/adsPlayer.type.ts +0 -29
  20. package/src/AdsPlayer/store/adsPlayerStore.ts +0 -59
  21. package/src/AdsPlayer/store/index.ts +0 -2
  22. package/src/AdsPlayer/utils/adStateReset.ts +0 -29
  23. package/src/AdsPlayer/utils/controls.ts +0 -69
  24. package/src/AdsPlayer/utils/useAdControlsAutoHide.ts +0 -32
  25. package/src/AdsPlayer/utils/useAdInitialization.ts +0 -86
  26. package/src/AdsPlayer/utils/useAdTracking.ts +0 -89
  27. package/src/AdsPlayer/utils/useAdsManager.ts +0 -215
  28. package/src/VideoPlayer/MediaControls/BottomControls.tsx +0 -210
  29. package/src/VideoPlayer/MediaControls/MediaControls.tsx +0 -30
  30. package/src/VideoPlayer/MediaControls/MediaControlsProvider.tsx +0 -104
  31. package/src/VideoPlayer/MediaControls/MiddleControls.tsx +0 -259
  32. package/src/VideoPlayer/MediaControls/TopControls.tsx +0 -100
  33. package/src/VideoPlayer/Settings/AudioAndSubtitles.tsx +0 -295
  34. package/src/VideoPlayer/Settings/Episodes.tsx +0 -297
  35. package/src/VideoPlayer/Settings/SettingModal.tsx +0 -127
  36. package/src/VideoPlayer/Settings/SpeedControls.tsx +0 -130
  37. package/src/VideoPlayer/Settings/VideoPlayerSettings.tsx +0 -141
  38. package/src/VideoPlayer/VideoPlayerCore.tsx +0 -356
  39. package/src/VideoPlayer/components/ProgressBar.tsx +0 -211
  40. package/src/VideoPlayer/components/SkipAndNextControls.tsx +0 -192
  41. package/src/VideoPlayer/components/SubtitleView.tsx +0 -53
  42. package/src/VideoPlayer/components/Toast.tsx +0 -61
  43. package/src/VideoPlayer/context/VideoPlayerConfig.tsx +0 -65
  44. package/src/VideoPlayer/context/index.ts +0 -5
  45. package/src/VideoPlayer/index.ts +0 -4
  46. package/src/VideoPlayer/store/index.ts +0 -2
  47. package/src/VideoPlayer/store/videoPlayer.type.ts +0 -214
  48. package/src/VideoPlayer/store/videoPlayerStore.ts +0 -97
  49. package/src/VideoPlayer/styles/globalStyles.ts +0 -73
  50. package/src/VideoPlayer/utils/display/Display.ts +0 -10
  51. package/src/VideoPlayer/utils/display/index.ts +0 -1
  52. package/src/VideoPlayer/utils/format/index.ts +0 -1
  53. package/src/VideoPlayer/utils/format/timeFormatter.ts +0 -44
  54. package/src/VideoPlayer/utils/hooks/index.ts +0 -5
  55. package/src/VideoPlayer/utils/hooks/useAdEventHandler.ts +0 -95
  56. package/src/VideoPlayer/utils/hooks/useOrientationLock.ts +0 -29
  57. package/src/VideoPlayer/utils/hooks/usePauseVideoOnAd.ts +0 -46
  58. package/src/VideoPlayer/utils/hooks/useVideoPlayerBack.ts +0 -66
  59. package/src/VideoPlayer/utils/hooks/useVideoResolutions.ts +0 -125
  60. package/src/VideoPlayer/utils/index.ts +0 -6
  61. package/src/VideoPlayer/utils/platform/PlatformSelector.ts +0 -13
  62. package/src/VideoPlayer/utils/platform/index.ts +0 -2
  63. package/src/VideoPlayer/utils/platform/lockOrientation.ts +0 -40
  64. package/src/VideoPlayer/utils/player/index.ts +0 -2
  65. package/src/VideoPlayer/utils/player/playerEvents.ts +0 -97
  66. package/src/VideoPlayer/utils/player/useWatchReporter.ts +0 -105
  67. package/src/VideoPlayer/utils/video/index.ts +0 -5
  68. package/src/VideoPlayer/utils/video/videoControl.ts +0 -185
  69. package/src/VideoPlayer/utils/video/videoRef.ts +0 -21
  70. package/src/VideoPlayer/utils/video/videoResume.ts +0 -23
  71. package/src/VideoPlayer/utils/video/videoSource.ts +0 -23
  72. package/src/VideoPlayer.tsx +0 -181
  73. package/src/index.tsx +0 -3
@@ -1,295 +0,0 @@
1
- import React, { useMemo } from 'react';
2
- import {
3
- FlatList,
4
- Platform,
5
- TouchableOpacity,
6
- View,
7
- Text,
8
- StyleSheet,
9
- } from 'react-native';
10
- import { scale, verticalScale } from 'react-native-size-matters';
11
- import { RFValue } from 'react-native-responsive-fontsize';
12
- import type { OnLoadData } from 'react-native-video';
13
- import {
14
- useVideoPlayerStore,
15
- type SubtitleTrack,
16
- type TrackSelection,
17
- } from '../store';
18
- import { useVideoPlayerConfig } from '../context';
19
-
20
- const ALLOWED_SUBTITLE_TYPES = [
21
- 'application/x-subrip',
22
- 'text/vtt',
23
- 'application/ttml+xml',
24
- ];
25
-
26
- const mapSubtitleType = (mimeType: string): 'srt' | 'ttml' | 'vtt' => {
27
- switch (mimeType) {
28
- case 'application/x-subrip':
29
- return 'srt';
30
- case 'application/ttml+xml':
31
- return 'ttml';
32
- case 'text/vtt':
33
- return 'vtt';
34
- default:
35
- return 'srt';
36
- }
37
- };
38
-
39
- const Separator = () => <View style={styles.separator} />;
40
-
41
- interface AudioItemProps {
42
- item: OnLoadData['audioTracks'][0];
43
- isSelected: boolean;
44
- onPress: () => void;
45
- colors: { text: string };
46
- }
47
- const AudioItem: React.FC<AudioItemProps> = ({
48
- item,
49
- isSelected,
50
- onPress,
51
- colors,
52
- }) => (
53
- <TouchableOpacity onPress={onPress}>
54
- <Text
55
- style={[
56
- styles.listItem,
57
- { color: colors.text },
58
- isSelected && styles.selected,
59
- ]}
60
- >
61
- {item.title}
62
- </Text>
63
- </TouchableOpacity>
64
- );
65
-
66
- interface SubtitleItemProps {
67
- item: TrackSelection;
68
- isSelected: boolean;
69
- onPress: () => void;
70
- colors: { text: string };
71
- }
72
- const SubtitleItem: React.FC<SubtitleItemProps> = ({
73
- item,
74
- isSelected,
75
- onPress,
76
- colors,
77
- }) => (
78
- <TouchableOpacity onPress={onPress}>
79
- <Text
80
- style={[
81
- styles.listItem,
82
- { color: colors.text },
83
- isSelected && styles.selected,
84
- ]}
85
- >
86
- {item.title || 'Unknown'}
87
- </Text>
88
- </TouchableOpacity>
89
- );
90
-
91
- const AudioAndSubtitles: React.FC = () => {
92
- const {
93
- setSettingsModal,
94
- onLoad,
95
- setSelectedAudioTrack,
96
- setSelectedSubtitleTrack,
97
- selectedAudioTrack,
98
- selectedSubtitleTrack,
99
- setActiveSubtitle,
100
- activeTrack,
101
- activeSubtitle,
102
- setIsPaused,
103
- } = useVideoPlayerStore();
104
- const { colors } = useVideoPlayerConfig();
105
-
106
- const audioTracks = useMemo(() => {
107
- return (
108
- onLoad?.audioTracks?.filter(
109
- (item: OnLoadData['audioTracks'][0]) =>
110
- item.title !== null && item.title !== ''
111
- ) || []
112
- );
113
- }, [onLoad?.audioTracks]);
114
-
115
- const subtitleTracks = useMemo(() => {
116
- const internal =
117
- onLoad?.textTracks
118
- ?.filter((track) => {
119
- const type = String(track.type);
120
- const isCEA608 =
121
- Platform.OS === 'android' && type === 'application/cea-608';
122
- return (
123
- !isCEA608 &&
124
- ALLOWED_SUBTITLE_TYPES.includes(type) &&
125
- track.title?.trim()
126
- );
127
- })
128
- .map((track, idx) => ({
129
- index: idx,
130
- title: track.title,
131
- language: track.language,
132
- type: track.type ? mapSubtitleType(String(track.type)) : 'srt',
133
- value: idx,
134
- isExternal: false,
135
- })) || [];
136
-
137
- const external =
138
- activeTrack?.subtitles?.map((item, idx) => ({
139
- index: internal.length + idx,
140
- type: mapSubtitleType(item.type),
141
- value: internal.length + idx,
142
- language: item.language,
143
- title: item.title || item.language || `Subtitle ${idx + 1}`,
144
- uri: item.url,
145
- isExternal: true,
146
- })) || [];
147
-
148
- return [...internal, ...external];
149
- }, [activeTrack?.subtitles, onLoad?.textTracks]);
150
-
151
- const handleSelectAudio = (item: OnLoadData['audioTracks'][0]) => {
152
- setSelectedAudioTrack({
153
- type: 'index',
154
- value: item.index,
155
- isExternal: false,
156
- });
157
- setSettingsModal({ isVisible: false, action: 'none' });
158
- };
159
-
160
- const handleSelectSubtitle = (item: TrackSelection) => {
161
- if (item.isExternal) {
162
- setActiveSubtitle({
163
- type: item.type as SubtitleTrack['type'],
164
- url: item.uri!,
165
- language: item.language,
166
- title: item.title,
167
- });
168
- setSelectedSubtitleTrack({
169
- type: 'index',
170
- value: 'Off',
171
- isExternal: false,
172
- });
173
- } else {
174
- setSelectedSubtitleTrack({
175
- type: 'index',
176
- value: Number(item.value),
177
- isExternal: false,
178
- });
179
- setActiveSubtitle(null);
180
- }
181
- setIsPaused(false);
182
- setSettingsModal({ isVisible: false, action: 'none' });
183
- };
184
-
185
- const handleDisableSubtitles = () => {
186
- setSelectedSubtitleTrack({
187
- type: 'index',
188
- value: 'Off',
189
- isExternal: false,
190
- });
191
- setActiveSubtitle(null);
192
- setIsPaused(false);
193
- setSettingsModal({ isVisible: false, action: 'none' });
194
- };
195
-
196
- return (
197
- <View style={styles.container}>
198
- <View style={styles.section}>
199
- {audioTracks.length > 0 && (
200
- <>
201
- <Text style={[styles.sectionTitle, { color: colors.text }]}>
202
- Audio
203
- </Text>
204
- <FlatList
205
- data={audioTracks}
206
- keyExtractor={({ index }) => `audio-${index}`}
207
- ItemSeparatorComponent={Separator}
208
- renderItem={({ item }) => (
209
- <AudioItem
210
- item={item}
211
- isSelected={selectedAudioTrack?.value === item.index}
212
- onPress={() => handleSelectAudio(item)}
213
- colors={colors}
214
- />
215
- )}
216
- />
217
- </>
218
- )}
219
- </View>
220
-
221
- <View style={styles.section}>
222
- <Text style={[styles.sectionTitle, { color: colors.text }]}>
223
- Subtitles
224
- </Text>
225
- <TouchableOpacity onPress={handleDisableSubtitles}>
226
- <Text
227
- style={[
228
- styles.listItem,
229
- { color: colors.text },
230
- (!activeSubtitle && selectedSubtitleTrack?.value === 'Off') ||
231
- selectedSubtitleTrack === null
232
- ? styles.selected
233
- : null,
234
- ]}
235
- >
236
- Off
237
- </Text>
238
- </TouchableOpacity>
239
- <Separator />
240
- <FlatList
241
- data={subtitleTracks}
242
- keyExtractor={({ index }) => `sub-${index}`}
243
- ItemSeparatorComponent={Separator}
244
- renderItem={({ item }) => (
245
- <SubtitleItem
246
- item={item}
247
- isSelected={
248
- selectedSubtitleTrack?.value === item.index ||
249
- activeSubtitle?.language === item.language
250
- }
251
- onPress={() => handleSelectSubtitle(item)}
252
- colors={{ text: colors.text }}
253
- />
254
- )}
255
- />
256
- </View>
257
- </View>
258
- );
259
- };
260
-
261
- export default AudioAndSubtitles;
262
-
263
- const styles = StyleSheet.create({
264
- container: {
265
- flex: 1,
266
- flexDirection: 'row',
267
- padding: scale(8),
268
- gap: scale(12),
269
- },
270
- section: {
271
- flex: 1,
272
- borderRadius: scale(12),
273
- padding: scale(8),
274
- },
275
- sectionTitle: {
276
- fontSize: RFValue(20),
277
- fontWeight: '600',
278
- marginBottom: verticalScale(8),
279
- letterSpacing: 0.6,
280
- },
281
- listItem: {
282
- fontSize: RFValue(17),
283
- paddingVertical: verticalScale(4),
284
- paddingHorizontal: scale(12),
285
- borderRadius: scale(8),
286
- opacity: 0.7,
287
- },
288
- selected: {
289
- opacity: 1,
290
- fontWeight: '700',
291
- },
292
- separator: {
293
- height: verticalScale(8),
294
- },
295
- });
@@ -1,297 +0,0 @@
1
- /* eslint-disable react/no-unstable-nested-components */
2
- import {
3
- FlatList,
4
- TouchableOpacity,
5
- View,
6
- StyleSheet,
7
- Text,
8
- } from 'react-native';
9
- import React from 'react';
10
- import FastImage from 'react-native-fast-image';
11
- import { moderateScale, verticalScale } from 'react-native-size-matters';
12
- import {
13
- MenuProvider,
14
- Menu,
15
- MenuOptions,
16
- MenuOption,
17
- MenuTrigger,
18
- } from 'react-native-popup-menu';
19
- import { RFValue } from 'react-native-responsive-fontsize';
20
- import { formatDuration, getEpisodeIndex } from '../utils';
21
- import { useVideoPlayerStore } from '../store/videoPlayerStore';
22
- import { useSafeAreaInsets } from 'react-native-safe-area-context';
23
- import globalStyles from '../styles/globalStyles';
24
- import type { MediaEpisode } from '../store';
25
- import { useVideoPlayerConfig } from '../context';
26
- import type { ExtendedWatchProgress } from '../utils';
27
-
28
- type EpisodesProps = {
29
- onPressEpisode: ({ episode }: { episode: MediaEpisode }) => Promise<boolean>;
30
- reportProgress: (event: ExtendedWatchProgress['event']) => void;
31
- };
32
-
33
- const Episodes: React.FC<EpisodesProps> = ({
34
- onPressEpisode,
35
- reportProgress,
36
- }) => {
37
- const {
38
- activeSeason,
39
- activeTrack,
40
- setCurrentTrackIndex,
41
- setActiveTrack,
42
- playList,
43
- setSettingsModal,
44
- setIsPaused,
45
- contentSeasons,
46
- setActiveSeason,
47
- setSelectedSubtitleTrack,
48
- setPlayBackRate,
49
- setActiveSubtitle,
50
- setSelectedVideoTrack,
51
- setMaxBitRate,
52
- setDuration,
53
- } = useVideoPlayerStore();
54
- const { colors } = useVideoPlayerConfig();
55
- const { left } = useSafeAreaInsets();
56
-
57
- if (!activeSeason?.seasonNumber || !activeSeason?.episodes) {
58
- return (
59
- <View style={globalStyles.flexOneJustifyContentCenterAndAlignItemsCenter}>
60
- <Text style={{ color: colors.text }}>
61
- Something went wrong. Please try again.
62
- </Text>
63
- </View>
64
- );
65
- }
66
-
67
- const handleEpisodePress = async (episode: MediaEpisode) => {
68
- const isSuccess = await onPressEpisode({ episode });
69
- if (!isSuccess) return;
70
- if (episode.id === activeTrack?.episodeId) {
71
- setSettingsModal({ isVisible: false, action: 'none' });
72
- setIsPaused(false);
73
- return;
74
- }
75
- const index = getEpisodeIndex(playList, episode.id);
76
- setCurrentTrackIndex(index);
77
- setDuration(0);
78
-
79
- setActiveTrack({
80
- type: 'series',
81
- episodeId: episode.id,
82
- contentId: episode.contentId,
83
- episodeName: episode.title,
84
- episodeNumber: episode.episodeNumber,
85
- seasonNumber: activeSeason.seasonNumber ?? 0,
86
- skipIntro: episode.skipIntro ?? undefined,
87
- nextEpisodeAt: episode.nextEpisodeAt ?? undefined,
88
- sourceLink: episode.sourceLink || '',
89
- thumbnail: episode.thumbnail,
90
- subtitles: episode.subtitles || null,
91
- id: episode.id,
92
- title: episode.title,
93
- description: episode.description || '',
94
- duration: episode.duration || 0,
95
- sourceType: episode.sourceType || 'HLS',
96
- });
97
- setSelectedSubtitleTrack(null);
98
- setActiveSubtitle(null);
99
- setSelectedVideoTrack(null);
100
- setMaxBitRate(null);
101
- setSettingsModal({ isVisible: false, action: 'none' });
102
- setIsPaused(false);
103
- setPlayBackRate(1, 'Normal');
104
- };
105
-
106
- return (
107
- <MenuProvider>
108
- <View>
109
- <Menu>
110
- <MenuTrigger
111
- style={[
112
- styles.menuTrigger,
113
- { marginLeft: left + moderateScale(8) },
114
- ]}
115
- customStyles={{
116
- triggerText: {
117
- ...menuTriggerCustomStyles.triggerText,
118
- color: colors.text,
119
- },
120
- }}
121
- text={`Season ${activeSeason?.seasonNumber}`}
122
- />
123
- <MenuOptions optionsContainerStyle={styles.menuOptionsContainer}>
124
- {contentSeasons?.map((season, index) => (
125
- <MenuOption
126
- style={styles.menuOption}
127
- customStyles={menuOptionCustomStyles}
128
- key={index}
129
- onSelect={() => setActiveSeason(season)}
130
- text={`Season ${season.seasonNumber}`}
131
- />
132
- ))}
133
- </MenuOptions>
134
- </Menu>
135
-
136
- <View style={styles.episodesContainer}>
137
- <FlatList
138
- data={activeSeason?.episodes}
139
- horizontal
140
- showsHorizontalScrollIndicator={false}
141
- ItemSeparatorComponent={() => (
142
- <View style={{ width: moderateScale(12) }} />
143
- )}
144
- ListHeaderComponent={() => (
145
- <View style={{ width: left + moderateScale(8) }} />
146
- )}
147
- ListFooterComponent={() => (
148
- <View style={{ width: moderateScale(16) }} />
149
- )}
150
- renderItem={({ item }) => (
151
- <TouchableOpacity
152
- onPress={() => {
153
- reportProgress('EPISODE_CHANGE');
154
- handleEpisodePress(item);
155
- }}
156
- style={styles.episodeItem}
157
- activeOpacity={0.8}
158
- >
159
- <FastImage
160
- source={{ uri: item?.thumbnail }}
161
- style={styles.episodeThumbnail}
162
- resizeMode={FastImage.resizeMode.cover}
163
- />
164
- {item.id === activeTrack?.episodeId && (
165
- <Text
166
- style={[
167
- styles.nowPlayingBadge,
168
- { color: colors.text, backgroundColor: colors.primary },
169
- ]}
170
- >
171
- Now Playing
172
- </Text>
173
- )}
174
-
175
- {/* Episode title */}
176
- <Text
177
- numberOfLines={1}
178
- style={[styles.episodeTitle, { color: colors.text }]}
179
- >
180
- {item?.title}
181
- </Text>
182
-
183
- {/* Season & Episode Number + Duration in one row */}
184
- <View style={styles.episodeInfoRow}>
185
- <Text style={styles.episodeInfoText}>
186
- {[
187
- item.episodeNumber &&
188
- `S${String(activeSeason?.seasonNumber).padStart(
189
- 2,
190
- '0'
191
- )} E${String(item.episodeNumber).padStart(2, '0')}`,
192
- item.publishDate && `(${item.publishDate})`,
193
- item?.duration && formatDuration(item?.duration, true),
194
- ]
195
- .filter(Boolean)
196
- .join(' | ')}
197
- </Text>
198
- </View>
199
- {/* Description */}
200
- {item.description && (
201
- <Text style={styles.episodeDescription} numberOfLines={3}>
202
- {item?.description}
203
- </Text>
204
- )}
205
- </TouchableOpacity>
206
- )}
207
- keyExtractor={(item) => item?.id}
208
- />
209
- </View>
210
- </View>
211
- </MenuProvider>
212
- );
213
- };
214
-
215
- const styles = StyleSheet.create({
216
- menuTrigger: {
217
- alignSelf: 'flex-start',
218
- backgroundColor: 'gray',
219
- paddingHorizontal: moderateScale(16),
220
- paddingVertical: moderateScale(8),
221
- marginTop: verticalScale(20),
222
- borderRadius: moderateScale(8),
223
- },
224
- menuOptionsContainer: {
225
- marginTop: verticalScale(60),
226
- width: moderateScale(150),
227
- },
228
- menuOption: {
229
- paddingHorizontal: moderateScale(16),
230
- paddingVertical: moderateScale(12),
231
- },
232
- episodesContainer: {
233
- marginTop: verticalScale(20),
234
- paddingBottom: verticalScale(20),
235
- },
236
- episodeItem: {
237
- width: moderateScale(240),
238
- backgroundColor: '#373737ff',
239
- borderRadius: moderateScale(12),
240
- overflow: 'hidden',
241
- },
242
- episodeThumbnail: {
243
- width: '100%',
244
- height: undefined,
245
- aspectRatio: 16 / 9,
246
- backgroundColor: '#444', // slightly lighter fallback
247
- },
248
- nowPlayingBadge: {
249
- position: 'absolute',
250
- top: moderateScale(6),
251
- left: moderateScale(6),
252
- paddingHorizontal: moderateScale(8),
253
- paddingVertical: moderateScale(4), // slightly bigger
254
- borderRadius: moderateScale(4),
255
- fontSize: RFValue(12),
256
- fontWeight: '600',
257
- overflow: 'hidden',
258
- },
259
- episodeTitle: {
260
- fontSize: RFValue(14), // bigger
261
- fontWeight: '600', // bolder
262
- marginHorizontal: moderateScale(8),
263
- marginTop: verticalScale(3),
264
- },
265
- episodeInfoRow: {
266
- flexDirection: 'row',
267
- justifyContent: 'flex-start', // better alignment
268
- marginHorizontal: moderateScale(8),
269
- marginTop: verticalScale(2),
270
- alignItems: 'center',
271
- },
272
- episodeInfoText: {
273
- color: '#f1f1f1ff',
274
- fontSize: RFValue(10.5),
275
- },
276
- episodeDescription: {
277
- marginHorizontal: moderateScale(8),
278
- marginVertical: verticalScale(5),
279
- color: '#f1f1f1ff',
280
- fontSize: RFValue(10),
281
- lineHeight: RFValue(10),
282
- },
283
- });
284
-
285
- const menuTriggerCustomStyles = {
286
- triggerText: {
287
- fontSize: RFValue(16),
288
- },
289
- };
290
-
291
- const menuOptionCustomStyles = {
292
- optionText: {
293
- fontSize: RFValue(16),
294
- },
295
- };
296
-
297
- export default Episodes;
@@ -1,127 +0,0 @@
1
- import { StyleSheet, TouchableOpacity, View } from 'react-native';
2
- import React from 'react';
3
- import { moderateScale } from 'react-native-size-matters';
4
- import { X } from 'lucide-react-native';
5
- import { useVideoPlayerStore } from '../store/videoPlayerStore';
6
-
7
- import Episodes from './Episodes';
8
- import SpeedControls from './SpeedControls';
9
- import VideoPlayerSettings from './VideoPlayerSettings';
10
- import AudioAndSubtitles from './AudioAndSubtitles';
11
- import {
12
- useVideoResolutions,
13
- type Resolution,
14
- } from '../utils/hooks/useVideoResolutions';
15
- import type { MediaEpisode, SettingsAction } from '../store/videoPlayer.type';
16
- import { useVideoPlayerConfig } from '../context';
17
- import type { ExtendedWatchProgress } from '../utils';
18
-
19
- const VisibleAction: React.FC<{
20
- settingModalAction: SettingsAction;
21
- onPressEpisode: ({ episode }: { episode: MediaEpisode }) => Promise<boolean>;
22
- reportProgress: (event: ExtendedWatchProgress['event']) => void;
23
- resolutions?: Resolution[];
24
- }> = ({ settingModalAction, onPressEpisode, reportProgress, resolutions }) => {
25
- switch (settingModalAction) {
26
- case 'speed':
27
- return <SpeedControls />;
28
- case 'audioOrSubtitle':
29
- return <AudioAndSubtitles />;
30
- case 'settings':
31
- return <VideoPlayerSettings resolutions={resolutions || []} />;
32
- case 'episodes':
33
- return (
34
- <Episodes
35
- onPressEpisode={onPressEpisode}
36
- reportProgress={reportProgress}
37
- />
38
- );
39
- default:
40
- return null;
41
- }
42
- };
43
-
44
- type SettingModalProps = {
45
- onPressEpisode: ({ episode }: { episode: MediaEpisode }) => Promise<boolean>;
46
- reportProgress: (event: ExtendedWatchProgress['event']) => void;
47
- };
48
-
49
- const SettingModal: React.FC<SettingModalProps> = ({
50
- onPressEpisode,
51
- reportProgress,
52
- }) => {
53
- const {
54
- settingsModal,
55
- setSettingsModal,
56
- setIsPaused,
57
- setControlsVisible,
58
- activeTrack,
59
- } = useVideoPlayerStore();
60
- const { colors } = useVideoPlayerConfig();
61
- const resolutions = useVideoResolutions(activeTrack);
62
-
63
- const onClose = () => {
64
- setSettingsModal({ isVisible: false, action: 'none' });
65
- setIsPaused(false);
66
- setControlsVisible(true);
67
- };
68
-
69
- if (!settingsModal.isVisible) return null;
70
-
71
- const containerStyle =
72
- settingsModal.action === 'audioOrSubtitle'
73
- ? [styles.contentContainer, styles.audioOrSubtitlePadding]
74
- : styles.contentContainer;
75
-
76
- return (
77
- <View style={StyleSheet.absoluteFill}>
78
- {/* Dark overlay */}
79
- <View style={styles.overlay} />
80
-
81
- {/* Close button */}
82
- <TouchableOpacity onPress={onClose} style={styles.closeButton}>
83
- <X color={colors.text} size={moderateScale(25)} />
84
- </TouchableOpacity>
85
-
86
- {/* Modal content */}
87
- <View style={containerStyle}>
88
- <VisibleAction
89
- settingModalAction={settingsModal.action}
90
- resolutions={resolutions}
91
- onPressEpisode={onPressEpisode}
92
- reportProgress={reportProgress}
93
- />
94
- </View>
95
- </View>
96
- );
97
- };
98
-
99
- export default SettingModal;
100
-
101
- const styles = StyleSheet.create({
102
- overlay: {
103
- ...StyleSheet.absoluteFillObject,
104
- backgroundColor: 'rgba(0,0,0,0.9)',
105
- pointerEvents: 'none',
106
- },
107
- closeButton: {
108
- position: 'absolute',
109
- top: moderateScale(20),
110
- right: moderateScale(60),
111
- width: moderateScale(50),
112
- height: moderateScale(50),
113
- justifyContent: 'center',
114
- alignItems: 'center',
115
- borderRadius: moderateScale(50),
116
- zIndex: 10000,
117
- },
118
- contentContainer: {
119
- flex: 1,
120
- zIndex: 1000,
121
- },
122
- audioOrSubtitlePadding: {
123
- paddingLeft: moderateScale(16),
124
- paddingRight: moderateScale(16),
125
- paddingTop: moderateScale(8),
126
- },
127
- });