diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 86ce87a0a70cb2edf47121297ec45fc2d0da3d9b..2d205229c2690c23351c8ead1a21347c51780b7a 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -158,5 +158,18 @@ "tripPageAdvanceOptionHeadline": "Erweiterte Optionen:", "tripPageAdvanceOptionDescription": "Ändern hier nur etwas wenn du sicher bist was du tust!", "tripPageToggleUploadedSwitch": "Festlegen, ob die Reise auf ein Portal hochgeladen wurde.", - "tripPageToggleDoneSwitch": "Festlegen, ob die Aufzeichnung der Fahrt abgeschlossen ist." + "tripPageToggleDoneSwitch": "Festlegen, ob die Aufzeichnung der Fahrt abgeschlossen ist.", + "hours": "Stunden", + "minutes": "Minuten", + "duration": "Dauer", + "oneOvertakeEvent": "Überholvorgang", + "multipleOvertakeEvents": "Überholvorgänge", + "portalMissingTitle": "Portal-Daten fehlen", + "portalMissingDescription": "Bitte gib in den Einstellungen URL und Key Deines OBS-Portals an.", + "noTracksTitle": "Keine Tracks", + "noTracksDescription": "Es gibt derzeit keine Tracks, die hochgeladen werden können.", + "uploadSuccessTitle": "Hochladen erfolgreich", + "uploadSuccessDescription": "Alle Tracks wurden erfolgreich hochgeladen.", + "uploadErrorTitle": "Hochladen fehlgeschlagen", + "uploadErrorDescription": "Einige Tracks konnten nicht hochgeladen werden. Bitte versuche es später erneut." } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f891b5bb850316400f1c12420b6ba235cbd18dc1..fc66842d21ea0ad57e218970b4cbfff1d4ed0697 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -158,6 +158,18 @@ "tripPageAdvanceOptionHeadline": "Advanced Options:", "tripPageAdvanceOptionDescription": "Only change these if you are sure what you are doing!", "tripPageToggleUploadedSwitch": "Set if trip is uploaded to a portal.", - "tripPageToggleDoneSwitch" : "Set if the trip is done with recording." - + "tripPageToggleDoneSwitch" : "Set if the trip is done with recording.", + "hours": "hours", + "minutes": "minutes", + "duration": "duration", + "oneOvertakeEvent": "overtake", + "multipleOvertakeEvents": "overtakes", + "portalMissingTitle": "No portal server or key", + "portalMissingDescription": "Please set the portal server and key in the settings.", + "noTracksTitle": "No tracks to upload", + "noTracksDescription": "There are no tracks to upload.", + "uploadSuccessTitle": "Upload successful", + "uploadSuccessDescription": "All tracks were uploaded successfully.", + "uploadErrorTitle": "Upload failed", + "uploadErrorDescription": "Some tracks could not be uploaded. Please try again later." } diff --git a/lib/obs_list_upload_page.dart b/lib/obs_list_upload_page.dart index a914c498be1e7ae08c56f79e7b12015d9c7def97..65d507c9f39efbd85256a701c230d481827de076 100644 --- a/lib/obs_list_upload_page.dart +++ b/lib/obs_list_upload_page.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:app/database/trip.dart'; import 'package:app/manager/settings_manager.dart'; import 'package:app/manager/upload_manger.dart'; import 'package:app/providers/trip_provider.dart'; @@ -7,6 +8,7 @@ import 'package:app/providers/upload_provider.dart'; import 'package:app/widgets/trip_page.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:toastification/toastification.dart'; import 'package:app/generated/i18n/app_localizations.dart'; @@ -26,6 +28,24 @@ class _ObsListUploadPageState extends State<ObsListUploadPage> { super.initState(); } + String _getTripSummary(Trip trip) { + // returns string with duration in format HH:mm and number of overtake events + final duration = trip.segments.last.timestamp.millisecondsSinceEpoch - + trip.segments.first.timestamp.millisecondsSinceEpoch; + + final durationString = + "${(duration ~/ 3600000).toString().padLeft(1, '0')}:${((duration % 3600000) ~/ 60000).toString().padLeft(2, '0')}" + + " ${AppLocalizations.of(context)!.hours}"; + + final overtakeEvents = + trip.segments.where((element) => element.confirmedIdx != -1).length; + + final overtakeEventsString = overtakeEvents == 1 + ? AppLocalizations.of(context)!.oneOvertakeEvent + : AppLocalizations.of(context)!.multipleOvertakeEvents; + return "$durationString, $overtakeEvents $overtakeEventsString"; + } + @override Widget build(BuildContext context) { final tripProvider = context.watch<TripProvider>(); @@ -54,9 +74,10 @@ class _ObsListUploadPageState extends State<ObsListUploadPage> { context: context, type: ToastificationType.error, style: ToastificationStyle.flat, - title: Text("No portal server or key"), - description: Text( - "Please set the portal server and key in the settings."), + title: Text(AppLocalizations.of(context)! + .portalMissingTitle), + description: Text(AppLocalizations.of(context)! + .portalMissingDescription), alignment: Alignment.topRight, autoCloseDuration: const Duration(seconds: 4), ); @@ -76,8 +97,10 @@ class _ObsListUploadPageState extends State<ObsListUploadPage> { context: context, type: ToastificationType.error, style: ToastificationStyle.flat, - title: Text("No tracks to upload"), - description: Text("There are no tracks to upload."), + title: Text( + AppLocalizations.of(context)!.noTracksTitle), + description: Text(AppLocalizations.of(context)! + .noTracksDescription), alignment: Alignment.topRight, autoCloseDuration: const Duration(seconds: 4), ); @@ -86,9 +109,10 @@ class _ObsListUploadPageState extends State<ObsListUploadPage> { context: context, type: ToastificationType.success, style: ToastificationStyle.flat, - title: Text("Upload successful"), - description: - Text("All tracks were uploaded successfully."), + title: Text(AppLocalizations.of(context)! + .uploadSuccessTitle), + description: Text(AppLocalizations.of(context)! + .uploadSuccessDescription), alignment: Alignment.topRight, autoCloseDuration: const Duration(seconds: 4), ); @@ -97,9 +121,10 @@ class _ObsListUploadPageState extends State<ObsListUploadPage> { context: context, type: ToastificationType.error, style: ToastificationStyle.flat, - title: Text("Upload failed"), - description: Text( - "$success/$numTracks tracks were uploaded successfully, ${numTracks - success} failed."), + title: Text( + AppLocalizations.of(context)!.uploadErrorTitle), + description: Text(AppLocalizations.of(context)! + .uploadErrorDescription), alignment: Alignment.topRight, autoCloseDuration: const Duration(seconds: 4), ); @@ -139,7 +164,7 @@ class _ObsListUploadPageState extends State<ObsListUploadPage> { "${trip.createdAt.day.toString().padLeft(2, '0')}.${trip.createdAt.month.toString().padLeft(2, '0')}.${trip.createdAt.year} ${trip.createdAt.hour.toString().padLeft(2, '0')}:${trip.createdAt.minute.toString().padLeft(2, '0')}", style: const TextStyle(fontSize: 20)), subtitle: Row(children: [ - Text(trip.trackID), + Text(_getTripSummary(trip)), // Display the date in forma dd.mm.yyyy HH:mm and the obs firmware revision Text(trip.uploaded ? AppLocalizations.of(context)!.uploaded @@ -156,15 +181,32 @@ class _ObsListUploadPageState extends State<ObsListUploadPage> { : const Icon(Icons.sensors), onTap: () { // Navigate to the map page - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => TripPage( - trip: trip, - onDelete: (trip) { - tripProvider.deleteTrip(trip.id); - })), - ); + try { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => TripPage( + trip: trip, + onDelete: (trip) { + tripProvider.deleteTrip(trip.id); + })), + ); + } catch (e, trace) { + Sentry.captureException(e, stackTrace: trace); + Sentry.captureMessage( + 'Failed to navigate to trip page'); + + toastification.show( + context: context, + type: ToastificationType.error, + style: ToastificationStyle.flat, + title: Text("Opening trip failed"), + description: Text( + "Failed to open the trip. If configured, the error has been sent to the developers."), + alignment: Alignment.topRight, + autoCloseDuration: const Duration(seconds: 4), + ); + } }, ), const Divider(),