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

@@ -191,7 +191,7 @@
},
{
"id": "5:2194624907249454848",
"lastPropertyId": "6:5035828038544573244",
"lastPropertyId": "7:5673785903451668117",
"name": "TaskStatusEntity",
"properties": [
{
@@ -275,7 +275,9 @@
"modelVersionParserMinimum": 5,
"retiredEntityUids": [],
"retiredIndexUids": [],
"retiredPropertyUids": [],
"retiredPropertyUids": [
5673785903451668117
],
"retiredRelationUids": [],
"version": 1
}

View File

@@ -240,7 +240,7 @@ final _entities = <obx_int.ModelEntity>[
obx_int.ModelEntity(
id: const obx_int.IdUid(5, 2194624907249454848),
name: 'TaskStatusEntity',
lastPropertyId: const obx_int.IdUid(6, 5035828038544573244),
lastPropertyId: const obx_int.IdUid(7, 5673785903451668117),
flags: 0,
properties: <obx_int.ModelProperty>[
obx_int.ModelProperty(
@@ -371,7 +371,7 @@ obx_int.ModelDefinition getObjectBoxModel() {
lastSequenceId: const obx_int.IdUid(0, 0),
retiredEntityUids: const [],
retiredIndexUids: const [],
retiredPropertyUids: const [],
retiredPropertyUids: const [5673785903451668117],
retiredRelationUids: const [],
modelVersion: 5,
modelVersionParserMinimum: 5,
@@ -632,7 +632,7 @@ obx_int.ModelDefinition getObjectBoxModel() {
},
objectToFB: (TaskStatusEntity object, fb.Builder fbb) {
final taskIdOffset = fbb.writeString(object.taskId);
fbb.startTable(7);
fbb.startTable(8);
fbb.addInt64(0, object.id);
fbb.addOffset(1, taskIdOffset);
fbb.addBool(2, object.completed);

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;
}
}

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.15+1
version: 0.9.16+1
environment:
sdk: ^3.7.0