Erweiterungen

This commit is contained in:
Sven committed 2026-02-25 10:40:29 +01:00
1 parent 955d7b3cb4
commit e9811da904
25 files changed
+1505 -128

No files matched your search

+4 -3
View File
@@ -9,6 +9,7 @@ import '../main.dart';
import '../model/job.dart'; import '../model/job.dart';
import '../objectbox.g.dart'; import '../objectbox.g.dart';
import '../popups/files_popup.dart'; import '../popups/files_popup.dart';
import '../tools/app_localizations.dart';
import '../tools/constants.dart'; import '../tools/constants.dart';
import '../tools/util.dart'; import '../tools/util.dart';
@@ -237,11 +238,11 @@ class _HeaderWidgetState extends State<_HeaderWidget> with ProducerMixin {
SizedBox( SizedBox(
height: 100, height: 100,
width: cellWidth * 2, width: cellWidth * 2,
child: const Center( child: Center(
child: Text( child: Text(
textAlign: TextAlign.center, textAlign: TextAlign.center,
"Angenommene Aufträge", 'accepted_jobs'.tr,
style: TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 18, fontSize: 18,
color: Colors.white), color: Colors.white),
+3 -2
View File
@@ -10,6 +10,7 @@ import 'package:stadtbote/tools/constants.dart';
import 'package:stadtbote/tools/messages/publish_payload_message.dart'; import 'package:stadtbote/tools/messages/publish_payload_message.dart';
import 'package:badges/badges.dart' as badges; import 'package:badges/badges.dart' as badges;
import '../tools/app_localizations.dart';
import '../tools/util.dart'; import '../tools/util.dart';
class ApproachAreaPage extends ContentViewWidget { class ApproachAreaPage extends ContentViewWidget {
@@ -101,8 +102,8 @@ class _ApproachAreaPageState extends State<ApproachAreaPage>
{ {
showZipPopup( showZipPopup(
context, context,
'ACHTUNG: Wenn Sie Ihre PLZ ändern, verlieren Sie Ihr Ranking!\n', 'zip_change_warning'.tr,
'Freimelden', 'release'.tr,
(zip) => {_sendZip(rank, zip)}), (zip) => {_sendZip(rank, zip)}),
} }
}, },
+14 -13
View File
@@ -18,6 +18,7 @@ import 'package:stadtbote/tools/messages/remove_state_0_job_from_map.dart';
import '../main.dart'; import '../main.dart';
import '../model/job.dart'; import '../model/job.dart';
import '../popups/files_popup.dart'; import '../popups/files_popup.dart';
import '../tools/app_localizations.dart';
import '../tools/constants.dart'; import '../tools/constants.dart';
import '../tools/util.dart'; import '../tools/util.dart';
@@ -124,9 +125,9 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> with ProducerMixin,
child: badges.Badge( child: badges.Badge(
position: badges.BadgePosition.topEnd(top: -13, end: -5), position: badges.BadgePosition.topEnd(top: -13, end: -5),
showBadge: true, showBadge: true,
badgeContent: const Text( badgeContent: Text(
'Neu', 'new'.tr,
style: TextStyle( style: const TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 18.0, fontSize: 18.0,
), ),
@@ -159,7 +160,7 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> with ProducerMixin,
), ),
], ],
), ),
Text('Auftragsnummer: ${job.externalId}'), Text('${'order_number'.tr}: ${job.externalId}'),
Text(job.tours[0].comp), Text(job.tours[0].comp),
Text(job.tours[0].street), Text(job.tours[0].street),
Text(job.tours[0].city), Text(job.tours[0].city),
@@ -173,11 +174,11 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> with ProducerMixin,
headerAlignment: ExpandablePanelHeaderAlignment.center, headerAlignment: ExpandablePanelHeaderAlignment.center,
tapBodyToCollapse: true, tapBodyToCollapse: true,
), ),
header: const Padding( header: Padding(
padding: EdgeInsets.all(0), padding: const EdgeInsets.all(0),
child: Text( child: Text(
"Weitere Infos....", 'more_info'.tr,
style: TextStyle(fontSize: 15, color: Colors.black, fontWeight: FontWeight.bold), style: const TextStyle(fontSize: 15, color: Colors.black, fontWeight: FontWeight.bold),
)), )),
collapsed: const SizedBox(), collapsed: const SizedBox(),
expanded: Column( expanded: Column(
@@ -202,7 +203,7 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> with ProducerMixin,
const SizedBox(height: 20), const SizedBox(height: 20),
Row(children: [ Row(children: [
Expanded( Expanded(
child: getDefaultButton(!job.global ? 'Ablehnen' : 'Ignorieren', () { child: getDefaultButton(!job.global ? 'decline'.tr : 'ignore'.tr, () {
sendMessage( sendMessage(
routingKey: Constants.messageTopicRemoveJob, routingKey: Constants.messageTopicRemoveJob,
payload: RemoveJobMessage(id: job.externalId), payload: RemoveJobMessage(id: job.externalId),
@@ -217,7 +218,7 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> with ProducerMixin,
), ),
const SizedBox(width: 20), const SizedBox(width: 20),
Expanded( Expanded(
child: getDefaultButton('Annehmen', () { child: getDefaultButton('accept'.tr, () {
sendMessage( sendMessage(
routingKey: Constants.messageTopicRemoveJob, routingKey: Constants.messageTopicRemoveJob,
payload: RemoveJobMessage(id: job.externalId), payload: RemoveJobMessage(id: job.externalId),
@@ -380,11 +381,11 @@ class _HeaderWidgetState extends State<_HeaderWidget> with ProducerMixin {
SizedBox( SizedBox(
height: 100, height: 100,
width: cellWidth * 2, width: cellWidth * 2,
child: const Center( child: Center(
child: Text( child: Text(
textAlign: TextAlign.center, textAlign: TextAlign.center,
"Zugewiesene Aufträge", 'assigned_jobs'.tr,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.white), style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.white),
), ),
), ),
), ),
+4 -3
View File
@@ -9,6 +9,7 @@ import 'package:stadtbote/messages/pop_content_view_message.dart';
import '../main.dart'; import '../main.dart';
import '../model/job.dart'; import '../model/job.dart';
import '../popups/files_popup.dart'; import '../popups/files_popup.dart';
import '../tools/app_localizations.dart';
import '../tools/constants.dart'; import '../tools/constants.dart';
import '../tools/util.dart'; import '../tools/util.dart';
@@ -226,11 +227,11 @@ class _HeaderWidgetState extends State<_HeaderWidget> with ProducerMixin {
SizedBox( SizedBox(
height: 100, height: 100,
width: cellWidth * 2, width: cellWidth * 2,
child: const Center( child: Center(
child: Text( child: Text(
textAlign: TextAlign.center, textAlign: TextAlign.center,
"Erledigte Aufträge", 'finished_jobs'.tr,
style: TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 18, fontSize: 18,
color: Colors.white), color: Colors.white),
+22 -21
View File
@@ -15,6 +15,7 @@ import 'package:stadtbote/model/chat_message.dart';
import 'package:stadtbote/model/session_status.dart'; import 'package:stadtbote/model/session_status.dart';
import 'package:stadtbote/network_messages/logout_message.dart'; import 'package:stadtbote/network_messages/logout_message.dart';
import 'package:stadtbote/popups/infos_popup.dart'; import 'package:stadtbote/popups/infos_popup.dart';
import 'package:stadtbote/tools/app_localizations.dart';
import 'package:stadtbote/tools/constants.dart'; import 'package:stadtbote/tools/constants.dart';
import 'package:stadtbote/tools/messages/job_received_message.dart'; import 'package:stadtbote/tools/messages/job_received_message.dart';
import 'package:stadtbote/tools/messages/publish_payload_message.dart'; import 'package:stadtbote/tools/messages/publish_payload_message.dart';
@@ -104,7 +105,7 @@ class _MainPageState extends State<MainPage> with ConsumerMixin, ProducerMixin {
elevation: 0, elevation: 0,
), ),
child: getDefaultButton( child: getDefaultButton(
'Zugewiesene Aufträge', 'assigned_jobs'.tr,
image: Image.asset('assets/zugewiesene_auftraege.png', image: Image.asset('assets/zugewiesene_auftraege.png',
width: 30, height: 30), width: 30, height: 30),
() async => { () async => {
@@ -144,7 +145,7 @@ class _MainPageState extends State<MainPage> with ConsumerMixin, ProducerMixin {
elevation: 0, elevation: 0,
), ),
child: getDefaultButton( child: getDefaultButton(
'Angenommene Aufträge', 'accepted_jobs'.tr,
image: Image.asset( image: Image.asset(
'assets/angenommene_auftraege.png', 'assets/angenommene_auftraege.png',
width: 30, width: 30,
@@ -163,7 +164,7 @@ class _MainPageState extends State<MainPage> with ConsumerMixin, ProducerMixin {
Visibility( Visibility(
visible: !_loggedOut, visible: !_loggedOut,
child: getDefaultButton( child: getDefaultButton(
'Erledigte Aufträge', 'finished_jobs'.tr,
image: Image.asset('assets/erledigte_auftraege.png', image: Image.asset('assets/erledigte_auftraege.png',
width: 30, height: 30), width: 30, height: 30),
() async => { () async => {
@@ -199,7 +200,7 @@ class _MainPageState extends State<MainPage> with ConsumerMixin, ProducerMixin {
elevation: 0, elevation: 0,
), ),
child: getDefaultButton( child: getDefaultButton(
'Nachrichten', 'messages'.tr,
image: Image.asset('assets/nachrichten.png', image: Image.asset('assets/nachrichten.png',
width: 30, height: 30), width: 30, height: 30),
() async => { () async => {
@@ -216,7 +217,7 @@ class _MainPageState extends State<MainPage> with ConsumerMixin, ProducerMixin {
Visibility( Visibility(
visible: !_loggedOut, visible: !_loggedOut,
child: getDefaultButton( child: getDefaultButton(
'Anfahrtsbereich', 'approach_area'.tr,
image: Image.asset('assets/anfahrtsbereich.png', image: Image.asset('assets/anfahrtsbereich.png',
width: 30, height: 30), width: 30, height: 30),
() async => { () async => {
@@ -230,7 +231,7 @@ class _MainPageState extends State<MainPage> with ConsumerMixin, ProducerMixin {
Visibility( Visibility(
visible: !_loggedOut && _showBWVButton, visible: !_loggedOut && _showBWVButton,
child: getDefaultButton( child: getDefaultButton(
'Wunschziel für heute', 'desired_zip'.tr,
image: Image.asset('assets/wunsch_plz.png', image: Image.asset('assets/wunsch_plz.png',
width: 30, height: 30), width: 30, height: 30),
() async => { () async => {
@@ -241,7 +242,7 @@ class _MainPageState extends State<MainPage> with ConsumerMixin, ProducerMixin {
}), }),
), ),
SizedBox(height: _loggedOut == true ? 0 : 20), SizedBox(height: _loggedOut == true ? 0 : 20),
getDefaultButton(_loggedOut ? 'Anmelden' : 'Abmelden', getDefaultButton(_loggedOut ? 'login'.tr : 'logout'.tr,
image: Image.asset( image: Image.asset(
_loggedOut _loggedOut
? 'assets/anmelden.png' ? 'assets/anmelden.png'
@@ -360,12 +361,12 @@ class _MainPageState extends State<MainPage> with ConsumerMixin, ProducerMixin {
showLogoutAlertDialog(BuildContext context) async { showLogoutAlertDialog(BuildContext context) async {
Widget yesButton = TextButton( Widget yesButton = TextButton(
child: const Text("Ja"), child: Text('yes'.tr),
onPressed: () async { onPressed: () async {
Navigator.of(context).pop(); Navigator.of(context).pop();
showMessageDialog( showMessageDialog(
context, "Information", "Sie werden abgemeldet.\nBitte warten..."); context, 'information'.tr, 'logging_out'.tr);
_sendLogoutMessage(); _sendLogoutMessage();
@@ -394,7 +395,7 @@ class _MainPageState extends State<MainPage> with ConsumerMixin, ProducerMixin {
); );
Widget noButton = TextButton( Widget noButton = TextButton(
child: const Text("Nein"), child: Text('no'.tr),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
@@ -402,8 +403,8 @@ class _MainPageState extends State<MainPage> with ConsumerMixin, ProducerMixin {
// set up the AlertDialog // set up the AlertDialog
AlertDialog alert = AlertDialog( AlertDialog alert = AlertDialog(
title: const Text("Warnung"), title: Text('warning'.tr),
content: const Text("Wollen Sie sich wirklich abmelden?"), content: Text('logout_confirm'.tr),
actions: [ actions: [
yesButton, yesButton,
noButton, noButton,
@@ -547,18 +548,18 @@ class _HeaderWidgetState extends State<_HeaderWidget> with ConsumerMixin {
children: <Widget>[ children: <Widget>[
SizedBox( SizedBox(
width: cellWidth, width: cellWidth,
child: const Text( child: Text(
'Meldung', 'message'.tr,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle(fontSize: 11, color: Colors.white), style: const TextStyle(fontSize: 11, color: Colors.white),
), ),
), ),
SizedBox( SizedBox(
width: cellWidth, width: cellWidth,
child: const Text( child: Text(
'Ortung', 'location'.tr,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle(fontSize: 11, color: Colors.white), style: const TextStyle(fontSize: 11, color: Colors.white),
), ),
), ),
], ],
@@ -602,10 +603,10 @@ class _HeaderWidgetState extends State<_HeaderWidget> with ConsumerMixin {
), ),
Column( Column(
children: [ children: [
const Text( Text(
'Kurierkennung', 'courier_id'.tr,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle(fontSize: 11, color: Colors.white), style: const TextStyle(fontSize: 11, color: Colors.white),
), ),
ValueListenableBuilder<String>( ValueListenableBuilder<String>(
valueListenable: _sidValueNotifier, valueListenable: _sidValueNotifier,
+5 -4
View File
@@ -12,6 +12,7 @@ import 'package:stadtbote/network_messages/messages_showed.dart';
import 'package:stadtbote/tools/constants.dart'; import 'package:stadtbote/tools/constants.dart';
import 'package:stadtbote/tools/messages/publish_payload_message.dart'; import 'package:stadtbote/tools/messages/publish_payload_message.dart';
import '../tools/app_localizations.dart';
import '../tools/util.dart'; import '../tools/util.dart';
class MessagesPage extends ContentViewWidget { class MessagesPage extends ContentViewWidget {
@@ -51,7 +52,7 @@ class _MessagesPageState extends State<MessagesPage> with ProducerMixin {
final box = MyApp.objectBoxStore.box<SessionStatus>(); final box = MyApp.objectBoxStore.box<SessionStatus>();
final sessions = box.getAll(); final sessions = box.getAll();
var status = sessions.isNotEmpty ? sessions.first : null; var status = sessions.isNotEmpty ? sessions.first : null;
_sid = status != null ? status.sid : 'Unbekannt'; _sid = status != null ? status.sid : 'unknown'.tr;
_sendMessagesReadMessage(); _sendMessagesReadMessage();
@@ -165,17 +166,17 @@ class _MessagesPageState extends State<MessagesPage> with ProducerMixin {
padding: const EdgeInsets.all(5), padding: const EdgeInsets.all(5),
child: Column( child: Column(
children: [ children: [
const Text('Soll die Nachricht gelöscht werden?'), Text('delete_message_confirm'.tr),
const SizedBox(height: 20), const SizedBox(height: 20),
Row(children: [ Row(children: [
Expanded( Expanded(
child: getDefaultButton('Nein', child: getDefaultButton('no'.tr,
() => {Navigator.of(context).pop()}), () => {Navigator.of(context).pop()}),
), ),
const SizedBox(width: 20), const SizedBox(width: 20),
Expanded( Expanded(
child: getDefaultButton( child: getDefaultButton(
'Ja', 'yes'.tr,
() async => { () async => {
MyApp.objectBoxStore.box<sbmessage.ChatMessage>() MyApp.objectBoxStore.box<sbmessage.ChatMessage>()
.remove(int.parse(message.id)), .remove(int.parse(message.id)),
+5 -4
View File
@@ -6,6 +6,7 @@ import 'package:stadtbote/messages/pop_content_view_message.dart';
import 'package:stadtbote/network_messages/set_desired_zip_message.dart'; import 'package:stadtbote/network_messages/set_desired_zip_message.dart';
import 'package:stadtbote/tools/messages/publish_payload_message.dart'; import 'package:stadtbote/tools/messages/publish_payload_message.dart';
import '../tools/app_localizations.dart';
import '../tools/constants.dart'; import '../tools/constants.dart';
import '../tools/util.dart'; import '../tools/util.dart';
@@ -43,7 +44,7 @@ class _SetDesiredZipPageState extends State<SetDesiredZipPage>
return Padding( return Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Column(children: [ child: Column(children: [
const Text("Bitte geben Sie Ihr Wunschziel für heute ein"), Text('enter_desired_zip'.tr),
const SizedBox(height: 20), const SizedBox(height: 20),
Row( Row(
mainAxisAlignment: mainAxisAlignment:
@@ -67,7 +68,7 @@ class _SetDesiredZipPageState extends State<SetDesiredZipPage>
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
getDefaultButton( getDefaultButton(
'Übernehmen', 'apply'.tr,
() => { () => {
if (textEditController.text.isEmpty || if (textEditController.text.isEmpty ||
textEditController.text.length == 5) textEditController.text.length == 5)
@@ -82,8 +83,8 @@ class _SetDesiredZipPageState extends State<SetDesiredZipPage>
} }
else else
{ {
showAlertDialog("Fehler", showAlertDialog('error'.tr,
"Das Feld muss leer sein, oder es müssen fünf Zahlen eingegeben werden") 'zip_validation_error'.tr)
} }
}) })
]), ]),
+5 -4
View File
@@ -26,6 +26,7 @@ import 'package:stadtbote/tools/messages/publish_payload_message.dart';
import '../main.dart'; import '../main.dart';
import '../model/task_info.dart'; import '../model/task_info.dart';
import '../tools/app_localizations.dart';
import '../tools/util.dart'; import '../tools/util.dart';
class TaskListPage extends ContentViewWidget { class TaskListPage extends ContentViewWidget {
@@ -93,7 +94,7 @@ class _TaskListPageState extends State<TaskListPage> with ProducerMixin {
visible: _commisionNumber.isNotEmpty, visible: _commisionNumber.isNotEmpty,
child: Row( child: Row(
children: [ children: [
Text('Komm-#: $_commisionNumber', style: const TextStyle(fontSize: 20), textAlign: TextAlign.left), Text('${'commission_number_short'.tr}: $_commisionNumber', style: const TextStyle(fontSize: 20), textAlign: TextAlign.left),
], ],
), ),
), ),
@@ -314,7 +315,7 @@ class _TaskListPageState extends State<TaskListPage> with ProducerMixin {
} }
taskInfo.answer = jsonEncode(answer.toJson()); taskInfo.answer = jsonEncode(answer.toJson());
taskInfo.additionalText = "Barcodes gescannt"; taskInfo.additionalText = 'barcodes_scanned'.tr;
taskInfo.completed = true; taskInfo.completed = true;
setState(() {}); setState(() {});
@@ -349,7 +350,7 @@ class _TaskListPageState extends State<TaskListPage> with ProducerMixin {
box.put(picture); box.put(picture);
} }
taskInfo.additionalText = "Fotos aufgenommen"; taskInfo.additionalText = 'photos_taken'.tr;
taskInfo.completed = true; taskInfo.completed = true;
if (mounted) { if (mounted) {
@@ -446,7 +447,7 @@ class _TaskListPageState extends State<TaskListPage> with ProducerMixin {
answer.sign = signature; answer.sign = signature;
taskInfo.answer = jsonEncode(answer.toJson()); taskInfo.answer = jsonEncode(answer.toJson());
taskInfo.additionalText = "Unterschrift erfasst"; taskInfo.additionalText = 'signature_captured'.tr;
taskInfo.completed = true; taskInfo.completed = true;
_sendFinTourMessage(); _sendFinTourMessage();
+12 -11
View File
@@ -8,6 +8,7 @@ import 'package:stadtbote/model/job_tour.dart';
import '../model/job.dart'; import '../model/job.dart';
import '../popups/files_popup.dart'; import '../popups/files_popup.dart';
import '../popups/map_popup.dart'; import '../popups/map_popup.dart';
import '../tools/app_localizations.dart';
import '../tools/constants.dart'; import '../tools/constants.dart';
import '../tools/util.dart'; import '../tools/util.dart';
@@ -59,7 +60,7 @@ class _TourDetailsPageState extends State<TourDetailsPage> with ProducerMixin {
if (widget.tour.rem.isNotEmpty) { if (widget.tour.rem.isNotEmpty) {
remark += '${widget.tour.rem}\n'; remark += '${widget.tour.rem}\n';
} else { } else {
remark = "* Keine Bemerkung vorhanden *"; remark = 'no_remark'.tr;
} }
return Padding( return Padding(
@@ -77,7 +78,7 @@ class _TourDetailsPageState extends State<TourDetailsPage> with ProducerMixin {
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
Text( Text(
"${"Station ${widget.tour.sort}"} ${mapTourMode(widget.tour.mode)}", "${'station'.tr} ${widget.tour.sort} ${mapTourMode(widget.tour.mode)}",
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
Text( Text(
@@ -97,11 +98,11 @@ class _TourDetailsPageState extends State<TourDetailsPage> with ProducerMixin {
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
Text( Text(
"Tel.: ${widget.tour.phone}", "${'phone'.tr} ${widget.tour.phone}",
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
Text( Text(
"Komm-#: ${widget.tour.com}", "${'commission_number'.tr}: ${widget.tour.com}",
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
if (widget.tour.files != null && widget.tour.files!.isNotEmpty) ...[ if (widget.tour.files != null && widget.tour.files!.isNotEmpty) ...[
@@ -110,9 +111,9 @@ class _TourDetailsPageState extends State<TourDetailsPage> with ProducerMixin {
children: [ children: [
FilesBadge(files: widget.tour.files), FilesBadge(files: widget.tour.files),
const SizedBox(width: 8), const SizedBox(width: 8),
const Text( Text(
'Dateien verfügbar', 'files_available'.tr,
style: TextStyle( style: const TextStyle(
fontSize: 12, fontSize: 12,
color: Colors.grey, color: Colors.grey,
), ),
@@ -122,7 +123,7 @@ class _TourDetailsPageState extends State<TourDetailsPage> with ProducerMixin {
], ],
const SizedBox(height: 10), const SizedBox(height: 10),
getDefaultButton( getDefaultButton(
'Karte', 'map'.tr,
() => { () => {
if (widget.tour.pos != null) if (widget.tour.pos != null)
{ {
@@ -131,8 +132,8 @@ class _TourDetailsPageState extends State<TourDetailsPage> with ProducerMixin {
} }
else else
{ {
showAlertDialog('Information', showAlertDialog('information'.tr,
'Es liegt keine Position für diese Station vor') 'no_position'.tr)
} }
}), }),
], ],
@@ -158,7 +159,7 @@ class _TourDetailsPageState extends State<TourDetailsPage> with ProducerMixin {
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
getDefaultButton( getDefaultButton(
'Weiter', 'next'.tr,
() async => { () async => {
sendMessage( sendMessage(
routingKey: Constants.messageTopicPushContentView, routingKey: Constants.messageTopicPushContentView,
+3 -2
View File
@@ -8,6 +8,7 @@ import 'package:stadtbote/popups/map_popup.dart';
import '../model/job.dart'; import '../model/job.dart';
import '../popups/files_popup.dart'; import '../popups/files_popup.dart';
import '../tools/app_localizations.dart';
import '../tools/constants.dart'; import '../tools/constants.dart';
import '../tools/util.dart'; import '../tools/util.dart';
@@ -102,7 +103,7 @@ class _TourListPageState extends State<TourListPage> with ProducerMixin {
foregroundColor: WidgetStateProperty.all<Color>(Colors.black), foregroundColor: WidgetStateProperty.all<Color>(Colors.black),
), ),
onPressed: () => {showMapPopup(context, widget.job.tours[0], widget.job.tours)}, onPressed: () => {showMapPopup(context, widget.job.tours[0], widget.job.tours)},
child: const Text("Karte")), child: Text('map'.tr)),
)) ))
], ],
), ),
@@ -157,7 +158,7 @@ class _TourListPageState extends State<TourListPage> with ProducerMixin {
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
"${"Station ${tour.sort}"} ${mapTourMode(tour.mode)}", "${'station'.tr} ${tour.sort} ${mapTourMode(tour.mode)}",
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
), ),
+4
View File
@@ -24,6 +24,7 @@ import 'content_views/utils/content_view_widget.dart';
import 'content_views/utils/widget_stack.dart'; import 'content_views/utils/widget_stack.dart';
import 'model/job.dart'; import 'model/job.dart';
import 'objectbox.g.dart'; import 'objectbox.g.dart';
import 'tools/app_localizations.dart';
import 'tools/constants.dart'; import 'tools/constants.dart';
import 'tools/util.dart'; import 'tools/util.dart';
@@ -32,6 +33,9 @@ Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
await Util.init(); await Util.init();
// Lade die gespeicherte Sprache
AppLocalizations().loadSavedLanguage();
MQClient.initialize(); MQClient.initialize();
MQClient.instance.declareQueue(Constants.messageTopicRemoveJob); MQClient.instance.declareQueue(Constants.messageTopicRemoveJob);
+5 -4
View File
@@ -16,6 +16,7 @@ import 'package:stadtbote/tools/messages/remove_job_message.dart';
import 'package:stadtbote/tools/mqtt_core.dart'; import 'package:stadtbote/tools/mqtt_core.dart';
import 'package:stadtbote/tools/util.dart'; import 'package:stadtbote/tools/util.dart';
import '../tools/app_localizations.dart';
import '../tools/messages/publish_payload_message.dart'; import '../tools/messages/publish_payload_message.dart';
final ScrollController _scrollController = ScrollController(); final ScrollController _scrollController = ScrollController();
@@ -109,7 +110,7 @@ Future<void> showAcceptJobsPopup(SharedMapReference mapReference, Function() onF
), ),
), ),
), ),
getDefaultButton("Liste schliessen", () { getDefaultButton('close_list'.tr, () {
isActive = false; isActive = false;
if (builderCreated) { if (builderCreated) {
extendedStatefulBuilder.unsubscribe(queueId: Constants.messageTopicJobReceived); extendedStatefulBuilder.unsubscribe(queueId: Constants.messageTopicJobReceived);
@@ -191,7 +192,7 @@ Future<List<Widget>> _fetchJobWidgets(StateSetter dialogState, Function() onFini
style: TextStyle(backgroundColor: isJobTooFarInFuture(job) ? Colors.red : Colors.transparent), style: TextStyle(backgroundColor: isJobTooFarInFuture(job) ? Colors.red : Colors.transparent),
), ),
), ),
SizedBox(width: double.infinity, child: Text('Auftragsnummer: ${job.id}', textAlign: TextAlign.left)), SizedBox(width: double.infinity, child: Text('${'order_number'.tr}: ${job.id}', textAlign: TextAlign.left)),
SizedBox(width: double.infinity, child: Text(job.tours[0].comp, textAlign: TextAlign.left)), SizedBox(width: double.infinity, child: Text(job.tours[0].comp, textAlign: TextAlign.left)),
SizedBox(width: double.infinity, child: Text(job.tours[0].street, textAlign: TextAlign.left)), SizedBox(width: double.infinity, child: Text(job.tours[0].street, textAlign: TextAlign.left)),
SizedBox(width: double.infinity, child: Text(job.tours[0].city, textAlign: TextAlign.left)), SizedBox(width: double.infinity, child: Text(job.tours[0].city, textAlign: TextAlign.left)),
@@ -212,7 +213,7 @@ Future<List<Widget>> _fetchJobWidgets(StateSetter dialogState, Function() onFini
const SizedBox(height: 10), const SizedBox(height: 10),
Row(children: [ Row(children: [
Expanded( Expanded(
child: getDefaultButton(!job.global ? 'Ablehnen' : 'Ignorieren', () { child: getDefaultButton(!job.global ? 'decline'.tr : 'ignore'.tr, () {
dialogState(() { dialogState(() {
_sendAnswer(mapReference, job, !job.global ? 2 : 3); _sendAnswer(mapReference, job, !job.global ? 2 : 3);
@@ -229,7 +230,7 @@ Future<List<Widget>> _fetchJobWidgets(StateSetter dialogState, Function() onFini
), ),
const SizedBox(width: 20), const SizedBox(width: 20),
Expanded( Expanded(
child: getDefaultButton('Annehmen', enabledTimerActive: false, () { child: getDefaultButton('accept'.tr, enabledTimerActive: false, () {
dialogState(() { dialogState(() {
_sendAnswer(mapReference, job, 1); _sendAnswer(mapReference, job, 1);
+62 -15
View File
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stadtbote/main.dart'; import 'package:stadtbote/main.dart';
import 'package:stadtbote/model/session_status.dart'; import 'package:stadtbote/model/session_status.dart';
import 'package:stadtbote/tools/app_localizations.dart';
import 'package:stadtbote/tools/mqtt_core.dart'; import 'package:stadtbote/tools/mqtt_core.dart';
import 'package:stadtbote/tools/util.dart'; import 'package:stadtbote/tools/util.dart';
@@ -10,7 +11,9 @@ void showInfosPopup(SessionStatus? status) async {
await showDialog( await showDialog(
context: MyApp.appNavigatorKey.currentContext!, context: MyApp.appNavigatorKey.currentContext!,
builder: (BuildContext context) { builder: (BuildContext context) {
late String connectedString = MqttCore.instance.getConnectionStatus() == ConnectionStateEnum.connected ? "Verbunden" : "NICHT verbunden"; late String connectedString = MqttCore.instance.getConnectionStatus() == ConnectionStateEnum.connected
? 'connected'.tr
: 'not_connected'.tr;
return AlertDialog( return AlertDialog(
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
@@ -18,31 +21,42 @@ void showInfosPopup(SessionStatus? status) async {
backgroundColor: Colors.white, backgroundColor: Colors.white,
content: StatefulBuilder(builder: (BuildContext context, StateSetter setState) { content: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
Future<String> getGpsStatustext() async { Future<String> getGpsStatustext() async {
String gpsStatus = "nicht verfügbar"; String gpsStatus = 'gps_not_available'.tr;
var currentPosition = await MyApp.getCurrentPosition(); var currentPosition = await MyApp.getCurrentPosition();
if (currentPosition != null) { if (currentPosition != null) {
var nowUtc = DateTime.now().toUtc(); var nowUtc = DateTime.now().toUtc();
var minutesDelta = nowUtc.difference(currentPosition.timestamp); var minutesDelta = nowUtc.difference(currentPosition.timestamp);
if (minutesDelta >= const Duration(minutes: 15)) { if (minutesDelta >= const Duration(minutes: 15)) {
gpsStatus = "veraltet"; gpsStatus = 'gps_outdated'.tr;
} else { } else {
gpsStatus = "aktuell"; gpsStatus = 'gps_available'.tr;
} }
} }
return gpsStatus; return gpsStatus;
} }
void onLanguageChanged(AppLanguage? newLanguage) {
if (newLanguage != null) {
AppLocalizations().setLanguage(newLanguage);
setState(() {});
// Sende Nachricht an MainPage, um UI zu aktualisieren
// Wir verwenden einen einfachen Ansatz: Die App wird neu geladen
// In einer echten App würde man hier einen State-Management-Mechanismus verwenden
}
}
return FutureBuilder<String>( return FutureBuilder<String>(
future: getGpsStatustext(), future: getGpsStatustext(),
builder: (context, snapshot) { builder: (context, snapshot) {
String gpsStatus = snapshot.data ?? "wird geladen..."; String gpsStatus = snapshot.data ?? 'loading'.tr;
var text = "Versionsnummer: a$version\n"; var text = "${'version'.tr}: a$version\n";
text += "Verbindungsstatus: $connectedString\n"; text += "${'connection_status'.tr}: $connectedString\n";
text += "GPS-Status: $gpsStatus\n"; text += "${'gps_status'.tr}: $gpsStatus\n";
text += "\n"; text += "\n";
text += "User Status:\n"; text += "${'user_status'.tr}:\n";
if (status != null) { if (status != null) {
text += "cr_id: ${status.crId}\n"; text += "cr_id: ${status.crId}\n";
text += "cust_id: ${status.custId}\n"; text += "cust_id: ${status.custId}\n";
@@ -51,12 +65,12 @@ void showInfosPopup(SessionStatus? status) async {
text += "server_version: ${status.serverVersion}\n"; text += "server_version: ${status.serverVersion}\n";
text += "server_instance: ${status.serverInstance}\n"; text += "server_instance: ${status.serverInstance}\n";
} else { } else {
text += "Keine Informationen gefunden"; text += 'no_info_found'.tr;
} }
return SizedBox( return SizedBox(
key: GlobalKey(), key: GlobalKey(),
height: 350, height: 450,
width: MediaQuery.of(context).size.width * 0.8, width: MediaQuery.of(context).size.width * 0.8,
child: Container( child: Container(
height: 100, height: 100,
@@ -72,9 +86,44 @@ void showInfosPopup(SessionStatus? status) async {
padding: const EdgeInsets.all(12.0), padding: const EdgeInsets.all(12.0),
child: Column( child: Column(
children: [ children: [
Expanded(child: Text(text, textAlign: TextAlign.left)), Expanded(child: SingleChildScrollView(child: Text(text, textAlign: TextAlign.left))),
const Divider(),
// Sprachauswahl
Row(
children: [
Text('${'language'.tr}: ', style: const TextStyle(fontWeight: FontWeight.bold)),
Expanded(
child: DropdownButtonHideUnderline(
child: DropdownButton<AppLanguage>(
isExpanded: true,
value: AppLocalizations().currentLanguage,
items: AppLanguage.values.map((AppLanguage language) {
return DropdownMenuItem<AppLanguage>(
value: language,
child: Row(
children: [
Text(language.flag, style: const TextStyle(fontSize: 20)),
const SizedBox(width: 8),
Flexible(
child: Text(
language.name,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 14),
),
),
],
),
);
}).toList(),
onChanged: onLanguageChanged,
),
),
),
],
),
const SizedBox(height: 12),
getDefaultButton( getDefaultButton(
'OK', 'ok'.tr,
() { () {
Navigator.pop(context); Navigator.pop(context);
}, },
@@ -88,5 +137,3 @@ void showInfosPopup(SessionStatus? status) async {
})); }));
}); });
} }
+4 -3
View File
@@ -4,6 +4,7 @@ import 'package:animated_toggle_switch/animated_toggle_switch.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart'; import 'package:latlong2/latlong.dart';
import 'package:stadtbote/tools/app_localizations.dart';
import 'package:stadtbote/tools/util.dart'; import 'package:stadtbote/tools/util.dart';
import '../model/job_tour.dart'; import '../model/job_tour.dart';
@@ -41,7 +42,7 @@ showMapPopup(BuildContext context, JobTour currentTour, List<JobTour> tourList)
currentTour = tour; currentTour = tour;
streamControllers[tour.sort]!.sink.add(true); streamControllers[tour.sort]!.sink.add(true);
} else { } else {
showAlertDialog('Information', 'Es liegt keine Position für diese Station vor'); showAlertDialog('information'.tr, 'no_position'.tr);
} }
}, },
child: SizedBox( child: SizedBox(
@@ -64,7 +65,7 @@ showMapPopup(BuildContext context, JobTour currentTour, List<JobTour> tourList)
height: 12.0, height: 12.0,
width: 70, width: 70,
child: Text( child: Text(
"Station ${tour.sort}", "${'station'.tr} ${tour.sort}",
softWrap: true, softWrap: true,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: const TextStyle( style: const TextStyle(
@@ -164,7 +165,7 @@ showMapPopup(BuildContext context, JobTour currentTour, List<JobTour> tourList)
mapController!.move(mapController!.camera.center, b ? 14.0 : 16.0); mapController!.move(mapController!.camera.center, b ? 14.0 : 16.0);
}, },
styleBuilder: (i) => ToggleStyle(indicatorColor: i == true ? _colors[0] : _colors[1]), styleBuilder: (i) => ToggleStyle(indicatorColor: i == true ? _colors[0] : _colors[1]),
textBuilder: (value) => value ? const Center(child: Text('Fern')) : const Center(child: Text('Nah')), textBuilder: (value) => value ? Center(child: Text('far'.tr)) : Center(child: Text('near'.tr)),
); );
}, },
), ),
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:stadtbote/model/task_info.dart'; import 'package:stadtbote/model/task_info.dart';
import 'package:stadtbote/tools/app_localizations.dart';
import 'package:stadtbote/tools/util.dart'; import 'package:stadtbote/tools/util.dart';
showComissionNumberPopup(BuildContext context, TaskInfo taskInfo, Function(String) onFinished) async { showComissionNumberPopup(BuildContext context, TaskInfo taskInfo, Function(String) onFinished) async {
@@ -42,15 +43,15 @@ showComissionNumberPopup(BuildContext context, TaskInfo taskInfo, Function(Strin
padding: const EdgeInsets.all(35.0), padding: const EdgeInsets.all(35.0),
child: Column( child: Column(
children: [ children: [
const Text('Bitte geben Sie die Kommisionsnummer ein'), Text('enter_commission_number'.tr),
const SizedBox(height: 20), const SizedBox(height: 20),
Util.getDefaultTextField('Kommisionsnummer', Util.getDefaultTextField('commission_number_hint'.tr,
textInputType: TextInputType.text, textInputType: TextInputType.text,
formatter: [FilteringTextInputFormatter.singleLineFormatter], formatter: [FilteringTextInputFormatter.singleLineFormatter],
controller: textEditingController, controller: textEditingController,
autofocus: true), autofocus: true),
const SizedBox(height: 20), const SizedBox(height: 20),
getDefaultButton('Übernehmen', () { getDefaultButton('apply'.tr, () {
final result = textEditingController.text; final result = textEditingController.text;
textEditingController.dispose(); textEditingController.dispose();
Navigator.of(context).pop(); Navigator.of(context).pop();
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stadtbote/model/task_info.dart'; import 'package:stadtbote/model/task_info.dart';
import 'package:stadtbote/model/tour_task.dart'; import 'package:stadtbote/model/tour_task.dart';
import 'package:stadtbote/tools/app_localizations.dart';
import 'package:stadtbote/tools/util.dart'; import 'package:stadtbote/tools/util.dart';
showPickupDeliveryStatusPopup(BuildContext context, TaskInfo taskInfo, Function(TourEntry?, String? remark) onFinished) async { showPickupDeliveryStatusPopup(BuildContext context, TaskInfo taskInfo, Function(TourEntry?, String? remark) onFinished) async {
@@ -58,7 +59,7 @@ showPickupDeliveryStatusPopup(BuildContext context, TaskInfo taskInfo, Function(
DropdownMenu<TourEntry>( DropdownMenu<TourEntry>(
expandedInsets: const EdgeInsets.all(0), expandedInsets: const EdgeInsets.all(0),
controller: controller, controller: controller,
hintText: 'Status', hintText: 'status'.tr,
onSelected: (TourEntry? value) { onSelected: (TourEntry? value) {
selectedTourEntry = value; selectedTourEntry = value;
@@ -68,9 +69,9 @@ showPickupDeliveryStatusPopup(BuildContext context, TaskInfo taskInfo, Function(
dropdownMenuEntries: entries, dropdownMenuEntries: entries,
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
Visibility(visible: selectedTourEntry != null ? selectedTourEntry!.queryRemark : false, child: Util.getDefaultTextField(controller: remController, "Bemerkung")), Visibility(visible: selectedTourEntry != null ? selectedTourEntry!.queryRemark : false, child: Util.getDefaultTextField(controller: remController, 'remark'.tr)),
const SizedBox(height: 20), const SizedBox(height: 20),
getDefaultButton('Übernehmen', buttonHeight: 50, () => { getDefaultButton('apply'.tr, buttonHeight: 50, () => {
if (selectedTourEntry!.queryRemark) { if (selectedTourEntry!.queryRemark) {
if (remController.text.isNotEmpty) { if (remController.text.isNotEmpty) {
Navigator.of(context).pop(), Navigator.of(context).pop(),
@@ -80,7 +81,7 @@ showPickupDeliveryStatusPopup(BuildContext context, TaskInfo taskInfo, Function(
onFinished(selectedTourEntry, remController.text) onFinished(selectedTourEntry, remController.text)
} else { } else {
showAlertDialog("Fehler", "Bitte geben Sie eine Bemerkung ein") showAlertDialog('error'.tr, 'enter_remark'.tr)
} }
} else { } else {
Navigator.of(context).pop(), Navigator.of(context).pop(),
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:stadtbote/model/task_info.dart'; import 'package:stadtbote/model/task_info.dart';
import 'package:stadtbote/model/tour_task.dart'; import 'package:stadtbote/model/tour_task.dart';
import 'package:stadtbote/tools/app_localizations.dart';
import 'package:stadtbote/tools/util.dart'; import 'package:stadtbote/tools/util.dart';
showReceiptGiverPopup(BuildContext context, TaskInfo taskInfo, Function(String, TourEntry) onFinished) async { showReceiptGiverPopup(BuildContext context, TaskInfo taskInfo, Function(String, TourEntry) onFinished) async {
@@ -57,7 +58,7 @@ showReceiptGiverPopup(BuildContext context, TaskInfo taskInfo, Function(String,
DropdownMenu<TourEntry>( DropdownMenu<TourEntry>(
expandedInsets: const EdgeInsets.all(0), expandedInsets: const EdgeInsets.all(0),
controller: controller, controller: controller,
hintText: 'Geschlecht', hintText: 'gender'.tr,
onSelected: (TourEntry? value) { onSelected: (TourEntry? value) {
selectedTourEntry = value; selectedTourEntry = value;
@@ -73,7 +74,7 @@ showReceiptGiverPopup(BuildContext context, TaskInfo taskInfo, Function(String,
maxLength: 40, maxLength: 40,
autofocus: true), autofocus: true),
const SizedBox(height: 20), const SizedBox(height: 20),
getDefaultButton('Übernehmen', () { getDefaultButton('apply'.tr, () {
if (textEditingController.text.isNotEmpty && selectedTourEntry != null) { if (textEditingController.text.isNotEmpty && selectedTourEntry != null) {
Navigator.of(context).pop(); Navigator.of(context).pop();
@@ -83,7 +84,7 @@ showReceiptGiverPopup(BuildContext context, TaskInfo taskInfo, Function(String,
onFinished(result, selectedTourEntry!); onFinished(result, selectedTourEntry!);
} else { } else {
showAlertDialog("Fehler", "Sie müssen einen Text eingeben und ein Geschlecht auswählen"); showAlertDialog('error'.tr, 'enter_text_and_gender'.tr);
} }
}) })
], ],
+3 -2
View File
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:signature/signature.dart'; import 'package:signature/signature.dart';
import 'package:stadtbote/model/task_info.dart'; import 'package:stadtbote/model/task_info.dart';
import 'package:stadtbote/tools/app_localizations.dart';
import 'package:stadtbote/tools/util.dart'; import 'package:stadtbote/tools/util.dart';
showSignaturePopup(BuildContext context, TaskInfo taskInfo, Function(String?) onFinished) async { showSignaturePopup(BuildContext context, TaskInfo taskInfo, Function(String?) onFinished) async {
@@ -78,13 +79,13 @@ showSignaturePopup(BuildContext context, TaskInfo taskInfo, Function(String?) on
), ),
), ),
getDefaultButton( getDefaultButton(
'Übernehmen', 'apply'.tr,
buttonHeight: 50, buttonHeight: 50,
() => { () => {
if (controller.points.length > 50) if (controller.points.length > 50)
{Navigator.of(context).pop(), onFinished(convertPoints(controller.points))} {Navigator.of(context).pop(), onFinished(convertPoints(controller.points))}
else else
{showAlertDialog("Fehler", "Die Unterschrift ist zu kurz.")} {showAlertDialog('error'.tr, 'signature_too_short'.tr)}
}) })
], ],
), ),
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:stadtbote/model/task_info.dart'; import 'package:stadtbote/model/task_info.dart';
import 'package:stadtbote/tools/app_localizations.dart';
import 'package:stadtbote/tools/util.dart'; import 'package:stadtbote/tools/util.dart';
showStationNoticePopup(BuildContext context, TaskInfo taskInfo, Function(String) onFinished) async { showStationNoticePopup(BuildContext context, TaskInfo taskInfo, Function(String) onFinished) async {
@@ -54,7 +55,7 @@ showStationNoticePopup(BuildContext context, TaskInfo taskInfo, Function(String)
autofocus: true), autofocus: true),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
getDefaultButton('Übernehmen', buttonHeight: 50, () { getDefaultButton('apply'.tr, buttonHeight: 50, () {
final result = textEditingController.text; final result = textEditingController.text;
textEditingController.dispose(); textEditingController.dispose();
Navigator.of(context).pop(); Navigator.of(context).pop();
@@ -3,6 +3,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:image/image.dart' as image_lib; import 'package:image/image.dart' as image_lib;
import 'package:stadtbote/model/task_info.dart'; import 'package:stadtbote/model/task_info.dart';
import 'package:stadtbote/tools/app_localizations.dart';
import 'package:stadtbote/tools/util.dart'; import 'package:stadtbote/tools/util.dart';
Future<void> showTakePhotosPopup(BuildContext context, TaskInfo taskInfo, Function(List<Uint8List>) onFinished) async { Future<void> showTakePhotosPopup(BuildContext context, TaskInfo taskInfo, Function(List<Uint8List>) onFinished) async {
@@ -53,7 +54,7 @@ Future<void> showTakePhotosPopup(BuildContext context, TaskInfo taskInfo, Functi
onTap: () {}, onTap: () {},
child: GestureDetector( child: GestureDetector(
onTap: () async { onTap: () async {
await showQuestionDialog(context, "Achtung", "Wollen Sie das Bild wirklich löschen?", [ await showQuestionDialog(context, 'attention'.tr, 'delete_photo_confirm'.tr, [
TextButton(onPressed: () => {Navigator.of(context).pop(), TextButton(onPressed: () => {Navigator.of(context).pop(),
imageDataList.removeAt(currentCarousselSliderIndex), imageDataList.removeAt(currentCarousselSliderIndex),
imageWidgetsList.removeAt(currentCarousselSliderIndex), imageWidgetsList.removeAt(currentCarousselSliderIndex),
@@ -63,8 +64,8 @@ Future<void> showTakePhotosPopup(BuildContext context, TaskInfo taskInfo, Functi
currentCarousselSliderIndex = 0, currentCarousselSliderIndex = 0,
setState(() {}) setState(() {})
}, child: const Text('Ja')), }, child: Text('yes'.tr)),
TextButton(onPressed: () => {Navigator.of(context).pop()}, child: const Text('Nein')), TextButton(onPressed: () => {Navigator.of(context).pop()}, child: Text('no'.tr)),
]); ]);
}, },
child: Image.memory(resizedImageData), child: Image.memory(resizedImageData),
@@ -99,7 +100,7 @@ Future<void> showTakePhotosPopup(BuildContext context, TaskInfo taskInfo, Functi
padding: const EdgeInsets.all(35.0), padding: const EdgeInsets.all(35.0),
child: Column( child: Column(
children: [ children: [
const Text('Aufgenommene Fotos'), Text('photos'.tr),
const SizedBox(height: 20), const SizedBox(height: 20),
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -129,16 +130,16 @@ Future<void> showTakePhotosPopup(BuildContext context, TaskInfo taskInfo, Functi
const SizedBox(height: 20), const SizedBox(height: 20),
Visibility( Visibility(
visible: imageDataList.length < (taskInfo.task?.max ?? 999), visible: imageDataList.length < (taskInfo.task?.max ?? 999),
child: getDefaultButton('Hinzufügen', buttonHeight: 50, () => {capturePhoto()})), child: getDefaultButton('add'.tr, buttonHeight: 50, () => {capturePhoto()})),
const SizedBox(height: 12), const SizedBox(height: 12),
getDefaultButton( getDefaultButton(
'Übernehmen', 'apply'.tr,
buttonHeight: 50, buttonHeight: 50,
() => { () => {
if (imageDataList.length >= (taskInfo.task?.min ?? 0) && imageDataList.length <= (taskInfo.task?.max ?? 999)) if (imageDataList.length >= (taskInfo.task?.min ?? 0) && imageDataList.length <= (taskInfo.task?.max ?? 999))
{Navigator.of(context).pop(), onFinished(imageDataList)} {Navigator.of(context).pop(), onFinished(imageDataList)}
else else
{showAlertDialog('Fehler', 'Es müssen mindestens ${taskInfo.task?.min ?? 0} Foto(s) aufgenommen werden')} {showAlertDialog('error'.tr, 'min_photos_error'.trParams({'min': taskInfo.task?.min ?? 0}))}
}) })
], ],
), ),
+4 -3
View File
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:stadtbote/tools/app_localizations.dart';
import 'package:stadtbote/tools/util.dart'; import 'package:stadtbote/tools/util.dart';
showZipPopup(BuildContext context, String text, String buttonText, showZipPopup(BuildContext context, String text, String buttonText,
@@ -55,7 +56,7 @@ showZipPopup(BuildContext context, String text, String buttonText,
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold)), fontWeight: FontWeight.bold)),
const SizedBox(height: 20), const SizedBox(height: 20),
Util.getDefaultTextField('Postleitzahl', Util.getDefaultTextField('zip'.tr,
formatter: [ formatter: [
FilteringTextInputFormatter.digitsOnly, FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(5), LengthLimitingTextInputFormatter(5),
@@ -89,11 +90,11 @@ bool _checkInput(BuildContext context, String input) {
String message = ''; String message = '';
if (input.length != 5) { if (input.length != 5) {
message += 'Bitte geben Sie eine fünfstellige Postleitzahl ein'; message += 'enter_zip'.tr;
} }
if (message.isNotEmpty) { if (message.isNotEmpty) {
showAlertDialog('Fehler', message); showAlertDialog('error'.tr, message);
} }
return message.isEmpty; return message.isEmpty;
File diff suppressed because it is too large. Load diff
+1
View File
@@ -31,6 +31,7 @@ class Constants {
static const String prefsPreviousMqttSubscription = "previous_mqtt_subscription"; static const String prefsPreviousMqttSubscription = "previous_mqtt_subscription";
static const String prefsBWVEnabled = "bwv_enabled"; static const String prefsBWVEnabled = "bwv_enabled";
static const String prefsDesiredZip = "desired_zip"; static const String prefsDesiredZip = "desired_zip";
static const String prefsAppLanguage = "app_language";
static const int stateAssigned = 0; static const int stateAssigned = 0;
static const int stateAccepted = 1; static const int stateAccepted = 1;
-1
View File
@@ -6,7 +6,6 @@ import 'dart:math';
import 'package:archive/archive.dart'; import 'package:archive/archive.dart';
import 'package:dart_mq/dart_mq.dart'; import 'package:dart_mq/dart_mq.dart';
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:mqtt5_client/mqtt5_client.dart'; import 'package:mqtt5_client/mqtt5_client.dart';
import 'package:mqtt5_client/mqtt5_server_client.dart'; import 'package:mqtt5_client/mqtt5_server_client.dart';
+16 -15
View File
@@ -10,6 +10,7 @@ import 'package:stadtbote/main.dart';
import 'package:stadtbote/model/job.dart'; import 'package:stadtbote/model/job.dart';
import 'package:stadtbote/model/log_entry.dart'; import 'package:stadtbote/model/log_entry.dart';
import 'package:stadtbote/objectbox.g.dart'; import 'package:stadtbote/objectbox.g.dart';
import 'package:stadtbote/tools/app_localizations.dart';
import 'package:stadtbote/tools/constants.dart'; import 'package:stadtbote/tools/constants.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
@@ -355,22 +356,22 @@ String mapVehicleTypeToImageName(int vehType)
String mapVehicleTypeToText(int vehType) { String mapVehicleTypeToText(int vehType) {
switch (vehType) { switch (vehType) {
case 1: case 1:
return "Fahrrad"; return 'bicycle'.tr;
case 2: case 2:
return "Pkw"; return 'car'.tr;
case 3: case 3:
return "Kombi"; return 'station_wagon'.tr;
case 4: case 4:
return "Kasten"; return 'van'.tr;
case 5: case 5:
return "Bus"; return 'bus'.tr;
case 6: case 6:
return "GrBus"; return 'large_bus'.tr;
case 7: case 7:
case 8: case 8:
@@ -379,10 +380,10 @@ String mapVehicleTypeToText(int vehType) {
case 12: case 12:
case 13: case 13:
case 14: case 14:
return "Lkw"; return 'truck'.tr;
case 999: case 999:
return "Service"; return 'service'.tr;
} }
return "!?????!"; return "!?????!";
@@ -392,15 +393,15 @@ String mapTourMode(String mode) {
var text = ""; var text = "";
switch (mode) { switch (mode) {
case "pu": case "pu":
text += "/ Abholung"; text += "/ ${'pickup'.tr}";
break; break;
case "del": case "del":
text += "/ Auslieferung"; text += "/ ${'delivery'.tr}";
break; break;
case "pu/del": case "pu/del":
text += "/ Abholung/Auslieferung"; text += "/ ${'pickup_delivery'.tr}";
break; break;
} }
@@ -490,16 +491,16 @@ Future<bool> taskDialogSecurityException(BuildContext context) async {
barrierDismissible: false, barrierDismissible: false,
builder: (dialogContext) { builder: (dialogContext) {
return AlertDialog( return AlertDialog(
title: const Text('Achtung'), title: Text('attention'.tr),
content: const Text('Wenn Sie den Dialog jetzt schließen gehen erfasste Daten verloren und die Aufgabe oder Station bleibt unerledigt.'), content: Text('close_dialog_warning'.tr),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Navigator.of(dialogContext).pop(true), onPressed: () => Navigator.of(dialogContext).pop(true),
child: const Text('Schließen'), child: Text('close'.tr),
), ),
TextButton( TextButton(
onPressed: () => Navigator.of(dialogContext).pop(false), onPressed: () => Navigator.of(dialogContext).pop(false),
child: const Text('Zurück'), child: Text('back'.tr),
), ),
], ],
); );