diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 6bc3cb56..8532f1df 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -6,6 +6,8 @@
+
+
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index e86e443b..a8309cd5 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -45,5 +45,19 @@
CADisableMinimumFrameDurationOnPhone
+
+ NSCalendarsUsageDescription
+ Access your calendar to add bridge closure events
+
+ NSCalendarsFullAccessUsageDescription
+ Full access to view and edit your calendar events
+ NSCalendarsWriteOnlyAccessUsageDescription
+ Add bridge closure events without reading existing events
+ CFBundleLocalizations
+
+ en
+ fr
+ es
+
diff --git a/lib/extensions/boats_extension.dart b/lib/extensions/boats_extension.dart
index 3f78cae6..c54084cd 100644
--- a/lib/extensions/boats_extension.dart
+++ b/lib/extensions/boats_extension.dart
@@ -4,20 +4,6 @@ import 'package:chabo_app/models/boat.dart';
import 'package:flutter/material.dart';
extension BoatsExtension on List {
- TextSpan toLocalizedTextSpan(BuildContext context) {
- final finalTextSpan = [];
- for (var index = 0; index < length; index++) {
- finalTextSpan.add(this[index].toLocalizedStatusTextSpan(context, true));
- if (index + 1 != length) {
- finalTextSpan.add(
- TextSpan(text: ' ${AppLocalizations.of(context)!.and} '),
- );
- }
- }
-
- return TextSpan(children: finalTextSpan);
- }
-
String getNames(BuildContext context) {
var finalString = '';
for (var index = 0; index < length; index++) {
diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb
index 7f1f8504..97437e51 100644
--- a/lib/l10n/app_en.arb
+++ b/lib/l10n/app_en.arb
@@ -231,5 +231,30 @@
"timeFormatTitle": "Time format",
"timeFormatSubTitle": "Display hours in 12 or 24 format",
"noMoreForecastsTitle": "No upcoming events",
- "noMoreForecastsMessage": "Bordeaux Métropole has not communicated any closure of the Chaban-Delmas Bridge for the coming weeks.\nStay informed of upcoming closures by returning here regularly"
+ "noMoreForecastsMessage": "Bordeaux Métropole has not communicated any closure of the Chaban-Delmas Bridge for the coming weeks.\nStay informed of upcoming closures by returning here regularly",
+ "shareEventTitle": "Share",
+ "calendarEventAddToCalendar": "Add to calendar",
+ "calendarEventTitle": "Closure of the Chaban Delmas bridge",
+ "calendarEventLocation": "Bordeaux, Chaban Delmas bridge",
+ "calendarEventMaintenanceDescription": "The Chaban bridge will close for maintenance \uD83D\uDEE0. It will remains closed for {duration} \uD83C\uDF09",
+ "@calendarEventMaintenanceDescription": {
+ "placeholders": {
+ "duration": {}
+ }
+ },
+ "calendarEventBoatDescription": "The Chaban bridge will close for {boat} \uD83D\uDEA2. It will remains closed for {duration} \uD83C\uDF09",
+ "@calendarEventBoatDescription": {
+ "placeholders": {
+ "boat": {},
+ "duration": {}
+ }
+ },
+ "bottomSheetTitle_maintenance": "Maintenance",
+ "bottomSheetTitle_boat": "Passage of vessel(s)",
+ "bottomSheetAdditionalInfo_maintenance": "The Chaban Bridge is closed for scheduled maintenance.",
+ "bottomSheetAdditionalInfo_boatLeaving": "leaving",
+ "bottomSheetAdditionalInfo_boatArriving": "arriving",
+ "bottomSheetAdditionalInfo_boatCrossingTimeDisclaimer": "Arrival and departure times are for information purposes only and are not guaranteed.",
+ "bottomSheetAdditionalInfo_shareMessage": "Hi, I'm going to be late, the Chaban Bridge is closed until"
}
+
diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb
index abeb5b75..e9c11b96 100644
--- a/lib/l10n/app_es.arb
+++ b/lib/l10n/app_es.arb
@@ -46,25 +46,25 @@
}
},
"dialogInformationContentBridge_closed_maintenance": "mantenimiento",
- "dialogInformationContentTime_of_crossing": "hora estimada de cruce",
+ "dialogInformationContentTime_of_crossing": "hora de paso estimada",
"duration": "Duración",
"errorScreenContentError": "Error",
- "errorScreenContentMessage": "Se produjo un error al abrir esta página. Encuentre la información técnica a continuación",
+ "errorScreenContentMessage": "Se ha producido un error al abrir esta pàgina. Encuentre información técnica a continuación",
"errorScreenContentTechnical_Info": "Información técnica",
- "unableAppInfo": "No se puede obtener información de la aplicación",
- "appDescription": "La aplicación móvil para obtener los horarios de cierre y apertura del puente Chaban Delmas ubicado en Bordeaux, Francia",
+ "unableAppInfo": "No se puede recuperar la información de la aplicación",
+ "appDescription": "Aplicación móvil para obtener los horarios de cierre y apertura del puente Chaban-Delmas ubicado en Burdeos, Francia",
"informationAboutTheApp": "Información sobre la aplicación",
"about": "Acerca de",
- "disclaimer": "Descargo de responsabilidad: cierres provisionales. Sujeto a confirmación de la Capitanía de Puerto.",
- "openSetting": "Ajustes",
+ "disclaimer": "Aviso: cierres provisionales. Sujeto a confirmación de la Capitania de Puerto.",
+ "openSetting": "Configuración",
"themeSettingTitle": "Tema",
"themeSettingSubTitle": "Cambiar la apariencia de la aplicación",
"lightTheme": "Tema claro",
"darkTheme": "Tema oscuro",
- "schedules": "Programar",
+ "schedules": "Horarios",
"systemTheme": "Tema del sistema",
"notifications": "Notificaciones",
- "notificationsSubtitle": "Administre las notificaciones de la aplicación",
+ "notificationsSubtitle": "Administrar las notificaciones de la aplicación",
"durationNotificationTitle": "{duration}antes",
"@durationNotificationTitle": {
"placeholders": {
@@ -95,35 +95,35 @@
"day": {}
}
},
- "dayNotificationExplanation": "Reciba una notificación el {day} a las {time} que enumere todos los cierres planeados para la próxima semana",
+ "dayNotificationExplanation": "Reciba una notificación el {day} a las {time} que enumere todos los cierres planificados para la próxima semana",
"@dayNotificationExplanation": {
"placeholders": {
"day": {},
"time": {}
}
},
- "closingNotificationTitle": "En el cierre",
- "closingNotificationExplanation": "Reciba una notificación cuando el puente cierre",
+ "closingNotificationTitle": "Al cierre",
+ "closingNotificationExplanation": "Reciba una notificación cuando el puente se cierra",
"notificationClosingChannelName": "Cierre",
- "notificationClosingTitle": "El puente Chaban ha cerrado ⛔",
- "notificationClosingBoatMessage": "El puente Chaban acaba de cerrarse para {boat} \uD83D\uDEA2. Permanecerá cerrado durante {duration} \uD83C\uDF09",
+ "notificationClosingTitle": "El puente Chaban está cerrado ⛔",
+ "notificationClosingBoatMessage": "El puente Chaban acaba de cerrarse para {boat} \uD83D\uDEA2. Permanecerà cerrado durante {duration} \uD83C\uDF09",
"@notificationClosingBoatMessage": {
"placeholders": {
"boat": {},
"duration": {}
}
},
- "notificationClosingMaintenanceMessage": "El puente Chaban acaba de cerrarse para mantenimiento \uD83D\uDEE0. Permanecerá cerrado durante {duration} \uD83C\uDF09",
+ "notificationClosingMaintenanceMessage": "El puente Chaban acaba de cerrarse para mantenimiento \uD83D\uDEE0. Permanecerà cerrado durante {duration} \uD83C\uDF09",
"@notificationClosingMaintenanceMessage": {
"placeholders": {
"duration": {}
}
},
"openingNotificationTitle": "En la apertura",
- "openingNotificationExplanation": "Reciba una notificación cuando el puente abra",
+ "openingNotificationExplanation": "Reciba una notificación cuando el puente se abre",
"notificationOpeningChannelName": "Apertura",
"notificationOpeningTitle": "El puente Chaban está abierto ✅",
- "notificationOpeningMessage": "El puente Chaban acaba de abrirse al tráfico \uD83D\uDEB2",
+ "notificationOpeningMessage": "El puente Chaban acaba de abrirse al tràfico \uD83D\uDEB2",
"monday": "Lunes",
"tuesday": "Martes",
"wednesday": "Miércoles",
@@ -132,7 +132,7 @@
"saturday": "Sábado",
"sunday": "Domingo",
"notificationDurationTitle": "Cierre inminente ⚠️",
- "notificationDurationBoatMessage": "El puente Chaban cerrará en {timeLeft} para {boat} \uD83D\uDEA2. Permanecerá cerrado durante {duration} \uD83C\uDF09",
+ "notificationDurationBoatMessage": "El puente Chaban se cerrarà en {timeLeft} para {boat} \uD83D\uDEA2. Permanecerà cerrado durante {duration} \uD83C\uDF09",
"@notificationDurationBoatMessage": {
"placeholders": {
"boat": {},
@@ -140,7 +140,7 @@
"duration": {}
}
},
- "notificationDurationMaintenanceMessage": "El puente Chaban cerrará en {timeLeft} para mantenimiento \uD83D\uDEE0. Permanecerá cerrado durante {duration} \uD83C\uDF09",
+ "notificationDurationMaintenanceMessage": "El puente Chaban se cerrarà en {timeLeft} para mantenimiento \uD83D\uDEE0. Permanecerà cerrado durante {duration} \uD83C\uDF09",
"@notificationDurationMaintenanceMessage": {
"placeholders": {
"timeLeft": {},
@@ -149,7 +149,7 @@
},
"notificationDurationChannelName": "Cierres inminentes",
"notificationTimeTitle": "\uD83D\uDDD3 Cierre programado para mañana",
- "notificationTimeBoatMessage": "El puente Chaban cerrará mañana a las {time} para {boat} \uD83D\uDEA2. Permanecerá cerrado durante {duration} \uD83C\uDF09",
+ "notificationTimeBoatMessage": "El puente Chaban se cerrarà mañana a las {time} para {boat} \uD83D\uDEA2. Permanecerà cerrado durante {duration} \uD83C\uDF09",
"@notificationTimeBoatMessage": {
"placeholders": {
"boat": {},
@@ -169,34 +169,34 @@
"boat": {}
}
},
- "notificationTimeMaintenanceMessage": "El puente Chaban cerrará mañana a las {time} por mantenimiento \uD83D\uDEE0. Permanecerá cerrado durante {duration} \uD83C\uDF09",
+ "notificationTimeMaintenanceMessage": "El puente Chaban se cerrarà mañana a las {time} para mantenimiento \uD83D\uDEE0. Permanecerà cerrado durante {duration} \uD83C\uDF09",
"@notificationTimeMaintenanceMessage": {
"placeholders": {
"time": {},
"duration": {}
}
},
- "notificationTimeChannelName": "Cierres del próximo día",
+ "notificationTimeChannelName": "Cierres del dìa siguiente",
"passedClosure": "Cierre pasado",
- "selectAboutDialog": "{choice, select, source_code {Código fuente} privacy_policy {Política de privacidad} yuhliet_instagram {Instagram de Yuhliet's} city_of_bordeaux {Ciudad de Bordeaux} bordeaux_open_data {Bordeaux Open Data} licenses {Licencias} changelog {Registro de cambios} other {Undefined}}",
+ "selectAboutDialog": "{choice, select, source_code {Código fuente} privacy_policy {Polìtica de privacidad} yuhliet_instagram {Instagram de Yuhliet} city_of_bordeaux {Ciudad de Burdeos} bordeaux_open_data {Bordeaux Open Data} licenses {Licencias} changelog {Registro de cambios} other {Indefinido}}",
"@selectAboutDialog": {
"placeholders": {
"choice": {}
}
},
- "day": "Día",
+ "day": "Dìa",
"notificationDayTitle": "\uD83D\uDD2E Cierre programado",
- "notificationDayMessage": "{count, plural, =0{No hay cierres programados para la próxima semana} =1{La próxima semana, el puente Chaban Delmas solo cerrará una vez} other{La próxima semana, el puente Chaban Delmas cerrará {count} veces}}",
+ "notificationDayMessage": "{count, plural, =0{Ningún cierre programado para la próxima semana} =1{La próxima semana, el puente Chaban-Delmas solo se cerrarà una vez} other{La próxima semana, el puente Chaban-Delmas se cerrarà {count} veces}}",
"@notificationDayMessage": {
"placeholders": {
"count": {}
}
},
- "notificationDayChannelName": "Cierres planificados",
- "leftHanded": "Zurdo.a",
- "rightHanded": "Diestro.a",
+ "notificationDayChannelName": "Cierres programados",
+ "leftHanded": "Zurdo",
+ "rightHanded": "Diestro",
"status": "Estado",
- "statusLoadMessage": "Carga del estado actual del puente",
+ "statusLoadMessage": "Cargando el estado actual del puente",
"loading": "Cargando...",
"dayNotificationAt": "en las",
"favoriteSlotsFrom": "De",
@@ -209,16 +209,16 @@
"index": {}
}
},
- "favoriteSlotsInterferenceWarning": "Este horario interfiere con uno o más intervalos de tiempo",
- "favoriteTimeSlotEnabledWarning": "Atención, al activar este parámetro solo recibirás notificaciones cuando ocurra un evento durante una de tus franjas horarias",
- "favoriteSlotsChooseDay": "Elegir los días de la semana",
- "moonHarborStatus": "{count, plural, =1 {está actualmente amarrado} other {están actualmente amarrados}} en el 'Puerto de la Luna'",
+ "favoriteSlotsInterferenceWarning": "Este horario interfiere con uno o màs intervalos de tiempo",
+ "favoriteTimeSlotEnabledWarning": "Atención, al activar este paràmetro solo recibiràs notificaciones cuando ocurra un evento durante una de tus franjas horarias",
+ "favoriteSlotsChooseDay": "Elegir los dìas de la semana",
+ "moonHarborStatus": "{count, plural, =1 {está actualmente amarrado} other {estàn actualmente amarrados}} en el 'Puerto de la Luna'",
"@moonHarborStatus": {
"placeholders": {
"count": {}
}
},
- "moonHarborShortStatus": "{count} {count, plural, =1 {barco está actualmente} other {buques están actualmente}} en Bordeaux",
+ "moonHarborShortStatus": "{count} {count, plural, =1 {barco está actualmente} other {buques estàn actualmente}} en Bordeaux",
"@moonHarborShortStatus": {
"placeholders": {
"count": {}
@@ -231,5 +231,29 @@
"timeFormatTitle": "Formato de hora",
"timeFormatSubTitle": "Visualización de las horas en formato de 12 o 24 horas.",
"noMoreForecastsTitle": "Ningún acontecimiento por venir",
- "noMoreForecastsMessage": "Bordeaux Métropole no ha comunicado ningún cierre del Puente Chaban-Delmas para las próximas semanas.\nManténgase informado de los próximos cierres volviendo aquí regularmente"
+ "noMoreForecastsMessage": "Bordeaux Métropole no ha comunicado ningún cierre del Puente Chaban-Delmas para las próximas semanas.\nManténgase informado de los próximos cierres volviendo aquì regularmente",
+ "shareEventTitle": "Compartir",
+ "calendarEventAddToCalendar": "Añadir al calendario",
+ "calendarEventTitle": "Cierre del puente Chaban Delmas",
+ "calendarEventLocation": "Bordeaux, puente Chaban Delmas",
+ "calendarEventMaintenanceDescription": "\"El puente Chaban permanecerá cerrado para mantenimiento \uD83D\uDEE0. Permanecerà cerrado durante {duration} \uD83C\uDF09",
+ "@calendarEventMaintenanceDescription": {
+ "placeholders": {
+ "duration": {}
+ }
+ },
+ "calendarEventBoatDescription": "El puente Chaban permanecerá cerrado para {boat} \uD83D\uDEA2. Permanecerà cerrado durante {duration} \uD83C\uDF09",
+ "@calendarEventBoatDescription": {
+ "placeholders": {
+ "boat": {},
+ "duration": {}
+ }
+ },
+ "bottomSheetTitle_maintenance": "Mantenimiento",
+ "bottomSheetTitle_boat": "Paso de la(s) embarcación(es)",
+ "bottomSheetAdditionalInfo_maintenance": "El puente Chaban está cerrado por mantenimiento programado.",
+ "bottomSheetAdditionalInfo_boatLeaving": "llegada",
+ "bottomSheetAdditionalInfo_boatArriving": "partida",
+ "bottomSheetAdditionalInfo_boatCrossingTimeDisclaimer": "Los horarios de llegada y salida son únicamente a título informativo y no están garantizados.",
+ "bottomSheetAdditionalInfo_shareMessage": "Hola, voy a llegar tarde; el puente Chaban está cerrado hasta"
}
diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb
index e28ecb95..8cb5f0b9 100644
--- a/lib/l10n/app_fr.arb
+++ b/lib/l10n/app_fr.arb
@@ -49,20 +49,19 @@
"dialogInformationContentTime_of_crossing": "heure de passage estimée",
"duration": "Durée",
"errorScreenContentError": "Erreur",
- "errorScreenContentMessage": "Une erreur est survenue lors de l'ouverture de cette page. Veuillez trouver les informations techniques ci-dessous",
+ "errorScreenContentMessage": "Une erreur est survenue lors de l'ouverture de cette page. Vous trouverez des informations techniques ci-dessous",
"errorScreenContentTechnical_Info": "Informations techniques",
- "unableAppInfo": "Impossible d'obtenir les informations de l'application",
- "appDescription": "L'application Mobile pour connaître les horaires de fermeture et d'ouverture du pont Chaban Delmas situé à Bordeaux, France",
- "informationAboutTheApp": "Informations concernant l'application",
+ "unableAppInfo": "Impossible de récupérer les informations de l'application",
+ "appDescription": "Application mobile pour obtenir les horaires de fermeture et d'ouverture du pont Chaban-Delmas situé à Bordeaux, France",
+ "informationAboutTheApp": "Informations sur l'application",
"about": "À propos",
- "disclaimer": "Avis de non-responsabilité : fermetures provisoires. Sous réserve de confirmation de la Capitainerie.",
+ "disclaimer": "Avertissement : fermetures provisoires. Sous réserve de confirmation de la Capitainerie.",
"openSetting": "Paramètres",
"themeSettingTitle": "Thème",
- "themeSettingSubTitle": "Changer l'apparence de l'application",
+ "themeSettingSubTitle": "Modifier l'apparence de l'application",
"lightTheme": "Thème clair",
"darkTheme": "Thème sombre",
- "schedules": "Calendrier",
- "status": "État",
+ "schedules": "Plannings",
"systemTheme": "Thème système",
"notifications": "Notifications",
"notificationsSubtitle": "Gérer les notifications de l'application",
@@ -72,7 +71,7 @@
"duration": {}
}
},
- "durationNotificationExplanation": "Recevoir une notification {duration}avant la prochaine fermeture. Cette valeur gère aussi le changement de couleur du statut actuel",
+ "durationNotificationExplanation": "Recevez une notification {duration}avant la prochaine fermeture. Cette valeur gère également le changement de couleur de l'état actuel",
"@durationNotificationExplanation": {
"placeholders": {
"duration": {}
@@ -84,19 +83,19 @@
"time": {}
}
},
- "timeNotificationExplanation": "Recevoir une notification la veille à {time} si une fermeture est prévue le lendemain",
+ "timeNotificationExplanation": "Recevez une notification la veille à {time} si une fermeture est prévue le lendemain",
"@timeNotificationExplanation": {
"placeholders": {
"time": {}
}
},
- "dayNotificationTitle": "Récap hebdo le {day}",
+ "dayNotificationTitle": "Récapitulatif hebdomadaire le {day}",
"@dayNotificationTitle": {
"placeholders": {
"day": {}
}
},
- "dayNotificationExplanation": "Recevoir une notification le {day} à {time} listant toutes les fermetures prévues pour la semaine qui arrive",
+ "dayNotificationExplanation": "Recevez une notification le {day} à {time} listant toutes les fermetures prévues pour la semaine à venir",
"@dayNotificationExplanation": {
"placeholders": {
"day": {},
@@ -104,27 +103,27 @@
}
},
"closingNotificationTitle": "À la fermeture",
- "closingNotificationExplanation": "Recevoir une notification quand le pont ferme à la circulation",
+ "closingNotificationExplanation": "Recevez une notification lorsque le pont se ferme",
"notificationClosingChannelName": "Fermeture",
"notificationClosingTitle": "Le pont Chaban est fermé ⛔",
- "notificationClosingBoatMessage": "Le pont Chaban vient de fermer pour {boat} \uD83D\uDEA2. Il restera fermé pendant {duration} \uD83C\uDF09",
+ "notificationClosingBoatMessage": "Le pont Chaban vient de se fermer pour {boat} \uD83D\uDEA2. Il restera fermé pendant {duration} \uD83C\uDF09",
"@notificationClosingBoatMessage": {
"placeholders": {
"boat": {},
"duration": {}
}
},
- "notificationClosingMaintenanceMessage": "Le pont Chaban vient de fermer pour maintenance \uD83D\uDEE0. Il restera fermé pendant {duration} \uD83C\uDF09",
+ "notificationClosingMaintenanceMessage": "Le pont Chaban vient de se fermer pour maintenance \uD83D\uDEE0. Il restera fermé pendant {duration} \uD83C\uDF09",
"@notificationClosingMaintenanceMessage": {
"placeholders": {
"duration": {}
}
},
"openingNotificationTitle": "À l'ouverture",
- "openingNotificationExplanation": "Recevoir une notification quand le pont ouvre à la circulation",
+ "openingNotificationExplanation": "Recevez une notification lorsque le pont s'ouvre",
"notificationOpeningChannelName": "Ouverture",
"notificationOpeningTitle": "Le pont Chaban est ouvert ✅",
- "notificationOpeningMessage": "Le pont Chaban vient de rouvir à la circulation \uD83D\uDEB2",
+ "notificationOpeningMessage": "Le pont Chaban vient de s'ouvrir à la circulation \uD83D\uDEB2",
"monday": "Lundi",
"tuesday": "Mardi",
"wednesday": "Mercredi",
@@ -132,8 +131,8 @@
"friday": "Vendredi",
"saturday": "Samedi",
"sunday": "Dimanche",
- "notificationDurationTitle": "Fermeture imminante ⚠️",
- "notificationDurationBoatMessage": "Le pont Chaban fermera dans {timeLeft} pour {boat} \uD83D\uDEA2. Il restera fermé pendant {duration} \uD83C\uDF09",
+ "notificationDurationTitle": "Fermeture imminente ⚠️",
+ "notificationDurationBoatMessage": "Le pont Chaban va se fermer dans {timeLeft} pour {boat} \uD83D\uDEA2. Il restera fermé pendant {duration} \uD83C\uDF09",
"@notificationDurationBoatMessage": {
"placeholders": {
"boat": {},
@@ -179,7 +178,7 @@
},
"notificationTimeChannelName": "Fermetures du lendemain",
"passedClosure": "Fermeture passée",
- "selectAboutDialog": "{choice, select, source_code {Code source} privacy_policy {Politique de confidentialité} yuhliet_instagram {Instagram de Yuhliet's} city_of_bordeaux {Ville de Bordeaux} bordeaux_open_data {Bordeaux Open Data} changelog {Journal des modifications} licenses {Licences} other {Undefined}}",
+ "selectAboutDialog": "{choice, select, source_code {Code source} privacy_policy {Politique de confidentialité} yuhliet_instagram {Instagram de Yuhliet} city_of_bordeaux {Ville de Bordeaux} bordeaux_open_data {Bordeaux Open Data} licenses {Licences} changelog {Journal des modifications} other {Undefined}}",
"@selectAboutDialog": {
"placeholders": {
"choice": {}
@@ -187,7 +186,7 @@
},
"day": "Jour",
"notificationDayTitle": "\uD83D\uDD2E Fermetures prévues",
- "notificationDayMessage": "{count, plural, =0{Aucune fermetures de prévue pour la semaine prochaine} =1{La semaine prochaine, le pont Chaban Delmas ne fermera qu'une seul fois} other{La semaine prochaine, le pont Chaban Delmas fermera à {count} reprises}}",
+ "notificationDayMessage": "{count, plural, =0{Aucune fermeture prévue pour la semaine prochaine} =1{La semaine prochaine, le pont Chaban-Delmas ne se fermera qu'une seule fois} other{La semaine prochaine, le pont Chaban-Delmas se fermera {count} fois}}",
"@notificationDayMessage": {
"placeholders": {
"count": {}
@@ -196,6 +195,7 @@
"notificationDayChannelName": "Fermetures prévues",
"leftHanded": "Gaucher.ère",
"rightHanded": "Droitier.ère",
+ "status": "État",
"statusLoadMessage": "Chargement de l'état actuel du pont",
"loading": "Chargement...",
"dayNotificationAt": "à",
@@ -231,5 +231,29 @@
"timeFormatTitle": "Format des heures",
"timeFormatSubTitle": "Afficher les heures au format 12 ou 24 heures",
"noMoreForecastsTitle": "Aucun évènement à venir",
- "noMoreForecastsMessage": "Bordeaux Métropole n'a communiqué aucune fermeture du Pont Chaban-Delmas pour les prochaines semaines.\nTenez-vous informer des prochaines fermetures en revenant ici régulièrement"
+ "noMoreForecastsMessage": "Bordeaux Métropole n'a communiqué aucune fermeture du Pont Chaban-Delmas pour les prochaines semaines.\nTenez-vous informer des prochaines fermetures en revenant ici régulièrement",
+ "shareEventTitle": "Partager",
+ "calendarEventAddToCalendar": "Ajouter au calendrier",
+ "calendarEventTitle": "Fermeture du pont Chaban Delmas",
+ "calendarEventLocation": "Bordeaux, pont Chaban Delmas",
+ "calendarEventMaintenanceDescription": "Le pont Chaban sera fermé pour maintenance \uD83D\uDEE0. Il restera fermé pendant {duration} \uD83C\uDF09",
+ "@calendarEventMaintenanceDescription": {
+ "placeholders": {
+ "duration": {}
+ }
+ },
+ "calendarEventBoatDescription": "Le pont Chaban sera pour {boat} \uD83D\uDEA2. Il restera fermé pendant {duration} \uD83C\uDF09",
+ "@calendarEventBoatDescription": {
+ "placeholders": {
+ "boat": {},
+ "duration": {}
+ }
+ },
+ "bottomSheetTitle_maintenance": "Maintenance",
+ "bottomSheetTitle_boat": "Passage de navire(s)",
+ "bottomSheetAdditionalInfo_maintenance": "Le pont Chaban est fermé pour maintenance planifiée.",
+ "bottomSheetAdditionalInfo_boatLeaving": "arrivée",
+ "bottomSheetAdditionalInfo_boatArriving": "départ",
+ "bottomSheetAdditionalInfo_boatCrossingTimeDisclaimer": "Les heures d'arrivées et de départs sont purement à des fins indicatives et ne sont pas garanties.",
+ "bottomSheetAdditionalInfo_shareMessage": "Salut, je vais avoir du retard, le Pont Chaban est fermé jusqu'à"
}
diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart
index df18b9aa..8ea19d7a 100644
--- a/lib/l10n/app_localizations.dart
+++ b/lib/l10n/app_localizations.dart
@@ -784,6 +784,84 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'Bordeaux Métropole has not communicated any closure of the Chaban-Delmas Bridge for the coming weeks.\nStay informed of upcoming closures by returning here regularly'**
String get noMoreForecastsMessage;
+
+ /// No description provided for @shareEventTitle.
+ ///
+ /// In en, this message translates to:
+ /// **'Share'**
+ String get shareEventTitle;
+
+ /// No description provided for @calendarEventAddToCalendar.
+ ///
+ /// In en, this message translates to:
+ /// **'Add to calendar'**
+ String get calendarEventAddToCalendar;
+
+ /// No description provided for @calendarEventTitle.
+ ///
+ /// In en, this message translates to:
+ /// **'Closure of the Chaban Delmas bridge'**
+ String get calendarEventTitle;
+
+ /// No description provided for @calendarEventLocation.
+ ///
+ /// In en, this message translates to:
+ /// **'Bordeaux, Chaban Delmas bridge'**
+ String get calendarEventLocation;
+
+ /// No description provided for @calendarEventMaintenanceDescription.
+ ///
+ /// In en, this message translates to:
+ /// **'The Chaban bridge will close for maintenance 🛠. It will remains closed for {duration} 🌉'**
+ String calendarEventMaintenanceDescription(Object duration);
+
+ /// No description provided for @calendarEventBoatDescription.
+ ///
+ /// In en, this message translates to:
+ /// **'The Chaban bridge will close for {boat} 🚢. It will remains closed for {duration} 🌉'**
+ String calendarEventBoatDescription(Object boat, Object duration);
+
+ /// No description provided for @bottomSheetTitle_maintenance.
+ ///
+ /// In en, this message translates to:
+ /// **'Maintenance'**
+ String get bottomSheetTitle_maintenance;
+
+ /// No description provided for @bottomSheetTitle_boat.
+ ///
+ /// In en, this message translates to:
+ /// **'Passage of vessel(s)'**
+ String get bottomSheetTitle_boat;
+
+ /// No description provided for @bottomSheetAdditionalInfo_maintenance.
+ ///
+ /// In en, this message translates to:
+ /// **'The Chaban Bridge is closed for scheduled maintenance.'**
+ String get bottomSheetAdditionalInfo_maintenance;
+
+ /// No description provided for @bottomSheetAdditionalInfo_boatLeaving.
+ ///
+ /// In en, this message translates to:
+ /// **'leaving'**
+ String get bottomSheetAdditionalInfo_boatLeaving;
+
+ /// No description provided for @bottomSheetAdditionalInfo_boatArriving.
+ ///
+ /// In en, this message translates to:
+ /// **'arriving'**
+ String get bottomSheetAdditionalInfo_boatArriving;
+
+ /// No description provided for @bottomSheetAdditionalInfo_boatCrossingTimeDisclaimer.
+ ///
+ /// In en, this message translates to:
+ /// **'Arrival and departure times are for information purposes only and are not guaranteed.'**
+ String get bottomSheetAdditionalInfo_boatCrossingTimeDisclaimer;
+
+ /// No description provided for @bottomSheetAdditionalInfo_shareMessage.
+ ///
+ /// In en, this message translates to:
+ /// **'Hi, I\'m going to be late, the Chaban Bridge is closed until'**
+ String get bottomSheetAdditionalInfo_shareMessage;
}
class _AppLocalizationsDelegate
diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart
index b13a599b..9f2fa657 100644
--- a/lib/l10n/app_localizations_en.dart
+++ b/lib/l10n/app_localizations_en.dart
@@ -460,4 +460,50 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get noMoreForecastsMessage =>
'Bordeaux Métropole has not communicated any closure of the Chaban-Delmas Bridge for the coming weeks.\nStay informed of upcoming closures by returning here regularly';
+
+ @override
+ String get shareEventTitle => 'Share';
+
+ @override
+ String get calendarEventAddToCalendar => 'Add to calendar';
+
+ @override
+ String get calendarEventTitle => 'Closure of the Chaban Delmas bridge';
+
+ @override
+ String get calendarEventLocation => 'Bordeaux, Chaban Delmas bridge';
+
+ @override
+ String calendarEventMaintenanceDescription(Object duration) {
+ return 'The Chaban bridge will close for maintenance 🛠. It will remains closed for $duration 🌉';
+ }
+
+ @override
+ String calendarEventBoatDescription(Object boat, Object duration) {
+ return 'The Chaban bridge will close for $boat 🚢. It will remains closed for $duration 🌉';
+ }
+
+ @override
+ String get bottomSheetTitle_maintenance => 'Maintenance';
+
+ @override
+ String get bottomSheetTitle_boat => 'Passage of vessel(s)';
+
+ @override
+ String get bottomSheetAdditionalInfo_maintenance =>
+ 'The Chaban Bridge is closed for scheduled maintenance.';
+
+ @override
+ String get bottomSheetAdditionalInfo_boatLeaving => 'leaving';
+
+ @override
+ String get bottomSheetAdditionalInfo_boatArriving => 'arriving';
+
+ @override
+ String get bottomSheetAdditionalInfo_boatCrossingTimeDisclaimer =>
+ 'Arrival and departure times are for information purposes only and are not guaranteed.';
+
+ @override
+ String get bottomSheetAdditionalInfo_shareMessage =>
+ 'Hi, I\'m going to be late, the Chaban Bridge is closed until';
}
diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart
index 1721d53e..0f3d7d2c 100644
--- a/lib/l10n/app_localizations_es.dart
+++ b/lib/l10n/app_localizations_es.dart
@@ -127,7 +127,7 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get dialogInformationContentTime_of_crossing =>
- 'hora estimada de cruce';
+ 'hora de paso estimada';
@override
String get duration => 'Duración';
@@ -137,18 +137,18 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get errorScreenContentMessage =>
- 'Se produjo un error al abrir esta página. Encuentre la información técnica a continuación';
+ 'Se ha producido un error al abrir esta pàgina. Encuentre información técnica a continuación';
@override
String get errorScreenContentTechnical_Info => 'Información técnica';
@override
String get unableAppInfo =>
- 'No se puede obtener información de la aplicación';
+ 'No se puede recuperar la información de la aplicación';
@override
String get appDescription =>
- 'La aplicación móvil para obtener los horarios de cierre y apertura del puente Chaban Delmas ubicado en Bordeaux, Francia';
+ 'Aplicación móvil para obtener los horarios de cierre y apertura del puente Chaban-Delmas ubicado en Burdeos, Francia';
@override
String get informationAboutTheApp => 'Información sobre la aplicación';
@@ -158,10 +158,10 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get disclaimer =>
- 'Descargo de responsabilidad: cierres provisionales. Sujeto a confirmación de la Capitanía de Puerto.';
+ 'Aviso: cierres provisionales. Sujeto a confirmación de la Capitania de Puerto.';
@override
- String get openSetting => 'Ajustes';
+ String get openSetting => 'Configuración';
@override
String get themeSettingTitle => 'Tema';
@@ -176,7 +176,7 @@ class AppLocalizationsEs extends AppLocalizations {
String get darkTheme => 'Tema oscuro';
@override
- String get schedules => 'Programar';
+ String get schedules => 'Horarios';
@override
String get systemTheme => 'Tema del sistema';
@@ -186,7 +186,7 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get notificationsSubtitle =>
- 'Administre las notificaciones de la aplicación';
+ 'Administrar las notificaciones de la aplicación';
@override
String durationNotificationTitle(Object duration) {
@@ -215,30 +215,30 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String dayNotificationExplanation(Object day, Object time) {
- return 'Reciba una notificación el $day a las $time que enumere todos los cierres planeados para la próxima semana';
+ return 'Reciba una notificación el $day a las $time que enumere todos los cierres planificados para la próxima semana';
}
@override
- String get closingNotificationTitle => 'En el cierre';
+ String get closingNotificationTitle => 'Al cierre';
@override
String get closingNotificationExplanation =>
- 'Reciba una notificación cuando el puente cierre';
+ 'Reciba una notificación cuando el puente se cierra';
@override
String get notificationClosingChannelName => 'Cierre';
@override
- String get notificationClosingTitle => 'El puente Chaban ha cerrado ⛔';
+ String get notificationClosingTitle => 'El puente Chaban está cerrado ⛔';
@override
String notificationClosingBoatMessage(Object boat, Object duration) {
- return 'El puente Chaban acaba de cerrarse para $boat 🚢. Permanecerá cerrado durante $duration 🌉';
+ return 'El puente Chaban acaba de cerrarse para $boat 🚢. Permanecerà cerrado durante $duration 🌉';
}
@override
String notificationClosingMaintenanceMessage(Object duration) {
- return 'El puente Chaban acaba de cerrarse para mantenimiento 🛠. Permanecerá cerrado durante $duration 🌉';
+ return 'El puente Chaban acaba de cerrarse para mantenimiento 🛠. Permanecerà cerrado durante $duration 🌉';
}
@override
@@ -246,7 +246,7 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get openingNotificationExplanation =>
- 'Reciba una notificación cuando el puente abra';
+ 'Reciba una notificación cuando el puente se abre';
@override
String get notificationOpeningChannelName => 'Apertura';
@@ -256,7 +256,7 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get notificationOpeningMessage =>
- 'El puente Chaban acaba de abrirse al tráfico 🚲';
+ 'El puente Chaban acaba de abrirse al tràfico 🚲';
@override
String get monday => 'Lunes';
@@ -288,7 +288,7 @@ class AppLocalizationsEs extends AppLocalizations {
Object timeLeft,
Object duration,
) {
- return 'El puente Chaban cerrará en $timeLeft para $boat 🚢. Permanecerá cerrado durante $duration 🌉';
+ return 'El puente Chaban se cerrarà en $timeLeft para $boat 🚢. Permanecerà cerrado durante $duration 🌉';
}
@override
@@ -296,7 +296,7 @@ class AppLocalizationsEs extends AppLocalizations {
Object timeLeft,
Object duration,
) {
- return 'El puente Chaban cerrará en $timeLeft para mantenimiento 🛠. Permanecerá cerrado durante $duration 🌉';
+ return 'El puente Chaban se cerrarà en $timeLeft para mantenimiento 🛠. Permanecerà cerrado durante $duration 🌉';
}
@override
@@ -311,7 +311,7 @@ class AppLocalizationsEs extends AppLocalizations {
Object time,
Object duration,
) {
- return 'El puente Chaban cerrará mañana a las $time para $boat 🚢. Permanecerá cerrado durante $duration 🌉';
+ return 'El puente Chaban se cerrarà mañana a las $time para $boat 🚢. Permanecerà cerrado durante $duration 🌉';
}
@override
@@ -326,11 +326,11 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String notificationTimeMaintenanceMessage(Object time, Object duration) {
- return 'El puente Chaban cerrará mañana a las $time por mantenimiento 🛠. Permanecerá cerrado durante $duration 🌉';
+ return 'El puente Chaban se cerrarà mañana a las $time para mantenimiento 🛠. Permanecerà cerrado durante $duration 🌉';
}
@override
- String get notificationTimeChannelName => 'Cierres del próximo día';
+ String get notificationTimeChannelName => 'Cierres del dìa siguiente';
@override
String get passedClosure => 'Cierre pasado';
@@ -339,19 +339,19 @@ class AppLocalizationsEs extends AppLocalizations {
String selectAboutDialog(String choice) {
String _temp0 = intl.Intl.selectLogic(choice, {
'source_code': 'Código fuente',
- 'privacy_policy': 'Política de privacidad',
- 'yuhliet_instagram': 'Instagram de Yuhliet\'s',
- 'city_of_bordeaux': 'Ciudad de Bordeaux',
+ 'privacy_policy': 'Polìtica de privacidad',
+ 'yuhliet_instagram': 'Instagram de Yuhliet',
+ 'city_of_bordeaux': 'Ciudad de Burdeos',
'bordeaux_open_data': 'Bordeaux Open Data',
'licenses': 'Licencias',
'changelog': 'Registro de cambios',
- 'other': 'Undefined',
+ 'other': 'Indefinido',
});
return '$_temp0';
}
@override
- String get day => 'Día';
+ String get day => 'Dìa';
@override
String get notificationDayTitle => '🔮 Cierre programado';
@@ -361,27 +361,28 @@ class AppLocalizationsEs extends AppLocalizations {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
- other: 'La próxima semana, el puente Chaban Delmas cerrará $count veces',
- one: 'La próxima semana, el puente Chaban Delmas solo cerrará una vez',
- zero: 'No hay cierres programados para la próxima semana',
+ other:
+ 'La próxima semana, el puente Chaban-Delmas se cerrarà $count veces',
+ one: 'La próxima semana, el puente Chaban-Delmas solo se cerrarà una vez',
+ zero: 'Ningún cierre programado para la próxima semana',
);
return '$_temp0';
}
@override
- String get notificationDayChannelName => 'Cierres planificados';
+ String get notificationDayChannelName => 'Cierres programados';
@override
- String get leftHanded => 'Zurdo.a';
+ String get leftHanded => 'Zurdo';
@override
- String get rightHanded => 'Diestro.a';
+ String get rightHanded => 'Diestro';
@override
String get status => 'Estado';
@override
- String get statusLoadMessage => 'Carga del estado actual del puente';
+ String get statusLoadMessage => 'Cargando el estado actual del puente';
@override
String get loading => 'Cargando...';
@@ -409,21 +410,21 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get favoriteSlotsInterferenceWarning =>
- 'Este horario interfiere con uno o más intervalos de tiempo';
+ 'Este horario interfiere con uno o màs intervalos de tiempo';
@override
String get favoriteTimeSlotEnabledWarning =>
- 'Atención, al activar este parámetro solo recibirás notificaciones cuando ocurra un evento durante una de tus franjas horarias';
+ 'Atención, al activar este paràmetro solo recibiràs notificaciones cuando ocurra un evento durante una de tus franjas horarias';
@override
- String get favoriteSlotsChooseDay => 'Elegir los días de la semana';
+ String get favoriteSlotsChooseDay => 'Elegir los dìas de la semana';
@override
String moonHarborStatus(num count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
- other: 'están actualmente amarrados',
+ other: 'estàn actualmente amarrados',
one: 'está actualmente amarrado',
);
return '$_temp0 en el \'Puerto de la Luna\'';
@@ -434,7 +435,7 @@ class AppLocalizationsEs extends AppLocalizations {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
- other: 'buques están actualmente',
+ other: 'buques estàn actualmente',
one: 'barco está actualmente',
);
return '$count $_temp0 en Bordeaux';
@@ -464,5 +465,51 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get noMoreForecastsMessage =>
- 'Bordeaux Métropole no ha comunicado ningún cierre del Puente Chaban-Delmas para las próximas semanas.\nManténgase informado de los próximos cierres volviendo aquí regularmente';
+ 'Bordeaux Métropole no ha comunicado ningún cierre del Puente Chaban-Delmas para las próximas semanas.\nManténgase informado de los próximos cierres volviendo aquì regularmente';
+
+ @override
+ String get shareEventTitle => 'Compartir';
+
+ @override
+ String get calendarEventAddToCalendar => 'Añadir al calendario';
+
+ @override
+ String get calendarEventTitle => 'Cierre del puente Chaban Delmas';
+
+ @override
+ String get calendarEventLocation => 'Bordeaux, puente Chaban Delmas';
+
+ @override
+ String calendarEventMaintenanceDescription(Object duration) {
+ return '\"El puente Chaban permanecerá cerrado para mantenimiento 🛠. Permanecerà cerrado durante $duration 🌉';
+ }
+
+ @override
+ String calendarEventBoatDescription(Object boat, Object duration) {
+ return 'El puente Chaban permanecerá cerrado para $boat 🚢. Permanecerà cerrado durante $duration 🌉';
+ }
+
+ @override
+ String get bottomSheetTitle_maintenance => 'Mantenimiento';
+
+ @override
+ String get bottomSheetTitle_boat => 'Paso de la(s) embarcación(es)';
+
+ @override
+ String get bottomSheetAdditionalInfo_maintenance =>
+ 'El puente Chaban está cerrado por mantenimiento programado.';
+
+ @override
+ String get bottomSheetAdditionalInfo_boatLeaving => 'llegada';
+
+ @override
+ String get bottomSheetAdditionalInfo_boatArriving => 'partida';
+
+ @override
+ String get bottomSheetAdditionalInfo_boatCrossingTimeDisclaimer =>
+ 'Los horarios de llegada y salida son únicamente a título informativo y no están garantizados.';
+
+ @override
+ String get bottomSheetAdditionalInfo_shareMessage =>
+ 'Hola, voy a llegar tarde; el puente Chaban está cerrado hasta';
}
diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart
index 8974df52..fe99156c 100644
--- a/lib/l10n/app_localizations_fr.dart
+++ b/lib/l10n/app_localizations_fr.dart
@@ -136,28 +136,28 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get errorScreenContentMessage =>
- 'Une erreur est survenue lors de l\'ouverture de cette page. Veuillez trouver les informations techniques ci-dessous';
+ 'Une erreur est survenue lors de l\'ouverture de cette page. Vous trouverez des informations techniques ci-dessous';
@override
String get errorScreenContentTechnical_Info => 'Informations techniques';
@override
String get unableAppInfo =>
- 'Impossible d\'obtenir les informations de l\'application';
+ 'Impossible de récupérer les informations de l\'application';
@override
String get appDescription =>
- 'L\'application Mobile pour connaître les horaires de fermeture et d\'ouverture du pont Chaban Delmas situé à Bordeaux, France';
+ 'Application mobile pour obtenir les horaires de fermeture et d\'ouverture du pont Chaban-Delmas situé à Bordeaux, France';
@override
- String get informationAboutTheApp => 'Informations concernant l\'application';
+ String get informationAboutTheApp => 'Informations sur l\'application';
@override
String get about => 'À propos';
@override
String get disclaimer =>
- 'Avis de non-responsabilité : fermetures provisoires. Sous réserve de confirmation de la Capitainerie.';
+ 'Avertissement : fermetures provisoires. Sous réserve de confirmation de la Capitainerie.';
@override
String get openSetting => 'Paramètres';
@@ -166,7 +166,7 @@ class AppLocalizationsFr extends AppLocalizations {
String get themeSettingTitle => 'Thème';
@override
- String get themeSettingSubTitle => 'Changer l\'apparence de l\'application';
+ String get themeSettingSubTitle => 'Modifier l\'apparence de l\'application';
@override
String get lightTheme => 'Thème clair';
@@ -175,7 +175,7 @@ class AppLocalizationsFr extends AppLocalizations {
String get darkTheme => 'Thème sombre';
@override
- String get schedules => 'Calendrier';
+ String get schedules => 'Plannings';
@override
String get systemTheme => 'Thème système';
@@ -194,7 +194,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String durationNotificationExplanation(Object duration) {
- return 'Recevoir une notification ${duration}avant la prochaine fermeture. Cette valeur gère aussi le changement de couleur du statut actuel';
+ return 'Recevez une notification ${duration}avant la prochaine fermeture. Cette valeur gère également le changement de couleur de l\'état actuel';
}
@override
@@ -204,17 +204,17 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String timeNotificationExplanation(Object time) {
- return 'Recevoir une notification la veille à $time si une fermeture est prévue le lendemain';
+ return 'Recevez une notification la veille à $time si une fermeture est prévue le lendemain';
}
@override
String dayNotificationTitle(Object day) {
- return 'Récap hebdo le $day';
+ return 'Récapitulatif hebdomadaire le $day';
}
@override
String dayNotificationExplanation(Object day, Object time) {
- return 'Recevoir une notification le $day à $time listant toutes les fermetures prévues pour la semaine qui arrive';
+ return 'Recevez une notification le $day à $time listant toutes les fermetures prévues pour la semaine à venir';
}
@override
@@ -222,7 +222,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get closingNotificationExplanation =>
- 'Recevoir une notification quand le pont ferme à la circulation';
+ 'Recevez une notification lorsque le pont se ferme';
@override
String get notificationClosingChannelName => 'Fermeture';
@@ -232,12 +232,12 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String notificationClosingBoatMessage(Object boat, Object duration) {
- return 'Le pont Chaban vient de fermer pour $boat 🚢. Il restera fermé pendant $duration 🌉';
+ return 'Le pont Chaban vient de se fermer pour $boat 🚢. Il restera fermé pendant $duration 🌉';
}
@override
String notificationClosingMaintenanceMessage(Object duration) {
- return 'Le pont Chaban vient de fermer pour maintenance 🛠. Il restera fermé pendant $duration 🌉';
+ return 'Le pont Chaban vient de se fermer pour maintenance 🛠. Il restera fermé pendant $duration 🌉';
}
@override
@@ -245,7 +245,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get openingNotificationExplanation =>
- 'Recevoir une notification quand le pont ouvre à la circulation';
+ 'Recevez une notification lorsque le pont s\'ouvre';
@override
String get notificationOpeningChannelName => 'Ouverture';
@@ -255,7 +255,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get notificationOpeningMessage =>
- 'Le pont Chaban vient de rouvir à la circulation 🚲';
+ 'Le pont Chaban vient de s\'ouvrir à la circulation 🚲';
@override
String get monday => 'Lundi';
@@ -279,7 +279,7 @@ class AppLocalizationsFr extends AppLocalizations {
String get sunday => 'Dimanche';
@override
- String get notificationDurationTitle => 'Fermeture imminante ⚠️';
+ String get notificationDurationTitle => 'Fermeture imminente ⚠️';
@override
String notificationDurationBoatMessage(
@@ -287,7 +287,7 @@ class AppLocalizationsFr extends AppLocalizations {
Object timeLeft,
Object duration,
) {
- return 'Le pont Chaban fermera dans $timeLeft pour $boat 🚢. Il restera fermé pendant $duration 🌉';
+ return 'Le pont Chaban va se fermer dans $timeLeft pour $boat 🚢. Il restera fermé pendant $duration 🌉';
}
@override
@@ -339,11 +339,11 @@ class AppLocalizationsFr extends AppLocalizations {
String _temp0 = intl.Intl.selectLogic(choice, {
'source_code': 'Code source',
'privacy_policy': 'Politique de confidentialité',
- 'yuhliet_instagram': 'Instagram de Yuhliet\'s',
+ 'yuhliet_instagram': 'Instagram de Yuhliet',
'city_of_bordeaux': 'Ville de Bordeaux',
'bordeaux_open_data': 'Bordeaux Open Data',
- 'changelog': 'Journal des modifications',
'licenses': 'Licences',
+ 'changelog': 'Journal des modifications',
'other': 'Undefined',
});
return '$_temp0';
@@ -361,10 +361,10 @@ class AppLocalizationsFr extends AppLocalizations {
count,
locale: localeName,
other:
- 'La semaine prochaine, le pont Chaban Delmas fermera à $count reprises',
+ 'La semaine prochaine, le pont Chaban-Delmas se fermera $count fois',
one:
- 'La semaine prochaine, le pont Chaban Delmas ne fermera qu\'une seul fois',
- zero: 'Aucune fermetures de prévue pour la semaine prochaine',
+ 'La semaine prochaine, le pont Chaban-Delmas ne se fermera qu\'une seule fois',
+ zero: 'Aucune fermeture prévue pour la semaine prochaine',
);
return '$_temp0';
}
@@ -466,4 +466,50 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get noMoreForecastsMessage =>
'Bordeaux Métropole n\'a communiqué aucune fermeture du Pont Chaban-Delmas pour les prochaines semaines.\nTenez-vous informer des prochaines fermetures en revenant ici régulièrement';
+
+ @override
+ String get shareEventTitle => 'Partager';
+
+ @override
+ String get calendarEventAddToCalendar => 'Ajouter au calendrier';
+
+ @override
+ String get calendarEventTitle => 'Fermeture du pont Chaban Delmas';
+
+ @override
+ String get calendarEventLocation => 'Bordeaux, pont Chaban Delmas';
+
+ @override
+ String calendarEventMaintenanceDescription(Object duration) {
+ return 'Le pont Chaban sera fermé pour maintenance 🛠. Il restera fermé pendant $duration 🌉';
+ }
+
+ @override
+ String calendarEventBoatDescription(Object boat, Object duration) {
+ return 'Le pont Chaban sera pour $boat 🚢. Il restera fermé pendant $duration 🌉';
+ }
+
+ @override
+ String get bottomSheetTitle_maintenance => 'Maintenance';
+
+ @override
+ String get bottomSheetTitle_boat => 'Passage de navire(s)';
+
+ @override
+ String get bottomSheetAdditionalInfo_maintenance =>
+ 'Le pont Chaban est fermé pour maintenance planifiée.';
+
+ @override
+ String get bottomSheetAdditionalInfo_boatLeaving => 'arrivée';
+
+ @override
+ String get bottomSheetAdditionalInfo_boatArriving => 'départ';
+
+ @override
+ String get bottomSheetAdditionalInfo_boatCrossingTimeDisclaimer =>
+ 'Les heures d\'arrivées et de départs sont purement à des fins indicatives et ne sont pas garanties.';
+
+ @override
+ String get bottomSheetAdditionalInfo_shareMessage =>
+ 'Salut, je vais avoir du retard, le Pont Chaban est fermé jusqu\'à';
}
diff --git a/lib/models/abstract_forecast.dart b/lib/models/abstract_forecast.dart
index 1e4edc06..0d6097c7 100644
--- a/lib/models/abstract_forecast.dart
+++ b/lib/models/abstract_forecast.dart
@@ -65,8 +65,6 @@ abstract class AbstractForecast extends Equatable {
_circulationClosingDate = value;
}
- RichText getInformationWidget(BuildContext context);
-
List getCoreInformationWidget(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final timeFormat = context.read().state.timeFormat;
@@ -164,6 +162,12 @@ abstract class AbstractForecast extends Equatable {
String getNotificationClosingMessage(BuildContext context);
+ String getCalendarEventClosingDescription(BuildContext context);
+
+ Widget getDetailedInfo(BuildContext context);
+
+ String getBottomSheetTitle(BuildContext context);
+
String getClosingReason(BuildContext context);
Color getColor(BuildContext context, bool reversed);
diff --git a/lib/models/boat.dart b/lib/models/boat.dart
index 9d83210f..a73f0d42 100644
--- a/lib/models/boat.dart
+++ b/lib/models/boat.dart
@@ -37,14 +37,13 @@ class Boat extends Equatable {
baseURL.replaceAll(Const.vesselFinderLinkPlaceholder, name),
),
text: text,
- style: TextStyle(
+ style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.bold,
color: colored
? isWineFestivalSailBoats
? Theme.of(context).colorScheme.bordeauxColor
: Theme.of(context).colorScheme.boatColor
: Theme.of(context).colorScheme.surface,
- decoration: TextDecoration.underline,
),
);
}
diff --git a/lib/models/boat_forecast.dart b/lib/models/boat_forecast.dart
index e5ba5f8f..f4299a58 100644
--- a/lib/models/boat_forecast.dart
+++ b/lib/models/boat_forecast.dart
@@ -3,7 +3,6 @@ import 'package:chabo_app/cubits/time_format_cubit.dart';
import 'package:chabo_app/extensions/boats_extension.dart';
import 'package:chabo_app/extensions/color_scheme_extension.dart';
import 'package:chabo_app/extensions/duration_extension.dart';
-import 'package:chabo_app/extensions/string_extension.dart';
import 'package:chabo_app/l10n/app_localizations.dart';
import 'package:chabo_app/models/abstract_forecast.dart';
import 'package:chabo_app/models/boat.dart';
@@ -96,45 +95,6 @@ class BoatForecast extends AbstractForecast {
closingType,
];
- @override
- RichText getInformationWidget(BuildContext context) {
- final timeFormat = context.read().state.timeFormat;
- final colorScheme = Theme.of(context).colorScheme;
-
- var schedule = circulationClosingDate.add(
- Duration(microseconds: closedDuration.inMicroseconds ~/ 2),
- );
- var scheduleString = intl.DateFormat(
- timeFormat.icuName,
- Localizations.localeOf(context).languageCode,
- ).format(schedule);
- if (isDuringTwoDays) {
- scheduleString =
- '${MaterialLocalizations.of(context).formatMediumDate(schedule)} ${AppLocalizations.of(context)!.at} ${intl.DateFormat(timeFormat.icuName, Localizations.localeOf(context).languageCode).format(schedule)}';
- }
-
- return RichText(
- text: TextSpan(
- style: Theme.of(context).textTheme.bodyLarge?.copyWith(height: 1.6),
- children: [
- ...getCoreInformationWidget(context),
- boats.toLocalizedTextSpan(context),
- TextSpan(
- text:
- '\n\n${AppLocalizations.of(context)!.dialogInformationContentTime_of_crossing.capitalize()} : ',
- ),
- TextSpan(
- text: scheduleString,
- style: TextStyle(
- fontWeight: FontWeight.bold,
- color: colorScheme.timeColor,
- ),
- ),
- ],
- ),
- );
- }
-
@override
String getNotificationDurationMessage(
BuildContext context,
@@ -165,6 +125,102 @@ class BoatForecast extends AbstractForecast {
);
}
+ @override
+ String getCalendarEventClosingDescription(BuildContext context) {
+ return AppLocalizations.of(context)!.calendarEventBoatDescription(
+ boats.toLocalizedString(context),
+ closedDuration.durationToString(context),
+ );
+ }
+
+ List _generateCrossingTimes(DateTime t, int n, int p) {
+ // Calculate the step in seconds
+ int stepInSeconds = p;
+
+ // Generate the list of times
+ List result = [];
+ for (int i = 0; i < n; i++) {
+ // Calculate the offset for the current time in seconds
+ double offset = (i - (n - 1) / 2.0) * stepInSeconds;
+ int offsetInSeconds = offset.round();
+
+ // Create a new DateTime by adding the offset
+ DateTime newTime = t.add(Duration(seconds: offsetInSeconds));
+
+ // Format the time as HH:MM:SS (or HH:MM if seconds are zero)
+ String formattedTime =
+ '${newTime.hour.toString().padLeft(2, '0')}h'
+ '${newTime.minute.toString().padLeft(2, '0')}';
+
+ result.add(formattedTime);
+ }
+
+ return result;
+ }
+
+ @override
+ Widget getDetailedInfo(BuildContext context) {
+ var halfDuration = Duration(seconds: closedDuration.inSeconds ~/ 2);
+ var medianTime = circulationClosingDate.add(halfDuration);
+ var crossingTimes = _generateCrossingTimes(medianTime, boats.length, 1800);
+ return Column(
+ spacing: 13,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ spacing: 3,
+ children: boats.asMap().entries.map((elem) {
+ final boat = elem.value;
+ final index = elem.key;
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ RichText(text: boat.toLocalizedTextSpan(context, true)),
+ Row(
+ spacing: 5,
+ children: [
+ Text(
+ boat.isLeaving
+ ? AppLocalizations.of(
+ context,
+ )!.bottomSheetAdditionalInfo_boatArriving
+ : AppLocalizations.of(
+ context,
+ )!.bottomSheetAdditionalInfo_boatLeaving,
+ style: Theme.of(context).textTheme.labelSmall?.copyWith(
+ fontStyle: FontStyle.italic,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ Text('- ${crossingTimes[index]}'),
+ ],
+ ),
+ ],
+ );
+ }).toList(),
+ ),
+ Text(
+ AppLocalizations.of(
+ context,
+ )!.bottomSheetAdditionalInfo_boatCrossingTimeDisclaimer,
+ textAlign: TextAlign.center,
+ style: Theme.of(context).textTheme.labelSmall?.copyWith(
+ fontStyle: FontStyle.italic,
+ color: Theme.of(
+ context,
+ ).colorScheme.inverseSurface.withValues(alpha: .4),
+ ),
+ ),
+ ],
+ );
+ }
+
+ @override
+ String getBottomSheetTitle(BuildContext context) {
+ return AppLocalizations.of(context)!.bottomSheetTitle_boat;
+ }
+
@override
Widget getIconWidget(
BuildContext context,
diff --git a/lib/models/maintenance_forecast.dart b/lib/models/maintenance_forecast.dart
index 5e1e176a..937df129 100644
--- a/lib/models/maintenance_forecast.dart
+++ b/lib/models/maintenance_forecast.dart
@@ -94,28 +94,24 @@ class MaintenanceForecast extends AbstractForecast {
}
@override
- RichText getInformationWidget(BuildContext context) {
- final colorScheme = Theme.of(context).colorScheme;
+ String getCalendarEventClosingDescription(BuildContext context) {
+ return AppLocalizations.of(context)!.calendarEventMaintenanceDescription(
+ closedDuration.durationToString(context),
+ );
+ }
- return RichText(
- text: TextSpan(
- style: Theme.of(context).textTheme.bodyLarge?.copyWith(height: 1.6),
- children: [
- ...getCoreInformationWidget(context),
- TextSpan(
- text: AppLocalizations.of(
- context,
- )!.dialogInformationContentBridge_closed_maintenance,
- style: TextStyle(
- color: colorScheme.maintenanceColor,
- fontWeight: FontWeight.bold,
- ),
- ),
- ],
- ),
+ @override
+ Widget getDetailedInfo(BuildContext context) {
+ return Text(
+ AppLocalizations.of(context)!.bottomSheetAdditionalInfo_maintenance,
);
}
+ @override
+ String getBottomSheetTitle(BuildContext context) {
+ return AppLocalizations.of(context)!.bottomSheetTitle_maintenance;
+ }
+
@override
Widget getIconWidget(
BuildContext context,
diff --git a/lib/screens/about_screen/about_screen.dart b/lib/screens/about_screen/about_screen.dart
index a10bb080..a8afcfed 100644
--- a/lib/screens/about_screen/about_screen.dart
+++ b/lib/screens/about_screen/about_screen.dart
@@ -88,10 +88,11 @@ class AboutScreen extends StatelessWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
- Flexible(
+ Expanded(
child: IconTheme(
data: Theme.of(context).iconTheme,
child: Row(
+ spacing: 20,
children: [
Container(
decoration: BoxDecoration(
@@ -106,36 +107,32 @@ class AboutScreen extends StatelessWidget {
),
child: iconWidget,
),
- Padding(
- padding: const EdgeInsets.symmetric(
- horizontal: 16.0,
- ),
+ Flexible(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
- Row(
- children: [
- Text(
- snapshot.data!.appName,
- style: Theme.of(context)
- .textTheme
- .headlineSmall!
- .copyWith(
- fontWeight: FontWeight.bold,
- fontSize: 30,
- ),
- ),
- Text(
- ' | ${_formatBetaVersion(snapshot.data!.version)} (${snapshot.data!.buildNumber})',
- style: textTheme.bodyMedium,
- ),
- ],
+ Text(
+ snapshot.data!.appName,
+ style: Theme.of(context)
+ .textTheme
+ .headlineSmall!
+ .copyWith(
+ fontWeight: FontWeight.bold,
+ fontSize: 35,
+ ),
+ ),
+ Text(
+ '${_formatBetaVersion(snapshot.data!.version)} (${snapshot.data!.buildNumber})',
+ style: textTheme.bodyMedium?.copyWith(
+ overflow: TextOverflow.fade,
+ ),
),
+ Divider(),
Text(
Const.legalLease,
- style: textTheme.bodySmall!.copyWith(),
+ style: textTheme.labelSmall!.copyWith(),
),
],
),
diff --git a/lib/screens/notification_screen/custom_list_tile_widget.dart b/lib/screens/notification_screen/custom_list_tile_widget.dart
index 876f9b81..9ddbf11c 100644
--- a/lib/screens/notification_screen/custom_list_tile_widget.dart
+++ b/lib/screens/notification_screen/custom_list_tile_widget.dart
@@ -33,83 +33,88 @@ class _CustomListTileWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SimpleContainer(
- child: ListTile(
- title: Row(
- mainAxisAlignment: MainAxisAlignment.start,
- children: [
- Flexible(
- flex: 10,
- child: Text(
- title,
- style: Theme.of(
- context,
- ).textTheme.titleLarge?.copyWith(fontSize: 19),
- overflow: TextOverflow.fade,
+ child: Material(
+ // Fix "The ListTile is wrapped in a DecoratedBox that has a background colo..."
+ type: MaterialType.transparency,
+ child: ListTile(
+ title: Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Flexible(
+ flex: 10,
+ child: Text(
+ title,
+ style: Theme.of(
+ context,
+ ).textTheme.titleLarge?.copyWith(fontSize: 19),
+ overflow: TextOverflow.fade,
+ ),
),
- ),
- const SizedBox(width: 10),
- Flexible(
- child: AnimatedSwitcher(
- duration: const Duration(
- milliseconds: CustomProperties.animationDurationMs,
+ const SizedBox(width: 10),
+ Flexible(
+ child: AnimatedSwitcher(
+ duration: const Duration(
+ milliseconds: CustomProperties.animationDurationMs,
+ ),
+ transitionBuilder:
+ (Widget child, Animation animation) {
+ return FadeTransition(
+ opacity: CurvedAnimation(
+ parent: animation,
+ curve: Curves.easeIn,
+ ),
+ child: SlideTransition(
+ position: Tween(
+ begin: const Offset(-1.0, 0.0),
+ end: const Offset(0.0, 0.0),
+ ).animate(animation),
+ child: child,
+ ),
+ );
+ },
+ child: constrainedBySlots && enabled
+ ? CircleAvatar(
+ radius: 5,
+ backgroundColor: Theme.of(
+ context,
+ ).colorScheme.warningColor,
+ child: Container(),
+ )
+ : const SizedBox(),
),
- transitionBuilder: (Widget child, Animation animation) {
- return FadeTransition(
- opacity: CurvedAnimation(
- parent: animation,
- curve: Curves.easeIn,
- ),
- child: SlideTransition(
- position: Tween(
- begin: const Offset(-1.0, 0.0),
- end: const Offset(0.0, 0.0),
- ).animate(animation),
- child: child,
+ ),
+ ],
+ ),
+ subtitle: Text(subtitle),
+ leading: Icon(leadingIcon),
+ onTap: onTap,
+ trailing: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ onTap != null
+ ? const VerticalDivider(width: 20)
+ : const SizedBox.shrink(),
+ Switch.adaptive(
+ thumbIcon: thumbIcon,
+ value: enabled,
+ onChanged: (value) {
+ Sentry.addBreadcrumb(
+ Breadcrumb(
+ message: 'Change "$title" state',
+ level: SentryLevel.info,
+ category: 'notification.change-state',
+ type: 'Notification',
+ data: {'old-state': !value, 'new-state': value},
),
);
+ onChanged(value);
},
- child: constrainedBySlots && enabled
- ? CircleAvatar(
- radius: 5,
- backgroundColor: Theme.of(
- context,
- ).colorScheme.warningColor,
- child: Container(),
- )
- : const SizedBox(),
),
- ),
- ],
- ),
- subtitle: Text(subtitle),
- leading: Icon(leadingIcon),
- onTap: onTap,
- trailing: Row(
- mainAxisSize: MainAxisSize.min,
- children: [
- onTap != null
- ? const VerticalDivider(width: 20)
- : const SizedBox.shrink(),
- Switch.adaptive(
- thumbIcon: thumbIcon,
- value: enabled,
- onChanged: (value) {
- Sentry.addBreadcrumb(
- Breadcrumb(
- message: 'Change "$title" state',
- level: SentryLevel.info,
- category: 'notification.change-state',
- type: 'Notification',
- data: {'old-state': !value, 'new-state': value},
- ),
- );
- onChanged(value);
- },
- ),
- ],
+ ],
+ ),
+ iconColor: iconColor ?? Theme.of(context).colorScheme.primary,
+ enabled: enabled,
),
- iconColor: iconColor ?? Theme.of(context).colorScheme.primary,
- enabled: enabled,
),
);
}
diff --git a/lib/service/event_share_service.dart b/lib/service/event_share_service.dart
new file mode 100644
index 00000000..fc20fcbf
--- /dev/null
+++ b/lib/service/event_share_service.dart
@@ -0,0 +1,51 @@
+import 'package:chabo_app/const.dart';
+import 'package:chabo_app/cubits/time_format_cubit.dart';
+import 'package:chabo_app/l10n/app_localizations.dart';
+import 'package:chabo_app/models/abstract_forecast.dart';
+import 'package:chabo_app/models/enums/time_format.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:intl/intl.dart';
+import 'package:share_plus/share_plus.dart';
+import 'package:add_2_calendar/add_2_calendar.dart';
+
+class EventShareService {
+ /// Add the forecast event to the user's calendar
+ static Future addToCalendar(
+ BuildContext context,
+ AbstractForecast forecast,
+ ) async {
+ final localizations = AppLocalizations.of(context)!;
+ // Create the event
+ final event = Event(
+ title: localizations.calendarEventTitle,
+ description: forecast.getCalendarEventClosingDescription(context),
+ location: localizations.calendarEventLocation,
+ startDate: forecast.circulationClosingDate,
+ endDate: forecast.circulationReOpeningDate,
+ allDay: false,
+ );
+
+ return Add2Calendar.addEvent2Cal(event);
+ }
+
+ /// Share the forecast event via messaging apps
+ static Future shareEvent(
+ BuildContext context,
+ AbstractForecast forecast,
+ ) async {
+ final timeFormat = context.read().state.timeFormat;
+ final languageCode = Localizations.localeOf(context).languageCode;
+ var stringDate = DateFormat(
+ timeFormat.icuName,
+ languageCode,
+ ).format(forecast.circulationReOpeningDate);
+ final ShareParams shareParams = ShareParams(
+ title: Const.appName,
+ text:
+ '${AppLocalizations.of(context)!.bottomSheetAdditionalInfo_shareMessage} $stringDate',
+ );
+
+ await SharePlus.instance.share(shareParams);
+ }
+}
diff --git a/lib/widgets/bottom_sheets/forecast_information_bottom_sheet.dart b/lib/widgets/bottom_sheets/forecast_information_bottom_sheet.dart
index abcda09d..355777b3 100644
--- a/lib/widgets/bottom_sheets/forecast_information_bottom_sheet.dart
+++ b/lib/widgets/bottom_sheets/forecast_information_bottom_sheet.dart
@@ -1,9 +1,13 @@
+import 'package:chabo_app/custom_properties.dart';
import 'package:chabo_app/extensions/color_scheme_extension.dart';
+import 'package:chabo_app/extensions/date_time_extension.dart';
import 'package:chabo_app/helpers/custom_page_routes.dart';
import 'package:chabo_app/l10n/app_localizations.dart';
import 'package:chabo_app/models/abstract_forecast.dart';
import 'package:chabo_app/screens/notification_screen/notification_screen.dart';
+import 'package:chabo_app/service/event_share_service.dart';
import 'package:flutter/material.dart';
+import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
class ForecastInformationBottomSheet extends StatefulWidget {
@@ -27,9 +31,7 @@ class _ForecastInformationBottomSheetState
@override
void initState() {
super.initState();
-
_controller = AnimationController(duration: _duration, vsync: this);
-
_controller.forward();
}
@@ -39,13 +41,12 @@ class _ForecastInformationBottomSheetState
super.dispose();
}
- /// convert 0-1 to 0-1-0
- double shake(double animation) =>
- 2 * (0.5 - (0.5 - Curves.bounceOut.transform(animation)).abs());
-
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
+ final textTheme = Theme.of(context).textTheme;
+ final appLocalization = AppLocalizations.of(context);
+ final warning = widget.forecast.interferingTimeSlots.isNotEmpty;
Sentry.addBreadcrumb(
Breadcrumb(
@@ -58,100 +59,266 @@ class _ForecastInformationBottomSheetState
);
return Padding(
- padding: const EdgeInsets.symmetric(horizontal: 20.0),
+ padding: const EdgeInsets.symmetric(horizontal: 25.0, vertical: 25),
child: Column(
mainAxisSize: MainAxisSize.min,
+ spacing: 20,
children: [
- if (widget.forecast.interferingTimeSlots.isNotEmpty)
- Flexible(
- child: Padding(
- padding: const EdgeInsets.symmetric(vertical: 10),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- Icon(
- Icons.warning_rounded,
- size: 25,
- color: colorScheme.warningColor,
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ ScaleTransition(
+ scale: _tween.animate(
+ CurvedAnimation(
+ parent: _controller,
+ curve: Curves.elasticOut,
+ ),
+ ),
+ child: widget.forecast.getIconWidget(context, false, 20, true),
+ ),
+ const SizedBox(width: 10),
+ Expanded(
+ child: Text(
+ widget.forecast.getBottomSheetTitle(context),
+ style: textTheme.titleLarge,
+ ),
+ ),
+ ],
+ ),
+ if (warning) _TimeSlotWarning(tween: _tween, duration: _duration),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ _TimeWidget(
+ isWarning: warning,
+ date: widget.forecast.circulationClosingDate
+ .toLocalizedTextSpan(
+ context,
+ Theme.of(context).textTheme.headlineLarge?.copyWith(
+ color: colorScheme.error,
+ ),
),
- const SizedBox(width: 10),
- Flexible(
- child: Text(
- AppLocalizations.of(
- context,
- )!.favoriteSlotsInterferenceWarning,
- overflow: TextOverflow.clip,
- style: Theme.of(context).textTheme.bodyMedium?.copyWith(
- color: colorScheme.warningColor,
- ),
+ text: appLocalization!.circulationClosing.toUpperCase(),
+ ),
+ FaIcon(FontAwesomeIcons.arrowRight, size: 20),
+ _TimeWidget(
+ isWarning: warning,
+ date: widget.forecast.circulationReOpeningDate
+ .toLocalizedTextSpan(
+ context,
+ Theme.of(context).textTheme.headlineLarge?.copyWith(
+ color: colorScheme.primary,
),
),
- const SizedBox(width: 10),
- ElevatedButton(
- style: ButtonStyle(
- backgroundColor: WidgetStateProperty.all(
- colorScheme.warningColor,
- ),
- foregroundColor: WidgetStateProperty.all(
- colorScheme.surface,
- ),
+ text: appLocalization.circulationReOpening.toUpperCase(),
+ ),
+ ],
+ ),
+ Column(
+ spacing: 15,
+ children: [
+ Container(
+ padding: EdgeInsets.symmetric(vertical: 10, horizontal: 14),
+ width: double.infinity,
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: colorScheme.surfaceContainerHigh,
+ width: 3,
+ ),
+ borderRadius: BorderRadius.circular(
+ CustomProperties.borderRadius,
+ ),
+ ),
+ child: widget.forecast.getDetailedInfo(context),
+ ),
+ SizedBox(
+ width: double.infinity,
+ height: 60,
+ child: ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ backgroundColor: widget.forecast.getColor(context, false),
+ foregroundColor: widget.forecast.getColor(context, true),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(
+ Radius.circular(CustomProperties.borderRadius),
),
- onPressed: () => {
- Navigator.of(context).pop(),
- Navigator.of(context).push(
- LeftToRightPageRoute(
- builder: (context) => const NotificationScreen(
- highlightTimeSlots: true,
- ),
- settings: const RouteSettings(
- name: NotificationScreen.routeName,
- ),
- ),
+ ),
+ ),
+ onPressed: () =>
+ EventShareService.addToCalendar(context, widget.forecast),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ spacing: 20,
+ children: [
+ const FaIcon(FontAwesomeIcons.calendarPlus, size: 20),
+ Text(
+ appLocalization.calendarEventAddToCalendar,
+ style: textTheme.titleMedium?.copyWith(
+ color: widget.forecast.getColor(context, true),
),
- },
- child: TweenAnimationBuilder(
- tween: _tween,
- duration: _duration,
- builder: (context, animation, child) =>
- Transform.translate(
- offset: Offset(20 * shake(animation), 0),
- child: child,
- ),
- child: const Icon(Icons.notifications_active),
),
- ),
- ],
+ ],
+ ),
),
),
- ),
- Padding(
- padding: const EdgeInsets.symmetric(vertical: 30),
- child: Row(
- mainAxisSize: MainAxisSize.max,
- crossAxisAlignment: CrossAxisAlignment.start,
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- ScaleTransition(
- scale: _tween.animate(
- CurvedAnimation(
- parent: _controller,
- curve: Curves.elasticOut,
+ SizedBox(
+ width: double.infinity,
+ height: 60,
+ child: OutlinedButton(
+ style: OutlinedButton.styleFrom(
+ foregroundColor: widget.forecast.getColor(context, false),
+ side: BorderSide(
+ width: 3,
+ color: widget.forecast.getColor(context, false),
),
- ),
- child: CircleAvatar(
- radius: 35,
- backgroundColor: widget.forecast.getColor(context, false),
- child: widget.forecast.getIconWidget(
- context,
- true,
- 33,
- true,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(
+ Radius.circular(CustomProperties.borderRadius),
+ ),
),
),
+ onPressed: () =>
+ EventShareService.shareEvent(context, widget.forecast),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ spacing: 20,
+ children: [
+ const FaIcon(FontAwesomeIcons.shareNodes, size: 20),
+ Text(
+ appLocalization.shareEventTitle,
+ style: textTheme.titleMedium?.copyWith(
+ color: widget.forecast.getColor(context, false),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class _TimeWidget extends StatelessWidget {
+ final TextSpan date;
+ final String text;
+ final bool isWarning;
+
+ const _TimeWidget({
+ required this.date,
+ required this.text,
+ required this.isWarning,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ final colorScheme = Theme.of(context).colorScheme;
+ final textTheme = Theme.of(context).textTheme;
+ return Container(
+ padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 5),
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(CustomProperties.borderRadius),
+ border: Border.all(
+ color: isWarning
+ ? colorScheme.warningColor.withValues(alpha: 0.5)
+ : Colors.transparent,
+ width: 3,
+ ),
+ color: colorScheme.surfaceContainerHigh,
+ ),
+ child: SizedBox(
+ height: 70,
+ width: 150,
+ child: Stack(
+ children: [
+ Positioned(
+ top: 2,
+ left: 15,
+ child: Text(
+ text,
+ style: textTheme.labelLarge?.copyWith(
+ fontWeight: FontWeight.bold,
+ color: colorScheme.onPrimaryContainer,
+ ),
+ ),
+ ),
+ Positioned(top: 30, left: 15, child: RichText(text: date)),
+ ],
+ ),
+ ),
+ );
+ }
+}
+
+class _TimeSlotWarning extends StatelessWidget {
+ final Tween tween;
+ final Duration duration;
+
+ const _TimeSlotWarning({required this.tween, required this.duration});
+
+ /// convert 0-1 to 0-1-0
+ double shake(double animation) =>
+ 2 * (0.5 - (0.5 - Curves.bounceOut.transform(animation)).abs());
+
+ @override
+ Widget build(BuildContext context) {
+ final colorScheme = Theme.of(context).colorScheme;
+ final textTheme = Theme.of(context).textTheme;
+
+ return Flexible(
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Icon(
+ Icons.warning_rounded,
+ size: 25,
+ color: colorScheme.warningColor,
+ ),
+ const SizedBox(width: 10),
+ Flexible(
+ child: Text(
+ AppLocalizations.of(context)!.favoriteSlotsInterferenceWarning,
+ overflow: TextOverflow.clip,
+ style: textTheme.labelLarge?.copyWith(
+ color: colorScheme.warningColor,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ),
+ const SizedBox(width: 10),
+ ElevatedButton(
+ style: ButtonStyle(
+ backgroundColor: WidgetStateProperty.all(
+ colorScheme.warningColor,
+ ),
+ foregroundColor: WidgetStateProperty.all(
+ colorScheme.surface,
+ ),
+ ),
+ onPressed: () => {
+ Navigator.of(context).pop(),
+ Navigator.of(context).push(
+ LeftToRightPageRoute(
+ builder: (context) =>
+ const NotificationScreen(highlightTimeSlots: true),
+ settings: const RouteSettings(
+ name: NotificationScreen.routeName,
+ ),
),
- const SizedBox(width: 10),
- Expanded(child: widget.forecast.getInformationWidget(context)),
- ],
+ ),
+ },
+ child: TweenAnimationBuilder(
+ tween: tween,
+ duration: duration,
+ builder: (context, animation, child) => Transform.translate(
+ offset: Offset(20 * shake(animation), 0),
+ child: child,
+ ),
+ child: const Icon(Icons.notifications_active),
),
),
],
diff --git a/lib/widgets/forecast/forecast_widget.dart b/lib/widgets/forecast/forecast_widget.dart
index 60df33f1..a9e71072 100644
--- a/lib/widgets/forecast/forecast_widget.dart
+++ b/lib/widgets/forecast/forecast_widget.dart
@@ -3,7 +3,6 @@ import 'package:chabo_app/custom_properties.dart';
import 'package:chabo_app/extensions/color_scheme_extension.dart';
import 'package:chabo_app/extensions/date_time_extension.dart';
import 'package:chabo_app/extensions/duration_extension.dart';
-import 'package:chabo_app/helpers/device_helper.dart';
import 'package:chabo_app/l10n/app_localizations.dart';
import 'package:chabo_app/models/abstract_forecast.dart';
import 'package:chabo_app/models/time_slot.dart';
@@ -71,20 +70,9 @@ class ForecastWidget extends StatelessWidget {
onTap ??
() async => {
await showModalBottomSheet(
- useSafeArea: false,
+ isScrollControlled: true,
barrierColor: Colors.black.withValues(alpha: 0.65),
- constraints: BoxConstraints(
- maxWidth: DeviceHelper.isPortrait(context)
- ? double.infinity
- : MediaQuery.of(context).size.width / 1.8,
- ),
- enableDrag: true,
context: context,
- shape: const RoundedRectangleBorder(
- borderRadius: BorderRadius.vertical(
- top: Radius.circular(CustomProperties.borderRadius * 2),
- ),
- ),
builder: (context) {
return ForecastInformationBottomSheet(forecast: forecast);
},
diff --git a/lib/widgets/simple_container.dart b/lib/widgets/simple_container.dart
index 319aebc0..62274b76 100644
--- a/lib/widgets/simple_container.dart
+++ b/lib/widgets/simple_container.dart
@@ -12,7 +12,7 @@ class SimpleContainer extends StatelessWidget {
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(CustomProperties.borderRadius),
- color: Theme.of(context).colorScheme.surfaceContainer,
+ color: Theme.of(context).colorScheme.surfaceContainerHigh,
),
child: child,
);
diff --git a/pubspec.lock b/pubspec.lock
index e43269b2..3e558367 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -9,6 +9,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "99.0.0"
+ add_2_calendar:
+ dependency: "direct main"
+ description:
+ name: add_2_calendar
+ sha256: "8274d1c7a776fdb46b7b7b9a4ed6b1b80ec8f2a9325fe46e2336687bcbc18ce5"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.1"
analyzer:
dependency: transitive
description:
@@ -217,6 +225,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.15.1"
+ cross_file:
+ dependency: transitive
+ description:
+ name: cross_file
+ sha256: "92c9c43c383bfa1c32079d3bc492d55d6d4318044b7b47edaff8971cbb555c51"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.3.5+4"
crypto:
dependency: transitive
description:
@@ -821,6 +837,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "9.23.0"
+ share_plus:
+ dependency: "direct main"
+ description:
+ name: share_plus
+ sha256: "9eee8283462d91a7a1c8bdb67d08874abd75a2f8fae3bc0ca033035e375fb3d8"
+ url: "https://pub.dev"
+ source: hosted
+ version: "13.2.0"
+ share_plus_platform_interface:
+ dependency: transitive
+ description:
+ name: share_plus_platform_interface
+ sha256: "7f7ae28cf400d13f811e297ff37742dba83b79e0a6f5dce14eec0248274e6ce9"
+ url: "https://pub.dev"
+ source: hosted
+ version: "7.1.0"
shared_preferences:
dependency: "direct main"
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index c918b395..c3f0e525 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -27,6 +27,7 @@ dependencies:
http: ^1.0.0
intl: ^0.20.2
package_info_plus: ^10.1.0
+ share_plus: ^13.2.0
shared_preferences: ^2.0.17
stream_transform: ^2.0.0
timezone: ^0.11.0
@@ -36,6 +37,7 @@ dependencies:
in_app_review: ^2.0.12
build_runner: ^2.15.0
intl_utils: ^2.8.14
+ add_2_calendar: ^3.1.1
dev_dependencies:
@@ -60,5 +62,3 @@ flutter_icons:
image_path: assets/images/chabo_icon.png
adaptive_icon_foreground: assets/images/chabo_icon.png
adaptive_icon_background: "#FFFFFF"
-
-
diff --git a/test/units/boat_forecast_test.dart b/test/units/boat_forecast_test.dart
index f2ada957..e0cf2a52 100644
--- a/test/units/boat_forecast_test.dart
+++ b/test/units/boat_forecast_test.dart
@@ -6,7 +6,6 @@ import 'package:chabo_app/models/time_slot.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
-import '../localized_testable_widget.dart';
void main() {
final forecast = BoatForecast(
@@ -81,52 +80,6 @@ void main() {
expect(forecast.closedDuration, const Duration(hours: 1));
});
- group('Info TextSpan', () {
- testWidgets(
- 'Same day',
- (WidgetTester tester) async {
- await tester.pumpWidget(
- await localizedTestableWidgetEN(
- child: Builder(
- builder: (BuildContext context) {
- final RichText richText =
- forecast.getInformationWidget(context);
- expect(
- richText.text.toPlainText(),
- 'Sunday, May 14, 2023 from  to , the Chaban bridge will be closed for the arrival of the TEST_BOAT\n\nEstimated time of crossing : 3:30 PM',
- );
-
- return const Placeholder();
- },
- ),
- ),
- );
- },
- );
-
- testWidgets(
- 'During tow days',
- (WidgetTester tester) async {
- await tester.pumpWidget(
- await localizedTestableWidgetEN(
- child: Builder(
- builder: (BuildContext context) {
- final RichText richText =
- forecast2.getInformationWidget(context);
- expect(
- richText.text.toPlainText(),
- 'From Sunday, May 14, 2023 , to Monday, May 15, 2023 , the Chaban bridge will be closed for the arrival of the TEST_BOAT\n\nEstimated time of crossing : Mon, May 15 at 2:00 AM',
- );
-
- return const Placeholder();
- },
- ),
- ),
- );
- },
- );
- });
-
group('During two days or not', () {
test('Is during 2 days', () {
expect(forecast2.isDuringTwoDays, true);
diff --git a/test/units/maintenance_forecast_test.dart b/test/units/maintenance_forecast_test.dart
index 9cae836d..754374c3 100644
--- a/test/units/maintenance_forecast_test.dart
+++ b/test/units/maintenance_forecast_test.dart
@@ -5,7 +5,6 @@ import 'package:chabo_app/models/time_slot.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
-import '../localized_testable_widget.dart';
void main() {
final forecast = MaintenanceForecast(
@@ -43,52 +42,6 @@ void main() {
expect(forecast.closedDuration, const Duration(hours: 1));
});
- group('Info TextSpan', () {
- testWidgets(
- 'Display info TextSpan (same day)',
- (WidgetTester tester) async {
- await tester.pumpWidget(
- await localizedTestableWidgetEN(
- child: Builder(
- builder: (BuildContext context) {
- final RichText richText =
- forecast.getInformationWidget(context);
- expect(
- richText.text.toPlainText(),
- 'Sunday, May 14, 2023 from  to , the Chaban bridge will be closed for maintenance',
- );
-
- return const Placeholder();
- },
- ),
- ),
- );
- },
- );
-
- testWidgets(
- 'Display info TextSpan (tow days)',
- (WidgetTester tester) async {
- await tester.pumpWidget(
- await localizedTestableWidgetEN(
- child: Builder(
- builder: (BuildContext context) {
- final RichText richText =
- forecast2.getInformationWidget(context);
- expect(
- richText.text.toPlainText(),
- 'From Sunday, May 14, 2023 , to Monday, May 15, 2023 , the Chaban bridge will be closed for maintenance',
- );
-
- return const Placeholder();
- },
- ),
- ),
- );
- },
- );
- });
-
group('During two days or not', () {
test('Is during 2 days', () {
expect(forecast2.isDuringTwoDays, true);
@@ -123,8 +76,8 @@ void main() {
);
const days = [Day.sunday];
- final isOverlaping = forecast.isOverlappingWithTimeSlot(timeSlot1, days);
- expect(isOverlaping, true);
+ final isOverlapping = forecast.isOverlappingWithTimeSlot(timeSlot1, days);
+ expect(isOverlapping, true);
});
test('(2) Is overlaping with [TimeSlots]', () {
diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake
index 6f56494f..5ca947ed 100644
--- a/windows/flutter/generated_plugins.cmake
+++ b/windows/flutter/generated_plugins.cmake
@@ -4,6 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
sentry_flutter
+ share_plus
url_launcher_windows
)