@zezosoft/zezo-ott-react-native-ui-kit 1.1.2 → 1.1.3
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/components/Auth/QrLogin/QrLogin.js +304 -138
- package/lib/module/components/Auth/QrLogin/QrLogin.js.map +1 -1
- package/lib/module/components/Auth/QrLogin/components/QrViewArea.js +193 -141
- package/lib/module/components/Auth/QrLogin/components/QrViewArea.js.map +1 -1
- package/lib/module/components/Content/Card/Category/Category.js +83 -11
- package/lib/module/components/Content/Card/Category/Category.js.map +1 -1
- package/lib/module/components/Content/Card/NowWatching/NowWatching.js +237 -108
- package/lib/module/components/Content/Card/NowWatching/NowWatching.js.map +1 -1
- package/lib/module/components/Content/Card/Sliders/Styles/One.js +185 -126
- package/lib/module/components/Content/Card/Sliders/Styles/One.js.map +1 -1
- package/lib/module/components/Content/Card/Sliders/Styles/Two.js +139 -92
- package/lib/module/components/Content/Card/Sliders/Styles/Two.js.map +1 -1
- package/lib/module/components/Content/Card/Styles/Five.js +131 -48
- package/lib/module/components/Content/Card/Styles/Five.js.map +1 -1
- package/lib/module/components/Content/Card/Styles/Four.js +126 -59
- package/lib/module/components/Content/Card/Styles/Four.js.map +1 -1
- package/lib/module/components/Content/Card/Styles/One.js +125 -50
- package/lib/module/components/Content/Card/Styles/One.js.map +1 -1
- package/lib/module/components/Content/Card/Styles/RotateInOut.js +138 -53
- package/lib/module/components/Content/Card/Styles/RotateInOut.js.map +1 -1
- package/lib/module/components/Content/Card/Styles/Six.js +207 -115
- package/lib/module/components/Content/Card/Styles/Six.js.map +1 -1
- package/lib/module/components/Content/Card/Styles/Three.js +134 -79
- package/lib/module/components/Content/Card/Styles/Three.js.map +1 -1
- package/lib/module/components/Content/Card/Styles/TopTen.js +186 -171
- package/lib/module/components/Content/Card/Styles/TopTen.js.map +1 -1
- package/lib/module/components/Content/Card/Styles/Two.js +144 -64
- package/lib/module/components/Content/Card/Styles/Two.js.map +1 -1
- package/lib/module/components/Content/Card/components/AdsPoster.js +162 -0
- package/lib/module/components/Content/Card/components/AdsPoster.js.map +1 -0
- package/lib/module/components/Content/Card/components/CardPoster.js +120 -136
- package/lib/module/components/Content/Card/components/CardPoster.js.map +1 -1
- package/lib/module/components/Content/Card/components/index.js +4 -0
- package/lib/module/components/Content/Card/components/index.js.map +1 -0
- package/lib/module/components/Content/Content.js +67 -27
- package/lib/module/components/Content/Content.js.map +1 -1
- package/lib/module/components/Content/Sections.js +32 -11
- package/lib/module/components/Content/Sections.js.map +1 -1
- package/lib/module/constants/dummySections.js +44 -4
- package/lib/module/constants/dummySections.js.map +1 -1
- package/lib/module/hooks/Images/index.js +5 -0
- package/lib/module/hooks/Images/index.js.map +1 -0
- package/lib/module/hooks/Images/useImageLoader.js +168 -0
- package/lib/module/hooks/Images/useImageLoader.js.map +1 -0
- package/lib/module/hooks/Images/useImageValidation.js +36 -0
- package/lib/module/hooks/Images/useImageValidation.js.map +1 -0
- package/lib/module/hooks/index.js +3 -0
- package/lib/module/hooks/index.js.map +1 -1
- package/lib/module/hooks/useAdTracking.js +270 -0
- package/lib/module/hooks/useAdTracking.js.map +1 -0
- package/lib/module/hooks/useCards.js +164 -0
- package/lib/module/hooks/useCards.js.map +1 -0
- package/lib/module/hooks/usePaginatedSection.js +11 -6
- package/lib/module/hooks/usePaginatedSection.js.map +1 -1
- package/lib/typescript/src/components/Auth/QrLogin/QrLogin.d.ts +2 -0
- package/lib/typescript/src/components/Auth/QrLogin/QrLogin.d.ts.map +1 -1
- package/lib/typescript/src/components/Auth/QrLogin/components/QrViewArea.d.ts.map +1 -1
- package/lib/typescript/src/components/Content/Card/Category/Category.d.ts.map +1 -1
- package/lib/typescript/src/components/Content/Card/NowWatching/NowWatching.d.ts.map +1 -1
- package/lib/typescript/src/components/Content/Card/Sliders/Styles/One.d.ts.map +1 -1
- package/lib/typescript/src/components/Content/Card/Sliders/Styles/Two.d.ts.map +1 -1
- package/lib/typescript/src/components/Content/Card/Styles/Five.d.ts +13 -1
- package/lib/typescript/src/components/Content/Card/Styles/Five.d.ts.map +1 -1
- package/lib/typescript/src/components/Content/Card/Styles/Four.d.ts +13 -1
- package/lib/typescript/src/components/Content/Card/Styles/Four.d.ts.map +1 -1
- package/lib/typescript/src/components/Content/Card/Styles/One.d.ts +15 -3
- package/lib/typescript/src/components/Content/Card/Styles/One.d.ts.map +1 -1
- package/lib/typescript/src/components/Content/Card/Styles/RotateInOut.d.ts +13 -1
- package/lib/typescript/src/components/Content/Card/Styles/RotateInOut.d.ts.map +1 -1
- package/lib/typescript/src/components/Content/Card/Styles/Six.d.ts +1 -0
- package/lib/typescript/src/components/Content/Card/Styles/Six.d.ts.map +1 -1
- package/lib/typescript/src/components/Content/Card/Styles/Three.d.ts +13 -5
- package/lib/typescript/src/components/Content/Card/Styles/Three.d.ts.map +1 -1
- package/lib/typescript/src/components/Content/Card/Styles/TopTen.d.ts +1 -0
- package/lib/typescript/src/components/Content/Card/Styles/TopTen.d.ts.map +1 -1
- package/lib/typescript/src/components/Content/Card/Styles/Two.d.ts +13 -1
- package/lib/typescript/src/components/Content/Card/Styles/Two.d.ts.map +1 -1
- package/lib/typescript/src/components/Content/Card/components/AdsPoster.d.ts +26 -0
- package/lib/typescript/src/components/Content/Card/components/AdsPoster.d.ts.map +1 -0
- package/lib/typescript/src/components/Content/Card/components/CardPoster.d.ts +3 -1
- package/lib/typescript/src/components/Content/Card/components/CardPoster.d.ts.map +1 -1
- package/lib/typescript/src/components/Content/Card/components/index.d.ts +2 -0
- package/lib/typescript/src/components/Content/Card/components/index.d.ts.map +1 -0
- package/lib/typescript/src/components/Content/Card/index.d.ts +76 -6
- package/lib/typescript/src/components/Content/Card/index.d.ts.map +1 -1
- package/lib/typescript/src/components/Content/Content.d.ts +4 -3
- package/lib/typescript/src/components/Content/Content.d.ts.map +1 -1
- package/lib/typescript/src/components/Content/Sections.d.ts +20 -6
- package/lib/typescript/src/components/Content/Sections.d.ts.map +1 -1
- package/lib/typescript/src/constants/dummySections.d.ts +5 -0
- package/lib/typescript/src/constants/dummySections.d.ts.map +1 -1
- package/lib/typescript/src/hooks/Images/index.d.ts +3 -0
- package/lib/typescript/src/hooks/Images/index.d.ts.map +1 -0
- package/lib/typescript/src/hooks/Images/useImageLoader.d.ts +36 -0
- package/lib/typescript/src/hooks/Images/useImageLoader.d.ts.map +1 -0
- package/lib/typescript/src/hooks/Images/useImageValidation.d.ts +17 -0
- package/lib/typescript/src/hooks/Images/useImageValidation.d.ts.map +1 -0
- package/lib/typescript/src/hooks/index.d.ts +3 -0
- package/lib/typescript/src/hooks/index.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useAdTracking.d.ts +39 -0
- package/lib/typescript/src/hooks/useAdTracking.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useCards.d.ts +36 -0
- package/lib/typescript/src/hooks/useCards.d.ts.map +1 -0
- package/lib/typescript/src/hooks/usePaginatedSection.d.ts +12 -2
- package/lib/typescript/src/hooks/usePaginatedSection.d.ts.map +1 -1
- package/lib/typescript/src/types/sections/index.d.ts +7 -4
- package/lib/typescript/src/types/sections/index.d.ts.map +1 -1
- package/package.json +6 -3
- package/src/components/Auth/QrLogin/QrLogin.tsx +382 -122
- package/src/components/Auth/QrLogin/components/QrViewArea.tsx +291 -197
- package/src/components/Content/Card/Category/Category.tsx +95 -8
- package/src/components/Content/Card/NowWatching/NowWatching.tsx +281 -136
- package/src/components/Content/Card/Sliders/Styles/One.tsx +244 -148
- package/src/components/Content/Card/Sliders/Styles/Two.tsx +171 -102
- package/src/components/Content/Card/Styles/Five.tsx +161 -62
- package/src/components/Content/Card/Styles/Four.tsx +164 -85
- package/src/components/Content/Card/Styles/One.tsx +161 -71
- package/src/components/Content/Card/Styles/RotateInOut.tsx +157 -60
- package/src/components/Content/Card/Styles/Six.tsx +242 -142
- package/src/components/Content/Card/Styles/Three.tsx +166 -133
- package/src/components/Content/Card/Styles/TopTen.tsx +230 -191
- package/src/components/Content/Card/Styles/Two.tsx +182 -79
- package/src/components/Content/Card/components/AdsPoster.tsx +202 -0
- package/src/components/Content/Card/components/CardPoster.tsx +134 -154
- package/src/components/Content/Card/components/index.ts +1 -0
- package/src/components/Content/Content.tsx +83 -45
- package/src/components/Content/Sections.tsx +51 -10
- package/src/constants/dummySections.ts +48 -1
- package/src/hooks/Images/index.ts +2 -0
- package/src/hooks/Images/useImageLoader.ts +206 -0
- package/src/hooks/Images/useImageValidation.ts +36 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/useAdTracking.ts +349 -0
- package/src/hooks/useCards.ts +228 -0
- package/src/hooks/usePaginatedSection.ts +26 -7
- package/src/types/sections/index.ts +7 -4
|
@@ -35,6 +35,50 @@ import { RFValue } from 'react-native-responsive-fontsize';
|
|
|
35
35
|
import RentOrBuyIcon from '../components/RentOrBuyIcon';
|
|
36
36
|
import type { IContentData } from '@zezosoft/zezo-ott-api-client';
|
|
37
37
|
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// Constants
|
|
40
|
+
// ============================================================================
|
|
41
|
+
const ITEM_WIDTH = moderateScale(230);
|
|
42
|
+
const BORDER_RADIUS = moderateScale(8);
|
|
43
|
+
const DEFAULT_SKELETON_COUNT = 4;
|
|
44
|
+
const ASPECT_RATIO = 9 / 16;
|
|
45
|
+
const PROGRESS_ANIMATION_DURATION = 500;
|
|
46
|
+
const TOUCH_OPACITY = 0.9;
|
|
47
|
+
const END_REACHED_THRESHOLD = 0.5;
|
|
48
|
+
const ITEM_MARGIN_RIGHT = moderateScale(12);
|
|
49
|
+
const FIRST_ITEM_MARGIN_LEFT = moderateScale(10);
|
|
50
|
+
const LIST_PADDING_RIGHT = moderateScale(15);
|
|
51
|
+
const GRADIENT_COLORS = ['rgba(0,0,0,0.95)', 'transparent'];
|
|
52
|
+
const GRADIENT_START = { x: 0, y: 1 };
|
|
53
|
+
const GRADIENT_END = { x: 0, y: 0 };
|
|
54
|
+
const PROGRESS_BG_COLOR = '#4F4E4E';
|
|
55
|
+
const PROGRESS_BORDER_RADIUS = 6;
|
|
56
|
+
const SKELETON_TITLE_WIDTH = '80%';
|
|
57
|
+
const SKELETON_SUBTITLE_WIDTH = '60%';
|
|
58
|
+
const SKELETON_BORDER_RADIUS = 4;
|
|
59
|
+
const SHADOW_COLOR = '#000';
|
|
60
|
+
const SHADOW_OFFSET = { width: 0, height: 2 };
|
|
61
|
+
const SHADOW_OPACITY = 0.08;
|
|
62
|
+
const SHADOW_RADIUS = 4;
|
|
63
|
+
const ELEVATION = 2;
|
|
64
|
+
const PLAY_ICON_SIZE = moderateScale(20);
|
|
65
|
+
const PLAY_ICON_CONTAINER_SIZE = moderateScale(32);
|
|
66
|
+
const PLAY_ICON_CONTAINER_RADIUS = moderateScale(16);
|
|
67
|
+
const SKELETON_TITLE_HEIGHT = verticalScale(10);
|
|
68
|
+
const SKELETON_SUBTITLE_HEIGHT = verticalScale(8);
|
|
69
|
+
const SKELETON_HEADER_WIDTH = moderateScale(100);
|
|
70
|
+
const SKELETON_HEADER_HEIGHT = verticalScale(14);
|
|
71
|
+
const SKELETON_HEADER_BORDER_RADIUS = moderateScale(4);
|
|
72
|
+
const SKELETON_HEADER_MARGIN_LEFT = moderateScale(12);
|
|
73
|
+
const SKELETON_HEADER_MARGIN_BOTTOM = verticalScale(6);
|
|
74
|
+
const INFO_CONTAINER_BOTTOM = 6;
|
|
75
|
+
const INFO_CONTAINER_HORIZONTAL = 8;
|
|
76
|
+
const TEXT_SECTION_PADDING_RIGHT = 8;
|
|
77
|
+
const SUBTITLE_OPACITY = 0.85;
|
|
78
|
+
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// Types
|
|
81
|
+
// ============================================================================
|
|
38
82
|
export interface IHistoryItem {
|
|
39
83
|
_id: string;
|
|
40
84
|
content: IContentData;
|
|
@@ -61,7 +105,6 @@ type Props = {
|
|
|
61
105
|
name: IGetSectionData['name'];
|
|
62
106
|
type: IGetSectionData['type'];
|
|
63
107
|
}) => void;
|
|
64
|
-
|
|
65
108
|
renderItemImage?: (params: {
|
|
66
109
|
item: IContentData;
|
|
67
110
|
index: number;
|
|
@@ -76,10 +119,25 @@ type Props = {
|
|
|
76
119
|
isLoadingHistory?: boolean;
|
|
77
120
|
};
|
|
78
121
|
|
|
79
|
-
|
|
80
|
-
|
|
122
|
+
type NowWatchingItemProps = {
|
|
123
|
+
item: IHistoryItem;
|
|
124
|
+
index: number;
|
|
125
|
+
isLast: boolean;
|
|
126
|
+
appliedTheme: ITheme;
|
|
127
|
+
onPressItem?: (item: IContentData) => void;
|
|
128
|
+
renderItemImage?: (params: {
|
|
129
|
+
item: IContentData;
|
|
130
|
+
index: number;
|
|
131
|
+
}) => React.ReactNode;
|
|
132
|
+
itemStyle?: StyleProp<ViewStyle>;
|
|
133
|
+
itemWidth: number;
|
|
134
|
+
borderRadius: number;
|
|
135
|
+
};
|
|
81
136
|
|
|
82
|
-
|
|
137
|
+
// ============================================================================
|
|
138
|
+
// Helper Components
|
|
139
|
+
// ============================================================================
|
|
140
|
+
const NowWatchingItem = memo<NowWatchingItemProps>(
|
|
83
141
|
({
|
|
84
142
|
item,
|
|
85
143
|
index,
|
|
@@ -90,48 +148,57 @@ const NowWatchingItem = memo(
|
|
|
90
148
|
itemStyle,
|
|
91
149
|
itemWidth,
|
|
92
150
|
borderRadius,
|
|
93
|
-
}: {
|
|
94
|
-
item: IHistoryItem;
|
|
95
|
-
index: number;
|
|
96
|
-
isLast: boolean;
|
|
97
|
-
appliedTheme: ITheme;
|
|
98
|
-
onPressItem?: (item: IContentData) => void;
|
|
99
|
-
renderItemImage?: (params: {
|
|
100
|
-
item: IContentData;
|
|
101
|
-
index: number;
|
|
102
|
-
}) => React.ReactNode;
|
|
103
|
-
itemStyle?: StyleProp<ViewStyle>;
|
|
104
|
-
itemWidth: number;
|
|
105
|
-
borderRadius: number;
|
|
106
151
|
}) => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
)
|
|
152
|
+
// ========================================================================
|
|
153
|
+
// Progress Calculation
|
|
154
|
+
// ========================================================================
|
|
155
|
+
const percentage = useMemo(() => {
|
|
156
|
+
if (!item.duration || item.duration === 0) return 0;
|
|
157
|
+
return Math.max(
|
|
158
|
+
0,
|
|
159
|
+
Math.min(100, Math.round((item.currentTime / item.duration) * 100))
|
|
160
|
+
);
|
|
161
|
+
}, [item.currentTime, item.duration]);
|
|
111
162
|
|
|
163
|
+
// ========================================================================
|
|
164
|
+
// Animation
|
|
165
|
+
// ========================================================================
|
|
112
166
|
const progress = useSharedValue(0);
|
|
113
167
|
|
|
114
168
|
useEffect(() => {
|
|
115
|
-
progress.value = withTiming(percentage, {
|
|
116
|
-
|
|
169
|
+
progress.value = withTiming(percentage, {
|
|
170
|
+
duration: PROGRESS_ANIMATION_DURATION,
|
|
171
|
+
});
|
|
172
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
173
|
+
}, [percentage]);
|
|
117
174
|
|
|
118
175
|
const animatedProgressStyle = useAnimatedStyle(() => ({
|
|
119
176
|
width: `${progress.value}%`,
|
|
120
177
|
}));
|
|
121
178
|
|
|
179
|
+
// ========================================================================
|
|
180
|
+
// Styles
|
|
181
|
+
// ========================================================================
|
|
122
182
|
const styles = useMemo(
|
|
123
183
|
() => getStyles(appliedTheme, itemWidth, borderRadius),
|
|
124
184
|
[appliedTheme, itemWidth, borderRadius]
|
|
125
185
|
);
|
|
186
|
+
|
|
187
|
+
const isFirstItem = index === 0;
|
|
188
|
+
const itemMarginStyle = isLast ? { marginRight: ITEM_MARGIN_RIGHT } : null;
|
|
189
|
+
|
|
190
|
+
// ========================================================================
|
|
191
|
+
// Render
|
|
192
|
+
// ========================================================================
|
|
126
193
|
return (
|
|
127
194
|
<TouchableOpacity
|
|
128
195
|
style={[
|
|
129
196
|
styles.item,
|
|
130
197
|
itemStyle,
|
|
131
|
-
|
|
132
|
-
|
|
198
|
+
isFirstItem && styles.firstItem,
|
|
199
|
+
itemMarginStyle,
|
|
133
200
|
]}
|
|
134
|
-
activeOpacity={
|
|
201
|
+
activeOpacity={TOUCH_OPACITY}
|
|
135
202
|
onPress={() => onPressItem?.(item.content)}
|
|
136
203
|
>
|
|
137
204
|
<View style={styles.cardWrapper}>
|
|
@@ -151,9 +218,9 @@ const NowWatchingItem = memo(
|
|
|
151
218
|
content_offering_type={item.content.content_offering_type}
|
|
152
219
|
/>
|
|
153
220
|
<LinearGradient
|
|
154
|
-
colors={
|
|
155
|
-
start={
|
|
156
|
-
end={
|
|
221
|
+
colors={GRADIENT_COLORS}
|
|
222
|
+
start={GRADIENT_START}
|
|
223
|
+
end={GRADIENT_END}
|
|
157
224
|
style={styles.gradientOverlay}
|
|
158
225
|
/>
|
|
159
226
|
</FastImage>
|
|
@@ -177,7 +244,7 @@ const NowWatchingItem = memo(
|
|
|
177
244
|
</View>
|
|
178
245
|
<View style={styles.playIconWrapper}>
|
|
179
246
|
<Play
|
|
180
|
-
size={
|
|
247
|
+
size={PLAY_ICON_SIZE}
|
|
181
248
|
color={appliedTheme.colors.primary}
|
|
182
249
|
fill={appliedTheme.colors.primary}
|
|
183
250
|
/>
|
|
@@ -189,6 +256,11 @@ const NowWatchingItem = memo(
|
|
|
189
256
|
}
|
|
190
257
|
);
|
|
191
258
|
|
|
259
|
+
NowWatchingItem.displayName = 'NowWatchingItem';
|
|
260
|
+
|
|
261
|
+
// ============================================================================
|
|
262
|
+
// Main Component
|
|
263
|
+
// ============================================================================
|
|
192
264
|
const NowWatching: React.FC<Props> = ({
|
|
193
265
|
section_id,
|
|
194
266
|
title,
|
|
@@ -203,48 +275,67 @@ const NowWatching: React.FC<Props> = ({
|
|
|
203
275
|
renderItemImage,
|
|
204
276
|
itemWidth = ITEM_WIDTH,
|
|
205
277
|
borderRadius = BORDER_RADIUS,
|
|
206
|
-
skeletonCount =
|
|
278
|
+
skeletonCount = DEFAULT_SKELETON_COUNT,
|
|
207
279
|
containerStyle,
|
|
208
280
|
itemStyle,
|
|
209
281
|
isLoadingHistory,
|
|
210
282
|
}) => {
|
|
211
|
-
|
|
283
|
+
// ========================================================================
|
|
284
|
+
// Refs & Hooks
|
|
285
|
+
// ========================================================================
|
|
286
|
+
const flatListRef = useRef<FlatList<IHistoryItem | number>>(null);
|
|
212
287
|
const onEndReachedCalledDuringMomentum = useRef(false);
|
|
213
288
|
const { theme: appliedTheme } = useInternalTheme(theme);
|
|
289
|
+
|
|
290
|
+
// ========================================================================
|
|
291
|
+
// Data Processing
|
|
292
|
+
// ========================================================================
|
|
293
|
+
const isLoadingState = isLoading || isLoadingHistory;
|
|
294
|
+
|
|
295
|
+
const { data, loadMoreData, pagination, isPaginating } =
|
|
296
|
+
usePaginatedSection<IHistoryItem>(
|
|
297
|
+
section_id,
|
|
298
|
+
moreFetchDataHistory,
|
|
299
|
+
initialData,
|
|
300
|
+
isLoadingState
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
const listData = useMemo(() => data ?? [], [data]);
|
|
304
|
+
|
|
305
|
+
// ========================================================================
|
|
306
|
+
// Styles
|
|
307
|
+
// ========================================================================
|
|
214
308
|
const styles = useMemo(
|
|
215
309
|
() => getStyles(appliedTheme, itemWidth, borderRadius),
|
|
216
310
|
[appliedTheme, itemWidth, borderRadius]
|
|
217
311
|
);
|
|
218
312
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
pagination,
|
|
223
|
-
loading: isPaginating,
|
|
224
|
-
} = usePaginatedSection<IHistoryItem>(
|
|
225
|
-
section_id,
|
|
226
|
-
moreFetchDataHistory,
|
|
227
|
-
initialData,
|
|
228
|
-
isLoading || isLoadingHistory
|
|
229
|
-
);
|
|
230
|
-
|
|
313
|
+
// ========================================================================
|
|
314
|
+
// Event Handlers
|
|
315
|
+
// ========================================================================
|
|
231
316
|
const handlePressMore = useCallback(() => {
|
|
232
317
|
onPressMore?.({ section_id, name: title, type });
|
|
233
318
|
}, [onPressMore, section_id, title, type]);
|
|
234
319
|
|
|
235
|
-
const listData = useMemo(() => data ?? [], [data]);
|
|
236
|
-
|
|
237
320
|
const handleEndReached = useCallback(() => {
|
|
238
|
-
|
|
321
|
+
const canLoadMore =
|
|
239
322
|
!onEndReachedCalledDuringMomentum.current &&
|
|
240
323
|
pagination?.hasNextPage &&
|
|
241
|
-
pagination?.nextPage
|
|
242
|
-
|
|
324
|
+
pagination?.nextPage;
|
|
325
|
+
|
|
326
|
+
if (canLoadMore) {
|
|
243
327
|
onEndReachedCalledDuringMomentum.current = true;
|
|
244
328
|
loadMoreData(pagination.nextPage);
|
|
245
329
|
}
|
|
246
330
|
}, [loadMoreData, pagination]);
|
|
247
331
|
|
|
332
|
+
const handleMomentumScrollBegin = useCallback(() => {
|
|
333
|
+
onEndReachedCalledDuringMomentum.current = false;
|
|
334
|
+
}, []);
|
|
335
|
+
|
|
336
|
+
// ========================================================================
|
|
337
|
+
// Render Functions
|
|
338
|
+
// ========================================================================
|
|
248
339
|
const renderItem: ListRenderItem<IHistoryItem> = useCallback(
|
|
249
340
|
({ item, index }) => {
|
|
250
341
|
const isLast = index === listData.length - 1;
|
|
@@ -273,41 +364,110 @@ const NowWatching: React.FC<Props> = ({
|
|
|
273
364
|
]
|
|
274
365
|
);
|
|
275
366
|
|
|
276
|
-
const renderSkeletonItem = (
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
<View style={styles.
|
|
294
|
-
<View style={styles.
|
|
295
|
-
<View style={styles.
|
|
296
|
-
|
|
367
|
+
const renderSkeletonItem = useCallback(
|
|
368
|
+
(index: number) => {
|
|
369
|
+
const isFirstItem = index === 0;
|
|
370
|
+
return (
|
|
371
|
+
<View
|
|
372
|
+
key={index}
|
|
373
|
+
style={[
|
|
374
|
+
styles.item,
|
|
375
|
+
itemStyle,
|
|
376
|
+
isFirstItem && styles.firstItem,
|
|
377
|
+
{ marginRight: ITEM_MARGIN_RIGHT },
|
|
378
|
+
]}
|
|
379
|
+
>
|
|
380
|
+
<SkeletonPlaceholder
|
|
381
|
+
backgroundColor={appliedTheme.colors.skeletonBaseColor}
|
|
382
|
+
highlightColor={appliedTheme.colors.skeletonHighlightColor}
|
|
383
|
+
>
|
|
384
|
+
<View style={styles.cardWrapper}>
|
|
385
|
+
<View style={styles.poster} />
|
|
386
|
+
<View style={styles.infoContainer}>
|
|
387
|
+
<View style={styles.textSection}>
|
|
388
|
+
<View style={styles.skeletonTitle} />
|
|
389
|
+
<View style={styles.skeletonSubTitle} />
|
|
390
|
+
<View style={styles.progressBackground} />
|
|
391
|
+
</View>
|
|
392
|
+
<View style={styles.playIconSkeleton} />
|
|
393
|
+
</View>
|
|
297
394
|
</View>
|
|
298
|
-
|
|
299
|
-
</View>
|
|
395
|
+
</SkeletonPlaceholder>
|
|
300
396
|
</View>
|
|
301
|
-
|
|
302
|
-
|
|
397
|
+
);
|
|
398
|
+
},
|
|
399
|
+
[
|
|
400
|
+
styles.item,
|
|
401
|
+
styles.firstItem,
|
|
402
|
+
styles.cardWrapper,
|
|
403
|
+
styles.poster,
|
|
404
|
+
styles.infoContainer,
|
|
405
|
+
styles.textSection,
|
|
406
|
+
styles.skeletonTitle,
|
|
407
|
+
styles.skeletonSubTitle,
|
|
408
|
+
styles.progressBackground,
|
|
409
|
+
styles.playIconSkeleton,
|
|
410
|
+
itemStyle,
|
|
411
|
+
appliedTheme.colors,
|
|
412
|
+
]
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
// ========================================================================
|
|
416
|
+
// FlatList Helpers
|
|
417
|
+
// ========================================================================
|
|
418
|
+
const flatListData = isLoadingState ? Array(skeletonCount).fill(0) : listData;
|
|
419
|
+
|
|
420
|
+
const keyExtractor = useCallback(
|
|
421
|
+
(item: IHistoryItem | number, index: number) =>
|
|
422
|
+
isLoadingState
|
|
423
|
+
? `skeleton-${index}`
|
|
424
|
+
: (item as IHistoryItem)._id || index.toString(),
|
|
425
|
+
[isLoadingState]
|
|
303
426
|
);
|
|
304
|
-
if (!isLoadingHistory && !isLoading && initialData?.length === 0) return null;
|
|
305
427
|
|
|
306
|
-
|
|
428
|
+
const renderFlatListItem = useCallback(
|
|
429
|
+
({ item, index }: { item: IHistoryItem | number; index: number }) => {
|
|
430
|
+
if (isLoadingState) {
|
|
431
|
+
return renderSkeletonItem(index);
|
|
432
|
+
}
|
|
433
|
+
return renderItem({
|
|
434
|
+
item: item as IHistoryItem,
|
|
435
|
+
index,
|
|
436
|
+
separators: {
|
|
437
|
+
highlight: () => {},
|
|
438
|
+
unhighlight: () => {},
|
|
439
|
+
updateProps: () => {},
|
|
440
|
+
},
|
|
441
|
+
});
|
|
442
|
+
},
|
|
443
|
+
[isLoadingState, renderSkeletonItem, renderItem]
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
// ========================================================================
|
|
447
|
+
// Early Returns
|
|
448
|
+
// ========================================================================
|
|
449
|
+
const hasNoData =
|
|
450
|
+
!isLoadingState &&
|
|
451
|
+
(!initialData || initialData.length === 0) &&
|
|
452
|
+
listData.length === 0 &&
|
|
453
|
+
!moreFetchDataHistory;
|
|
454
|
+
|
|
455
|
+
if (hasNoData) {
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// ========================================================================
|
|
460
|
+
// Computed Values
|
|
461
|
+
// ========================================================================
|
|
462
|
+
const shouldShowTitle = !isLoadingState && title;
|
|
463
|
+
const shouldShowSkeletonHeader = isLoadingState;
|
|
307
464
|
|
|
465
|
+
// ========================================================================
|
|
466
|
+
// Render
|
|
467
|
+
// ========================================================================
|
|
308
468
|
return (
|
|
309
469
|
<View style={[styles.container, containerStyle]}>
|
|
310
|
-
{
|
|
470
|
+
{shouldShowTitle && (
|
|
311
471
|
<NavigateToMore
|
|
312
472
|
title={title}
|
|
313
473
|
onPress={handlePressMore}
|
|
@@ -320,71 +480,56 @@ const NowWatching: React.FC<Props> = ({
|
|
|
320
480
|
showAllProps={{ iconColor: appliedTheme.colors.textPrimary, theme }}
|
|
321
481
|
/>
|
|
322
482
|
)}
|
|
323
|
-
{
|
|
483
|
+
{shouldShowSkeletonHeader && (
|
|
324
484
|
<SkeletonPlaceholder
|
|
325
485
|
highlightColor={appliedTheme.colors.skeletonHighlightColor}
|
|
326
486
|
backgroundColor={appliedTheme.colors.skeletonBaseColor}
|
|
327
487
|
>
|
|
328
488
|
<SkeletonPlaceholder.Item
|
|
329
|
-
width={
|
|
330
|
-
height={
|
|
331
|
-
borderRadius={
|
|
332
|
-
marginLeft={
|
|
333
|
-
marginBottom={
|
|
489
|
+
width={SKELETON_HEADER_WIDTH}
|
|
490
|
+
height={SKELETON_HEADER_HEIGHT}
|
|
491
|
+
borderRadius={SKELETON_HEADER_BORDER_RADIUS}
|
|
492
|
+
marginLeft={SKELETON_HEADER_MARGIN_LEFT}
|
|
493
|
+
marginBottom={SKELETON_HEADER_MARGIN_BOTTOM}
|
|
334
494
|
/>
|
|
335
495
|
</SkeletonPlaceholder>
|
|
336
496
|
)}
|
|
337
497
|
<FlatList
|
|
338
498
|
ref={flatListRef}
|
|
339
499
|
horizontal
|
|
340
|
-
data={
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
: listData
|
|
344
|
-
}
|
|
345
|
-
keyExtractor={(_, index) => index.toString()}
|
|
346
|
-
renderItem={({ item, index }) =>
|
|
347
|
-
isLoading || isLoadingHistory
|
|
348
|
-
? renderSkeletonItem(index)
|
|
349
|
-
: renderItem({
|
|
350
|
-
item,
|
|
351
|
-
index,
|
|
352
|
-
separators: {
|
|
353
|
-
highlight: () => {},
|
|
354
|
-
unhighlight: () => {},
|
|
355
|
-
updateProps: () => {},
|
|
356
|
-
},
|
|
357
|
-
})
|
|
358
|
-
}
|
|
500
|
+
data={flatListData}
|
|
501
|
+
keyExtractor={keyExtractor}
|
|
502
|
+
renderItem={renderFlatListItem}
|
|
359
503
|
showsHorizontalScrollIndicator={false}
|
|
360
504
|
contentContainerStyle={styles.listContent}
|
|
361
505
|
onEndReached={handleEndReached}
|
|
362
|
-
onEndReachedThreshold={
|
|
363
|
-
onMomentumScrollBegin={
|
|
364
|
-
onEndReachedCalledDuringMomentum.current = false;
|
|
365
|
-
}}
|
|
506
|
+
onEndReachedThreshold={END_REACHED_THRESHOLD}
|
|
507
|
+
onMomentumScrollBegin={handleMomentumScrollBegin}
|
|
366
508
|
ListFooterComponent={isPaginating ? renderSkeletonItem(0) : null}
|
|
367
509
|
/>
|
|
368
510
|
</View>
|
|
369
511
|
);
|
|
370
512
|
};
|
|
371
513
|
|
|
514
|
+
// ============================================================================
|
|
515
|
+
// Styles
|
|
516
|
+
// ============================================================================
|
|
372
517
|
const getStyles = (theme: ITheme, itemWidth: number, borderRadius: number) =>
|
|
373
518
|
StyleSheet.create({
|
|
374
519
|
container: {
|
|
375
520
|
marginVertical: verticalScale(6),
|
|
376
521
|
},
|
|
377
522
|
listContent: {
|
|
378
|
-
paddingRight:
|
|
523
|
+
paddingRight: LIST_PADDING_RIGHT,
|
|
379
524
|
},
|
|
380
525
|
item: {
|
|
381
|
-
marginRight:
|
|
526
|
+
marginRight: ITEM_MARGIN_RIGHT,
|
|
382
527
|
},
|
|
383
528
|
firstItem: {
|
|
384
|
-
marginLeft:
|
|
529
|
+
marginLeft: FIRST_ITEM_MARGIN_LEFT,
|
|
385
530
|
},
|
|
386
531
|
navigateToMoreContainer: {
|
|
387
|
-
paddingHorizontal:
|
|
532
|
+
paddingHorizontal: FIRST_ITEM_MARGIN_LEFT,
|
|
388
533
|
marginBottom: verticalScale(8),
|
|
389
534
|
},
|
|
390
535
|
title: {
|
|
@@ -396,15 +541,15 @@ const getStyles = (theme: ITheme, itemWidth: number, borderRadius: number) =>
|
|
|
396
541
|
borderRadius,
|
|
397
542
|
overflow: 'hidden',
|
|
398
543
|
backgroundColor: theme.colors.surfaceVariant,
|
|
399
|
-
shadowColor:
|
|
400
|
-
shadowOffset:
|
|
401
|
-
shadowOpacity:
|
|
402
|
-
shadowRadius:
|
|
403
|
-
elevation:
|
|
544
|
+
shadowColor: SHADOW_COLOR,
|
|
545
|
+
shadowOffset: SHADOW_OFFSET,
|
|
546
|
+
shadowOpacity: SHADOW_OPACITY,
|
|
547
|
+
shadowRadius: SHADOW_RADIUS,
|
|
548
|
+
elevation: ELEVATION,
|
|
404
549
|
},
|
|
405
550
|
poster: {
|
|
406
551
|
width: '100%',
|
|
407
|
-
height: itemWidth *
|
|
552
|
+
height: itemWidth * ASPECT_RATIO,
|
|
408
553
|
borderRadius,
|
|
409
554
|
overflow: 'hidden',
|
|
410
555
|
backgroundColor: theme.colors.surfaceVariant,
|
|
@@ -415,16 +560,16 @@ const getStyles = (theme: ITheme, itemWidth: number, borderRadius: number) =>
|
|
|
415
560
|
},
|
|
416
561
|
infoContainer: {
|
|
417
562
|
position: 'absolute',
|
|
418
|
-
bottom:
|
|
419
|
-
left:
|
|
420
|
-
right:
|
|
563
|
+
bottom: INFO_CONTAINER_BOTTOM,
|
|
564
|
+
left: INFO_CONTAINER_HORIZONTAL,
|
|
565
|
+
right: INFO_CONTAINER_HORIZONTAL,
|
|
421
566
|
flexDirection: 'row',
|
|
422
567
|
alignItems: 'center',
|
|
423
568
|
justifyContent: 'space-between',
|
|
424
569
|
},
|
|
425
570
|
textSection: {
|
|
426
571
|
flex: 1,
|
|
427
|
-
paddingRight:
|
|
572
|
+
paddingRight: TEXT_SECTION_PADDING_RIGHT,
|
|
428
573
|
},
|
|
429
574
|
titleText: {
|
|
430
575
|
color: theme.colors.white,
|
|
@@ -434,45 +579,45 @@ const getStyles = (theme: ITheme, itemWidth: number, borderRadius: number) =>
|
|
|
434
579
|
subTitleText: {
|
|
435
580
|
color: theme.colors.white,
|
|
436
581
|
fontSize: RFValue(10),
|
|
437
|
-
opacity:
|
|
582
|
+
opacity: SUBTITLE_OPACITY,
|
|
438
583
|
marginTop: verticalScale(2),
|
|
439
584
|
},
|
|
440
585
|
progressBackground: {
|
|
441
586
|
marginTop: verticalScale(4),
|
|
442
587
|
height: verticalScale(4),
|
|
443
|
-
backgroundColor:
|
|
444
|
-
borderRadius:
|
|
588
|
+
backgroundColor: PROGRESS_BG_COLOR,
|
|
589
|
+
borderRadius: PROGRESS_BORDER_RADIUS,
|
|
445
590
|
width: '100%',
|
|
446
591
|
},
|
|
447
592
|
progressForeground: {
|
|
448
593
|
height: '100%',
|
|
449
|
-
borderRadius:
|
|
594
|
+
borderRadius: PROGRESS_BORDER_RADIUS,
|
|
450
595
|
backgroundColor: theme.colors.primary,
|
|
451
596
|
},
|
|
452
597
|
playIconWrapper: {
|
|
453
598
|
justifyContent: 'center',
|
|
454
599
|
alignItems: 'center',
|
|
455
|
-
width:
|
|
456
|
-
height:
|
|
457
|
-
borderRadius:
|
|
600
|
+
width: PLAY_ICON_CONTAINER_SIZE,
|
|
601
|
+
height: PLAY_ICON_CONTAINER_SIZE,
|
|
602
|
+
borderRadius: PLAY_ICON_CONTAINER_RADIUS,
|
|
458
603
|
backgroundColor: theme.colors.blueBackground,
|
|
459
604
|
},
|
|
460
605
|
skeletonTitle: {
|
|
461
|
-
width:
|
|
462
|
-
height:
|
|
463
|
-
borderRadius:
|
|
606
|
+
width: SKELETON_TITLE_WIDTH,
|
|
607
|
+
height: SKELETON_TITLE_HEIGHT,
|
|
608
|
+
borderRadius: SKELETON_BORDER_RADIUS,
|
|
464
609
|
marginBottom: verticalScale(4),
|
|
465
610
|
},
|
|
466
611
|
skeletonSubTitle: {
|
|
467
|
-
width:
|
|
468
|
-
height:
|
|
469
|
-
borderRadius:
|
|
612
|
+
width: SKELETON_SUBTITLE_WIDTH,
|
|
613
|
+
height: SKELETON_SUBTITLE_HEIGHT,
|
|
614
|
+
borderRadius: SKELETON_BORDER_RADIUS,
|
|
470
615
|
marginBottom: verticalScale(6),
|
|
471
616
|
},
|
|
472
617
|
playIconSkeleton: {
|
|
473
|
-
width:
|
|
474
|
-
height:
|
|
475
|
-
borderRadius:
|
|
618
|
+
width: PLAY_ICON_CONTAINER_SIZE,
|
|
619
|
+
height: PLAY_ICON_CONTAINER_SIZE,
|
|
620
|
+
borderRadius: PLAY_ICON_CONTAINER_RADIUS,
|
|
476
621
|
},
|
|
477
622
|
});
|
|
478
623
|
|