Aufgaben-JSON testweise von Web-URL laden, Ankunft-Task als Button, RadioGroup-Umstellung
- TEMP-Loader: Aufgaben beim Oeffnen der Task-Seite von https://appcreation.de/download/task.json laden (Fallback: Tour-Daten) - Task-Typ 1 (Ankunft melden) als Bestaetigungs-Button statt Checkbox - Statusauswahl (Typ 11) auf RadioGroup umgestellt (Deprecation behoben) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1d0d23c1a9
commit
d864b9c72a
2 files changed
+92
-12
No files matched your search
@@ -2,6 +2,8 @@ import 'dart:convert';
|
||||
|
||||
import 'package:dart_mq/dart_mq.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
// TEMP (nur zum Testen, s. _tempTaskJsonUrl): wieder entfernen.
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:image/image.dart' as image_lib;
|
||||
import 'package:intl/intl.dart';
|
||||
@@ -25,6 +27,44 @@ import '../model/tour_task.dart';
|
||||
import '../tools/app_localizations.dart';
|
||||
import '../tools/util.dart';
|
||||
|
||||
// =============================================================================
|
||||
// TEMPORÄR — NUR ZUM TESTEN, WIEDER ENTFERNEN
|
||||
//
|
||||
// Lädt das Aufgaben-JSON beim Öffnen der Seite von einer Webseite statt die
|
||||
// Aufgaben der übergebenen Tour zu verwenden. Die URL muss entweder eine
|
||||
// JSON-Liste von Aufgaben liefern oder ein Objekt mit einer "tasks"-Liste.
|
||||
//
|
||||
// Zum Entfernen: diesen Block, den http-Import oben und die mit
|
||||
// "TEMP" markierte Zeile in _fetchTaskList() löschen. Alternativ die URL auf
|
||||
// null setzen, dann greift wieder das normale Verhalten (auch bei Ladefehler).
|
||||
// =============================================================================
|
||||
// ignore: unnecessary_nullable_for_final_variable_declarations
|
||||
const String? _tempTaskJsonUrl = "https://appcreation.de/download/task.json";
|
||||
|
||||
Future<List<TourTask>?> _tempLoadTasksFromWeb() async {
|
||||
final url = _tempTaskJsonUrl;
|
||||
if (url == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
final response = await http.get(Uri.parse(url));
|
||||
if (response.statusCode != 200) {
|
||||
debugPrint("TEMP: Aufgaben-JSON laden fehlgeschlagen, HTTP ${response.statusCode}");
|
||||
return null;
|
||||
}
|
||||
|
||||
final decoded = jsonDecode(utf8.decode(response.bodyBytes));
|
||||
final list = decoded is List ? decoded : (decoded as Map<String, dynamic>)['tasks'] as List<dynamic>;
|
||||
|
||||
return list.map((e) => TourTask.fromJson(e as Map<String, dynamic>)).toList();
|
||||
} catch (e) {
|
||||
debugPrint("TEMP: Aufgaben-JSON laden fehlgeschlagen: $e");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// ========================================================== ENDE TEMPORÄR ====
|
||||
|
||||
/// Seiten-Wizard zur Bearbeitung der Aufgaben einer Tour. Pro Aufgabe wird
|
||||
/// genau eine Seite angezeigt; mit „Zurück"/„Weiter" navigiert der Bearbeiter
|
||||
/// zwischen den Aufgaben, die letzte Seite schließt die Tour ab.
|
||||
@@ -98,7 +138,10 @@ class _TaskListPageState extends State<TaskListPage> with ProducerMixin {
|
||||
Future<List<TaskInfo>> _fetchTaskList() async {
|
||||
List<TaskInfo> taskList = [];
|
||||
|
||||
for (var task in widget.tour.tasks!) {
|
||||
// TEMP (nur zum Testen): Aufgaben von Webseite statt aus der Tour laden.
|
||||
final tasks = await _tempLoadTasksFromWeb() ?? widget.tour.tasks!;
|
||||
|
||||
for (var task in tasks) {
|
||||
final box = MyApp.objectBoxStore.box<TaskInfo>();
|
||||
final query = box.query(TaskInfo_.sId.equals(task.sId)).build();
|
||||
var taskInfo = query.findFirst();
|
||||
@@ -274,7 +317,7 @@ class _TaskListPageState extends State<TaskListPage> with ProducerMixin {
|
||||
|
||||
switch (type) {
|
||||
case 1:
|
||||
return _buildConfirmBody(draft, 'confirm_arrival'.tr);
|
||||
return _buildConfirmButtonBody(draft, 'confirm_arrival'.tr);
|
||||
case 2:
|
||||
return _buildSignatureBody(taskInfo, draft);
|
||||
case 3:
|
||||
@@ -300,7 +343,39 @@ class _TaskListPageState extends State<TaskListPage> with ProducerMixin {
|
||||
}
|
||||
}
|
||||
|
||||
/// Bestätigungs-Aufgabe (Ankunft melden = 1, Checkbox = 6).
|
||||
/// Bestätigung per Button (Ankunft melden = 1). Antippen bestätigt bzw.
|
||||
/// nimmt die Bestätigung wieder zurück; der Zustand wird über ein
|
||||
/// Häkchen-Symbol im Button angezeigt.
|
||||
Widget _buildConfirmButtonBody(_TaskDraft draft, String label) {
|
||||
final confirmed = draft.confirmed;
|
||||
return SizedBox(
|
||||
height: 52,
|
||||
child: MaterialButton(
|
||||
color: Constants.colorPrimary,
|
||||
elevation: 3,
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15))),
|
||||
onPressed: () => setState(() => draft.confirmed = !confirmed),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (confirmed) ...[
|
||||
const Icon(Icons.check_circle, color: Colors.white),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
Flexible(
|
||||
child: Text(
|
||||
label,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(fontSize: 16, color: Colors.white),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Bestätigungs-Aufgabe als Checkbox (Typ 6).
|
||||
Widget _buildConfirmBody(_TaskDraft draft, String label) {
|
||||
return CheckboxListTile(
|
||||
value: draft.confirmed,
|
||||
@@ -339,14 +414,20 @@ class _TaskListPageState extends State<TaskListPage> with ProducerMixin {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
...options.map((o) => RadioListTile<int>(
|
||||
value: o.code,
|
||||
groupValue: draft.selectedCode,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
activeColor: Constants.colorPrimary,
|
||||
title: Text(o.label),
|
||||
onChanged: (value) => setState(() => draft.selectedCode = value),
|
||||
)),
|
||||
RadioGroup<int>(
|
||||
groupValue: draft.selectedCode,
|
||||
onChanged: (value) => setState(() => draft.selectedCode = value),
|
||||
child: Column(
|
||||
children: options
|
||||
.map((o) => RadioListTile<int>(
|
||||
value: o.code,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
activeColor: Constants.colorPrimary,
|
||||
title: Text(o.label),
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
if (requiresRemark) ...[
|
||||
const SizedBox(height: 8),
|
||||
Util.getDefaultTextField(
|
||||
|
||||
Reference in new issue
Block a user