diff --git a/Linphone/core/App.cpp b/Linphone/core/App.cpp index d755683ff..fcc5d033f 100644 --- a/Linphone/core/App.cpp +++ b/Linphone/core/App.cpp @@ -114,6 +114,7 @@ #include "tool/request/RequestDialog.hpp" #include "tool/thread/Thread.hpp" #include "tool/ui/DashRectangle.hpp" +#include "tool/ui/FocusNavigator.hpp" #if defined(Q_OS_MACOS) #include "core/event-count-notifier/EventCountNotifierMacOs.hpp" @@ -714,6 +715,7 @@ void App::initCore() { #endif mEngine->rootContext()->setContextProperty("applicationName", APPLICATION_NAME); mEngine->rootContext()->setContextProperty("executableName", EXECUTABLE_NAME); + mEngine->rootContext()->setContextProperty("FocusNavigator", new FocusNavigator(mEngine)); initCppInterfaces(); mEngine->addImageProvider(ImageProvider::ProviderId, new ImageProvider()); diff --git a/Linphone/data/languages/de.ts b/Linphone/data/languages/de.ts index febc3e85b..b285614ac 100644 --- a/Linphone/data/languages/de.ts +++ b/Linphone/data/languages/de.ts @@ -22,6 +22,21 @@ + + AbstractSettingsMenu + + + back_previous_menu_accessible_name + Back to previous menu + + + + + settings_page_selection_accessible_name + Settings page selection + + + AbstractWindow @@ -670,143 +685,141 @@ App - + remote_provisioning_dialog Voulez-vous télécharger et appliquer la configuration depuis cette adresse ? Möchten Sie die Remote-Konfiguration von dieser Adresse herunterladen und anwenden? - - - + + + info_popup_error_title Error Fehler - - + + info_popup_configuration_failed_message Remote provisioning failed : %1 - + info_popup_error_checking_update An error occured while trying to check update. Please try again later or contact support team. - + info_popup_new_version_download_label - Download it ! - + info_popup_new_version_available_title New version available ! - + info_popup_new_version_available_message A new version of Linphone (%1) is available. %2 - + info_popup_version_up_to_date_title - Up to date - + info_popup_version_up_to_date_message Your version is up to date - + configuration_error_detail not reachable - + application_description "A free and open source SIP video-phone." Ein kostenloses Open-Source SIP Video-Telefon. - + command_line_arg_order "Send an order to the application towards a command line" Kommandozeilen-Befehl an die Anwendung schicken - + command_line_option_show_help Zeige Hilfe - + command_line_option_show_app_version App-Version anzeigen - + command_line_option_config_to_fetch "Specify the linphone configuration file to be fetched. It will be merged with the current configuration." Abzurufende Linphone-Konfigurationsdatei angeben. Sie wird mit der aktuellen Konfiguration zusammengeführt. - + command_line_option_config_to_fetch_arg "URL, path or file" URL, Pfad oder Datei - + command_line_option_minimized - + command_line_option_log_to_stdout Debug-Informationen auf der Standardausgabe ausgeben - + command_line_option_print_app_logs_only "Print only logs from the application" Nur Anwendungs-Logs ausgeben - + hide_action "Cacher" "Afficher" Ausblenden - + show_action Zeigen - + quit_action "Quitter" Beenden - + check_for_update Check for update - + mark_all_read_action @@ -1019,11 +1032,35 @@ CallHistoryListView - + call_name_accessible_button Call %1 + Anruf %1 + + + + call_history_entry_accessible_name + %1 - %2 - %3 - right arrow for call-back button + + + notification_missed_call_title + "Appel manqué" + Verpasster Anruf + + + + call_outgoing + "Appel sortant" + Ausgehender Anruf + + + + call_audio_incoming + "Appel entrant" + Eingehender Anruf + CallLayout @@ -1080,7 +1117,6 @@ local_group_call - "Local group call" @@ -1230,101 +1266,101 @@ Anrufprotokoll leer - + history_dialog_delete_all_call_logs_title Supprimer l'historique d'appels ? Anrufprotokoll löschen? - + history_dialog_delete_all_call_logs_message "L'ensemble de votre historique d'appels sera définitivement supprimé." Das gesamte Anrufprotokoll wird dauerhaft gelöscht. - + history_dialog_delete_call_logs_title Supprimer l'historique d'appels ? Anrufprotokoll löschen? - + history_dialog_delete_call_logs_message "L'ensemble de votre historique d'appels avec ce correspondant sera définitivement supprimé." Das Anrufprotokoll mit diesem Benutzer wird dauerhaft gelöscht. - + call_history_call_list_title "Appels" Anrufe - + call_history_options_accessible_name - - + + menu_delete_history "Supprimer l'historique" Verlauf löschen - + call_history_list_options_accessible_name Call history options - + create_new_call_accessible_name Create new call - + call_search_in_history "Rechercher un appel" Anruf suchen - + call_forward_to_address_info - + call_forward_to_address_info_voicemail - + list_filter_no_result_found "Aucun résultat…" Kein Ergebnis gefunden… - + history_list_empty_history "Aucun appel dans votre historique" Anrufverlauf leer - + return_to_call_history_accessible_name Return to call history - + call_action_start_new_call "Nouvel appel" Neuer Anruf - + call_start_group_call_title "Appel de groupe" Gruppenanruf @@ -1338,7 +1374,7 @@ - + call_action_start_group_call "Lancer" Starten @@ -1354,74 +1390,74 @@ Erforderlich - - - + + + information_popup_error_title Fehler - + group_call_error_must_have_name "Un nom doit être donné à l'appel de groupe Es muss ein Name für den Anruf angegeben werden - + group_call_error_not_connected "Vous n'etes pas connecté" Sie sind nicht verbunden - + menu_see_existing_contact "Show contact" Kontakt anzeigen - + menu_add_address_to_contacts "Add to contacts" Zu Kontakten hinzufügen - + menu_copy_sip_address "Copier l'adresse SIP" SIP-Adresse kopieren - + sip_address_copied_to_clipboard_toast Adresse copiée SIP-Adresse kopiert - + sip_address_copied_to_clipboard_message L'adresse a été copié dans le presse_papiers Die Adresse wurde in die Zwischenablage kopiert - + sip_address_copy_to_clipboard_error "Erreur lors de la copie de l'adresse" Fehler beim Kopieren der Adresse - + notification_missed_call_title "Appel manqué" Verpasster Anruf - + call_outgoing "Appel sortant" Ausgehender Anruf - + call_audio_incoming "Appel entrant" Eingehender Anruf @@ -2344,7 +2380,6 @@ Error popup_error_nb_files_not_found_message - %n files were not found @@ -2365,7 +2400,6 @@ Error popup_error_unsupported_files_message - Unable to get supported mime type for %1 files. @@ -2598,91 +2632,91 @@ Error - + info_popup_error_title Fehler - + info_popup_chatroom_creation_failed Chat room creation failed ! - + loading_popup_chatroom_creation_pending_message Chat room is being created... - + chat_dialog_delete_chat_title Supprimer la conversation ? - + chat_dialog_delete_chat_message "La conversation et tous ses messages seront supprimés." - + chat_list_title "Conversations" Konversationen - + menu_mark_all_as_read "mark all as read" - + chat_search_in_history "Rechercher une conversation" - + list_filter_no_result_found "Aucun résultat…" Kein Ergebnis… - + chat_list_empty_history "Aucune conversation dans votre historique" - + chat_action_start_new_chat "New chat" - + chat_start_group_chat_title "Nouveau groupe" - + chat_action_start_group_chat "Créer" Erstellen - - - + + + information_popup_error_title Fehler - + information_popup_chat_creation_failed_message "La création a échoué" @@ -2693,25 +2727,25 @@ Error Der Codec konnte nicht installiert werden. - + group_chat_error_must_have_name "Un nom doit être donné au groupe - + group_chat_error_no_participant "Please select at least one participant - + group_call_error_not_connected "Vous n'etes pas connecté" Sie sind nicht verbunden - + chat_creation_in_progress Creation de la conversation en cours … @@ -2771,28 +2805,34 @@ Error CliModel + show_function_description - Zeigen + Zeigen + fetch_config_function_description - Konfiguration abrufen + Konfiguration abrufen + call_function_description - Anrufen + Anrufen + bye_function_description - Auflegen + Auflegen + accept_function_description - Akzeptieren + Akzeptieren + decline_function_description - Ablehnen + Ablehnen @@ -3006,53 +3046,71 @@ Error ContactListItem - + + call_with_contact_name_accessible_button + "Call %1" + + + + + video_call_with_contact_name_accessible_button + "Video call %1" + + + + + message_with_contact_name_accessible_button + "Message %1" + + + + contact_details_remove_from_favourites "Enlever des favoris" Aus Favoriten entfernen - + contact_details_add_to_favourites "Ajouter aux favoris" Zu Favoriten hinzufügen - + Partager Teilen - + information_popup_error_title Fehler - + information_popup_vcard_creation_error La création du fichier vcard a échoué VCard-Erstellung fehlgeschlagen - + information_popup_vcard_creation_title VCard créée VCard erstellt - + information_popup_vcard_creation_success "VCard du contact enregistrée dans %1" VCard in %1 gespeichert - + contact_sharing_email_title Partage de contact Kontakt teilen - + contact_details_delete "Supprimer" Löschen @@ -3088,149 +3146,149 @@ Error Zurzeit keine Kontakte - + contact_new_title "Nouveau contact" Neuer Kontakt - + create Erstellen - + contact_edit_title "Modifier contact" Kontakt bearbeiten - + save Speichern - + contact_dialog_delete_title Supprimer %1 ?" %1 löschen? - + contact_dialog_delete_message Ce contact sera définitivement supprimé. Dieser Kontakt wird dauerhaft gelöscht. - + contact_deleted_toast "Contact supprimé" Kontakt gelöscht - + contact_deleted_message "%1 a été supprimé" %1 wurde gelöscht - + contact_dialog_devices_trust_popup_title "Augmenter la confiance" Vertrauenslevel erhöhen - + contact_dialog_devices_trust_popup_message "Pour augmenter le niveau de confiance vous devez appeler les différents appareils de votre contact et valider un code.<br><br>Vous êtes sur le point d’appeler “%1” voulez vous continuer ?" Um das Vertrauenslevel zu erhöhen müssen Sie Ihren Kontakt anrufen und einen Code bestätigen.<br><br>Sie sind dabei, "%1" anzurufen. Möchten Sie fortfahren? - + popup_do_not_show_again Ne plus afficher Nicht mehr anzeigen - + cancel Abbrechen - + dialog_call "Appeler" Anrufen - + contact_dialog_devices_trust_help_title "Niveau de confiance" Vertrauenslevel - + contact_dialog_devices_trust_help_message "Vérifiez les appareils de votre contact pour confirmer que vos communications seront sécurisées et sans compromission. <br>Quand tous seront vérifiés, vous atteindrez le niveau de confiance maximal." Überprüfen Sie die Geräte Ihres Kontakts um sicherzustellen, dass Ihre Kommunikation sicher und unkompromittiert ist. Wenn alle Geräte überprüft sind, erreichen Sie das höchste Vertrauenslevel. - + dialog_ok "Ok" Ok - + bottom_navigation_contacts_label "Contacts" Kontakte - + create_contact_accessible_name Create new contact - + search_bar_look_for_contact_text Rechercher un contact Kontakt suchen - + list_filter_no_result_found Aucun résultat… Kein Ergebnis… - + contact_list_empty Aucun contact pour le moment Zurzeit keine Kontakte - + more_info_accessible_name More info %1 - + expand_accessible_name Expand %1 - + shrink_accessible_name Shrink %1 - - + + contact_details_edit Edit ---------- @@ -3238,19 +3296,19 @@ Error Bearbeiten - + contact_call_action "Appel" Anrufen - + contact_message_action "Message" Nachricht - + contact_video_call_action "Appel vidéo" Videoanruf @@ -3276,133 +3334,133 @@ Error Offline - + contact_details_numbers_and_addresses_title "Coordonnées" Kontaktinformationen - + call_adress_accessible_name Call address %1 - + contact_details_company_name "Société :" Unternehmen : - + contact_details_job_title "Poste :" Beruf : - + contact_details_medias_title "Medias" Medien - - + + contact_details_medias_subtitle "Afficher les medias partagés" Geteilte Medien anzeigen - + contact_details_trust_title "Confiance" Vertrauen - + contact_dialog_devices_trust_title "Niveau de confiance - Appareils vérifiés" Vertrauenslevel - Verifizierte Geräte - + contact_details_no_device_found "Aucun appareil" Kein Gerät - + contact_device_without_name "Appareil inconnu" Unbekanntes Gerät - + contact_make_call_check_device_trust "Vérifier" Überprüfen - + verify_device_accessible_name Verify %1 device - + contact_details_actions_title "Autres actions" Weitere Aktionen - + contact_details_remove_from_favourites "Retirer des favoris" Aus Favoriten entfernen - + contact_details_add_to_favourites "Ajouter aux favoris" Zu Favoriten hinzufügen - + contact_details_share "Partager" Teilen - + information_popup_error_title Fehler - + contact_details_share_error_mesage "La création du fichier vcard a échoué" VCard-Erstellung fehlgeschlagen - + contact_details_share_success_title "VCard créée" VCard erstellt - + contact_details_share_success_mesage "VCard du contact enregistrée dans %1" VCard wurde in %1 gespeichert - + contact_details_share_email_title "Partage de contact" Kontakt teilen - + contact_details_delete "Supprimer ce contact" Kontakt löschen @@ -4430,7 +4488,6 @@ Error default_account_connection_state_error_toast - Erreur durant la connexion, veuillez vérifier vos paramètres Fehler bei der Verbindung @@ -4445,144 +4502,144 @@ Error MainLayout - + bottom_navigation_calls_label "Appels" Anrufe - + open_calls_page_accessible_name "Open calls page" - + bottom_navigation_contacts_label "Contacts" Kontakte - + open_contacts_page_accessible_name "Open contacts page" - + bottom_navigation_conversations_label "Conversations" Konversationen - + open_conversations_page_accessible_name "Open conversations page" - + bottom_navigation_meetings_label "Réunions" Besprechungen - + open_contact_page_accessible_name "Open meetings page" - + searchbar_placeholder_text "Rechercher un contact, appeler %1" Kontakt suchen, %1 anrufen - + searchbar_placeholder_text_chat_feature_enabled "ou envoyer un message …" oder eine Nachricht senden … - + do_not_disturb_accessible_name "Do not disturb" Nicht stören - - + + contact_presence_status_disable_do_not_disturb "Désactiver ne pas déranger" Nicht stören deaktivieren - + information_popup_error_title Fehler - + no_voicemail_uri_error_message "L'URI de messagerie vocale n'est pas définie." Die Voicemail-URI ist nicht definiert. - + account_list_accessible_name "Account list" - + application_options_accessible_name "Application options" - + drawer_menu_manage_account Mon compte Mein Konto - + contact_presence_status_enable_do_not_disturb "Activer ne pas déranger" Nicht stören aktivieren - + settings_title Einstellungen - + recordings_title "Enregistrements" Aufnahmen - + help_title "Aide" Hilfe - + help_quit_title "Quitter l'application" App beenden - + quit_app_question "Quitter %1 ?" %1 beenden? - + drawer_menu_add_account "Ajouter un compte" Konto hinzufügen @@ -4789,158 +4846,158 @@ Error Keine Besprechungen - + meeting_schedule_cancel_dialog_message "Souhaitez-vous annuler et supprimer cette réunion ?" Möchten Sie diese Besprechung absagen und löschen? - + meeting_schedule_delete_dialog_message Souhaitez-vous supprimer cette réunion ? Möchten Sie diese Besprechung löschen? - + meeting_schedule_cancel_and_delete_action "Annuler et supprimer" Absagen und löschen - + meeting_schedule_delete_only_action "Supprimer seulement" Nur löschen - + meeting_schedule_delete_action "Supprimer" Löschen - + back_action Retour Zurück - + meetings_list_title Réunions Besprechungen - + meetings_search_hint "Rechercher une réunion" Besprechung suchen - + list_filter_no_result_found "Aucun résultat…" Kein Ergebnis… - + meetings_empty_list "Aucune réunion" Keine Besprechungen - - + + meeting_schedule_title "Nouvelle réunion" Neue Besprechung - + create Erstellen - - - - - - + + + + + + information_popup_error_title Fehler - - + + meeting_schedule_mandatory_field_not_filled_toast Veuillez saisir un titre et sélectionner au moins un participant Bitte Titel bestimmen und mindestens einen Teilnehmer auswählen - - + + meeting_schedule_duration_error_toast "La fin de la conférence doit être plus récente que son début" Das Ende der Besprechung muss nach dem Beginn liegen - - + + meeting_schedule_creation_in_progress "Création de la réunion en cours …" Besprechung wird erstellt… - + meeting_info_created_toast "Réunion planifiée avec succès" Besprechung erfolgreich erstellt - + meeting_failed_to_schedule_toast "Échec de création de la réunion !" Besprechung konnte nicht erstellt werden! - + save Speichern - - + + saved "Enregistré" Gespeichert - + meeting_info_updated_toast "Réunion mise à jour" Besprechung geändert - + meeting_schedule_edit_in_progress "Modification de la réunion en cours…" Bersprechung wird geändert… - + meeting_failed_to_edit_toast "Échec de la modification de la réunion !" Besprechung konnte nicht geändert werden! - + meeting_schedule_add_participants_title "Ajouter des participants" Teilnehmer hinzufügen - + meeting_schedule_add_participants_apply Apply @@ -4949,7 +5006,7 @@ Error Hinzufügen - + group_call_participant_selected "%n participant(s) sélectionné(s)" @@ -4958,31 +5015,31 @@ Error - + meeting_info_delete "Supprimer la réunion" Besprechung löschen - + meeting_address_copied_to_clipboard_toast "Adresse de la réunion copiée" Besprechungs-URI kopiert - + meeting_schedule_timezone_title "Fuseau horaire" Zeitzone - + meeting_info_organizer_label "Organisateur" Organisator - + meeting_info_join_title "Rejoindre la réunion" Besprechung beitreten @@ -5218,6 +5275,36 @@ Error + + NumericPad + + + numpad_longpress_accessible_name + %1 longpress %2 + + + + + call_accessible_name + Call + + + + + erase_accessible_name + Erase + + + + + NumericPadPopup + + + close_numeric_pad_accessible_name + Close numeric pad + + + OIDCModel @@ -6235,7 +6322,6 @@ Pour les activer dans un projet commercial, merci de nous contacter. unknown_audio_device_name - "Unknown device" Unbekannter Gerätename @@ -6430,9 +6516,6 @@ Pour les activer dans un projet commercial, merci de nous contacter. chat_error - Error creating or opening the chat ----------- -Error in the chat diff --git a/Linphone/data/languages/en.ts b/Linphone/data/languages/en.ts index 0018122bd..18a020089 100644 --- a/Linphone/data/languages/en.ts +++ b/Linphone/data/languages/en.ts @@ -22,6 +22,21 @@ Save %1 settings + + AbstractSettingsMenu + + + back_previous_menu_accessible_name + Back to previous menu + Back to previous menu + + + + settings_page_selection_accessible_name + Settings page selection + Settings page selection + + AbstractWindow @@ -661,143 +676,141 @@ App - + remote_provisioning_dialog Voulez-vous télécharger et appliquer la configuration depuis cette adresse ? Do you want to download and apply remote provisioning from this address ? - - - + + + info_popup_error_title Error Error - - + + info_popup_configuration_failed_message Remote provisioning failed : %1 Remote provisioning failed : %1 - + info_popup_error_checking_update An error occured while trying to check update. Please try again later or contact support team. An error occured while trying to check update. Please try again later or contact support team. - + info_popup_new_version_download_label - Download it ! Download it ! - + info_popup_new_version_available_title New version available ! New version available ! - + info_popup_new_version_available_message A new version of Linphone (%1) is available. %2 A new version of Linphone (%1) is available at %1 - + info_popup_version_up_to_date_title - Up to date Up to date - + info_popup_version_up_to_date_message Your version is up to date Up to date Your version is up to date - + configuration_error_detail not reachable not reachable - + application_description "A free and open source SIP video-phone." A free and open source SIP video-phone. - + command_line_arg_order "Send an order to the application towards a command line" Send an order to the application towards a command line - + command_line_option_show_help Show this help - + command_line_option_show_app_version Show app version - + command_line_option_config_to_fetch "Specify the linphone configuration file to be fetched. It will be merged with the current configuration." Specify the linphone configuration file to be fetched. It will be merged with the current configuration. - + command_line_option_config_to_fetch_arg "URL, path or file" URL, path or file - + command_line_option_minimized Minimize - + command_line_option_log_to_stdout Log to stdout some debug information while running - + command_line_option_print_app_logs_only "Print only logs from the application" Print only logs from the application - + hide_action "Cacher" "Afficher" Hide - + show_action Show - + quit_action "Quitter" Quit - + check_for_update Check for update Check for update - + mark_all_read_action Marquer tout comme lu @@ -1030,11 +1043,35 @@ CallHistoryListView - + call_name_accessible_button Call %1 Call %1 + + + call_history_entry_accessible_name + %1 - %2 - %3 - right arrow for call-back button + %1 - %2 - %3 - right arrow for call-back button + + + + notification_missed_call_title + "Appel manqué" + Missed call + + + + call_outgoing + "Appel sortant" + Outgoing call + + + + call_audio_incoming + "Appel entrant" + Incoming call + CallLayout @@ -1091,7 +1128,6 @@ local_group_call - "Local group call" Local group call @@ -1229,12 +1265,12 @@ CallPage - + call_forward_to_address_info Forward calls to: - + call_forward_to_address_info_voicemail Voicemail @@ -1251,170 +1287,170 @@ Empty call history - + history_dialog_delete_all_call_logs_title Supprimer l'historique d'appels ? Delete call history ? - + history_dialog_delete_all_call_logs_message "L'ensemble de votre historique d'appels sera définitivement supprimé." Call history will be permanently deleted. - + history_dialog_delete_call_logs_title Supprimer l'historique d'appels ? Delete call history ? - + history_dialog_delete_call_logs_message "L'ensemble de votre historique d'appels avec ce correspondant sera définitivement supprimé." Call history with this user will be permanently deleted. - + call_history_call_list_title "Appels" Calls - + call_history_options_accessible_name Call history options - - + + menu_delete_history "Supprimer l'historique" Delete history - + call_history_list_options_accessible_name Call history options Call history options - + create_new_call_accessible_name Create new call Create new call - + call_search_in_history "Rechercher un appel" Find call - + list_filter_no_result_found "Aucun résultat…" No result found… - + history_list_empty_history "Aucun appel dans votre historique" No call in history - + return_to_call_history_accessible_name Return to call history Return to call history - + call_action_start_new_call "Nouvel appel" New call - + call_start_group_call_title "Appel de groupe" Group call - + call_action_start_group_call "Lancer" Start - - - + + + information_popup_error_title Error - + group_call_error_must_have_name "Un nom doit être donné à l'appel de groupe A name must be provided for the call - + group_call_error_not_connected "Vous n'etes pas connecté" You are not connected - + menu_see_existing_contact "Show contact" Show contact - + menu_add_address_to_contacts "Add to contacts" Add to contacts - + menu_copy_sip_address "Copier l'adresse SIP" Copy SIP address - + sip_address_copied_to_clipboard_toast Adresse copiée SIP address copied - + sip_address_copied_to_clipboard_message L'adresse a été copié dans le presse_papiers The address has been copied to the clipboard - + sip_address_copy_to_clipboard_error "Erreur lors de la copie de l'adresse" Error copying address - + notification_missed_call_title "Appel manqué" Missed call - + call_outgoing "Appel sortant" Outgoing call - + call_audio_incoming "Appel entrant" Incoming call @@ -2337,7 +2373,6 @@ Error popup_error_nb_files_not_found_message - %n files were not found %1 files were not found @@ -2358,7 +2393,6 @@ Error popup_error_unsupported_files_message - Unable to get supported mime type for %1 files. Unable to get supported mime type for %1 files. @@ -2588,115 +2622,115 @@ Only your correspondent can decrypt them. No conversation - + info_popup_error_title Error - + info_popup_chatroom_creation_failed Chat room creation failed ! Chat room creation failed ! - + loading_popup_chatroom_creation_pending_message Chat room is being created... Chat room is being created... - + chat_dialog_delete_chat_title Supprimer la conversation ? Delete conversation ? - + chat_dialog_delete_chat_message "La conversation et tous ses messages seront supprimés." This conversation and all its messages will be deleted. - + chat_list_title "Conversations" Conversations - + menu_mark_all_as_read "mark all as read" Mark all as read - + chat_search_in_history "Rechercher une conversation" Search for a chat - + list_filter_no_result_found "Aucun résultat…" No result… - + chat_list_empty_history "Aucune conversation dans votre historique" No conversation in history - + chat_action_start_new_chat "New chat" New conversation - + chat_start_group_chat_title "Nouveau groupe" New group - + chat_action_start_group_chat "Créer" Create - - - + + + information_popup_error_title Error - + information_popup_chat_creation_failed_message "La création a échoué" Creation failed - + group_chat_error_must_have_name "Un nom doit être donné au groupe A name must be set for the group - + group_chat_error_no_participant "Please select at least one participant Please select at least one participant - + group_call_error_not_connected "Vous n'etes pas connecté" You are not connected - + chat_creation_in_progress Creation de la conversation en cours … Chat creation pending… @@ -2756,28 +2790,34 @@ Only your correspondent can decrypt them. CliModel + show_function_description - Show + Show + fetch_config_function_description - Fetch configuration + Fetch configuration + call_function_description - Call + Call + bye_function_description - Hang up + Hang up + accept_function_description - Accept + Accept + decline_function_description - Decline + Decline @@ -2966,53 +3006,71 @@ Only your correspondent can decrypt them. ContactListItem - + + call_with_contact_name_accessible_button + "Call %1" + Call %1 + + + + video_call_with_contact_name_accessible_button + "Video call %1" + Video call %1 + + + + message_with_contact_name_accessible_button + "Message %1" + Message %1 + + + contact_details_remove_from_favourites "Enlever des favoris" Remove from favorites - + contact_details_add_to_favourites "Ajouter aux favoris" Add to favorites - + Partager Share - + information_popup_error_title Error - + information_popup_vcard_creation_error La création du fichier vcard a échoué VCard creation failed - + information_popup_vcard_creation_title VCard créée VCard created - + information_popup_vcard_creation_success "VCard du contact enregistrée dans %1" VCard has been saved in %1 - + contact_sharing_email_title Partage de contact Share contact - + contact_details_delete "Supprimer" Delete @@ -3048,149 +3106,149 @@ Only your correspondent can decrypt them. No contact at the moment - + contact_new_title "Nouveau contact" New contact - + create Create - + contact_edit_title "Modifier contact" Edit contact - + save Save - + contact_dialog_delete_title Supprimer %1 ?" Delete %1? - + contact_dialog_delete_message Ce contact sera définitivement supprimé. This contact will be permanently deleted. - + contact_deleted_toast "Contact supprimé" Contact deleted - + contact_deleted_message "%1 a été supprimé" %1 has been deleted - + contact_dialog_devices_trust_popup_title "Augmenter la confiance" Increase trust level - + contact_dialog_devices_trust_popup_message "Pour augmenter le niveau de confiance vous devez appeler les différents appareils de votre contact et valider un code.<br><br>Vous êtes sur le point d’appeler “%1” voulez vous continuer ?" To increase trust level you must call your contact's devices and validate a code.<br><br>You are about to call "%1" do you want to continue? - + popup_do_not_show_again Ne plus afficher Do not show again - + cancel Cancel - + dialog_call "Appeler" Call - + contact_dialog_devices_trust_help_title "Niveau de confiance" Trust level - + contact_dialog_devices_trust_help_message "Vérifiez les appareils de votre contact pour confirmer que vos communications seront sécurisées et sans compromission. <br>Quand tous seront vérifiés, vous atteindrez le niveau de confiance maximal." Verify your contact's devices to confirm that your communications will be secure and uncompromised. When all are verified, you will reach the maximum trust level. - + dialog_ok "Ok" Ok - + bottom_navigation_contacts_label "Contacts" Contacts - + search_bar_look_for_contact_text Rechercher un contact Find contact - + list_filter_no_result_found Aucun résultat… No result… - + contact_list_empty Aucun contact pour le moment No contact at the moment - + expand_accessible_name Expand %1 Expand %1 - + shrink_accessible_name Shrink %1 Shrink %1 - + create_contact_accessible_name Create new contact Create new contact - + more_info_accessible_name More info %1 More info %1 - - + + contact_details_edit Edit ---------- @@ -3198,151 +3256,151 @@ Only your correspondent can decrypt them. Edit - + contact_call_action "Appel" Call - + contact_message_action "Message" Message - + contact_video_call_action "Appel vidéo" Video call - + contact_details_numbers_and_addresses_title "Coordonnées" Contact details - + call_adress_accessible_name Call address %1 Call address %1 - + contact_details_company_name "Société :" Company : - + contact_details_job_title "Poste :" Job : - + contact_details_medias_title "Medias" Medias - - + + contact_details_medias_subtitle "Afficher les medias partagés" Show shared media - + contact_details_trust_title "Confiance" Trust - + contact_dialog_devices_trust_title "Niveau de confiance - Appareils vérifiés" Trust Level - Verified Devices - + contact_details_no_device_found "Aucun appareil" No device - + contact_device_without_name "Appareil inconnu" Unknown device - + contact_make_call_check_device_trust "Vérifier" Verify - + verify_device_accessible_name Verify %1 device Verify %1 device - + contact_details_actions_title "Autres actions" Other actions - + contact_details_remove_from_favourites "Retirer des favoris" Remove from favorites - + contact_details_add_to_favourites "Ajouter aux favoris" Add to favorites - + contact_details_share "Partager" Share - + information_popup_error_title Error - + contact_details_share_error_mesage "La création du fichier vcard a échoué" VCard creation failed - + contact_details_share_success_title "VCard créée" VCard created - + contact_details_share_success_mesage "VCard du contact enregistrée dans %1" VCard has been saved in %1 - + contact_details_share_email_title "Partage de contact" Share contact - + contact_details_delete "Supprimer ce contact" Delete contact @@ -4362,7 +4420,6 @@ Expiration : %1 default_account_connection_state_error_toast - Erreur durant la connexion, veuillez vérifier vos paramètres Error during connection @@ -4377,144 +4434,144 @@ Expiration : %1 MainLayout - + bottom_navigation_calls_label "Appels" Calls - + open_calls_page_accessible_name "Open calls page" Open calls pages - + bottom_navigation_contacts_label "Contacts" Contacts - + open_contacts_page_accessible_name "Open contacts page" Open contacts page - + bottom_navigation_conversations_label "Conversations" Conversations - + open_conversations_page_accessible_name "Open conversations page" Open conversations page - + bottom_navigation_meetings_label "Réunions" Meetings - + open_contact_page_accessible_name "Open meetings page" Open meetings page - + searchbar_placeholder_text "Rechercher un contact, appeler %1" Find contact, call %1 - + searchbar_placeholder_text_chat_feature_enabled "ou envoyer un message …" or send message … - + do_not_disturb_accessible_name "Do not disturb" Do not disturb - - + + contact_presence_status_disable_do_not_disturb "Désactiver ne pas déranger" Disable do not disturb - + information_popup_error_title Error - + no_voicemail_uri_error_message "L'URI de messagerie vocale n'est pas définie." The voicemail URI is not defined. - + account_list_accessible_name "Account list" account list - + application_options_accessible_name "Application options" Application options - + drawer_menu_manage_account Mon compte My account - + contact_presence_status_enable_do_not_disturb "Activer ne pas déranger" Enable do not disturb - + settings_title Settings - + recordings_title "Enregistrements" Records - + help_title "Aide" Help - + help_quit_title "Quitter l'application" Quit the app - + quit_app_question "Quitter %1 ?" Quit %1 ? - + drawer_menu_add_account "Ajouter un compte" Add an account @@ -4721,163 +4778,163 @@ Expiration : %1 No meeting - + meeting_schedule_cancel_dialog_message "Souhaitez-vous annuler et supprimer cette réunion ?" Would you like to cancel and delete this meeting? - + meeting_schedule_delete_dialog_message Souhaitez-vous supprimer cette réunion ? Would you like to delete this meeting? - + meeting_schedule_cancel_and_delete_action "Annuler et supprimer" Cancel and delete - + meeting_schedule_delete_only_action "Supprimer seulement" Delete only - + meeting_schedule_delete_action "Supprimer" Delete - + back_action Retour Back - + meetings_list_title Réunions Meetings - + meetings_search_hint "Rechercher une réunion" Find meeting - + list_filter_no_result_found "Aucun résultat…" No result… - + meetings_empty_list "Aucune réunion" No meeting - - + + meeting_schedule_title "Nouvelle réunion" New meeting - + create Create - - - - - - + + + + + + information_popup_error_title Error - - + + meeting_schedule_mandatory_field_not_filled_toast Veuillez saisir un titre et sélectionner au moins un participant Please fill the title and select at least one participant - - + + meeting_schedule_duration_error_toast "La fin de la conférence doit être plus récente que son début" The end of the conference must be more recent than its beginning - - + + meeting_schedule_creation_in_progress "Création de la réunion en cours …" Creation in progress… - + meeting_info_created_toast "Réunion planifiée avec succès" Meeting successfully created - + meeting_failed_to_schedule_toast "Échec de création de la réunion !" Failed to create meeting! - + save Save - - + + saved "Enregistré" Saved - + meeting_info_updated_toast "Réunion mise à jour" Meeting updated - + meeting_schedule_edit_in_progress "Modification de la réunion en cours…" Meeting update in progress… - + meeting_failed_to_edit_toast "Échec de la modification de la réunion !" Failed to update meeting ! - + meeting_schedule_add_participants_title "Ajouter des participants" Add participants - + meeting_schedule_add_participants_apply Apply - + group_call_participant_selected "%n participant(s) sélectionné(s)" @@ -4886,31 +4943,31 @@ Expiration : %1 - + meeting_info_delete "Supprimer la réunion" Delete meeting - + meeting_address_copied_to_clipboard_toast "Adresse de la réunion copiée" Meeting URI copied - + meeting_schedule_timezone_title "Fuseau horaire" Timezone - + meeting_info_organizer_label "Organisateur" Organizer - + meeting_info_join_title "Rejoindre la réunion" Join meeting @@ -5141,6 +5198,36 @@ Expiration : %1 New message on chatroom %1 + + NumericPad + + + numpad_longpress_accessible_name + %1 longpress %2 + %1 longpress %2 + + + + call_accessible_name + Call + Call + + + + erase_accessible_name + Erase + Erase + + + + NumericPadPopup + + + close_numeric_pad_accessible_name + Close numeric pad + Close numeric pad + + OIDCModel @@ -6114,7 +6201,6 @@ To enable them in a commercial project, please contact us. unknown_audio_device_name - "Unknown device" Unknown device name @@ -6370,9 +6456,6 @@ To enable them in a commercial project, please contact us. chat_error - Error creating or opening the chat ----------- -Error in the chat Error in the chat diff --git a/Linphone/data/languages/fr.ts b/Linphone/data/languages/fr.ts index dc8c5c138..67c519909 100644 --- a/Linphone/data/languages/fr.ts +++ b/Linphone/data/languages/fr.ts @@ -22,6 +22,21 @@ Sauvegarder les paramètres %1 + + AbstractSettingsMenu + + + back_previous_menu_accessible_name + Back to previous menu + Retour au menu précédent + + + + settings_page_selection_accessible_name + Settings page selection + Selection de la page de paramètre + + AbstractWindow @@ -656,143 +671,141 @@ App - + remote_provisioning_dialog Voulez-vous télécharger et appliquer la configuration depuis cette adresse ? Voulez-vous télécharger et appliquer la configuration depuis cette adresse ? - - - + + + info_popup_error_title Error Erreur - - + + info_popup_configuration_failed_message Remote provisioning failed : %1 La configuration distante a échoué : %1 - + info_popup_error_checking_update An error occured while trying to check update. Please try again later or contact support team. Une erreur est survenue lors de la recherche de mise à jour. Merci de réessayer plus tard ou de contacter l'équipe de support. - + info_popup_new_version_download_label - Download it ! Téléchargez-là ! - + info_popup_new_version_available_title New version available ! Nouvelle version disponible ! - + info_popup_new_version_available_message A new version of Linphone (%1) is available. %2 Une nouvelle version de Linphone (%1) est disponible. %2 - + info_popup_version_up_to_date_title - Up to date À jour - + info_popup_version_up_to_date_message Your version is up to date Votre version est à jour - + configuration_error_detail not reachable indisponible - + application_description "A free and open source SIP video-phone." A free and open source SIP video-phone. - + command_line_arg_order "Send an order to the application towards a command line" Send an order to the application towards a command line - + command_line_option_show_help Show this help - + command_line_option_show_app_version Afficher la version de l'application - + command_line_option_config_to_fetch "Specify the linphone configuration file to be fetched. It will be merged with the current configuration." Specify the linphone configuration file to be fetched. It will be merged with the current configuration. - + command_line_option_config_to_fetch_arg "URL, path or file" URL, path or file - + command_line_option_minimized Minimiser - + command_line_option_log_to_stdout Log to stdout some debug information while running - + command_line_option_print_app_logs_only "Print only logs from the application" Print only logs from the application - + hide_action "Cacher" "Afficher" Cacher - + show_action Afficher - + quit_action "Quitter" Quitter - + check_for_update Check for update Rechercher une mise à jour - + mark_all_read_action Marquer tout comme lu @@ -1005,11 +1018,35 @@ CallHistoryListView - + call_name_accessible_button Call %1 Appeler %1 + + + call_history_entry_accessible_name + %1 - %2 - %3 - right arrow for call-back button + %1 - %2 - %3 - flèche droite pour bouton de rappel + + + + notification_missed_call_title + "Appel manqué" + Appel manqué + + + + call_outgoing + "Appel sortant" + Appel sortant + + + + call_audio_incoming + "Appel entrant" + Appel entrant + CallLayout @@ -1066,7 +1103,6 @@ local_group_call - "Local group call" Appel de groupe local @@ -1216,180 +1252,180 @@ Historique d'appel vide - + history_dialog_delete_all_call_logs_title Supprimer l'historique d'appels ? Supprimer l'historique d'appels ? - + history_dialog_delete_all_call_logs_message "L'ensemble de votre historique d'appels sera définitivement supprimé." L'ensemble de votre historique d'appels sera définitivement supprimé. - + history_dialog_delete_call_logs_title Supprimer l'historique d'appels ? Supprimer l'historique d'appels ? - + history_dialog_delete_call_logs_message "L'ensemble de votre historique d'appels avec ce correspondant sera définitivement supprimé." L'ensemble de votre historique d'appels avec ce correspondant sera définitivement supprimé. - + call_history_call_list_title "Appels" Appels - + call_history_options_accessible_name Options de l' - - + + menu_delete_history "Supprimer l'historique" Supprimer l'historique - + call_history_list_options_accessible_name Call history options Options de la liste de l'historique d'appel - + create_new_call_accessible_name Create new call Créer un nouvel appel - + call_search_in_history "Rechercher un appel" Rechercher un appel - + call_forward_to_address_info Transférer l'appel à : - + call_forward_to_address_info_voicemail Boîte vocale - + list_filter_no_result_found "Aucun résultat…" Aucun résultat… - + history_list_empty_history "Aucun appel dans votre historique" Aucun appel dans votre historique - + return_to_call_history_accessible_name Return to call history Retourner à l'historique d'appels - + call_action_start_new_call "Nouvel appel" Nouvel appel - + call_start_group_call_title "Appel de groupe" Appel de groupe - + call_action_start_group_call "Lancer" Lancer - - - + + + information_popup_error_title Erreur - + group_call_error_must_have_name "Un nom doit être donné à l'appel de groupe Un nom doit être donné à l'appel de groupe - + group_call_error_not_connected "Vous n'etes pas connecté" Vous n'etes pas connecté - + menu_see_existing_contact "Show contact" Voir le contact - + menu_add_address_to_contacts "Add to contacts" Ajouter aux contacts - + menu_copy_sip_address "Copier l'adresse SIP" Copier l'adresse SIP - + sip_address_copied_to_clipboard_toast Adresse copiée Adresse copiée - + sip_address_copied_to_clipboard_message L'adresse a été copié dans le presse_papiers L'adresse a été copié dans le presse-papiers - + sip_address_copy_to_clipboard_error "Erreur lors de la copie de l'adresse" Erreur lors de la copie de l'adresse - + notification_missed_call_title "Appel manqué" Appel manqué - + call_outgoing "Appel sortant" Appel sortant - + call_audio_incoming "Appel entrant" Appel entrant @@ -2312,7 +2348,6 @@ Error popup_error_nb_files_not_found_message - %n files were not found %1 fichiers n'ont pas été trouvés @@ -2333,7 +2368,6 @@ Error popup_error_unsupported_files_message - Unable to get supported mime type for %1 files. Impossible de trouver un type MIME pris en charge pour %1 fichiers. @@ -2563,115 +2597,115 @@ en bout. Seul votre correspondant peut les déchiffrer. Aucune conversation - + info_popup_error_title Erreur - + info_popup_chatroom_creation_failed Chat room creation failed ! La création de la conversation a échoué ! - + loading_popup_chatroom_creation_pending_message Chat room is being created... Création de la conversation en cours... - + chat_dialog_delete_chat_title Supprimer la conversation ? Supprimer la conversation ? - + chat_dialog_delete_chat_message "La conversation et tous ses messages seront supprimés." La conversation et tous ses messages seront supprimés. - + chat_list_title "Conversations" Conversations - + menu_mark_all_as_read "mark all as read" Tout marquer comme lu - + chat_search_in_history "Rechercher une conversation" Rechercher une conversation - + list_filter_no_result_found "Aucun résultat…" Aucun résultat… - + chat_list_empty_history "Aucune conversation dans votre historique" Aucune conversation dans votre historique - + chat_action_start_new_chat "New chat" Nouvelle conversation - + chat_start_group_chat_title "Nouveau groupe" Nouveau groupe - + chat_action_start_group_chat "Créer" Créer - - - + + + information_popup_error_title Erreur - + information_popup_chat_creation_failed_message "La création a échoué" La création a échoué - + group_chat_error_must_have_name "Un nom doit être donné au groupe Un nom doit être donné au groupe - + group_chat_error_no_participant "Please select at least one participant Veuillez sélectionner au moins un participant - + group_call_error_not_connected "Vous n'etes pas connecté" Vous n'êtes pas connecté - + chat_creation_in_progress Creation de la conversation en cours … Création de la conversation en cours… @@ -2731,28 +2765,34 @@ en bout. Seul votre correspondant peut les déchiffrer. CliModel + show_function_description - Afficher + Afficher + fetch_config_function_description - Récupérer une configuration + Récupérer une configuration + call_function_description - Appeler + Appeler + bye_function_description - Raccrocher + Raccrocher + accept_function_description - Accepter + Accepter + decline_function_description - Décliner + Décliner @@ -2941,53 +2981,71 @@ en bout. Seul votre correspondant peut les déchiffrer. ContactListItem - + + call_with_contact_name_accessible_button + "Call %1" + Appeller %1 + + + + video_call_with_contact_name_accessible_button + "Video call %1" + Appel vidéo %1 + + + + message_with_contact_name_accessible_button + "Message %1" + Message %1 + + + contact_details_remove_from_favourites "Enlever des favoris" Enlever des favoris - + contact_details_add_to_favourites "Ajouter aux favoris" Ajouter aux favoris - + Partager Partager - + information_popup_error_title Erreur - + information_popup_vcard_creation_error La création du fichier vcard a échoué La création du fichier vcard a échoué - + information_popup_vcard_creation_title VCard créée VCard créée - + information_popup_vcard_creation_success "VCard du contact enregistrée dans %1" VCard du contact enregistrée dans %1 - + contact_sharing_email_title Partage de contact Partage de contact - + contact_details_delete "Supprimer" Supprimer @@ -3023,149 +3081,149 @@ en bout. Seul votre correspondant peut les déchiffrer. Aucun contact pour le moment - + contact_new_title "Nouveau contact" Nouveau contact - + create Créer - + contact_edit_title "Modifier contact" Modifier contact - + save Enregistrer - + contact_dialog_delete_title Supprimer %1 ?" Supprimer %1 ? - + contact_dialog_delete_message Ce contact sera définitivement supprimé. Ce contact sera définitivement supprimé. - + contact_deleted_toast "Contact supprimé" Contact supprimé - + contact_deleted_message "%1 a été supprimé" %1 a été supprimé - + contact_dialog_devices_trust_popup_title "Augmenter la confiance" Augmenter la confiance - + contact_dialog_devices_trust_popup_message "Pour augmenter le niveau de confiance vous devez appeler les différents appareils de votre contact et valider un code.<br><br>Vous êtes sur le point d’appeler “%1” voulez vous continuer ?" Pour augmenter le niveau de confiance vous devez appeler les différents appareils de votre contact et valider un code.<br><br>Vous êtes sur le point d’appeler “%1” voulez vous continuer ? - + popup_do_not_show_again Ne plus afficher Ne plus afficher - + cancel Annuler - + dialog_call "Appeler" Appeler - + contact_dialog_devices_trust_help_title "Niveau de confiance" Niveau de confiance - + contact_dialog_devices_trust_help_message "Vérifiez les appareils de votre contact pour confirmer que vos communications seront sécurisées et sans compromission. <br>Quand tous seront vérifiés, vous atteindrez le niveau de confiance maximal." Vérifiez les appareils de votre contact pour confirmer que vos communications seront sécurisées et sans compromission. <br>Quand tous seront vérifiés, vous atteindrez le niveau de confiance maximal. - + dialog_ok "Ok" Ok - + bottom_navigation_contacts_label "Contacts" Contacts - + search_bar_look_for_contact_text Rechercher un contact Rechercher un contact - + list_filter_no_result_found Aucun résultat… Aucun résultat… - + contact_list_empty Aucun contact pour le moment Aucun contact pour le moment - + expand_accessible_name Expand %1 Étendre %1 - + shrink_accessible_name Shrink %1 Réduire %1 - + create_contact_accessible_name Create new contact Créer un nouveau contact - + more_info_accessible_name More info %1 Plus d'information %1 - - + + contact_details_edit Edit ---------- @@ -3173,151 +3231,151 @@ en bout. Seul votre correspondant peut les déchiffrer. Éditer - + contact_call_action "Appel" Appel - + contact_message_action "Message" Message - + contact_video_call_action "Appel vidéo" Appel vidéo - + contact_details_numbers_and_addresses_title "Coordonnées" Coordonnées - + call_adress_accessible_name Call address %1 Appeller l'adresse %1 - + contact_details_company_name "Société :" Société : - + contact_details_job_title "Poste :" Poste : - + contact_details_medias_title "Medias" Medias - - + + contact_details_medias_subtitle "Afficher les medias partagés" Afficher les medias partagés - + contact_details_trust_title "Confiance" Confiance - + contact_dialog_devices_trust_title "Niveau de confiance - Appareils vérifiés" Niveau de confiance - Appareils vérifiés - + contact_details_no_device_found "Aucun appareil" Aucun appareil - + contact_device_without_name "Appareil inconnu" Appareil inconnu - + contact_make_call_check_device_trust "Vérifier" Vérifier - + verify_device_accessible_name Verify %1 device Vérifier l'appareil %1 - + contact_details_actions_title "Autres actions" Autres actions - + contact_details_remove_from_favourites "Retirer des favoris" Retirer des favoris - + contact_details_add_to_favourites "Ajouter aux favoris" Ajouter aux favoris - + contact_details_share "Partager" Partager - + information_popup_error_title Erreur - + contact_details_share_error_mesage "La création du fichier vcard a échoué" La création du fichier vcard a échoué - + contact_details_share_success_title "VCard créée" VCard créée - + contact_details_share_success_mesage "VCard du contact enregistrée dans %1" VCard du contact enregistrée dans %1 - + contact_details_share_email_title "Partage de contact" Partage de contact - + contact_details_delete "Supprimer ce contact" Supprimer ce contact @@ -4337,7 +4395,6 @@ Expiration : %1 default_account_connection_state_error_toast - Erreur durant la connexion, veuillez vérifier vos paramètres Erreur durant la connexion @@ -4352,144 +4409,144 @@ Expiration : %1 MainLayout - + bottom_navigation_calls_label "Appels" Appels - + open_calls_page_accessible_name "Open calls page" Ouvrir la page des appels - + bottom_navigation_contacts_label "Contacts" Contacts - + open_contacts_page_accessible_name "Open contacts page" Ouvrir la page des contacts - + bottom_navigation_conversations_label "Conversations" Conversations - + open_conversations_page_accessible_name "Open conversations page" Ouvrir la page des conversations - + bottom_navigation_meetings_label "Réunions" Réunions - + open_contact_page_accessible_name "Open meetings page" Ouvrir la page des réunions - + searchbar_placeholder_text "Rechercher un contact, appeler %1" Rechercher un contact, appeler %1 - + searchbar_placeholder_text_chat_feature_enabled "ou envoyer un message …" ou envoyer un message … - + do_not_disturb_accessible_name "Do not disturb" Ne pas déranger - - + + contact_presence_status_disable_do_not_disturb "Désactiver ne pas déranger" Désactiver ne pas déranger - + information_popup_error_title Erreur - + no_voicemail_uri_error_message "L'URI de messagerie vocale n'est pas définie." L'URI de messagerie vocale n'est pas définie. - + account_list_accessible_name "Account list" liste des comptes - + application_options_accessible_name "Application options" Options de l'application - + drawer_menu_manage_account Mon compte Mon compte - + contact_presence_status_enable_do_not_disturb "Activer ne pas déranger" Activer ne pas déranger - + settings_title Paramètres - + recordings_title "Enregistrements" Enregistrements - + help_title "Aide" Aide - + help_quit_title "Quitter l'application" Quitter l'application - + quit_app_question "Quitter %1 ?" Quitter %1 ? - + drawer_menu_add_account "Ajouter un compte" Ajouter un compte @@ -4692,163 +4749,163 @@ Expiration : %1 Aucune réunion - + meeting_schedule_cancel_dialog_message "Souhaitez-vous annuler et supprimer cette réunion ?" Souhaitez-vous annuler et supprimer cette réunion ? - + meeting_schedule_delete_dialog_message Souhaitez-vous supprimer cette réunion ? Souhaitez-vous supprimer cette réunion ? - + meeting_schedule_cancel_and_delete_action "Annuler et supprimer" Annuler et supprimer - + meeting_schedule_delete_only_action "Supprimer seulement" Supprimer seulement - + meeting_schedule_delete_action "Supprimer" Supprimer - + back_action Retour Retour - + meetings_list_title Réunions Réunions - + meetings_search_hint "Rechercher une réunion" Rechercher une réunion - + list_filter_no_result_found "Aucun résultat…" Aucun résultat… - + meetings_empty_list "Aucune réunion" Aucune réunion - - + + meeting_schedule_title "Nouvelle réunion" Nouvelle réunion - + create Créer - - - - - - + + + + + + information_popup_error_title Erreur - - + + meeting_schedule_mandatory_field_not_filled_toast Veuillez saisir un titre et sélectionner au moins un participant Veuillez saisir un titre et sélectionner au moins un participant - - + + meeting_schedule_duration_error_toast "La fin de la conférence doit être plus récente que son début" La fin de la conférence doit être plus récente que son début - - + + meeting_schedule_creation_in_progress "Création de la réunion en cours …" Création de la réunion en cours… - + meeting_info_created_toast "Réunion planifiée avec succès" Réunion planifiée avec succès - + meeting_failed_to_schedule_toast "Échec de création de la réunion !" Échec de création de la réunion ! - + save Enregistrer - - + + saved "Enregistré" Enregistré - + meeting_info_updated_toast "Réunion mise à jour" Réunion mise à jour - + meeting_schedule_edit_in_progress "Modification de la réunion en cours…" Modification de la réunion en cours… - + meeting_failed_to_edit_toast "Échec de la modification de la réunion !" Échec de la modification de la réunion ! - + meeting_schedule_add_participants_title "Ajouter des participants" Ajouter des participants - + meeting_schedule_add_participants_apply Appliquer - + group_call_participant_selected "%n participant(s) sélectionné(s)" @@ -4857,31 +4914,31 @@ Expiration : %1 - + meeting_info_delete "Supprimer la réunion" Supprimer la réunion - + meeting_address_copied_to_clipboard_toast "Adresse de la réunion copiée" Adresse de la réunion copiée - + meeting_schedule_timezone_title "Fuseau horaire" Fuseau horaire - + meeting_info_organizer_label "Organisateur" Organisateur - + meeting_info_join_title "Rejoindre la réunion" Rejoindre la réunion @@ -5112,6 +5169,36 @@ Expiration : %1 Nouveau message sur la conversation %1 + + NumericPad + + + numpad_longpress_accessible_name + %1 longpress %2 + %1 appui long %2 + + + + call_accessible_name + Call + Appeler + + + + erase_accessible_name + Erase + Effacer + + + + NumericPadPopup + + + close_numeric_pad_accessible_name + Close numeric pad + Fermer le pavé numérique + + OIDCModel @@ -6080,7 +6167,6 @@ Pour les activer dans un projet commercial, merci de nous contacter. unknown_audio_device_name - "Unknown device" Appareil inconnu @@ -6282,9 +6368,6 @@ Pour les activer dans un projet commercial, merci de nous contacter. chat_error - Error creating or opening the chat ----------- -Error in the chat Erreur dans le chat diff --git a/Linphone/tool/CMakeLists.txt b/Linphone/tool/CMakeLists.txt index e14869028..923c6f304 100644 --- a/Linphone/tool/CMakeLists.txt +++ b/Linphone/tool/CMakeLists.txt @@ -27,6 +27,7 @@ list(APPEND _LINPHONEAPP_SOURCES tool/file/TemporaryFile.cpp tool/ui/DashRectangle.cpp + tool/ui/FocusNavigator.cpp tool/accessibility/AccessibilityHelper.cpp tool/accessibility/KeyboardShortcuts.cpp diff --git a/Linphone/tool/accessibility/FocusHelper.cpp b/Linphone/tool/accessibility/FocusHelper.cpp index 392673ce4..877f899f9 100644 --- a/Linphone/tool/accessibility/FocusHelper.cpp +++ b/Linphone/tool/accessibility/FocusHelper.cpp @@ -34,6 +34,7 @@ bool FocusHelperAttached::eventFilter(QObject *watched, QEvent *event) { auto fe = static_cast(event); if (fe) { int focusReason = fe->reason(); + // qDebug() << "FocusReason" << focusReason; // Usefull to debug focus problems m_keyboardFocus = (focusReason == Qt::TabFocusReason || focusReason == Qt::BacktabFocusReason); m_otherFocus = focusReason == Qt::OtherFocusReason; emit keyboardFocusChanged(); diff --git a/Linphone/tool/ui/FocusNavigator.cpp b/Linphone/tool/ui/FocusNavigator.cpp new file mode 100644 index 000000000..e94724b70 --- /dev/null +++ b/Linphone/tool/ui/FocusNavigator.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2010-2025 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "FocusNavigator.hpp" + +#include +#include + +FocusNavigator::FocusNavigator(QObject *parent) : QObject(parent) { + connect(qApp, &QGuiApplication::focusObjectChanged, this, &FocusNavigator::onFocusObjectChanged); + qApp->installEventFilter(this); +} + +bool FocusNavigator::doesLastFocusWasKeyboard() { + return mLastFocusWasKeyboard; +} + +bool FocusNavigator::eventFilter(QObject *, QEvent *event) { + switch (event->type()) { + case QEvent::FocusIn: { + auto fe = static_cast(event); + if (fe) { + int focusReason = fe->reason(); + mLastFocusWasKeyboard = (focusReason == Qt::TabFocusReason || focusReason == Qt::BacktabFocusReason); + } + break; + } + default: + break; + } + return false; +} + +void FocusNavigator::onFocusObjectChanged(QObject *obj) { + // qDebug() << "New focus object" << obj; // Usefull to debug focus problems + auto item = qobject_cast(obj); + if (!item) return; + emit focusChanged(item, mLastFocusWasKeyboard); +} diff --git a/Linphone/tool/ui/FocusNavigator.hpp b/Linphone/tool/ui/FocusNavigator.hpp new file mode 100644 index 000000000..955cf743e --- /dev/null +++ b/Linphone/tool/ui/FocusNavigator.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010-2025 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +class FocusNavigator : public QObject { + Q_OBJECT + +public: + explicit FocusNavigator(QObject *parent = nullptr); + Q_INVOKABLE bool doesLastFocusWasKeyboard(); + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; + +signals: + void focusChanged(QQuickItem *item, bool keyboardFocus); + +private: + bool mLastFocusWasKeyboard = false; + void onFocusObjectChanged(QObject *obj); +}; diff --git a/Linphone/view/Control/Button/IconButton.qml b/Linphone/view/Control/Button/IconButton.qml index fce059491..2385f1186 100644 --- a/Linphone/view/Control/Button/IconButton.qml +++ b/Linphone/view/Control/Button/IconButton.qml @@ -23,7 +23,8 @@ Button { : mainItem.hovered || mainItem.hasNavigationFocus ? mainItem.hoveredColor : mainItem.color - border.color: mainItem.borderColor + border.color: mainItem.keyboardFocus ? mainItem.keyboardFocusedBorderColor : mainItem.borderColor + border.width: mainItem.keyboardFocus ? mainItem.keyboardFocusedBorderWidth : mainItem.borderWidth } contentItem: EffectImage { diff --git a/Linphone/view/Control/Container/VerticalTabBar.qml b/Linphone/view/Control/Container/VerticalTabBar.qml index 1d655251f..20dbedf65 100644 --- a/Linphone/view/Control/Container/VerticalTabBar.qml +++ b/Linphone/view/Control/Container/VerticalTabBar.qml @@ -18,6 +18,9 @@ Control.TabBar { property AccountGui defaultAccount property int visibleCount: 0 + + signal enterPressed() + signal spacePressed() // Call it after model is ready. If done before, Repeater will not be updated function initButtons(){ @@ -96,6 +99,8 @@ Control.TabBar { onVisibleChanged: mainItem.updateVisibleCount() text: modelData.accessibilityLabel property bool keyboardFocus: FocusHelper.keyboardFocus + focusPolicy: Qt.StrongFocus + activeFocusOnTab: true UnreadNotification { unread: !defaultAccount ? -1 @@ -165,6 +170,23 @@ Control.TabBar { mainItem.implicitWidth = Math.max(mainItem.implicitWidth, advanceWidth + buttonIcon.buttonSize) } } + Keys.onPressed: event => { + if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) { + mainItem.enterPressed() + } else if(event.key === Qt.Key_Space){ + mainItem.spacePressed() + } else if(event.key === Qt.Key_Down){ + event.accepted = true; + if(TabBar.index >= mainItem.visibleCount - 1) + return; + tabButton.nextItemInFocusChain(true).forceActiveFocus(Qt.TabFocusReason) + } else if(event.key === Qt.Key_Up){ + event.accepted = true; + if(TabBar.index <= 0) + return; + tabButton.nextItemInFocusChain(false).forceActiveFocus(Qt.BacktabFocusReason) + } + } onClicked: { mainItem.setCurrentIndex(TabBar.index) } diff --git a/Linphone/view/Control/Display/Call/CallHistoryListView.qml b/Linphone/view/Control/Display/Call/CallHistoryListView.qml index 89c023c2d..6ac875503 100644 --- a/Linphone/view/Control/Display/Call/CallHistoryListView.qml +++ b/Linphone/view/Control/Display/Call/CallHistoryListView.qml @@ -5,17 +5,22 @@ import QtQuick.Controls.Basic as Control import Linphone import UtilsCpp import SettingsCpp +import CustomControls 1.0 import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils ListView { id: mainItem clip: true + keyNavigationEnabled: false // We will reimplement the keyNavigation + activeFocusOnTab: true property SearchBar searchBar property bool loading: false property string searchText: searchBar?.text property real busyIndicatorSize: Utils.getSizeWithScreenRatio(60) + property bool keyboardFocus: FocusHelper.keyboardFocus + property bool lastFocusByNavigationKeyboard: false // Workaround to get the correct focusReason signal resultsReceived @@ -41,7 +46,26 @@ ListView { Keys.onPressed: event => { if (event.key == Qt.Key_Escape) { console.log("Back") - searchBar.forceActiveFocus() + searchBar.forceActiveFocus(Qt.BacktabFocusReason) + event.accepted = true + } + + // Re-implement key navigation to have Qt.TabFocusReason and Qt.BacktabFocusReason instead of Qt.OtherFocusReason when using arrows to navigate in listView + else if (event.key === Qt.Key_Up) { + if(currentIndex === 0){ + searchBar.forceActiveFocus(Qt.BacktabFocusReason) + lastFocusByNavigationKeyboard = false + }else{ + decrementCurrentIndex() + currentItem.forceActiveFocus(Qt.BacktabFocusReason) // The focusReason is created by QT later, need to create a workaround + lastFocusByNavigationKeyboard = true + } + event.accepted = true + } + else if(event.key === Qt.Key_Down){ + incrementCurrentIndex() + currentItem.forceActiveFocus(Qt.TabFocusReason) // The focusReason is created by QT later, need to create a workaround + lastFocusByNavigationKeyboard = true event.accepted = true } } @@ -113,6 +137,8 @@ ListView { delegate: FocusScope { width: mainItem.width height: Utils.getSizeWithScreenRatio(56) + Accessible.role: Accessible.ListItem + RowLayout { z: 1 anchors.fill: parent @@ -188,12 +214,14 @@ ListView { } } BigButton { + id: callButton visible: !modelData.core.isConference || !SettingsCpp.disableMeetingsFeature style: ButtonStyle.noBackground icon.source: AppIcons.phone - focus: true + focus: false activeFocusOnTab: false asynchronous: false + //: Call %1 Accessible.name: qsTr("call_name_accessible_button").arg(historyAvatar.displayNameVal) onClicked: { @@ -206,12 +234,38 @@ ListView { UtilsCpp.createCall(modelData.core.remoteAddress) } } + Keys.onPressed: event => { + if (event.key === Qt.Key_Left){ + backgroundMouseArea.forceActiveFocus(Qt.BacktabFocusReason) + lastFocusByNavigationKeyboard = true; + } + } + onActiveFocusChanged: { + if (!activeFocus) { + console.log("Unfocus button"); + callButton.focus = false // Make sure to be unfocusable (could be when called by forceActiveFocus) + backgroundMouseArea.focus = true + } + } } } MouseArea { + id: backgroundMouseArea hoverEnabled: true anchors.fill: parent focus: true + property bool keyboardFocus: FocusHelper.keyboardFocus || activeFocus && lastFocusByNavigationKeyboard + + //: %1 - %2 - %3 - right arrow for call-back button + Accessible.name: qsTr("call_history_entry_accessible_name").arg( + //: "Appel manqué" + modelData.core.status === LinphoneEnums.CallStatus.Missed ? qsTr("notification_missed_call_title") + //: "Appel sortant" + : modelData.core.isOutgoing ? qsTr("call_outgoing") + //: "Appel entrant" + : qsTr("call_audio_incoming") + ).arg(historyAvatar.displayNameVal).arg(UtilsCpp.formatDate(modelData.core.date)) + onContainsMouseChanged: { if (containsMouse) mainItem.lastMouseContainsIndex = index @@ -224,12 +278,20 @@ ListView { radius: Utils.getSizeWithScreenRatio(8) color: mainItem.currentIndex === index ? DefaultStyle.main2_200 : DefaultStyle.main2_100 + border.color: backgroundMouseArea.keyboardFocus ? DefaultStyle.main2_900 : "transparent" + border.width: backgroundMouseArea.keyboardFocus ? Utils.getSizeWithScreenRatio(3) : 0 visible: mainItem.lastMouseContainsIndex === index || mainItem.currentIndex === index } onPressed: { mainItem.currentIndex = model.index mainItem.forceActiveFocus() + mainItem.lastFocusByNavigationKeyboard = false + } + Keys.onPressed: event => { + if(event.key === Qt.Key_Right){ + callButton.forceActiveFocus(Qt.TabFocusReason) + } } } } diff --git a/Linphone/view/Control/Display/Contact/AllContactListView.qml b/Linphone/view/Control/Display/Contact/AllContactListView.qml index 4e3af895a..f275677a8 100644 --- a/Linphone/view/Control/Display/Contact/AllContactListView.qml +++ b/Linphone/view/Control/Display/Contact/AllContactListView.qml @@ -185,7 +185,7 @@ Flickable { direction) if (newItem) { newItem.selectIndex( - direction > 0 ? -1 : newItem.model.count - 1) + direction > 0 ? -1 : newItem.model.count - 1, direction > 0 ? Qt.BacktabFocusReason : Qt.TabFocusReason) event.accepted = true } } diff --git a/Linphone/view/Control/Display/Contact/ContactListItem.qml b/Linphone/view/Control/Display/Contact/ContactListItem.qml index 9d4f57660..bc8458b3a 100644 --- a/Linphone/view/Control/Display/Contact/ContactListItem.qml +++ b/Linphone/view/Control/Display/Contact/ContactListItem.qml @@ -6,6 +6,7 @@ import Linphone import UtilsCpp import ConstantsCpp import SettingsCpp +import CustomControls 1.0 import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils @@ -149,6 +150,9 @@ FocusScope { onClicked: UtilsCpp.createCall(mainItem.addressFromFilter) KeyNavigation.left: chatButton KeyNavigation.right: videoCallButton + //: "Call %1" + Accessible.name: qsTr("call_with_contact_name_accessible_button").arg(mainItem.displayName) + keyboardFocus: FocusHelper.keyboardFocus || FocusHelper.otherFocus } IconButton { id: videoCallButton @@ -164,6 +168,9 @@ FocusScope { onClicked: UtilsCpp.createCall(mainItem.addressFromFilter, {"localVideoEnabled": true}) KeyNavigation.left: callButton KeyNavigation.right: chatButton + //: "Video call %1" + Accessible.name: qsTr("video_call_with_contact_name_accessible_button").arg(mainItem.displayName) + keyboardFocus: FocusHelper.keyboardFocus || FocusHelper.otherFocus } IconButton { id: chatButton @@ -184,6 +191,9 @@ FocusScope { console.debug("[ContactListItem.qml] Open conversation") mainWindow.displayChatPage(mainItem.addressFromFilter) } + //: "Message %1" + Accessible.name: qsTr("message_with_contact_name_accessible_button").arg(mainItem.displayName) + keyboardFocus: FocusHelper.keyboardFocus || FocusHelper.otherFocus } } PopupButton { diff --git a/Linphone/view/Control/Display/Contact/ContactListView.qml b/Linphone/view/Control/Display/Contact/ContactListView.qml index ca86cd767..d5944d301 100644 --- a/Linphone/view/Control/Display/Contact/ContactListView.qml +++ b/Linphone/view/Control/Display/Contact/ContactListView.qml @@ -68,13 +68,13 @@ ListView { property bool _moveToIndex: false - function selectIndex(index){ + function selectIndex(index, focusReason = Qt.OtherFocusReason){ if(mainItem.expanded && index >= 0){ mainItem.currentIndex = index var item = itemAtIndex(mainItem.currentIndex) if(item){// Item is ready and available mainItem.highlightedContact = item.searchResultItem - item.forceActiveFocus() + item.forceActiveFocus(focusReason) updatePosition() _moveToIndex = false }else{// Move on the next items load. @@ -85,7 +85,7 @@ ListView { mainItem.currentIndex = -1 mainItem.highlightedContact = null if(headerItem) { - headerItem.forceActiveFocus() + headerItem.forceActiveFocus(focusReason) } _moveToIndex = false } @@ -97,12 +97,12 @@ ListView { if(event.key == Qt.Key_Up || event.key == Qt.Key_Down){ if(event.key == Qt.Key_Up && !headerItem.activeFocus) { if(currentIndex >= 0 ) { - selectIndex(mainItem.currentIndex-1) + selectIndex(mainItem.currentIndex-1, Qt.BacktabFocusReason) event.accepted = true; } }else if(event.key == Qt.Key_Down && mainItem.expanded){ if(currentIndex < model.count - 1) { - selectIndex(mainItem.currentIndex+1) + selectIndex(mainItem.currentIndex+1, Qt.TabFocusReason) event.accepted = true; } } diff --git a/Linphone/view/Control/Display/Settings/SettingsMenuItem.qml b/Linphone/view/Control/Display/Settings/SettingsMenuItem.qml index 2792a8d91..e953b0f49 100644 --- a/Linphone/view/Control/Display/Settings/SettingsMenuItem.qml +++ b/Linphone/view/Control/Display/Settings/SettingsMenuItem.qml @@ -20,6 +20,7 @@ Item { //: %1 settings Accessible.name: qsTr("setting_tab_accessible_name").arg(titleText) + Accessible.role: Accessible.ListItem Keys.onPressed: (event)=>{ if(event.key == Qt.Key_Space || event.key == Qt.Key_Return || event.key == Qt.Key_Enter){ diff --git a/Linphone/view/Control/Input/NumericPad.qml b/Linphone/view/Control/Input/NumericPad.qml index f145c14e1..c5fb1b5dc 100644 --- a/Linphone/view/Control/Input/NumericPad.qml +++ b/Linphone/view/Control/Input/NumericPad.qml @@ -172,6 +172,9 @@ FocusScope { radius: Utils.getSizeWithScreenRatio(71) style: ButtonStyle.numericPad + //: %1 longpress %2 + Accessible.name: longPressText.text ? qsTr("numpad_longpress_accessible_name").arg(pressText.text).arg(longPressText.text) : pressText.text + contentItem: Item { anchors.fill: parent Text { @@ -214,7 +217,10 @@ FocusScope { icon.height: Utils.getSizeWithScreenRatio(32) radius: Utils.getSizeWithScreenRatio(71) style: ButtonStyle.phoneGreen - + + //: Call + Accessible.name: qsTr("call_accessible_name") + onClicked: mainItem.launchCall() KeyNavigation.left: eraseButton @@ -237,6 +243,9 @@ FocusScope { Layout.Layout.preferredWidth: Utils.getSizeWithScreenRatio(38) Layout.Layout.preferredHeight: Utils.getSizeWithScreenRatio(38) + //: Erase + Accessible.name: qsTr("erase_accessible_name") + onClicked: mainItem.wipe() KeyNavigation.left: launchCallButton @@ -244,8 +253,13 @@ FocusScope { KeyNavigation.up: numPadGrid.getButtonAt(11) KeyNavigation.down: numPadGrid.getButtonAt(1) - background: Item { - visible: false + background: Rectangle { + width: eraseButton.width + height: eraseButton.height + color: "transparent" + + border.color: eraseButton.keyboardFocus ? eraseButton.keyboardFocusedBorderColor : "transparent" + border.width: eraseButton.keyboardFocus ? eraseButton.keyboardFocusedBorderWidth : eraseButton.borderWidth } } } diff --git a/Linphone/view/Control/Popup/NumericPadPopup.qml b/Linphone/view/Control/Popup/NumericPadPopup.qml index 56c763ee3..529448e99 100644 --- a/Linphone/view/Control/Popup/NumericPadPopup.qml +++ b/Linphone/view/Control/Popup/NumericPadPopup.qml @@ -69,6 +69,8 @@ Control.Popup { icon.height: Utils.getSizeWithScreenRatio(24) style: ButtonStyle.noBackground onClicked: mainItem.close() + //: Close numeric pad + Accessible.name: qsTr("close_numeric_pad_accessible_name") } } contentItem: NumericPad{ diff --git a/Linphone/view/Control/Tool/Helper/utils.js b/Linphone/view/Control/Tool/Helper/utils.js index 9b72b4c14..e7e99ed42 100644 --- a/Linphone/view/Control/Tool/Helper/utils.js +++ b/Linphone/view/Control/Tool/Helper/utils.js @@ -807,6 +807,17 @@ function infoDialog(window, message) { }, function (status) {}) } +// Ensure that the item is visible in the view +function ensureVisibleY(item, view){ + const itemPosition = item.mapToItem(view, 0, 0) + + if (itemPosition.y < 0){ + view.contentY = view.contentY + itemPosition.y + } else if (itemPosition.y + item.height > view.height){ + view.contentY = itemPosition.y + view.contentY + item.height - view.height + } +} + // Set position of list.currentItem into the scrollItem function updatePosition(scrollItem, list){ if(scrollItem.height == 0) return; diff --git a/Linphone/view/Page/Form/Settings/AbstractSettingsMenu.qml b/Linphone/view/Page/Form/Settings/AbstractSettingsMenu.qml index 3cbe9ee8e..d5b461158 100644 --- a/Linphone/view/Page/Form/Settings/AbstractSettingsMenu.qml +++ b/Linphone/view/Page/Form/Settings/AbstractSettingsMenu.qml @@ -48,6 +48,8 @@ AbstractMainPage { onClicked: { mainItem.goBackRequested() } + //: Back to previous menu + Accessible.name: qsTr("back_previous_menu_accessible_name") } Text { text: titleText @@ -69,6 +71,9 @@ AbstractMainPage { property int selectedIndex: mainItem.defaultIndex != -1 ? mainItem.defaultIndex : 0 activeFocusOnTab: true spacing: Utils.getSizeWithScreenRatio(5) + Accessible.role: Accessible.List + //: Settings page selection + Accessible.name: qsTr("settings_page_selection_accessible_name") delegate: SettingsMenuItem { titleText: modelData.title @@ -86,7 +91,9 @@ AbstractMainPage { let initialEntry = mainItem.families[familiesList.selectedIndex] rightPanelStackView.push(layoutUrl(initialEntry.layout), { titleText: initialEntry.title, model: initialEntry.model, container: rightPanelStackView}) familiesList.currentIndex = familiesList.selectedIndex - backButton.forceActiveFocus() } } + Control.StackView.onActivated: { + familiesList.forceActiveFocus(FocusNavigator.doesLastFocusWasKeyboard() ? Qt.TabFocusReason : Qt.MouseFocusReason) + } } diff --git a/Linphone/view/Page/Layout/Main/MainLayout.qml b/Linphone/view/Page/Layout/Main/MainLayout.qml index e108ff40c..bdc9508f4 100644 --- a/Linphone/view/Page/Layout/Main/MainLayout.qml +++ b/Linphone/view/Page/Layout/Main/MainLayout.qml @@ -14,6 +14,7 @@ Item { id: mainItem property var callObj property var contextualMenuOpenedComponent: undefined + property bool focusPageOnNextLoad: false // Focus the page on next load - usefull cause of loader signal addAccountRequest signal openNewCallRequest @@ -184,6 +185,18 @@ Item { mainStackView.currentItem.forceActiveFocus(); } } + + /** + * Focus the page when user select the page with keyboard. + * Do not add this behavior on the arrows + */ + onEnterPressed: { + focusPageOnNextLoad = true + } + onSpacePressed: { + focusPageOnNextLoad = true + } + Component.onCompleted: { if (SettingsCpp.shortcutCount > 0) { var shortcuts = SettingsCpp.shortcuts; @@ -639,6 +652,10 @@ Item { openContextualMenuComponent(page); } } + onLoaded: { + if(focusPageOnNextLoad) item.forceActiveFocus(Qt.TabFocusReason) + focusPageOnNextLoad = false + } } Loader { active: mainStackLayout.currentIndex === 1 @@ -654,6 +671,10 @@ Item { } } } + onLoaded: { + if(focusPageOnNextLoad) item.forceActiveFocus(Qt.TabFocusReason) + focusPageOnNextLoad = false + } } Loader { active: mainStackLayout.currentIndex === 2 @@ -672,6 +693,10 @@ Item { } } } + onLoaded: { + if(focusPageOnNextLoad) item.forceActiveFocus(Qt.TabFocusReason) + focusPageOnNextLoad = false + } } Loader { @@ -688,6 +713,10 @@ Item { } } } + onLoaded: { + if(focusPageOnNextLoad) item.forceActiveFocus(Qt.TabFocusReason) + focusPageOnNextLoad = false + } } } diff --git a/Linphone/view/Page/Layout/Settings/AbstractSettingsLayout.qml b/Linphone/view/Page/Layout/Settings/AbstractSettingsLayout.qml index bf995d01f..1e175a822 100644 --- a/Linphone/view/Page/Layout/Settings/AbstractSettingsLayout.qml +++ b/Linphone/view/Page/Layout/Settings/AbstractSettingsLayout.qml @@ -100,17 +100,13 @@ Rectangle { } } } - Control.ScrollView { + Flickable { id: scrollView anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom anchors.top: header.bottom anchors.topMargin: Utils.getSizeWithScreenRatio(16) - // Workaround while the CI is made with Qt6.5.3 - // When updated to 6.8, remove this Item and - // change the ScrollView with a Flickable - Item{anchors.fill: parent} contentHeight: contentListView.contentHeight Control.ScrollBar.vertical: ScrollBar { active: contentListView.contentHeight > scrollView.height @@ -130,21 +126,21 @@ Rectangle { model: mainItem.contentModel anchors.left: parent.left anchors.right: parent.right - anchors.leftMargin: Utils.getSizeWithScreenRatio(45) - anchors.rightMargin: Utils.getSizeWithScreenRatio(45) + anchors.leftMargin: Utils.getSizeWithScreenRatio(45) + anchors.rightMargin: Utils.getSizeWithScreenRatio(45) height: contentHeight - spacing: Utils.getSizeWithScreenRatio(10) + spacing: Utils.getSizeWithScreenRatio(10) delegate: ColumnLayout { - visible: modelData.visible != undefined ? modelData.visible: true - Component.onCompleted: if (!visible) height = 0 - spacing: Utils.getSizeWithScreenRatio(16) + visible: modelData.visible != undefined ? modelData.visible: true + Component.onCompleted: if (!visible) height = 0 + spacing: Utils.getSizeWithScreenRatio(16) width: contentListView.width Rectangle { visible: index !== 0 - Layout.topMargin: Utils.getSizeWithScreenRatio(modelData.hideTopSeparator ? 0 : 16) - Layout.bottomMargin: Utils.getSizeWithScreenRatio(16) + Layout.topMargin: Utils.getSizeWithScreenRatio(modelData.hideTopSeparator ? 0 : 16) + Layout.bottomMargin: Utils.getSizeWithScreenRatio(16) Layout.fillWidth: true - height: Utils.getSizeWithScreenRatio(1) + height: Utils.getSizeWithScreenRatio(1) color: modelData.hideTopSeparator ? 'transparent' : DefaultStyle.main2_500_main } GridLayout { @@ -152,12 +148,12 @@ Rectangle { columns: mainItem.useVerticalLayout ? 1 : 2 Layout.fillWidth: true // Layout.preferredWidth: parent.width - rowSpacing: modelData.title.length > 0 || modelData.subTitle.length > 0 ? Utils.getSizeWithScreenRatio(20) : 0 - columnSpacing: Utils.getSizeWithScreenRatio(47) + rowSpacing: modelData.title.length > 0 || modelData.subTitle.length > 0 ? Utils.getSizeWithScreenRatio(20) : 0 + columnSpacing: Utils.getSizeWithScreenRatio(47) ColumnLayout { - Layout.preferredWidth: Utils.getSizeWithScreenRatio(341) - Layout.maximumWidth: Utils.getSizeWithScreenRatio(341) - spacing: Utils.getSizeWithScreenRatio(3) + Layout.preferredWidth: Utils.getSizeWithScreenRatio(341) + Layout.maximumWidth: Utils.getSizeWithScreenRatio(341) + spacing: Utils.getSizeWithScreenRatio(3) Text { text: modelData.title visible: modelData.title.length > 0 @@ -179,10 +175,10 @@ Rectangle { } } RowLayout { - Layout.topMargin: modelData.hideTopMargin ? 0 : Utils.getSizeWithScreenRatio(mainItem.useVerticalLayout ? 10 : 21) - Layout.bottomMargin: Utils.getSizeWithScreenRatio(21) - Layout.leftMargin: mainItem.useVerticalLayout ? 0 : Utils.getSizeWithScreenRatio(17) - Layout.preferredWidth: Utils.getSizeWithScreenRatio(modelData.customWidth > 0 ? modelData.customWidth : 545) + Layout.topMargin: modelData.hideTopMargin ? 0 : Utils.getSizeWithScreenRatio(mainItem.useVerticalLayout ? 10 : 21) + Layout.bottomMargin: Utils.getSizeWithScreenRatio(21) + Layout.leftMargin: mainItem.useVerticalLayout ? 0 : Utils.getSizeWithScreenRatio(17) + Layout.preferredWidth: Utils.getSizeWithScreenRatio(modelData.customWidth > 0 ? modelData.customWidth : 545) Layout.alignment: Qt.AlignRight Loader { id: contentLoader @@ -190,12 +186,22 @@ Rectangle { sourceComponent: modelData.contentComponent } Item { - Layout.preferredWidth: Utils.getSizeWithScreenRatio(modelData.customRightMargin > 0 ? modelData.customRightMargin : 17) + Layout.preferredWidth: Utils.getSizeWithScreenRatio(modelData.customRightMargin > 0 ? modelData.customRightMargin : 17) } } } } } + + Connections { + target: FocusNavigator + + function onFocusChanged(item, keyboardFocus) { + if(Utils.isDescendant(item,scrollView) && keyboardFocus){ + Utils.ensureVisibleY(item, scrollView) + } + } + } } } diff --git a/Linphone/view/Page/Main/Call/CallPage.qml b/Linphone/view/Page/Main/Call/CallPage.qml index 372de87fa..d6ffb7bc3 100644 --- a/Linphone/view/Page/Main/Call/CallPage.qml +++ b/Linphone/view/Page/Main/Call/CallPage.qml @@ -24,6 +24,14 @@ AbstractMainPage { goToCallHistory() } + /** + * Focus on the first pertinent element in the page (LINQT-2202) + * @override + */ + function forceActiveFocus(reason = undefined){ + listStackView.currentItem?.newCallButton?.forceActiveFocus(reason) + } + //Group call properties property ConferenceInfoGui confInfoGui property AccountProxy accounts: AccountProxy { @@ -134,6 +142,8 @@ AbstractMainPage { FocusScope { objectName: "historyListItem" property alias listView: historyListView + property alias newCallButton: newCallButton + ColumnLayout { anchors.fill: parent spacing: 0 @@ -187,6 +197,7 @@ AbstractMainPage { } Button { id: newCallButton + focus: true style: ButtonStyle.noBackground icon.source: AppIcons.newCall Layout.preferredWidth: Utils.getSizeWithScreenRatio(34) diff --git a/Linphone/view/Page/Main/Chat/ChatPage.qml b/Linphone/view/Page/Main/Chat/ChatPage.qml index c50b4a7bb..e141a6adf 100644 --- a/Linphone/view/Page/Main/Chat/ChatPage.qml +++ b/Linphone/view/Page/Main/Chat/ChatPage.qml @@ -16,6 +16,14 @@ AbstractMainPage { emptyListText: qsTr("chat_empty_title") newItemIconSource: AppIcons.plusCircle + /** + * Focus on the first pertinent element in the page (LINQT-2202) + * @override + */ + function forceActiveFocus(reason = undefined){ + listStackView.currentItem?.newChatButton?.forceActiveFocus(reason) + } + property AccountProxy accounts: AccountProxy { id: accountProxy } @@ -116,6 +124,7 @@ AbstractMainPage { FocusScope { objectName: "chatListItem" property alias listView: chatListView + property alias newChatButton: newChatButton ColumnLayout { anchors.fill: parent spacing: 0 @@ -158,6 +167,7 @@ AbstractMainPage { } Button { id: newChatButton + focus: true style: ButtonStyle.noBackground icon.source: AppIcons.plusCircle Layout.preferredWidth: Utils.getSizeWithScreenRatio(28) diff --git a/Linphone/view/Page/Main/Contact/ContactPage.qml b/Linphone/view/Page/Main/Contact/ContactPage.qml index 2b58cbb20..135270a1d 100644 --- a/Linphone/view/Page/Main/Contact/ContactPage.qml +++ b/Linphone/view/Page/Main/Contact/ContactPage.qml @@ -17,6 +17,14 @@ AbstractMainPage { emptyListText: qsTr("contacts_list_empty") newItemIconSource: AppIcons.plusCircle + /** + * Focus on the first pertinent element in the page (LINQT-2202) + * @override + */ + function forceActiveFocus(reason = undefined){ + createContactButton.forceActiveFocus(reason) + } + // disable left panel contact list interaction while a contact is being edited property bool leftPanelEnabled: !rightPanelStackView.currentItem || rightPanelStackView.currentItem.objectName @@ -243,6 +251,7 @@ AbstractMainPage { visible: !rightPanelStackView.currentItem || rightPanelStackView.currentItem.objectName !== "contactEdition" style: ButtonStyle.noBackground + focus: true icon.source: AppIcons.plusCircle Layout.preferredWidth: Utils.getSizeWithScreenRatio(28) Layout.preferredHeight: Utils.getSizeWithScreenRatio(28) diff --git a/Linphone/view/Page/Main/Meeting/MeetingPage.qml b/Linphone/view/Page/Main/Meeting/MeetingPage.qml index 326fbf76a..a57b9fe9f 100644 --- a/Linphone/view/Page/Main/Meeting/MeetingPage.qml +++ b/Linphone/view/Page/Main/Meeting/MeetingPage.qml @@ -26,6 +26,15 @@ AbstractMainPage { rightPanelStackTopMargin: Utils.getSizeWithScreenRatio(45) rightPanelStackBottomMargin: Utils.getSizeWithScreenRatio(30) + /** + * Focus on the first pertinent element in the page (LINQT-2202) + * @override + */ + function forceActiveFocus(reason = undefined){ + leftPanelStackView.currentItem?.newConfButton?.forceActiveFocus(reason) + } + + function createPreFilledMeeting(subject, addresses) { mainItem.selectedConference = Qt.createQmlObject('import Linphone ConferenceInfoGui{ @@ -137,6 +146,7 @@ AbstractMainPage { id: listLayout FocusScope{ property string objectName: "listLayout" + property alias newConfButton: newConfButton Control.StackView.onDeactivated: { mainItem.selectedConference = null } @@ -166,6 +176,7 @@ AbstractMainPage { } Button { id: newConfButton + focus: true style: ButtonStyle.noBackground icon.source: AppIcons.plusCircle Layout.preferredWidth: Utils.getSizeWithScreenRatio(28)