@zezosoft/zezo-ott-react-native-ui-kit 1.0.8 → 1.0.9

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 (106) hide show
  1. package/README.md +1 -1
  2. package/lib/module/components/Account/Account.js +1 -1
  3. package/lib/module/components/Account/Account.js.map +1 -1
  4. package/lib/module/components/Auth/AuthProvider/AuthProvider.js +48 -19
  5. package/lib/module/components/Auth/AuthProvider/AuthProvider.js.map +1 -1
  6. package/lib/module/components/Auth/Login/LoginWithEmail.js +4 -2
  7. package/lib/module/components/Auth/Login/LoginWithEmail.js.map +1 -1
  8. package/lib/module/components/Auth/OTP/OTP.js +15 -1
  9. package/lib/module/components/Auth/OTP/OTP.js.map +1 -1
  10. package/lib/module/components/Auth/SignUp/SignUp.js +4 -2
  11. package/lib/module/components/Auth/SignUp/SignUp.js.map +1 -1
  12. package/lib/module/components/BlurView/BlurView.js +171 -0
  13. package/lib/module/components/BlurView/BlurView.js.map +1 -0
  14. package/lib/module/components/BlurView/index.js +9 -0
  15. package/lib/module/components/BlurView/index.js.map +1 -0
  16. package/lib/module/components/Content/Card/Styles/Four.js +1 -1
  17. package/lib/module/components/Content/Card/Styles/Four.js.map +1 -1
  18. package/lib/module/components/Content/Content.js +4 -2
  19. package/lib/module/components/Content/Content.js.map +1 -1
  20. package/lib/module/components/ContentView/ContentView.js +4 -2
  21. package/lib/module/components/ContentView/ContentView.js.map +1 -1
  22. package/lib/module/components/ContentView/components/MiniInfo.js +64 -19
  23. package/lib/module/components/ContentView/components/MiniInfo.js.map +1 -1
  24. package/lib/module/components/Settings/AppSettings.js +1 -1
  25. package/lib/module/components/Settings/AppSettings.js.map +1 -1
  26. package/lib/module/components/Subscription/SubOne.js +340 -13
  27. package/lib/module/components/Subscription/SubOne.js.map +1 -1
  28. package/lib/module/components/TabBar/One.js +71 -108
  29. package/lib/module/components/TabBar/One.js.map +1 -1
  30. package/lib/module/components/TabBar/Three.js +63 -78
  31. package/lib/module/components/TabBar/Three.js.map +1 -1
  32. package/lib/module/components/TabBar/Two.js +110 -106
  33. package/lib/module/components/TabBar/Two.js.map +1 -1
  34. package/lib/module/components/User/PurchaseHistory/PurchaseHistory.js +324 -0
  35. package/lib/module/components/User/PurchaseHistory/PurchaseHistory.js.map +1 -0
  36. package/lib/module/components/User/index.js +2 -1
  37. package/lib/module/components/User/index.js.map +1 -1
  38. package/lib/module/components/index.js +1 -0
  39. package/lib/module/components/index.js.map +1 -1
  40. package/lib/module/hooks/useNavigationMode.js +34 -0
  41. package/lib/module/hooks/useNavigationMode.js.map +1 -0
  42. package/lib/module/utils/Spacing.js +26 -0
  43. package/lib/module/utils/Spacing.js.map +1 -0
  44. package/lib/typescript/src/components/Auth/AuthProvider/AuthProvider.d.ts +1 -0
  45. package/lib/typescript/src/components/Auth/AuthProvider/AuthProvider.d.ts.map +1 -1
  46. package/lib/typescript/src/components/Auth/Login/LoginWithEmail.d.ts.map +1 -1
  47. package/lib/typescript/src/components/Auth/OTP/OTP.d.ts +2 -0
  48. package/lib/typescript/src/components/Auth/OTP/OTP.d.ts.map +1 -1
  49. package/lib/typescript/src/components/Auth/SignUp/SignUp.d.ts.map +1 -1
  50. package/lib/typescript/src/components/Auth/index.d.ts +2 -0
  51. package/lib/typescript/src/components/Auth/index.d.ts.map +1 -1
  52. package/lib/typescript/src/components/BlurView/BlurView.d.ts +48 -0
  53. package/lib/typescript/src/components/BlurView/BlurView.d.ts.map +1 -0
  54. package/lib/typescript/src/components/BlurView/index.d.ts +7 -0
  55. package/lib/typescript/src/components/BlurView/index.d.ts.map +1 -0
  56. package/lib/typescript/src/components/Content/Card/Styles/Four.d.ts.map +1 -1
  57. package/lib/typescript/src/components/Content/Content.d.ts.map +1 -1
  58. package/lib/typescript/src/components/ContentView/ContentView.d.ts +1 -1
  59. package/lib/typescript/src/components/ContentView/ContentView.d.ts.map +1 -1
  60. package/lib/typescript/src/components/ContentView/components/MiniInfo.d.ts +17 -1
  61. package/lib/typescript/src/components/ContentView/components/MiniInfo.d.ts.map +1 -1
  62. package/lib/typescript/src/components/Subscription/SubOne.d.ts +6 -0
  63. package/lib/typescript/src/components/Subscription/SubOne.d.ts.map +1 -1
  64. package/lib/typescript/src/components/Subscription/index.d.ts.map +1 -1
  65. package/lib/typescript/src/components/TabBar/One.d.ts +2 -2
  66. package/lib/typescript/src/components/TabBar/One.d.ts.map +1 -1
  67. package/lib/typescript/src/components/TabBar/Three.d.ts +3 -2
  68. package/lib/typescript/src/components/TabBar/Three.d.ts.map +1 -1
  69. package/lib/typescript/src/components/TabBar/Two.d.ts +13 -4
  70. package/lib/typescript/src/components/TabBar/Two.d.ts.map +1 -1
  71. package/lib/typescript/src/components/TabBar/index.d.ts +1 -1
  72. package/lib/typescript/src/components/User/PurchaseHistory/PurchaseHistory.d.ts +50 -0
  73. package/lib/typescript/src/components/User/PurchaseHistory/PurchaseHistory.d.ts.map +1 -0
  74. package/lib/typescript/src/components/User/index.d.ts +2 -1
  75. package/lib/typescript/src/components/User/index.d.ts.map +1 -1
  76. package/lib/typescript/src/components/index.d.ts +1 -0
  77. package/lib/typescript/src/components/index.d.ts.map +1 -1
  78. package/lib/typescript/src/hooks/useNavigationMode.d.ts +14 -0
  79. package/lib/typescript/src/hooks/useNavigationMode.d.ts.map +1 -0
  80. package/lib/typescript/src/types/content/content-view.types.d.ts +2 -0
  81. package/lib/typescript/src/types/content/content-view.types.d.ts.map +1 -1
  82. package/lib/typescript/src/utils/Spacing.d.ts +16 -0
  83. package/lib/typescript/src/utils/Spacing.d.ts.map +1 -0
  84. package/package.json +9 -5
  85. package/src/components/Account/Account.tsx +1 -1
  86. package/src/components/Auth/AuthProvider/AuthProvider.tsx +82 -37
  87. package/src/components/Auth/Login/LoginWithEmail.tsx +9 -2
  88. package/src/components/Auth/OTP/OTP.tsx +37 -1
  89. package/src/components/Auth/SignUp/SignUp.tsx +9 -2
  90. package/src/components/BlurView/BlurView.tsx +199 -0
  91. package/src/components/BlurView/index.ts +7 -0
  92. package/src/components/Content/Card/Styles/Four.tsx +3 -1
  93. package/src/components/Content/Content.tsx +5 -4
  94. package/src/components/ContentView/ContentView.tsx +8 -1
  95. package/src/components/ContentView/components/MiniInfo.tsx +99 -22
  96. package/src/components/Settings/AppSettings.tsx +1 -1
  97. package/src/components/Subscription/SubOne.tsx +422 -11
  98. package/src/components/TabBar/One.tsx +79 -141
  99. package/src/components/TabBar/Three.tsx +84 -99
  100. package/src/components/TabBar/Two.tsx +139 -110
  101. package/src/components/User/PurchaseHistory/PurchaseHistory.tsx +439 -0
  102. package/src/components/User/index.ts +8 -1
  103. package/src/components/index.ts +1 -0
  104. package/src/hooks/useNavigationMode.ts +35 -0
  105. package/src/types/content/content-view.types.ts +5 -0
  106. package/src/utils/Spacing.ts +27 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Spacing.d.ts","sourceRoot":"","sources":["../../../../src/utils/Spacing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,GACrC,cAAa,MAAW,KACvB,MAIF,CAAC;AAGF,eAAO,MAAM,oBAAoB,iBARlB,MAAM,KAClB,MAO2D,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zezosoft/zezo-ott-react-native-ui-kit",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "A professional React Native UI component library built for OTT applications.",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "lib/typescript/src/index.d.ts",
@@ -85,6 +85,7 @@
85
85
  "eslint-plugin-prettier": "^5.2.3",
86
86
  "jest": "^29.7.0",
87
87
  "lottie-react-native": "^7.3.4",
88
+ "moment": "^2.30.1",
88
89
  "prettier": "^3.0.3",
89
90
  "react": "19.0.0",
90
91
  "react-native": "0.79.6",
@@ -97,6 +98,7 @@
97
98
  "react-native-markdown-display": "^7.0.2",
98
99
  "react-native-mmkv": "^3.3.0",
99
100
  "react-native-modal": "^14.0.0-rc.1",
101
+ "react-native-navigation-mode": "^1.2.3",
100
102
  "react-native-reanimated": "^4.1.0",
101
103
  "react-native-safe-area-context": "^5.6.1",
102
104
  "react-native-super-grid": "^6.0.2",
@@ -110,9 +112,10 @@
110
112
  "peerDependencies": {
111
113
  "@react-native-community/blur": "^4.4.0",
112
114
  "@react-native-masked-view/masked-view": "^0.3.0",
113
- "@react-navigation/bottom-tabs": "^7.4.0",
114
- "@react-navigation/native": "^7.1.0",
115
- "lottie-react-native": "^7.0.0",
115
+ "@react-navigation/bottom-tabs": "*",
116
+ "@react-navigation/native": "*",
117
+ "lottie-react-native": "*",
118
+ "moment": "*",
116
119
  "react": "*",
117
120
  "react-native": "*",
118
121
  "react-native-device-info": "^14.0.0",
@@ -121,6 +124,7 @@
121
124
  "react-native-gesture-handler": "^2.0.0",
122
125
  "react-native-linear-gradient": "^2.8.0",
123
126
  "react-native-mmkv": "*",
127
+ "react-native-navigation-mode": "*",
124
128
  "react-native-nitro-modules": "^0.29.0",
125
129
  "react-native-reanimated": "*",
126
130
  "react-native-safe-area-context": "*",
@@ -129,7 +133,7 @@
129
133
  "react-native-svg": "*",
130
134
  "react-native-video": "*",
131
135
  "react-native-vision-camera": "*",
132
- "react-native-worklets": "^0.5.0"
136
+ "react-native-worklets": "*"
133
137
  },
134
138
  "dependencies": {
135
139
  "color": "^5.0.0",
@@ -133,7 +133,7 @@ export const Account: React.FC<AccountProps> = ({
133
133
  <ScrollView
134
134
  contentContainerStyle={[
135
135
  styles.content,
136
- { paddingBottom: insets.bottom + verticalScale(40) },
136
+ { paddingBottom: verticalScale(100) + insets.bottom },
137
137
  ]}
138
138
  showsVerticalScrollIndicator={false}
139
139
  keyboardShouldPersistTaps="handled"
@@ -2,14 +2,13 @@
2
2
  * @author Naresh Dhamu
3
3
  * @lastModified Tue 22 Oct 2025
4
4
  */
5
- import React, { useEffect, useRef, useState } from 'react';
5
+ import React, { useEffect, useMemo, useRef, useState } from 'react';
6
6
  import {
7
7
  View,
8
8
  StyleSheet,
9
9
  SafeAreaView,
10
10
  TouchableOpacity,
11
11
  Animated,
12
- Platform,
13
12
  } from 'react-native';
14
13
  import { moderateScale, scale, verticalScale } from 'react-native-size-matters';
15
14
  import { useInternalTheme } from '../../../theme/hook/useInternalTheme';
@@ -19,6 +18,7 @@ import { Text } from '../../Text';
19
18
  import { BackgroundLayout } from '../../BackgroundLayout/BackgroundLayout';
20
19
  import { Phone, Mail } from 'lucide-react-native';
21
20
  import { Button } from '../../Button';
21
+ import { default as SkeletonPlaceholder } from 'react-native-skeleton-placeholder';
22
22
 
23
23
  export interface AuthProviderProps {
24
24
  logoUri: string;
@@ -35,6 +35,7 @@ export interface AuthProviderProps {
35
35
  };
36
36
  variant?: 'one' | 'two';
37
37
  theme?: ThemeOverride;
38
+ isLoading?: boolean;
38
39
  authProvider?: {
39
40
  phone?: {
40
41
  enabled?: boolean;
@@ -55,6 +56,7 @@ const AuthProvider: React.FC<AuthProviderProps> = ({
55
56
  text,
56
57
  variant = 'one',
57
58
  theme: overrideTheme,
59
+ isLoading = false,
58
60
  authProvider = {
59
61
  phone: { enabled: true },
60
62
  email: { enabled: true },
@@ -105,46 +107,70 @@ const AuthProvider: React.FC<AuthProviderProps> = ({
105
107
  label: string;
106
108
  icon: React.ReactNode;
107
109
  enabled: boolean;
108
- }[] = [
109
- {
110
- key: 'phone',
111
- label: text?.loginWithPhone || 'Phone',
112
- icon: <Phone size={moderateScale(16)} />,
113
- enabled: phoneEnabled,
114
- },
115
- {
116
- key: 'email',
117
- label: text?.loginWithEmail || 'Email',
118
- icon: <Mail size={moderateScale(16)} />,
119
- enabled: emailEnabled,
120
- },
121
- ];
110
+ }[] = useMemo(
111
+ () => [
112
+ {
113
+ key: 'phone',
114
+ label: text?.loginWithPhone || 'Phone',
115
+ icon: <Phone size={moderateScale(16)} />,
116
+ enabled: phoneEnabled,
117
+ },
118
+ {
119
+ key: 'email',
120
+ label: text?.loginWithEmail || 'Email',
121
+ icon: <Mail size={moderateScale(16)} />,
122
+ enabled: emailEnabled,
123
+ },
124
+ ],
125
+ [text?.loginWithPhone, text?.loginWithEmail, phoneEnabled, emailEnabled]
126
+ );
122
127
 
123
128
  const renderButtons = () => (
124
129
  <View style={styles.buttonContainer}>
125
130
  {authMethods
126
131
  .filter((item) => item.enabled)
127
132
  .map((item) => (
128
- <Button.Secondary
129
- key={item.key}
130
- containerStyle={{
131
- backgroundColor:
132
- activeTab === item.key ? colors.button : 'transparent',
133
- borderWidth: 1.2,
134
- borderColor: colors.button,
135
- }}
136
- titleStyle={{
137
- color:
138
- activeTab === item.key ? colors.buttonText : colors.textPrimary,
139
- }}
140
- title={`Continue with ${item.label}`}
141
- onPress={() => handlePress(item.key)}
142
- leftIcon={React.cloneElement(item.icon as any, {
143
- color:
144
- activeTab === item.key ? colors.buttonText : colors.textPrimary,
145
- size: moderateScale(18),
146
- })}
147
- />
133
+ <React.Fragment key={item.key}>
134
+ {isLoading ? (
135
+ <SkeletonPlaceholder
136
+ backgroundColor={colors.skeletonBaseColor}
137
+ highlightColor={colors.skeletonHighlightColor}
138
+ borderRadius={moderateScale(8)}
139
+ >
140
+ <View
141
+ style={{
142
+ width: '100%',
143
+ height: verticalScale(48),
144
+ borderRadius: moderateScale(8),
145
+ }}
146
+ />
147
+ </SkeletonPlaceholder>
148
+ ) : (
149
+ <Button.Secondary
150
+ containerStyle={{
151
+ backgroundColor:
152
+ activeTab === item.key ? colors.button : 'transparent',
153
+ borderWidth: 1.2,
154
+ borderColor: colors.button,
155
+ }}
156
+ titleStyle={{
157
+ color:
158
+ activeTab === item.key
159
+ ? colors.buttonText
160
+ : colors.textPrimary,
161
+ }}
162
+ title={`Continue with ${item.label}`}
163
+ onPress={() => handlePress(item.key)}
164
+ leftIcon={React.cloneElement(item.icon as any, {
165
+ color:
166
+ activeTab === item.key
167
+ ? colors.buttonText
168
+ : colors.textPrimary,
169
+ size: moderateScale(18),
170
+ })}
171
+ />
172
+ )}
173
+ </React.Fragment>
148
174
  ))}
149
175
  </View>
150
176
  );
@@ -152,6 +178,25 @@ const AuthProvider: React.FC<AuthProviderProps> = ({
152
178
  // Toggle render without absolute
153
179
  const renderToggle = () => {
154
180
  const enabledMethods = authMethods.filter((m) => m.enabled);
181
+
182
+ if (isLoading) {
183
+ return (
184
+ <SkeletonPlaceholder
185
+ backgroundColor={colors.skeletonBaseColor}
186
+ highlightColor={colors.skeletonHighlightColor}
187
+ borderRadius={50}
188
+ >
189
+ <View
190
+ style={{
191
+ width: '100%',
192
+ height: verticalScale(48),
193
+ borderRadius: 50,
194
+ }}
195
+ />
196
+ </SkeletonPlaceholder>
197
+ );
198
+ }
199
+
155
200
  return (
156
201
  <View
157
202
  style={[
@@ -257,7 +302,7 @@ const styles = StyleSheet.create({
257
302
  bottomSection: {
258
303
  width: '100%',
259
304
  alignItems: 'center',
260
- paddingBottom: verticalScale(Platform.OS === 'ios' ? 40 : 30),
305
+ paddingBottom: verticalScale(30),
261
306
  },
262
307
  title: {
263
308
  fontSize: moderateScale(18),
@@ -24,6 +24,7 @@ import BackBtn from '../../Button/BackBtn';
24
24
  import { Text } from '../../Text';
25
25
  import type { ThemeOverride } from '../../../theme/themes';
26
26
  import { RFValue } from 'react-native-responsive-fontsize';
27
+ import { getResponsiveBottomSpacing } from '../../../utils/Spacing';
27
28
 
28
29
  type FormValues = {
29
30
  email: string;
@@ -313,7 +314,14 @@ const LoginWithEmail: React.FC<LoginWithEmailProps> = ({
313
314
  </View>
314
315
 
315
316
  {!isKeyboardOpen && shouldRender(onSignup || renderSignupPrompt) && (
316
- <View style={styles.signupContainer}>
317
+ <View
318
+ style={[
319
+ styles.signupContainer,
320
+ {
321
+ bottom: getResponsiveBottomSpacing(35),
322
+ },
323
+ ]}
324
+ >
317
325
  {renderSignupPrompt ? (
318
326
  renderSignupPrompt({
319
327
  onPress: () => handleKeyboardDismiss(onSignup),
@@ -388,7 +396,6 @@ const styles = StyleSheet.create({
388
396
  },
389
397
  signupContainer: {
390
398
  position: 'absolute',
391
- bottom: verticalScale(30),
392
399
  left: 0,
393
400
  right: 0,
394
401
  alignItems: 'center',
@@ -47,6 +47,8 @@ type OTPProps = {
47
47
  otpDigitCount?: number;
48
48
  keyboardType?: KeyboardTypeOptions;
49
49
  phoneNumber?: string;
50
+ enableAutoFill?: boolean;
51
+ autoSubmitOnFill?: boolean;
50
52
  text?: {
51
53
  otpLabel?: string;
52
54
  otpPlaceholder?: string;
@@ -110,6 +112,8 @@ const OTP: React.FC<OTPProps> = ({
110
112
  otpDigitCount = 4,
111
113
  keyboardType = 'number-pad',
112
114
  phoneNumber,
115
+ enableAutoFill = true,
116
+ autoSubmitOnFill = true,
113
117
  text = DEFAULT_TEXT,
114
118
  onResendOtp,
115
119
  renderResendButton,
@@ -239,6 +243,31 @@ const OTP: React.FC<OTPProps> = ({
239
243
  }
240
244
  }, [onSubmit, otp, otpDigitCount]);
241
245
 
246
+ // Auto-submit when OTP is auto-filled and complete
247
+ useEffect(() => {
248
+ if (
249
+ autoSubmitOnFill &&
250
+ otp.length === otpDigitCount &&
251
+ !isSubmitting &&
252
+ !loading &&
253
+ onSubmit
254
+ ) {
255
+ const timer = setTimeout(() => {
256
+ handleSubmit();
257
+ }, 300); // Small delay to ensure OTP is fully set
258
+ return () => clearTimeout(timer);
259
+ }
260
+ return;
261
+ }, [
262
+ otp,
263
+ otpDigitCount,
264
+ autoSubmitOnFill,
265
+ isSubmitting,
266
+ loading,
267
+ onSubmit,
268
+ handleSubmit,
269
+ ]);
270
+
242
271
  const handleResendOtp = useCallback(() => {
243
272
  if (onResendOtp) {
244
273
  onResendOtp();
@@ -325,7 +354,14 @@ const OTP: React.FC<OTPProps> = ({
325
354
  cellCount={otpDigitCount}
326
355
  rootStyle={styles.codeFieldRoot}
327
356
  keyboardType={keyboardType}
328
- textContentType="oneTimeCode"
357
+ textContentType={enableAutoFill ? 'oneTimeCode' : 'none'}
358
+ autoComplete={
359
+ enableAutoFill
360
+ ? Platform.OS === 'android'
361
+ ? 'sms-otp'
362
+ : 'off'
363
+ : 'off'
364
+ }
329
365
  renderCell={({ index, symbol, isFocused }) => (
330
366
  <Text
331
367
  key={index}
@@ -25,6 +25,7 @@ import BackBtn from '../../Button/BackBtn';
25
25
  import { Text } from '../../Text';
26
26
  import type { ThemeOverride } from '../../../theme/themes';
27
27
  import { RFValue } from 'react-native-responsive-fontsize';
28
+ import { getResponsiveBottomSpacing } from '../../../utils/Spacing';
28
29
 
29
30
  type FormValues = {
30
31
  username: string;
@@ -349,7 +350,14 @@ const Signup: React.FC<SignupProps> = ({
349
350
  (renderLoginPrompt ? (
350
351
  renderLoginPrompt()
351
352
  ) : (
352
- <View style={styles.loginContainerWrapper}>
353
+ <View
354
+ style={[
355
+ styles.loginContainerWrapper,
356
+ {
357
+ bottom: getResponsiveBottomSpacing(35),
358
+ },
359
+ ]}
360
+ >
353
361
  <View style={styles.loginContainer}>
354
362
  <View style={styles.loginRow}>
355
363
  <Text
@@ -415,7 +423,6 @@ const styles = StyleSheet.create({
415
423
  },
416
424
  loginContainerWrapper: {
417
425
  position: 'absolute',
418
- bottom: verticalScale(30),
419
426
  left: 0,
420
427
  right: 0,
421
428
  alignItems: 'center',
@@ -0,0 +1,199 @@
1
+ /**
2
+ * @author Naresh Dhamu
3
+ * @lastModified Thu 06 Nov 2025 at 05:00 PM
4
+ */
5
+
6
+ import React from 'react';
7
+ import { View, StyleSheet, type ViewStyle, type StyleProp } from 'react-native';
8
+
9
+ /**
10
+ * BlurView Props - Same as @react-native-community/blur
11
+ */
12
+ export interface BlurViewProps {
13
+ /** Style of the BlurView container */
14
+ style?: StyleProp<ViewStyle>;
15
+
16
+ /** The blur type (tint) - exactly matches community lib */
17
+ blurType?:
18
+ | 'dark'
19
+ | 'light'
20
+ | 'xlight'
21
+ | 'extraDark'
22
+ | 'regular'
23
+ | 'prominent'
24
+ | 'chromeMaterial'
25
+ | 'material'
26
+ | 'thickMaterial'
27
+ | 'thinMaterial'
28
+ | 'ultraThinMaterial'
29
+ | 'chromeMaterialDark'
30
+ | 'materialDark'
31
+ | 'thickMaterialDark'
32
+ | 'thinMaterialDark'
33
+ | 'ultraThinMaterialDark'
34
+ | 'chromeMaterialLight'
35
+ | 'materialLight'
36
+ | 'thickMaterialLight'
37
+ | 'thinMaterialLight'
38
+ | 'ultraThinMaterialLight';
39
+
40
+ /** The blur intensity amount (0-100) - exactly matches community lib */
41
+ blurAmount?: number;
42
+
43
+ /** Fallback color for reduced transparency - exactly matches community lib */
44
+ reducedTransparencyFallbackColor?: string;
45
+
46
+ /** iOS only: Overlay color - exactly matches community lib */
47
+ overlayColor?: string;
48
+
49
+ /** Android only: Downsample factor (higher = more blur but lower quality) */
50
+ downsampleFactor?: number;
51
+
52
+ /** Android only: Blur radius */
53
+ blurRadius?: number;
54
+
55
+ /** Child components */
56
+ children?: React.ReactNode;
57
+ }
58
+
59
+ /**
60
+ * Custom BlurView - 100% Compatible with @react-native-community/blur
61
+ *
62
+ * ✅ Same API as @react-native-community/blur
63
+ * ✅ Works on iOS, Android, and Web
64
+ * ✅ Drop-in replacement - just change the import
65
+ * 🚫 Simulates blur (no live backdrop) using semi-transparent layers
66
+ *
67
+ * @example
68
+ * ```tsx
69
+ * <BlurView
70
+ * style={styles.blur}
71
+ * blurType="light"
72
+ * blurAmount={10}
73
+ * reducedTransparencyFallbackColor="white"
74
+ * />
75
+ * ```
76
+ */
77
+ const BlurView: React.FC<BlurViewProps> = ({
78
+ style,
79
+ blurType = 'light',
80
+ blurAmount = 100,
81
+ reducedTransparencyFallbackColor,
82
+ overlayColor,
83
+ children,
84
+ }) => {
85
+ // Clamp blur amount to 0-100 range (same as community lib)
86
+ const intensity = Math.max(0, Math.min(100, blurAmount));
87
+
88
+ // Get tint style based on blur type
89
+ const tintStyle = getBlurTintStyle(
90
+ blurType,
91
+ intensity,
92
+ reducedTransparencyFallbackColor,
93
+ overlayColor
94
+ );
95
+
96
+ // Platform-specific rendering
97
+ return (
98
+ <View style={[styles.container, style]}>
99
+ {/* Background blur layer */}
100
+ <View style={[StyleSheet.absoluteFillObject, tintStyle]} />
101
+
102
+ {/* Content layer */}
103
+ <View pointerEvents="box-none" style={styles.content}>
104
+ {children}
105
+ </View>
106
+ </View>
107
+ );
108
+ };
109
+
110
+ /**
111
+ * Get blur tint style based on blurType
112
+ * Matches the exact behavior of @react-native-community/blur
113
+ */
114
+ function getBlurTintStyle(
115
+ blurType: string,
116
+ intensity: number,
117
+ fallbackColor?: string,
118
+ overlayColor?: string
119
+ ): ViewStyle {
120
+ // If overlayColor is provided, use it (iOS behavior)
121
+ if (overlayColor) {
122
+ return { backgroundColor: overlayColor };
123
+ }
124
+
125
+ // Calculate opacity based on intensity (0-100)
126
+ // Higher intensity = more opaque = stronger blur effect
127
+ const opacity = Math.min(0.95, intensity / 100);
128
+ const lightOpacity = opacity * 0.7;
129
+ const darkOpacity = opacity * 0.8;
130
+
131
+ // Match exact blur types from @react-native-community/blur
132
+ switch (blurType) {
133
+ // Dark blur types
134
+ case 'dark':
135
+ return { backgroundColor: `rgba(0, 0, 0, ${darkOpacity})` };
136
+ case 'extraDark':
137
+ return {
138
+ backgroundColor: `rgba(0, 0, 0, ${Math.min(0.98, darkOpacity * 1.2)})`,
139
+ };
140
+ case 'materialDark':
141
+ case 'thickMaterialDark':
142
+ case 'chromeMaterialDark':
143
+ return { backgroundColor: `rgba(28, 28, 30, ${darkOpacity})` };
144
+ case 'thinMaterialDark':
145
+ return { backgroundColor: `rgba(28, 28, 30, ${darkOpacity * 0.7})` };
146
+ case 'ultraThinMaterialDark':
147
+ return { backgroundColor: `rgba(28, 28, 30, ${darkOpacity * 0.5})` };
148
+
149
+ // Light blur types
150
+ case 'light':
151
+ return {
152
+ backgroundColor:
153
+ fallbackColor || `rgba(255, 255, 255, ${lightOpacity})`,
154
+ };
155
+ case 'xlight':
156
+ return { backgroundColor: `rgba(255, 255, 255, ${lightOpacity * 0.6})` };
157
+ case 'materialLight':
158
+ case 'chromeMaterialLight':
159
+ return { backgroundColor: `rgba(255, 255, 255, ${lightOpacity})` };
160
+ case 'thickMaterialLight':
161
+ return { backgroundColor: `rgba(242, 242, 247, ${lightOpacity})` };
162
+ case 'thinMaterialLight':
163
+ return { backgroundColor: `rgba(242, 242, 247, ${lightOpacity * 0.7})` };
164
+ case 'ultraThinMaterialLight':
165
+ return { backgroundColor: `rgba(242, 242, 247, ${lightOpacity * 0.5})` };
166
+
167
+ // Regular/prominent types
168
+ case 'regular':
169
+ case 'prominent':
170
+ return { backgroundColor: `rgba(255, 255, 255, ${lightOpacity * 0.8})` };
171
+ case 'material':
172
+ case 'chromeMaterial':
173
+ return { backgroundColor: `rgba(242, 242, 247, ${lightOpacity})` };
174
+ case 'thickMaterial':
175
+ return { backgroundColor: `rgba(242, 242, 247, ${lightOpacity * 1.1})` };
176
+ case 'thinMaterial':
177
+ return { backgroundColor: `rgba(242, 242, 247, ${lightOpacity * 0.7})` };
178
+ case 'ultraThinMaterial':
179
+ return { backgroundColor: `rgba(242, 242, 247, ${lightOpacity * 0.5})` };
180
+
181
+ // Default
182
+ default:
183
+ return {
184
+ backgroundColor:
185
+ fallbackColor || `rgba(255, 255, 255, ${lightOpacity})`,
186
+ };
187
+ }
188
+ }
189
+
190
+ const styles = StyleSheet.create({
191
+ container: {
192
+ overflow: 'hidden',
193
+ },
194
+ content: {
195
+ flex: 1,
196
+ },
197
+ });
198
+
199
+ export default BlurView;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @author Naresh Dhamu
3
+ * @lastModified Thu 06 Nov 2025 at 05:00 PM
4
+ */
5
+
6
+ export { default as BlurView, default } from './BlurView';
7
+ export type { BlurViewProps } from './BlurView';
@@ -234,7 +234,9 @@ const MovieCardFour: React.FC<MovieCardFourProps> = ({
234
234
  ref={flatListRef}
235
235
  data={data}
236
236
  horizontal
237
- keyExtractor={(item, index) => `${item._id}-${index}`}
237
+ keyExtractor={(item, index) =>
238
+ item._id || `item-${item.slug || item.name || index}`
239
+ }
238
240
  renderItem={renderItem}
239
241
  showsHorizontalScrollIndicator={false}
240
242
  contentContainerStyle={styles.listContent}
@@ -12,7 +12,7 @@ import {
12
12
  type StyleProp,
13
13
  type ViewStyle,
14
14
  } from 'react-native';
15
- import { scale } from 'react-native-size-matters';
15
+ import { scale, verticalScale } from 'react-native-size-matters';
16
16
  import Animated, {
17
17
  type AnimatedStyle,
18
18
  type SharedValue,
@@ -26,6 +26,7 @@ import type { IHistoryItem } from './Card/NowWatching/NowWatching';
26
26
  import type { ThemeOverride } from '../../theme/themes';
27
27
  import { NoContentFallback, type NoContentFallbackProps } from '../Fallbacks';
28
28
  import { useInternalTheme } from '../../theme/hook';
29
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
29
30
 
30
31
  export interface ICustomComponentsForContent {
31
32
  type: string;
@@ -150,6 +151,7 @@ export const Content: React.FC<IContentProps> = ({
150
151
  isLoading,
151
152
  noContentFallbackProps,
152
153
  }) => {
154
+ const insets = useSafeAreaInsets();
153
155
  const sectionData = useMemo<IGetSectionData[]>(
154
156
  () => contentData?.sectionData ?? [],
155
157
  [contentData?.sectionData]
@@ -247,9 +249,8 @@ export const Content: React.FC<IContentProps> = ({
247
249
  }
248
250
  onEndReachedThreshold={0.7}
249
251
  contentContainerStyle={[
250
- {
251
- paddingBottom: scale(100),
252
- },
252
+ { paddingBottom: verticalScale(100) + insets.bottom },
253
+
253
254
  contentContainerStyle,
254
255
  ]}
255
256
  />
@@ -33,6 +33,7 @@ export const ContentView = ({
33
33
  recommendedContentCardStyles,
34
34
  history,
35
35
  episodeCardMode,
36
+ pricingAndExpiryInfo,
36
37
  }: ComponentProps) => {
37
38
  const { theme: appliedTheme } = useInternalTheme(theme);
38
39
  const seekTime = history?.currentTime || 0;
@@ -95,7 +96,13 @@ export const ContentView = ({
95
96
  isLoading={isLoading}
96
97
  style={genreTagsStyles}
97
98
  />
98
- <MiniInfo content={content} theme={theme} isLoading={isLoading} />
99
+ <MiniInfo
100
+ content={content}
101
+ theme={theme}
102
+ isLoading={isLoading}
103
+ {...pricingAndExpiryInfo}
104
+ />
105
+
99
106
  <AboutSection
100
107
  theme={appliedTheme}
101
108
  description={content?.description}