diff --git a/creche_app/lib/features/chat/chat_list_screen.dart b/creche_app/lib/features/chat/chat_list_screen.dart deleted file mode 100644 index 21960e1..0000000 --- a/creche_app/lib/features/chat/chat_list_screen.dart +++ /dev/null @@ -1,203 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:go_router/go_router.dart'; -import 'package:supabase_flutter/supabase_flutter.dart'; -import '/core/auth_provider.dart'; -import '/models/profile.dart'; - -const _bg = Color(0xFF0D1117); -const _card = Color(0xFF161B22); -const _blue = Color(0xFF4FC3F7); - -String _roleLabel(String r) { - switch (r) { - case 'principal': return 'Diretora'; - case 'admin': return 'Administrador'; - case 'teacher': return 'Educadora'; - case 'staff': return 'Auxiliar'; - case 'parent': return 'Encarregado'; - default: return r; - } -} - -class ChatListScreen extends ConsumerWidget { - const ChatListScreen({super.key}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final sb = Supabase.instance.client; - final profileAsync = ref.watch(currentProfileProvider); - - return profileAsync.when( - data: (myProfile) { - if (myProfile == null) { - return const Scaffold( - backgroundColor: _bg, - body: Center(child: Text('Perfil não encontrado', style: TextStyle(color: Colors.white))), - ); - } - return Scaffold( - backgroundColor: _bg, - appBar: AppBar( - backgroundColor: _card, - title: const Text('Mensagens', style: TextStyle(color: _blue, fontWeight: FontWeight.bold)), - elevation: 0, - ), - body: StreamBuilder>>( - stream: sb.from('profiles').stream(primaryKey: ['id']), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return const Center(child: CircularProgressIndicator(color: _blue)); - } - final profiles = snapshot.data! - .map(Profile.fromMap) - .where((p) => p.id != myProfile.id) - .toList() - ..sort((a, b) => a.fullName.compareTo(b.fullName)); - - if (profiles.isEmpty) { - return Center(child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.chat_bubble_outline, size: 64, color: Colors.white.withOpacity(0.07)), - const SizedBox(height: 12), - const Text('Sem utilizadores para contactar', - style: TextStyle(color: Color(0xFF888888))), - ])); - } - - return ListView.separated( - padding: const EdgeInsets.symmetric(vertical: 8), - itemCount: profiles.length, - separatorBuilder: (_, __) => Divider( - height: 1, indent: 72, - color: Colors.white.withOpacity(0.05), - ), - itemBuilder: (context, i) { - final profile = profiles[i]; - return _ChatTile( - profile: profile, - myProfileId: myProfile.id, - onTap: () => context.go('/chat/${profile.id}'), - ); - }, - ); - }, - ), - ); - }, - loading: () => const Scaffold( - backgroundColor: _bg, - body: Center(child: CircularProgressIndicator(color: _blue)), - ), - error: (e, _) => Scaffold( - backgroundColor: _bg, - body: Center(child: Text('Erro: $e', style: const TextStyle(color: Colors.red))), - ), - ); - } -} - -class _ChatTile extends StatelessWidget { - final Profile profile; - final String myProfileId; - final VoidCallback onTap; - const _ChatTile({required this.profile, required this.myProfileId, required this.onTap}); - - @override - Widget build(BuildContext context) { - final sb = Supabase.instance.client; - return FutureBuilder?>( - future: _getLastMessage(sb), - builder: (context, snap) { - final lastMsg = snap.data?['content'] as String? ?? ''; - final unread = snap.data?['unread'] as int? ?? 0; - final hasUnread = unread > 0; - - return Material( - color: Colors.transparent, - child: InkWell( - onTap: onTap, - splashColor: _blue.withOpacity(0.08), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - child: Row(children: [ - // Avatar - CircleAvatar( - radius: 26, - backgroundColor: _blue.withOpacity(0.12), - backgroundImage: profile.avatarUrl != null - ? NetworkImage(profile.avatarUrl!) : null, - child: profile.avatarUrl == null - ? Text(profile.fullName.isNotEmpty ? profile.fullName[0].toUpperCase() : '?', - style: const TextStyle(color: _blue, fontWeight: FontWeight.bold, fontSize: 18)) - : null, - ), - const SizedBox(width: 14), - // Info - Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(profile.fullName, - style: TextStyle( - color: Colors.white, - fontWeight: hasUnread ? FontWeight.bold : FontWeight.w500, - fontSize: 14, - )), - const SizedBox(height: 2), - Text(lastMsg.isNotEmpty ? lastMsg : _roleLabel(profile.role), - maxLines: 1, overflow: TextOverflow.ellipsis, - style: TextStyle( - color: hasUnread ? _blue : const Color(0xFF888888), - fontSize: 12, - fontWeight: hasUnread ? FontWeight.w600 : FontWeight.normal, - )), - ])), - // Unread badge - if (hasUnread) - Container( - padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 3), - decoration: BoxDecoration( - color: _blue, borderRadius: BorderRadius.circular(12), - ), - child: Text('$unread', - style: const TextStyle(color: Colors.white, fontSize: 11, fontWeight: FontWeight.bold)), - ) - else - const Icon(Icons.chevron_right, color: Color(0xFF444466), size: 20), - ]), - ), - ), - ); - }, - ); - } - -Future?> _getLastMessage(SupabaseClient sb) async { - try { - final msgs = await sb - .from('messages') - .select('content, from_user, is_read') - .or( - 'and(from_user.eq.$myProfileId,to_user.eq.${profile.id}),' - 'and(from_user.eq.${profile.id},to_user.eq.$myProfileId)' - ) - .order('created_at', ascending: false) - .limit(1); - - if (msgs.isEmpty) return null; - - final last = msgs.first; - - final unreadMsgs = await sb - .from('messages') - .select('id') - .eq('from_user', profile.id) - .eq('to_user', myProfileId) - .eq('is_read', false); - - return { - 'content': last['content'] as String, - 'unread': unreadMsgs.length, - }; - } catch (_) { - return null; - } -} -}