diff --git a/assets/Progress of loading hand.lottie b/assets/Progress of loading hand.lottie new file mode 100644 index 0000000..64c9a2a Binary files /dev/null and b/assets/Progress of loading hand.lottie differ diff --git a/assets/Dog Running.lottie b/assets/dog-running.lottie similarity index 100% rename from assets/Dog Running.lottie rename to assets/dog-running.lottie diff --git a/metro.config.js b/metro.config.js index dc78200..9ef0040 100644 --- a/metro.config.js +++ b/metro.config.js @@ -25,7 +25,7 @@ config.transformer = { // Optimize resolver for better tree shaking and SVG support 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'], resolverMainFields: ['react-native', 'browser', 'main'], }; diff --git a/package-lock.json b/package-lock.json index 1e1eded..2cba9c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,6 +46,7 @@ "expo-system-ui": "^4.0.9", "expo-web-browser": "~14.0.2", "lodash": "^4.17.21", + "lottie-react-native": "^7.3.1", "react": "18.3.1", "react-native": "0.76.9", "react-native-gesture-handler": "~2.20.2", @@ -10434,6 +10435,26 @@ "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": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", diff --git a/package.json b/package.json index 8ab9089..b7e6eae 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "expo-system-ui": "^4.0.9", "expo-web-browser": "~14.0.2", "lodash": "^4.17.21", + "lottie-react-native": "^7.3.1", "react": "18.3.1", "react-native": "0.76.9", "react-native-gesture-handler": "~2.20.2", diff --git a/src/components/common/DogLoadingSpinner.tsx b/src/components/common/DogLoadingSpinner.tsx new file mode 100644 index 0000000..0bdf629 --- /dev/null +++ b/src/components/common/DogLoadingSpinner.tsx @@ -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 = ({ + 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 ( + + + {text && ( + + {text} + + )} + + ); +}; + +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; diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index ef5f768..edf15ae 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -48,6 +48,7 @@ import { useSettings, settingsEmitter } from '../hooks/useSettings'; import FeaturedContent from '../components/home/FeaturedContent'; import CatalogSection from '../components/home/CatalogSection'; import { SkeletonFeatured } from '../components/home/SkeletonLoaders'; +import DogLoadingSpinner from '../components/common/DogLoadingSpinner'; import homeStyles, { sharedStyles } from '../styles/homeStyles'; import { useTheme } from '../contexts/ThemeContext'; import type { Theme } from '../contexts/ThemeContext'; @@ -92,7 +93,7 @@ const SkeletonCatalog = React.memo(() => { return ( - + ); @@ -545,8 +546,7 @@ const HomeScreen = () => { translucent /> - - Loading your content... + ); @@ -633,7 +633,7 @@ const HomeScreen = () => { - + ({ flex: 1, justifyContent: 'center', alignItems: 'center', - paddingBottom: 90, + // Ensure perfect centering }, loadingText: { marginTop: 12, diff --git a/src/screens/SearchScreen.tsx b/src/screens/SearchScreen.tsx index 4780d13..9c7edd1 100644 --- a/src/screens/SearchScreen.tsx +++ b/src/screens/SearchScreen.tsx @@ -40,9 +40,11 @@ import { logger } from '../utils/logger'; import { BlurView } from 'expo-blur'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useTheme } from '../contexts/ThemeContext'; +import DogLoadingSpinner from '../components/common/DogLoadingSpinner'; const { width, height } = Dimensions.get('window'); const isTablet = width >= 768; +const TAB_BAR_HEIGHT = 85; // Tablet-optimized poster sizes const HORIZONTAL_ITEM_WIDTH = isTablet ? width * 0.18 : width * 0.3; @@ -582,7 +584,13 @@ const SearchScreen = () => { {/* Content Container */} {searching ? ( - + + + ) : query.trim().length === 1 ? (