import 'package:flutter/foundation.dart'; 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 '../utils/theme_manager.dart'; import '../utils/theme_notifier.dart'; import 'components/animated_background.dart'; import 'google_play_games_widget.dart'; import '../game/audio/audio_manager.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 ThemeAwareBuilder( builder: (context, theme) { return Scaffold( backgroundColor: ZenColors.currentAppBackground, 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: Icon( Icons.arrow_back, color: ZenColors.currentPrimaryText, 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.currentPrimaryText, 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), // Appearance Section _buildSectionHeader( AppLocalizations.of(context)!.appearance, ), _buildThemeTile(), 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 - Hidden as requested // _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.5', style: TextStyle( color: ZenColors.currentMutedText, fontSize: 14, ), ), const SizedBox(height: 8), Text( AppLocalizations.of( context, )!.stressReliefGame, style: TextStyle( color: ZenColors.currentMutedText, fontSize: 12, fontStyle: FontStyle.italic, ), ), ], ), ), ], ), ), ), ], ), ), ), ); }, ); } Widget _buildSectionHeader(String title) { return Align( alignment: Alignment.centerLeft, child: Text( title, style: TextStyle( color: ZenColors.currentSecondaryText, 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.currentUiElements.withValues(alpha: 0.3), borderRadius: BorderRadius.circular(12), border: Border.all( color: ZenColors.currentUiElements.withValues(alpha: 0.2), width: 1, ), ), child: Row( children: [ Icon(icon, color: ZenColors.currentPrimaryText, size: 24), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( color: ZenColors.currentPrimaryText, fontSize: 16, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 2), Text( subtitle, style: TextStyle( color: ZenColors.currentSecondaryText, fontSize: 13, ), ), ], ), ), Switch( value: value, onChanged: onChanged, activeColor: ZenColors.currentButtonBackground, activeTrackColor: ZenColors.currentButtonBackground.withValues( alpha: 0.3, ), inactiveThumbColor: ZenColors.currentMutedText, inactiveTrackColor: ZenColors.currentMutedText.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.currentUiElements.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.currentUiElements.withValues(alpha: 0.2), width: 1, ), ), child: Row( children: [ Icon(icon, color: ZenColors.currentPrimaryText, size: 24), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( color: ZenColors.currentPrimaryText, fontSize: 16, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 2), Text( subtitle, style: TextStyle( color: ZenColors.currentSecondaryText, fontSize: 13, ), ), ], ), ), Icon( Icons.arrow_forward_ios, color: ZenColors.currentMutedText, size: 16, ), ], ), ), ), ), ); } 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.currentUiElements.withValues(alpha: 0.3), borderRadius: BorderRadius.circular(12), border: Border.all( color: ZenColors.currentUiElements.withValues(alpha: 0.2), width: 1, ), ), child: Row( children: [ Icon(icon, color: ZenColors.currentPrimaryText, size: 24), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( color: ZenColors.currentPrimaryText, 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.currentButtonBackground, inactiveColor: ZenColors.currentMutedText.withValues( alpha: 0.2, ), ), ], ), ), ], ), ); } Widget _buildThemeTile() { var currentTheme = ThemeManager.currentTheme; // In release builds, if default theme is selected, switch to automatic if (!kDebugMode && currentTheme == SeasonalTheme.default_) { currentTheme = SeasonalTheme.automatic; // Update the setting asynchronously WidgetsBinding.instance.addPostFrameCallback((_) { ThemeManager.setTheme(SeasonalTheme.automatic); }); } final currentThemeName = _getLocalizedThemeName(currentTheme); return Container( margin: const EdgeInsets.only(top: 12), child: Material( color: ZenColors.currentUiElements.withValues(alpha: 0.3), borderRadius: BorderRadius.circular(12), child: InkWell( onTap: _showThemeDialog, borderRadius: BorderRadius.circular(12), child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all( color: ZenColors.currentUiElements.withValues(alpha: 0.2), width: 1, ), ), child: Row( children: [ Icon( ThemeManager.getThemeIcon(currentTheme), color: ZenColors.currentPrimaryText, size: 24, ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( AppLocalizations.of(context)!.colorTheme, style: TextStyle( color: ZenColors.currentPrimaryText, fontSize: 16, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 2), Text( currentThemeName, style: TextStyle( color: ZenColors.currentSecondaryText, fontSize: 13, ), ), ], ), ), Icon( Icons.arrow_forward_ios, color: ZenColors.currentMutedText, 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.currentUiElements.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.currentUiElements.withValues(alpha: 0.2), width: 1, ), ), child: Row( children: [ Icon( Icons.language, color: ZenColors.currentPrimaryText, size: 24, ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( AppLocalizations.of(context)!.language, style: TextStyle( color: ZenColors.currentPrimaryText, fontSize: 16, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 2), Text( currentLanguageName, style: TextStyle( color: ZenColors.currentSecondaryText, fontSize: 13, ), ), ], ), ), Icon( Icons.arrow_forward_ios, color: ZenColors.currentMutedText, size: 16, ), ], ), ), ), ), ); } Widget _buildDonationTile() { return _buildActionTile( icon: Icons.favorite, title: AppLocalizations.of(context)!.supportDevelopment, subtitle: AppLocalizations.of(context)!.supportDevelopmentDesc, onTap: _showDonationDialog, ); } // Event Handlers 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); SettingsManager.applySfxVolume(); } 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()); } void _showLanguageDialog() { if (_hapticsEnabled) { HapticUtils.vibrate(duration: 50); } showDialog(context: context, builder: (context) => _buildLanguageDialog()); } void _showThemeDialog() { if (_hapticsEnabled) { HapticUtils.vibrate(duration: 50); } showDialog(context: context, builder: (context) => _buildThemeDialog()); } // Dialog Builders Widget _buildTutorialDialog() { return AlertDialog( backgroundColor: ZenColors.currentUiElements, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), title: Text( AppLocalizations.of(context)!.howToUseZenTap, style: TextStyle( color: ZenColors.currentPrimaryText, 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.currentButtonBackground, foregroundColor: ZenColors.currentButtonText, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: Text(AppLocalizations.of(context)!.gotIt), ), ], ); } Widget _buildTutorialStep({required IconData icon, required String text}) { return Row( children: [ Icon(icon, color: ZenColors.currentButtonBackground, size: 20), const SizedBox(width: 12), Expanded( child: Text( text, style: TextStyle( color: ZenColors.currentSecondaryText, fontSize: 14, ), ), ), ], ); } Widget _buildLanguageDialog() { final currentLocale = LocaleManager.currentLocale; return AlertDialog( backgroundColor: ZenColors.currentUiElements, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), title: Text( AppLocalizations.of(context)!.selectLanguage, style: TextStyle( color: ZenColors.currentPrimaryText, 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.currentButtonBackground.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.currentButtonBackground .withValues(alpha: 0.3) : ZenColors.currentUiElements.withValues( alpha: 0.2, ), width: 1, ), ), child: Row( children: [ Expanded( child: Text( languageName, style: TextStyle( color: isSelected ? ZenColors.currentButtonBackground : ZenColors.currentPrimaryText, fontSize: 16, fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, ), ), ), if (isSelected) Icon( Icons.check, color: ZenColors.currentButtonBackground, size: 20, ), ], ), ), ), ), ); }).toList(), ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: Text( AppLocalizations.of(context)!.cancel, style: TextStyle(color: ZenColors.currentMutedText), ), ), ], ); } Widget _buildThemeDialog() { final currentTheme = ThemeManager.currentTheme; return AlertDialog( backgroundColor: ZenColors.currentUiElements, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), title: Text( AppLocalizations.of(context)!.selectTheme, style: TextStyle( color: ZenColors.currentPrimaryText, fontSize: 22, fontWeight: FontWeight.bold, ), ), content: SizedBox( width: double.maxFinite, child: Column( mainAxisSize: MainAxisSize.min, children: [ // Use a constraint container with max height for scrolling ConstrainedBox( constraints: BoxConstraints( maxHeight: MediaQuery.of(context).size.height * 0.5, ), child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: ThemeManager.availableThemes.map((theme) { final isSelected = theme == currentTheme; final themeName = _getLocalizedThemeName(theme); final themeIcon = ThemeManager.getThemeIcon(theme); return Container( margin: const EdgeInsets.only(bottom: 8), child: Material( color: isSelected ? ZenColors.currentButtonBackground .withValues(alpha: 0.1) : Colors.transparent, borderRadius: BorderRadius.circular(12), child: InkWell( onTap: () => _selectTheme(theme), borderRadius: BorderRadius.circular(12), child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all( color: isSelected ? ZenColors.currentButtonBackground .withValues(alpha: 0.3) : ZenColors.currentUiElements .withValues(alpha: 0.2), width: 1, ), ), child: Row( children: [ Icon( themeIcon, color: isSelected ? ZenColors .currentButtonBackground : ZenColors.currentPrimaryText, size: 20, ), const SizedBox(width: 12), Expanded( child: Text( themeName, style: TextStyle( color: isSelected ? ZenColors .currentButtonBackground : ZenColors .currentPrimaryText, fontSize: 16, fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, ), ), ), if (isSelected) Icon( Icons.check, color: ZenColors.currentButtonBackground, size: 20, ), ], ), ), ), ), ); }).toList(), ), ), ), ], ), ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: Text( AppLocalizations.of(context)!.cancel, style: TextStyle(color: ZenColors.currentMutedText), ), ), ], ); } Widget _buildDonationDialog() { return AlertDialog( backgroundColor: ZenColors.currentUiElements, 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.currentPrimaryText, fontSize: 22, fontWeight: FontWeight.bold, ), ), ], ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( AppLocalizations.of(context)!.supportMessage, style: TextStyle( color: ZenColors.currentSecondaryText, 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.currentSecondaryText, 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.currentMutedText), ), ), ], ); } 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.currentPrimaryText, fontSize: 14, fontWeight: FontWeight.w500, ), ), Text( subtitle, style: TextStyle( color: ZenColors.currentSecondaryText, fontSize: 12, ), ), ], ), ), Icon(Icons.open_in_new, color: color, size: 16), ], ), ), ), ); } // Helper Methods String _getLocalizedThemeName(SeasonalTheme theme) { final localizations = AppLocalizations.of(context)!; switch (theme) { case SeasonalTheme.automatic: // Get the auto-detected season (not the effective theme) final detectedSeason = ThemeManager.autoDetectedSeason; String seasonName; // Get the season name based on auto-detected season switch (detectedSeason) { case SeasonalTheme.spring: seasonName = localizations.springTheme; break; case SeasonalTheme.summer: seasonName = localizations.summerTheme; break; case SeasonalTheme.autumn: seasonName = localizations.autumnTheme; break; case SeasonalTheme.winter: seasonName = localizations.winterTheme; break; default: seasonName = localizations.defaultTheme; break; } // Concatenate automatic with detected season return '${localizations.automaticTheme} ($seasonName)'; case SeasonalTheme.default_: return localizations.defaultTheme; case SeasonalTheme.spring: return localizations.springTheme; case SeasonalTheme.summer: return localizations.summerTheme; case SeasonalTheme.autumn: return localizations.autumnTheme; case SeasonalTheme.winter: return localizations.winterTheme; } } 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 } } Future _selectTheme(SeasonalTheme theme) async { if (_hapticsEnabled) { HapticUtils.vibrate(duration: 30); } await SettingsManager.setSelectedTheme(theme); // Switch menu music to match new theme AudioManager().playMenuMusic(); if (mounted) { Navigator.of(context).pop(); // Close theme dialog setState(() {}); // Refresh the settings screen to show new theme } } 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.currentMutedText, behavior: SnackBarBehavior.floating, ), ); } } } catch (e) { // Show error on exception if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( AppLocalizations.of(context)!.errorOpeningDonationLink, ), backgroundColor: ZenColors.currentMutedText, behavior: SnackBarBehavior.floating, ), ); } } } }