import 'package:flutter/material.dart'; import '../../../../data/network/api_client.dart'; import '../../../../l10n/app_localizations.dart'; import '../../../../shared/theme/design_tokens.dart'; import '../../../../shared/widgets/app_modal_dialog.dart'; import '../../../../shared/widgets/gua_icon.dart'; import '../../data/models/profile_settings.dart'; import '../../data/repositories/invite_repository.dart'; import '../models/legal_document_type.dart'; import '../utils/legal_document_assets.dart'; import 'account_delete_screen.dart'; import '../widgets/settings_section_widgets.dart'; import 'coin_center_screen.dart'; import 'feedback_screen.dart'; import 'general_settings_screen.dart'; import 'invite_screen.dart'; import 'legal_document_screen.dart'; import 'profile_edit_screen.dart'; class SettingsScreen extends StatefulWidget { const SettingsScreen({ super.key, required this.account, required this.userId, required this.settings, required this.coinBalance, required this.inviteRepository, required this.apiClient, required this.onInterfaceLanguageChanged, required this.onSettingsChanged, required this.onUploadAvatar, required this.onLogout, required this.onDeleteAccount, required this.onSaveProfile, required this.onBalanceChanged, }); final String account; final String userId; final ProfileSettingsV1 settings; final int coinBalance; final InviteRepository inviteRepository; final ApiClient apiClient; final Future Function(String languageTag) onInterfaceLanguageChanged; final Future Function(ProfileSettingsV1 settings) onSettingsChanged; final Future Function(String filePath) onUploadAvatar; final Future Function() onLogout; final Future Function() onDeleteAccount; final Future Function(ProfileSettingsV1 updated) onSaveProfile; final void Function(int newBalance) onBalanceChanged; @override State createState() => _SettingsScreenState(); } class _SettingsScreenState extends State { late ProfileSettingsV1 _settings; @override void initState() { super.initState(); _settings = widget.settings; } @override void didUpdateWidget(covariant SettingsScreen oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.settings != widget.settings) { _settings = widget.settings; } } @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; final colors = Theme.of(context).colorScheme; return Scaffold( backgroundColor: colors.surfaceContainerLow, appBar: AppBar( title: Text(l10n.settingsTitle), centerTitle: true, backgroundColor: colors.surfaceContainerLow, surfaceTintColor: colors.surfaceContainerLow, ), body: ListView( padding: const EdgeInsets.fromLTRB( AppSpacing.lg, AppSpacing.md, AppSpacing.lg, AppSpacing.xl, ), children: [ ProfileHeaderCard( account: widget.account, displayName: _settings.displayName.isEmpty ? widget.account : _settings.displayName, bio: _settings.bio, avatarUrl: _settings.avatarUrl, onEditTap: _openProfileEdit, ), const SizedBox(height: AppSpacing.lg), WalletHeroCard( balance: widget.coinBalance, subtitle: l10n.settingsCoinHeroSubtitle, onTap: _openCoinCenter, ), const SizedBox(height: AppSpacing.xl), SettingsGroupCard( children: [ SettingsMenuTile( icon: Icons.tune_rounded, title: l10n.settingsGeneralTitle, tint: colors.primary, background: colors.surfaceContainerHighest, onTap: _openGeneralSettings, ), SettingsMenuTile( icon: Icons.card_giftcard_rounded, title: l10n.settingsInviteTitle, tint: colors.primary, background: colors.surfaceContainerHighest, onTap: _openInvite, ), SettingsMenuTile( icon: Icons.feedback_outlined, title: l10n.settingsFeedbackTitle, tint: colors.primary, background: colors.surfaceContainerHighest, onTap: () => Navigator.of(context).push( MaterialPageRoute( builder: (_) => FeedbackScreen(apiClient: widget.apiClient), ), ), ), SettingsMenuTile( icon: Icons.person_rounded, title: l10n.settingsAccountAndDataTitle, tint: colors.primary, background: colors.surfaceContainerHighest, showDivider: false, onTap: _openAccountDelete, ), ], ), const SizedBox(height: AppSpacing.xl), SettingsGroupCard( children: [ SettingsMenuTile( icon: Icons.info_outline_rounded, title: l10n.aboutUs, tint: colors.secondary, background: colors.surfaceContainerHighest, onTap: () => _openLegalDocument(LegalDocumentType.aboutUs), ), SettingsMenuTile( icon: Icons.security_rounded, title: l10n.privacyPolicy, tint: colors.secondary, background: colors.surfaceContainerHighest, onTap: () => _openLegalDocument(LegalDocumentType.privacyPolicy), ), SettingsMenuTile( icon: Icons.description_outlined, title: l10n.termsOfService, tint: colors.secondary, background: colors.surfaceContainerHighest, showDivider: false, onTap: () => _openLegalDocument(LegalDocumentType.termsOfService), ), ], ), const SizedBox(height: AppSpacing.xl), FilledButton( onPressed: _confirmLogout, style: FilledButton.styleFrom( elevation: 0, backgroundColor: colors.error, foregroundColor: colors.onError, padding: const EdgeInsets.symmetric(vertical: AppSpacing.lg), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(AppRadius.full), ), ), child: Text(l10n.logout), ), ], ), ); } Future _openCoinCenter() async { await Navigator.of(context).push( MaterialPageRoute( builder: (_) => CoinCenterScreen( balance: widget.coinBalance, userId: widget.userId, onBalanceChanged: widget.onBalanceChanged, ), ), ); } Future _openGeneralSettings() async { await Navigator.of(context).push( MaterialPageRoute( builder: (_) => GeneralSettingsScreen( settings: _settings, onSettingsChanged: (newSettings) async { await widget.onSettingsChanged(newSettings); if (!mounted) return; setState(() { _settings = newSettings; }); }, ), ), ); } Future _openInvite() async { await Navigator.of(context).push( MaterialPageRoute( builder: (_) => InviteScreen(inviteRepository: widget.inviteRepository), ), ); } Future _openProfileEdit() async { final result = await Navigator.of(context).push( MaterialPageRoute( builder: (_) => ProfileEditScreen( account: widget.account, settings: _settings, onUploadAvatar: widget.onUploadAvatar, onSave: widget.onSaveProfile, ), ), ); if (result == null || !mounted) { return; } setState(() { _settings = result; }); } void _openLegalDocument(LegalDocumentType type) { final l10n = AppLocalizations.of(context)!; final locale = Localizations.localeOf(context); Navigator.of(context).push( MaterialPageRoute( builder: (_) => LegalDocumentScreen( title: legalDocumentTitle(l10n, type), assetPath: legalDocumentAssetPath(locale, type), ), ), ); } Future _openAccountDelete() async { final deleted = await Navigator.of(context).push( MaterialPageRoute( builder: (_) => AccountDeleteScreen(onDeleteAccount: widget.onDeleteAccount), ), ); if (deleted != true) { return; } await widget.onLogout(); if (!mounted) { return; } Navigator.of(context).popUntil((route) => route.isFirst); } Future _confirmLogout() async { final l10n = AppLocalizations.of(context)!; final confirmed = await showDialog( context: context, builder: (dialogContext) { return AppModalDialog( title: l10n.settingsLogoutDialogTitle, message: l10n.settingsLogoutDialogBody, iconWidget: const GuaIcon(), actions: [ AppModalDialogAction( label: l10n.settingsCancel, onPressed: () => Navigator.of(dialogContext).pop(false), ), AppModalDialogAction( label: l10n.logout, primary: true, destructive: true, onPressed: () => Navigator.of(dialogContext).pop(true), ), ], ); }, ); if (confirmed != true) { return; } await widget.onLogout(); if (!mounted) { return; } Navigator.of(context).popUntil((route) => route.isFirst); } }