feat: erweiterte Chat-Funktionalität, UI-Verbesserungen und Lokalisierungsupdates

- Chat: Nachrichten-Status (read/unread), WebSocket-Verbesserungen
- App: Login-Optimierung, Job-Übersicht verbessert, neue Übersetzungen
- Backend: Dialog-Styling, Invoice-Generator, Job-Verwaltung erweitert
- Mehrsprachigkeit: Neue Übersetzungen für DE, EN, ES, ET, FR, LT, LV, PL, RU, TR
This commit is contained in:
2026-04-04 10:30:36 +02:00
parent d6132fabe1
commit bba5733783
55 changed files with 2708 additions and 697 deletions

View File

@@ -5,6 +5,7 @@ import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:image/image.dart' as img;
import 'l10n/app_localizations.dart';
import 'l10n/localization_helpers.dart';
import 'app_state.dart';
import 'models/chat.dart';
import 'models/chat_message.dart';
@@ -195,9 +196,7 @@ class _ChatDetailsViewState extends State<ChatDetailsView> {
if (sender == null || sender.isEmpty) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context).noSenderMessage),
),
SnackBar(content: Text(AppLocalizations.of(context).noSenderMessage)),
);
}
return;
@@ -233,7 +232,6 @@ class _ChatDetailsViewState extends State<ChatDetailsView> {
return;
}
await _chatService.saveOutgoingMessage(result);
_syncActiveChatFromService();
_messageController.clear();
@@ -250,7 +248,10 @@ class _ChatDetailsViewState extends State<ChatDetailsView> {
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(_activeChat.title, style: const TextStyle(fontSize: 16)),
Text(
localizedChatTitle(context, _activeChat),
style: const TextStyle(fontSize: 16),
),
if (isJobChat && _activeChat.jobNumber != null)
Text(
'Job-Nr: ${_activeChat.jobNumber}',
@@ -540,9 +541,7 @@ class _ChatDetailsViewState extends State<ChatDetailsView> {
if (sender == null || sender.isEmpty) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context).noSenderMessage),
),
SnackBar(content: Text(AppLocalizations.of(context).noSenderMessage)),
);
}
return;
@@ -589,7 +588,6 @@ class _ChatDetailsViewState extends State<ChatDetailsView> {
return;
}
await _chatService.saveOutgoingMessage(result);
_syncActiveChatFromService();
if (prepared.bytes.isNotEmpty) {
@@ -645,7 +643,7 @@ class _ChatDetailsViewState extends State<ChatDetailsView> {
return '${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}';
} else if (messageDate == today.subtract(const Duration(days: 1))) {
// Yesterday
return 'Gestern ${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}';
return '${AppLocalizations.of(context).yesterday} ${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}';
} else {
// Older - show date and time
return '${dateTime.day.toString().padLeft(2, '0')}.${dateTime.month.toString().padLeft(2, '0')} ${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}';
@@ -659,21 +657,27 @@ class _ChatDetailsViewState extends State<ChatDetailsView> {
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(_activeChat.title),
title: Text(localizedChatTitle(context, _activeChat)),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('${AppLocalizations.of(context).status}: ${isJobChat ? AppLocalizations.of(context).chatTypeJob : AppLocalizations.of(context).chatTypeGeneral}'),
Text(
'${AppLocalizations.of(context).status}: ${isJobChat ? AppLocalizations.of(context).chatTypeJob : AppLocalizations.of(context).chatTypeGeneral}',
),
const SizedBox(height: 8),
if (isJobChat && _activeChat.jobNumber != null) ...[
Text('${AppLocalizations.of(context).jobNumber}: ${_activeChat.jobNumber}'),
Text(
'${AppLocalizations.of(context).jobNumber}: ${_activeChat.jobNumber}',
),
const SizedBox(height: 8),
],
Text('${AppLocalizations.of(context).messages}: ${_messages.length}'),
Text(
'${AppLocalizations.of(context).messages}: ${_messages.length}',
),
const SizedBox(height: 8),
Text(
'Erstellt: ${_formatMessageTime(_messages.isNotEmpty ? _messages.first.createdAt : DateTime.now())}',
'${AppLocalizations.of(context).created}: ${_formatMessageTime(_messages.isNotEmpty ? _messages.first.createdAt : DateTime.now())}',
),
],
),