Files
votianlt/app/lib/chats_view.dart

187 lines
5.2 KiB
Dart

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<ChatsView> createState() => _ChatsViewState();
}
class _ChatsViewState extends State<ChatsView> {
final ChatService _chatService = ChatService();
List<Chat> _chats = const [];
StreamSubscription<List<Chat>>? _chatSubscription;
bool _isInitializing = true;
@override
void initState() {
super.initState();
_initializeChats();
}
Future<void> _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';
}
}
}