Commit 2ab2e929 authored by Clouard Regis's avatar Clouard Regis
Browse files

Released 3.1.2

parent b604aaaf
...@@ -5,11 +5,11 @@ All notable changes to this project will be documented in this file. ...@@ -5,11 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 98 [Unreleased] ## 98 [3.1.2] - 2021-08-10
### Fixed ### Fixed
### Added - Android setting for reading HTML files (info boxes)
### Changed ### Changed
- Turning up to Android 11 - Turning up to Android 11
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
"without_chronometer": "Non-timed, no statistics", "without_chronometer": "Non-timed, no statistics",
"without_gps": "Without GPS assistance", "without_gps": "Without GPS assistance",
"with_gps": "With GPS assistance", "with_gps": "With GPS assistance",
"vikazimut_presentation_ensicaen": "The mobile application is a project of computer science students from ENSICAEN\n(École nationale supérieure d'ingénieurs de Caen, Normandy).", "vikazimut_presentation_ensicaen": "The mobile application is a project of computer science students from ENSICAEN\n(National Graduate School of Engineering Caen, Normandy).",
"vikazimut_presentation_unicaen": "and of computer science students from university of Caen, Normandy.", "vikazimut_presentation_unicaen": "and of computer science students from university of Caen, Normandy.",
"vikazimut_student": "The Student Team", "vikazimut_student": "The Student Team",
"vikazimut_supervisors": "The Supervisors", "vikazimut_supervisors": "The Supervisors",
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"continue_route": "Continua il percorso", "continue_route": "Continua il percorso",
"sport_course": "Modalità gara di orientamento", "sport_course": "Modalità gara di orientamento",
"walk_course": "Modalità passeggiata", "walk_course": "Modalità passeggiata",
"course_type": "Typo della gara", "course_type": "Formato della gara",
"ok": "OK", "ok": "OK",
"validation_mode": "Modalità di convalida", "validation_mode": "Modalità di convalida",
"preset_order": "Ordine imposto", "preset_order": "Ordine imposto",
...@@ -16,10 +16,10 @@ ...@@ -16,10 +16,10 @@
"deny_gps_service": "Vietare", "deny_gps_service": "Vietare",
"enable_gps_service": "Attivare", "enable_gps_service": "Attivare",
"disable_gps_service": "Disattivare", "disable_gps_service": "Disattivare",
"nfc_unavailable_message": "Non puo convalidare i posti con il NFC perché l'NFC non è attivato o il suo dispositivo non ha un lettore NFC", "nfc_unavailable_message": "Non può convalidare i posti con il NFC perché l'NFC non è attivato o il suo dispositivo non ha un lettore NFC",
"gps_disabled_message": "La funzione di localizzazione del suo dispositivo è disabilitata.\nVuole abilitarla\u00A0?", "gps_disabled_message": "La funzione di localizzazione del suo dispositivo è disabilitata.\nVuole abilitarla\u00A0?",
"gps_denied_message": "L'app non dispone dell'autorizzazione per utilizzare il GPS..\nVuole consentirlo\u00A0?", "gps_denied_message": "L'app non dispone dell'autorizzazione per utilizzare il GPS..\nVuole consentirlo\u00A0?",
"no_network_and_no_stored_map_error_message": "Nessuna connessione di rete e nessuna scheda registrata in precedenza.\nImpossible continuare.", "no_network_and_no_stored_map_error_message": "Nessuna connessione di rete e nessuna scheda registrata in precedenza.\nImpossibile continuare.",
"qr_code_menu_item": "Flash il codice QR", "qr_code_menu_item": "Flash il codice QR",
"qrcode_scanner_title": "Lettore di Codici QR", "qrcode_scanner_title": "Lettore di Codici QR",
"course_state_message": "Stato dello percorso", "course_state_message": "Stato dello percorso",
...@@ -34,26 +34,26 @@ ...@@ -34,26 +34,26 @@
"quit_course": "Abbandonare il percorso", "quit_course": "Abbandonare il percorso",
"validate_missing_control_point": "Segnalare il checkpoint mancante", "validate_missing_control_point": "Segnalare il checkpoint mancante",
"skip_missing_control_point": "Convalida forzata del checkpoint", "skip_missing_control_point": "Convalida forzata del checkpoint",
"send_result_title": "Pubilcare la traccia GPS sul sito per confrontarla", "send_result_title": "Pubblicare la traccia GPS sul sito per confrontarla",
"enter_nickname": "Entrare un nickname", "enter_nickname": "Entrare un nickname",
"error_no_nickname": "Per favore inserisci un nickname", "error_no_nickname": "Per favore inserisci un nickname",
"history_activity_title": "Gare precedenti", "history_activity_title": "Gare precedenti",
"user_map_name": "Mappa\u00A0:", "user_map_name": "Mappa\u00A0:",
"course_date": "Percorso del", "course_date": "Percorso del",
"walk_date": "Passegiato del", "walk_date": "Passeggiato del",
"course_time": "Tempo\u00A0:", "course_time": "Tempo\u00A0:",
"with_chronometer": "Con cronometro e statistiche", "with_chronometer": "Con cronometro e statistiche",
"without_chronometer": "Senza cronometro ne statistiche", "without_chronometer": "Senza cronometro ne statistiche",
"without_gps": "Senza assistenza GPS", "without_gps": "Senza assistenza GPS",
"with_gps": "Con assistenza GPS", "with_gps": "Con assistenza GPS",
"vikazimut_presentation_ensicaen": "L'app mobile è un projeto degli studienti in informatico dell' ENSICAEN\n(Scuola Nationale Superieure dIngenieri di Caen, Normandie)", "vikazimut_presentation_ensicaen": "L'app mobile è un progetto degli studenti in informatico della scuola di specializzazione nazionale di Ingegneria di Caen (Normandie)",
"vikazimut_presentation_unicaen": "e studienti in informatica dell'università di Caen, Normandie", "vikazimut_presentation_unicaen": "e studenti in informatica dell'università di Caen, Normandie",
"vikazimut_student": "Gli studienti", "vikazimut_student": "Gli studenti",
"vikazimut_supervisors": "I mentori", "vikazimut_supervisors": "I mentori",
"sport_mode": "Modo sport", "sport_mode": "Modo sport",
"walk_mode": "Modo passeggiata", "walk_mode": "Modo passeggiata",
"map_downloading_error_message": "Impossible di caricare la mappa. Nessuna connessione di rete.", "map_downloading_error_message": "Impossibile di caricare la mappa. Nessuna connessione di rete.",
"error_download_map": "Erreure durante il caricamento della mappa\u00A0:", "error_download_map": "Errore durante il caricamento della mappa\u00A0:",
"cp_start": "Partenza", "cp_start": "Partenza",
"cp_finish": "Arrivo", "cp_finish": "Arrivo",
"history_help_message": "Trascina il risultato per eliminarlo", "history_help_message": "Trascina il risultato per eliminarlo",
...@@ -67,13 +67,13 @@ ...@@ -67,13 +67,13 @@
"tester_team": "Il team di test", "tester_team": "Il team di test",
"send_results_to_server": "Confrontare", "send_results_to_server": "Confrontare",
"already_scanned_control_point_message": "Il checkpoint %s è già validato.", "already_scanned_control_point_message": "Il checkpoint %s è già validato.",
"course_already_started_message": "Il percorso è già comenciato.", "course_already_started_message": "Il percorso è già cominciato.",
"quit_course_confirmation_title": "Cancellare il percorso\u00A0?", "quit_course_confirmation_title": "Cancellare il percorso\u00A0?",
"stop_course_confirmation_title": "Fermare il percorso prima della fine\u00A0?", "stop_course_confirmation_title": "Fermare il percorso prima della fine\u00A0?",
"quit_course_confirmation_message": "Confermare disegnando una Z con i quattro punti", "quit_course_confirmation_message": "Confermare disegnando una Z con i quattro punti",
"aid_dialog_title": "Bisogno di aiuto\u00A0?", "aid_dialog_title": "Bisogno di aiuto\u00A0?",
"aid_dialog_message": "Un avatar apparirà per 15 secondi dove si trove sulla mappa.\nMa, serà penalizzato da 5 minuti.", "aid_dialog_message": "Un avatar apparirà per 15 secondi dove ti trovi sulla mappa.\nMa, sarai penalizzato da 5 minuti.",
"yes_aid": "Si, aiutame", "yes_aid": "Si,aiutami",
"no_aid": "No, non ho bisogno", "no_aid": "No, non ho bisogno",
"send": "Mandare", "send": "Mandare",
"yes": "Sì", "yes": "Sì",
...@@ -82,11 +82,11 @@ ...@@ -82,11 +82,11 @@
"force_validation_cp_simple": "Convalida forzata del checkpoint n°%s\u00A0?", "force_validation_cp_simple": "Convalida forzata del checkpoint n°%s\u00A0?",
"missing_cp_notification_plus_report": "Segnala e convalida il checkpoint mancante n°%s (%s)\u00A0?", "missing_cp_notification_plus_report": "Segnala e convalida il checkpoint mancante n°%s (%s)\u00A0?",
"missing_cp_error_no_location": "Impossibile individuare la sua posizione per verificare di essere vicino allo checkpoint.", "missing_cp_error_no_location": "Impossibile individuare la sua posizione per verificare di essere vicino allo checkpoint.",
"missing_cp_error_distance": "Per forzare la convalida di un checkpoint mancante, deve essere entro %1$dm dalla sua posizione.\nCerca encora\u00A0!", "missing_cp_error_distance": "Per forzare la convalida di un checkpoint mancante, deve essere entro %1$dm dalla sua posizione.\nCerca ancora\u00A0!",
"missing_cp_error_title": "Azione negata", "missing_cp_error_title": "Azione negata",
"validating_cp_error_title": "Forzare la convalidazione", "validating_cp_error_title": "Forzare la convalidazione",
"validating_cp_error_no_location": "Impossibile individuare la sua posizione per determinare il checkpoint da convalidare.", "validating_cp_error_no_location": "Impossibile individuare la sua posizione per determinare il checkpoint da convalidare.",
"success_validating_control_point": "Convalidation del checkpoint %s confirmato", "success_validating_control_point": "Convalidation del checkpoint %s confermato\n\n",
"server_connection_error_use_memorized_map": "Nessuna connessione di rete.\nUtilizzo delle mappa in memoria.", "server_connection_error_use_memorized_map": "Nessuna connessione di rete.\nUtilizzo delle mappa in memoria.",
"error_title": "Errore", "error_title": "Errore",
"error_prefix": "Errore :", "error_prefix": "Errore :",
...@@ -103,9 +103,9 @@ ...@@ -103,9 +103,9 @@
"general_conditions_of_use_item": "Termini di servizio", "general_conditions_of_use_item": "Termini di servizio",
"memory_map_usage": "Memoria utilizzata\u00A0: %.1f %s (vuoto: %.1f %s)", "memory_map_usage": "Memoria utilizzata\u00A0: %.1f %s (vuoto: %.1f %s)",
"qrcode_start_button_message": "Premere il pulsante per scannerizzare il codice QR del checkpoint di partenza o usa il lettore NFC", "qrcode_start_button_message": "Premere il pulsante per scannerizzare il codice QR del checkpoint di partenza o usa il lettore NFC",
"auto_start_button_message_sport_mode": "Preme il pulsante.\n\nLo parcorso inizierà quando attraversera il checkpoint di partenza.", "auto_start_button_message_sport_mode": "Preme il pulsante.\n\nLo percorso inizierà quando attraverserà il checkpoint di partenza.",
"auto_start_button_message_walk_mode": "Premere il pulsante per iniziare il percorso.", "auto_start_button_message_walk_mode": "Premere il pulsante per iniziare il percorso.",
"penalty_message": "inclusi penaliti\u00A0:", "penalty_message": "inclusi penalità\u00A0:",
"panic": "Sono perso\u00A0!", "panic": "Sono perso\u00A0!",
"map_list_downloading_message": "Trova l'elenco delle mappe disponibili sul server", "map_list_downloading_message": "Trova l'elenco delle mappe disponibili sul server",
"control_point_index": "Numero\ncheckpoint", "control_point_index": "Numero\ncheckpoint",
...@@ -115,7 +115,7 @@ ...@@ -115,7 +115,7 @@
"cumulative_time": "Tempo\ncumulativo", "cumulative_time": "Tempo\ncumulativo",
"really_exit": "Uscire della pagina dei risultati", "really_exit": "Uscire della pagina dei risultati",
"result_exit_message": "Vuole uscire della pagina di risultati\u00A0?", "result_exit_message": "Vuole uscire della pagina di risultati\u00A0?",
"missing_map_message": "Non è possible visualizzare i resultati perché la mappa è stata cancellata dal suo cellulare. È necessario scaricare nuovamente la mappa prima di poter visualizzare nuovamente i risultati.", "missing_map_message": "Non è possible visualizzare i risultati perché la mappa è stata cancellata dal suo cellulare. È necessario scaricare nuovamente la mappa prima di poter visualizzare nuovamente i risultati.",
"data_protection": "PRIVACY E PROTEZIONE DEI DATI: Nessun dato privato altre allo nickname e la traccia GPS (riportata al 1 gennaio 1970) sarà inviato al server.", "data_protection": "PRIVACY E PROTEZIONE DEI DATI: Nessun dato privato altre allo nickname e la traccia GPS (riportata al 1 gennaio 1970) sarà inviato al server.",
"yes_bypass": "Sì, Vuol evitare questo checkpoint", "yes_bypass": "Sì, Vuol evitare questo checkpoint",
"no_continue": "No, continuo a cercare", "no_continue": "No, continuo a cercare",
...@@ -127,10 +127,10 @@ ...@@ -127,10 +127,10 @@
"scanned_start_control_point": "Inizio del percorso", "scanned_start_control_point": "Inizio del percorso",
"scanned_end_control_point": "Fino del percorso", "scanned_end_control_point": "Fino del percorso",
"wait_validation_for_start": "Dove passare per il checkpoint di partenza per attivare il segnale di inizio.", "wait_validation_for_start": "Dove passare per il checkpoint di partenza per attivare il segnale di inizio.",
"send_result_error_no_connection": "Erreur\u00A0: Impossible per connettersi a internet... Controle la sua connessione", "send_result_error_no_connection": "Errore\u00A0: Impossibile per connettersi a internet... Controle la sua connessione",
"last_punched_display_with_name": "Convalidato : %1d (%2s)", "last_punched_display_with_name": "Convalidato : %1d (%2s)",
"last_punched_display": "Convalidata : %1d", "last_punched_display": "Convalidata : %1d",
"location_required_tile": "Impossible andare oltre", "location_required_tile": "Impossibile andare oltre",
"average_speed_message": "Velocità media", "average_speed_message": "Velocità media",
"Total": "Somma", "Total": "Somma",
"assistance_message_one": "(assistenza\u00A0: %1$d)", "assistance_message_one": "(assistenza\u00A0: %1$d)",
...@@ -141,11 +141,11 @@ ...@@ -141,11 +141,11 @@
"general_conditions_of_use_title": "Termini di servizio", "general_conditions_of_use_title": "Termini di servizio",
"manual_title": "Manuale d'uso", "manual_title": "Manuale d'uso",
"history_menu_item": "Percorsi salvati", "history_menu_item": "Percorsi salvati",
"no_web_navigator": "Impossible d'aprire un browser web sul suo dispositivo", "no_web_navigator": "Impossibile d'aprire un browser web sul suo dispositivo",
"quit_result": "Sì, lascia la pagina", "quit_result": "Sì, lascia la pagina",
"dont_quit_result": "No, rimanere", "dont_quit_result": "No, rimanere",
"control_point_title": "Posto", "control_point_title": "Posto",
"visited_time_title": "Tempo di\npassaggioX", "visited_time_title": "Tempo di\npassaggio",
"out_of_bounds": "È fuori mappa", "out_of_bounds": "È fuori mappa",
"confirm_title": "Conferma", "confirm_title": "Conferma",
"walk_started": "Andiamo !", "walk_started": "Andiamo !",
......
...@@ -25,7 +25,7 @@ class MapChoiceViewState extends State<MapChoiceView> { ...@@ -25,7 +25,7 @@ class MapChoiceViewState extends State<MapChoiceView> {
bool _isSearching = false; bool _isSearching = false;
String searchQuery = ""; String searchQuery = "";
MapChoiceViewState(CourseMode mode) : _presenter = MapChoicePresenter(mode); MapChoiceViewState(CourseMode mode): _presenter = MapChoicePresenter(mode);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -57,10 +57,7 @@ class MapChoiceViewState extends State<MapChoiceView> { ...@@ -57,10 +57,7 @@ class MapChoiceViewState extends State<MapChoiceView> {
})), })),
), ),
), ),
body: Semantics( body: MapListView(searchQuery: searchQuery, presenter: _presenter),
label: "Liste des cartes disponibles",
child: MapListView(searchQuery: searchQuery, presenter: _presenter),
),
), ),
); );
} }
......
...@@ -60,8 +60,7 @@ class _MapListViewState extends State<MapListView> { ...@@ -60,8 +60,7 @@ class _MapListViewState extends State<MapListView> {
ScaffoldMessenger.of(context).showSnackBar(snackBar); ScaffoldMessenger.of(context).showSnackBar(snackBar);
} }
}); });
// TODO return MapProxyListView(presenter: widget.presenter, mapProxies: snapshot.data!, searchQuery: widget.searchQuery);
return Semantics(label: "Liste des cartes disponibles", child: MapProxyListView(presenter: widget.presenter, mapProxies: snapshot.data!, searchQuery: widget.searchQuery),);
} else { } else {
return _WaitingWidget(); return _WaitingWidget();
} }
......
...@@ -54,16 +54,13 @@ class _SplashScreenState extends State<SplashScreen> with TickerProviderStateMix ...@@ -54,16 +54,13 @@ class _SplashScreenState extends State<SplashScreen> with TickerProviderStateMix
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Semantics( return Center(
label: "Powered by ENSICAEN", // TODO child: Transform.scale(
child: Center( scale: _scale,
child: Transform.scale( child: Image.asset(
scale: _scale, 'assets/images/splash.webp',
child: Image.asset( isAntiAlias: true,
'assets/images/splash.webp', scale: 2.5,
isAntiAlias: true,
scale: 2.5,
),
), ),
), ),
); );
......
...@@ -131,130 +131,122 @@ Future<void> _buildAndShowDialog({ ...@@ -131,130 +131,122 @@ Future<void> _buildAndShowDialog({
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.0)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.0)),
elevation: 0.0, elevation: 0.0,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
child: Semantics( child: Stack(
scopesRoute: true, children: <Widget>[
explicitChildNodes: true, Container(
namesRoute: true, width: screenWidth >= 600 ? 500 : screenWidth,
label: '$title: $message', padding: const EdgeInsets.only(
child: Stack( top: 45.0 + 16.0,
children: <Widget>[ bottom: 16.0,
Container( left: 16.0,
width: screenWidth >= 600 ? 500 : screenWidth, right: 16.0,
padding: const EdgeInsets.only( ),
top: 45.0 + 16.0, margin: const EdgeInsets.only(top: 55.0),
bottom: 16.0, decoration: BoxDecoration(
left: 16.0, color: Theme.of(context).dialogBackgroundColor,
right: 16.0, shape: BoxShape.rectangle,
), borderRadius: BorderRadius.circular(16.0),
margin: const EdgeInsets.only(top: 55.0), boxShadow: [
decoration: BoxDecoration( const BoxShadow(
color: Theme.of(context).dialogBackgroundColor, color: Colors.black26,
shape: BoxShape.rectangle, blurRadius: 10.0,
borderRadius: BorderRadius.circular(16.0), offset: const Offset(0.0, 10.0),
boxShadow: [ ),
const BoxShadow( ],
color: Colors.black26, ),
blurRadius: 10.0, child: Column(
offset: const Offset(0.0, 10.0), mainAxisSize: MainAxisSize.min,
), children: <Widget>[
], if (title.isNotEmpty)
), Text(
child: Column( title,
mainAxisSize: MainAxisSize.min, style: TextStyle(
children: <Widget>[ color: color,
if (title.isNotEmpty) fontSize: 20.0,
Text( fontWeight: FontWeight.w700,
title,
style: TextStyle(
color: color,
fontSize: 20.0,
fontWeight: FontWeight.w700,
),
), ),
const SizedBox(height: 16.0), ),
Flexible( const SizedBox(height: 16.0),
fit: FlexFit.loose, Flexible(
child: SingleChildScrollView( fit: FlexFit.loose,
child: Text( child: SingleChildScrollView(
message, child: Text(
textAlign: TextAlign.center, message,
style: const TextStyle( textAlign: TextAlign.center,
fontSize: 16.0, style: const TextStyle(
), fontSize: 16.0,
), ),
), ),
), ),
if (usePattern) ),
PatternLock( if (usePattern)
secretCode: [0, 1, 2, 3], PatternLock(
onSuccess: () { secretCode: [0, 1, 2, 3],
Navigator.of(context).pop(); onSuccess: () {
if (positiveButtonAction != null) { Navigator.of(context).pop();
positiveButtonAction(); if (positiveButtonAction != null) {
} positiveButtonAction();
}, }
), },
const SizedBox(height: 16.0), ),
if (checkboxMessage != null && checkboxMessage.isNotEmpty) const SizedBox(height: 16.0),
CheckBoxContainer( if (checkboxMessage != null && checkboxMessage.isNotEmpty)
checkboxValue: remember, CheckBoxContainer(
checkboxMessage: checkboxMessage, checkboxValue: remember,
color: color, checkboxMessage: checkboxMessage,
), color: color,
Align( ),
alignment: Alignment.bottomRight, Align(
child: Row( alignment: Alignment.bottomRight,
mainAxisAlignment: MainAxisAlignment.end, child: Row(
children: <Widget>[ mainAxisAlignment: MainAxisAlignment.end,
if (!usePattern) children: <Widget>[
TextButton( if (!usePattern)
child: Text( TextButton(
positiveButtonText, child: Text(
style: TextStyle(color: color), positiveButtonText,
), style: TextStyle(color: color),
onPressed: () {
if (remember[0] && checkboxAction != null) {
checkboxAction();
}
Navigator.of(context).pop();
if (positiveButtonAction != null) {
positiveButtonAction();
}
},
), ),
const SizedBox( onPressed: () {
width: 40.0, if (remember[0] && checkboxAction != null) {
checkboxAction();
}
Navigator.of(context).pop();
if (positiveButtonAction != null) {
positiveButtonAction();
}
},
), ),
if (negativeButtonText != null) const SizedBox(width: 40.0,),
TextButton( if (negativeButtonText != null)
child: Text( TextButton(
negativeButtonText, child: Text(
style: TextStyle(color: color), negativeButtonText,
), style: TextStyle(color: color),
onPressed: () {
Navigator.of(context).pop();
if (negativeButtonAction != null) {
negativeButtonAction();
}
},
), ),
], onPressed: () {
), Navigator.of(context).pop();
if (negativeButtonAction != null) {
negativeButtonAction();
}
},
),
],
), ),
], ),
), ],
), ),
Positioned( ),
left: 16.0, Positioned(
right: 16.0, left: 16.0,
child: CircleAvatar( right: 16.0,
backgroundColor: color, child: CircleAvatar(
radius: 45.0, backgroundColor: color,
child: dialogIcon, radius: 45.0,
), child: dialogIcon,
), ),
], ),
), ],
), ),
); );
} }
......
...@@ -34,7 +34,7 @@ dependencies: ...@@ -34,7 +34,7 @@ dependencies:
sprintf: ^6.0.0 sprintf: ^6.0.0
intl: ^0.17.0 intl: ^0.17.0
webview_flutter: ^2.0.10 webview_flutter: ^2.0.12
xml: ^5.1.1 xml: ^5.1.1
http: ^0.13.3 http: ^0.13.3
url_launcher: ^6.0.9 url_launcher: ^6.0.9
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment