@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.
- package/lib/module/AdsPlayer/store/adsPlayerStore.js +3 -3
- package/lib/module/AdsPlayer/store/adsPlayerStore.js.map +1 -1
- package/lib/module/VideoPlayer/store/videoPlayerStore.js +3 -3
- package/lib/module/VideoPlayer/store/videoPlayerStore.js.map +1 -1
- package/lib/typescript/src/AdsPlayer/store/adsPlayerStore.d.ts +2 -3
- package/lib/typescript/src/AdsPlayer/store/adsPlayerStore.d.ts.map +1 -1
- package/lib/typescript/src/VideoPlayer/store/videoPlayerStore.d.ts +2 -3
- package/lib/typescript/src/VideoPlayer/store/videoPlayerStore.d.ts.map +1 -1
- package/package.json +5 -3
- package/src/AdsPlayer/AdsPlayer.tsx +0 -311
- package/src/AdsPlayer/MediaControls/AdBottomControls.tsx +0 -191
- package/src/AdsPlayer/MediaControls/AdMediaControls.tsx +0 -104
- package/src/AdsPlayer/MediaControls/AdMediaControlsProvider.tsx +0 -62
- package/src/AdsPlayer/MediaControls/AdMiddleControls.tsx +0 -63
- package/src/AdsPlayer/MediaControls/AdTopControls.tsx +0 -191
- package/src/AdsPlayer/MediaControls/index.ts +0 -5
- package/src/AdsPlayer/components/RotatingLoader.tsx +0 -79
- package/src/AdsPlayer/index.ts +0 -4
- package/src/AdsPlayer/store/adsPlayer.type.ts +0 -29
- package/src/AdsPlayer/store/adsPlayerStore.ts +0 -59
- package/src/AdsPlayer/store/index.ts +0 -2
- package/src/AdsPlayer/utils/adStateReset.ts +0 -29
- package/src/AdsPlayer/utils/controls.ts +0 -69
- package/src/AdsPlayer/utils/useAdControlsAutoHide.ts +0 -32
- package/src/AdsPlayer/utils/useAdInitialization.ts +0 -86
- package/src/AdsPlayer/utils/useAdTracking.ts +0 -89
- package/src/AdsPlayer/utils/useAdsManager.ts +0 -215
- package/src/VideoPlayer/MediaControls/BottomControls.tsx +0 -210
- package/src/VideoPlayer/MediaControls/MediaControls.tsx +0 -30
- package/src/VideoPlayer/MediaControls/MediaControlsProvider.tsx +0 -104
- package/src/VideoPlayer/MediaControls/MiddleControls.tsx +0 -259
- package/src/VideoPlayer/MediaControls/TopControls.tsx +0 -100
- package/src/VideoPlayer/Settings/AudioAndSubtitles.tsx +0 -295
- package/src/VideoPlayer/Settings/Episodes.tsx +0 -297
- package/src/VideoPlayer/Settings/SettingModal.tsx +0 -127
- package/src/VideoPlayer/Settings/SpeedControls.tsx +0 -130
- package/src/VideoPlayer/Settings/VideoPlayerSettings.tsx +0 -141
- package/src/VideoPlayer/VideoPlayerCore.tsx +0 -356
- package/src/VideoPlayer/components/ProgressBar.tsx +0 -211
- package/src/VideoPlayer/components/SkipAndNextControls.tsx +0 -192
- package/src/VideoPlayer/components/SubtitleView.tsx +0 -53
- package/src/VideoPlayer/components/Toast.tsx +0 -61
- package/src/VideoPlayer/context/VideoPlayerConfig.tsx +0 -65
- package/src/VideoPlayer/context/index.ts +0 -5
- package/src/VideoPlayer/index.ts +0 -4
- package/src/VideoPlayer/store/index.ts +0 -2
- package/src/VideoPlayer/store/videoPlayer.type.ts +0 -214
- package/src/VideoPlayer/store/videoPlayerStore.ts +0 -97
- package/src/VideoPlayer/styles/globalStyles.ts +0 -73
- package/src/VideoPlayer/utils/display/Display.ts +0 -10
- package/src/VideoPlayer/utils/display/index.ts +0 -1
- package/src/VideoPlayer/utils/format/index.ts +0 -1
- package/src/VideoPlayer/utils/format/timeFormatter.ts +0 -44
- package/src/VideoPlayer/utils/hooks/index.ts +0 -5
- package/src/VideoPlayer/utils/hooks/useAdEventHandler.ts +0 -95
- package/src/VideoPlayer/utils/hooks/useOrientationLock.ts +0 -29
- package/src/VideoPlayer/utils/hooks/usePauseVideoOnAd.ts +0 -46
- package/src/VideoPlayer/utils/hooks/useVideoPlayerBack.ts +0 -66
- package/src/VideoPlayer/utils/hooks/useVideoResolutions.ts +0 -125
- package/src/VideoPlayer/utils/index.ts +0 -6
- package/src/VideoPlayer/utils/platform/PlatformSelector.ts +0 -13
- package/src/VideoPlayer/utils/platform/index.ts +0 -2
- package/src/VideoPlayer/utils/platform/lockOrientation.ts +0 -40
- package/src/VideoPlayer/utils/player/index.ts +0 -2
- package/src/VideoPlayer/utils/player/playerEvents.ts +0 -97
- package/src/VideoPlayer/utils/player/useWatchReporter.ts +0 -105
- package/src/VideoPlayer/utils/video/index.ts +0 -5
- package/src/VideoPlayer/utils/video/videoControl.ts +0 -185
- package/src/VideoPlayer/utils/video/videoRef.ts +0 -21
- package/src/VideoPlayer/utils/video/videoResume.ts +0 -23
- package/src/VideoPlayer/utils/video/videoSource.ts +0 -23
- package/src/VideoPlayer.tsx +0 -181
- package/src/index.tsx +0 -3
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { memo } from 'react';
|
|
2
|
-
import { StyleSheet, View } from 'react-native';
|
|
3
|
-
import TopControls from './TopControls';
|
|
4
|
-
import MiddleControls from './MiddleControls';
|
|
5
|
-
import BottomControls from './BottomControls';
|
|
6
|
-
|
|
7
|
-
export type MediaControlsProps = {
|
|
8
|
-
onClose?: () => void;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const MediaControls: React.FC<MediaControlsProps> = ({ onClose }) => {
|
|
12
|
-
return (
|
|
13
|
-
<View style={styles.container}>
|
|
14
|
-
<TopControls onClose={onClose} />
|
|
15
|
-
<MiddleControls />
|
|
16
|
-
<BottomControls />
|
|
17
|
-
</View>
|
|
18
|
-
);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export default memo(MediaControls);
|
|
22
|
-
|
|
23
|
-
const styles = StyleSheet.create({
|
|
24
|
-
container: {
|
|
25
|
-
flex: 1,
|
|
26
|
-
flexDirection: 'column',
|
|
27
|
-
justifyContent: 'space-between',
|
|
28
|
-
minHeight: 0,
|
|
29
|
-
},
|
|
30
|
-
});
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useRef, useMemo } from 'react';
|
|
2
|
-
import { TouchableOpacity, View, type ViewStyle, Animated } from 'react-native';
|
|
3
|
-
import { type EdgeInsets } from 'react-native-safe-area-context';
|
|
4
|
-
import { moderateScale } from 'react-native-size-matters';
|
|
5
|
-
import MediaControls, { type MediaControlsProps } from './MediaControls';
|
|
6
|
-
import SettingModal from '../Settings/SettingModal';
|
|
7
|
-
import { useVideoPlayerStore } from '../store/videoPlayerStore';
|
|
8
|
-
import SkipAndNextControls from '../components/SkipAndNextControls';
|
|
9
|
-
import type { MediaEpisode } from '../store/videoPlayer.type';
|
|
10
|
-
import globalStyles from '../styles/globalStyles';
|
|
11
|
-
import type { ExtendedWatchProgress } from '../utils';
|
|
12
|
-
import SubtitleView from '../components/SubtitleView';
|
|
13
|
-
|
|
14
|
-
const HORIZONTAL_PADDING = moderateScale(12);
|
|
15
|
-
const BOTTOM_PADDING_EXTRA = moderateScale(8);
|
|
16
|
-
const MIN_TOP_PADDING = moderateScale(10);
|
|
17
|
-
|
|
18
|
-
interface MediaControlsProviderProps extends MediaControlsProps {
|
|
19
|
-
children: React.ReactNode;
|
|
20
|
-
onPressEpisode: ({ episode }: { episode: MediaEpisode }) => Promise<boolean>;
|
|
21
|
-
reportProgress: (event: ExtendedWatchProgress['event']) => void;
|
|
22
|
-
insets: EdgeInsets;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const MediaControlsProvider: React.FC<MediaControlsProviderProps> = ({
|
|
26
|
-
children,
|
|
27
|
-
onClose,
|
|
28
|
-
onPressEpisode,
|
|
29
|
-
reportProgress,
|
|
30
|
-
insets,
|
|
31
|
-
}) => {
|
|
32
|
-
const { top, bottom, left, right } = insets;
|
|
33
|
-
const controlsVisible = useVideoPlayerStore((state) => state.controlsVisible);
|
|
34
|
-
const setControlsVisible = useVideoPlayerStore(
|
|
35
|
-
(state) => state.setControlsVisible
|
|
36
|
-
);
|
|
37
|
-
const controlsTimer = useVideoPlayerStore((state) => state.controlsTimer);
|
|
38
|
-
const timeoutId = React.useRef<NodeJS.Timeout | null>(null);
|
|
39
|
-
const fadeAnim = useRef(new Animated.Value(0)).current;
|
|
40
|
-
|
|
41
|
-
// Safe-area padding: never negative, single source of truth (MediaControls uses View, not SafeAreaView)
|
|
42
|
-
const containerPadding: ViewStyle = useMemo(
|
|
43
|
-
() => ({
|
|
44
|
-
paddingTop: top - MIN_TOP_PADDING,
|
|
45
|
-
paddingBottom: bottom + BOTTOM_PADDING_EXTRA,
|
|
46
|
-
paddingLeft: left + HORIZONTAL_PADDING,
|
|
47
|
-
paddingRight: right + HORIZONTAL_PADDING,
|
|
48
|
-
}),
|
|
49
|
-
[top, bottom, left, right]
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
// Memoize animated style
|
|
53
|
-
const animatedStyle = useMemo(
|
|
54
|
-
() => [globalStyles.absoluteFill, { opacity: fadeAnim }],
|
|
55
|
-
[fadeAnim]
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
Animated.timing(fadeAnim, {
|
|
60
|
-
toValue: controlsVisible ? 1 : 0,
|
|
61
|
-
duration: 200,
|
|
62
|
-
useNativeDriver: true,
|
|
63
|
-
}).start();
|
|
64
|
-
|
|
65
|
-
if (controlsVisible) {
|
|
66
|
-
timeoutId.current = setTimeout(() => {
|
|
67
|
-
setControlsVisible(false);
|
|
68
|
-
}, controlsTimer * 1000);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return () => {
|
|
72
|
-
if (timeoutId.current) clearTimeout(timeoutId.current);
|
|
73
|
-
};
|
|
74
|
-
}, [controlsVisible, controlsTimer, setControlsVisible, fadeAnim]);
|
|
75
|
-
|
|
76
|
-
return (
|
|
77
|
-
<View style={globalStyles.flexOne}>
|
|
78
|
-
{children}
|
|
79
|
-
<Animated.View
|
|
80
|
-
pointerEvents={controlsVisible ? 'auto' : 'none'}
|
|
81
|
-
style={animatedStyle}
|
|
82
|
-
>
|
|
83
|
-
<TouchableOpacity
|
|
84
|
-
onPress={() => setControlsVisible(false)}
|
|
85
|
-
style={[globalStyles.controlsContainer, containerPadding]}
|
|
86
|
-
activeOpacity={1}
|
|
87
|
-
>
|
|
88
|
-
<MediaControls onClose={onClose} />
|
|
89
|
-
</TouchableOpacity>
|
|
90
|
-
</Animated.View>
|
|
91
|
-
<SettingModal
|
|
92
|
-
onPressEpisode={onPressEpisode}
|
|
93
|
-
reportProgress={reportProgress}
|
|
94
|
-
/>
|
|
95
|
-
<SubtitleView />
|
|
96
|
-
<SkipAndNextControls
|
|
97
|
-
onPressEpisode={onPressEpisode}
|
|
98
|
-
reportProgress={reportProgress}
|
|
99
|
-
/>
|
|
100
|
-
</View>
|
|
101
|
-
);
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
export default MediaControlsProvider;
|
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import React, { useState, useRef, useMemo } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
StyleSheet,
|
|
4
|
-
Text,
|
|
5
|
-
TouchableOpacity,
|
|
6
|
-
View,
|
|
7
|
-
Animated,
|
|
8
|
-
Easing,
|
|
9
|
-
} from 'react-native';
|
|
10
|
-
import { moderateScale, scale } from 'react-native-size-matters';
|
|
11
|
-
import { RFValue } from 'react-native-responsive-fontsize';
|
|
12
|
-
import { Play, Pause, RotateCcw, RotateCw } from 'lucide-react-native';
|
|
13
|
-
|
|
14
|
-
import { useVideoPlayerStore } from '../store/videoPlayerStore';
|
|
15
|
-
import { videoRef } from '../utils';
|
|
16
|
-
import { handlePause } from '../utils';
|
|
17
|
-
import { useVideoPlayerConfig } from '../context';
|
|
18
|
-
import RotatingLoader from '../../AdsPlayer/components/RotatingLoader';
|
|
19
|
-
import globalStyles from '../styles/globalStyles';
|
|
20
|
-
|
|
21
|
-
const BUTTON_SIZE = moderateScale(80);
|
|
22
|
-
const SMALL_BUTTON_SIZE = moderateScale(60);
|
|
23
|
-
const FEEDBACK_DURATION = 500;
|
|
24
|
-
const MOVE_DISTANCE = 60;
|
|
25
|
-
const SKIP_INCREMENT = 10;
|
|
26
|
-
|
|
27
|
-
type SkipButtonProps = {
|
|
28
|
-
direction: 'forward' | 'backward';
|
|
29
|
-
onPress: ({ second }: { second: number }) => void;
|
|
30
|
-
colors: { text: string };
|
|
31
|
-
disabled?: boolean;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const MiddleControls: React.FC = () => {
|
|
35
|
-
const {
|
|
36
|
-
isPaused,
|
|
37
|
-
isBuffering,
|
|
38
|
-
setStartWatchTime,
|
|
39
|
-
error,
|
|
40
|
-
setIsPaused,
|
|
41
|
-
duration,
|
|
42
|
-
currentTime,
|
|
43
|
-
setCurrentTime,
|
|
44
|
-
} = useVideoPlayerStore();
|
|
45
|
-
|
|
46
|
-
const { colors } = useVideoPlayerConfig();
|
|
47
|
-
|
|
48
|
-
const isVideoEnded = duration > 0 && currentTime >= duration;
|
|
49
|
-
|
|
50
|
-
const handleSkip = (delta: number) => {
|
|
51
|
-
let newTime = currentTime + delta;
|
|
52
|
-
if (newTime < 0) newTime = 0;
|
|
53
|
-
if (newTime > duration) newTime = duration;
|
|
54
|
-
|
|
55
|
-
videoRef?.current?.seek(newTime);
|
|
56
|
-
setCurrentTime(newTime);
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const handlePlayPause = () => {
|
|
60
|
-
if (isVideoEnded) {
|
|
61
|
-
videoRef.current?.seek(0);
|
|
62
|
-
setCurrentTime(0);
|
|
63
|
-
setIsPaused(false);
|
|
64
|
-
setStartWatchTime(Date.now());
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (!isPaused) {
|
|
69
|
-
handlePause();
|
|
70
|
-
setIsPaused(true);
|
|
71
|
-
} else {
|
|
72
|
-
setIsPaused(false);
|
|
73
|
-
setStartWatchTime(Date.now());
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// Memoize container style
|
|
78
|
-
const containerStyle = useMemo(
|
|
79
|
-
() => [globalStyles.absoluteFill, styles.container],
|
|
80
|
-
[]
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
if (error) {
|
|
84
|
-
return (
|
|
85
|
-
<View style={containerStyle}>
|
|
86
|
-
<Text style={[styles.errorText, { color: colors.text }]}>{error}</Text>
|
|
87
|
-
</View>
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return (
|
|
92
|
-
<View style={containerStyle}>
|
|
93
|
-
<SkipButton
|
|
94
|
-
direction="backward"
|
|
95
|
-
onPress={({ second }) => handleSkip(-second)}
|
|
96
|
-
colors={colors}
|
|
97
|
-
disabled={currentTime <= 0}
|
|
98
|
-
/>
|
|
99
|
-
|
|
100
|
-
{isBuffering ? (
|
|
101
|
-
<View style={[styles.button, styles.playButton]}>
|
|
102
|
-
<RotatingLoader
|
|
103
|
-
color={colors.text}
|
|
104
|
-
autoRotate={isBuffering}
|
|
105
|
-
size={scale(50)}
|
|
106
|
-
/>
|
|
107
|
-
</View>
|
|
108
|
-
) : (
|
|
109
|
-
<TouchableOpacity
|
|
110
|
-
onPress={handlePlayPause}
|
|
111
|
-
style={[styles.button, styles.playButton]}
|
|
112
|
-
activeOpacity={0.8}
|
|
113
|
-
>
|
|
114
|
-
{isPaused ? (
|
|
115
|
-
<Play size={scale(50)} color={colors.text} />
|
|
116
|
-
) : (
|
|
117
|
-
<Pause size={scale(50)} color={colors.text} />
|
|
118
|
-
)}
|
|
119
|
-
</TouchableOpacity>
|
|
120
|
-
)}
|
|
121
|
-
|
|
122
|
-
<SkipButton
|
|
123
|
-
direction="forward"
|
|
124
|
-
onPress={({ second }) => handleSkip(second)}
|
|
125
|
-
colors={colors}
|
|
126
|
-
disabled={currentTime >= duration}
|
|
127
|
-
/>
|
|
128
|
-
</View>
|
|
129
|
-
);
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
export default MiddleControls;
|
|
133
|
-
|
|
134
|
-
const SkipButton: React.FC<SkipButtonProps> = ({
|
|
135
|
-
direction,
|
|
136
|
-
onPress,
|
|
137
|
-
colors,
|
|
138
|
-
disabled,
|
|
139
|
-
}) => {
|
|
140
|
-
const [step, setStep] = useState(0);
|
|
141
|
-
const anim = useRef(new Animated.Value(0)).current;
|
|
142
|
-
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
143
|
-
|
|
144
|
-
const handlePress = () => {
|
|
145
|
-
if (disabled) return;
|
|
146
|
-
|
|
147
|
-
const newStep = step + SKIP_INCREMENT;
|
|
148
|
-
setStep(newStep);
|
|
149
|
-
onPress({ second: newStep });
|
|
150
|
-
|
|
151
|
-
anim.setValue(0);
|
|
152
|
-
Animated.timing(anim, {
|
|
153
|
-
toValue: 1,
|
|
154
|
-
duration: FEEDBACK_DURATION,
|
|
155
|
-
easing: Easing.out(Easing.quad),
|
|
156
|
-
useNativeDriver: true,
|
|
157
|
-
}).start();
|
|
158
|
-
|
|
159
|
-
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
160
|
-
timeoutRef.current = setTimeout(() => setStep(0), FEEDBACK_DURATION);
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
const translateX = anim.interpolate({
|
|
164
|
-
inputRange: [0, 1],
|
|
165
|
-
outputRange:
|
|
166
|
-
direction === 'forward'
|
|
167
|
-
? [SMALL_BUTTON_SIZE, SMALL_BUTTON_SIZE + MOVE_DISTANCE]
|
|
168
|
-
: [-SMALL_BUTTON_SIZE, -SMALL_BUTTON_SIZE - MOVE_DISTANCE],
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
const opacity = anim.interpolate({
|
|
172
|
-
inputRange: [0, 0.8, 1],
|
|
173
|
-
outputRange: [1, 1, 0],
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
const scaleAnim = anim.interpolate({
|
|
177
|
-
inputRange: [0, 0.5, 1],
|
|
178
|
-
outputRange: [1, 1.3, 1],
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
return (
|
|
182
|
-
<TouchableOpacity
|
|
183
|
-
onPress={handlePress}
|
|
184
|
-
style={[
|
|
185
|
-
styles.button,
|
|
186
|
-
styles.smallButton,
|
|
187
|
-
disabled && styles.disabledButton,
|
|
188
|
-
]}
|
|
189
|
-
activeOpacity={disabled ? 1 : 0.7}
|
|
190
|
-
disabled={disabled}
|
|
191
|
-
>
|
|
192
|
-
{/* Skip Icon */}
|
|
193
|
-
{direction === 'forward' ? (
|
|
194
|
-
<RotateCw size={scale(35)} color={colors.text} />
|
|
195
|
-
) : (
|
|
196
|
-
<RotateCcw size={scale(35)} color={colors.text} />
|
|
197
|
-
)}
|
|
198
|
-
|
|
199
|
-
{/* Skip Duration Feedback */}
|
|
200
|
-
{step > 0 && !disabled && (
|
|
201
|
-
<Animated.View
|
|
202
|
-
style={[
|
|
203
|
-
styles.feedbackOverlay,
|
|
204
|
-
{
|
|
205
|
-
transform: [{ translateX }, { scale: scaleAnim }],
|
|
206
|
-
opacity,
|
|
207
|
-
},
|
|
208
|
-
]}
|
|
209
|
-
>
|
|
210
|
-
<Text style={[styles.feedbackText, { color: colors.text }]}>
|
|
211
|
-
{step}s
|
|
212
|
-
</Text>
|
|
213
|
-
</Animated.View>
|
|
214
|
-
)}
|
|
215
|
-
</TouchableOpacity>
|
|
216
|
-
);
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
const styles = StyleSheet.create({
|
|
220
|
-
container: {
|
|
221
|
-
flex: 1,
|
|
222
|
-
flexDirection: 'row',
|
|
223
|
-
justifyContent: 'center',
|
|
224
|
-
alignItems: 'center',
|
|
225
|
-
},
|
|
226
|
-
button: {
|
|
227
|
-
justifyContent: 'center',
|
|
228
|
-
alignItems: 'center',
|
|
229
|
-
borderRadius: 100,
|
|
230
|
-
},
|
|
231
|
-
playButton: {
|
|
232
|
-
width: BUTTON_SIZE,
|
|
233
|
-
height: BUTTON_SIZE,
|
|
234
|
-
marginHorizontal: moderateScale(14),
|
|
235
|
-
},
|
|
236
|
-
smallButton: {
|
|
237
|
-
width: SMALL_BUTTON_SIZE,
|
|
238
|
-
height: SMALL_BUTTON_SIZE,
|
|
239
|
-
marginHorizontal: moderateScale(10),
|
|
240
|
-
},
|
|
241
|
-
disabledButton: {
|
|
242
|
-
opacity: 0.3,
|
|
243
|
-
},
|
|
244
|
-
errorText: {
|
|
245
|
-
fontSize: RFValue(18),
|
|
246
|
-
fontWeight: '600',
|
|
247
|
-
textAlign: 'center',
|
|
248
|
-
paddingHorizontal: scale(20),
|
|
249
|
-
},
|
|
250
|
-
feedbackOverlay: {
|
|
251
|
-
position: 'absolute',
|
|
252
|
-
justifyContent: 'center',
|
|
253
|
-
alignItems: 'center',
|
|
254
|
-
},
|
|
255
|
-
feedbackText: {
|
|
256
|
-
fontSize: RFValue(15),
|
|
257
|
-
fontWeight: '600',
|
|
258
|
-
},
|
|
259
|
-
});
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
|
|
3
|
-
import { moderateScale } from 'react-native-size-matters';
|
|
4
|
-
import { RFValue } from 'react-native-responsive-fontsize';
|
|
5
|
-
import { X } from 'lucide-react-native';
|
|
6
|
-
import { lockToPortrait } from '../utils';
|
|
7
|
-
import { useVideoPlayerConfig } from '../context';
|
|
8
|
-
import { useVideoPlayerStore } from '../store/videoPlayerStore';
|
|
9
|
-
|
|
10
|
-
interface TopControlsProps {
|
|
11
|
-
onClose?: () => void;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const TopControls: React.FC<TopControlsProps> = ({ onClose }) => {
|
|
15
|
-
const { activeTrack } = useVideoPlayerStore();
|
|
16
|
-
const { colors } = useVideoPlayerConfig();
|
|
17
|
-
const handleClose = () => {
|
|
18
|
-
// onClose already handles reportProgress and store reset in VideoPlayerCore
|
|
19
|
-
onClose?.();
|
|
20
|
-
lockToPortrait();
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const showSubtitle =
|
|
24
|
-
activeTrack?.isTrailer ||
|
|
25
|
-
activeTrack?.seasonNumber !== undefined ||
|
|
26
|
-
activeTrack?.episodeNumber !== undefined;
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<View style={styles.container}>
|
|
30
|
-
<View style={styles.textContainer}>
|
|
31
|
-
<Text
|
|
32
|
-
numberOfLines={1}
|
|
33
|
-
ellipsizeMode="tail"
|
|
34
|
-
style={[styles.title, { color: colors.text }]}
|
|
35
|
-
>
|
|
36
|
-
{activeTrack?.title || 'Unknown'}
|
|
37
|
-
</Text>
|
|
38
|
-
{showSubtitle && (
|
|
39
|
-
<Text style={[styles.subtitle, { color: colors.text }]}>
|
|
40
|
-
{activeTrack?.isTrailer
|
|
41
|
-
? 'Trailer'
|
|
42
|
-
: `${
|
|
43
|
-
activeTrack?.seasonNumber
|
|
44
|
-
? `S${activeTrack.seasonNumber} `
|
|
45
|
-
: ''
|
|
46
|
-
}${
|
|
47
|
-
activeTrack?.episodeNumber
|
|
48
|
-
? `E${activeTrack.episodeNumber}`
|
|
49
|
-
: ''
|
|
50
|
-
}`}
|
|
51
|
-
</Text>
|
|
52
|
-
)}
|
|
53
|
-
</View>
|
|
54
|
-
|
|
55
|
-
<TouchableOpacity
|
|
56
|
-
style={styles.closeButton}
|
|
57
|
-
onPress={handleClose}
|
|
58
|
-
accessibilityRole="button"
|
|
59
|
-
accessibilityLabel="Close player"
|
|
60
|
-
accessibilityHint="Closes the video player and exits"
|
|
61
|
-
>
|
|
62
|
-
<X size={moderateScale(25)} color={colors.text} />
|
|
63
|
-
</TouchableOpacity>
|
|
64
|
-
</View>
|
|
65
|
-
);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export default TopControls;
|
|
69
|
-
|
|
70
|
-
const styles = StyleSheet.create({
|
|
71
|
-
container: {
|
|
72
|
-
flexDirection: 'row',
|
|
73
|
-
justifyContent: 'space-between',
|
|
74
|
-
alignItems: 'center',
|
|
75
|
-
paddingHorizontal: moderateScale(16),
|
|
76
|
-
paddingVertical: moderateScale(8),
|
|
77
|
-
zIndex: 51,
|
|
78
|
-
},
|
|
79
|
-
textContainer: {
|
|
80
|
-
flex: 1,
|
|
81
|
-
minWidth: 0,
|
|
82
|
-
paddingRight: moderateScale(10),
|
|
83
|
-
},
|
|
84
|
-
title: {
|
|
85
|
-
fontSize: RFValue(18),
|
|
86
|
-
fontWeight: '600',
|
|
87
|
-
},
|
|
88
|
-
subtitle: {
|
|
89
|
-
fontSize: RFValue(14),
|
|
90
|
-
fontWeight: '400',
|
|
91
|
-
marginTop: moderateScale(2),
|
|
92
|
-
},
|
|
93
|
-
closeButton: {
|
|
94
|
-
width: moderateScale(40),
|
|
95
|
-
height: moderateScale(40),
|
|
96
|
-
justifyContent: 'center',
|
|
97
|
-
alignItems: 'center',
|
|
98
|
-
borderRadius: moderateScale(20),
|
|
99
|
-
},
|
|
100
|
-
});
|