feat: Drag-and-Drop-Reihenfolge, Station-Abschluss-Flow und UI-Verbesserungen
Lieferstationen-Dialog (Backend/Vaadin): - Aufgaben per Drag & Drop neu anordnen, inkl. Drag-Handle, komprimierter Kachelansicht während des Drags und horizontaler Einfügelinie als Drop-Target - Drop-Indikator wird unterdrückt, wenn der Drop keine Positionsänderung bewirken würde, und nach dem Abschluss clientseitig zuverlässig aufgeräumt - Drag-Handle, Aufgabentyp-Label und Close-Button auf einheitlicher Position ausgerichtet; Abstände in der Kachel komprimiert Station-Abschluss-Flow (Flutter-App + Backend): - Neuer Button "Station abschließen" unter den Aufgaben; deaktiviert, solange Pflichtaufgaben offen sind, ansonsten aktiv (auch wenn nur optionale Aufgaben existieren) - Hinweisdialog nach Erledigung der letzten Pflichtaufgabe sowie Warnung bei offenen optionalen Aufgaben vor dem Senden - Neue station_completed-Nachricht (jobId, jobNumber, stationOrder, completedAt, hasIncompleteOptionalTasks) wird an den Server gesendet - Backend: Auftrag wird nicht mehr automatisch beim Erledigen der letzten Pflichtaufgabe abgeschlossen, sondern erst beim Empfang der station_completed-Nachricht (neuer Handler in MessageController und MessagingConfig) Aufgabenliste in der App: - Farbcodierung optionaler Aufgaben entfernt; stattdessen vertikal zentrierter "Optional"-Chip am rechten Kartenrand Weitere UI-Überarbeitungen über Login, Jobs, Chats, Settings, Aufgaben-Capture- Screens, Offline-Banner und zugehörige Widgets. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import 'package:file_selector/file_selector.dart' as file_selector;
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:votianlt_app/services/developer.dart' as developer;
|
||||
import '../app_theme.dart';
|
||||
import '../l10n/app_localizations.dart';
|
||||
|
||||
class ChatPhotoDialog extends StatefulWidget {
|
||||
@@ -278,7 +279,7 @@ class _ChatPhotoDialogState extends State<ChatPhotoDialog> {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Icons.warning, color: Colors.orange[700], size: 40),
|
||||
const Icon(Icons.warning, color: AppColors.warning, size: 40),
|
||||
const SizedBox(height: 12),
|
||||
Text(_errorMessage!, textAlign: TextAlign.center),
|
||||
],
|
||||
@@ -330,11 +331,7 @@ class _ChatPhotoDialogState extends State<ChatPhotoDialog> {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.photo_camera_back,
|
||||
color: Colors.deepPurple[400],
|
||||
size: 48,
|
||||
),
|
||||
Icon(Icons.photo_camera_back, color: AppColors.primary, size: 48),
|
||||
const SizedBox(height: 12),
|
||||
const Text(
|
||||
'Wähle ein Foto von deinem Gerät aus.',
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:votianlt_app/services/developer.dart' as developer;
|
||||
import 'package:votianlt_app/services/websocket_service.dart';
|
||||
import 'package:votianlt_app/services/dart_mq.dart';
|
||||
import '../app_theme.dart';
|
||||
|
||||
class OfflineBanner extends StatefulWidget {
|
||||
const OfflineBanner({super.key});
|
||||
@@ -24,8 +25,13 @@ class _OfflineBannerState extends State<OfflineBanner> {
|
||||
// Check if we're already connected (e.g., coming back to this screen)
|
||||
_hadConnection = _stompService.isConnected && _stompService.isAuthenticated;
|
||||
// Initialize countdown based on current connection state
|
||||
_onConnectionChange(_stompService.isConnected && _stompService.isAuthenticated);
|
||||
_connSub = DartMQ().subscribe<bool>(MQTopics.connectionStatus, _onConnectionChange);
|
||||
_onConnectionChange(
|
||||
_stompService.isConnected && _stompService.isAuthenticated,
|
||||
);
|
||||
_connSub = DartMQ().subscribe<bool>(
|
||||
MQTopics.connectionStatus,
|
||||
_onConnectionChange,
|
||||
);
|
||||
}
|
||||
|
||||
void _onConnectionChange(bool isConnected) {
|
||||
@@ -68,7 +74,10 @@ class _OfflineBannerState extends State<OfflineBanner> {
|
||||
// Only auto-reconnect if we already know the target; discovery remains user-initiated
|
||||
await _stompService.connect();
|
||||
} catch (e, stackTrace) {
|
||||
developer.log('Auto-reconnect attempt failed: $e', name: 'OfflineBanner');
|
||||
developer.log(
|
||||
'Auto-reconnect attempt failed: $e',
|
||||
name: 'OfflineBanner',
|
||||
);
|
||||
developer.log('Stack trace: $stackTrace', name: 'OfflineBanner');
|
||||
}
|
||||
|
||||
@@ -114,19 +123,19 @@ class _OfflineBannerState extends State<OfflineBanner> {
|
||||
title = 'Offline – Verbindung verloren';
|
||||
subtitle = 'Verbindung wird wiederhergestellt.';
|
||||
icon = Icons.wifi_off;
|
||||
bgColor = Colors.red[50];
|
||||
iconColor = Colors.red[700];
|
||||
titleColor = Colors.red[900];
|
||||
subtitleColor = Colors.red[800];
|
||||
bgColor = AppColors.dangerSoft;
|
||||
iconColor = AppColors.danger;
|
||||
titleColor = AppColors.danger;
|
||||
subtitleColor = AppColors.danger.withValues(alpha: 0.85);
|
||||
} else {
|
||||
// Initial connection attempt
|
||||
title = 'Verbinde mit Server...';
|
||||
subtitle = 'Bitte warten.';
|
||||
icon = Icons.sync;
|
||||
bgColor = Colors.orange[50];
|
||||
iconColor = Colors.orange[700];
|
||||
titleColor = Colors.orange[900];
|
||||
subtitleColor = Colors.orange[800];
|
||||
bgColor = AppColors.warningSoft;
|
||||
iconColor = AppColors.warning;
|
||||
titleColor = AppColors.warning;
|
||||
subtitleColor = AppColors.warning.withValues(alpha: 0.85);
|
||||
}
|
||||
|
||||
return Container(
|
||||
@@ -152,10 +161,7 @@ class _OfflineBannerState extends State<OfflineBanner> {
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
subtitle,
|
||||
style: TextStyle(
|
||||
color: subtitleColor,
|
||||
fontSize: 12,
|
||||
),
|
||||
style: TextStyle(color: subtitleColor, fontSize: 12),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -165,4 +171,3 @@ class _OfflineBannerState extends State<OfflineBanner> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user