added loading animations

This commit is contained in:
tapframe 2025-08-13 03:06:42 +05:30
parent facffe0f19
commit 77029294aa
8 changed files with 133 additions and 7 deletions

Binary file not shown.

View file

@ -25,7 +25,7 @@ config.transformer = {
// Optimize resolver for better tree shaking and SVG support // Optimize resolver for better tree shaking and SVG support
config.resolver = { config.resolver = {
...config.resolver, ...config.resolver,
assetExts: config.resolver.assetExts.filter((ext) => ext !== 'svg'), assetExts: [...config.resolver.assetExts.filter((ext) => ext !== 'svg'), 'lottie'],
sourceExts: [...config.resolver.sourceExts, 'svg'], sourceExts: [...config.resolver.sourceExts, 'svg'],
resolverMainFields: ['react-native', 'browser', 'main'], resolverMainFields: ['react-native', 'browser', 'main'],
}; };

21
package-lock.json generated
View file

@ -46,6 +46,7 @@
"expo-system-ui": "^4.0.9", "expo-system-ui": "^4.0.9",
"expo-web-browser": "~14.0.2", "expo-web-browser": "~14.0.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"lottie-react-native": "^7.3.1",
"react": "18.3.1", "react": "18.3.1",
"react-native": "0.76.9", "react-native": "0.76.9",
"react-native-gesture-handler": "~2.20.2", "react-native-gesture-handler": "~2.20.2",
@ -10434,6 +10435,26 @@
"loose-envify": "cli.js" "loose-envify": "cli.js"
} }
}, },
"node_modules/lottie-react-native": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/lottie-react-native/-/lottie-react-native-7.3.1.tgz",
"integrity": "sha512-VW0gtiP1i3Jv6+PaVaNg6QDIqAXwAqmxVp1UOJFqsB6FeBN0zc8M/XR8DE8YiayZzd149nlqGOgmwoV7FbRGDw==",
"license": "Apache-2.0",
"peerDependencies": {
"@lottiefiles/dotlottie-react": "^0.6.5",
"react": "*",
"react-native": ">=0.46",
"react-native-windows": ">=0.63.x"
},
"peerDependenciesMeta": {
"@lottiefiles/dotlottie-react": {
"optional": true
},
"react-native-windows": {
"optional": true
}
}
},
"node_modules/lower-case": { "node_modules/lower-case": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",

View file

@ -47,6 +47,7 @@
"expo-system-ui": "^4.0.9", "expo-system-ui": "^4.0.9",
"expo-web-browser": "~14.0.2", "expo-web-browser": "~14.0.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"lottie-react-native": "^7.3.1",
"react": "18.3.1", "react": "18.3.1",
"react-native": "0.76.9", "react-native": "0.76.9",
"react-native-gesture-handler": "~2.20.2", "react-native-gesture-handler": "~2.20.2",

View file

@ -0,0 +1,86 @@
import React from 'react';
import { View, Text, StyleSheet, Dimensions } from 'react-native';
import LottieView from 'lottie-react-native';
import { useTheme } from '../../contexts/ThemeContext';
interface DogLoadingSpinnerProps {
text?: string;
size?: 'small' | 'medium' | 'large';
style?: any;
source?: any; // optional override for Lottie source
offsetY?: number; // optional vertical offset
}
const DogLoadingSpinner: React.FC<DogLoadingSpinnerProps> = ({
text,
size = 'large',
style,
source,
offsetY = 0,
}) => {
const { currentTheme } = useTheme();
const getSizeStyles = () => {
switch (size) {
case 'small':
return { width: 60, height: 60 };
case 'medium':
return { width: 100, height: 100 };
case 'large':
default:
return { width: 150, height: 150 };
}
};
const getTextSize = () => {
switch (size) {
case 'small':
return 12;
case 'medium':
return 14;
case 'large':
default:
return 16;
}
};
return (
<View style={[styles.container, { transform: [{ translateY: offsetY }] }, style]}>
<LottieView
source={source || require('../../../assets/dog-running.lottie')}
autoPlay
loop
style={[styles.animation, getSizeStyles()]}
resizeMode="contain"
/>
{text && (
<Text style={[
styles.text,
{
color: currentTheme.colors.textMuted,
fontSize: getTextSize()
}
]}>
{text}
</Text>
)}
</View>
);
};
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
},
animation: {
// Size will be set by getSizeStyles()
},
text: {
marginTop: 16,
textAlign: 'center',
fontWeight: '500',
},
});
export default DogLoadingSpinner;

View file

@ -48,6 +48,7 @@ import { useSettings, settingsEmitter } from '../hooks/useSettings';
import FeaturedContent from '../components/home/FeaturedContent'; import FeaturedContent from '../components/home/FeaturedContent';
import CatalogSection from '../components/home/CatalogSection'; import CatalogSection from '../components/home/CatalogSection';
import { SkeletonFeatured } from '../components/home/SkeletonLoaders'; import { SkeletonFeatured } from '../components/home/SkeletonLoaders';
import DogLoadingSpinner from '../components/common/DogLoadingSpinner';
import homeStyles, { sharedStyles } from '../styles/homeStyles'; import homeStyles, { sharedStyles } from '../styles/homeStyles';
import { useTheme } from '../contexts/ThemeContext'; import { useTheme } from '../contexts/ThemeContext';
import type { Theme } from '../contexts/ThemeContext'; import type { Theme } from '../contexts/ThemeContext';
@ -92,7 +93,7 @@ const SkeletonCatalog = React.memo(() => {
return ( return (
<View style={styles.catalogContainer}> <View style={styles.catalogContainer}>
<View style={styles.loadingPlaceholder}> <View style={styles.loadingPlaceholder}>
<ActivityIndicator size="small" color={currentTheme.colors.primary} /> <DogLoadingSpinner size="small" text="" />
</View> </View>
</View> </View>
); );
@ -545,8 +546,7 @@ const HomeScreen = () => {
translucent translucent
/> />
<View style={styles.loadingMainContainer}> <View style={styles.loadingMainContainer}>
<ActivityIndicator size="large" color={currentTheme.colors.primary} /> <DogLoadingSpinner size="large" offsetY={-20} />
<Text style={[styles.loadingText, { color: currentTheme.colors.textMuted }]}>Loading your content...</Text>
</View> </View>
</View> </View>
); );
@ -633,7 +633,7 @@ const HomeScreen = () => {
<View style={styles.catalogPlaceholder}> <View style={styles.catalogPlaceholder}>
<View style={styles.placeholderHeader}> <View style={styles.placeholderHeader}>
<View style={[styles.placeholderTitle, { backgroundColor: currentTheme.colors.elevation1 }]} /> <View style={[styles.placeholderTitle, { backgroundColor: currentTheme.colors.elevation1 }]} />
<ActivityIndicator size="small" color={currentTheme.colors.primary} /> <DogLoadingSpinner size="small" text="" />
</View> </View>
<ScrollView <ScrollView
horizontal horizontal
@ -793,7 +793,7 @@ const styles = StyleSheet.create<any>({
flex: 1, flex: 1,
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
paddingBottom: 90, // Ensure perfect centering
}, },
loadingText: { loadingText: {
marginTop: 12, marginTop: 12,

View file

@ -40,9 +40,11 @@ import { logger } from '../utils/logger';
import { BlurView } from 'expo-blur'; import { BlurView } from 'expo-blur';
import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useTheme } from '../contexts/ThemeContext'; import { useTheme } from '../contexts/ThemeContext';
import DogLoadingSpinner from '../components/common/DogLoadingSpinner';
const { width, height } = Dimensions.get('window'); const { width, height } = Dimensions.get('window');
const isTablet = width >= 768; const isTablet = width >= 768;
const TAB_BAR_HEIGHT = 85;
// Tablet-optimized poster sizes // Tablet-optimized poster sizes
const HORIZONTAL_ITEM_WIDTH = isTablet ? width * 0.18 : width * 0.3; const HORIZONTAL_ITEM_WIDTH = isTablet ? width * 0.18 : width * 0.3;
@ -582,7 +584,13 @@ const SearchScreen = () => {
{/* Content Container */} {/* Content Container */}
<View style={[styles.contentContainer, { backgroundColor: currentTheme.colors.darkBackground }]}> <View style={[styles.contentContainer, { backgroundColor: currentTheme.colors.darkBackground }]}>
{searching ? ( {searching ? (
<SimpleSearchAnimation /> <View style={styles.loadingOverlay} pointerEvents="none">
<DogLoadingSpinner
size="large"
offsetY={-60}
source={require('../../assets/Progress of loading hand.lottie')}
/>
</View>
) : query.trim().length === 1 ? ( ) : query.trim().length === 1 ? (
<Animated.View <Animated.View
style={styles.emptyContainer} style={styles.emptyContainer}
@ -815,6 +823,16 @@ const styles = StyleSheet.create({
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
}, },
loadingOverlay: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
justifyContent: 'center',
alignItems: 'center',
zIndex: 5,
},
loadingText: { loadingText: {
marginTop: 16, marginTop: 16,
fontSize: 16, fontSize: 16,