import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import '../models/group_member_model.dart'; import '../models/user_model.dart'; import '../providers/group_provider.dart'; import '../providers/user_provider.dart'; import '../theme/app_theme.dart'; import '../widgets/app_sidebar.dart'; import '../widgets/responsive_layout.dart'; class GroupDetailScreen extends StatefulWidget { final String groupId; const GroupDetailScreen({super.key, required this.groupId}); @override State createState() => _GroupDetailScreenState(); } class _GroupDetailScreenState extends State { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { final groups = context.read(); groups.loadGroupMembers(widget.groupId); if (groups.groups.isEmpty) groups.loadGroups(); context.read().loadUsers(); }); } @override Widget build(BuildContext context) { return Consumer(builder: (_, groupProvider, __) { final group = groupProvider.groups.where((g) => g.id == widget.groupId).firstOrNull; return ResponsiveLayout( title: group?.name ?? 'جزئیات گروه', sidebar: const AppSidebar(), body: _GroupDetailBody( groupId: widget.groupId, groupName: group?.name ?? '...', isActive: group?.isActive ?? true, ), ); }); } } class _GroupDetailBody extends StatelessWidget { final String groupId; final String groupName; final bool isActive; const _GroupDetailBody({ required this.groupId, required this.groupName, required this.isActive, }); @override Widget build(BuildContext context) { return SingleChildScrollView( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // ── Back button + Header ────────────────────────────────── Row( children: [ IconButton( onPressed: () => context.go('/groups'), icon: const Icon(Icons.arrow_back_rounded), tooltip: 'بازگشت', ), const SizedBox(width: 8), Expanded( child: Text( groupName, style: const TextStyle( fontSize: 24, fontWeight: FontWeight.w800, color: AppTheme.textPrimary, ), ), ), ElevatedButton.icon( onPressed: () => _showAddMemberDialog(context), icon: const Icon(Icons.person_add_rounded, size: 18), label: const Text('افزودن عضو'), ), ], ), const SizedBox(height: 20), // ── Group info card ─────────────────────────────────────── Card( child: Padding( padding: const EdgeInsets.all(20), child: Row( children: [ Container( width: 56, height: 56, decoration: BoxDecoration( color: const Color(0xFF7C3AED).withValues(alpha: 0.12), borderRadius: BorderRadius.circular(14), ), child: const Icon( Icons.groups_rounded, color: Color(0xFF7C3AED), size: 28, ), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text( groupName, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w700, color: AppTheme.textPrimary, ), ), const SizedBox(width: 10), _StatusBadge(isActive: isActive), ], ), ], ), ), ], ), ), ), const SizedBox(height: 24), // ── Members section ─────────────────────────────────────── const Text( 'اعضای گروه', style: TextStyle( fontSize: 18, fontWeight: FontWeight.w700, color: AppTheme.textPrimary, ), ), const SizedBox(height: 12), _MembersTable(groupId: groupId), ], ), ); } void _showAddMemberDialog(BuildContext context) { showDialog( context: context, builder: (_) => _AddMemberDialog(groupId: groupId), ); } } // ── Add Member Dialog ──────────────────────────────────────────────────────── class _AddMemberDialog extends StatefulWidget { final String groupId; const _AddMemberDialog({required this.groupId}); @override State<_AddMemberDialog> createState() => _AddMemberDialogState(); } class _AddMemberDialogState extends State<_AddMemberDialog> { UserModel? _selectedUser; bool _loading = false; String? _error; Future _submit() async { if (_selectedUser == null) { setState(() => _error = 'لطفاً یک کاربر انتخاب کنید'); return; } setState(() { _loading = true; _error = null; }); final provider = context.read(); final currentMembers = provider.membersOf(widget.groupId); if (currentMembers.any((m) => m.username == _selectedUser!.username)) { setState(() { _loading = false; _error = 'این کاربر قبلاً عضو این گروه است'; }); return; } final success = await provider.inviteMember( widget.groupId, _selectedUser!.username, ); if (!mounted) return; setState(() => _loading = false); if (success) { Navigator.of(context).pop(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('«${_selectedUser!.username}» به گروه اضافه شد'), backgroundColor: AppTheme.success, ), ); } else { setState(() => _error = provider.error); } } @override Widget build(BuildContext context) { return Consumer(builder: (_, userProvider, __) { final users = userProvider.users; return AlertDialog( title: const Row( children: [ Icon(Icons.person_add_rounded, color: AppTheme.primary), SizedBox(width: 10), Text('افزودن عضو به گروه'), ], ), content: SizedBox( width: 400, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // User selector DropdownButtonFormField( initialValue: _selectedUser, decoration: const InputDecoration( labelText: 'انتخاب کاربر', prefixIcon: Icon(Icons.person_outline_rounded), ), hint: const Text('کاربر را انتخاب کنید'), items: users .map((u) => DropdownMenuItem( value: u, child: Text( '${u.username} (${u.role.label})', ), )) .toList(), onChanged: (v) => setState(() => _selectedUser = v), ), if (_error != null) ...[ const SizedBox(height: 12), Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: AppTheme.danger.withValues(alpha: 0.08), borderRadius: BorderRadius.circular(8), border: Border.all( color: AppTheme.danger.withValues(alpha: 0.3)), ), child: Text( _error!, style: const TextStyle(color: AppTheme.danger, fontSize: 13), ), ), ], ], ), ), actions: [ TextButton( onPressed: _loading ? null : () => Navigator.of(context).pop(), child: const Text('انصراف'), ), ElevatedButton( onPressed: _loading ? null : _submit, child: _loading ? const SizedBox( width: 18, height: 18, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2)) : const Text('افزودن'), ), ], ); }); } } // ── Members Table ──────────────────────────────────────────────────────────── class _MembersTable extends StatelessWidget { final String groupId; const _MembersTable({required this.groupId}); @override Widget build(BuildContext context) { return Consumer(builder: (_, provider, __) { final members = provider.membersOf(groupId); if (members.isEmpty) { return Card( child: Padding( padding: const EdgeInsets.all(40), child: Center( child: Column( children: [ const Icon(Icons.people_outline_rounded, size: 56, color: AppTheme.border), const SizedBox(height: 12), const Text( 'هنوز عضوی به این گروه اضافه نشده است', style: TextStyle(color: AppTheme.textSecondary), ), const SizedBox(height: 16), ElevatedButton.icon( onPressed: () => showDialog( context: context, builder: (_) => _AddMemberDialog(groupId: groupId), ), icon: const Icon(Icons.person_add_rounded, size: 16), label: const Text('افزودن اولین عضو'), ), ], ), ), ), ); } return Card( child: ClipRRect( borderRadius: BorderRadius.circular(12), child: SingleChildScrollView( child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: DataTable( columns: const [ DataColumn(label: Text('کاربر')), DataColumn(label: Text('نقش در گروه')), DataColumn(label: Text('وضعیت آنلاین')), DataColumn(label: Text('عملیات')), ], rows: members.map((m) => _buildRow(context, m)).toList(), ), ), ), ), ); }); } DataRow _buildRow(BuildContext context, GroupMemberModel member) { final color = member.role == GroupRole.manager ? const Color(0xFF0891B2) : AppTheme.textSecondary; return DataRow( cells: [ DataCell( Row( mainAxisSize: MainAxisSize.min, children: [ CircleAvatar( radius: 16, backgroundColor: AppTheme.primary.withValues(alpha: 0.12), child: Text( (member.username ?? member.userId)[0].toUpperCase(), style: const TextStyle( color: AppTheme.primary, fontSize: 13, fontWeight: FontWeight.w700, ), ), ), const SizedBox(width: 10), Text( member.username ?? member.userId, style: const TextStyle(fontWeight: FontWeight.w600), ), ], ), ), DataCell( Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: color.withValues(alpha: 0.12), borderRadius: BorderRadius.circular(20), ), child: Text( member.role.label, style: TextStyle( color: color, fontSize: 12, fontWeight: FontWeight.w600, ), ), ), ), DataCell( _OnlineBadge(isOnline: member.isOnline), ), DataCell( _RemoveMemberButton(groupId: groupId, member: member), ), ], ); } } class _RemoveMemberButton extends StatefulWidget { final String groupId; final GroupMemberModel member; const _RemoveMemberButton({required this.groupId, required this.member}); @override State<_RemoveMemberButton> createState() => _RemoveMemberButtonState(); } class _RemoveMemberButtonState extends State<_RemoveMemberButton> { bool _loading = false; Future _remove() async { final confirmed = await showDialog( context: context, builder: (_) => AlertDialog( title: const Text('تأیید حذف عضو'), content: Text( 'آیا مطمئن هستید که می‌خواهید «${widget.member.username ?? widget.member.userId}» را از این گروه حذف کنید؟'), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('انصراف'), ), ElevatedButton( onPressed: () => Navigator.pop(context, true), style: ElevatedButton.styleFrom(backgroundColor: AppTheme.danger), child: const Text('حذف'), ), ], ), ); if (confirmed != true || !mounted) return; setState(() => _loading = true); final provider = context.read(); final success = await provider.removeMember(widget.groupId, widget.member.userId); if (!mounted) return; setState(() => _loading = false); if (success) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('عضو از گروه حذف شد'), backgroundColor: AppTheme.success, ), ); } else if (provider.error != null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(provider.error!), backgroundColor: AppTheme.danger, ), ); } } @override Widget build(BuildContext context) { if (_loading) { return const SizedBox( width: 18, height: 18, child: CircularProgressIndicator(strokeWidth: 2)); } return IconButton( onPressed: _remove, icon: const Icon(Icons.person_remove_rounded, size: 18), color: AppTheme.danger, tooltip: 'حذف از گروه', ); } } // ── Status Badge ───────────────────────────────────────────────────────────── class _StatusBadge extends StatelessWidget { final bool isActive; const _StatusBadge({required this.isActive}); @override Widget build(BuildContext context) { final color = isActive ? AppTheme.success : AppTheme.danger; return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: color.withValues(alpha: 0.12), borderRadius: BorderRadius.circular(20), ), child: Text( isActive ? 'فعال' : 'غیرفعال', style: TextStyle( color: color, fontSize: 12, fontWeight: FontWeight.w600, ), ), ); } } class _OnlineBadge extends StatelessWidget { final bool isOnline; const _OnlineBadge({required this.isOnline}); @override Widget build(BuildContext context) { final color = isOnline ? AppTheme.success : AppTheme.textSecondary; return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: color.withValues(alpha: 0.12), borderRadius: BorderRadius.circular(20), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Container( width: 6, height: 6, decoration: BoxDecoration(color: color, shape: BoxShape.circle), ), const SizedBox(width: 5), Text( isOnline ? 'آنلاین' : 'آفلاین', style: TextStyle( color: color, fontSize: 12, fontWeight: FontWeight.w600, ), ), ], ), ); } }