feat: Auftragsdetails und Stationsabschluss für Version 0.9.24

Preisanzeige in der App entfernen und Auftragsbezeichnungen vereinheitlichen.

Stationsabschlüsse und Benachrichtigungen absichern sowie Historie um Aufgabenbeschreibungen und ausführende Nutzer erweitern.

Regressionstests ergänzen und App sowie Backend auf Version 0.9.24 anheben.
This commit is contained in:
Sven committed 2026-10-01 11:31:59 +02:00
1 parent 7325c77739
commit b642f42954
37 files changed
+1067 -223

No files matched your search

+3 -3
View File
@@ -120,10 +120,10 @@ class _ChatsViewState extends State<ChatsView> {
title: Text(() {
if (isJobChat) {
if (jobNumber != null && jobNumber.isNotEmpty) {
return 'Job $jobNumber';
return 'Auftrag $jobNumber';
}
if (showJobId) {
return 'Job $jobId';
return 'Auftrag $jobId';
}
}
return localizedChatTitle(context, chat);
@@ -154,7 +154,7 @@ class _ChatsViewState extends State<ChatsView> {
),
),
child: Text(
isJobChat ? 'JOB' : 'ALLG',
isJobChat ? 'AUFTRAG' : 'ALLG',
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w600,
+2 -23
View File
@@ -145,7 +145,7 @@ class _JobsViewState extends State<JobsView> with RouteAware {
if (mounted) {
final message =
jobNumber != null
? 'Job $jobNumber ${AppLocalizations.of(context).jobRemoved}'
? 'Auftrag $jobNumber ${AppLocalizations.of(context).jobRemoved}'
: AppLocalizations.of(context).jobRemoved;
_showSnack(message, backgroundColor: AppColors.warning);
}
@@ -1406,7 +1406,7 @@ class _JobsViewState extends State<JobsView> with RouteAware {
],
),
const SizedBox(height: 8),
// Dates and Price
// Creation date
Row(
children: [
Expanded(
@@ -1428,27 +1428,6 @@ class _JobsViewState extends State<JobsView> with RouteAware {
],
),
),
if (job.price > 0) ...[
Container(
padding: const EdgeInsets.symmetric(
horizontal: 6,
vertical: 2,
),
decoration: BoxDecoration(
color: Colors.green[50],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.green[200]!),
),
child: Text(
'${job.price.toStringAsFixed(2)} €',
style: TextStyle(
fontSize: 12,
color: Colors.green[700],
fontWeight: FontWeight.w600,
),
),
),
],
],
),
],
+18 -15
View File
@@ -52,7 +52,7 @@ class AppLocalizationsDe extends AppLocalizations {
// ==================== NAVIGATION ====================
@override
String get jobs => 'Jobs';
String get jobs => 'Aufträge';
@override
String get availableJobs => 'Auftragsliste';
@@ -155,10 +155,11 @@ class AppLocalizationsDe extends AppLocalizations {
// ==================== JOBS ====================
@override
String get noJobsAssigned => 'Keine Jobs zugewiesen';
String get noJobsAssigned => 'Keine Aufträge zugewiesen';
@override
String get noJobsMessage => 'Ihre zugewiesenen Jobs werden hier angezeigt.';
String get noJobsMessage =>
'Ihre zugewiesenen Aufträge werden hier angezeigt.';
@override
String get pullToRefresh => 'Nach unten ziehen zum Aktualisieren';
@@ -206,13 +207,13 @@ class AppLocalizationsDe extends AppLocalizations {
String get dimensions => 'Abmessungen';
@override
String get jobDeleted => 'Job gelöscht';
String get jobDeleted => 'Auftrag gelöscht';
@override
String get jobDeleteError => 'Fehler beim Löschen des Jobs';
String get jobDeleteError => 'Fehler beim Löschen des Auftrags';
@override
String get jobCompleted => 'Job abgeschlossen';
String get jobCompleted => 'Auftrag abgeschlossen';
@override
String get from => 'Von';
@@ -221,10 +222,11 @@ class AppLocalizationsDe extends AppLocalizations {
String get to => 'nach';
@override
String get jobsUpdated => 'Jobs aktualisiert';
String get jobsUpdated => 'Aufträge aktualisiert';
@override
String get connectionRestored => 'Verbindung wiederhergestellt. Lade Jobs...';
String get connectionRestored =>
'Verbindung wiederhergestellt. Lade Aufträge...';
@override
String get connectionLost => 'Verbindung verloren. Offline.';
@@ -233,13 +235,13 @@ class AppLocalizationsDe extends AppLocalizations {
String get offline => 'Offline';
@override
String get deleteJob => 'Job löschen';
String get deleteJob => 'Auftrag löschen';
@override
String get jobRemoved => 'wurde entfernt';
@override
String get newJobReceived => 'Neuer Job erhalten';
String get newJobReceived => 'Neuer Auftrag erhalten';
@override
String get jobDetails => 'Auftragsdetails';
@@ -258,7 +260,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get noDeliveryStationsMessage =>
'Dieser Job enthält aktuell keine Lieferstationen.';
'Dieser Auftrag enthält aktuell keine Lieferstationen.';
@override
String get phone => 'Telefon';
@@ -277,7 +279,8 @@ class AppLocalizationsDe extends AppLocalizations {
String get noTasks => 'Keine Aufgaben';
@override
String get noTasksMessage => 'Für diesen Job sind keine Aufgaben definiert.';
String get noTasksMessage =>
'Für diesen Auftrag sind keine Aufgaben definiert.';
@override
String get taskOrder => 'Reihenfolge';
@@ -498,13 +501,13 @@ class AppLocalizationsDe extends AppLocalizations {
String get imageSendError => 'Bild konnte nicht gesendet werden.';
@override
String get chatTypeJob => 'Job-spezifisch';
String get chatTypeJob => 'Auftragsbezogen';
@override
String get chatTypeGeneral => 'Allgemein';
@override
String get jobNumber => 'Job-Nummer';
String get jobNumber => 'Auftragsnummer';
@override
String get messages => 'Nachrichten';
@@ -558,7 +561,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get noCargoItemsMessage =>
'Für diesen Job sind keine Frachtgüter definiert.';
'Für diesen Auftrag sind keine Frachtgüter definiert.';
@override
String get article => 'Artikel';
+7
View File
@@ -46,5 +46,12 @@ String localizedChatTitle(BuildContext context, Chat chat) {
if (chat.type == ChatType.general) {
return AppLocalizations.of(context).generalMessages;
}
// Older locally stored conversations still use the previous title prefix.
if (chat.title.startsWith('Job ')) {
return 'Auftrag ${chat.title.substring(4)}';
}
if (chat.title == 'Job-Chat') {
return 'Auftrags-Chat';
}
return localizeKnownText(context, chat.title);
}
+1 -1
View File
@@ -98,7 +98,7 @@ class Chat {
final lastMessage = messages.isNotEmpty ? messages.last : null;
return Chat(
id: id,
title: 'Job $jobNumber',
title: 'Auftrag $jobNumber',
receiver: receiver,
type: ChatType.jobSpecific,
jobId: jobId,
+1 -1
View File
@@ -109,7 +109,7 @@ class Job {
this.assignedTo,
this.location,
this.additionalData,
}) : title = title ?? 'Job $jobNumber',
}) : title = title ?? 'Auftrag $jobNumber',
description =
description ?? 'Transport von $pickupCity nach $deliveryCity';
+3 -3
View File
@@ -350,12 +350,12 @@ class ChatService {
String _buildJobTitle(String? jobNumber, String? jobId) {
if (jobNumber != null && jobNumber.isNotEmpty) {
return 'Job $jobNumber';
return 'Auftrag $jobNumber';
}
if (jobId != null && jobId.length >= 6) {
return 'Job ${jobId.substring(0, 6).toUpperCase()}';
return 'Auftrag ${jobId.substring(0, 6).toUpperCase()}';
}
return 'Job-Chat';
return 'Auftrags-Chat';
}
String? _determineCounterpart(
+15 -7
View File
@@ -21,9 +21,9 @@ class NotificationService {
'Benachrichtigungen bei neuen Chat-Nachrichten';
static const String _jobChannelId = 'new_jobs';
static const String _jobChannelName = 'Neue Jobs';
static const String _jobChannelName = 'Neue Aufträge';
static const String _jobChannelDescription =
'Benachrichtigungen bei neuen Job-Zuweisungen';
'Benachrichtigungen bei neuen Auftragszuweisungen';
int _nextId = 0;
@@ -49,12 +49,15 @@ class NotificationService {
await _plugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
AndroidFlutterLocalNotificationsPlugin
>()
?.requestNotificationsPermission();
_initialized = true;
developer.log('NotificationService initialized',
name: 'NotificationService');
developer.log(
'NotificationService initialized',
name: 'NotificationService',
);
}
Future<void> showChatNotification({
@@ -87,8 +90,13 @@ class NotificationService {
iOS: iosDetails,
);
await _plugin.show(_nextId++, title, body, details,
payload: 'chat:$conversationKey');
await _plugin.show(
_nextId++,
title,
body,
details,
payload: 'chat:$conversationKey',
);
}
Future<void> showJobNotification({
+8 -8
View File
@@ -440,11 +440,11 @@ class WebSocketService {
if (currentJobCount > 0 && jobs.length > currentJobCount) {
final newCount = jobs.length - currentJobCount;
NotificationService().showJobNotification(
title: 'Neue Jobs',
title: 'Neue Aufträge',
body:
newCount == 1
? 'Sie haben einen neuen Job erhalten.'
: 'Sie haben $newCount neue Jobs erhalten.',
? 'Sie haben einen neuen Auftrag erhalten.'
: 'Sie haben $newCount neue Aufträge erhalten.',
);
}
@@ -597,11 +597,11 @@ class WebSocketService {
// Show notification with sound for new job
NotificationService().showJobNotification(
title: 'Neuer Job',
title: 'Neuer Auftrag',
body:
jobNumber != null && jobNumber.isNotEmpty
? 'Job $jobNumber wurde Ihnen zugewiesen.'
: 'Sie haben einen neuen Job erhalten.',
? 'Auftrag $jobNumber wurde Ihnen zugewiesen.'
: 'Sie haben einen neuen Auftrag erhalten.',
);
// Publish event via DartMQ for UI to handle
@@ -642,8 +642,8 @@ class WebSocketService {
final jobNumber = message.jobNumber ?? '';
notificationTitle =
jobNumber.isNotEmpty
? 'Nachricht zu Job $jobNumber'
: 'Neue Job-Nachricht';
? 'Nachricht zu Auftrag $jobNumber'
: 'Neue Auftragsnachricht';
} else {
notificationTitle = 'Neue Nachricht';
}
+1 -1
View File
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 0.9.23+923
version: 0.9.24+924
environment:
sdk: ^3.7.0