// Version: 1.1.0 | Created: 2026-04-01 | Updated: 2026-04-02 // Profile screen. Shows current user info and logout button. import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../core/auth/auth_notifier.dart'; import '../../../core/auth/auth_state.dart'; import '../../../core/config/app_config.dart'; import '../../../core/network/matrix_client.dart'; import '../../../shared/utils/matrix_id.dart'; import '../../../shared/widgets/matrix_avatar.dart'; class ProfileScreen extends ConsumerWidget { const ProfileScreen({super.key, this.embedded = false}); /// When true, this screen is shown inside the bottom-nav tab of RoomsScreen. final bool embedded; @override Widget build(BuildContext context, WidgetRef ref) { final authState = ref.watch(authProvider); final client = ref.watch(matrixClientProvider); final userId = authState.maybeWhen( authenticated: (userId, _, __) => userId, orElse: () => '', ); final displayName = client.userID?.matrixLocalpart ?? 'Unknown'; final body = ListView( padding: const EdgeInsets.all(24), children: [ Center(child: MatrixAvatar(name: displayName, radius: 48)), const SizedBox(height: 16), Center( child: Text( '@$displayName', style: Theme.of( context, ).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold), ), ), Center( child: Text( userId, style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.onSurface.withAlpha(153), ), ), ), const SizedBox(height: 32), const Divider(), const SizedBox(height: 16), Text( 'Settings', style: Theme.of(context).textTheme.labelLarge?.copyWith( color: Theme.of(context).colorScheme.onSurface.withAlpha(153), ), ), const SizedBox(height: 8), ExpansionTile( leading: const Icon(Icons.notifications_outlined), title: const Text('Notifications'), children: [ SwitchListTile( title: const Text('Push notifications'), subtitle: const Text('Coming in Phase 2'), value: false, onChanged: null, ), SwitchListTile( title: const Text('Notification sounds'), subtitle: const Text('Coming in Phase 2'), value: false, onChanged: null, ), ], ), ExpansionTile( leading: const Icon(Icons.security_outlined), title: const Text('Security & Privacy'), children: [ ListTile( leading: const Icon(Icons.lock_outline), title: const Text('End-to-end encryption'), subtitle: const Text('Setup coming in Phase 3'), enabled: false, ), ListTile( leading: const Icon(Icons.verified_user_outlined), title: const Text('Verify devices'), subtitle: const Text('Cross-signing setup — coming in Phase 2'), enabled: false, ), ListTile( leading: const Icon(Icons.password_outlined), title: const Text('Change password'), subtitle: const Text('Managed via m8chat.au account settings'), enabled: false, ), ], ), const SizedBox(height: 16), const Divider(), const SizedBox(height: 16), _LogoutButton( onLogout: () async { await ref.read(authProvider.notifier).logout(); }, ), const SizedBox(height: 16), Center( child: Text( '${AppConfig.appName} ${AppConfig.appVersion} · ${AppConfig.matrixServerName}', style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.onSurface.withAlpha(77), ), ), ), ], ); if (embedded) return body; return Scaffold( appBar: AppBar(title: const Text('Profile')), body: body, ); } } class _LogoutButton extends StatelessWidget { const _LogoutButton({required this.onLogout}); final VoidCallback onLogout; @override Widget build(BuildContext context) { return OutlinedButton.icon( onPressed: () { showDialog( context: context, builder: (_) => AlertDialog( title: const Text('Sign out'), content: Text( 'Are you sure you want to sign out of ${AppConfig.appName}?', ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Cancel'), ), TextButton( onPressed: () { Navigator.of(context).pop(); onLogout(); }, child: Text( 'Sign out', style: TextStyle(color: Theme.of(context).colorScheme.error), ), ), ], ), ); }, icon: const Icon(Icons.logout), label: const Text('Sign out'), style: OutlinedButton.styleFrom( foregroundColor: Theme.of(context).colorScheme.error, side: BorderSide(color: Theme.of(context).colorScheme.error), minimumSize: const Size.fromHeight(48), ), ); } }