VHS-Karten integriert, Bildzoom ergänzt und Chat-IDs korrigiert

Unterschriftenerfassung dauerhaft auf Deutsch anzeigen, lokale VHS-Buildkonfiguration und Regressionstests ergänzen sowie Version auf 357.0.0+357 anheben.
This commit is contained in:
Sven committed 2026-10-07 10:41:41 +02:00
1 parent c0b667c4ee
commit 5e7babf265
26 files changed
+752 -93

No files matched your search

+40 -35
View File
@@ -114,14 +114,13 @@ class _FileListItemState extends State<_FileListItem> {
},
);
} else if (widget.file.isImage) {
// Show image in a dialog on top of the files dialog
// Bildanhänge wie PDFs vergrößern und im gezoomten Zustand verschieben.
await showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
insetPadding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
AppBar(
title: Text(widget.file.name),
@@ -131,41 +130,47 @@ class _FileListItemState extends State<_FileListItem> {
),
automaticallyImplyLeading: false,
),
Flexible(
child: Image.network(
widget.file.url,
fit: BoxFit.contain,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
),
);
},
errorBuilder: (context, error, stackTrace) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.error_outline,
size: 64,
color: Colors.red,
Expanded(
child: InteractiveViewer(
minScale: 1,
maxScale: 5,
child: SizedBox.expand(
child: Image.network(
widget.file.url,
fit: BoxFit.contain,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
),
const SizedBox(height: 16),
Text(
'Fehler beim Laden des Bildes:\n$error',
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.red),
);
},
errorBuilder: (context, error, stackTrace) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.error_outline,
size: 64,
color: Colors.red,
),
const SizedBox(height: 16),
Text(
'Fehler beim Laden des Bildes:\n$error',
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.red),
),
],
),
],
),
);
},
);
},
),
),
),
),
],
+34
View File
@@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
import 'package:stadtbote/content_views/vhs_map_page.dart';
import 'package:stadtbote/model/job.dart';
import 'package:stadtbote/model/job_tour.dart';
import 'package:stadtbote/popups/map_popup.dart';
import 'package:stadtbote/tools/app_localizations.dart';
import 'package:stadtbote/tools/util.dart';
Future<void> showJobMapPopup(
BuildContext context,
Job job, {
JobTour? currentTour,
}) async {
final mapUrl = job.mapUrl?.trim();
if (mapUrl != null && mapUrl.isNotEmpty) {
final uri = Uri.tryParse(mapUrl);
if (uri == null) {
await showAlertDialog('error'.tr, 'Die Kartenadresse ist ungültig.');
return;
}
await Navigator.of(
context,
).push<void>(MaterialPageRoute(builder: (_) => VhsMapPage(uri: uri)));
return;
}
final tours = job.tours;
final tour = currentTour ?? (tours.isNotEmpty ? tours.first : null);
if (tour?.pos == null) {
await showAlertDialog('information'.tr, 'no_position'.tr);
return;
}
await showMapPopup(context, tour!, tours);
}
+8 -3
View File
@@ -13,7 +13,7 @@ showSignaturePopup(BuildContext context, TaskInfo taskInfo, Function(String?) on
canPop: false,
onPopInvokedWithResult: (bool didPop, dynamic result) async {
if (!didPop) {
final shouldPop = await taskDialogSecurityException(context);
final shouldPop = await taskDialogSecurityException(context, language: AppLanguage.german);
if (shouldPop) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
if (context.mounted) {
@@ -79,13 +79,18 @@ showSignaturePopup(BuildContext context, TaskInfo taskInfo, Function(String?) on
),
),
getDefaultButton(
'apply'.tr,
AppLocalizations.tr('apply', language: AppLanguage.german),
buttonHeight: 50,
() => {
if (controller.points.length > 50)
{Navigator.of(context).pop(), onFinished(convertPoints(controller.points))}
else
{showAlertDialog('error'.tr, 'signature_too_short'.tr)}
{
showAlertDialog(
AppLocalizations.tr('error', language: AppLanguage.german),
AppLocalizations.tr('signature_too_short', language: AppLanguage.german),
)
}
})
],
),