@zezosoft/zezo-ott-react-native-video-player 1.0.3 → 1.0.5
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/MediaControls/AdBottomControls.js +2 -2
- package/lib/module/AdsPlayer/MediaControls/AdBottomControls.js.map +1 -1
- package/package.json +1 -2
- 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,214 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type EnumValues,
|
|
3
|
-
type OnLoadData,
|
|
4
|
-
ResizeMode,
|
|
5
|
-
SelectedVideoTrackType,
|
|
6
|
-
} from 'react-native-video';
|
|
7
|
-
|
|
8
|
-
export interface BaseEntity {
|
|
9
|
-
id: string;
|
|
10
|
-
title: string;
|
|
11
|
-
contentId: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface TimeRange {
|
|
15
|
-
start: number;
|
|
16
|
-
end: number;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface SubtitleTrack {
|
|
20
|
-
title?: string;
|
|
21
|
-
language?: string;
|
|
22
|
-
type:
|
|
23
|
-
| 'application/x-subrip'
|
|
24
|
-
| 'application/ttml+xml'
|
|
25
|
-
| 'text/vtt'
|
|
26
|
-
| 'application/octet-stream';
|
|
27
|
-
url: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface MediaEpisode extends BaseEntity {
|
|
31
|
-
description: string;
|
|
32
|
-
duration: number;
|
|
33
|
-
sourceLink: string;
|
|
34
|
-
sourceType: 'HLS' | 'MP4';
|
|
35
|
-
subtitles: SubtitleTrack[];
|
|
36
|
-
thumbnail: string;
|
|
37
|
-
episodeNumber: number;
|
|
38
|
-
skipIntro?: TimeRange | null;
|
|
39
|
-
nextEpisodeAt?: number | null;
|
|
40
|
-
publishDate?: string | null;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface MediaSeason extends BaseEntity {
|
|
44
|
-
order: number;
|
|
45
|
-
seasonNumber?: number;
|
|
46
|
-
episodes: MediaEpisode[] | null;
|
|
47
|
-
isActive: boolean;
|
|
48
|
-
createdBy: string;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface MediaTrack extends BaseEntity {
|
|
52
|
-
description: string;
|
|
53
|
-
duration: number;
|
|
54
|
-
thumbnail: string;
|
|
55
|
-
type: 'movie' | 'series' | 'live_stream' | 'VERTICAL_STREAM';
|
|
56
|
-
isTrailer?: boolean;
|
|
57
|
-
sourceType: 'HLS' | 'MP4';
|
|
58
|
-
sourceLink: string;
|
|
59
|
-
trailerSource?: string | null;
|
|
60
|
-
episodeId?: string | null;
|
|
61
|
-
episodeName?: string | null;
|
|
62
|
-
episodeNumber?: number | null;
|
|
63
|
-
seasonId?: string | null;
|
|
64
|
-
seasonNumber?: number | null;
|
|
65
|
-
skipIntro?: TimeRange | null;
|
|
66
|
-
nextEpisodeAt?: number | null;
|
|
67
|
-
subtitles?: SubtitleTrack[] | null;
|
|
68
|
-
publishDate?: string | null;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export interface TrackSelection {
|
|
72
|
-
index?: number;
|
|
73
|
-
type: string;
|
|
74
|
-
value: string | number;
|
|
75
|
-
isExternal: boolean;
|
|
76
|
-
title?: string;
|
|
77
|
-
uri?: string;
|
|
78
|
-
language?: string;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export interface IosTrackResolution {
|
|
82
|
-
width: number | string | null;
|
|
83
|
-
height: number | string | null;
|
|
84
|
-
bandwidth: number;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export type SettingsAction =
|
|
88
|
-
| 'playbackRate'
|
|
89
|
-
| 'audioOrSubtitle'
|
|
90
|
-
| 'settings'
|
|
91
|
-
| 'episodes'
|
|
92
|
-
| 'speed'
|
|
93
|
-
| 'none';
|
|
94
|
-
|
|
95
|
-
export type AdPosition = 'pre' | 'mid' | 'post';
|
|
96
|
-
|
|
97
|
-
export interface AdTracking {
|
|
98
|
-
impression?: string;
|
|
99
|
-
start?: string;
|
|
100
|
-
firstQuartile?: string;
|
|
101
|
-
midpoint?: string;
|
|
102
|
-
thirdQuartile?: string;
|
|
103
|
-
complete?: string;
|
|
104
|
-
skip?: string;
|
|
105
|
-
click?: string;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export interface VideoAd {
|
|
109
|
-
id: string;
|
|
110
|
-
title: string;
|
|
111
|
-
description: string;
|
|
112
|
-
position: AdPosition;
|
|
113
|
-
source: string;
|
|
114
|
-
duration: number;
|
|
115
|
-
time?: number;
|
|
116
|
-
skippable: boolean;
|
|
117
|
-
skipAfter: number;
|
|
118
|
-
clickThroughUrl?: string;
|
|
119
|
-
tracking?: AdTracking;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
type StateSetter<T> = (value: T) => void;
|
|
123
|
-
|
|
124
|
-
export interface VideoPlayerStore {
|
|
125
|
-
currentTime: number;
|
|
126
|
-
setCurrentTime: StateSetter<number>;
|
|
127
|
-
|
|
128
|
-
duration: number;
|
|
129
|
-
setDuration: StateSetter<number>;
|
|
130
|
-
|
|
131
|
-
isPaused: boolean;
|
|
132
|
-
setIsPaused: StateSetter<boolean>;
|
|
133
|
-
|
|
134
|
-
isBuffering: boolean;
|
|
135
|
-
setIsBuffering: StateSetter<boolean>;
|
|
136
|
-
|
|
137
|
-
resizeMode: EnumValues<ResizeMode>;
|
|
138
|
-
setResizeMode: StateSetter<EnumValues<ResizeMode>>;
|
|
139
|
-
|
|
140
|
-
playableDuration: number;
|
|
141
|
-
setPlayableDuration: StateSetter<number>;
|
|
142
|
-
|
|
143
|
-
onLoad: OnLoadData | null;
|
|
144
|
-
setOnLoad: StateSetter<OnLoadData>;
|
|
145
|
-
|
|
146
|
-
error: string | null;
|
|
147
|
-
setError: StateSetter<string | null>;
|
|
148
|
-
|
|
149
|
-
playBackRate: number;
|
|
150
|
-
playBackRateLabel: string | null;
|
|
151
|
-
setPlayBackRate: (rate: number, label: string) => void;
|
|
152
|
-
|
|
153
|
-
controlsVisible: boolean;
|
|
154
|
-
setControlsVisible: StateSetter<boolean>;
|
|
155
|
-
|
|
156
|
-
controlsTimer: number;
|
|
157
|
-
setControlsTimer: StateSetter<number>;
|
|
158
|
-
|
|
159
|
-
selectedAudioTrack: TrackSelection | null;
|
|
160
|
-
setSelectedAudioTrack: StateSetter<TrackSelection | null>;
|
|
161
|
-
|
|
162
|
-
selectedSubtitleTrack: TrackSelection | null;
|
|
163
|
-
setSelectedSubtitleTrack: StateSetter<TrackSelection | null>;
|
|
164
|
-
|
|
165
|
-
selectedVideoTrack: { type: SelectedVideoTrackType; value: number } | null;
|
|
166
|
-
setSelectedVideoTrack: StateSetter<{
|
|
167
|
-
type: SelectedVideoTrackType;
|
|
168
|
-
value: number;
|
|
169
|
-
} | null>;
|
|
170
|
-
|
|
171
|
-
activeSubtitle: SubtitleTrack | null;
|
|
172
|
-
setActiveSubtitle: StateSetter<SubtitleTrack | null>;
|
|
173
|
-
|
|
174
|
-
activeTrack: MediaTrack | null;
|
|
175
|
-
setActiveTrack: StateSetter<MediaTrack | null>;
|
|
176
|
-
|
|
177
|
-
playList: MediaTrack[];
|
|
178
|
-
setPlayList: StateSetter<MediaTrack[]>;
|
|
179
|
-
|
|
180
|
-
currentTrackIndex: number;
|
|
181
|
-
setCurrentTrackIndex: StateSetter<number>;
|
|
182
|
-
|
|
183
|
-
contentSeasons: MediaSeason[] | null;
|
|
184
|
-
setContentSeasons: StateSetter<MediaSeason[] | null>;
|
|
185
|
-
|
|
186
|
-
activeSeason: MediaSeason | null;
|
|
187
|
-
setActiveSeason: StateSetter<MediaSeason | null>;
|
|
188
|
-
|
|
189
|
-
settingsModal: {
|
|
190
|
-
isVisible: boolean;
|
|
191
|
-
action: SettingsAction;
|
|
192
|
-
};
|
|
193
|
-
setSettingsModal: StateSetter<{
|
|
194
|
-
isVisible: boolean;
|
|
195
|
-
action: SettingsAction;
|
|
196
|
-
}>;
|
|
197
|
-
|
|
198
|
-
maxBitRate: number | null;
|
|
199
|
-
setMaxBitRate: StateSetter<number | null>;
|
|
200
|
-
|
|
201
|
-
startWatchTime: number | null;
|
|
202
|
-
setStartWatchTime: StateSetter<number | null>;
|
|
203
|
-
|
|
204
|
-
isViewCounted: boolean;
|
|
205
|
-
setIsViewCounted: StateSetter<boolean>;
|
|
206
|
-
|
|
207
|
-
isSkipIntroVisible: boolean;
|
|
208
|
-
setIsSkipIntroVisible: StateSetter<boolean>;
|
|
209
|
-
|
|
210
|
-
isNextEpisodeVisible: boolean;
|
|
211
|
-
setIsNextEpisodeVisible: StateSetter<boolean>;
|
|
212
|
-
|
|
213
|
-
resetStore: () => void;
|
|
214
|
-
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { create } from 'zustand';
|
|
2
|
-
import { createJSONStorage, persist } from 'zustand/middleware';
|
|
3
|
-
import { MMKV } from 'react-native-mmkv';
|
|
4
|
-
import { ResizeMode, type EnumValues } from 'react-native-video';
|
|
5
|
-
import type { SettingsAction, VideoPlayerStore } from './videoPlayer.type';
|
|
6
|
-
|
|
7
|
-
export const storage = new MMKV({
|
|
8
|
-
id: 'videoPlayerStorage',
|
|
9
|
-
encryptionKey: 'videoPlayerKey',
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
export const mmkvStorage = {
|
|
13
|
-
setItem: (key: string, value: string) => storage.set(key, value),
|
|
14
|
-
getItem: (key: string) => storage.getString(key) ?? null,
|
|
15
|
-
removeItem: (key: string) => storage.delete(key),
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const storeDataDefaults = {
|
|
19
|
-
currentTime: 0,
|
|
20
|
-
duration: 0,
|
|
21
|
-
isPaused: false,
|
|
22
|
-
isBuffering: false,
|
|
23
|
-
resizeMode: ResizeMode.CONTAIN,
|
|
24
|
-
controlsVisible: true,
|
|
25
|
-
controlsTimer: 6,
|
|
26
|
-
activeTrack: null,
|
|
27
|
-
playableDuration: 0,
|
|
28
|
-
settingsModal: { isVisible: false, action: 'none' as SettingsAction },
|
|
29
|
-
playBackRate: 1,
|
|
30
|
-
playBackRateLabel: null,
|
|
31
|
-
onLoad: null,
|
|
32
|
-
selectedAudioTrack: null,
|
|
33
|
-
selectedSubtitleTrack: null,
|
|
34
|
-
selectedVideoTrack: null,
|
|
35
|
-
activeSubtitle: null,
|
|
36
|
-
maxBitRate: null,
|
|
37
|
-
startWatchTime: null,
|
|
38
|
-
playList: [],
|
|
39
|
-
currentTrackIndex: 0,
|
|
40
|
-
contentSeasons: null,
|
|
41
|
-
activeSeason: null,
|
|
42
|
-
error: null,
|
|
43
|
-
isViewCounted: false,
|
|
44
|
-
isSkipIntroVisible: false,
|
|
45
|
-
isNextEpisodeVisible: false,
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export const useVideoPlayerStore = create<VideoPlayerStore>()(
|
|
49
|
-
persist(
|
|
50
|
-
(set) => ({
|
|
51
|
-
...storeDataDefaults,
|
|
52
|
-
|
|
53
|
-
setCurrentTime: (currentTime) => set({ currentTime }),
|
|
54
|
-
setDuration: (duration) => set({ duration }),
|
|
55
|
-
setIsPaused: (isPaused) => set({ isPaused }),
|
|
56
|
-
setIsBuffering: (isBuffering) => set({ isBuffering }),
|
|
57
|
-
setResizeMode: (resizeMode: EnumValues<ResizeMode>) =>
|
|
58
|
-
set({ resizeMode }),
|
|
59
|
-
setControlsVisible: (controlsVisible) => set({ controlsVisible }),
|
|
60
|
-
setControlsTimer: (controlsTimer) => set({ controlsTimer }),
|
|
61
|
-
setActiveTrack: (activeTrack) => set({ activeTrack }),
|
|
62
|
-
setPlayableDuration: (playableDuration) => set({ playableDuration }),
|
|
63
|
-
setSettingsModal: ({ isVisible, action }) =>
|
|
64
|
-
set({ settingsModal: { isVisible, action } }),
|
|
65
|
-
setPlayBackRate: (playBackRate, playBackRateLabel) =>
|
|
66
|
-
set({ playBackRate, playBackRateLabel }),
|
|
67
|
-
setOnLoad: (onLoad) => set({ onLoad }),
|
|
68
|
-
setSelectedAudioTrack: (selectedAudioTrack) =>
|
|
69
|
-
set({ selectedAudioTrack }),
|
|
70
|
-
setSelectedSubtitleTrack: (selectedSubtitleTrack: any) =>
|
|
71
|
-
set({ selectedSubtitleTrack }),
|
|
72
|
-
setSelectedVideoTrack: (selectedVideoTrack) =>
|
|
73
|
-
set({ selectedVideoTrack }),
|
|
74
|
-
setActiveSubtitle: (activeSubtitle) => set({ activeSubtitle }),
|
|
75
|
-
setMaxBitRate: (maxBitRate) => set({ maxBitRate }),
|
|
76
|
-
setStartWatchTime: (startWatchTime) => set({ startWatchTime }),
|
|
77
|
-
setPlayList: (playList) => set({ playList }),
|
|
78
|
-
setCurrentTrackIndex: (currentTrackIndex) => set({ currentTrackIndex }),
|
|
79
|
-
setContentSeasons: (contentSeasons) => set({ contentSeasons }),
|
|
80
|
-
setActiveSeason: (activeSeason) => set({ activeSeason }),
|
|
81
|
-
setError: (error) => set({ error }),
|
|
82
|
-
setIsViewCounted: (isViewCounted) => set({ isViewCounted }),
|
|
83
|
-
setIsSkipIntroVisible: (isSkipIntroVisible) =>
|
|
84
|
-
set({ isSkipIntroVisible }),
|
|
85
|
-
setIsNextEpisodeVisible: (isNextEpisodeVisible) =>
|
|
86
|
-
set({ isNextEpisodeVisible }),
|
|
87
|
-
resetStore: () => {
|
|
88
|
-
set(storeDataDefaults);
|
|
89
|
-
storage.clearAll();
|
|
90
|
-
},
|
|
91
|
-
}),
|
|
92
|
-
{
|
|
93
|
-
name: 'VideoPlayerStorage',
|
|
94
|
-
storage: createJSONStorage(() => mmkvStorage),
|
|
95
|
-
}
|
|
96
|
-
)
|
|
97
|
-
);
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { StyleSheet } from 'react-native';
|
|
2
|
-
|
|
3
|
-
const globalStyles = StyleSheet.create({
|
|
4
|
-
centerContainer: {
|
|
5
|
-
flex: 1,
|
|
6
|
-
alignItems: 'center',
|
|
7
|
-
justifyContent: 'center',
|
|
8
|
-
},
|
|
9
|
-
container: {
|
|
10
|
-
flex: 1,
|
|
11
|
-
},
|
|
12
|
-
newContainer: {
|
|
13
|
-
flex: 1,
|
|
14
|
-
},
|
|
15
|
-
flexOneJustifyContentAndAlignItemsCenter: {
|
|
16
|
-
flex: 1,
|
|
17
|
-
justifyContent: 'center',
|
|
18
|
-
alignItems: 'center',
|
|
19
|
-
},
|
|
20
|
-
flexOneJustifyContentCenterAndAlignItemsCenter: {
|
|
21
|
-
flex: 1,
|
|
22
|
-
justifyContent: 'center',
|
|
23
|
-
alignItems: 'center',
|
|
24
|
-
},
|
|
25
|
-
hundredPercentWidth: {
|
|
26
|
-
width: '100%',
|
|
27
|
-
},
|
|
28
|
-
hundredPercentHeight: {
|
|
29
|
-
height: '100%',
|
|
30
|
-
},
|
|
31
|
-
marginZeroAndPaddingZero: {
|
|
32
|
-
margin: 0,
|
|
33
|
-
padding: 0,
|
|
34
|
-
},
|
|
35
|
-
overflowHidden: {
|
|
36
|
-
overflow: 'hidden',
|
|
37
|
-
},
|
|
38
|
-
flexOne: {
|
|
39
|
-
flex: 1,
|
|
40
|
-
},
|
|
41
|
-
flexZero: {
|
|
42
|
-
flex: 0,
|
|
43
|
-
},
|
|
44
|
-
positionAbsolute: {
|
|
45
|
-
position: 'absolute',
|
|
46
|
-
},
|
|
47
|
-
twentyPercentWidth: {
|
|
48
|
-
width: '20%',
|
|
49
|
-
},
|
|
50
|
-
alignItemsCenterAndJustifyContentCenter: {
|
|
51
|
-
alignItems: 'center',
|
|
52
|
-
justifyContent: 'center',
|
|
53
|
-
},
|
|
54
|
-
textAlignCenter: {
|
|
55
|
-
textAlign: 'center',
|
|
56
|
-
},
|
|
57
|
-
flexRow_alignCenter_justifyBetween: {
|
|
58
|
-
flexDirection: 'row',
|
|
59
|
-
alignItems: 'center',
|
|
60
|
-
justifyContent: 'space-between',
|
|
61
|
-
},
|
|
62
|
-
flexOneWithBlackBackground: {
|
|
63
|
-
flex: 1,
|
|
64
|
-
backgroundColor: 'black',
|
|
65
|
-
},
|
|
66
|
-
absoluteFill: StyleSheet.absoluteFillObject,
|
|
67
|
-
controlsContainer: {
|
|
68
|
-
flex: 1,
|
|
69
|
-
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
70
|
-
},
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
export default globalStyles;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Dimensions } from 'react-native';
|
|
2
|
-
|
|
3
|
-
const { height, width } = Dimensions.get('window');
|
|
4
|
-
|
|
5
|
-
const setHeight = (h: number) => (height / 100) * h;
|
|
6
|
-
const setWidth = (w: number) => (width / 100) * w;
|
|
7
|
-
const fullWidth = Dimensions.get('window').width;
|
|
8
|
-
const fullHeight = Dimensions.get('window').height;
|
|
9
|
-
|
|
10
|
-
export default { setHeight, setWidth, fullWidth, fullHeight };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default as Display } from './Display';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './timeFormatter';
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
export const formatDuration = (
|
|
2
|
-
totalSeconds: number,
|
|
3
|
-
hideSeconds = false,
|
|
4
|
-
addSpaces = false
|
|
5
|
-
): string => {
|
|
6
|
-
const hours = Math.floor(totalSeconds / 3600);
|
|
7
|
-
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
8
|
-
const seconds = totalSeconds % 60;
|
|
9
|
-
|
|
10
|
-
const formatUnit = (value: number, label: string) =>
|
|
11
|
-
value ? `${value}${addSpaces ? ` ${label} ` : label}` : '';
|
|
12
|
-
|
|
13
|
-
const result =
|
|
14
|
-
formatUnit(hours, 'h') +
|
|
15
|
-
formatUnit(minutes, 'm') +
|
|
16
|
-
formatUnit(seconds, 's');
|
|
17
|
-
|
|
18
|
-
return hideSeconds
|
|
19
|
-
? formatUnit(hours, 'h') + formatUnit(minutes, 'm')
|
|
20
|
-
: result;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export const formatTime = (seconds: number) => {
|
|
24
|
-
const h = Math.floor(seconds / 3600);
|
|
25
|
-
const m = Math.floor((seconds % 3600) / 60);
|
|
26
|
-
const s = Math.floor(seconds % 60);
|
|
27
|
-
if (h > 0) {
|
|
28
|
-
return `${h}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
|
|
29
|
-
}
|
|
30
|
-
return `${m}:${String(s).padStart(2, '0')}`;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export const formatTimeWithMs = (seconds: number): string => {
|
|
34
|
-
if (isNaN(seconds) || seconds < 0) return '00:00.000';
|
|
35
|
-
const totalMs = Math.floor(seconds * 1000);
|
|
36
|
-
const ms = totalMs % 1000;
|
|
37
|
-
const totalSec = Math.floor(totalMs / 1000);
|
|
38
|
-
const min = Math.floor(totalSec / 60);
|
|
39
|
-
const sec = totalSec % 60;
|
|
40
|
-
return `${String(min).padStart(2, '0')}:${String(sec).padStart(
|
|
41
|
-
2,
|
|
42
|
-
'0'
|
|
43
|
-
)}.${String(ms).padStart(3, '0')}`;
|
|
44
|
-
};
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
2
|
-
import type { VideoAd } from '../../store/videoPlayer.type';
|
|
3
|
-
import type { ExtendedWatchProgress } from '../player/useWatchReporter';
|
|
4
|
-
import type { MediaEpisode } from '../../store/videoPlayer.type';
|
|
5
|
-
|
|
6
|
-
interface UseAdEventHandlerParams {
|
|
7
|
-
resumeVideoFromAd: (resumeTime: number | null) => void;
|
|
8
|
-
resumeTime: number | null;
|
|
9
|
-
playerEvents: {
|
|
10
|
-
onEnd: (params: {
|
|
11
|
-
reportProgress: (event: ExtendedWatchProgress['event']) => void;
|
|
12
|
-
onPressEpisode: ({
|
|
13
|
-
episode,
|
|
14
|
-
}: {
|
|
15
|
-
episode: MediaEpisode;
|
|
16
|
-
}) => Promise<boolean>;
|
|
17
|
-
autoNext: boolean;
|
|
18
|
-
}) => void;
|
|
19
|
-
};
|
|
20
|
-
reportProgress: (event: ExtendedWatchProgress['event']) => void;
|
|
21
|
-
onPressEpisode?: ({ episode }: { episode: MediaEpisode }) => Promise<boolean>;
|
|
22
|
-
autoNext: boolean;
|
|
23
|
-
onAdEnd?: (ad: VideoAd) => void;
|
|
24
|
-
onAdError?: (error: Error, ad: VideoAd) => void;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Reusable hook for handling ad events (end, skip, error)
|
|
29
|
-
* Consolidates duplicate logic from handleAdEnd, handleAdSkip, and handleAdError
|
|
30
|
-
*/
|
|
31
|
-
export const useAdEventHandler = ({
|
|
32
|
-
resumeVideoFromAd,
|
|
33
|
-
resumeTime,
|
|
34
|
-
playerEvents,
|
|
35
|
-
reportProgress,
|
|
36
|
-
onPressEpisode,
|
|
37
|
-
autoNext,
|
|
38
|
-
onAdEnd,
|
|
39
|
-
onAdError,
|
|
40
|
-
}: UseAdEventHandlerParams) => {
|
|
41
|
-
const handlePostRollAd = useCallback(() => {
|
|
42
|
-
playerEvents.onEnd({
|
|
43
|
-
reportProgress,
|
|
44
|
-
onPressEpisode: onPressEpisode ?? (async () => true),
|
|
45
|
-
autoNext,
|
|
46
|
-
});
|
|
47
|
-
}, [playerEvents, reportProgress, onPressEpisode, autoNext]);
|
|
48
|
-
|
|
49
|
-
const handleNonPostRollAd = useCallback(() => {
|
|
50
|
-
resumeVideoFromAd(resumeTime);
|
|
51
|
-
}, [resumeVideoFromAd, resumeTime]);
|
|
52
|
-
|
|
53
|
-
const handleAdEnd = useCallback(
|
|
54
|
-
(endedAd: VideoAd) => {
|
|
55
|
-
onAdEnd?.(endedAd);
|
|
56
|
-
|
|
57
|
-
if (endedAd.position === 'post') {
|
|
58
|
-
handlePostRollAd();
|
|
59
|
-
} else {
|
|
60
|
-
handleNonPostRollAd();
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
[onAdEnd, handlePostRollAd, handleNonPostRollAd]
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
const handleAdSkip = useCallback(
|
|
67
|
-
(skippedAd: VideoAd) => {
|
|
68
|
-
onAdEnd?.(skippedAd);
|
|
69
|
-
|
|
70
|
-
if (skippedAd.position !== 'post') {
|
|
71
|
-
handleNonPostRollAd();
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
[onAdEnd, handleNonPostRollAd]
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
const handleAdError = useCallback(
|
|
78
|
-
(error: Error, errorAd: VideoAd) => {
|
|
79
|
-
onAdError?.(error, errorAd);
|
|
80
|
-
|
|
81
|
-
if (errorAd.position !== 'post') {
|
|
82
|
-
handleNonPostRollAd();
|
|
83
|
-
} else {
|
|
84
|
-
handlePostRollAd();
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
[onAdError, handleNonPostRollAd, handlePostRollAd]
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
return {
|
|
91
|
-
handleAdEnd,
|
|
92
|
-
handleAdSkip,
|
|
93
|
-
handleAdError,
|
|
94
|
-
};
|
|
95
|
-
};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
2
|
-
import { lockToLandscape, lockToPortrait } from '../platform';
|
|
3
|
-
|
|
4
|
-
interface UseOrientationLockParams {
|
|
5
|
-
isFocused: boolean;
|
|
6
|
-
mode: 'fullscreen' | 'normal';
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Reusable hook for managing orientation locking
|
|
11
|
-
* Consolidates orientation logic from VideoPlayer
|
|
12
|
-
*/
|
|
13
|
-
export const useOrientationLock = ({
|
|
14
|
-
isFocused,
|
|
15
|
-
mode,
|
|
16
|
-
}: UseOrientationLockParams) => {
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
if (!isFocused) {
|
|
19
|
-
lockToPortrait();
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (mode === 'fullscreen') {
|
|
24
|
-
lockToLandscape();
|
|
25
|
-
} else {
|
|
26
|
-
lockToPortrait();
|
|
27
|
-
}
|
|
28
|
-
}, [isFocused, mode]);
|
|
29
|
-
};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { useEffect, useRef } from 'react';
|
|
2
|
-
import { useVideoPlayerStore } from '../../store/videoPlayerStore';
|
|
3
|
-
import { useAdsPlayerStore } from '../../../AdsPlayer/store/adsPlayerStore';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Reusable hook to pause main video when ads start playing
|
|
7
|
-
* Saves current time as resume time for pre-roll ads
|
|
8
|
-
*/
|
|
9
|
-
export const usePauseVideoOnAd = () => {
|
|
10
|
-
const { setIsPaused, currentTime, isPaused } = useVideoPlayerStore();
|
|
11
|
-
const { currentAd, isAdPlaying, resumeTime, setResumeTime } =
|
|
12
|
-
useAdsPlayerStore();
|
|
13
|
-
|
|
14
|
-
const lastResumeTimeRef = useRef<number | null>(null);
|
|
15
|
-
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
if (isAdPlaying && currentAd) {
|
|
18
|
-
// Only pause if not already paused to prevent unnecessary updates
|
|
19
|
-
if (!isPaused) {
|
|
20
|
-
setIsPaused(true);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Save current time as resume time if not already set (for pre-roll ads)
|
|
24
|
-
// Use ref to prevent setting the same value multiple times
|
|
25
|
-
if (
|
|
26
|
-
resumeTime === null &&
|
|
27
|
-
currentTime > 0 &&
|
|
28
|
-
lastResumeTimeRef.current !== currentTime
|
|
29
|
-
) {
|
|
30
|
-
lastResumeTimeRef.current = currentTime;
|
|
31
|
-
setResumeTime(currentTime);
|
|
32
|
-
}
|
|
33
|
-
} else if (!isAdPlaying && !currentAd) {
|
|
34
|
-
// Reset ref when no ad is playing
|
|
35
|
-
lastResumeTimeRef.current = null;
|
|
36
|
-
}
|
|
37
|
-
}, [
|
|
38
|
-
isAdPlaying,
|
|
39
|
-
currentAd,
|
|
40
|
-
isPaused,
|
|
41
|
-
setIsPaused,
|
|
42
|
-
currentTime,
|
|
43
|
-
resumeTime,
|
|
44
|
-
setResumeTime,
|
|
45
|
-
]);
|
|
46
|
-
};
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { useEffect, useCallback, useRef } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
BackHandler,
|
|
4
|
-
Platform,
|
|
5
|
-
AppState,
|
|
6
|
-
type AppStateStatus,
|
|
7
|
-
} from 'react-native';
|
|
8
|
-
import { lockToPortrait } from '../platform/lockOrientation';
|
|
9
|
-
import { useVideoPlayerStore } from '../../store/videoPlayerStore';
|
|
10
|
-
|
|
11
|
-
type UseVideoPlayerBackProps = {
|
|
12
|
-
navigation?: any;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export const useVideoPlayerBack = ({
|
|
16
|
-
navigation,
|
|
17
|
-
}: UseVideoPlayerBackProps = {}) => {
|
|
18
|
-
const { resetStore } = useVideoPlayerStore();
|
|
19
|
-
const hasClosed = useRef(false);
|
|
20
|
-
|
|
21
|
-
const handleClose = useCallback(() => {
|
|
22
|
-
if (hasClosed.current) return;
|
|
23
|
-
hasClosed.current = true;
|
|
24
|
-
|
|
25
|
-
resetStore();
|
|
26
|
-
lockToPortrait();
|
|
27
|
-
|
|
28
|
-
if (navigation?.canGoBack()) {
|
|
29
|
-
navigation.goBack();
|
|
30
|
-
}
|
|
31
|
-
}, [resetStore, navigation]);
|
|
32
|
-
|
|
33
|
-
useEffect(() => {
|
|
34
|
-
const backHandler =
|
|
35
|
-
Platform.OS === 'android'
|
|
36
|
-
? BackHandler.addEventListener('hardwareBackPress', () => {
|
|
37
|
-
handleClose();
|
|
38
|
-
return true;
|
|
39
|
-
})
|
|
40
|
-
: undefined;
|
|
41
|
-
|
|
42
|
-
const unsubscribe = navigation?.addListener('beforeRemove', (e: any) => {
|
|
43
|
-
e.preventDefault();
|
|
44
|
-
handleClose();
|
|
45
|
-
navigation.dispatch(e.data.action);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
const handleAppStateChange = (nextAppState: AppStateStatus) => {
|
|
49
|
-
if (nextAppState === 'inactive') {
|
|
50
|
-
handleClose();
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
const appStateListener = AppState.addEventListener(
|
|
54
|
-
'change',
|
|
55
|
-
handleAppStateChange
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
return () => {
|
|
59
|
-
backHandler?.remove();
|
|
60
|
-
unsubscribe?.();
|
|
61
|
-
appStateListener.remove();
|
|
62
|
-
};
|
|
63
|
-
}, [handleClose, navigation]);
|
|
64
|
-
|
|
65
|
-
return handleClose;
|
|
66
|
-
};
|