import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; import '../l10n/app_localizations.dart'; import '../utils/colors.dart'; import '../utils/haptic_utils.dart'; import '../utils/settings_manager.dart'; import '../utils/locale_manager.dart'; import 'components/animated_background.dart'; import 'google_play_games_widget.dart'; class SettingsScreen extends StatefulWidget { const SettingsScreen({super.key}); @override State createState() => _SettingsScreenState(); } class _SettingsScreenState extends State { bool _musicEnabled = true; bool _hapticsEnabled = true; double _bgmVolume = 0.4; double _sfxVolume = 0.6; @override void initState() { super.initState(); _loadSettings(); } Future _loadSettings() async { setState(() { _musicEnabled = SettingsManager.isMusicEnabled; _hapticsEnabled = SettingsManager.isHapticsEnabled; _bgmVolume = SettingsManager.bgmVolume; _sfxVolume = SettingsManager.sfxVolume; }); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: ZenColors.appBackground, body: AnimatedBackground( child: SafeArea( child: Column( children: [ // Header Padding( padding: const EdgeInsets.all(16.0), child: Row( children: [ IconButton( onPressed: () => Navigator.of(context).pop(), icon: const Icon( Icons.arrow_back, color: ZenColors.primaryText, size: 28, ), style: IconButton.styleFrom( backgroundColor: ZenColors.black.withValues(alpha: 0.3), shape: const CircleBorder(), ), ), const SizedBox(width: 16), Text( AppLocalizations.of(context)!.settings, style: TextStyle( color: ZenColors.primaryText, fontSize: 28, fontWeight: FontWeight.bold, letterSpacing: 1.0, ), ), ], ), ), // Settings List Expanded( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 20.0), child: Column( children: [ const SizedBox(height: 20), // Audio Section _buildSectionHeader(AppLocalizations.of(context)!.audio), _buildSettingTile( icon: Icons.music_note, title: AppLocalizations.of(context)!.backgroundMusic, subtitle: AppLocalizations.of(context)!.backgroundMusicDesc, value: _musicEnabled, onChanged: _toggleMusic, ), _buildVolumeSlider( icon: Icons.volume_up, title: AppLocalizations.of(context)!.musicVolume, value: _bgmVolume, onChanged: _setBgmVolume, ), const SizedBox(height: 10), _buildVolumeSlider( icon: Icons.volume_up, title: AppLocalizations.of(context)!.soundEffectsVolume, value: _sfxVolume, onChanged: _setSfxVolume, ), const SizedBox(height: 30), // Feedback Section _buildSectionHeader(AppLocalizations.of(context)!.feedback), _buildSettingTile( icon: Icons.vibration, title: AppLocalizations.of(context)!.hapticFeedback, subtitle: AppLocalizations.of(context)!.hapticFeedbackDesc, value: _hapticsEnabled, onChanged: _toggleHaptics, ), const SizedBox(height: 30), // Language Section _buildSectionHeader(AppLocalizations.of(context)!.language), _buildLanguageTile(), const SizedBox(height: 30), // Tutorial Section _buildSectionHeader(AppLocalizations.of(context)!.help), _buildActionTile( icon: Icons.help_outline, title: AppLocalizations.of(context)!.showTutorial, subtitle: AppLocalizations.of(context)!.showTutorialDesc, onTap: _showTutorial, ), const SizedBox(height: 30), // Google Play Games Section _buildSectionHeader(AppLocalizations.of(context)!.googlePlayGames), const GooglePlayGamesWidget(), const SizedBox(height: 30), // Support Section _buildSectionHeader(AppLocalizations.of(context)!.supportZenTap), _buildDonationTile(), const SizedBox(height: 30), // About Section Padding( padding: const EdgeInsets.only(bottom: 20), child: Column( children: [ Text( 'ZenTap v1.0.2', style: TextStyle( color: ZenColors.mutedText, fontSize: 14, ), ), const SizedBox(height: 8), Text( AppLocalizations.of(context)!.stressReliefGame, style: TextStyle( color: ZenColors.mutedText, fontSize: 12, fontStyle: FontStyle.italic, ), ), ], ), ), ], ), ), ), ], ), ), ), ); } Widget _buildSectionHeader(String title) { return Align( alignment: Alignment.centerLeft, child: Text( title, style: TextStyle( color: ZenColors.secondaryText, fontSize: 16, fontWeight: FontWeight.w600, letterSpacing: 0.5, ), ), ); } Widget _buildSettingTile({ required IconData icon, required String title, required String subtitle, required bool value, required ValueChanged onChanged, }) { return Container( margin: const EdgeInsets.only(top: 12), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: ZenColors.uiElements.withValues(alpha: 0.3), borderRadius: BorderRadius.circular(12), border: Border.all( color: ZenColors.uiElements.withValues(alpha: 0.2), width: 1, ), ), child: Row( children: [ Icon( icon, color: ZenColors.primaryText, size: 24, ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle( color: ZenColors.primaryText, fontSize: 16, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 2), Text( subtitle, style: TextStyle( color: ZenColors.secondaryText, fontSize: 13, ), ), ], ), ), Switch( value: value, onChanged: onChanged, activeColor: ZenColors.buttonBackground, activeTrackColor: ZenColors.buttonBackground.withValues(alpha: 0.3), inactiveThumbColor: ZenColors.mutedText, inactiveTrackColor: ZenColors.mutedText.withValues(alpha: 0.2), ), ], ), ); } Widget _buildActionTile({ required IconData icon, required String title, required String subtitle, required VoidCallback onTap, }) { return Container( margin: const EdgeInsets.only(top: 12), child: Material( color: ZenColors.uiElements.withValues(alpha: 0.3), borderRadius: BorderRadius.circular(12), child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(12), child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all( color: ZenColors.uiElements.withValues(alpha: 0.2), width: 1, ), ), child: Row( children: [ Icon( icon, color: ZenColors.primaryText, size: 24, ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle( color: ZenColors.primaryText, fontSize: 16, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 2), Text( subtitle, style: TextStyle( color: ZenColors.secondaryText, fontSize: 13, ), ), ], ), ), Icon( Icons.arrow_forward_ios, color: ZenColors.mutedText, size: 16, ), ], ), ), ), ), ); } Future _toggleMusic(bool value) async { setState(() { _musicEnabled = value; }); await SettingsManager.setMusicEnabled(value); if (_hapticsEnabled) { await HapticUtils.vibrate(duration: 50); } } Future _setBgmVolume(double value) async { setState(() { _bgmVolume = value; }); await SettingsManager.setBgmVolume(value); SettingsManager.applyBgmVolume(); } Future _setSfxVolume(double value) async { setState(() { _sfxVolume = value; }); await SettingsManager.setSfxVolume(value); } Future _toggleHaptics(bool value) async { setState(() { _hapticsEnabled = value; }); await SettingsManager.setHapticsEnabled(value); // Give immediate feedback if enabling haptics if (value) { await HapticUtils.vibrate(duration: 100); } } void _showTutorial() { if (_hapticsEnabled) { HapticUtils.vibrate(duration: 50); } showDialog( context: context, builder: (context) => _buildTutorialDialog(), ); } void _showDonationDialog() { if (_hapticsEnabled) { HapticUtils.vibrate(duration: 50); } showDialog( context: context, builder: (context) => _buildDonationDialog(), ); } Future _openDonationLink(String url) async { if (_hapticsEnabled) { HapticUtils.vibrate(duration: 30); } try { final Uri uri = Uri.parse(url); if (await canLaunchUrl(uri)) { await launchUrl(uri, mode: LaunchMode.externalApplication); Navigator.of(context).pop(); // Close dialog after opening link } else { // Show error if URL can't be launched if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.couldNotOpenDonationLink), backgroundColor: ZenColors.mutedText, behavior: SnackBarBehavior.floating, ), ); } } } catch (e) { // Show error on exception if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.errorOpeningDonationLink), backgroundColor: ZenColors.mutedText, behavior: SnackBarBehavior.floating, ), ); } } } Widget _buildTutorialDialog() { return AlertDialog( backgroundColor: ZenColors.uiElements, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), title: Text( AppLocalizations.of(context)!.howToUseZenTap, style: TextStyle( color: ZenColors.primaryText, fontSize: 22, fontWeight: FontWeight.bold, ), ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildTutorialStep( icon: Icons.touch_app, text: AppLocalizations.of(context)!.tapToPopBubbles, ), const SizedBox(height: 16), _buildTutorialStep( icon: Icons.stars, text: AppLocalizations.of(context)!.earnRelaxationPoints, ), const SizedBox(height: 16), _buildTutorialStep( icon: Icons.self_improvement, text: AppLocalizations.of(context)!.chooseZenMode, ), const SizedBox(height: 16), _buildTutorialStep( icon: Icons.pause, text: AppLocalizations.of(context)!.tapPauseAnytime, ), ], ), actions: [ ElevatedButton( onPressed: () => Navigator.of(context).pop(), style: ElevatedButton.styleFrom( backgroundColor: ZenColors.buttonBackground, foregroundColor: ZenColors.buttonText, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: Text(AppLocalizations.of(context)!.gotIt), ), ], ); } Widget _buildVolumeSlider({ required IconData icon, required String title, required double value, required ValueChanged onChanged, }) { return Container( margin: const EdgeInsets.only(top: 8), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: ZenColors.uiElements.withValues(alpha: 0.3), borderRadius: BorderRadius.circular(12), border: Border.all( color: ZenColors.uiElements.withValues(alpha: 0.2), width: 1, ), ), child: Row( children: [ Icon( icon, color: ZenColors.primaryText, size: 24, ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle( color: ZenColors.primaryText, fontSize: 16, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 8), Slider( value: value, onChanged: onChanged, min: 0.0, max: 1.0, divisions: 10, label: '${(value * 100).round()}%', activeColor: ZenColors.buttonBackground, inactiveColor: ZenColors.mutedText.withValues(alpha: 0.2), ), ], ), ), ], ), ); } Widget _buildTutorialStep({ required IconData icon, required String text, }) { return Row( children: [ Icon( icon, color: ZenColors.buttonBackground, size: 20, ), const SizedBox(width: 12), Expanded( child: Text( text, style: TextStyle( color: ZenColors.secondaryText, fontSize: 14, ), ), ), ], ); } Widget _buildDonationTile() { return _buildActionTile( icon: Icons.favorite, title: AppLocalizations.of(context)!.supportDevelopment, subtitle: AppLocalizations.of(context)!.supportDevelopmentDesc, onTap: _showDonationDialog, ); } Widget _buildDonationDialog() { return AlertDialog( backgroundColor: ZenColors.uiElements, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), title: Row( children: [ Icon( Icons.favorite, color: ZenColors.red, size: 24, ), const SizedBox(width: 12), Text( AppLocalizations.of(context)!.supportZenTapTitle, style: TextStyle( color: ZenColors.primaryText, fontSize: 22, fontWeight: FontWeight.bold, ), ), ], ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( AppLocalizations.of(context)!.supportMessage, style: TextStyle( color: ZenColors.secondaryText, fontSize: 14, height: 1.4, ), ), const SizedBox(height: 20), // Ko-fi Button _buildDonationButton( icon: Icons.coffee, title: AppLocalizations.of(context)!.buyMeACoffee, subtitle: AppLocalizations.of(context)!.kofiOneTime, color: const Color(0xFF13C3FF), onTap: () => _openDonationLink('https://ko-fi.com/fsociety_hu'), ), const SizedBox(height: 12), // PayPal Button _buildDonationButton( icon: Icons.payment, title: AppLocalizations.of(context)!.paypalDonation, subtitle: AppLocalizations.of(context)!.directDonation, color: const Color(0xFF0070BA), onTap: () => _openDonationLink('https://paypal.me/fsocietyhu'), ), const SizedBox(height: 12), // GitHub Sponsors Button _buildDonationButton( icon: Icons.code, title: AppLocalizations.of(context)!.githubSponsors, subtitle: AppLocalizations.of(context)!.monthlySupport, color: const Color(0xFFEA4AAA), onTap: () => _openDonationLink('https://github.com/sponsors/fszontagh'), ), const SizedBox(height: 16), Text( AppLocalizations.of(context)!.thankYouMessage, style: TextStyle( color: ZenColors.secondaryText, fontSize: 12, fontStyle: FontStyle.italic, ), textAlign: TextAlign.center, ), ], ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: Text( AppLocalizations.of(context)!.maybeLater, style: TextStyle( color: ZenColors.mutedText, ), ), ), ], ); } Widget _buildDonationButton({ required IconData icon, required String title, required String subtitle, required Color color, required VoidCallback onTap, }) { return Material( color: color.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(12), child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(12), child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all( color: color.withValues(alpha: 0.3), width: 1, ), ), child: Row( children: [ Icon( icon, color: color, size: 20, ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( color: ZenColors.primaryText, fontSize: 14, fontWeight: FontWeight.w500, ), ), Text( subtitle, style: TextStyle( color: ZenColors.secondaryText, fontSize: 12, ), ), ], ), ), Icon( Icons.open_in_new, color: color, size: 16, ), ], ), ), ), ); } Widget _buildLanguageTile() { final currentLocale = LocaleManager.currentLocale; final currentLanguageName = LocaleManager.getLocaleDisplayName(currentLocale); return Container( margin: const EdgeInsets.only(top: 12), child: Material( color: ZenColors.uiElements.withValues(alpha: 0.3), borderRadius: BorderRadius.circular(12), child: InkWell( onTap: _showLanguageDialog, borderRadius: BorderRadius.circular(12), child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all( color: ZenColors.uiElements.withValues(alpha: 0.2), width: 1, ), ), child: Row( children: [ const Icon( Icons.language, color: ZenColors.primaryText, size: 24, ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( AppLocalizations.of(context)!.language, style: TextStyle( color: ZenColors.primaryText, fontSize: 16, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 2), Text( currentLanguageName, style: TextStyle( color: ZenColors.secondaryText, fontSize: 13, ), ), ], ), ), Icon( Icons.arrow_forward_ios, color: ZenColors.mutedText, size: 16, ), ], ), ), ), ), ); } void _showLanguageDialog() { if (_hapticsEnabled) { HapticUtils.vibrate(duration: 50); } showDialog( context: context, builder: (context) => _buildLanguageDialog(), ); } Widget _buildLanguageDialog() { final currentLocale = LocaleManager.currentLocale; return AlertDialog( backgroundColor: ZenColors.uiElements, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), title: Text( AppLocalizations.of(context)!.selectLanguage, style: TextStyle( color: ZenColors.primaryText, fontSize: 22, fontWeight: FontWeight.bold, ), ), content: Column( mainAxisSize: MainAxisSize.min, children: LocaleManager.supportedLocales.map((locale) { final isSelected = locale.languageCode == currentLocale.languageCode; final languageName = LocaleManager.getLocaleDisplayName(locale); return Container( margin: const EdgeInsets.only(bottom: 8), child: Material( color: isSelected ? ZenColors.buttonBackground.withValues(alpha: 0.1) : Colors.transparent, borderRadius: BorderRadius.circular(12), child: InkWell( onTap: () => _selectLanguage(locale), borderRadius: BorderRadius.circular(12), child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all( color: isSelected ? ZenColors.buttonBackground.withValues(alpha: 0.3) : ZenColors.uiElements.withValues(alpha: 0.2), width: 1, ), ), child: Row( children: [ Expanded( child: Text( languageName, style: TextStyle( color: isSelected ? ZenColors.buttonBackground : ZenColors.primaryText, fontSize: 16, fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, ), ), ), if (isSelected) Icon( Icons.check, color: ZenColors.buttonBackground, size: 20, ), ], ), ), ), ), ); }).toList(), ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: Text( AppLocalizations.of(context)!.cancel, style: TextStyle( color: ZenColors.mutedText, ), ), ), ], ); } Future _selectLanguage(Locale locale) async { if (_hapticsEnabled) { HapticUtils.vibrate(duration: 30); } await LocaleManager.setLocale(locale); if (mounted) { Navigator.of(context).pop(); // Close language dialog setState(() {}); // Refresh the settings screen to show new language } } }