diff --git a/lib/core/localizations/app_localizations.dart b/lib/core/localizations/app_localizations.dart index 81a8231..7808ce7 100644 --- a/lib/core/localizations/app_localizations.dart +++ b/lib/core/localizations/app_localizations.dart @@ -3,7 +3,6 @@ import '../providers/language_provider.dart'; class AppLocalizations { final Locale locale; - AppLocalizations(this.locale); static AppLocalizations? of(BuildContext context) { @@ -18,6 +17,10 @@ class AppLocalizations { switch (locale.languageCode) { case 'hi': return 'द वॉलपेपर कंपनी'; + case 'es': + return 'La Compañía de Fondos'; + case 'ja': + return '壁紙会社'; default: return 'The Wallpaper Co.'; } @@ -27,6 +30,10 @@ class AppLocalizations { switch (locale.languageCode) { case 'hi': return 'शीर्षक या श्रेणी द्वारा वॉलपेपर खोजें...'; + case 'es': + return 'Busca fondos por título o categoría...'; + case 'ja': + return 'タイトルやカテゴリで壁紙を検索...'; default: return 'Search wallpapers by title or category...'; } @@ -36,6 +43,10 @@ class AppLocalizations { switch (locale.languageCode) { case 'hi': return 'होम'; + case 'es': + return 'Inicio'; + case 'ja': + return 'ホーム'; default: return 'Home'; } @@ -45,6 +56,10 @@ class AppLocalizations { switch (locale.languageCode) { case 'hi': return 'पसंदीदा'; + case 'es': + return 'Favoritos'; + case 'ja': + return 'お気に入り'; default: return 'Favorites'; } @@ -54,6 +69,10 @@ class AppLocalizations { switch (locale.languageCode) { case 'hi': return 'सभी'; + case 'es': + return 'Todo'; + case 'ja': + return 'すべて'; default: return 'All'; } @@ -63,6 +82,10 @@ class AppLocalizations { switch (locale.languageCode) { case 'hi': return 'प्रकृति'; + case 'es': + return 'Naturaleza'; + case 'ja': + return '自然'; default: return 'Nature'; } @@ -72,6 +95,10 @@ class AppLocalizations { switch (locale.languageCode) { case 'hi': return 'अमूर्त'; + case 'es': + return 'Abstracto'; + case 'ja': + return '抽象的'; default: return 'Abstract'; } @@ -81,6 +108,10 @@ class AppLocalizations { switch (locale.languageCode) { case 'hi': return 'शहरी'; + case 'es': + return 'Urbano'; + case 'ja': + return '都市'; default: return 'Urban'; } @@ -90,6 +121,10 @@ class AppLocalizations { switch (locale.languageCode) { case 'hi': return 'न्यूनतम'; + case 'es': + return 'Minimalista'; + case 'ja': + return 'ミニマル'; default: return 'Minimal'; } @@ -99,6 +134,10 @@ class AppLocalizations { switch (locale.languageCode) { case 'hi': return 'अंतरिक्ष'; + case 'es': + return 'Espacio'; + case 'ja': + return '宇宙'; default: return 'Space'; } @@ -108,6 +147,10 @@ class AppLocalizations { switch (locale.languageCode) { case 'hi': return 'जानवर'; + case 'es': + return 'Animales'; + case 'ja': + return '動物'; default: return 'Animals'; } @@ -117,6 +160,10 @@ class AppLocalizations { switch (locale.languageCode) { case 'hi': return 'कला'; + case 'es': + return 'Arte'; + case 'ja': + return 'アート'; default: return 'Art'; } @@ -126,107 +173,77 @@ class AppLocalizations { switch (locale.languageCode) { case 'hi': return 'कारें'; + case 'es': + return 'Coches'; + case 'ja': + return '車'; default: return 'Cars'; } } - String get noResultsTitle { - switch (locale.languageCode) { - case 'hi': - return 'कोई वॉलपेपर नहीं मिला'; - default: - return 'No wallpapers found'; - } - } - - String noResultsMessage(String query) { - switch (locale.languageCode) { - case 'hi': - return '"$query" के लिए कोई परिणाम नहीं'; - default: - return 'No results for "$query"'; - } - } - - String get clearSearch { - switch (locale.languageCode) { - case 'hi': - return 'खोज साफ़ करें'; - default: - return 'Clear Search'; - } - } - String get download { switch (locale.languageCode) { case 'hi': return 'डाउनलोड'; + case 'es': + return 'Descargar'; + case 'ja': + return 'ダウンロード'; default: return 'Download'; } } - String get setWallpaper { - switch (locale.languageCode) { - case 'hi': - return 'वॉलपेपर सेट करें'; - default: - return 'Set Wallpaper'; - } - } - String get share { switch (locale.languageCode) { case 'hi': return 'साझा करें'; + case 'es': + return 'Compartir'; + case 'ja': + return '共有する'; default: return 'Share'; } } - String get loading { - switch (locale.languageCode) { - case 'hi': - return 'लोड हो रहा है...'; - default: - return 'Loading...'; - } - } - - String get error { - switch (locale.languageCode) { - case 'hi': - return 'त्रुटि'; - default: - return 'Error'; - } - } - - String get retry { + String get clearSearch { switch (locale.languageCode) { case 'hi': - return 'पुनः प्रयास करें'; + return 'खोज साफ़ करें'; + case 'es': + return 'Borrar búsqueda'; + case 'ja': + return '検索をクリア'; default: - return 'Retry'; + return 'Clear Search'; } } - String get noFavorites { + String get noResultsTitle { switch (locale.languageCode) { case 'hi': - return 'अभी तक कोई पसंदीदा नहीं'; + return 'कोई वॉलपेपर नहीं मिला'; + case 'es': + return 'No se encontraron fondos'; + case 'ja': + return '壁紙が見つかりません'; default: - return 'No favorites yet'; + return 'No wallpapers found'; } } - String get noFavoritesMessage { + String noResultsMessage(String query) { switch (locale.languageCode) { case 'hi': - return 'यहाँ देखने के लिए कुछ वॉलपेपर को अपने पसंदीदा में जोड़ें'; + return '"$query" के लिए कोई परिणाम नहीं'; + case 'es': + return 'Sin resultados para "$query"'; + case 'ja': + return '"$query" の結果はありません'; default: - return 'Add some wallpapers to your favorites to see them here'; + return 'No results for "$query"'; } } } diff --git a/lib/core/providers/language_provider.dart b/lib/core/providers/language_provider.dart index 7e92be5..08f4854 100644 --- a/lib/core/providers/language_provider.dart +++ b/lib/core/providers/language_provider.dart @@ -7,34 +7,50 @@ class LanguageProvider extends ChangeNotifier { Locale get currentLocale => _currentLocale; + static const List supportedLocales = [ + Locale('en'), + Locale('hi'), + Locale('es'), + Locale('ja'), + ]; + LanguageProvider() { _loadLanguagePreference(); } void setLanguage(Locale locale) { if (_currentLocale == locale) return; - _currentLocale = locale; _saveLanguagePreference(); notifyListeners(); } void toggleLanguage() { + // Cycle: en → hi → es → ja → en if (_currentLocale.languageCode == 'en') { setLanguage(const Locale('hi')); + } else if (_currentLocale.languageCode == 'hi') { + setLanguage(const Locale('es')); + } else if (_currentLocale.languageCode == 'es') { + setLanguage(const Locale('ja')); } else { setLanguage(const Locale('en')); } } - bool get isHindi => _currentLocale.languageCode == 'hi'; bool get isEnglish => _currentLocale.languageCode == 'en'; + bool get isHindi => _currentLocale.languageCode == 'hi'; + bool get isSpanish => _currentLocale.languageCode == 'es'; + bool get isJapanese => _currentLocale.languageCode == 'ja'; String get currentLanguageName { switch (_currentLocale.languageCode) { case 'hi': return 'हिंदी'; - case 'en': + case 'es': + return 'Español'; + case 'ja': + return '日本語'; default: return 'English'; } @@ -43,8 +59,8 @@ class LanguageProvider extends ChangeNotifier { Future _loadLanguagePreference() async { try { final prefs = await SharedPreferences.getInstance(); - final languageCode = prefs.getString(_languagePreferenceKey) ?? 'en'; - _currentLocale = Locale(languageCode); + final code = prefs.getString(_languagePreferenceKey) ?? 'en'; + _currentLocale = Locale(code); notifyListeners(); } catch (e) { debugPrint('Error loading language preference: $e'); @@ -62,6 +78,4 @@ class LanguageProvider extends ChangeNotifier { debugPrint('Error saving language preference: $e'); } } - - static const List supportedLocales = [Locale('en'), Locale('hi')]; } diff --git a/lib/core/utils/category_utils.dart b/lib/core/utils/category_utils.dart index ef3d630..9f1cfcf 100644 --- a/lib/core/utils/category_utils.dart +++ b/lib/core/utils/category_utils.dart @@ -2,85 +2,29 @@ import 'package:flutter/material.dart'; import '../localizations/app_localizations.dart'; class CategoryUtils { - static String getLocalizedCategoryName( - BuildContext context, - String categoryName, - ) { - final localizations = AppLocalizations.of(context); - - switch (categoryName.toLowerCase()) { + static String getLocalizedCategoryName(BuildContext context, String category) { + final loc = AppLocalizations.of(context) ?? AppLocalizations(const Locale('en')); + switch (category.toLowerCase()) { case 'all': - return localizations?.all ?? 'All'; + return loc.all; case 'nature': - return localizations?.nature ?? 'Nature'; + return loc.nature; case 'abstract': - return localizations?.abstract ?? 'Abstract'; + return loc.abstract; case 'urban': - return localizations?.urban ?? 'Urban'; + return loc.urban; case 'minimal': - return localizations?.minimal ?? 'Minimal'; + return loc.minimal; case 'space': - return _getSpaceTranslation(context); + return loc.space; case 'animals': - return _getAnimalsTranslation(context); + return loc.animals; case 'art': - return _getArtTranslation(context); + return loc.art; case 'cars': - return _getCarsTranslation(context); - case 'technology': - return _getTechnologyTranslation(context); - default: - return categoryName; - } - } - - static String _getSpaceTranslation(BuildContext context) { - final locale = Localizations.localeOf(context); - switch (locale.languageCode) { - case 'hi': - return 'अंतरिक्ष'; - default: - return 'Space'; - } - } - - static String _getAnimalsTranslation(BuildContext context) { - final locale = Localizations.localeOf(context); - switch (locale.languageCode) { - case 'hi': - return 'जानवर'; - default: - return 'Animals'; - } - } - - static String _getArtTranslation(BuildContext context) { - final locale = Localizations.localeOf(context); - switch (locale.languageCode) { - case 'hi': - return 'कला'; - default: - return 'Art'; - } - } - - static String _getCarsTranslation(BuildContext context) { - final locale = Localizations.localeOf(context); - switch (locale.languageCode) { - case 'hi': - return 'कारें'; - default: - return 'Cars'; - } - } - - static String _getTechnologyTranslation(BuildContext context) { - final locale = Localizations.localeOf(context); - switch (locale.languageCode) { - case 'hi': - return 'तकनीक'; + return loc.cars; default: - return 'Technology'; + return category; } } } diff --git a/lib/features/home/presentation/widgets/language_toggle_button.dart b/lib/features/home/presentation/widgets/language_toggle_button.dart index 42fe39e..6629230 100644 --- a/lib/features/home/presentation/widgets/language_toggle_button.dart +++ b/lib/features/home/presentation/widgets/language_toggle_button.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:the_wallpaper_company/core/providers/language_provider.dart'; +// import '../providers/language_provider.dart'; class LanguageToggleButton extends StatelessWidget { const LanguageToggleButton({super.key}); @@ -9,55 +10,51 @@ class LanguageToggleButton extends StatelessWidget { Widget build(BuildContext context) { return Consumer( builder: (context, languageProvider, child) { + // Display text for the currently selected language + String displayText; + Color textColor; +//language toggle button + switch (languageProvider.currentLocale.languageCode) { + case 'hi': + displayText = 'हि'; + textColor = Colors.blue; + break; + case 'en': + displayText = 'EN'; + textColor = Colors.orange; + break; + case 'es': + displayText = 'ES'; + textColor = Colors.green; + break; + case 'ja': + displayText = 'JA'; + textColor = Colors.red; + break; + default: + displayText = 'EN'; + textColor = Colors.orange; + } + return Container( margin: const EdgeInsets.only(right: 8), decoration: BoxDecoration( - color: Theme.of(context).brightness == Brightness.dark - ? Colors.grey[800]?.withValues(alpha: 0.8) - : Colors.white.withValues(alpha: 0.8), + color: Colors.white.withOpacity(0.8), borderRadius: BorderRadius.circular(25), - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: 0.1), - blurRadius: 10, - offset: const Offset(0, 2), - ), - ], ), child: Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(25), - onTap: () { - languageProvider.toggleLanguage(); - }, + onTap: () => languageProvider.toggleLanguage(), // cycles language child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - child: AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - transitionBuilder: - (Widget child, Animation animation) { - return ScaleTransition( - scale: animation, - child: FadeTransition( - opacity: animation, - child: child, - ), - ); - }, - child: Text( - languageProvider.isHindi ? 'EN' : 'हि', - key: ValueKey(languageProvider.currentLocale.languageCode), - style: TextStyle( - color: languageProvider.isHindi - ? Colors.orange[600] - : Colors.blue[600], - fontSize: 14, - fontWeight: FontWeight.bold, - ), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Text( + displayText, + style: TextStyle( + color: textColor, + fontSize: 14, + fontWeight: FontWeight.bold, ), ), ), diff --git a/lib/features/home/presentation/widgets/no_results_widget.dart b/lib/features/home/presentation/widgets/no_results_widget.dart index 61a4fc9..3cd36b8 100644 --- a/lib/features/home/presentation/widgets/no_results_widget.dart +++ b/lib/features/home/presentation/widgets/no_results_widget.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; -import '../../../../core/localizations/app_localizations.dart'; +import 'package:the_wallpaper_company/core/localizations/app_localizations.dart'; +// import '../localizations/app_localizations.dart'; class NoResultsWidget extends StatelessWidget { final String searchQuery; @@ -13,6 +14,9 @@ class NoResultsWidget extends StatelessWidget { @override Widget build(BuildContext context) { + // final loc = AppLocalizations.of(context) ?? AppLocalizations(const Locale('en')); + final loc = AppLocalizations.of(context) ?? AppLocalizations(const Locale ('en')); + return Center( child: Padding( padding: const EdgeInsets.all(32.0), @@ -28,40 +32,31 @@ class NoResultsWidget extends StatelessWidget { ), const SizedBox(height: 16), Text( - AppLocalizations.of(context)?.noResultsTitle ?? - 'No wallpapers found', + loc.noResultsTitle, style: Theme.of(context).textTheme.headlineSmall?.copyWith( - color: Theme.of(context).brightness == Brightness.dark - ? Colors.grey[400] - : Colors.grey[600], - fontWeight: FontWeight.w600, - ), + color: Theme.of(context).brightness == Brightness.dark + ? Colors.grey[400] + : Colors.grey[600], + fontWeight: FontWeight.w600, + ), ), const SizedBox(height: 8), Text( - AppLocalizations.of( - context, - )?.noResultsMessage(searchQuery.trim()) ?? - 'No results for "${searchQuery.trim()}"', - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: Theme.of(context).brightness == Brightness.dark - ? Colors.grey[500] - : Colors.grey[500], - ), + loc.noResultsMessage(searchQuery.trim()), textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Theme.of(context).brightness == Brightness.dark + ? Colors.grey[500] + : Colors.grey[500], + ), ), const SizedBox(height: 24), ElevatedButton.icon( onPressed: onClearSearch, icon: const Icon(Icons.clear), - label: Text( - AppLocalizations.of(context)?.clearSearch ?? 'Clear Search', - ), + label: Text(loc.clearSearch), style: ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric( - horizontal: 24, - vertical: 12, - ), + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(25), ), diff --git a/lib/firebase_message.dart b/lib/firebase_message.dart index c465985..7f8c129 100644 --- a/lib/firebase_message.dart +++ b/lib/firebase_message.dart @@ -138,7 +138,7 @@ class NotificationServices { //function to get device token on which we will send the notifications Future getDeviceToken() async { String? token = await messaging.getToken(); - return token!; + return token ?? ''; } void isTokenRefresh() async { diff --git a/lib/main.dart b/lib/main.dart index 6515aea..fbbf54d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,6 +4,7 @@ import 'package:firebase_remote_config/firebase_remote_config.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; + import 'package:the_wallpaper_company/core/constants.dart'; import 'package:the_wallpaper_company/core/providers/theme_provider.dart'; import 'package:the_wallpaper_company/core/providers/language_provider.dart'; @@ -27,6 +28,7 @@ Future main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); + runApp( MultiProvider( providers: [ @@ -49,16 +51,16 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { bool _isDarkMode = false; + @override void initState() { super.initState(); _initRemoteConfig(); + // Handle notification tap when app is launched from terminated state WidgetsBinding.instance.addPostFrameCallback((_) async { - final initialMessage = await FirebaseMessaging.instance - .getInitialMessage(); + final initialMessage = await FirebaseMessaging.instance.getInitialMessage(); if (initialMessage != null) { - // Use the same logic as _handleBackgroundMessage final data = initialMessage.data; final wallpaperId = data['id']; final imageUrl = data['imageUrl']; @@ -94,20 +96,27 @@ class _MyAppState extends State { return MaterialApp( navigatorKey: navigatorKey, debugShowCheckedModeBanner: false, - title: 'The Wallpaper Co.', + + // 🔹 Title localized + title: AppLocalizations(languageProvider.currentLocale).appTitle, + + // 🔹 Theme & Dark Mode theme: themeProvider.lightTheme, darkTheme: themeProvider.darkTheme, - themeMode: themeProvider.isDarkMode - ? ThemeMode.dark - : ThemeMode.light, + themeMode: + themeProvider.isDarkMode ? ThemeMode.dark : ThemeMode.light, + + // 🔹 Localization setup locale: languageProvider.currentLocale, + supportedLocales: LanguageProvider.supportedLocales, localizationsDelegates: const [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], - supportedLocales: LanguageProvider.supportedLocales, + + // 🔹 Home Screen home: const HomeScreen(), ); }, @@ -124,36 +133,29 @@ class _MyAppState extends State { ), ); await remoteConfig.fetchAndActivate(); - final remoteThemeValue = remoteConfig.getBool( - AppConstants.remoteConfigKey, - ); - // Sync with theme provider if context is available + final remoteThemeValue = remoteConfig.getBool(AppConstants.remoteConfigKey); + + // Sync theme with provider if context is available if (mounted && context.mounted) { - final themeProvider = Provider.of( - context, - listen: false, - ); + final themeProvider = + Provider.of(context, listen: false); themeProvider.setDarkMode(remoteThemeValue); } setState(() { _isDarkMode = remoteThemeValue; - debugPrint('hello Dark Mode:[$_isDarkMode'); + debugPrint('Dark Mode: $_isDarkMode'); }); remoteConfig.onConfigUpdated.listen((event) async { await remoteConfig.activate(); - final updatedThemeValue = remoteConfig.getBool( - AppConstants.remoteConfigKey, - ); + final updatedThemeValue = + remoteConfig.getBool(AppConstants.remoteConfigKey); - // Sync with theme provider if context is available if (mounted && context.mounted) { - final themeProvider = Provider.of( - context, - listen: false, - ); + final themeProvider = + Provider.of(context, listen: false); themeProvider.setDarkMode(updatedThemeValue); } @@ -167,3 +169,4 @@ class _MyAppState extends State { } } } + diff --git a/pubspec.lock b/pubspec.lock index 8931f95..7010a37 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -778,6 +778,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + translator: + dependency: "direct main" + description: + name: translator + sha256: fb28ada8b29931f5142907bac62dda375b14a60a57ec72ed37b78e3e97a7047b + url: "https://pub.dev" + source: hosted + version: "1.0.4+1" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 894a8fe..33d413a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,6 +59,7 @@ dependencies: firebase_analytics: ^12.0.1 firebase_messaging: ^16.0.1 flutter_local_notifications: ^19.4.1 + translator: ^1.0.4+1 dev_dependencies: flutter_test: