Version 0.9.16: Skip-Button entfernt, manuelle Auftragsbeendigung und E-Mail-Verbesserungen

App:
- Skip-Button für optionale Aufgaben entfernt — optionale Aufgaben blockieren
  nicht mehr den Fortschritt und können jederzeit nachträglich bearbeitet werden

Backend:
- Manuelle Auftragsbeendigung mit Begründung in der Job-Zusammenfassung hinzugefügt
- Leere Lieferstationen werden beim Übernehmen automatisch entfernt
- E-Mail-Benachrichtigungen zeigen jetzt den tatsächlichen App-Benutzernamen an
- WebSocket: konfigurierbare Max-Nachrichtengröße und Session-Idle-Timeout
- docker_push.sh Pfadkorrektur
- Lokalisierungen für 10 Sprachen aktualisiert
- EmailService-Test hinzugefügt

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-09 16:43:38 +02:00
parent bba5733783
commit 1ac755bcbd
22 changed files with 516 additions and 46 deletions

View File

@@ -40,7 +40,6 @@ class TaskView extends StatefulWidget {
class _TaskViewState extends State<TaskView> {
final Set<String> _completedTasks = {};
final Set<String> _skippedTasks = {};
final DatabaseService _databaseService = DatabaseService();
// Store SVG representations of signatures per task for later use
final Map<String, String> _signatureSvgByTask = {};
@@ -61,7 +60,7 @@ class _TaskViewState extends State<TaskView> {
.toList();
}
/// Load task completion statuses from database and merge with JSON task states
/// Load task completion and skipped statuses from database and merge with JSON task states
Future<void> _loadTaskStatuses() async {
final statuses = await _databaseService.loadAllTaskStatuses();
setState(() {
@@ -170,33 +169,26 @@ class _TaskViewState extends State<TaskView> {
itemBuilder: (context, index) {
final task = _visibleTasks[index];
final isCompleted = _completedTasks.contains(task.id);
final isSkipped = _skippedTasks.contains(task.id);
final canBeCompletedNow =
!isCompleted && !isSkipped && _arePreviousTasksCompleted(index);
!isCompleted && _arePreviousTasksCompleted(index);
// Hintergrundfarbe je nach Status:
// abgeschlossen → hellgrün, übersprungen → hellgelb, bearbeitbar → weiß, gesperrt → hellgrau
// abgeschlossen → hellgrün, bearbeitbar → weiß, gesperrt → hellgrau
final Color cardColor =
isCompleted
? const Color(0xFFE8F5E9) // hellgrün
: isSkipped
? const Color(0xFFFFF8E1) // hellgelb
: canBeCompletedNow
? Colors.white
: const Color(0xFFF5F5F5); // hellgrau
final Color borderColor =
isCompleted
? Colors.green[300]!
: isSkipped
? Colors.amber[300]!
: canBeCompletedNow
? Colors.grey[300]!
: Colors.grey[200]!;
final Color circleColor =
isCompleted
? Colors.green[600]!
: isSkipped
? Colors.amber[600]!
: canBeCompletedNow
? Colors.deepPurple[400]!
: Colors.grey[400]!;
@@ -250,7 +242,7 @@ class _TaskViewState extends State<TaskView> {
children: [
_buildTaskDisplayText(
task,
isCompleted || isSkipped,
isCompleted,
index,
),
if (_getTaskStationLabel(task) != null) ...[
@@ -264,6 +256,28 @@ class _TaskViewState extends State<TaskView> {
),
),
],
if (task.optional) ...[
const SizedBox(height: 4),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 2,
),
decoration: BoxDecoration(
color: Colors.amber[50],
border: Border.all(color: Colors.amber[300]!),
borderRadius: BorderRadius.circular(12),
),
child: Text(
AppLocalizations.of(context).optional,
style: TextStyle(
fontSize: 11,
color: Colors.amber[800],
fontWeight: FontWeight.w600,
),
),
),
],
],
),
),
@@ -271,10 +285,6 @@ class _TaskViewState extends State<TaskView> {
const SizedBox(width: 8),
Icon(Icons.check_circle, color: Colors.green[600]),
],
if (isSkipped) ...[
const SizedBox(width: 8),
Icon(Icons.skip_next, color: Colors.amber[600]),
],
],
),
),
@@ -634,9 +644,7 @@ class _TaskViewState extends State<TaskView> {
if (index <= 0) return true;
for (int i = 0; i < index; i++) {
final t = _visibleTasks[i];
if (!t.optional &&
!_completedTasks.contains(t.id) &&
!_skippedTasks.contains(t.id)) {
if (!t.optional && !_completedTasks.contains(t.id)) {
return false;
}
}