updated code with dsc and device binding

This commit is contained in:
Abin Toppo
2026-05-08 13:39:41 +05:30
parent c1ecc97e29
commit 66461370a2
120 changed files with 11910 additions and 8347 deletions
+171 -96
View File
@@ -1,124 +1,173 @@
import React, { useEffect, useRef } from 'react';
import React, { useEffect } from 'react';
import {
View,
Text,
TouchableOpacity,
StyleSheet,
Dimensions,
Animated,
Platform,
} from 'react-native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import * as LucideIcons from 'lucide-react-native';
import Animated, {
useAnimatedStyle,
useSharedValue,
withSpring,
withTiming,
interpolate,
Extrapolation
} from 'react-native-reanimated';
import Screens from '../Screens';
import colors from '../Constant/Color';
import NavigationString from '../Constant/NavigationString';
import EditableExcel from '../Screens/Tender/Component/EnvelopeCExcelPreview';
import { useTheme } from '../Hooks/useTheme';
import { typography } from '../theme/typography';
// import EditableExcel from '../Screens/Tender/Component/EnvelopeCExcelPreview';
const { width } = Dimensions.get('window');
const TAB_BAR_HEIGHT = 60;
const TAB_BAR_HEIGHT = 70; // Slightly taller for premium feel
const TAB_BUTTON_WIDTH = width / 4;
const Tab = createBottomTabNavigator();
const TabButton = ({ route, isFocused, onPress }: any) => {
const icons: Record<string, { outline: any; filled: any }> = {
Home: { outline: "Home", filled: "Home" },
const { colors } = useTheme();
const icons: Record<string, { outline: keyof typeof LucideIcons; filled: keyof typeof LucideIcons }> = {
Home: { outline: "House", filled: "House" },
Auction: { outline: "Gavel", filled: "Gavel" },
Tender: { outline: "FileText", filled: "FileText" },
Profile: { outline: "User", filled: "User" },
};
const IconName = LucideIcons[isFocused ? icons[route.name].filled : icons[route.name].outline];
const scaleAnim = useRef(new Animated.Value(1)).current;
const translateYAnim = useRef(new Animated.Value(0)).current;
const opacityAnim = useRef(new Animated.Value(1)).current;
// Lucide icons don't always have 'filled' variants in the set, so we might use the same icon
// or rely on color/strokeWidth to indicate state.
const iconKey = icons[route.name]?.outline || "HelpCircle"; // Fallback
const IconName = LucideIcons[iconKey] as React.ElementType;
const scale = useSharedValue(0);
const translateY = useSharedValue(0);
useEffect(() => {
if (isFocused) {
Animated.parallel([
Animated.sequence([
Animated.timing(translateYAnim, {
toValue: -8,
duration: 120,
useNativeDriver: true,
}),
Animated.spring(translateYAnim, {
toValue: 0,
friction: 3,
tension: 80,
useNativeDriver: true,
}),
]),
Animated.spring(scaleAnim, {
toValue: 1.3,
friction: 5,
tension: 150,
useNativeDriver: true,
}),
Animated.timing(opacityAnim, {
toValue: 1,
duration: 250,
useNativeDriver: true,
}),
]).start();
scale.value = withSpring(1, { damping: 12, stiffness: 100 });
translateY.value = withSpring(-4, { damping: 12, stiffness: 100 });
} else {
Animated.parallel([
Animated.spring(scaleAnim, {
toValue: 1,
friction: 5,
tension: 150,
useNativeDriver: true,
}),
Animated.timing(opacityAnim, {
toValue: 0.6,
duration: 150,
useNativeDriver: true,
}),
]).start();
scale.value = withTiming(0, { duration: 200 });
translateY.value = withSpring(0, { damping: 12, stiffness: 100 });
}
}, [isFocused]);
const animatedPillStyle = useAnimatedStyle(() => {
return {
transform: [{ scale: scale.value }],
opacity: interpolate(scale.value, [0, 1], [0, 1], Extrapolation.CLAMP),
};
});
const animatedIconStyle = useAnimatedStyle(() => {
return {
transform: [{ scale: interpolate(scale.value, [0, 1], [1, 0.9]) }], // Slight shrink on press
};
});
const animatedTextStyle = useAnimatedStyle(() => {
const opacity = interpolate(scale.value, [0, 1], [0, 1]);
const translateX = interpolate(scale.value, [0, 1], [20, 0]); // Slide in from right
return {
opacity,
transform: [{ translateX }],
display: scale.value === 0 ? 'none' : 'flex', // Hide when inactive
marginLeft: 4, // Reduced space
};
});
return (
<TouchableOpacity
onPress={onPress}
style={[styles.tabButton, { width: TAB_BUTTON_WIDTH }]}
style={styles.tabButton}
activeOpacity={0.8}
>
<Animated.View
style={[
styles.iconContainer,
{
transform: [{ scale: scaleAnim }, { translateY: translateYAnim }],
opacity: opacityAnim,
},
]}
>
{IconName && (
<IconName
size={20}
color={isFocused ? colors.primary : '#888'}
strokeWidth={2}
/>
)}
</Animated.View>
<View style={styles.tabContent}>
<Animated.View style={animatedIconStyle}>
{IconName && (
<IconName
size={24}
color={isFocused ? colors.primary : colors.text}
strokeWidth={isFocused ? 2.5 : 2}
/>
)}
</Animated.View>
<Text
style={[
styles.label,
{
color: isFocused ? colors.primary : '#888',
fontWeight: isFocused ? '600' : '400',
},
]}
>
{route.name === 'BrandDay' ? 'Coupons' : route.name}
</Text>
{isFocused && (
<Animated.Text
style={[
styles.label,
animatedTextStyle,
{
color: colors.primary,
fontFamily: typography.fonts.medium,
fontWeight: undefined, // Remove fontWeight as we use fontFamily
},
]}
numberOfLines={1}
>
{route.name === 'BrandDay' ? 'Coupons' : route.name}
</Animated.Text>
)}
</View>
</TouchableOpacity>
);
};
const CustomTabBar = ({ state, descriptors, navigation }: any) => {
const { colors, shadows } = useTheme();
const { width: windowWidth } = Dimensions.get('window');
const TAB_BAR_WIDTH = windowWidth - 40; // 20 margin each side
const TAB_PADDING_H = 10; // 5 padding left + 5 padding right
const TAB_WIDTH = (TAB_BAR_WIDTH - TAB_PADDING_H) / state.routes.length;
const translateX = useSharedValue(0);
useEffect(() => {
translateX.value = withSpring(state.index * TAB_WIDTH, {
damping: 15,
stiffness: 150,
mass: 0.5,
});
}, [state.index]);
const animatedIndicatorStyle = useAnimatedStyle(() => {
return {
transform: [{ translateX: translateX.value }],
};
});
return (
<View style={styles.tabBar}>
<View style={[
styles.tabBar,
{
backgroundColor: colors.background, // Use transparent to allow shadow to show
shadowColor: colors.shadow, // Dynamic shadow color
shadowOffset: { width: 0, height: 10 },
shadowOpacity: 0.2, // Consistent opacity
shadowRadius: 10,
borderColor: colors.border, // Subtle border for definition
borderWidth: 3,
elevation: 20,
}
]}>
<Animated.View
style={[
styles.slidingIndicator,
{
width: TAB_WIDTH,
backgroundColor: colors.primary,
opacity: 0.3,
elevation: 10, // Subtle elevation for the indicator
},
animatedIndicatorStyle,
]}
/>
{state.routes.map((route: any, index: number) => {
const isFocused = state.index === index;
@@ -136,8 +185,9 @@ const CustomTabBar = ({ state, descriptors, navigation }: any) => {
};
export default function BottomTab() {
const { colors } = useTheme();
return (
<View style={styles.container}>
<View style={[styles.container, { backgroundColor: colors.background }]}>
<Tab.Navigator
tabBar={(props) => <CustomTabBar {...props} />}
screenOptions={{
@@ -148,9 +198,9 @@ export default function BottomTab() {
<Tab.Screen name="Home" component={Screens.Home} />
<Tab.Screen name={NavigationString.Auction} component={Screens.Auction} />
<Tab.Screen name={NavigationString.Tender} component={Screens.Tender} />
{/* <Tab.Screen name={'EditableExcel'} component={EditableExcel} /> */}
<Tab.Screen name={NavigationString.Profile} component={Screens.ProfileTab} />
{/* <Tab.Screen name={'EditableExcel'} component={EditableExcel} /> */}
<Tab.Screen name={NavigationString.Profile} component={Screens.ProfileTab} />
</Tab.Navigator>
</View>
);
@@ -159,29 +209,54 @@ export default function BottomTab() {
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
tabBar: {
position: 'absolute',
bottom: 20,
left: 20,
right: 20,
flexDirection: 'row',
height: TAB_BAR_HEIGHT,
backgroundColor: '#fff',
borderTopWidth: 1,
borderTopColor: '#eee',
elevation: 5,
height: 70,
borderRadius: 35,
elevation: 20, // stronger Android elevation
shadowColor: '#000', // iOS shadow color
shadowOffset: { width: 0, height: 10 },
shadowOpacity: Platform.OS === 'ios' ? 0.25 : 0.2,
shadowRadius: 12,
overflow: 'visible', // allow shadow to render outside rounded corners
zIndex: 9999,
paddingBottom: 0,
justifyContent: 'space-around',
alignItems: 'center',
paddingHorizontal: 5,
},
tabButton: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
height: '100%',
},
iconContainer: {
marginBottom: 4,
justifyContent: 'center',
tabContent: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: 4, // Drastically reduced from 12
paddingVertical: 4,
borderRadius: 20,
},
slidingIndicator: {
position: 'absolute',
top: 12,
left: 5,
height: 40,
borderRadius: 30,
zIndex: 0,
},
label: {
fontSize: 11,
textAlign: 'center',
includeFontPadding: false,
fontSize: 11, // Slightly smaller text
textAlign: 'left',
textTransform: 'capitalize',
letterSpacing: 0.2, // Tighter spacing
},
});