ganfra
1 year ago
committed by
GitHub
217 changed files with 2370 additions and 1049 deletions
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
Fix long click on simple formatted messages |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
Fix top padding in room list when app is opened in offline mode. |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
Add a sub-screen "Notifications" in the existing application Settings |
@ -1,10 +1,4 @@
@@ -1,10 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
||||
<string name="screen_analytics_prompt_data_usage">"Wir werden keine personenbezogenen Daten aufzeichnen oder auswerten"</string> |
||||
<string name="screen_analytics_prompt_help_us_improve">"Teile anonyme Nutzungsdaten, um uns bei der Identifizierung von Problemen zu helfen."</string> |
||||
<string name="screen_analytics_prompt_read_terms">"Du kannst alle unsere Nutzerbedingungen %1$s lesen."</string> |
||||
<string name="screen_analytics_prompt_read_terms_content_link">"hier"</string> |
||||
<string name="screen_analytics_prompt_settings">"Du kannst dies jederzeit deaktivieren"</string> |
||||
<string name="screen_analytics_prompt_third_party_sharing">"Wir geben deine Daten nicht an Dritte weiter"</string> |
||||
<string name="screen_analytics_prompt_title">"Hilf uns, %1$s zu verbessern"</string> |
||||
</resources> |
||||
|
@ -1,10 +1,10 @@
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
||||
<string name="screen_analytics_prompt_data_usage">"Nous n\'enregistrerons ni ne traiterons aucune donnée personnelle"</string> |
||||
<string name="screen_analytics_prompt_data_usage">"Nous n\'enregistrerons ni ne profilerons aucune donnée personnelle"</string> |
||||
<string name="screen_analytics_prompt_help_us_improve">"Partagez des données d\'utilisation anonymes pour nous aider à identifier les problèmes."</string> |
||||
<string name="screen_analytics_prompt_read_terms">"Consultez nos conditions d\'utilisation %1$s."</string> |
||||
<string name="screen_analytics_prompt_read_terms">"Vous pouvez lire toutes nos conditions %1$s."</string> |
||||
<string name="screen_analytics_prompt_read_terms_content_link">"ici"</string> |
||||
<string name="screen_analytics_prompt_settings">"Vous pouvez désactiver cette fonction à tout moment"</string> |
||||
<string name="screen_analytics_prompt_settings">"Vous pouvez le désactiver à tout moment"</string> |
||||
<string name="screen_analytics_prompt_third_party_sharing">"Nous ne partagerons pas vos données avec des tiers"</string> |
||||
<string name="screen_analytics_prompt_title">"Aidez-nous à améliorer %1$s"</string> |
||||
<string name="screen_analytics_prompt_title">"Aidez à améliorer %1$s"</string> |
||||
</resources> |
||||
|
@ -1,5 +1,10 @@
@@ -1,5 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
||||
<string name="screen_analytics_prompt_data_usage">"我們不會紀錄或剖繪您的個人資料"</string> |
||||
<string name="screen_analytics_prompt_help_us_improve">"分享匿名的使用數據以協助我們釐清問題"</string> |
||||
<string name="screen_analytics_prompt_read_terms">"您可以到 %1$s 閱讀我們的條款。"</string> |
||||
<string name="screen_analytics_prompt_read_terms_content_link">"這裡"</string> |
||||
<string name="screen_analytics_prompt_settings">"您可以在任何時候關閉它"</string> |
||||
<string name="screen_analytics_prompt_third_party_sharing">"我們不會和第三方分享您的資料"</string> |
||||
<string name="screen_analytics_prompt_title">"讓 %1$s 變得更好"</string> |
||||
</resources> |
||||
|
@ -1,15 +1,4 @@
@@ -1,15 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
||||
<string name="screen_create_room_action_create_room">"Neuer Raum"</string> |
||||
<string name="screen_create_room_action_invite_people">"Freunde zu Element einladen"</string> |
||||
<string name="screen_create_room_add_people_title">"Personen hinzufügen"</string> |
||||
<string name="screen_create_room_error_creating_room">"Beim Erstellen des Raums ist ein Fehler aufgetreten"</string> |
||||
<string name="screen_create_room_private_option_description">"Die Nachrichten in diesem Raum sind verschlüsselt. Die Verschlüsselung kann nicht nachträglich deaktiviert werden."</string> |
||||
<string name="screen_create_room_private_option_title">"Privater Raum (nur auf Einladung)"</string> |
||||
<string name="screen_create_room_public_option_description">"Nachrichten sind nicht verschlüsselt und jeder kann sie lesen. Du kannst die Verschlüsselung zu einem späteren Zeitpunkt aktivieren."</string> |
||||
<string name="screen_create_room_public_option_title">"Öffentlicher Raum (jeder)"</string> |
||||
<string name="screen_create_room_room_name_label">"Raumname"</string> |
||||
<string name="screen_create_room_topic_label">"Thema (optional)"</string> |
||||
<string name="screen_start_chat_error_starting_chat">"Beim Versuch, einen Chat zu starten, ist ein Fehler aufgetreten"</string> |
||||
<string name="screen_create_room_title">"Raum erstellen"</string> |
||||
</resources> |
||||
|
@ -1,15 +1,15 @@
@@ -1,15 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
||||
<string name="screen_create_room_action_create_room">"Nouveau salon"</string> |
||||
<string name="screen_create_room_action_create_room">"Nouvelle salle"</string> |
||||
<string name="screen_create_room_action_invite_people">"Inviter des amis sur Element"</string> |
||||
<string name="screen_create_room_add_people_title">"Inviter des personnes"</string> |
||||
<string name="screen_create_room_error_creating_room">"Une erreur s\'est produite lors de la création du salon"</string> |
||||
<string name="screen_create_room_private_option_description">"Les messages dans ce salon sont chiffrés. Une fois activé, le chiffrement ne peut pas être désactivé."</string> |
||||
<string name="screen_create_room_private_option_title">"Salon privé (sur invitation uniquement)"</string> |
||||
<string name="screen_create_room_public_option_description">"Les messages ne sont pas chiffrés et n\'importe qui peut les lire. Vous pouvez activer le chiffrement ultérieurement."</string> |
||||
<string name="screen_create_room_public_option_title">"Salon public (n’importe qui)"</string> |
||||
<string name="screen_create_room_room_name_label">"Nom du salon"</string> |
||||
<string name="screen_create_room_topic_label">"Sujet (optionnel)"</string> |
||||
<string name="screen_create_room_error_creating_room">"Une erreur s\'est produite lors de la création de la salle"</string> |
||||
<string name="screen_create_room_private_option_description">"Les messages dans cette pièce sont cryptés. Le cryptage ne peut pas être désactivé par la suite."</string> |
||||
<string name="screen_create_room_private_option_title">"Salle privée (sur invitation seulement)"</string> |
||||
<string name="screen_create_room_public_option_description">"Les messages ne sont pas cryptés et n\'importe qui peut les lire. Vous pouvez activer le chiffrement ultérieurement."</string> |
||||
<string name="screen_create_room_public_option_title">"Salle publique (tout le monde)"</string> |
||||
<string name="screen_create_room_room_name_label">"Nom de la salle"</string> |
||||
<string name="screen_create_room_topic_label">"Sujet (facultatif)"</string> |
||||
<string name="screen_start_chat_error_starting_chat">"Une erreur s\'est produite lors de la tentative de démarrage d\'une discussion"</string> |
||||
<string name="screen_create_room_title">"Créer un salon"</string> |
||||
<string name="screen_create_room_title">"Créer une salle"</string> |
||||
</resources> |
||||
|
@ -1,11 +1,5 @@
@@ -1,11 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
||||
<string name="screen_migration_message">"Dies ist ein einmaliger Vorgang, danke fürs Warten."</string> |
||||
<string name="screen_migration_title">"Dein Konto einrichten"</string> |
||||
<string name="screen_welcome_bullet_1">"Anrufe, Umfragen, Suche und mehr werden später in diesem Jahr hinzugefügt."</string> |
||||
<string name="screen_welcome_bullet_2">"Der Nachrichtenverlauf für verschlüsselte Räume wird in diesem Update nicht verfügbar sein."</string> |
||||
<string name="screen_welcome_bullet_3">"Wir würden uns freuen, wenn du uns über die Einstellungsseite deine Meinung mitteilst."</string> |
||||
<string name="screen_welcome_button">"Los geht\'s!"</string> |
||||
<string name="screen_welcome_subtitle">"Folgendes musst du wissen:"</string> |
||||
<string name="screen_welcome_title">"Willkommen bei %1$s!"</string> |
||||
<string name="screen_notification_optin_subtitle">"Du kannst deine Einstellungen später ändern."</string> |
||||
<string name="screen_notification_optin_title">"Erlaube Benachrichtigungen und verpasse keine Nachricht"</string> |
||||
</resources> |
||||
|
@ -1,9 +0,0 @@
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
||||
<string name="screen_invites_decline_chat_message">"Möchtest du den Beitritt zu %1$s wirklich ablehnen?"</string> |
||||
<string name="screen_invites_decline_chat_title">"Einladung ablehnen"</string> |
||||
<string name="screen_invites_decline_direct_chat_message">"Möchtest du den privaten Chat mit %1$s wirklich ablehnen?"</string> |
||||
<string name="screen_invites_decline_direct_chat_title">"Chat ablehnen"</string> |
||||
<string name="screen_invites_empty_list">"Keine Einladungen"</string> |
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) hat dich eingeladen"</string> |
||||
</resources> |
@ -1,47 +1,8 @@
@@ -1,47 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
||||
<string name="screen_account_provider_change">"Kontoanbieter wechseln"</string> |
||||
<string name="screen_account_provider_form_hint">"Adresse des Homeservers"</string> |
||||
<string name="screen_account_provider_form_notice">"Gib einen Suchbegriff oder eine Domainadresse ein."</string> |
||||
<string name="screen_account_provider_form_subtitle">"Suche nach einem Unternehmen, einer Community oder einem privaten Server."</string> |
||||
<string name="screen_account_provider_form_title">"Finde einen Kontoanbieter"</string> |
||||
<string name="screen_account_provider_signin_subtitle">"Hier werden deine Konversationen stattfinden — genauso wie du einen E-Mail-Anbieter verwenden würdest, um deine E-Mails aufzubewahren."</string> |
||||
<string name="screen_account_provider_signin_title">"Du bist dabei dich bei %s anzumelden"</string> |
||||
<string name="screen_account_provider_signup_subtitle">"Hier werden deine Konversationen stattfinden — genauso wie du einen E-Mail-Anbieter verwenden würdest, um deine E-Mails aufzubewahren."</string> |
||||
<string name="screen_account_provider_signup_title">"Du bist dabei ein Konto auf %s zu erstellen"</string> |
||||
<string name="screen_change_account_provider_matrix_org_subtitle">"Matrix.org ist ein großer, kostenloser Server im öffentlichen Matrix-Netzwerk für sichere, dezentrale Kommunikation, der von der Matrix.org Foundation betrieben wird."</string> |
||||
<string name="screen_change_account_provider_other">"Andere"</string> |
||||
<string name="screen_change_account_provider_subtitle">"Verwende einen anderen Kontoanbieter, z. B. deinen eigenen privaten Server oder ein Arbeitskonto."</string> |
||||
<string name="screen_change_account_provider_title">"Kontoanbieter ändern"</string> |
||||
<string name="screen_change_server_error_invalid_homeserver">"Wir konnten diesen Homeserver nicht erreichen. Bitte überprüfe, dass du die Homeserver-URL korrekt eingegeben hast. Wenn die URL korrekt ist, wende dich an deinen Homeserver-Administrator für weitere Hilfe."</string> |
||||
<string name="screen_change_server_error_no_sliding_sync_message">"Dieser Server unterstützt derzeit keine Sliding Sync."</string> |
||||
<string name="screen_change_server_form_header">"Homeserver-URL"</string> |
||||
<string name="screen_change_server_form_notice">"Du kannst dich nur mit einem existierenden Server verbinden, der Sliding Sync unterstützt. Dein Homeserver-Administrator muss es konfigurieren. %1$s"</string> |
||||
<string name="screen_change_server_subtitle">"Wie lautet die Adresse deines Servers?"</string> |
||||
<string name="screen_login_error_deactivated_account">"Dieses Konto wurde deaktiviert."</string> |
||||
<string name="screen_login_error_invalid_credentials">"Falscher Benutzername und/oder Passwort"</string> |
||||
<string name="screen_login_error_invalid_user_id">"Dies ist kein gültiger Benutzeridentifikator. Erwartetes Format: \'@user:homeserver.org\'"</string> |
||||
<string name="screen_login_error_unsupported_authentication">"Der ausgewählte Homeserver unterstützt kein Passwort- oder OIDC-Login. Bitte kontaktiere deinen Admin oder wähle einen anderen Homeserver."</string> |
||||
<string name="screen_login_form_header">"Gib deine Daten ein"</string> |
||||
<string name="screen_login_title">"Willkommen zurück!"</string> |
||||
<string name="screen_login_title_with_homeserver">"Bei %1$s anmelden"</string> |
||||
<string name="screen_server_confirmation_change_server">"Kontoanbieter wechseln"</string> |
||||
<string name="screen_server_confirmation_message_login_element_dot_io">"Ein privater Server für Element-Mitarbeiter."</string> |
||||
<string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix ist ein offenes Netzwerk für sichere, dezentrale Kommunikation"</string> |
||||
<string name="screen_server_confirmation_message_register">"Hier werden deine Konversationen stattfinden — genau so wie du einen E-Mail-Anbieter verwenden würdest, um deine E-Mails aufzubewahren."</string> |
||||
<string name="screen_server_confirmation_title_login">"Du bist dabei dich bei %1$s anzumelden"</string> |
||||
<string name="screen_server_confirmation_title_register">"Du bist dabei ein Konto auf %1$s zu erstellen"</string> |
||||
<string name="screen_waitlist_message">"Im Moment besteht eine hohe Nachfrage nach %1$s auf %2$s. Besuche die App in ein paar Tagen wieder und versuche es erneut. |
||||
|
||||
Vielen Dank für deine Geduld!"</string> |
||||
<string name="screen_waitlist_message_success">"Willkommen bei %1$s!"</string> |
||||
<string name="screen_waitlist_title">"Du hast es fast geschafft!"</string> |
||||
<string name="screen_waitlist_title_success">"Du bist dabei."</string> |
||||
<string name="screen_account_provider_continue">"Weiter"</string> |
||||
<string name="screen_change_server_submit">"Weiter"</string> |
||||
<string name="screen_change_server_title">"Wählen deinen Server"</string> |
||||
<string name="screen_login_password_hint">"Passwort"</string> |
||||
<string name="screen_login_submit">"Weiter"</string> |
||||
<string name="screen_login_subtitle">"Matrix ist ein offenes Netzwerk für sichere, dezentrale Kommunikation"</string> |
||||
<string name="screen_login_username_hint">"Benutzername"</string> |
||||
</resources> |
||||
|
@ -1,8 +0,0 @@
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
||||
<string name="screen_signout_confirmation_dialog_content">"Möchtest du Dich wirklich abmelden?"</string> |
||||
<string name="screen_signout_confirmation_dialog_title">"Abmelden"</string> |
||||
<string name="screen_signout_in_progress_dialog_content">"Abmeldung läuft…"</string> |
||||
<string name="screen_signout_confirmation_dialog_submit">"Abmelden"</string> |
||||
<string name="screen_signout_preference_item">"Abmelden"</string> |
||||
</resources> |
@ -1,41 +1,5 @@
@@ -1,41 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
||||
<plurals name="room_timeline_state_changes"> |
||||
<item quantity="one">"%1$d Raumänderung"</item> |
||||
<item quantity="other">"%1$d Raumänderungen"</item> |
||||
</plurals> |
||||
<string name="screen_room_attachment_source_camera">"Kamera"</string> |
||||
<string name="screen_room_attachment_source_camera_photo">"Foto aufnehmen"</string> |
||||
<string name="screen_room_attachment_source_camera_video">"Video aufnehmen"</string> |
||||
<string name="screen_room_attachment_source_files">"Anhang"</string> |
||||
<string name="screen_room_attachment_source_gallery">"Foto- & Video-Bibliothek"</string> |
||||
<string name="screen_room_attachment_source_location">"Standort"</string> |
||||
<string name="screen_room_attachment_source_poll">"Umfrage"</string> |
||||
<string name="screen_room_encrypted_history_banner">"Der Nachrichtenverlauf ist in diesem Raum derzeit nicht verfügbar"</string> |
||||
<string name="screen_room_error_failed_retrieving_user_details">"Benutzerdetails konnten nicht abgerufen werden"</string> |
||||
<string name="screen_room_invite_again_alert_message">"Möchtest du sie wieder einladen?"</string> |
||||
<string name="screen_room_invite_again_alert_title">"Du bist allein in diesem Chat"</string> |
||||
<string name="screen_room_message_copied">"Nachricht kopiert"</string> |
||||
<string name="screen_room_no_permission_to_post">"Du bist keine Berechtigung, um in diesem Raum zu posten"</string> |
||||
<string name="screen_room_notification_settings_allow_custom">"Benutzerdefinierte Einstellung zulassen"</string> |
||||
<string name="screen_room_notification_settings_allow_custom_footnote">"Das Aktivieren dieser Option wird die Standardeinstellungen überschreiben."</string> |
||||
<string name="screen_room_notification_settings_custom_settings_title">"Benachrichtige mich in diesem Chat für"</string> |
||||
<string name="screen_room_notification_settings_default_setting_footnote">"Du kannst es in deinem %1$s ändern."</string> |
||||
<string name="screen_room_notification_settings_default_setting_footnote_content_link">"Globale Einstellungen"</string> |
||||
<string name="screen_room_notification_settings_default_setting_title">"Standardeinstellung"</string> |
||||
<string name="screen_room_notification_settings_edit_remove_setting">"Benutzerdefinierte Einstellung entfernen"</string> |
||||
<string name="screen_room_notification_settings_error_loading_settings">"Beim Laden der Benachrichtigungseinstellungen ist ein Fehler aufgetreten."</string> |
||||
<string name="screen_room_notification_settings_error_restoring_default">"Wiederherstellung des Standardmodus fehlgeschlagen. Bitte versuche es erneut."</string> |
||||
<string name="screen_room_notification_settings_error_setting_mode">"Fehler beim Einstellen des Modus. Bitte versuche es erneut."</string> |
||||
<string name="screen_room_notification_settings_mode_all_messages">"Alle Nachrichten"</string> |
||||
<string name="screen_room_notification_settings_mode_mentions_and_keywords">"Nur Erwähnungen und Schlüsselwörter"</string> |
||||
<string name="screen_room_notification_settings_room_custom_settings_title">"In diesem Raum, benachrichtige mich für"</string> |
||||
<string name="screen_room_reactions_show_less">"Weniger anzeigen"</string> |
||||
<string name="screen_room_reactions_show_more">"Mehr anzeigen"</string> |
||||
<string name="screen_room_retry_send_menu_send_again_action">"Erneut senden"</string> |
||||
<string name="screen_room_retry_send_menu_title">"Ihre Nachricht konnte nicht gesendet werden"</string> |
||||
<string name="screen_room_timeline_add_reaction">"Emoji hinzufügen"</string> |
||||
<string name="screen_room_timeline_less_reactions">"Weniger anzeigen"</string> |
||||
<string name="screen_room_error_failed_processing_media">"Fehler bei der Verarbeitung von Medien zum Hochladen, bitte versuche es erneut."</string> |
||||
<string name="screen_room_attachment_text_formatting">"Textformatierung"</string> |
||||
<string name="screen_room_retry_send_menu_remove_action">"Entfernen"</string> |
||||
</resources> |
||||
|
@ -1,10 +0,0 @@
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
||||
<string name="screen_onboarding_sign_in_manually">"Manuell anmelden"</string> |
||||
<string name="screen_onboarding_sign_in_with_qr_code">"Mit QR-Code anmelden"</string> |
||||
<string name="screen_onboarding_sign_up">"Konto erstellen"</string> |
||||
<string name="screen_onboarding_subtitle">"Sicher kommunizieren und zusammenarbeiten"</string> |
||||
<string name="screen_onboarding_welcome_message">"Willkommen beim schnellsten Element aller Zeiten. Optimiert für Geschwindigkeit und Einfachheit."</string> |
||||
<string name="screen_onboarding_welcome_subtitle">"Willkommen zur %1$s. Verbessert, für Geschwindigkeit und Einfachheit."</string> |
||||
<string name="screen_onboarding_welcome_title">"Sei in deinem Element"</string> |
||||
</resources> |
@ -1,10 +1,10 @@
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
||||
<string name="screen_onboarding_sign_in_manually">"Se connecter manuellement"</string> |
||||
<string name="screen_onboarding_sign_in_with_qr_code">"Se connecter avec un code QR"</string> |
||||
<string name="screen_onboarding_sign_in_manually">"Connectez-vous manuellement"</string> |
||||
<string name="screen_onboarding_sign_in_with_qr_code">"Connectez-vous avec le code QR"</string> |
||||
<string name="screen_onboarding_sign_up">"Créer un compte"</string> |
||||
<string name="screen_onboarding_subtitle">"Communiquer et collaborer en toute sécurité"</string> |
||||
<string name="screen_onboarding_welcome_message">"Bienvenue dans l’Element le plus rapide de tous les temps. Surpuissant pour plus de vitesse et de simplicité."</string> |
||||
<string name="screen_onboarding_welcome_subtitle">"Bienvenue dans %1$s. Affiné pour plus de rapidité et de simplicité."</string> |
||||
<string name="screen_onboarding_subtitle">"Communiquez et collaborez en toute sécurité"</string> |
||||
<string name="screen_onboarding_welcome_message">"Bienvenue dans l\'Element le plus rapide de tous les temps. Boosté pour plus de rapidité et de simplicité."</string> |
||||
<string name="screen_onboarding_welcome_subtitle">"Bienvenue sur %1$s. Boosté, pour rapidité et simplicité."</string> |
||||
<string name="screen_onboarding_welcome_title">"Soyez dans votre Element"</string> |
||||
</resources> |
||||
|
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
||||
<string name="screen_create_poll_add_option_btn">"Option hinzufügen"</string> |
||||
<string name="screen_create_poll_anonymous_desc">"Ergebnisse erst nach Ende der Umfrage anzeigen"</string> |
||||
<string name="screen_create_poll_anonymous_headline">"Anonyme Umfrage"</string> |
||||
<string name="screen_create_poll_answer_hint">"Option %1$d"</string> |
||||
<string name="screen_create_poll_discard_confirmation">"Bist du sicher, dass du diese Umfrage verwerfen willst?"</string> |
||||
<string name="screen_create_poll_discard_confirmation_title">"Umfrage verwerfen"</string> |
||||
<string name="screen_create_poll_question_desc">"Frage oder Thema"</string> |
||||
<string name="screen_create_poll_title">"Umfrage erstellen"</string> |
||||
</resources> |
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> |
||||
<string name="screen_create_poll_add_option_btn">"Pridať možnosť"</string> |
||||
<string name="screen_create_poll_anonymous_desc">"Zobraziť výsledky až po skončení ankety"</string> |
||||
<string name="screen_create_poll_anonymous_headline">"Anonymná anketa"</string> |
||||
<string name="screen_create_poll_answer_hint">"Možnosť %1$d"</string> |
||||
<string name="screen_create_poll_discard_confirmation">"Ste si istí, že chcete túto anketu zahodiť?"</string> |
||||
<string name="screen_create_poll_discard_confirmation_title">"Odstrániť anketu"</string> |
||||
<string name="screen_create_poll_question_desc">"Otázka alebo téma"</string> |
||||
<string name="screen_create_poll_question_hint">"O čom je anketa?"</string> |
||||
<string name="screen_create_poll_title">"Vytvoriť anketu"</string> |
||||
</resources> |
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.preferences.impl.notifications |
||||
|
||||
sealed interface NotificationSettingsEvents { |
||||
|
||||
data object RefreshSystemNotificationsEnabled : NotificationSettingsEvents |
||||
data class SetNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents |
||||
data class SetAtRoomNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents |
||||
data class SetCallNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents |
||||
data object FixConfigurationMismatch : NotificationSettingsEvents |
||||
data object ClearConfigurationMismatchError : NotificationSettingsEvents |
||||
} |
@ -0,0 +1,57 @@
@@ -0,0 +1,57 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.preferences.impl.notifications |
||||
|
||||
import androidx.compose.runtime.Composable |
||||
import androidx.compose.ui.Modifier |
||||
import com.bumble.appyx.core.modality.BuildContext |
||||
import com.bumble.appyx.core.node.Node |
||||
import com.bumble.appyx.core.plugin.Plugin |
||||
import com.bumble.appyx.core.plugin.plugins |
||||
import dagger.assisted.Assisted |
||||
import dagger.assisted.AssistedInject |
||||
import io.element.android.anvilannotations.ContributesNode |
||||
import io.element.android.libraries.di.SessionScope |
||||
|
||||
@ContributesNode(SessionScope::class) |
||||
class NotificationSettingsNode @AssistedInject constructor( |
||||
@Assisted buildContext: BuildContext, |
||||
@Assisted plugins: List<Plugin>, |
||||
private val presenter: NotificationSettingsPresenter, |
||||
) : Node(buildContext, plugins = plugins) { |
||||
|
||||
interface Callback : Plugin { |
||||
fun editDefaultNotificationMode(isOneToOne: Boolean) |
||||
} |
||||
|
||||
private val callbacks = plugins<Callback>() |
||||
|
||||
private fun openEditDefault(isOneToOne: Boolean) { |
||||
callbacks.forEach { it.editDefaultNotificationMode(isOneToOne) } |
||||
} |
||||
|
||||
@Composable |
||||
override fun View(modifier: Modifier) { |
||||
val state = presenter.present() |
||||
NotificationSettingsView( |
||||
state = state, |
||||
onOpenEditDefault = { openEditDefault(isOneToOne = it) }, |
||||
onBackPressed = ::navigateUp, |
||||
modifier = modifier, |
||||
) |
||||
} |
||||
} |
@ -0,0 +1,168 @@
@@ -0,0 +1,168 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.preferences.impl.notifications |
||||
|
||||
import androidx.compose.runtime.Composable |
||||
import androidx.compose.runtime.LaunchedEffect |
||||
import androidx.compose.runtime.MutableState |
||||
import androidx.compose.runtime.collectAsState |
||||
import androidx.compose.runtime.mutableStateOf |
||||
import androidx.compose.runtime.remember |
||||
import androidx.compose.runtime.rememberCoroutineScope |
||||
import io.element.android.libraries.architecture.Presenter |
||||
import io.element.android.libraries.matrix.api.MatrixClient |
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService |
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode |
||||
import io.element.android.libraries.pushstore.api.UserPushStore |
||||
import io.element.android.libraries.pushstore.api.UserPushStoreFactory |
||||
import kotlinx.coroutines.CoroutineScope |
||||
import kotlinx.coroutines.FlowPreview |
||||
import kotlinx.coroutines.flow.debounce |
||||
import kotlinx.coroutines.flow.launchIn |
||||
import kotlinx.coroutines.flow.onEach |
||||
import kotlinx.coroutines.launch |
||||
import javax.inject.Inject |
||||
import kotlin.time.Duration.Companion.seconds |
||||
|
||||
class NotificationSettingsPresenter @Inject constructor( |
||||
private val notificationSettingsService: NotificationSettingsService, |
||||
private val userPushStoreFactory: UserPushStoreFactory, |
||||
private val matrixClient: MatrixClient, |
||||
private val systemNotificationsEnabledProvider: SystemNotificationsEnabledProvider |
||||
) : Presenter<NotificationSettingsState> { |
||||
@Composable |
||||
override fun present(): NotificationSettingsState { |
||||
val userPushStore = remember { userPushStoreFactory.create(matrixClient.sessionId) } |
||||
val systemNotificationsEnabled: MutableState<Boolean> = remember { |
||||
mutableStateOf(systemNotificationsEnabledProvider.notificationsEnabled()) |
||||
} |
||||
|
||||
val localCoroutineScope = rememberCoroutineScope() |
||||
val appNotificationsEnabled = userPushStore |
||||
.getNotificationEnabledForDevice() |
||||
.collectAsState(initial = false) |
||||
|
||||
val matrixSettings: MutableState<NotificationSettingsState.MatrixSettings> = remember { |
||||
mutableStateOf(NotificationSettingsState.MatrixSettings.Uninitialized) |
||||
} |
||||
|
||||
LaunchedEffect(Unit) { |
||||
fetchSettings(matrixSettings) |
||||
observeNotificationSettings(matrixSettings) |
||||
} |
||||
|
||||
fun handleEvents(event: NotificationSettingsEvents) { |
||||
when (event) { |
||||
is NotificationSettingsEvents.SetAtRoomNotificationsEnabled -> localCoroutineScope.setAtRoomNotificationsEnabled(event.enabled) |
||||
is NotificationSettingsEvents.SetCallNotificationsEnabled -> localCoroutineScope.setCallNotificationsEnabled(event.enabled) |
||||
is NotificationSettingsEvents.SetNotificationsEnabled -> localCoroutineScope.setNotificationsEnabled(userPushStore, event.enabled) |
||||
NotificationSettingsEvents.ClearConfigurationMismatchError -> { |
||||
matrixSettings.value = NotificationSettingsState.MatrixSettings.Invalid(fixFailed = false) |
||||
} |
||||
NotificationSettingsEvents.FixConfigurationMismatch -> localCoroutineScope.fixConfigurationMismatch(matrixSettings) |
||||
NotificationSettingsEvents.RefreshSystemNotificationsEnabled -> { |
||||
systemNotificationsEnabled.value = systemNotificationsEnabledProvider.notificationsEnabled() |
||||
} |
||||
} |
||||
} |
||||
|
||||
return NotificationSettingsState( |
||||
matrixSettings = matrixSettings.value, |
||||
appSettings = NotificationSettingsState.AppSettings( |
||||
systemNotificationsEnabled = systemNotificationsEnabled.value, |
||||
appNotificationsEnabled = appNotificationsEnabled.value |
||||
), |
||||
eventSink = ::handleEvents |
||||
) |
||||
} |
||||
|
||||
@OptIn(FlowPreview::class) |
||||
private fun CoroutineScope.observeNotificationSettings(target: MutableState<NotificationSettingsState.MatrixSettings>) { |
||||
notificationSettingsService.notificationSettingsChangeFlow |
||||
.debounce(0.5.seconds) |
||||
.onEach { |
||||
fetchSettings(target) |
||||
} |
||||
.launchIn(this) |
||||
} |
||||
|
||||
private fun CoroutineScope.fetchSettings(target: MutableState<NotificationSettingsState.MatrixSettings>) = launch { |
||||
val groupDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = false, isOneToOne = false).getOrThrow() |
||||
val encryptedGroupDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = false).getOrThrow() |
||||
|
||||
val oneToOneDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = false, isOneToOne = true).getOrThrow() |
||||
val encryptedOneToOneDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = true).getOrThrow() |
||||
|
||||
if(groupDefaultMode != encryptedGroupDefaultMode || oneToOneDefaultMode != encryptedOneToOneDefaultMode) { |
||||
target.value = NotificationSettingsState.MatrixSettings.Invalid(fixFailed = false) |
||||
return@launch |
||||
} |
||||
|
||||
val callNotificationsEnabled = notificationSettingsService.isCallEnabled().getOrThrow() |
||||
val atRoomNotificationsEnabled = notificationSettingsService.isRoomMentionEnabled().getOrThrow() |
||||
|
||||
target.value = NotificationSettingsState.MatrixSettings.Valid( |
||||
atRoomNotificationsEnabled = atRoomNotificationsEnabled, |
||||
callNotificationsEnabled = callNotificationsEnabled, |
||||
defaultGroupNotificationMode = encryptedGroupDefaultMode, |
||||
defaultOneToOneNotificationMode = encryptedOneToOneDefaultMode, |
||||
) |
||||
} |
||||
|
||||
private fun CoroutineScope.fixConfigurationMismatch(target: MutableState<NotificationSettingsState.MatrixSettings>) = launch { |
||||
runCatching { |
||||
val groupDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = false, isOneToOne = false).getOrThrow() |
||||
val encryptedGroupDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = false).getOrThrow() |
||||
|
||||
if (groupDefaultMode != encryptedGroupDefaultMode) { |
||||
notificationSettingsService.setDefaultRoomNotificationMode( |
||||
isEncrypted = encryptedGroupDefaultMode != RoomNotificationMode.ALL_MESSAGES, |
||||
mode = RoomNotificationMode.ALL_MESSAGES, |
||||
isOneToOne = false, |
||||
) |
||||
} |
||||
|
||||
val oneToOneDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = false, isOneToOne = true).getOrThrow() |
||||
val encryptedOneToOneDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = true).getOrThrow() |
||||
|
||||
if (oneToOneDefaultMode != encryptedOneToOneDefaultMode) { |
||||
notificationSettingsService.setDefaultRoomNotificationMode( |
||||
isEncrypted = encryptedOneToOneDefaultMode != RoomNotificationMode.ALL_MESSAGES, |
||||
mode = RoomNotificationMode.ALL_MESSAGES, |
||||
isOneToOne = true, |
||||
) |
||||
} |
||||
}.fold( |
||||
onSuccess = {}, |
||||
onFailure = { |
||||
target.value = NotificationSettingsState.MatrixSettings.Invalid(fixFailed = true) |
||||
} |
||||
) |
||||
} |
||||
|
||||
private fun CoroutineScope.setAtRoomNotificationsEnabled(enabled: Boolean) = launch { |
||||
notificationSettingsService.setRoomMentionEnabled(enabled) |
||||
} |
||||
|
||||
private fun CoroutineScope.setCallNotificationsEnabled(enabled: Boolean) = launch { |
||||
notificationSettingsService.setCallEnabled(enabled) |
||||
} |
||||
|
||||
private fun CoroutineScope.setNotificationsEnabled(userPushStore: UserPushStore, enabled: Boolean) = launch { |
||||
userPushStore.setNotificationEnabledForDevice(enabled) |
||||
} |
||||
} |
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.preferences.impl.notifications |
||||
|
||||
import androidx.compose.runtime.Immutable |
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode |
||||
|
||||
@Immutable |
||||
data class NotificationSettingsState( |
||||
val matrixSettings: MatrixSettings, |
||||
val appSettings: AppSettings, |
||||
val eventSink: (NotificationSettingsEvents) -> Unit, |
||||
) { |
||||
sealed interface MatrixSettings { |
||||
data object Uninitialized : MatrixSettings |
||||
data class Valid( |
||||
val atRoomNotificationsEnabled: Boolean, |
||||
val callNotificationsEnabled: Boolean, |
||||
val defaultGroupNotificationMode: RoomNotificationMode?, |
||||
val defaultOneToOneNotificationMode: RoomNotificationMode?, |
||||
) : MatrixSettings |
||||
|
||||
data class Invalid( |
||||
val fixFailed: Boolean |
||||
) : MatrixSettings |
||||
} |
||||
|
||||
data class AppSettings( |
||||
val systemNotificationsEnabled: Boolean, |
||||
val appNotificationsEnabled: Boolean, |
||||
) |
||||
} |
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,41 @@
@@ -0,0 +1,41 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.preferences.impl.notifications |
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider |
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode |
||||
|
||||
open class NotificationSettingsStateProvider : PreviewParameterProvider<NotificationSettingsState> { |
||||
override val values: Sequence<NotificationSettingsState> |
||||
get() = sequenceOf( |
||||
aNotificationSettingsState(), |
||||
) |
||||
} |
||||
|
||||
fun aNotificationSettingsState() = NotificationSettingsState( |
||||
matrixSettings = NotificationSettingsState.MatrixSettings.Valid( |
||||
atRoomNotificationsEnabled = true, |
||||
callNotificationsEnabled = true, |
||||
defaultGroupNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, |
||||
defaultOneToOneNotificationMode = RoomNotificationMode.ALL_MESSAGES, |
||||
), |
||||
appSettings = NotificationSettingsState.AppSettings( |
||||
systemNotificationsEnabled = false, |
||||
appNotificationsEnabled = true, |
||||
), |
||||
eventSink = {} |
||||
) |
@ -0,0 +1,263 @@
@@ -0,0 +1,263 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.preferences.impl.notifications |
||||
|
||||
import androidx.compose.foundation.layout.Box |
||||
import androidx.compose.foundation.layout.Column |
||||
import androidx.compose.foundation.layout.Row |
||||
import androidx.compose.foundation.layout.Spacer |
||||
import androidx.compose.foundation.layout.fillMaxWidth |
||||
import androidx.compose.foundation.layout.height |
||||
import androidx.compose.foundation.layout.padding |
||||
import androidx.compose.material.icons.Icons |
||||
import androidx.compose.material.icons.filled.NotificationsOff |
||||
import androidx.compose.material3.MaterialTheme |
||||
import androidx.compose.runtime.Composable |
||||
import androidx.compose.ui.Alignment |
||||
import androidx.compose.ui.Modifier |
||||
import androidx.compose.ui.platform.LocalContext |
||||
import androidx.compose.ui.res.stringResource |
||||
import androidx.compose.ui.text.style.TextAlign |
||||
import androidx.compose.ui.tooling.preview.Preview |
||||
import androidx.compose.ui.tooling.preview.PreviewParameter |
||||
import androidx.compose.ui.unit.dp |
||||
import androidx.lifecycle.Lifecycle |
||||
import io.element.android.libraries.androidutils.system.startNotificationSettingsIntent |
||||
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog |
||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory |
||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch |
||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceText |
||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceView |
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark |
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight |
||||
import io.element.android.libraries.designsystem.theme.components.Button |
||||
import io.element.android.libraries.designsystem.theme.components.ButtonSize |
||||
import io.element.android.libraries.designsystem.theme.components.Surface |
||||
import io.element.android.libraries.designsystem.theme.components.Text |
||||
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent |
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode |
||||
import io.element.android.libraries.theme.ElementTheme |
||||
import io.element.android.libraries.ui.strings.CommonStrings |
||||
|
||||
/** |
||||
* A view that allows a user edit their global notification settings. |
||||
*/ |
||||
@Composable |
||||
fun NotificationSettingsView( |
||||
state: NotificationSettingsState, |
||||
onOpenEditDefault: (isOneToOne: Boolean) -> Unit, |
||||
onBackPressed: () -> Unit, |
||||
modifier: Modifier = Modifier, |
||||
) { |
||||
OnLifecycleEvent { _, event -> |
||||
when (event) { |
||||
Lifecycle.Event.ON_RESUME -> state.eventSink.invoke(NotificationSettingsEvents.RefreshSystemNotificationsEnabled) |
||||
else -> Unit |
||||
} |
||||
} |
||||
PreferenceView( |
||||
modifier = modifier, |
||||
onBackPressed = onBackPressed, |
||||
title = stringResource(id = CommonStrings.screen_notification_settings_title) |
||||
) { |
||||
|
||||
when (state.matrixSettings) { |
||||
is NotificationSettingsState.MatrixSettings.Invalid -> InvalidNotificationSettingsView( |
||||
showError = state.matrixSettings.fixFailed, |
||||
onContinueClicked = { state.eventSink(NotificationSettingsEvents.FixConfigurationMismatch) }, |
||||
onDismissError = { state.eventSink(NotificationSettingsEvents.ClearConfigurationMismatchError) }, |
||||
) |
||||
NotificationSettingsState.MatrixSettings.Uninitialized -> return@PreferenceView |
||||
is NotificationSettingsState.MatrixSettings.Valid -> NotificationSettingsContentView( |
||||
matrixSettings = state.matrixSettings, |
||||
systemSettings = state.appSettings, |
||||
onNotificationsEnabledChanged = { state.eventSink(NotificationSettingsEvents.SetNotificationsEnabled(it))}, |
||||
onGroupChatsClicked = { onOpenEditDefault(false) }, |
||||
onDirectChatsClicked = { onOpenEditDefault(true) }, |
||||
onMentionNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetAtRoomNotificationsEnabled(it)) }, |
||||
// onCallsNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetCallNotificationsEnabled(it)) }, |
||||
) |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Composable |
||||
private fun NotificationSettingsContentView( |
||||
matrixSettings: NotificationSettingsState.MatrixSettings.Valid, |
||||
systemSettings: NotificationSettingsState.AppSettings, |
||||
onNotificationsEnabledChanged: (Boolean) -> Unit, |
||||
onGroupChatsClicked: () -> Unit, |
||||
onDirectChatsClicked: () -> Unit, |
||||
onMentionNotificationsChanged: (Boolean) -> Unit, |
||||
// onCallsNotificationsChanged: (Boolean) -> Unit, |
||||
modifier: Modifier = Modifier, |
||||
) { |
||||
val context = LocalContext.current |
||||
if (systemSettings.appNotificationsEnabled && !systemSettings.systemNotificationsEnabled) { |
||||
PreferenceText( |
||||
icon = Icons.Filled.NotificationsOff, |
||||
title = stringResource(id = CommonStrings.screen_notification_settings_system_notifications_turned_off), |
||||
subtitle = stringResource(id = CommonStrings.screen_notification_settings_system_notifications_action_required, |
||||
stringResource(id = CommonStrings.screen_notification_settings_system_notifications_action_required_content_link)), |
||||
onClick = { |
||||
context.startNotificationSettingsIntent() |
||||
} |
||||
) |
||||
} |
||||
|
||||
PreferenceSwitch( |
||||
modifier = modifier, |
||||
title = stringResource(id = CommonStrings.screen_notification_settings_enable_notifications), |
||||
isChecked = systemSettings.appNotificationsEnabled, |
||||
switchAlignment = Alignment.Top, |
||||
onCheckedChange = onNotificationsEnabledChanged |
||||
) |
||||
|
||||
if (systemSettings.appNotificationsEnabled) { |
||||
PreferenceCategory(title = stringResource(id = CommonStrings.screen_notification_settings_notification_section_title)) { |
||||
PreferenceText( |
||||
title = stringResource(id = CommonStrings.screen_notification_settings_group_chats), |
||||
subtitle = getTitleForRoomNotificationMode(mode = matrixSettings.defaultGroupNotificationMode), |
||||
onClick = onGroupChatsClicked |
||||
) |
||||
|
||||
PreferenceText( |
||||
title = stringResource(id = CommonStrings.screen_notification_settings_direct_chats), |
||||
subtitle = getTitleForRoomNotificationMode(mode = matrixSettings.defaultOneToOneNotificationMode), |
||||
onClick = onDirectChatsClicked |
||||
) |
||||
} |
||||
|
||||
PreferenceCategory(title = stringResource(id = CommonStrings.screen_notification_settings_mode_mentions)) { |
||||
PreferenceSwitch( |
||||
modifier = Modifier, |
||||
title = stringResource(id = CommonStrings.screen_notification_settings_room_mention_label), |
||||
isChecked = matrixSettings.atRoomNotificationsEnabled, |
||||
switchAlignment = Alignment.Top, |
||||
onCheckedChange = onMentionNotificationsChanged |
||||
) |
||||
} |
||||
// We are removing the call notification toggle until call support has been added |
||||
// PreferenceCategory(title = stringResource(id = CommonStrings.screen_notification_settings_additional_settings_section_title)) { |
||||
// PreferenceSwitch( |
||||
// modifier = Modifier, |
||||
// title = stringResource(id = CommonStrings.screen_notification_settings_calls_label), |
||||
// isChecked = matrixSettings.callNotificationsEnabled, |
||||
// switchAlignment = Alignment.Top, |
||||
// onCheckedChange = onCallsNotificationsChanged |
||||
// ) |
||||
// } |
||||
} |
||||
} |
||||
|
||||
@Composable |
||||
private fun getTitleForRoomNotificationMode(mode: RoomNotificationMode?) = |
||||
when(mode) { |
||||
RoomNotificationMode.ALL_MESSAGES -> stringResource(id = CommonStrings.screen_notification_settings_edit_mode_all_messages) |
||||
RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> stringResource(id = CommonStrings.screen_notification_settings_edit_mode_mentions_and_keywords) |
||||
RoomNotificationMode.MUTE -> stringResource(id = CommonStrings.common_mute) |
||||
null -> "" |
||||
} |
||||
|
||||
@Composable |
||||
private fun InvalidNotificationSettingsView( |
||||
showError: Boolean, |
||||
onContinueClicked: () -> Unit, |
||||
onDismissError: () -> Unit, |
||||
modifier: Modifier = Modifier |
||||
) { |
||||
Box(modifier = modifier.padding(horizontal = 16.dp, vertical = 8.dp)) { |
||||
Surface( |
||||
Modifier.fillMaxWidth(), |
||||
shape = MaterialTheme.shapes.small, |
||||
color = MaterialTheme.colorScheme.surfaceVariant |
||||
) { |
||||
Column( |
||||
Modifier |
||||
.fillMaxWidth() |
||||
.padding(horizontal = 16.dp, vertical = 12.dp) |
||||
) { |
||||
Row { |
||||
Text( |
||||
stringResource(CommonStrings.screen_notification_settings_configuration_mismatch), |
||||
modifier = Modifier.weight(1f), |
||||
style = ElementTheme.typography.fontBodyLgMedium, |
||||
color = MaterialTheme.colorScheme.primary, |
||||
textAlign = TextAlign.Start, |
||||
) |
||||
} |
||||
Spacer(modifier = Modifier.height(4.dp)) |
||||
Text( |
||||
stringResource(CommonStrings.screen_notification_settings_configuration_mismatch_description), |
||||
style = ElementTheme.typography.fontBodyMdRegular, |
||||
) |
||||
Spacer(modifier = Modifier.height(12.dp)) |
||||
Button( |
||||
text = stringResource(CommonStrings.action_continue), |
||||
size = ButtonSize.Medium, |
||||
modifier = Modifier.fillMaxWidth(), |
||||
onClick = onContinueClicked, |
||||
) |
||||
} |
||||
} |
||||
} |
||||
if(showError) { |
||||
ErrorDialog( |
||||
title = stringResource(id = CommonStrings.dialog_title_error), |
||||
content = stringResource(id = CommonStrings.screen_notification_settings_failed_fixing_configuration), |
||||
onDismiss = onDismissError |
||||
) |
||||
} |
||||
} |
||||
|
||||
@Preview |
||||
@Composable |
||||
internal fun NotificationSettingsViewLightPreview(@PreviewParameter(NotificationSettingsStateProvider::class) state: NotificationSettingsState) = |
||||
ElementPreviewLight { ContentToPreview(state) } |
||||
|
||||
@Preview |
||||
@Composable |
||||
internal fun NotificationSettingsViewDarkPreview(@PreviewParameter(NotificationSettingsStateProvider::class) state: NotificationSettingsState) = |
||||
ElementPreviewDark { ContentToPreview(state) } |
||||
|
||||
@Composable |
||||
private fun ContentToPreview(state: NotificationSettingsState) { |
||||
NotificationSettingsView( |
||||
state = state, |
||||
onBackPressed = {}, |
||||
onOpenEditDefault = {}, |
||||
) |
||||
} |
||||
|
||||
@Preview |
||||
@Composable |
||||
internal fun InvalidNotificationSettingsViewightPreview() = |
||||
ElementPreviewLight { InvalidNotificationSettingsContentToPreview() } |
||||
|
||||
@Preview |
||||
@Composable |
||||
internal fun InvalidNotificationSettingsViewDarkPreview() = |
||||
ElementPreviewDark { InvalidNotificationSettingsContentToPreview() } |
||||
|
||||
@Composable |
||||
private fun InvalidNotificationSettingsContentToPreview() { |
||||
InvalidNotificationSettingsView( |
||||
showError = false, |
||||
onContinueClicked = {}, |
||||
onDismissError = {}, |
||||
) |
||||
} |
@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.preferences.impl.notifications |
||||
|
||||
import android.content.Context |
||||
import androidx.core.app.NotificationManagerCompat |
||||
import com.squareup.anvil.annotations.ContributesBinding |
||||
import io.element.android.libraries.di.AppScope |
||||
import io.element.android.libraries.di.ApplicationContext |
||||
import io.element.android.libraries.di.SingleIn |
||||
import javax.inject.Inject |
||||
|
||||
interface SystemNotificationsEnabledProvider { |
||||
fun notificationsEnabled(): Boolean |
||||
} |
||||
@SingleIn(AppScope::class) |
||||
@ContributesBinding(AppScope::class, boundType = SystemNotificationsEnabledProvider::class) |
||||
class DefaultSystemNotificationsEnabledProvider @Inject constructor( |
||||
@ApplicationContext private val context: Context, |
||||
): SystemNotificationsEnabledProvider { |
||||
override fun notificationsEnabled(): Boolean { |
||||
return NotificationManagerCompat.from(context).areNotificationsEnabled() |
||||
} |
||||
} |
||||
|
@ -0,0 +1,98 @@
@@ -0,0 +1,98 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.preferences.impl.notifications.edit |
||||
import androidx.compose.foundation.layout.Column |
||||
import androidx.compose.foundation.layout.Row |
||||
import androidx.compose.foundation.layout.fillMaxWidth |
||||
import androidx.compose.foundation.layout.padding |
||||
import androidx.compose.foundation.layout.size |
||||
import androidx.compose.foundation.selection.selectable |
||||
import androidx.compose.runtime.Composable |
||||
import androidx.compose.ui.Alignment |
||||
import androidx.compose.ui.Modifier |
||||
import androidx.compose.ui.res.stringResource |
||||
import androidx.compose.ui.semantics.Role |
||||
import androidx.compose.ui.unit.dp |
||||
import io.element.android.libraries.designsystem.preview.DayNightPreviews |
||||
import io.element.android.libraries.designsystem.preview.ElementPreview |
||||
import io.element.android.libraries.designsystem.theme.components.RadioButton |
||||
import io.element.android.libraries.designsystem.theme.components.Text |
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode |
||||
import io.element.android.libraries.theme.ElementTheme |
||||
import io.element.android.libraries.ui.strings.CommonStrings |
||||
|
||||
@Composable |
||||
fun DefaultNotificationSettingOption( |
||||
mode: RoomNotificationMode, |
||||
modifier: Modifier = Modifier, |
||||
isSelected: Boolean = false, |
||||
onOptionSelected: (RoomNotificationMode) -> Unit = {}, |
||||
) { |
||||
val subtitle = when(mode) { |
||||
RoomNotificationMode.ALL_MESSAGES -> stringResource(id = CommonStrings.screen_notification_settings_edit_mode_all_messages) |
||||
RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> stringResource(id = CommonStrings.screen_notification_settings_edit_mode_mentions_and_keywords) |
||||
else -> "" |
||||
} |
||||
Row( |
||||
modifier |
||||
.fillMaxWidth() |
||||
.selectable( |
||||
selected = isSelected, |
||||
onClick = { onOptionSelected(mode) }, |
||||
role = Role.RadioButton, |
||||
) |
||||
.padding(8.dp), |
||||
) { |
||||
Column( |
||||
Modifier |
||||
.weight(1f) |
||||
.padding(horizontal = 8.dp) |
||||
.align(Alignment.CenterVertically) |
||||
) { |
||||
Text( |
||||
text = subtitle, |
||||
style = ElementTheme.typography.fontBodyLgRegular, |
||||
) |
||||
} |
||||
|
||||
RadioButton( |
||||
modifier = Modifier |
||||
.align(Alignment.CenterVertically) |
||||
.size(48.dp), |
||||
selected = isSelected, |
||||
onClick = null // null recommended for accessibility with screenreaders |
||||
) |
||||
} |
||||
} |
||||
@DayNightPreviews |
||||
@Composable |
||||
internal fun DefaultNotificationSettingOptionPreview() = ElementPreview { ContentToPreview() } |
||||
|
||||
@Composable |
||||
private fun ContentToPreview() { |
||||
Column { |
||||
DefaultNotificationSettingOption( |
||||
mode = RoomNotificationMode.ALL_MESSAGES, |
||||
isSelected = true, |
||||
) |
||||
DefaultNotificationSettingOption( |
||||
mode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, |
||||
isSelected = false, |
||||
) |
||||
} |
||||
} |
||||
|
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.preferences.impl.notifications.edit |
||||
|
||||
import androidx.compose.runtime.Composable |
||||
import androidx.compose.ui.Modifier |
||||
import com.bumble.appyx.core.modality.BuildContext |
||||
import com.bumble.appyx.core.node.Node |
||||
import com.bumble.appyx.core.plugin.Plugin |
||||
import dagger.assisted.Assisted |
||||
import dagger.assisted.AssistedInject |
||||
import io.element.android.anvilannotations.ContributesNode |
||||
import io.element.android.libraries.architecture.NodeInputs |
||||
import io.element.android.libraries.architecture.inputs |
||||
import io.element.android.libraries.di.SessionScope |
||||
|
||||
@ContributesNode(SessionScope::class) |
||||
class EditDefaultNotificationSettingNode @AssistedInject constructor( |
||||
@Assisted buildContext: BuildContext, |
||||
@Assisted plugins: List<Plugin>, |
||||
presenterFactory: EditDefaultNotificationSettingPresenter.Factory |
||||
) : Node(buildContext, plugins = plugins) { |
||||
|
||||
data class Inputs( |
||||
val isOneToOne: Boolean |
||||
) : NodeInputs |
||||
|
||||
private val inputs = inputs<Inputs>() |
||||
private val presenter = presenterFactory.create(inputs.isOneToOne) |
||||
|
||||
@Composable |
||||
override fun View(modifier: Modifier) { |
||||
val state = presenter.present() |
||||
EditDefaultNotificationSettingView( |
||||
state = state, |
||||
onBackPressed = ::navigateUp, |
||||
modifier = modifier |
||||
) |
||||
} |
||||
} |
@ -0,0 +1,92 @@
@@ -0,0 +1,92 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.preferences.impl.notifications.edit |
||||
|
||||
import androidx.compose.runtime.Composable |
||||
import androidx.compose.runtime.LaunchedEffect |
||||
import androidx.compose.runtime.MutableState |
||||
import androidx.compose.runtime.mutableStateOf |
||||
import androidx.compose.runtime.remember |
||||
import androidx.compose.runtime.rememberCoroutineScope |
||||
import dagger.assisted.Assisted |
||||
import dagger.assisted.AssistedFactory |
||||
import dagger.assisted.AssistedInject |
||||
import io.element.android.libraries.architecture.Presenter |
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService |
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode |
||||
import kotlinx.coroutines.CoroutineScope |
||||
import kotlinx.coroutines.FlowPreview |
||||
import kotlinx.coroutines.flow.debounce |
||||
import kotlinx.coroutines.flow.launchIn |
||||
import kotlinx.coroutines.flow.onEach |
||||
import kotlinx.coroutines.launch |
||||
import kotlin.time.Duration.Companion.seconds |
||||
|
||||
class EditDefaultNotificationSettingPresenter @AssistedInject constructor( |
||||
private val notificationSettingsService: NotificationSettingsService, |
||||
@Assisted private val isOneToOne: Boolean, |
||||
) : Presenter<EditDefaultNotificationSettingState> { |
||||
@AssistedFactory |
||||
interface Factory { |
||||
fun create(oneToOne: Boolean): EditDefaultNotificationSettingPresenter |
||||
} |
||||
@Composable |
||||
override fun present(): EditDefaultNotificationSettingState { |
||||
|
||||
val mode: MutableState<RoomNotificationMode?> = remember { |
||||
mutableStateOf(null) |
||||
} |
||||
val localCoroutineScope = rememberCoroutineScope() |
||||
LaunchedEffect(Unit) { |
||||
fetchSettings(mode) |
||||
observeNotificationSettings(mode) |
||||
} |
||||
|
||||
fun handleEvents(event: EditDefaultNotificationSettingStateEvents) { |
||||
when (event) { |
||||
is EditDefaultNotificationSettingStateEvents.SetNotificationMode -> localCoroutineScope.setDefaultNotificationMode(event.mode) |
||||
} |
||||
} |
||||
|
||||
return EditDefaultNotificationSettingState( |
||||
isOneToOne = isOneToOne, |
||||
mode = mode.value, |
||||
eventSink = ::handleEvents |
||||
) |
||||
} |
||||
|
||||
private fun CoroutineScope.fetchSettings(mode: MutableState<RoomNotificationMode?>) = launch { |
||||
mode.value = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = isOneToOne).getOrThrow() |
||||
} |
||||
|
||||
@OptIn(FlowPreview::class) |
||||
private fun CoroutineScope.observeNotificationSettings(mode: MutableState<RoomNotificationMode?>) { |
||||
notificationSettingsService.notificationSettingsChangeFlow |
||||
.debounce(0.5.seconds) |
||||
.onEach { |
||||
fetchSettings(mode) |
||||
} |
||||
.launchIn(this) |
||||
} |
||||
|
||||
private fun CoroutineScope.setDefaultNotificationMode(mode: RoomNotificationMode) = launch { |
||||
// On modern clients, we don't have different settings for encrypted and non-encrypted rooms (Legacy clients did). |
||||
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = true, mode = mode, isOneToOne = isOneToOne) |
||||
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = false, mode = mode, isOneToOne = isOneToOne) |
||||
} |
||||
|
||||
} |
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.preferences.impl.notifications.edit |
||||
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode |
||||
|
||||
data class EditDefaultNotificationSettingState( |
||||
val isOneToOne: Boolean, |
||||
val mode: RoomNotificationMode?, |
||||
val eventSink: (EditDefaultNotificationSettingStateEvents) -> Unit, |
||||
) |
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.preferences.impl.notifications.edit |
||||
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode |
||||
|
||||
sealed interface EditDefaultNotificationSettingStateEvents { |
||||
data class SetNotificationMode(val mode: RoomNotificationMode): EditDefaultNotificationSettingStateEvents |
||||
} |
@ -0,0 +1,75 @@
@@ -0,0 +1,75 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.preferences.impl.notifications.edit |
||||
|
||||
import androidx.compose.foundation.layout.Column |
||||
import androidx.compose.foundation.selection.selectableGroup |
||||
import androidx.compose.runtime.Composable |
||||
import androidx.compose.ui.Modifier |
||||
import androidx.compose.ui.res.stringResource |
||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory |
||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceView |
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode |
||||
import io.element.android.libraries.ui.strings.CommonStrings |
||||
|
||||
/** |
||||
* A view that allows a user to edit the default notification setting for rooms. This can be set separately |
||||
* for one-to-one and group rooms, indicated by [EditDefaultNotificationSettingState.isOneToOne]. |
||||
*/ |
||||
@Composable |
||||
fun EditDefaultNotificationSettingView( |
||||
state: EditDefaultNotificationSettingState, |
||||
onBackPressed: () -> Unit, |
||||
modifier: Modifier = Modifier, |
||||
) { |
||||
|
||||
val title = if(state.isOneToOne) { |
||||
CommonStrings.screen_notification_settings_direct_chats |
||||
} else { |
||||
CommonStrings.screen_notification_settings_group_chats |
||||
} |
||||
PreferenceView( |
||||
modifier = modifier, |
||||
onBackPressed = onBackPressed, |
||||
title = stringResource(id = title) |
||||
) { |
||||
|
||||
// Only ALL_MESSAGES and MENTIONS_AND_KEYWORDS_ONLY are valid global defaults. |
||||
val validModes = listOf(RoomNotificationMode.ALL_MESSAGES, RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY) |
||||
|
||||
val categoryTitle = if(state.isOneToOne) { |
||||
CommonStrings.screen_notification_settings_edit_screen_direct_section_header |
||||
} else { |
||||
CommonStrings.screen_notification_settings_edit_screen_group_section_header |
||||
} |
||||
PreferenceCategory(title = stringResource(id = categoryTitle)) { |
||||
|
||||
if (state.mode != null) { |
||||
Column(modifier = Modifier.selectableGroup()) { |
||||
validModes.forEach { item -> |
||||
DefaultNotificationSettingOption( |
||||
mode = item, |
||||
isSelected = state.mode == item, |
||||
onOptionSelected = { state.eventSink(EditDefaultNotificationSettingStateEvents.SetNotificationMode(it)) } |
||||
) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue