import 'dart:async'; import 'package:flutter/material.dart'; import 'l10n/app_localizations.dart'; import 'models/chat.dart'; import 'services/chat_service.dart'; import 'widgets/offline_banner.dart'; class ChatsView extends StatefulWidget { const ChatsView({super.key}); @override State createState() => _ChatsViewState(); } class _ChatsViewState extends State { final ChatService _chatService = ChatService(); List _chats = const []; StreamSubscription>? _chatSubscription; bool _isInitializing = true; @override void initState() { super.initState(); _initializeChats(); } Future _initializeChats() async { await _chatService.initialize(); if (!mounted) return; setState(() { _chats = _chatService.currentChats; _isInitializing = false; }); _chatSubscription = _chatService.chatsStream.listen((chats) { if (!mounted) return; setState(() { _chats = chats; }); }); } @override void dispose() { _chatSubscription?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(AppLocalizations.of(context).chats), backgroundColor: Colors.deepPurple[100], ), body: Column( children: [ const OfflineBanner(), Expanded(child: _buildBody()), ], ), ); } Widget _buildBody() { if (_isInitializing) { return const Center(child: CircularProgressIndicator()); } if (_chats.isEmpty) { return const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.chat_outlined, size: 64, color: Colors.grey), SizedBox(height: 16), Text( 'Keine Chats verfügbar', style: TextStyle(fontSize: 16, color: Colors.grey), ), ], ), ); } return ListView.builder( itemCount: _chats.length, itemBuilder: (context, index) { final chat = _chats[index]; return _buildChatTile(chat); }, ); } Widget _buildChatTile(Chat chat) { final isJobChat = chat.type == ChatType.jobSpecific; final hasMessages = chat.messages.isNotEmpty; final previewText = hasMessages ? chat.lastMessagePreview : 'Noch keine Nachrichten'; final timeLabel = hasMessages ? _formatTime(chat.lastMessageTime) : '--'; final jobId = chat.jobId?.trim(); final jobNumber = chat.jobNumber?.trim(); final showJobId = isJobChat && jobId != null && jobId.isNotEmpty; return Card( margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), child: ListTile( leading: CircleAvatar( backgroundColor: isJobChat ? Colors.blue[100] : Colors.green[100], child: Icon( isJobChat ? Icons.work : Icons.support_agent, color: isJobChat ? Colors.blue[700] : Colors.green[700], ), ), title: Text(() { if (isJobChat) { if (jobNumber != null && jobNumber.isNotEmpty) { return 'Job $jobNumber'; } if (showJobId) { return 'Job $jobId'; } } return chat.type == ChatType.general ? 'Allgemeine Nachrichten' : chat.title; }(), style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 16)), subtitle: Text( previewText, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 14, color: Colors.grey[700]), ), trailing: Column( crossAxisAlignment: CrossAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( timeLabel, style: TextStyle(fontSize: 12, color: Colors.grey[500]), ), const SizedBox(height: 4), Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: isJobChat ? Colors.blue[50] : Colors.green[50], borderRadius: BorderRadius.circular(10), border: Border.all( color: isJobChat ? Colors.blue[200]! : Colors.green[200]!, ), ), child: Text( isJobChat ? 'JOB' : 'ALLG', style: TextStyle( fontSize: 10, fontWeight: FontWeight.w600, color: isJobChat ? Colors.blue[700] : Colors.green[700], ), ), ), ], ), onTap: () { Navigator.of(context).pushNamed('/chat_details', arguments: chat); }, ), ); } String _formatTime(DateTime dateTime) { final now = DateTime.now(); final difference = now.difference(dateTime); if (difference.inDays > 0) { return '${difference.inDays}T'; } else if (difference.inHours > 0) { return '${difference.inHours}h'; } else if (difference.inMinutes > 0) { return '${difference.inMinutes}m'; } else { return 'jetzt'; } } }