From 8aada10f0d32a80fe7372f0c4c52b7e09d236fe3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 3 Sep 2020 15:21:21 +0200 Subject: [PATCH 01/89] Show M_WEAK_PASSWORD error in the password field --- .../matrix/android/sdk/api/failure/MatrixError.kt | 2 ++ .../im/vector/app/features/login/LoginFragment.kt | 14 ++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixError.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixError.kt index ff68107ffc..77a5dc4f85 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixError.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixError.kt @@ -132,6 +132,8 @@ data class MatrixError( const val M_CANNOT_LEAVE_SERVER_NOTICE_ROOM = "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM" /** (Not documented yet) */ const val M_WRONG_ROOM_KEYS_VERSION = "M_WRONG_ROOM_KEYS_VERSION" + /** (Not documented yet) */ + const val M_WEAK_PASSWORD = "M_WEAK_PASSWORD" const val M_TERMS_NOT_SIGNED = "M_TERMS_NOT_SIGNED" diff --git a/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt index a2c458dd67..3ee0d6d9df 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt @@ -33,13 +33,13 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.showPassword import im.vector.app.core.extensions.toReducedUrl -import org.matrix.android.sdk.api.failure.Failure -import org.matrix.android.sdk.api.failure.MatrixError -import org.matrix.android.sdk.api.failure.isInvalidPassword import io.reactivex.Observable import io.reactivex.functions.BiFunction import io.reactivex.rxkotlin.subscribeBy import kotlinx.android.synthetic.main.fragment_login.* +import org.matrix.android.sdk.api.failure.Failure +import org.matrix.android.sdk.api.failure.MatrixError +import org.matrix.android.sdk.api.failure.isInvalidPassword import javax.inject.Inject /** @@ -234,7 +234,13 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() { } override fun onError(throwable: Throwable) { - loginFieldTil.error = errorFormatter.toHumanReadable(throwable) + // Show M_WEAK_PASSWORD error in the password field + if (throwable is Failure.ServerError + && throwable.error.code == MatrixError.M_WEAK_PASSWORD) { + passwordFieldTil.error = errorFormatter.toHumanReadable(throwable) + } else { + loginFieldTil.error = errorFormatter.toHumanReadable(throwable) + } } override fun updateWithState(state: LoginViewState) { From bf0b6d738ada87a14827664d74d0476202760d2c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 8 Sep 2020 17:49:26 +0200 Subject: [PATCH 02/89] Version++ --- CHANGES.md | 24 ++++++++++++++++++++++++ vector/build.gradle | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 4d1be71a25..b1a93209bc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,27 @@ +Changes in Element 1.0.7 (2020-XX-XX) +=================================================== + +Features ✨: + - + +Improvements 🙌: + - + +Bugfix 🐛: + - + +Translations 🗣: + - + +SDK API changes ⚠️: + - + +Build 🧱: + - + +Other changes: + - + Changes in Element 1.0.6 (2020-09-08) =================================================== diff --git a/vector/build.gradle b/vector/build.gradle index 52ff0dd23c..6b251d5329 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -17,7 +17,7 @@ androidExtensions { // Note: 2 digits max for each value ext.versionMajor = 1 ext.versionMinor = 0 -ext.versionPatch = 6 +ext.versionPatch = 7 static def getGitTimestamp() { def cmd = 'git show -s --format=%ct' From f0b582fef072467fe637d2de39bbc63d305b2798 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Tue, 8 Sep 2020 03:22:29 +0000 Subject: [PATCH 03/89] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1867 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/zh_Hant/ --- vector/src/main/res/values-zh-rTW/strings.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml index 24480a2d90..ae01b55ab9 100644 --- a/vector/src/main/res/values-zh-rTW/strings.xml +++ b/vector/src/main/res/values-zh-rTW/strings.xml @@ -2547,4 +2547,22 @@ Matrix 中的消息可見度類似于電子郵件。我們忘記您的郵件意 警告!登出前的最後一次嘗試! 太多錯誤,您已被登出 +此電話號碼已被定義。 + 未新增電話號碼到您的帳號 + 電子郵件地址 + 未傳送電子郵件到您的帳號 + 電話號碼 + 移除 %s? + 確保您已經點擊我們傳送給您的電子郵件中的連結。 + + 電子郵件與電話號碼 + 管理連結到您 Matrix 帳號的電子郵件與電話號碼 + + 代碼 + 請使用國際格式(電話號碼必須以 \'+\' 開頭) + 透過確認此登入來驗證您的身份,以及授予存取加密訊息的權限。 + 抱歉,對於使用單一登入的帳號,還無法執行此動作。 + + 無法開啟禁止您進入的聊天室。 + 找不到此聊天室。請確定它存在。 From f932100388bc2814efc429907c959156c82d2388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Mon, 7 Sep 2020 14:45:19 +0000 Subject: [PATCH 04/89] Translated using Weblate (Estonian) Currently translated at 100.0% (1867 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/et/ --- vector/src/main/res/values-et/strings.xml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/vector/src/main/res/values-et/strings.xml b/vector/src/main/res/values-et/strings.xml index 6bd85ad42e..2825586f55 100644 --- a/vector/src/main/res/values-et/strings.xml +++ b/vector/src/main/res/values-et/strings.xml @@ -2526,4 +2526,25 @@ Hoiatus! Viimane katse enne väljalogimist! Liiga palju vigu PIN-koodi sisestamisel ning sa oled nüüd välja logitud +See telefoninumber on juba määratletud. + Ühtegi telefoninumbrit pole sinu kasutajakontoga seotud + E-posti aadressid + Ühtegi e-posti aadressi pole sinu kasutajakontoga seotud + Telefoninumbrid + Kas eemaldan %s\? + Palun vaata üle, et kindlasti oleksid klõpsinud linki, mille me sulle e-kirjaga saatsime. + + E-posti aadressid ja telefoninumbrid + Halda on Matrix\'i kontoga seotud e-posti aadresse ja telefoninumbreid + + Kood + Palun kasuta rahvusvahelist vormingut (telefoninumbri alguses peaks olema „+“) + Lisaturvalisus mõttes verifitseeri %s võrreldes selleks üheks korraks loodud koodi teie mõlemas seadmes. +\n +\nParima turvalisuse nimel kohtuge silmast silma. + Kinnita oma isikusamasust verifitseerides seda sisselogimissessiooni. Sellega tagad ligipääsu krüptitud sõnumitele. + Vabandust, selline tegevus pole veel võimalik kasutajakontode puhul, kus kasutatakse ühekordset sisselogimist. + + Ei ole võimalik avada sellise jututoa vaadet, kus sulle on seatud suhtluskeeld. + Ei leia sellist jututuba. Palun kontrolli, et ta ikka olemas on. From 11fc0fed75b809b5eca4f47df7c754aee2d49151 Mon Sep 17 00:00:00 2001 From: "@a2sc:matrix.org" Date: Mon, 7 Sep 2020 20:07:19 +0000 Subject: [PATCH 05/89] Translated using Weblate (German) Currently translated at 100.0% (1867 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/de/ --- vector/src/main/res/values-de/strings.xml | 44 ++++++++++++++++------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml index f7037c11fc..2b8ca03ecc 100644 --- a/vector/src/main/res/values-de/strings.xml +++ b/vector/src/main/res/values-de/strings.xml @@ -250,7 +250,7 @@ Element benötigt die Berechtigung, auf deine Kamera zugreifen zu können, um Bilder aufzunehmen und Video-Anrufe durchzuführen. " \n -\nBitte erlaube den Zugriff im nächsten Dialog, um den Anruf zu durchzuführen." +\nBitte erlaube den Zugriff im nächsten Dialog, um den Anruf durchzuführen." Element benötigt die Berechtigung, auf dein Mikrofon zugreifen zu können, um (Sprach-)Anrufe tätigen zu können. " \n @@ -825,7 +825,7 @@ Achtung: Diese Datei wird vielleicht gelöscht, wenn die App deinstalliert wird. Community Avatare - Schüttele, um einen Fehler zu melden + Schütteln, um einen Fehler zu melden Aktionen Mitglieder auflisten @@ -904,7 +904,7 @@ Achtung: Diese Datei wird vielleicht gelöscht, wenn die App deinstalliert wird. \nMöchtest du welche hinzufügen\? Account deaktivieren - Deaktivere meinen Account + Deaktiviere meinen Account Sende Analysedaten Element sammelt anonyme Analysedaten um uns zu helfen, die App zu verbessern. @@ -1191,7 +1191,7 @@ Versuche die Anwendung neuzustarten. Laute Benachrichtigungen einstellen Anrufbenachrichtigung einstellen - Stumme Benachrichtigungen einstellen + Lautlose Benachrichtigungen einstellen Wähle LED-Farbe, Vibration, Ton… @@ -1407,7 +1407,7 @@ Verwahre deinen Wiederherstellungsschlüssel an einem sehr sicheren Ort wie eine Sitzung verifizieren Unbekannte IP-Adresse - Eine neue Sitzung fordert Verschlüsselungs-Schlüssel an. + Eine neue Sitzung fordert Verschlüsselungsschlüssel an. \nSitzungsname: %1$s \nZuletzt gesehen: %2$s \nWenn du dich nicht mit einer anderen Sitzung angemeldet hast, ignoriere diese Anfrage. @@ -1652,7 +1652,7 @@ Verwahre deinen Wiederherstellungsschlüssel an einem sehr sicheren Ort wie eine Verbindung zum Identitätsserver trennen Identitätsserver konfigurieren Identitätsserver ändern - Erkennbare E-Mail-Adressen + Auffindbare E-Mail-Adressen Erkennungsoptionen werden angezeigt, sobald du eine E-Mail hinzugefügt hast. ausstehend @@ -1714,11 +1714,11 @@ Verwahre deinen Wiederherstellungsschlüssel an einem sehr sicheren Ort wie eine Du nutzt aktuell %1$s um vorhandene Kontakte zu finden und um von dir bekannten Kontakten gefunden zu werden. Du benutzt aktuell keinen Identitätsserver. Um zu entdecken und um von dir bekannten Kontakten entdeckt zu werden, richte unten einen ein. - Entdeckbare Telefonnummern - Bitte gebe Adresse des Identitätsserver ein + Auffindbare Telefonnummern + Bitte gib die Adresse des Identitätsservers ein Identitätsserver hat keine Nutzungsbedingungen Der Identitätsserver den du ausgewählt hast, hat keine Nutzungsbedingungen. Fahre nur fort, wenn du dem/r Besitzer!n des Dienstes vertraust - Eine Textnachricht wurde an %s gesendet. Bitte gebe den Verifizierungscode ein, den sie enthält. + Eine Textnachricht wurde an %s gesendet. Bitte gib den Verifizierungscode ein, den sie enthält. Aktiviere ausführliche Logs. Ausführliche Logs werden der Entwicklung der App dadurch helfen, dass mehr Informationen übertragen werden, wenn du einen Fehlerbericht sendest. Auch wenn dies aktiviert ist, werden keine Nachrichteninhalte oder andere privaten Daten aufgezeichnet. @@ -2108,7 +2108,7 @@ Verwahre deinen Wiederherstellungsschlüssel an einem sehr sicheren Ort wie eine Deine neue Sitzung ist jetzt verifiziert. Sie hat Zugriff auf deine verschlüsselten Nachrichten, und andere Benutzer!nnen sehen sie als vertrauenswürdig an. - Kreuz-Signierung + Cross-Signing Cross-Signing ist aktiviert \nPrivate Schlüssel auf dem Gerät. Cross-Signing ist aktiviert @@ -2624,9 +2624,9 @@ Verwahre deinen Wiederherstellungsschlüssel an einem sehr sicheren Ort wie eine Aktiviere PIN Wenn du deine PIN zurücksetzen möchtest, tippe \"PIN vergessen\" um dich abzumelden und sie anschließend zurückzusetzen. Bestätige PIN um die PIN zu deaktivieren - Fasse \"unable to decrypt\"-Fehler im Chatverlauf zu Hinweisen zusammen - Verhindern Sie versehentliche Anrufe - Bitten Sie um Bestätigung, bevor Sie einen Anruf tätigen + Fasse \"Nicht entschlüsselbar\"-Fehler im Chatverlauf zu Hinweisen zusammen + Verhindere versehentliche Anrufe + Bitte um Bestätigung, bevor du einen Anruf tätigst Konfiguration Dir fehlt die Berechtigung in diesem Raum eine Konferenz zu starten Es ist bereits eine Konferenz aktiv! @@ -2658,4 +2658,22 @@ Verwahre deinen Wiederherstellungsschlüssel an einem sehr sicheren Ort wie eine Warnung! Letzter Versuch bevor du ausgeloggt wirst! Zu viele Fehler, du bist ausgeloggt worden +Diese Telefonnummer ist bereits registriert. + Deinem Konto wurde keine Telefonnummer hinzugefügt + E-mail-Adressen + Deinem Konto wurde keine E-Mail hinzugefügt + Telefonnummern + %s entfernen\? + Stelle sicher, dass du auf den Link in der E-Mail geklickt hast, die wir dir gesendet haben. + + E-Mail-Adressen und Telefonnummern + Verwalte E-Mails und Telefonnummern, die mit deinem Matrix-Konto verknüpft sind + + Code + Verwende das internationale Format (Telefonnummer muss mit \'+\' beginnen) + Bestätige deine Identität, indem du dieses Login verifizierst, um Zugriff auf verschlüsselte Nachrichten zu erhalten. + Leider ist dieser Vorgang für Konten, die über Single Sign-On verbunden sind, noch nicht möglich. + + Raum, indem du gebannt wurdest, kann nicht geöffnet werden. + Raum kann nicht gefunden werden. Stelle sicher, dass er existiert. From a7ee4517054c13a975230264ee0cd7a0521b5212 Mon Sep 17 00:00:00 2001 From: "@a2sc:matrix.org" Date: Mon, 7 Sep 2020 20:48:03 +0000 Subject: [PATCH 06/89] Translated using Weblate (German) Currently translated at 100.0% (3 of 3 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.riot.im/projects/element-android/element-store/de/ --- vector/src/main/play/listings/de/full_description.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/play/listings/de/full_description.txt b/vector/src/main/play/listings/de/full_description.txt index e06205f89f..133f5e10d4 100644 --- a/vector/src/main/play/listings/de/full_description.txt +++ b/vector/src/main/play/listings/de/full_description.txt @@ -13,7 +13,7 @@ Element ist zu all diesem in der Lage, weil es Matrix nutzt - einen Standard fü Element gibt dir die Kontrolle, indem es dir die Wahl darüber lässt, wer deine Konversationen hostet. In der Element App kannst du zwischen verschiedenen Möglichkeiten auswählen: -1. Kostenlos auf dem öffentlichen matrix.org Server registrieren +1. Kostenlos auf dem öffentlichen matrix.org Server registrieren, der von den Matrix-Entwicklern gehostet wird, oder wähle aus Tausenden von öffentlichen Servern, die von Freiwilligen gehostet werden 2. Einen Account auf einem eigenen Server auf eigener Hardware betreiben 3. Einen Account auf einem benutzerdefinierten Server erstellen, zum Beispiel durch ein Abonnment bei der Element Matrix Services Hosting-Platform From d1fedcac7c980187364815335c252b1e9ff6dd73 Mon Sep 17 00:00:00 2001 From: Nikita Epifanov Date: Mon, 7 Sep 2020 13:23:26 +0000 Subject: [PATCH 07/89] Translated using Weblate (Russian) Currently translated at 100.0% (1867 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/ru/ --- vector/src/main/res/values-ru/strings.xml | 50 +++++++++++++++-------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/vector/src/main/res/values-ru/strings.xml b/vector/src/main/res/values-ru/strings.xml index 42d96669cb..695d7d5451 100644 --- a/vector/src/main/res/values-ru/strings.xml +++ b/vector/src/main/res/values-ru/strings.xml @@ -100,7 +100,7 @@ %d пользователь %d пользователя %d пользователей - + Отправить логи @@ -836,13 +836,13 @@ %d комната %d комнаты %d комнат - + %d комната %d комнаты %d комнат - + %1$s в %2$s @@ -850,7 +850,7 @@ %d активный виджет %d активных виджета %d активных виджетов - + @@ -860,45 +860,45 @@ %d активный участник %d активных участника %d активных участников - + %d участник %d участника %d участников - + %d новое сообщение %d новых сообщения %d новых сообщений - + %1$s комната найдена для %2$s %1$s комнаты найдено для %2$s %1$s комнат найдено для %2$s - + %d изменение членства %d изменения членства %d изменений членства - + %d непрочитанное уведомление %d непрочитанных уведомления %d непрочитанных уведомлений - + %d непрочитанное уведомление %d непрочитанных уведомления %d непрочитанных уведомлений - + Получить аватар Заметка аватара @@ -1033,20 +1033,20 @@ %d выбран %d выбрано %d выбраны - + %d участник %d участника %d участников - + %d комната %d комнаты %d комнат - + Системные оповещения @@ -1307,7 +1307,7 @@ %d новый ключ был добавлен к этому устройству. %d новых ключа были добавлены к этому устройству. %d новых ключей были добавлены к этому устройству. - + @@ -1358,7 +1358,7 @@ Резервное копирование %d ключа… Резервное копирование %d ключей… Резервное копирование %d ключей… - + Все ключи сохранены @@ -2701,4 +2701,22 @@ Предупреждение! Последняя оставшаяся попытка перед выходом из системы! Слишком много ошибок, вы вышли из системы +Этот номер телефона уже определён. + В ваш аккаунт не добавлен номер телефона + Адрес электронной почты + В ваш аккаунт не добавлен адрес электронной почты + Телефонные номера + Удалить %s\? + Убедитесь, что вы перешли по ссылке в электронном письме, которое мы вам отправили. + + Электронная почта и номера телефонов + Управляйте электронной почтой и номерами телефонов, привязанными к вашей учетной записи Matrix + + Код + Используйте международный формат (номер телефона должен начинаться с \'+\') + Подтвердите свою личность, проверив этот логин, предоставив ему доступ к зашифрованным сообщениям. + К сожалению, эта операция пока недоступна для учетных записей, подключенных с помощью единого входа. + + Невозможно открыть комнату, в которую вам запрещён доступ. + Невозможно найти эту комнату. Убедитесь, что она существует. From 09ccf7cdde3909ab4f53594633d44852f2bedb8b Mon Sep 17 00:00:00 2001 From: Nikita Epifanov Date: Mon, 7 Sep 2020 13:22:51 +0000 Subject: [PATCH 08/89] Translated using Weblate (Russian) Currently translated at 100.0% (3 of 3 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.riot.im/projects/element-android/element-store/ru/ --- vector/src/main/play/listings/ru/full_description.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/play/listings/ru/full_description.txt b/vector/src/main/play/listings/ru/full_description.txt index c0ab718630..2ac7f9be54 100644 --- a/vector/src/main/play/listings/ru/full_description.txt +++ b/vector/src/main/play/listings/ru/full_description.txt @@ -13,7 +13,7 @@ Element может делать все это, потому что он рабо Element предоставляет вам полный контроль, позволяя выбрать поставщиков услуг, обслуживающих серверы с вашими беседами. Вы свободны выбрать любой способ размещения прямо из приложения Element: -1. Получить бесплатную учетную запись на общедоступном сервере matrix.org +1. Получить бесплатную учетную запись на общедоступном сервере matrix.org, размещенном разработчиками Matrix, или выберите один из тысяч общедоступных серверов, размещенных волонтерами. 2. Разместить свою учетную запись на собственном сервере 3. Зарегистрироваться на индивидуальном сервере, просто подписавшись на услуги платформы Element Matrix Services From 4581efa4c33e5666c0f367568a8771cedb214f2e Mon Sep 17 00:00:00 2001 From: LinAGKar Date: Tue, 8 Sep 2020 06:56:02 +0000 Subject: [PATCH 09/89] Translated using Weblate (Swedish) Currently translated at 100.0% (1867 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/sv/ --- vector/src/main/res/values-sv/strings.xml | 24 ++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/vector/src/main/res/values-sv/strings.xml b/vector/src/main/res/values-sv/strings.xml index 5383c03ba9..29429ee208 100644 --- a/vector/src/main/res/values-sv/strings.xml +++ b/vector/src/main/res/values-sv/strings.xml @@ -1307,8 +1307,8 @@ Sessioner Låt andra användare se när du skriver. Markdownformatering - Visa läsindikationer - Tryck på läsindikationer för en detaljerad lista. + Visa läskvitton + Tryck på läskvitton för en detaljerad lista. Säker säkerhetskopiering Sätt upp säker säkerhetskopiering Återställ säker säkerhetskopiering @@ -2277,7 +2277,7 @@ Standard i %1$s Anpassad (%1$d) i %2$s - Hoppa till läsindikation + Hoppa till läskvitto Element hanterar inte händelser av typen \'%1$s\' Element stötte på ett fel vid rendering av innehållet i händelsen med id \'%1$s\' @@ -2532,4 +2532,22 @@ Aktivera PIN Om du vill återställa din PIN-kod, tryck på \"Glömt PIN\?\" för att logga ut och återställa. Bekräfta PIN för att återställa PIN +Det här telefonnumret är redan definierat. + Inget telefonnummer har lagts till till ditt konto + E-postadresser + Ingen e-postadress har lagts till till ditt konto + Telefonnummer + Ta bort %s\? + Se till att du har klickat på länken i e-brevet vi skickade till dig. + + E-postadresser och telefonnummer + Hantera e-postadresser och telefonnummer länkade till ditt Matrix-konto + + Kod + Vänligen använd internationellt format (telefonnumret måste börja med \'+\') + Bekräfta din identitet genom att verifiera den här inloggningen, och ge den åtkomst till dina krypterade meddelanden. + Tyvärr stöds den här handlingen inte än för konton anslutna med externt konto. + + Kan inte öppna ett rum du är bannad från. + Kan inte hitta det här rummet. Se till att det existerar. From 925d4d077fdac2b56b7d33428fb3a61997ca5ceb Mon Sep 17 00:00:00 2001 From: LinAGKar Date: Tue, 8 Sep 2020 06:55:10 +0000 Subject: [PATCH 10/89] Translated using Weblate (Swedish) Currently translated at 100.0% (3 of 3 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.riot.im/projects/element-android/element-store/sv/ --- vector/src/main/play/listings/sv/full_description.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/play/listings/sv/full_description.txt b/vector/src/main/play/listings/sv/full_description.txt index c446568483..afd0975586 100644 --- a/vector/src/main/play/listings/sv/full_description.txt +++ b/vector/src/main/play/listings/sv/full_description.txt @@ -13,7 +13,7 @@ Element kan göra allt detta för att den använder Matrix - standarden för öp Element sätter dig i kontroll genom att låta dig välja att vara värd för dina konversationer. Från appen Element kan du välja att ansluta på följande sätt: -1. Skaffa ett gratis konto på den publika servern på matrix.org +1. Skaffa ett gratis konto på den publika servern på matrix.org, vilken drivs av Matrix-utvecklarna, eller välj bland tusentals offentliga servrar som drivs av volontärer 2. Var värd för ditt eget konto genom att driva en server på din egen hårdvara 3. Skapa ett konto på en anpassad server genom att registrera dig på värdplattformen Element Matrix Services @@ -25,6 +25,6 @@ Element sätter dig i kontroll genom att låta dig välja att vara värd för di SUPERSÄKER: Riktig totalsträckskryptering (bara de in konversationen kan avkryptera meddelandena), och korssingering för att verifiera konversationsmedlemmars enheter. -Komplett kommunikation: Meddelanden, röst- och videosamtal, fildelning, skärmdelning och massa integrationer, bottar och widgets. Skapa rum och gemenskaper, håll kontakten och få saker gjorda. +KOMPLETT KOMMUNIKATION: Meddelanden, röst- och videosamtal, fildelning, skärmdelning och massa integrationer, bottar och widgets. Skapa rum och gemenskaper, håll kontakten och få saker gjorda. ÖVERALLT DÄR DU ÄR: Håll kontakten vart du än befinner dig med fullständigt synkroniserad meddelandehistorik på alla dina enheter och på webben på https://app.element.io. From 73ab32fd92506ae2da2f84c34c75a24f3e1a1a0c Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 28 Aug 2020 20:01:10 +0200 Subject: [PATCH 11/89] Start reworking date formatting --- .../core/date/AbbrevDateFormatterProvider.kt | 33 ++++++++ .../app/core/date/DateFormatterProvider.kt | 27 ++++++ .../app/core/date/DateFormatterProviders.kt | 31 +++++++ .../core/date/DefaultDateFormatterProvider.kt | 37 ++++++++ .../app/core/date/VectorDateFormatter.kt | 84 +++++++++++++++++-- .../vector/app/core/resources/DateProvider.kt | 9 ++ .../timeline/TimelineEventController.kt | 11 ++- .../timeline/action/MessageActionState.kt | 5 +- .../action/MessageActionsEpoxyController.kt | 9 +- .../ViewEditHistoryEpoxyController.kt | 2 +- .../reactions/ViewReactionsViewModel.kt | 4 +- .../home/room/list/RoomSummaryItemFactory.kt | 19 ++--- .../media/DataAttachmentRoomProvider.kt | 2 +- .../media/RoomEventsAttachmentProvider.kt | 2 +- .../uploads/files/UploadsFileController.kt | 2 +- .../GossipingEventsEpoxyController.kt | 2 +- 16 files changed, 243 insertions(+), 36 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/core/date/AbbrevDateFormatterProvider.kt create mode 100644 vector/src/main/java/im/vector/app/core/date/DateFormatterProvider.kt create mode 100644 vector/src/main/java/im/vector/app/core/date/DateFormatterProviders.kt create mode 100644 vector/src/main/java/im/vector/app/core/date/DefaultDateFormatterProvider.kt diff --git a/vector/src/main/java/im/vector/app/core/date/AbbrevDateFormatterProvider.kt b/vector/src/main/java/im/vector/app/core/date/AbbrevDateFormatterProvider.kt new file mode 100644 index 0000000000..5108591344 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/date/AbbrevDateFormatterProvider.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 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 im.vector.app.core.date + +import android.text.format.DateFormat +import im.vector.app.core.resources.LocaleProvider +import org.threeten.bp.format.DateTimeFormatter +import javax.inject.Inject + +class AbbrevDateFormatterProvider @Inject constructor(private val localeProvider: LocaleProvider) : DateFormatterProvider { + + override val dateWithMonthFormatter: DateTimeFormatter by lazy { + DateTimeFormatter.ofPattern("d MMM", localeProvider.current()) + } + + override val dateWithYearFormatter: DateTimeFormatter by lazy { + DateTimeFormatter.ofPattern("dd.MM.yyyy",localeProvider.current()) + } +} diff --git a/vector/src/main/java/im/vector/app/core/date/DateFormatterProvider.kt b/vector/src/main/java/im/vector/app/core/date/DateFormatterProvider.kt new file mode 100644 index 0000000000..0ca2eed2a6 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/date/DateFormatterProvider.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 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 im.vector.app.core.date + +import org.threeten.bp.format.DateTimeFormatter + +interface DateFormatterProvider { + + val dateWithMonthFormatter: DateTimeFormatter + + val dateWithYearFormatter: DateTimeFormatter +} + diff --git a/vector/src/main/java/im/vector/app/core/date/DateFormatterProviders.kt b/vector/src/main/java/im/vector/app/core/date/DateFormatterProviders.kt new file mode 100644 index 0000000000..a216b6b5d8 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/date/DateFormatterProviders.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020 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 im.vector.app.core.date + +import javax.inject.Inject + +class DateFormatterProviders @Inject constructor(private val defaultDateFormatterProvider: DefaultDateFormatterProvider, + private val abbrevDateFormatterProvider: AbbrevDateFormatterProvider) { + + fun provide(abbrev: Boolean): DateFormatterProvider { + return if (abbrev) { + abbrevDateFormatterProvider + } else { + defaultDateFormatterProvider + } + } +} diff --git a/vector/src/main/java/im/vector/app/core/date/DefaultDateFormatterProvider.kt b/vector/src/main/java/im/vector/app/core/date/DefaultDateFormatterProvider.kt new file mode 100644 index 0000000000..7a0f671887 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/date/DefaultDateFormatterProvider.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 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 im.vector.app.core.date + +import android.content.Context +import android.text.format.DateFormat +import im.vector.app.core.resources.LocaleProvider +import org.threeten.bp.format.DateTimeFormatter +import javax.inject.Inject + +class DefaultDateFormatterProvider @Inject constructor(private val context: Context, + private val localeProvider: LocaleProvider) + : DateFormatterProvider { + + override val dateWithMonthFormatter: DateTimeFormatter by lazy { + DateTimeFormatter.ofPattern(DateFormat.getBestDateTimePattern(localeProvider.current(), "d MMMMM")) + } + + override val dateWithYearFormatter: DateTimeFormatter by lazy { + DateTimeFormatter.ofPattern(DateFormat.getBestDateTimePattern(localeProvider.current(), "d MMM y")) + } + +} diff --git a/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt b/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt index 02050b0a56..8b0de26a28 100644 --- a/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt +++ b/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt @@ -19,8 +19,11 @@ package im.vector.app.core.date import android.content.Context import android.text.format.DateFormat import android.text.format.DateUtils +import im.vector.app.core.resources.DateProvider import im.vector.app.core.resources.LocaleProvider +import im.vector.app.core.resources.toTimestamp import org.threeten.bp.LocalDateTime +import org.threeten.bp.Period import org.threeten.bp.format.DateTimeFormatter import java.util.Calendar import java.util.Date @@ -41,22 +44,77 @@ fun startOfDay(time: Long): Long { } class VectorDateFormatter @Inject constructor(private val context: Context, - private val localeProvider: LocaleProvider) { + private val localeProvider: LocaleProvider, + private val dateFormatterProviders: DateFormatterProviders) { - private val messageHourFormatter by lazy { - DateTimeFormatter.ofPattern("H:mm", localeProvider.current()) + private val hourFormatter by lazy { + if (DateFormat.is24HourFormat(context)) { + DateTimeFormatter.ofPattern("H:mm", localeProvider.current()) + } else { + DateTimeFormatter.ofPattern("h:mm a", localeProvider.current()) + } } - private val messageDayFormatter by lazy { - DateTimeFormatter.ofPattern(DateFormat.getBestDateTimePattern(localeProvider.current(), "EEE d MMM")) + private val dayFormatter by lazy { + DateTimeFormatter.ofPattern("EEE", localeProvider.current()) + } + + private val fullDateFormatter by lazy { + if (DateFormat.is24HourFormat(context)) { + DateTimeFormatter.ofPattern("EEE, d MMM yyyy H:mm", localeProvider.current()) + } else { + DateTimeFormatter.ofPattern("EEE, d MMM yyyy h:mm a", localeProvider.current()) + } } fun formatMessageHour(localDateTime: LocalDateTime): String { - return messageHourFormatter.format(localDateTime) + return hourFormatter.format(localDateTime) } fun formatMessageDay(localDateTime: LocalDateTime): String { - return messageDayFormatter.format(localDateTime) + return dayFormatter.format(localDateTime) + } + + fun formatMessageDayWithMonth(localDateTime: LocalDateTime, abbrev: Boolean = false): String { + return dateFormatterProviders.provide(abbrev).dateWithMonthFormatter.format(localDateTime) + } + + fun formatMessageDayWithYear(localDateTime: LocalDateTime, abbrev: Boolean = false): String { + return dateFormatterProviders.provide(abbrev).dateWithYearFormatter.format(localDateTime) + } + + fun formatMessageDate( + date: LocalDateTime?, + showFullDate: Boolean = false, + onlyTimeIfSameDay: Boolean = false, + useRelative: Boolean = false, + alwaysShowYear: Boolean = false, + abbrev: Boolean = false + ): String { + if (date == null) { + return "" + } + if (showFullDate) { + return fullDateFormatter.format(date) + } + val currentDate = DateProvider.currentLocalDateTime() + val isSameDay = date.toLocalDate() == currentDate.toLocalDate() + return if (onlyTimeIfSameDay && isSameDay) { + formatMessageHour(date) + } else { + val period = Period.between(date.toLocalDate(), currentDate.toLocalDate()) + if (period.years >= 1 || alwaysShowYear) { + formatMessageDayWithYear(date, abbrev) + } else if (period.months >= 1) { + formatMessageDayWithMonth(date, abbrev) + } else if (useRelative && period.days < 2) { + getRelativeDay(date.toTimestamp()) + } else if (useRelative && period.days < 7) { + formatMessageDay(date) + } else { + formatMessageDayWithMonth(date, abbrev) + } + } } /** @@ -71,12 +129,22 @@ class VectorDateFormatter @Inject constructor(private val context: Context, return "" } val now = System.currentTimeMillis() + var flags = DateUtils.FORMAT_SHOW_WEEKDAY + return DateUtils.getRelativeDateTimeString( context, time, DateUtils.DAY_IN_MILLIS, now - startOfDay(now - 2 * DateUtils.DAY_IN_MILLIS), - DateUtils.FORMAT_SHOW_WEEKDAY or DateUtils.FORMAT_SHOW_TIME + flags ).toString() } + + private fun getRelativeDay(ts: Long): String { + return DateUtils.getRelativeTimeSpanString( + ts, + System.currentTimeMillis(), + DateUtils.DAY_IN_MILLIS, + DateUtils.FORMAT_SHOW_WEEKDAY).toString() + } } diff --git a/vector/src/main/java/im/vector/app/core/resources/DateProvider.kt b/vector/src/main/java/im/vector/app/core/resources/DateProvider.kt index 5769b04d29..443a214259 100644 --- a/vector/src/main/java/im/vector/app/core/resources/DateProvider.kt +++ b/vector/src/main/java/im/vector/app/core/resources/DateProvider.kt @@ -19,10 +19,12 @@ package im.vector.app.core.resources import org.threeten.bp.Instant import org.threeten.bp.LocalDateTime import org.threeten.bp.ZoneId +import org.threeten.bp.ZoneOffset object DateProvider { private val zoneId = ZoneId.systemDefault() + private val zoneOffset = ZoneOffset.UTC fun toLocalDateTime(timestamp: Long?): LocalDateTime { val instant = Instant.ofEpochMilli(timestamp ?: 0) @@ -33,4 +35,11 @@ object DateProvider { val instant = Instant.now() return LocalDateTime.ofInstant(instant, zoneId) } + + fun toTimestamp(localDateTime: LocalDateTime): Long { + return localDateTime.toInstant(zoneOffset).toEpochMilli() + } } + +fun LocalDateTime.toTimestamp(): Long = DateProvider.toTimestamp(this) + diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt index 0bf2876288..c946bec074 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt @@ -29,6 +29,7 @@ import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.epoxy.LoadingItem_ import im.vector.app.core.extensions.localDateTime import im.vector.app.core.extensions.nextOrNull +import im.vector.app.core.resources.DateProvider import im.vector.app.features.home.room.detail.RoomDetailAction import im.vector.app.features.home.room.detail.RoomDetailViewState import im.vector.app.features.home.room.detail.UnreadState @@ -53,7 +54,6 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageImageInfoCon import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent -import org.threeten.bp.LocalDateTime import javax.inject.Inject class TimelineEventController @Inject constructor(private val dateFormatter: VectorDateFormatter, @@ -333,13 +333,16 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec ) { requestModelBuild() } - val daySeparatorItem = buildDaySeparatorItem(addDaySeparator, date) + val daySeparatorItem = buildDaySeparatorItem(addDaySeparator, event.root.originServerTs) return CacheItemData(event.localId, event.root.eventId, eventModel, mergedHeaderModel, daySeparatorItem) } - private fun buildDaySeparatorItem(addDaySeparator: Boolean, date: LocalDateTime): DaySeparatorItem? { + private fun buildDaySeparatorItem(addDaySeparator: Boolean, originServerTs: Long?): DaySeparatorItem? { return if (addDaySeparator) { - val formattedDay = dateFormatter.formatMessageDay(date) + val formattedDay = dateFormatter.formatMessageDate( + date = DateProvider.toLocalDateTime(originServerTs), + alwaysShowYear = true + ) DaySeparatorItem_().formattedDay(formattedDay).id(formattedDay) } else { null diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionState.kt index b1c324e12b..587400700d 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionState.kt @@ -23,6 +23,7 @@ import im.vector.app.core.extensions.canReact import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import java.text.SimpleDateFormat +import java.time.LocalDateTime import java.util.Date import java.util.Locale @@ -56,11 +57,7 @@ data class MessageActionState( constructor(args: TimelineEventFragmentArgs) : this(roomId = args.roomId, eventId = args.eventId, informationData = args.informationData) - private val dateFormat = SimpleDateFormat("EEE, d MMM yyyy HH:mm", Locale.getDefault()) - fun senderName(): String = informationData.memberName?.toString() ?: "" - fun time(): String? = timelineEvent()?.root?.originServerTs?.let { dateFormat.format(Date(it)) } ?: "" - fun canReact() = timelineEvent()?.canReact() == true && actionPermissions.canReact } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt index f4287eb3a4..48ed73d980 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt @@ -20,12 +20,14 @@ import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.mvrx.Success import im.vector.app.EmojiCompatFontProvider import im.vector.app.R +import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.epoxy.bottomsheet.BottomSheetQuickReactionsItem import im.vector.app.core.epoxy.bottomsheet.bottomSheetActionItem import im.vector.app.core.epoxy.bottomsheet.bottomSheetMessagePreviewItem import im.vector.app.core.epoxy.bottomsheet.bottomSheetQuickReactionsItem import im.vector.app.core.epoxy.bottomsheet.bottomSheetSendStateItem import im.vector.app.core.epoxy.dividerItem +import im.vector.app.core.extensions.localDateTime import im.vector.app.core.resources.StringProvider import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.timeline.TimelineEventController @@ -40,13 +42,16 @@ import javax.inject.Inject class MessageActionsEpoxyController @Inject constructor( private val stringProvider: StringProvider, private val avatarRenderer: AvatarRenderer, - private val fontProvider: EmojiCompatFontProvider + private val fontProvider: EmojiCompatFontProvider, + private val dateFormatter: VectorDateFormatter ) : TypedEpoxyController() { var listener: MessageActionsEpoxyControllerListener? = null override fun buildModels(state: MessageActionState) { // Message preview + val date = state.timelineEvent()?.root?.localDateTime() + val formattedDate = dateFormatter.formatMessageDate(date, showFullDate = true) bottomSheetMessagePreviewItem { id("preview") avatarRenderer(avatarRenderer) @@ -54,7 +59,7 @@ class MessageActionsEpoxyController @Inject constructor( movementMethod(createLinkMovementMethod(listener)) userClicked { listener?.didSelectMenuAction(EventSharedAction.OpenUserProfile(state.informationData.senderId)) } body(state.messageBody.linkify(listener)) - time(state.time()) + time(formattedDate) } // Send state diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt index deb9b64500..3db02adc0a 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt @@ -83,7 +83,7 @@ class ViewEditHistoryEpoxyController(private val context: Context, if (lastDate?.get(Calendar.DAY_OF_YEAR) != evDate.get(Calendar.DAY_OF_YEAR)) { // need to display header with day val dateString = if (DateUtils.isToday(evDate.timeInMillis)) context.getString(R.string.today) - else dateFormatter.formatMessageDay(timelineEvent.localDateTime()) + else dateFormatter.formatMessageDayWithMonth(timelineEvent.localDateTime()) genericItemHeader { id(evDate.hashCode()) text(dateString) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt index 0484481019..29032ee5fa 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt @@ -29,12 +29,12 @@ import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.home.room.detail.timeline.action.TimelineEventFragmentArgs +import io.reactivex.Observable +import io.reactivex.Single import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.room.model.ReactionAggregatedSummary import org.matrix.android.sdk.rx.RxRoom import org.matrix.android.sdk.rx.unwrap -import io.reactivex.Observable -import io.reactivex.Single data class DisplayReactionsViewState( val eventId: String, diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt index da58748dea..19561280a6 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt @@ -21,7 +21,6 @@ import im.vector.app.R import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.epoxy.VectorEpoxyModel import im.vector.app.core.extensions.localDateTime -import im.vector.app.core.resources.DateProvider import im.vector.app.core.resources.StringProvider import im.vector.app.core.utils.DebouncedClickListener import im.vector.app.features.home.AvatarRenderer @@ -53,8 +52,8 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor } private fun createInvitationItem(roomSummary: RoomSummary, - changeMembershipState: ChangeMembershipState, - listener: RoomSummaryController.Listener?): VectorEpoxyModel<*> { + changeMembershipState: ChangeMembershipState, + listener: RoomSummaryController.Listener?): VectorEpoxyModel<*> { val secondLine = if (roomSummary.isDirect) { roomSummary.inviterId } else { @@ -87,15 +86,13 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor var latestEventTime: CharSequence = "" val latestEvent = roomSummary.latestPreviewableEvent if (latestEvent != null) { - val date = latestEvent.root.localDateTime() - val currentDate = DateProvider.currentLocalDateTime() - val isSameDay = date.toLocalDate() == currentDate.toLocalDate() latestFormattedEvent = displayableEventFormatter.format(latestEvent, roomSummary.isDirect.not()) - latestEventTime = if (isSameDay) { - dateFormatter.formatMessageHour(date) - } else { - dateFormatter.formatMessageDay(date) - } + latestEventTime = dateFormatter.formatMessageDate( + date = latestEvent.root.localDateTime(), + useRelative = true, + onlyTimeIfSameDay = true, + abbrev = true + ) } val typingMessage = typingHelper.getTypingMessage(roomSummary.typingUsers) return RoomSummaryItem_() diff --git a/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt b/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt index daa8bbc206..76305cb6bb 100644 --- a/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt +++ b/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt @@ -79,7 +79,7 @@ class DataAttachmentRoomProvider( val timeLineEvent = room?.getTimeLineEvent(item.eventId) if (timeLineEvent != null) { val dateString = timeLineEvent.root.localDateTime().let { - "${dateFormatter.formatMessageDay(it)} at ${dateFormatter.formatMessageHour(it)} " + "${dateFormatter.formatMessageDayWithMonth(it)} at ${dateFormatter.formatMessageHour(it)} " } overlayView?.updateWith("${position + 1} of ${attachments.size}", "${timeLineEvent.senderInfo.displayName} $dateString") overlayView?.videoControlsGroup?.isVisible = timeLineEvent.root.isVideoMessage() diff --git a/vector/src/main/java/im/vector/app/features/media/RoomEventsAttachmentProvider.kt b/vector/src/main/java/im/vector/app/features/media/RoomEventsAttachmentProvider.kt index e5f0f481bf..c06dd261e2 100644 --- a/vector/src/main/java/im/vector/app/features/media/RoomEventsAttachmentProvider.kt +++ b/vector/src/main/java/im/vector/app/features/media/RoomEventsAttachmentProvider.kt @@ -129,7 +129,7 @@ class RoomEventsAttachmentProvider( super.overlayViewAtPosition(context, position) val item = attachments[position] val dateString = item.root.localDateTime().let { - "${dateFormatter.formatMessageDay(it)} at ${dateFormatter.formatMessageHour(it)} " + "${dateFormatter.formatMessageDayWithMonth(it)} at ${dateFormatter.formatMessageHour(it)} " } overlayView?.updateWith("${position + 1} of ${attachments.size}", "${item.senderInfo.displayName} $dateString") overlayView?.videoControlsGroup?.isVisible = item.root.isVideoMessage() diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/files/UploadsFileController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/files/UploadsFileController.kt index 46ab4f5986..37b93ea902 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/files/UploadsFileController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/files/UploadsFileController.kt @@ -18,12 +18,12 @@ package im.vector.app.features.roomprofile.uploads.files import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.epoxy.VisibilityState -import org.matrix.android.sdk.api.session.room.uploads.UploadEvent import im.vector.app.R import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.epoxy.loadingItem import im.vector.app.core.resources.StringProvider import im.vector.app.features.roomprofile.uploads.RoomUploadsViewState +import org.matrix.android.sdk.api.session.room.uploads.UploadEvent import javax.inject.Inject class UploadsFileController @Inject constructor( diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsEpoxyController.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsEpoxyController.kt index 2acfff2463..69910bb100 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsEpoxyController.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsEpoxyController.kt @@ -94,7 +94,7 @@ class GossipingEventsEpoxyController @Inject constructor( ) description( span { - +vectorDateFormatter.formatMessageDay(DateProvider.toLocalDateTime(event.ageLocalTs)) + +vectorDateFormatter.formatMessageDayWithMonth(DateProvider.toLocalDateTime(event.ageLocalTs)) +" ${vectorDateFormatter.formatMessageHour(DateProvider.toLocalDateTime(event.ageLocalTs))}" span("\nfrom: ") { textStyle = "bold" From 0ff28c4f50bfae7cc6ff22864f0bd8d89358ebe4 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 31 Aug 2020 18:30:37 +0200 Subject: [PATCH 12/89] Date formatting: try to generalise usage of VectorDateFormatter and get proper formatting for Date + Time --- .../core/date/AbbrevDateFormatterProvider.kt | 6 +- .../im/vector/app/core/date/DateFormatKind.kt | 27 ++++ .../core/date/DefaultDateFormatterProvider.kt | 7 +- .../app/core/date/VectorDateFormatter.kt | 153 ++++++++++-------- .../vector/app/core/resources/DateProvider.kt | 6 +- .../DisplayReadReceiptsController.kt | 3 +- .../timeline/TimelineEventController.kt | 6 +- .../action/MessageActionsEpoxyController.kt | 6 +- .../ViewEditHistoryEpoxyController.kt | 13 +- .../helper/MessageInformationDataFactory.kt | 3 +- .../reactions/ViewReactionsViewModel.kt | 3 +- .../home/room/list/RoomSummaryItemFactory.kt | 9 +- .../media/DataAttachmentRoomProvider.kt | 5 +- .../media/RoomEventsAttachmentProvider.kt | 6 +- .../uploads/files/UploadsFileController.kt | 3 +- .../features/settings/devices/DeviceItem.kt | 13 +- .../settings/devices/DevicesController.kt | 8 +- .../GossipingEventsEpoxyController.kt | 5 +- 18 files changed, 159 insertions(+), 123 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/core/date/DateFormatKind.kt diff --git a/vector/src/main/java/im/vector/app/core/date/AbbrevDateFormatterProvider.kt b/vector/src/main/java/im/vector/app/core/date/AbbrevDateFormatterProvider.kt index 5108591344..e516be7e57 100644 --- a/vector/src/main/java/im/vector/app/core/date/AbbrevDateFormatterProvider.kt +++ b/vector/src/main/java/im/vector/app/core/date/AbbrevDateFormatterProvider.kt @@ -24,10 +24,12 @@ import javax.inject.Inject class AbbrevDateFormatterProvider @Inject constructor(private val localeProvider: LocaleProvider) : DateFormatterProvider { override val dateWithMonthFormatter: DateTimeFormatter by lazy { - DateTimeFormatter.ofPattern("d MMM", localeProvider.current()) + val pattern = DateFormat.getBestDateTimePattern(localeProvider.current(), "d MMM") + DateTimeFormatter.ofPattern(pattern, localeProvider.current()) } override val dateWithYearFormatter: DateTimeFormatter by lazy { - DateTimeFormatter.ofPattern("dd.MM.yyyy",localeProvider.current()) + val pattern = DateFormat.getBestDateTimePattern(localeProvider.current(), "dd.MM.yyyy") + DateTimeFormatter.ofPattern(pattern, localeProvider.current()) } } diff --git a/vector/src/main/java/im/vector/app/core/date/DateFormatKind.kt b/vector/src/main/java/im/vector/app/core/date/DateFormatKind.kt new file mode 100644 index 0000000000..3828b13089 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/date/DateFormatKind.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 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 im.vector.app.core.date + +enum class DateFormatKind { + DEFAULT_DATE_AND_TIME, + ROOM_LIST, + TIMELINE_DAY_DIVIDER, + MESSAGE_DETAIL, + MESSAGE_SIMPLE, + EDIT_HISTORY_ROW, + EDIT_HISTORY_HEADER +} diff --git a/vector/src/main/java/im/vector/app/core/date/DefaultDateFormatterProvider.kt b/vector/src/main/java/im/vector/app/core/date/DefaultDateFormatterProvider.kt index 7a0f671887..c8736f3ab1 100644 --- a/vector/src/main/java/im/vector/app/core/date/DefaultDateFormatterProvider.kt +++ b/vector/src/main/java/im/vector/app/core/date/DefaultDateFormatterProvider.kt @@ -27,11 +27,12 @@ class DefaultDateFormatterProvider @Inject constructor(private val context: Cont : DateFormatterProvider { override val dateWithMonthFormatter: DateTimeFormatter by lazy { - DateTimeFormatter.ofPattern(DateFormat.getBestDateTimePattern(localeProvider.current(), "d MMMMM")) + val pattern = DateFormat.getBestDateTimePattern(localeProvider.current(), "d MMMMM") + DateTimeFormatter.ofPattern(pattern) } override val dateWithYearFormatter: DateTimeFormatter by lazy { - DateTimeFormatter.ofPattern(DateFormat.getBestDateTimePattern(localeProvider.current(), "d MMM y")) + val pattern = DateFormat.getBestDateTimePattern(localeProvider.current(), "d MMM y") + DateTimeFormatter.ofPattern(pattern) } - } diff --git a/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt b/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt index 8b0de26a28..ecc1d7fe12 100644 --- a/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt +++ b/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt @@ -25,23 +25,8 @@ import im.vector.app.core.resources.toTimestamp import org.threeten.bp.LocalDateTime import org.threeten.bp.Period import org.threeten.bp.format.DateTimeFormatter -import java.util.Calendar -import java.util.Date import javax.inject.Inject - -/** - * Returns the timestamp for the start of the day of the provided time. - * For example, for the time "Jul 21, 11:11" the start of the day: "Jul 21, 00:00" is returned. - */ -fun startOfDay(time: Long): Long { - val calendar = Calendar.getInstance() - calendar.time = Date(time) - calendar.set(Calendar.HOUR_OF_DAY, 0) - calendar.set(Calendar.MINUTE, 0) - calendar.set(Calendar.SECOND, 0) - calendar.set(Calendar.MILLISECOND, 0) - return calendar.time.time -} +import kotlin.math.absoluteValue class VectorDateFormatter @Inject constructor(private val context: Context, private val localeProvider: LocaleProvider, @@ -55,38 +40,71 @@ class VectorDateFormatter @Inject constructor(private val context: Context, } } - private val dayFormatter by lazy { - DateTimeFormatter.ofPattern("EEE", localeProvider.current()) + private val fullDateFormatter by lazy { + val pattern = if (DateFormat.is24HourFormat(context)) { + DateFormat.getBestDateTimePattern(localeProvider.current(), "EEE, d MMM yyyy H:mm") + } else { + DateFormat.getBestDateTimePattern(localeProvider.current(), "EEE, d MMM yyyy h:mm a") + } + DateTimeFormatter.ofPattern(pattern, localeProvider.current()) } - private val fullDateFormatter by lazy { - if (DateFormat.is24HourFormat(context)) { - DateTimeFormatter.ofPattern("EEE, d MMM yyyy H:mm", localeProvider.current()) - } else { - DateTimeFormatter.ofPattern("EEE, d MMM yyyy h:mm a", localeProvider.current()) + /** + * This method is used to format some date in the app. + * It will be able to show only time, only date or both with some logic. + * @param ts the timestamp to format or null. + * @param dateFormatKind the kind of format to use + * + * @return the formatted date as string. + */ + fun format(ts: Long?, dateFormatKind: DateFormatKind): String { + if (ts == null) return "" + val localDateTime = DateProvider.toLocalDateTime(ts) + return when (dateFormatKind) { + DateFormatKind.DEFAULT_DATE_AND_TIME -> formatDateAndTime(ts) + DateFormatKind.ROOM_LIST -> formatTimeOrDate( + date = localDateTime, + showTimeIfSameDay = true, + abbrev = true, + useRelative = true + ) + DateFormatKind.TIMELINE_DAY_DIVIDER -> formatTimeOrDate( + date = localDateTime, + alwaysShowYear = true + ) + DateFormatKind.MESSAGE_DETAIL -> formatFullDate(localDateTime) + DateFormatKind.MESSAGE_SIMPLE -> formatHour(localDateTime) + DateFormatKind.EDIT_HISTORY_ROW -> formatHour(localDateTime) + DateFormatKind.EDIT_HISTORY_HEADER -> formatTimeOrDate( + date = localDateTime, + abbrev = true, + useRelative = true + ) } } - fun formatMessageHour(localDateTime: LocalDateTime): String { + private fun formatFullDate(localDateTime: LocalDateTime): String { + return fullDateFormatter.format(localDateTime) + } + + private fun formatHour(localDateTime: LocalDateTime): String { return hourFormatter.format(localDateTime) } - fun formatMessageDay(localDateTime: LocalDateTime): String { - return dayFormatter.format(localDateTime) - } - - fun formatMessageDayWithMonth(localDateTime: LocalDateTime, abbrev: Boolean = false): String { + private fun formatDateWithMonth(localDateTime: LocalDateTime, abbrev: Boolean = false): String { return dateFormatterProviders.provide(abbrev).dateWithMonthFormatter.format(localDateTime) } - fun formatMessageDayWithYear(localDateTime: LocalDateTime, abbrev: Boolean = false): String { + private fun formatDateWithYear(localDateTime: LocalDateTime, abbrev: Boolean = false): String { return dateFormatterProviders.provide(abbrev).dateWithYearFormatter.format(localDateTime) } - fun formatMessageDate( + /** + * This method will only show time or date following the parameters. + */ + private fun formatTimeOrDate( date: LocalDateTime?, - showFullDate: Boolean = false, - onlyTimeIfSameDay: Boolean = false, + showTimeIfSameDay: Boolean = false, useRelative: Boolean = false, alwaysShowYear: Boolean = false, abbrev: Boolean = false @@ -94,52 +112,49 @@ class VectorDateFormatter @Inject constructor(private val context: Context, if (date == null) { return "" } - if (showFullDate) { - return fullDateFormatter.format(date) - } val currentDate = DateProvider.currentLocalDateTime() val isSameDay = date.toLocalDate() == currentDate.toLocalDate() - return if (onlyTimeIfSameDay && isSameDay) { - formatMessageHour(date) + return if (showTimeIfSameDay && isSameDay) { + formatHour(date) } else { - val period = Period.between(date.toLocalDate(), currentDate.toLocalDate()) - if (period.years >= 1 || alwaysShowYear) { - formatMessageDayWithYear(date, abbrev) - } else if (period.months >= 1) { - formatMessageDayWithMonth(date, abbrev) - } else if (useRelative && period.days < 2) { - getRelativeDay(date.toTimestamp()) - } else if (useRelative && period.days < 7) { - formatMessageDay(date) - } else { - formatMessageDayWithMonth(date, abbrev) - } + formatDate(date, currentDate, alwaysShowYear, abbrev, useRelative) + } + } + + private fun formatDate( + date: LocalDateTime, + currentDate: LocalDateTime, + alwaysShowYear: Boolean, + abbrev: Boolean, + useRelative: Boolean + ): String { + val period = Period.between(date.toLocalDate(), currentDate.toLocalDate()) + return if (period.years.absoluteValue >= 1 || alwaysShowYear) { + formatDateWithYear(date, abbrev) + } else if (useRelative && period.days.absoluteValue < 2 && period.months.absoluteValue < 1) { + getRelativeDay(date.toTimestamp()) + } else { + formatDateWithMonth(date, abbrev) } } /** - * Formats a localized relative date time for the last 2 days, e.g, "Today, HH:MM", "Yesterday, HH:MM" or - * "2 days ago, HH:MM". - * For earlier timestamps the absolute date time is returned, e.g. "Month Day, HH:MM". - * - * @param time the absolute timestamp [ms] that should be formatted relative to now + * This method will show date and time with a preposition */ - fun formatRelativeDateTime(time: Long?): String { - if (time == null) { - return "" - } - val now = System.currentTimeMillis() - var flags = DateUtils.FORMAT_SHOW_WEEKDAY - - return DateUtils.getRelativeDateTimeString( - context, - time, - DateUtils.DAY_IN_MILLIS, - now - startOfDay(now - 2 * DateUtils.DAY_IN_MILLIS), - flags - ).toString() + private fun formatDateAndTime(ts: Long): String { + val date = DateProvider.toLocalDateTime(ts) + val currentDate = DateProvider.currentLocalDateTime() + // This fake date is created to be able to use getRelativeTimeSpanString so we can get a "at" + // preposition and the right am/pm management. + val fakeDate = LocalDateTime.of(currentDate.toLocalDate(), date.toLocalTime()) + val formattedTime = DateUtils.getRelativeTimeSpanString(context, fakeDate.toTimestamp(), true).toString() + val formattedDate = formatDate(date, currentDate, alwaysShowYear = false, abbrev = true, useRelative = true) + return "$formattedDate $formattedTime" } + /** + * We are using this method for the keywords Today/Yesterday + */ private fun getRelativeDay(ts: Long): String { return DateUtils.getRelativeTimeSpanString( ts, diff --git a/vector/src/main/java/im/vector/app/core/resources/DateProvider.kt b/vector/src/main/java/im/vector/app/core/resources/DateProvider.kt index 443a214259..2fce3e974a 100644 --- a/vector/src/main/java/im/vector/app/core/resources/DateProvider.kt +++ b/vector/src/main/java/im/vector/app/core/resources/DateProvider.kt @@ -19,12 +19,14 @@ package im.vector.app.core.resources import org.threeten.bp.Instant import org.threeten.bp.LocalDateTime import org.threeten.bp.ZoneId -import org.threeten.bp.ZoneOffset object DateProvider { private val zoneId = ZoneId.systemDefault() - private val zoneOffset = ZoneOffset.UTC + private val zoneOffset by lazy { + val now = currentLocalDateTime() + zoneId.rules.getOffset(now) + } fun toLocalDateTime(timestamp: Long?): LocalDateTime { val instant = Instant.ofEpochMilli(timestamp ?: 0) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsController.kt index 2094e7f8a9..d5133a7ea3 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsController.kt @@ -17,6 +17,7 @@ package im.vector.app.features.home.room.detail.readreceipts import com.airbnb.epoxy.TypedEpoxyController +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData @@ -36,7 +37,7 @@ class DisplayReadReceiptsController @Inject constructor(private val dateFormatte override fun buildModels(readReceipts: List) { readReceipts.forEach { - val timestamp = dateFormatter.formatRelativeDateTime(it.timestamp) + val timestamp = dateFormatter.format(it.timestamp, DateFormatKind.DEFAULT_DATE_AND_TIME) DisplayReadReceiptItem_() .id(it.userId) .matrixItem(it.toMatrixItem()) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt index c946bec074..f9635d4b85 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt @@ -25,6 +25,7 @@ import androidx.recyclerview.widget.RecyclerView import com.airbnb.epoxy.EpoxyController import com.airbnb.epoxy.EpoxyModel import com.airbnb.epoxy.VisibilityState +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.epoxy.LoadingItem_ import im.vector.app.core.extensions.localDateTime @@ -339,10 +340,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec private fun buildDaySeparatorItem(addDaySeparator: Boolean, originServerTs: Long?): DaySeparatorItem? { return if (addDaySeparator) { - val formattedDay = dateFormatter.formatMessageDate( - date = DateProvider.toLocalDateTime(originServerTs), - alwaysShowYear = true - ) + val formattedDay = dateFormatter.format(originServerTs, DateFormatKind.TIMELINE_DAY_DIVIDER) DaySeparatorItem_().formattedDay(formattedDay).id(formattedDay) } else { null diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt index 48ed73d980..cc3d5cc463 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt @@ -20,6 +20,7 @@ import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.mvrx.Success import im.vector.app.EmojiCompatFontProvider import im.vector.app.R +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.epoxy.bottomsheet.BottomSheetQuickReactionsItem import im.vector.app.core.epoxy.bottomsheet.bottomSheetActionItem @@ -27,7 +28,6 @@ import im.vector.app.core.epoxy.bottomsheet.bottomSheetMessagePreviewItem import im.vector.app.core.epoxy.bottomsheet.bottomSheetQuickReactionsItem import im.vector.app.core.epoxy.bottomsheet.bottomSheetSendStateItem import im.vector.app.core.epoxy.dividerItem -import im.vector.app.core.extensions.localDateTime import im.vector.app.core.resources.StringProvider import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.timeline.TimelineEventController @@ -50,8 +50,8 @@ class MessageActionsEpoxyController @Inject constructor( override fun buildModels(state: MessageActionState) { // Message preview - val date = state.timelineEvent()?.root?.localDateTime() - val formattedDate = dateFormatter.formatMessageDate(date, showFullDate = true) + val date = state.timelineEvent()?.root?.originServerTs + val formattedDate = dateFormatter.format(date, DateFormatKind.MESSAGE_DETAIL) bottomSheetMessagePreviewItem { id("preview") avatarRenderer(avatarRenderer) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt index 3db02adc0a..65ecdfa430 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt @@ -17,27 +17,26 @@ package im.vector.app.features.home.room.detail.timeline.edithistory import android.content.Context import android.text.Spannable -import android.text.format.DateUtils import androidx.core.content.ContextCompat import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Incomplete import com.airbnb.mvrx.Success import im.vector.app.R +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter -import im.vector.app.core.extensions.localDateTime import im.vector.app.core.ui.list.genericFooterItem import im.vector.app.core.ui.list.genericItem import im.vector.app.core.ui.list.genericItemHeader import im.vector.app.core.ui.list.genericLoaderItem import im.vector.app.features.html.EventHtmlRenderer +import me.gujun.android.span.span +import name.fraser.neil.plaintext.diff_match_patch import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent import org.matrix.android.sdk.api.util.ContentUtils.extractUsefulTextFromReply import org.matrix.android.sdk.internal.session.room.send.TextContent -import me.gujun.android.span.span -import name.fraser.neil.plaintext.diff_match_patch import java.util.Calendar /** @@ -82,11 +81,9 @@ class ViewEditHistoryEpoxyController(private val context: Context, } if (lastDate?.get(Calendar.DAY_OF_YEAR) != evDate.get(Calendar.DAY_OF_YEAR)) { // need to display header with day - val dateString = if (DateUtils.isToday(evDate.timeInMillis)) context.getString(R.string.today) - else dateFormatter.formatMessageDayWithMonth(timelineEvent.localDateTime()) genericItemHeader { id(evDate.hashCode()) - text(dateString) + text(dateFormatter.format(evDate.timeInMillis, DateFormatKind.EDIT_HISTORY_ROW)) } } lastDate = evDate @@ -130,7 +127,7 @@ class ViewEditHistoryEpoxyController(private val context: Context, } genericItem { id(timelineEvent.eventId) - title(dateFormatter.formatMessageHour(timelineEvent.localDateTime())) + title(dateFormatter.format(timelineEvent.originServerTs, DateFormatKind.EDIT_HISTORY_ROW)) description(spannedDiff ?: body) } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt index 49ac3ccfa9..e050889dbd 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt @@ -18,6 +18,7 @@ package im.vector.app.features.home.room.detail.timeline.helper +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.extensions.localDateTime import im.vector.app.core.resources.ColorProvider @@ -68,7 +69,7 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses || isNextMessageReceivedMoreThanOneHourAgo || isTileTypeMessage(nextEvent) - val time = dateFormatter.formatMessageHour(date) + val time = dateFormatter.format(event.root.originServerTs, DateFormatKind.MESSAGE_SIMPLE) val e2eDecoration = getE2EDecoration(event) return MessageInformationData( diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt index 29032ee5fa..a36f656f52 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt @@ -24,6 +24,7 @@ import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyViewEvents @@ -112,7 +113,7 @@ class ViewReactionsViewModel @AssistedInject constructor(@Assisted summary.key, event.root.senderId ?: "", event.senderInfo.disambiguatedDisplayName, - dateFormatter.formatRelativeDateTime(event.root.originServerTs) + dateFormatter.format(event.root.originServerTs, DateFormatKind.DEFAULT_DATE_AND_TIME) ) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt index 19561280a6..06cb0172d0 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt @@ -18,9 +18,9 @@ package im.vector.app.features.home.room.list import android.view.View import im.vector.app.R +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.epoxy.VectorEpoxyModel -import im.vector.app.core.extensions.localDateTime import im.vector.app.core.resources.StringProvider import im.vector.app.core.utils.DebouncedClickListener import im.vector.app.features.home.AvatarRenderer @@ -87,12 +87,7 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor val latestEvent = roomSummary.latestPreviewableEvent if (latestEvent != null) { latestFormattedEvent = displayableEventFormatter.format(latestEvent, roomSummary.isDirect.not()) - latestEventTime = dateFormatter.formatMessageDate( - date = latestEvent.root.localDateTime(), - useRelative = true, - onlyTimeIfSameDay = true, - abbrev = true - ) + latestEventTime = dateFormatter.format(latestEvent.root.originServerTs, DateFormatKind.ROOM_LIST) } val typingMessage = typingHelper.getTypingMessage(roomSummary.typingUsers) return RoomSummaryItem_() diff --git a/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt b/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt index 76305cb6bb..6209179961 100644 --- a/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt +++ b/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt @@ -19,6 +19,7 @@ package im.vector.app.features.media import android.content.Context import android.view.View import androidx.core.view.isVisible +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.extensions.localDateTime import im.vector.lib.attachmentviewer.AttachmentInfo @@ -78,9 +79,7 @@ class DataAttachmentRoomProvider( val item = attachments[position] val timeLineEvent = room?.getTimeLineEvent(item.eventId) if (timeLineEvent != null) { - val dateString = timeLineEvent.root.localDateTime().let { - "${dateFormatter.formatMessageDayWithMonth(it)} at ${dateFormatter.formatMessageHour(it)} " - } + val dateString = dateFormatter.format(timeLineEvent.root.originServerTs, DateFormatKind.DEFAULT_DATE_AND_TIME) overlayView?.updateWith("${position + 1} of ${attachments.size}", "${timeLineEvent.senderInfo.displayName} $dateString") overlayView?.videoControlsGroup?.isVisible = timeLineEvent.root.isVideoMessage() } else { diff --git a/vector/src/main/java/im/vector/app/features/media/RoomEventsAttachmentProvider.kt b/vector/src/main/java/im/vector/app/features/media/RoomEventsAttachmentProvider.kt index c06dd261e2..5c0c33d078 100644 --- a/vector/src/main/java/im/vector/app/features/media/RoomEventsAttachmentProvider.kt +++ b/vector/src/main/java/im/vector/app/features/media/RoomEventsAttachmentProvider.kt @@ -19,8 +19,8 @@ package im.vector.app.features.media import android.content.Context import android.view.View import androidx.core.view.isVisible +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter -import im.vector.app.core.extensions.localDateTime import im.vector.lib.attachmentviewer.AttachmentInfo import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.session.Session @@ -128,9 +128,7 @@ class RoomEventsAttachmentProvider( override fun overlayViewAtPosition(context: Context, position: Int): View? { super.overlayViewAtPosition(context, position) val item = attachments[position] - val dateString = item.root.localDateTime().let { - "${dateFormatter.formatMessageDayWithMonth(it)} at ${dateFormatter.formatMessageHour(it)} " - } + val dateString = dateFormatter.format(item.root.originServerTs, DateFormatKind.DEFAULT_DATE_AND_TIME) overlayView?.updateWith("${position + 1} of ${attachments.size}", "${item.senderInfo.displayName} $dateString") overlayView?.videoControlsGroup?.isVisible = item.root.isVideoMessage() return overlayView diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/files/UploadsFileController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/files/UploadsFileController.kt index 37b93ea902..f2c0ad2a9d 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/files/UploadsFileController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/files/UploadsFileController.kt @@ -19,6 +19,7 @@ package im.vector.app.features.roomprofile.uploads.files import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.epoxy.VisibilityState import im.vector.app.R +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.epoxy.loadingItem import im.vector.app.core.resources.StringProvider @@ -71,7 +72,7 @@ class UploadsFileController @Inject constructor( title(uploadEvent.contentWithAttachmentContent.body) subtitle(stringProvider.getString(R.string.uploads_files_subtitle, uploadEvent.senderInfo.disambiguatedDisplayName, - dateFormatter.formatRelativeDateTime(uploadEvent.root.originServerTs))) + dateFormatter.format(uploadEvent.root.originServerTs, DateFormatKind.DEFAULT_DATE_AND_TIME))) listener(object : UploadsFileItem.Listener { override fun onItemClicked() { listener?.onOpenClicked(uploadEvent) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceItem.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceItem.kt index 6025ea03b2..0b18b65314 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceItem.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceItem.kt @@ -45,6 +45,9 @@ abstract class DeviceItem : VectorEpoxyModel() { @EpoxyAttribute lateinit var deviceInfo: DeviceInfo + @EpoxyAttribute + var lastSeenFormatted: String? = null + @EpoxyAttribute var currentDevice = false @@ -105,15 +108,7 @@ abstract class DeviceItem : VectorEpoxyModel() { val lastSeenIp = deviceInfo.lastSeenIp?.takeIf { ip -> ip.isNotBlank() } ?: "-" - val lastSeenTime = deviceInfo.lastSeenTs?.let { ts -> - val dateFormatTime = SimpleDateFormat("HH:mm:ss", Locale.ROOT) - val date = Date(ts) - - val time = dateFormatTime.format(date) - val dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()) - - dateFormat.format(date) + ", " + time - } ?: "-" + val lastSeenTime = lastSeenFormatted ?: "-" holder.deviceLastSeenText.text = holder.root.context.getString(R.string.devices_details_last_seen_format, lastSeenIp, lastSeenTime) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesController.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesController.kt index 5d0c9fb1b0..ca2fea89d3 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesController.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesController.kt @@ -21,9 +21,9 @@ import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized -import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel -import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import im.vector.app.R +import im.vector.app.core.date.DateFormatKind +import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.epoxy.errorWithRetryItem import im.vector.app.core.epoxy.loadingItem import im.vector.app.core.error.ErrorFormatter @@ -32,11 +32,14 @@ import im.vector.app.core.resources.StringProvider import im.vector.app.core.ui.list.genericItemHeader import im.vector.app.core.utils.DimensionConverter import im.vector.app.features.settings.VectorPreferences +import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel +import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import javax.inject.Inject class DevicesController @Inject constructor(private val errorFormatter: ErrorFormatter, private val stringProvider: StringProvider, private val colorProvider: ColorProvider, + private val dateFormatter: VectorDateFormatter, private val dimensionConverter: DimensionConverter, private val vectorPreferences: VectorPreferences) : EpoxyController() { @@ -100,6 +103,7 @@ class DevicesController @Inject constructor(private val errorFormatter: ErrorFor deviceInfo(deviceInfo) currentDevice(true) e2eCapable(true) + lastSeenFormatted(dateFormatter.format(deviceInfo.lastSeenTs, DateFormatKind.DEFAULT_DATE_AND_TIME)) itemClickAction { callback?.onDeviceClicked(deviceInfo) } trusted(DeviceTrustLevel(currentSessionCrossTrusted, true)) } diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsEpoxyController.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsEpoxyController.kt index 69910bb100..66bf6d4ff4 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsEpoxyController.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsEpoxyController.kt @@ -31,11 +31,11 @@ import org.matrix.android.sdk.internal.crypto.model.rest.GossipingToDeviceObject import org.matrix.android.sdk.internal.crypto.model.rest.RoomKeyShareRequest import org.matrix.android.sdk.internal.crypto.model.rest.SecretShareRequest import im.vector.app.R +import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.epoxy.loadingItem import im.vector.app.core.extensions.exhaustive import im.vector.app.core.resources.ColorProvider -import im.vector.app.core.resources.DateProvider import im.vector.app.core.resources.StringProvider import im.vector.app.core.ui.list.GenericItem import im.vector.app.core.ui.list.genericFooterItem @@ -94,8 +94,7 @@ class GossipingEventsEpoxyController @Inject constructor( ) description( span { - +vectorDateFormatter.formatMessageDayWithMonth(DateProvider.toLocalDateTime(event.ageLocalTs)) - +" ${vectorDateFormatter.formatMessageHour(DateProvider.toLocalDateTime(event.ageLocalTs))}" + +vectorDateFormatter.format(event.ageLocalTs, DateFormatKind.DEFAULT_DATE_AND_TIME) span("\nfrom: ") { textStyle = "bold" } From c6178e504fc8a10e08d0979ba7cc5071fd7771b4 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 1 Sep 2020 11:01:32 +0200 Subject: [PATCH 13/89] Clean files and update CHANGES --- CHANGES.md | 2 +- tools/check/forbidden_strings_in_code.txt | 2 +- .../app/core/date/DateFormatterProvider.kt | 1 - .../app/core/date/VectorDateFormatter.kt | 6 ++--- .../vector/app/core/resources/DateProvider.kt | 1 - .../crypto/keysrequest/KeyRequestHandler.kt | 24 +++++++------------ .../timeline/TimelineEventController.kt | 1 - .../timeline/action/MessageActionState.kt | 4 ---- .../media/DataAttachmentRoomProvider.kt | 1 - .../app/features/settings/VectorLocale.kt | 3 ++- .../features/settings/devices/DeviceItem.kt | 4 ---- 11 files changed, 15 insertions(+), 34 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b1a93209bc..19104b3ed8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,7 +5,7 @@ Features ✨: - Improvements 🙌: - - + - Handle date formatting properly (show time am/pm if needed, display year when needed) Bugfix 🐛: - diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index b5438a0c5b..0a58175731 100644 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -164,7 +164,7 @@ Formatter\.formatShortFileSize===1 # android\.text\.TextUtils ### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If it is ok, change the value in file forbidden_strings_in_code.txt -enum class===76 +enum class===77 ### Do not import temporary legacy classes import org.matrix.android.sdk.internal.legacy.riot===3 diff --git a/vector/src/main/java/im/vector/app/core/date/DateFormatterProvider.kt b/vector/src/main/java/im/vector/app/core/date/DateFormatterProvider.kt index 0ca2eed2a6..ed1c2d828a 100644 --- a/vector/src/main/java/im/vector/app/core/date/DateFormatterProvider.kt +++ b/vector/src/main/java/im/vector/app/core/date/DateFormatterProvider.kt @@ -24,4 +24,3 @@ interface DateFormatterProvider { val dateWithYearFormatter: DateTimeFormatter } - diff --git a/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt b/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt index ecc1d7fe12..eb6f6a94f7 100644 --- a/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt +++ b/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt @@ -34,7 +34,7 @@ class VectorDateFormatter @Inject constructor(private val context: Context, private val hourFormatter by lazy { if (DateFormat.is24HourFormat(context)) { - DateTimeFormatter.ofPattern("H:mm", localeProvider.current()) + DateTimeFormatter.ofPattern("HH:mm", localeProvider.current()) } else { DateTimeFormatter.ofPattern("h:mm a", localeProvider.current()) } @@ -42,7 +42,7 @@ class VectorDateFormatter @Inject constructor(private val context: Context, private val fullDateFormatter by lazy { val pattern = if (DateFormat.is24HourFormat(context)) { - DateFormat.getBestDateTimePattern(localeProvider.current(), "EEE, d MMM yyyy H:mm") + DateFormat.getBestDateTimePattern(localeProvider.current(), "EEE, d MMM yyyy HH:mm") } else { DateFormat.getBestDateTimePattern(localeProvider.current(), "EEE, d MMM yyyy h:mm a") } @@ -58,7 +58,7 @@ class VectorDateFormatter @Inject constructor(private val context: Context, * @return the formatted date as string. */ fun format(ts: Long?, dateFormatKind: DateFormatKind): String { - if (ts == null) return "" + if (ts == null) return "-" val localDateTime = DateProvider.toLocalDateTime(ts) return when (dateFormatKind) { DateFormatKind.DEFAULT_DATE_AND_TIME -> formatDateAndTime(ts) diff --git a/vector/src/main/java/im/vector/app/core/resources/DateProvider.kt b/vector/src/main/java/im/vector/app/core/resources/DateProvider.kt index 2fce3e974a..30cb1dcae4 100644 --- a/vector/src/main/java/im/vector/app/core/resources/DateProvider.kt +++ b/vector/src/main/java/im/vector/app/core/resources/DateProvider.kt @@ -44,4 +44,3 @@ object DateProvider { } fun LocalDateTime.toTimestamp(): Long = DateProvider.toTimestamp(this) - diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysrequest/KeyRequestHandler.kt b/vector/src/main/java/im/vector/app/features/crypto/keysrequest/KeyRequestHandler.kt index 961cca4b70..4ed0e037d4 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysrequest/KeyRequestHandler.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysrequest/KeyRequestHandler.kt @@ -21,6 +21,8 @@ package im.vector.app.features.crypto.keysrequest import android.content.Context import im.vector.app.R +import im.vector.app.core.date.DateFormatKind +import im.vector.app.core.date.VectorDateFormatter import im.vector.app.features.popup.DefaultVectorAlert import im.vector.app.features.popup.PopupAlertManager import org.matrix.android.sdk.api.MatrixCallback @@ -38,10 +40,6 @@ import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import timber.log.Timber -import java.text.DateFormat -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale import javax.inject.Inject import javax.inject.Singleton @@ -54,8 +52,11 @@ import javax.inject.Singleton */ @Singleton -class KeyRequestHandler @Inject constructor(private val context: Context, private val popupAlertManager: PopupAlertManager) - : GossipingRequestListener, +class KeyRequestHandler @Inject constructor( + private val context: Context, + private val popupAlertManager: PopupAlertManager, + private val dateFormatter: VectorDateFormatter +) : GossipingRequestListener, VerificationService.Listener { private val alertsToRequests = HashMap>() @@ -156,16 +157,7 @@ class KeyRequestHandler @Inject constructor(private val context: Context, privat moreInfo.lastSeenIp } - val lastSeenTime = moreInfo.lastSeenTs?.let { ts -> - val dateFormatTime = SimpleDateFormat("HH:mm:ss", Locale.getDefault()) - val date = Date(ts) - - val time = dateFormatTime.format(date) - val dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()) - - dateFormat.format(date) + ", " + time - } ?: "-" - + val lastSeenTime = dateFormatter.format(moreInfo.lastSeenTs, DateFormatKind.DEFAULT_DATE_AND_TIME) val lastSeenInfo = context.getString(R.string.devices_details_last_seen_format, lastSeenIp, lastSeenTime) dialogText = if (wasNewDevice) { context.getString(R.string.you_added_a_new_device_with_info, deviceName, lastSeenInfo) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt index f9635d4b85..be59128c26 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt @@ -30,7 +30,6 @@ import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.epoxy.LoadingItem_ import im.vector.app.core.extensions.localDateTime import im.vector.app.core.extensions.nextOrNull -import im.vector.app.core.resources.DateProvider import im.vector.app.features.home.room.detail.RoomDetailAction import im.vector.app.features.home.room.detail.RoomDetailViewState import im.vector.app.features.home.room.detail.UnreadState diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionState.kt index 587400700d..83d56a65c9 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionState.kt @@ -22,10 +22,6 @@ import com.airbnb.mvrx.Uninitialized import im.vector.app.core.extensions.canReact import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent -import java.text.SimpleDateFormat -import java.time.LocalDateTime -import java.util.Date -import java.util.Locale /** * Quick reactions state diff --git a/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt b/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt index 6209179961..085153a721 100644 --- a/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt +++ b/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt @@ -21,7 +21,6 @@ import android.view.View import androidx.core.view.isVisible import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter -import im.vector.app.core.extensions.localDateTime import im.vector.lib.attachmentviewer.AttachmentInfo import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.session.events.model.isVideoMessage diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt b/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt index b9d81ab005..d0e4af4b97 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt @@ -22,6 +22,7 @@ import androidx.core.content.edit import androidx.preference.PreferenceManager import im.vector.app.BuildConfig import im.vector.app.R +import im.vector.app.core.resources.LocaleProvider import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import timber.log.Timber @@ -57,7 +58,7 @@ object VectorLocale { /** * Init this object */ - fun init(context: Context) { + fun init(context: Context, localeProvider: LocaleProvider) { this.context = context val preferences = PreferenceManager.getDefaultSharedPreferences(context) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceItem.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceItem.kt index 0b18b65314..7affdbf25b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceItem.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceItem.kt @@ -31,10 +31,6 @@ import im.vector.app.core.epoxy.VectorEpoxyModel import im.vector.app.core.resources.ColorProvider import im.vector.app.core.utils.DimensionConverter import me.gujun.android.span.span -import java.text.DateFormat -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale /** * A list item for Device. From 18dcd6b9b1d11183f004298ad53e5e1666b0cb98 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 7 Sep 2020 10:46:46 +0200 Subject: [PATCH 14/89] Date format: add more comments and fix wrong format kind usage --- .../im/vector/app/core/date/DateFormatKind.kt | 17 +++++++++++++++++ .../ViewEditHistoryEpoxyController.kt | 2 +- .../app/features/settings/VectorLocale.kt | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/date/DateFormatKind.kt b/vector/src/main/java/im/vector/app/core/date/DateFormatKind.kt index 3828b13089..b08a1dc725 100644 --- a/vector/src/main/java/im/vector/app/core/date/DateFormatKind.kt +++ b/vector/src/main/java/im/vector/app/core/date/DateFormatKind.kt @@ -16,12 +16,29 @@ package im.vector.app.core.date +/* This will represent all kind of available date formats for the app. + We will use the date Sep 7 2020 at 9:30am as an example. + The formatting is depending of the current date. + */ enum class DateFormatKind { + // Will show date relative and time (today or yesterday or Sep 7 or 09/07/2020 at 9:30am) DEFAULT_DATE_AND_TIME, + + // Will show hour or date relative (9:30am or yesterday or Sep 7 or 09/07/2020) ROOM_LIST, + + // Will show full date (Sep 7 2020) TIMELINE_DAY_DIVIDER, + + // Will show full date and time (Mon, Sep 7 2020, 9:30am) MESSAGE_DETAIL, + + // Will only show time (9:30am) MESSAGE_SIMPLE, + + // Will only show time (9:30am) EDIT_HISTORY_ROW, + + // Will only show date relative (today or yesterday or Sep 7 or 09/07/2020) EDIT_HISTORY_HEADER } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt index 65ecdfa430..c82dd70e54 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt @@ -83,7 +83,7 @@ class ViewEditHistoryEpoxyController(private val context: Context, // need to display header with day genericItemHeader { id(evDate.hashCode()) - text(dateFormatter.format(evDate.timeInMillis, DateFormatKind.EDIT_HISTORY_ROW)) + text(dateFormatter.format(evDate.timeInMillis, DateFormatKind.EDIT_HISTORY_HEADER)) } } lastDate = evDate diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt b/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt index d0e4af4b97..45667c1f77 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt @@ -58,7 +58,7 @@ object VectorLocale { /** * Init this object */ - fun init(context: Context, localeProvider: LocaleProvider) { + fun init(context: Context) { this.context = context val preferences = PreferenceManager.getDefaultSharedPreferences(context) From b97d922808ef9289914261f634ea343519f71252 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 9 Sep 2020 11:33:22 +0200 Subject: [PATCH 15/89] ktlint --- .../main/java/im/vector/app/features/settings/VectorLocale.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt b/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt index 45667c1f77..b9d81ab005 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt @@ -22,7 +22,6 @@ import androidx.core.content.edit import androidx.preference.PreferenceManager import im.vector.app.BuildConfig import im.vector.app.R -import im.vector.app.core.resources.LocaleProvider import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import timber.log.Timber From f1d902b9ad27a785112ba22f8f770796b472758d Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 1 Sep 2020 19:36:50 +0200 Subject: [PATCH 16/89] Enable strict mode and remove some stuff from the main thread --- .../internal/database/RealmInstanceWrapper.kt | 35 +++++++++ .../internal/database/RealmSessionProvider.kt | 72 +++++++++++++++++++ .../mapper/ReadReceiptsSummaryMapper.kt | 10 ++- .../sdk/internal/session/SessionModule.kt | 5 ++ .../sdk/internal/session/room/RoomGetter.kt | 11 ++- .../room/state/StateEventDataSource.kt | 14 ++-- .../session/room/timeline/DefaultTimeline.kt | 10 +-- .../room/timeline/DefaultTimelineService.kt | 26 +++---- .../internal/session/user/UserDataSource.kt | 15 ++-- .../user/accountdata/AccountDataDataSource.kt | 15 ++-- .../session/widgets/helper/WidgetFactory.kt | 10 ++- .../java/im/vector/app/VectorApplication.kt | 8 +++ .../app/core/glide/VectorGlideModelLoader.kt | 2 +- .../home/room/detail/RoomDetailViewModel.kt | 16 +++-- .../timeline/item/MessageImageVideoItem.kt | 2 +- .../features/media/ImageContentRenderer.kt | 10 ++- .../features/rageshake/VectorFileLogger.kt | 19 +++-- .../members/RoomMemberListViewModel.kt | 16 ++--- .../vector/app/features/themes/ThemeUtils.kt | 16 ++++- 19 files changed, 225 insertions(+), 87 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstanceWrapper.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionProvider.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstanceWrapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstanceWrapper.kt new file mode 100644 index 0000000000..851605437f --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstanceWrapper.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 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 org.matrix.android.sdk.internal.database + +import io.realm.Realm +import java.io.Closeable + +class RealmInstanceWrapper(private val realm: Realm, private val closeRealmOnClose: Boolean) : Closeable { + + override fun close() { + if (closeRealmOnClose) { + realm.close() + } + } + + fun withRealm(block: (Realm) -> R): R { + return use { + block(it.realm) + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionProvider.kt new file mode 100644 index 0000000000..a232d83b6d --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionProvider.kt @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 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 org.matrix.android.sdk.internal.database + +import android.os.Looper +import androidx.annotation.MainThread +import com.zhuinden.monarchy.Monarchy +import io.realm.Realm +import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.session.SessionLifecycleObserver +import org.matrix.android.sdk.internal.session.SessionScope +import javax.inject.Inject +import kotlin.concurrent.getOrSet + +/** + * This class keeps an instance of realm open in the main thread so you can grab it whenever you want to get a realm + * instance. This does check each time if you are on the main thread or not and returns the appropriate realm instance. + */ +@SessionScope +class RealmSessionProvider @Inject constructor(@SessionDatabase private val monarchy: Monarchy) + : SessionLifecycleObserver { + + private val realmThreadLocal = ThreadLocal() + + /** + * Allow you to execute a block with an opened realm. It automatically closes it if necessary (ie. when not in main thread) + */ + fun withRealm(block: (Realm) -> R): R { + return getRealmWrapper().withRealm(block) + } + + @MainThread + override fun onStart() { + realmThreadLocal.getOrSet { + Realm.getInstance(monarchy.realmConfiguration) + } + } + + @MainThread + override fun onStop() { + realmThreadLocal.get()?.close() + realmThreadLocal.remove() + } + + private fun getRealmWrapper(): RealmInstanceWrapper { + val isOnMainThread = isOnMainThread() + val realm = if (isOnMainThread) { + realmThreadLocal.getOrSet { + Realm.getInstance(monarchy.realmConfiguration) + } + } else { + Realm.getInstance(monarchy.realmConfiguration) + } + return RealmInstanceWrapper(realm, closeRealmOnClose = !isOnMainThread) + } + + private fun isOnMainThread() = Looper.myLooper() == Looper.getMainLooper() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/ReadReceiptsSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/ReadReceiptsSummaryMapper.kt index 188ca4937c..6b9c0e7a45 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/ReadReceiptsSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/ReadReceiptsSummaryMapper.kt @@ -18,26 +18,24 @@ package org.matrix.android.sdk.internal.database.mapper import org.matrix.android.sdk.api.session.room.model.ReadReceipt +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.model.ReadReceiptsSummaryEntity import org.matrix.android.sdk.internal.database.model.UserEntity import org.matrix.android.sdk.internal.database.query.where -import org.matrix.android.sdk.internal.di.SessionDatabase -import io.realm.Realm -import io.realm.RealmConfiguration import javax.inject.Inject -internal class ReadReceiptsSummaryMapper @Inject constructor(@SessionDatabase private val realmConfiguration: RealmConfiguration) { +internal class ReadReceiptsSummaryMapper @Inject constructor(private val realmSessionProvider: RealmSessionProvider) { fun map(readReceiptsSummaryEntity: ReadReceiptsSummaryEntity?): List { if (readReceiptsSummaryEntity == null) { return emptyList() } - return Realm.getInstance(realmConfiguration).use { realm -> + return realmSessionProvider.withRealm { realm -> val readReceipts = readReceiptsSummaryEntity.readReceipts readReceipts .mapNotNull { val user = UserEntity.where(realm, it.userId).findFirst() - ?: return@mapNotNull null + ?: return@mapNotNull null ReadReceipt(user.asDomain(), it.originServerTs.toLong()) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt index d404cecc51..e2042bfeac 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt @@ -47,6 +47,7 @@ import org.matrix.android.sdk.internal.crypto.secrets.DefaultSharedSecretStorage import org.matrix.android.sdk.internal.crypto.verification.VerificationMessageProcessor import org.matrix.android.sdk.internal.database.DatabaseCleaner import org.matrix.android.sdk.internal.database.EventInsertLiveObserver +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.SessionRealmConfigurationFactory import org.matrix.android.sdk.internal.di.Authenticated import org.matrix.android.sdk.internal.di.DeviceId @@ -343,6 +344,10 @@ internal abstract class SessionModule { @IntoSet abstract fun bindDatabaseCleaner(observer: DatabaseCleaner): SessionLifecycleObserver + @Binds + @IntoSet + abstract fun bindRealmSessionProvider(observer: RealmSessionProvider): SessionLifecycleObserver + @Binds abstract fun bindInitialSyncProgressService(service: DefaultInitialSyncProgressService): InitialSyncProgressService diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomGetter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomGetter.kt index 38dcad2311..985cf80e97 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomGetter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomGetter.kt @@ -17,17 +17,16 @@ package org.matrix.android.sdk.internal.session.room -import com.zhuinden.monarchy.Monarchy +import io.realm.Realm import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.model.RoomEntity import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields import org.matrix.android.sdk.internal.database.query.where -import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper -import io.realm.Realm import javax.inject.Inject internal interface RoomGetter { @@ -38,18 +37,18 @@ internal interface RoomGetter { @SessionScope internal class DefaultRoomGetter @Inject constructor( - @SessionDatabase private val monarchy: Monarchy, + private val realmSessionProvider: RealmSessionProvider, private val roomFactory: RoomFactory ) : RoomGetter { override fun getRoom(roomId: String): Room? { - return Realm.getInstance(monarchy.realmConfiguration).use { realm -> + return realmSessionProvider.withRealm { realm -> createRoom(realm, roomId) } } override fun getDirectRoomWith(otherUserId: String): Room? { - return Realm.getInstance(monarchy.realmConfiguration).use { realm -> + return realmSessionProvider.withRealm { realm -> RoomSummaryEntity.where(realm) .equalTo(RoomSummaryEntityFields.IS_DIRECT, true) .equalTo(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.JOIN.name) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt index e8dc2ddf40..65d30868d8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt @@ -20,24 +20,26 @@ package org.matrix.android.sdk.internal.session.room.state import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations import com.zhuinden.monarchy.Monarchy +import io.realm.Realm +import io.realm.RealmQuery +import io.realm.kotlin.where import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toOptional +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.mapper.asDomain import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.query.process -import io.realm.Realm -import io.realm.RealmQuery -import io.realm.kotlin.where import javax.inject.Inject -internal class StateEventDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy) { +internal class StateEventDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy, + private val realmSessionProvider: RealmSessionProvider) { fun getStateEvent(roomId: String, eventType: String, stateKey: QueryStringValue): Event? { - return Realm.getInstance(monarchy.realmConfiguration).use { realm -> + return realmSessionProvider.withRealm { realm -> buildStateEventQuery(realm, roomId, setOf(eventType), stateKey).findFirst()?.root?.asDomain() } } @@ -53,7 +55,7 @@ internal class StateEventDataSource @Inject constructor(@SessionDatabase private } fun getStateEvents(roomId: String, eventTypes: Set, stateKey: QueryStringValue): List { - return Realm.getInstance(monarchy.realmConfiguration).use { realm -> + return realmSessionProvider.withRealm { realm -> buildStateEventQuery(realm, roomId, eventTypes, stateKey) .findAll() .mapNotNull { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt index 421cd1b063..52651af881 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt @@ -39,6 +39,7 @@ import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.api.util.CancelableBag +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper import org.matrix.android.sdk.internal.database.model.ChunkEntity import org.matrix.android.sdk.internal.database.model.ChunkEntityFields @@ -76,7 +77,8 @@ internal class DefaultTimeline( private val settings: TimelineSettings, private val hiddenReadReceipts: TimelineHiddenReadReceipts, private val eventBus: EventBus, - private val eventDecryptor: TimelineEventDecryptor + private val eventDecryptor: TimelineEventDecryptor, + private val realmSessionProvider: RealmSessionProvider ) : Timeline, TimelineHiddenReadReceipts.Delegate { data class OnNewTimelineEvents(val roomId: String, val eventIds: List) @@ -136,13 +138,13 @@ internal class DefaultTimeline( } override fun pendingEventCount(): Int { - return Realm.getInstance(realmConfiguration).use { + return realmSessionProvider.withRealm { RoomEntity.where(it, roomId).findFirst()?.sendingTimelineEvents?.count() ?: 0 } } override fun failedToDeliverEventCount(): Int { - return Realm.getInstance(realmConfiguration).use { + return realmSessionProvider.withRealm { TimelineEventEntity.findAllInRoomWithSendStates(it, roomId, SendState.HAS_FAILED_STATES).count() } } @@ -239,7 +241,7 @@ internal class DefaultTimeline( return eventId } // Otherwise, we should check if the event is in the db, but is hidden because of filters - return Realm.getInstance(realmConfiguration).use { localRealm -> + return realmSessionProvider.withRealm { localRealm -> val nonFilteredEvents = buildEventQuery(localRealm) .sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING) .findAll() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt index db675f69f5..c60a944409 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt @@ -22,6 +22,9 @@ import androidx.lifecycle.Transformations import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import com.zhuinden.monarchy.Monarchy +import io.realm.Sort +import io.realm.kotlin.where +import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.events.model.isImageMessage import org.matrix.android.sdk.api.session.events.model.isVideoMessage import org.matrix.android.sdk.api.session.room.timeline.Timeline @@ -30,7 +33,7 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineService import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toOptional -import org.matrix.android.sdk.internal.crypto.store.db.doWithRealm +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.mapper.ReadReceiptsSummaryMapper import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper import org.matrix.android.sdk.internal.database.model.TimelineEventEntity @@ -38,13 +41,10 @@ import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.task.TaskExecutor -import org.matrix.android.sdk.internal.util.fetchCopyMap -import io.realm.Sort -import io.realm.kotlin.where -import org.greenrobot.eventbus.EventBus internal class DefaultTimelineService @AssistedInject constructor(@Assisted private val roomId: String, @SessionDatabase private val monarchy: Monarchy, + private val realmSessionProvider: RealmSessionProvider, private val eventBus: EventBus, private val taskExecutor: TaskExecutor, private val contextOfEventTask: GetContextOfEventTask, @@ -73,17 +73,17 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv hiddenReadReceipts = TimelineHiddenReadReceipts(readReceiptsSummaryMapper, roomId, settings), eventBus = eventBus, eventDecryptor = eventDecryptor, - fetchTokenAndPaginateTask = fetchTokenAndPaginateTask + fetchTokenAndPaginateTask = fetchTokenAndPaginateTask, + realmSessionProvider = realmSessionProvider ) } override fun getTimeLineEvent(eventId: String): TimelineEvent? { - return monarchy - .fetchCopyMap({ - TimelineEventEntity.where(it, roomId = roomId, eventId = eventId).findFirst() - }, { entity, _ -> - timelineEventMapper.map(entity) - }) + return realmSessionProvider.withRealm { realm -> + TimelineEventEntity.where(realm, roomId = roomId, eventId = eventId).findFirst()?.let { + timelineEventMapper.map(it) + } + } } override fun getTimeLineEventLive(eventId: String): LiveData> { @@ -98,7 +98,7 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv override fun getAttachmentMessages(): List { // TODO pretty bad query.. maybe we should denormalize clear type in base? - return doWithRealm(monarchy.realmConfiguration) { realm -> + return realmSessionProvider.withRealm { realm -> realm.where() .equalTo(TimelineEventEntityFields.ROOM_ID, roomId) .sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.ASCENDING) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserDataSource.kt index dd3c6856c0..f6cb86c0ed 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserDataSource.kt @@ -23,9 +23,11 @@ import androidx.paging.DataSource import androidx.paging.LivePagedListBuilder import androidx.paging.PagedList import com.zhuinden.monarchy.Monarchy +import io.realm.Case import org.matrix.android.sdk.api.session.user.model.User import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toOptional +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.mapper.asDomain import org.matrix.android.sdk.internal.database.model.IgnoredUserEntity import org.matrix.android.sdk.internal.database.model.IgnoredUserEntityFields @@ -33,11 +35,10 @@ import org.matrix.android.sdk.internal.database.model.UserEntity import org.matrix.android.sdk.internal.database.model.UserEntityFields import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase -import org.matrix.android.sdk.internal.util.fetchCopied -import io.realm.Case import javax.inject.Inject -internal class UserDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy) { +internal class UserDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy, + private val realmSessionProvider: RealmSessionProvider) { private val realmDataSourceFactory: Monarchy.RealmDataSourceFactory by lazy { monarchy.createDataSourceFactory { realm -> @@ -58,10 +59,10 @@ internal class UserDataSource @Inject constructor(@SessionDatabase private val m } fun getUser(userId: String): User? { - val userEntity = monarchy.fetchCopied { UserEntity.where(it, userId).findFirst() } - ?: return null - - return userEntity.asDomain() + return realmSessionProvider.withRealm { + val userEntity = UserEntity.where(it, userId).findFirst() + userEntity?.asDomain() + } } fun getUserLive(userId: String): LiveData> { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataDataSource.kt index d54bfdd63d..a9261eddab 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataDataSource.kt @@ -20,18 +20,20 @@ package org.matrix.android.sdk.internal.session.user.accountdata import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations import com.zhuinden.monarchy.Monarchy +import io.realm.Realm +import io.realm.RealmQuery +import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toOptional +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.mapper.AccountDataMapper import org.matrix.android.sdk.internal.database.model.UserAccountDataEntity import org.matrix.android.sdk.internal.database.model.UserAccountDataEntityFields import org.matrix.android.sdk.internal.di.SessionDatabase -import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent -import io.realm.Realm -import io.realm.RealmQuery import javax.inject.Inject internal class AccountDataDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy, + private val realmSessionProvider: RealmSessionProvider, private val accountDataMapper: AccountDataMapper) { fun getAccountDataEvent(type: String): UserAccountDataEvent? { @@ -45,10 +47,9 @@ internal class AccountDataDataSource @Inject constructor(@SessionDatabase privat } fun getAccountDataEvents(types: Set): List { - return monarchy.fetchAllMappedSync( - { accountDataEventsQuery(it, types) }, - accountDataMapper::map - ) + return realmSessionProvider.withRealm { + accountDataEventsQuery(it, types).findAll().map(accountDataMapper::map) + } } fun getLiveAccountDataEvents(types: Set): LiveData> { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt index 2cbc9b23dc..992dbf16df 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt @@ -23,17 +23,15 @@ import org.matrix.android.sdk.api.session.room.sender.SenderInfo import org.matrix.android.sdk.api.session.widgets.model.Widget import org.matrix.android.sdk.api.session.widgets.model.WidgetContent import org.matrix.android.sdk.api.session.widgets.model.WidgetType -import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper import org.matrix.android.sdk.internal.session.user.UserDataSource -import io.realm.Realm -import io.realm.RealmConfiguration import java.net.URLEncoder import javax.inject.Inject -internal class WidgetFactory @Inject constructor(@SessionDatabase private val realmConfiguration: RealmConfiguration, - private val userDataSource: UserDataSource, +internal class WidgetFactory @Inject constructor(private val userDataSource: UserDataSource, + private val realmSessionProvider: RealmSessionProvider, @UserId private val userId: String) { fun create(widgetEvent: Event): Widget? { @@ -44,7 +42,7 @@ internal class WidgetFactory @Inject constructor(@SessionDatabase private val re val senderInfo = if (widgetEvent.senderId == null || widgetEvent.roomId == null) { null } else { - Realm.getInstance(realmConfiguration).use { + realmSessionProvider.withRealm { val roomMemberHelper = RoomMemberHelper(it, widgetEvent.roomId) val roomMemberSummaryEntity = roomMemberHelper.getLastRoomMember(widgetEvent.senderId) SenderInfo( diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index f64ebf9245..bca0a028e9 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -21,6 +21,7 @@ import android.content.Context import android.content.res.Configuration import android.os.Handler import android.os.HandlerThread +import android.os.StrictMode import androidx.core.provider.FontRequest import androidx.core.provider.FontsContractCompat import androidx.lifecycle.Lifecycle @@ -92,6 +93,13 @@ class VectorApplication : private var fontThreadHandler: Handler? = null override fun onCreate() { + if (BuildConfig.DEBUG) { + StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder() + .detectAll() + .penaltyFlashScreen() + .penaltyLog() + .build()) + } super.onCreate() appContext = this vectorComponent = DaggerVectorComponent.factory().create(this) diff --git a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt index 2a17c2ca1b..0eba78dbf8 100644 --- a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt +++ b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt @@ -100,7 +100,7 @@ class VectorGlideDataFetcher(private val activeSessionHolder: ActiveSessionHolde override fun loadData(priority: Priority, callback: DataFetcher.DataCallback) { Timber.v("Load data: $data") - if (data.isLocalFile() && data.url != null) { + if (data.isLocalFile && data.url != null) { val initialFile = File(data.url) callback.onDataReady(initialFile.inputStream()) return diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index eab0007080..a77d50d767 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -896,13 +896,15 @@ class RoomDetailViewModel @AssistedInject constructor( } private fun handleEventVisible(action: RoomDetailAction.TimelineEventTurnsVisible) { - if (action.event.root.sendState.isSent()) { // ignore pending/local events - visibleEventsObservable.accept(action) - } - // We need to update this with the related m.replace also (to move read receipt) - action.event.annotations?.editSummary?.sourceEvents?.forEach { - room.getTimeLineEvent(it)?.let { event -> - visibleEventsObservable.accept(RoomDetailAction.TimelineEventTurnsVisible(event)) + viewModelScope.launch(Dispatchers.Default) { + if (action.event.root.sendState.isSent()) { // ignore pending/local events + visibleEventsObservable.accept(action) + } + // We need to update this with the related m.replace also (to move read receipt) + action.event.annotations?.editSummary?.sourceEvents?.forEach { + room.getTimeLineEvent(it)?.let { event -> + visibleEventsObservable.accept(RoomDetailAction.TimelineEventTurnsVisible(event)) + } } } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt index 9ada087207..ffc51f671f 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt @@ -50,7 +50,7 @@ abstract class MessageImageVideoItem : AbsMessageItem(null) + private val mColorByAttr = HashMap() // init the theme @@ -68,8 +71,16 @@ object ThemeUtils { * @return the selected application theme */ fun getApplicationTheme(context: Context): String { - return PreferenceManager.getDefaultSharedPreferences(context) - .getString(APPLICATION_THEME_KEY, THEME_LIGHT_VALUE) ?: THEME_LIGHT_VALUE + val currentTheme = this.currentTheme.get() + return if (currentTheme == null) { + val themeFromPref = PreferenceManager + .getDefaultSharedPreferences(context) + .getString(APPLICATION_THEME_KEY, THEME_LIGHT_VALUE) ?: THEME_LIGHT_VALUE + this.currentTheme.set(themeFromPref) + themeFromPref + } else { + currentTheme + } } /** @@ -78,6 +89,7 @@ object ThemeUtils { * @param aTheme the new theme */ fun setApplicationTheme(context: Context, aTheme: String) { + currentTheme.set(aTheme) when (aTheme) { THEME_DARK_VALUE -> context.setTheme(R.style.AppTheme_Dark) THEME_BLACK_VALUE -> context.setTheme(R.style.AppTheme_Black) From fa381cc06d4d25faef2ad01279fb818265b4778a Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 8 Sep 2020 12:53:08 +0200 Subject: [PATCH 17/89] Use a singleton for default shared pref --- .../im/vector/app/receivers/DebugReceiver.kt | 6 ++-- .../java/im/vector/app/push/fcm/FcmHelper.kt | 6 ++-- .../app/core/di/DefaultSharedPreferences.kt | 31 +++++++++++++++++++ .../app/core/ui/views/KeysBackupBanner.kt | 18 +++++------ .../im/vector/app/core/utils/RingtoneUtils.kt | 10 +++--- .../features/disclaimer/DisclaimerDialog.kt | 6 ++-- .../homeserver/ServerUrlsRepository.kt | 8 ++--- .../VectorUncaughtExceptionHandler.kt | 8 ++--- .../vector/app/features/settings/FontScale.kt | 6 ++-- .../app/features/settings/VectorLocale.kt | 6 ++-- .../features/settings/VectorPreferences.kt | 4 +-- .../vector/app/features/themes/ThemeUtils.kt | 5 ++- 12 files changed, 72 insertions(+), 42 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/core/di/DefaultSharedPreferences.kt diff --git a/vector/src/debug/java/im/vector/app/receivers/DebugReceiver.kt b/vector/src/debug/java/im/vector/app/receivers/DebugReceiver.kt index 7b64bed08e..0cea9e3d8e 100644 --- a/vector/src/debug/java/im/vector/app/receivers/DebugReceiver.kt +++ b/vector/src/debug/java/im/vector/app/receivers/DebugReceiver.kt @@ -22,7 +22,7 @@ import android.content.Intent import android.content.IntentFilter import android.content.SharedPreferences import androidx.core.content.edit -import androidx.preference.PreferenceManager +import im.vector.app.core.di.DefaultSharedPreferences import im.vector.app.core.utils.lsFiles import timber.log.Timber @@ -44,7 +44,7 @@ class DebugReceiver : BroadcastReceiver() { } private fun dumpPreferences(context: Context) { - logPrefs("DefaultSharedPreferences", PreferenceManager.getDefaultSharedPreferences(context)) + logPrefs("DefaultSharedPreferences", DefaultSharedPreferences.getInstance(context)) } private fun logPrefs(name: String, sharedPreferences: SharedPreferences?) { @@ -58,7 +58,7 @@ class DebugReceiver : BroadcastReceiver() { } private fun alterScalarToken(context: Context) { - PreferenceManager.getDefaultSharedPreferences(context).edit { + DefaultSharedPreferences.getInstance(context).edit { // putString("SCALAR_TOKEN_PREFERENCE_KEY" + Matrix.getInstance(context).defaultSession.myUserId, "bad_token") } } diff --git a/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt b/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt index 6c68d6c3b5..84ca392c45 100755 --- a/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt +++ b/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt @@ -19,7 +19,6 @@ package im.vector.app.push.fcm import android.app.Activity import android.content.Context -import androidx.preference.PreferenceManager import android.widget.Toast import androidx.core.content.edit import com.google.android.gms.common.ConnectionResult @@ -27,6 +26,7 @@ import com.google.android.gms.common.GoogleApiAvailability import com.google.firebase.iid.FirebaseInstanceId import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.core.di.DefaultSharedPreferences import im.vector.app.core.pushers.PushersManager import im.vector.app.features.settings.VectorPreferences import timber.log.Timber @@ -46,7 +46,7 @@ object FcmHelper { * @return the FCM token or null if not received from FCM */ fun getFcmToken(context: Context): String? { - return PreferenceManager.getDefaultSharedPreferences(context).getString(PREFS_KEY_FCM_TOKEN, null) + return DefaultSharedPreferences.getInstance(context).getString(PREFS_KEY_FCM_TOKEN, null) } /** @@ -58,7 +58,7 @@ object FcmHelper { */ fun storeFcmToken(context: Context, token: String?) { - PreferenceManager.getDefaultSharedPreferences(context).edit { + DefaultSharedPreferences.getInstance(context).edit { putString(PREFS_KEY_FCM_TOKEN, token) } } diff --git a/vector/src/main/java/im/vector/app/core/di/DefaultSharedPreferences.kt b/vector/src/main/java/im/vector/app/core/di/DefaultSharedPreferences.kt new file mode 100644 index 0000000000..745af3e16c --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/di/DefaultSharedPreferences.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020 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 im.vector.app.core.di + +import android.content.Context +import android.content.SharedPreferences +import androidx.preference.PreferenceManager + +object DefaultSharedPreferences { + + @Volatile private var INSTANCE: SharedPreferences? = null + + fun getInstance(context: Context): SharedPreferences = + INSTANCE ?: synchronized(this) { + INSTANCE ?: PreferenceManager.getDefaultSharedPreferences(context).also { INSTANCE = it } + } +} diff --git a/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt b/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt index 14d9261204..f4890780b5 100755 --- a/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt @@ -23,11 +23,11 @@ import android.widget.TextView import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.edit import androidx.core.view.isVisible -import androidx.preference.PreferenceManager import butterknife.BindView import butterknife.ButterKnife import butterknife.OnClick import im.vector.app.R +import im.vector.app.core.di.DefaultSharedPreferences import timber.log.Timber /** @@ -57,7 +57,7 @@ class KeysBackupBanner @JvmOverloads constructor( init { setupView() - PreferenceManager.getDefaultSharedPreferences(context).edit { + DefaultSharedPreferences.getInstance(context).edit { putBoolean(BANNER_SETUP_DO_NOT_SHOW_AGAIN, false) putString(BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION, "") } @@ -105,17 +105,17 @@ class KeysBackupBanner @JvmOverloads constructor( state.let { when (it) { is State.Setup -> { - PreferenceManager.getDefaultSharedPreferences(context).edit { + DefaultSharedPreferences.getInstance(context).edit { putBoolean(BANNER_SETUP_DO_NOT_SHOW_AGAIN, true) } } is State.Recover -> { - PreferenceManager.getDefaultSharedPreferences(context).edit { + DefaultSharedPreferences.getInstance(context).edit { putString(BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION, it.version) } } is State.Update -> { - PreferenceManager.getDefaultSharedPreferences(context).edit { + DefaultSharedPreferences.getInstance(context).edit { putString(BANNER_UPDATE_DO_NOT_SHOW_FOR_VERSION, it.version) } } @@ -150,7 +150,7 @@ class KeysBackupBanner @JvmOverloads constructor( private fun renderSetup(nbOfKeys: Int) { if (nbOfKeys == 0 - || PreferenceManager.getDefaultSharedPreferences(context).getBoolean(BANNER_SETUP_DO_NOT_SHOW_AGAIN, false)) { + || DefaultSharedPreferences.getInstance(context).getBoolean(BANNER_SETUP_DO_NOT_SHOW_AGAIN, false)) { // Do not display the setup banner if there is no keys to backup, or if the user has already closed it isVisible = false } else { @@ -164,7 +164,7 @@ class KeysBackupBanner @JvmOverloads constructor( } private fun renderRecover(version: String) { - if (version == PreferenceManager.getDefaultSharedPreferences(context).getString(BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION, null)) { + if (version == DefaultSharedPreferences.getInstance(context).getString(BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION, null)) { isVisible = false } else { isVisible = true @@ -177,7 +177,7 @@ class KeysBackupBanner @JvmOverloads constructor( } private fun renderUpdate(version: String) { - if (version == PreferenceManager.getDefaultSharedPreferences(context).getString(BANNER_UPDATE_DO_NOT_SHOW_FOR_VERSION, null)) { + if (version == DefaultSharedPreferences.getInstance(context).getString(BANNER_UPDATE_DO_NOT_SHOW_FOR_VERSION, null)) { isVisible = false } else { isVisible = true @@ -258,7 +258,7 @@ class KeysBackupBanner @JvmOverloads constructor( * Inform the banner that a Recover has been done for this version, so do not show the Recover banner for this version */ fun onRecoverDoneForVersion(context: Context, version: String) { - PreferenceManager.getDefaultSharedPreferences(context).edit { + DefaultSharedPreferences.getInstance(context).edit { putString(BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION, version) } } diff --git a/vector/src/main/java/im/vector/app/core/utils/RingtoneUtils.kt b/vector/src/main/java/im/vector/app/core/utils/RingtoneUtils.kt index 82b8c3a51a..9b84ea7b2f 100644 --- a/vector/src/main/java/im/vector/app/core/utils/RingtoneUtils.kt +++ b/vector/src/main/java/im/vector/app/core/utils/RingtoneUtils.kt @@ -21,7 +21,7 @@ import android.media.Ringtone import android.media.RingtoneManager import android.net.Uri import androidx.core.content.edit -import androidx.preference.PreferenceManager +import im.vector.app.core.di.DefaultSharedPreferences import im.vector.app.features.settings.VectorPreferences /** @@ -40,7 +40,7 @@ import im.vector.app.features.settings.VectorPreferences * @see Ringtone */ fun getCallRingtoneUri(context: Context): Uri? { - val callRingtone: String? = PreferenceManager.getDefaultSharedPreferences(context) + val callRingtone: String? = DefaultSharedPreferences.getInstance(context) .getString(VectorPreferences.SETTINGS_CALL_RINGTONE_URI_PREFERENCE_KEY, null) callRingtone?.let { @@ -94,7 +94,7 @@ fun getCallRingtoneName(context: Context): String? { * @see Ringtone */ fun setCallRingtoneUri(context: Context, ringtoneUri: Uri) { - PreferenceManager.getDefaultSharedPreferences(context) + DefaultSharedPreferences.getInstance(context) .edit { putString(VectorPreferences.SETTINGS_CALL_RINGTONE_URI_PREFERENCE_KEY, ringtoneUri.toString()) } @@ -104,14 +104,14 @@ fun setCallRingtoneUri(context: Context, ringtoneUri: Uri) { * Set using Riot default ringtone */ fun useRiotDefaultRingtone(context: Context): Boolean { - return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(VectorPreferences.SETTINGS_CALL_RINGTONE_USE_RIOT_PREFERENCE_KEY, true) + return DefaultSharedPreferences.getInstance(context).getBoolean(VectorPreferences.SETTINGS_CALL_RINGTONE_USE_RIOT_PREFERENCE_KEY, true) } /** * Ask if default Riot ringtone has to be used */ fun setUseRiotDefaultRingtone(context: Context, useRiotDefault: Boolean) { - PreferenceManager.getDefaultSharedPreferences(context) + DefaultSharedPreferences.getInstance(context) .edit { putBoolean(VectorPreferences.SETTINGS_CALL_RINGTONE_USE_RIOT_PREFERENCE_KEY, useRiotDefault) } diff --git a/vector/src/main/java/im/vector/app/features/disclaimer/DisclaimerDialog.kt b/vector/src/main/java/im/vector/app/features/disclaimer/DisclaimerDialog.kt index b9568e0b62..c2cd2e11e3 100644 --- a/vector/src/main/java/im/vector/app/features/disclaimer/DisclaimerDialog.kt +++ b/vector/src/main/java/im/vector/app/features/disclaimer/DisclaimerDialog.kt @@ -20,8 +20,8 @@ import android.app.Activity import android.content.Context import androidx.appcompat.app.AlertDialog import androidx.core.content.edit -import androidx.preference.PreferenceManager import im.vector.app.R +import im.vector.app.core.di.DefaultSharedPreferences import im.vector.app.core.utils.openUrlInChromeCustomTab import im.vector.app.features.settings.VectorSettingsUrls @@ -31,7 +31,7 @@ private const val CURRENT_DISCLAIMER_VALUE = 2 private const val SHARED_PREF_KEY = "LAST_DISCLAIMER_VERSION_VALUE" fun showDisclaimerDialog(activity: Activity) { - val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(activity) + val sharedPrefs = DefaultSharedPreferences.getInstance(activity) if (sharedPrefs.getInt(SHARED_PREF_KEY, 0) < CURRENT_DISCLAIMER_VALUE) { sharedPrefs.edit { @@ -52,7 +52,7 @@ fun showDisclaimerDialog(activity: Activity) { } fun doNotShowDisclaimerDialog(context: Context) { - val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context) + val sharedPrefs = DefaultSharedPreferences.getInstance(context) sharedPrefs.edit { putInt(SHARED_PREF_KEY, CURRENT_DISCLAIMER_VALUE) diff --git a/vector/src/main/java/im/vector/app/features/homeserver/ServerUrlsRepository.kt b/vector/src/main/java/im/vector/app/features/homeserver/ServerUrlsRepository.kt index 683dea43b0..094fc4b3bb 100644 --- a/vector/src/main/java/im/vector/app/features/homeserver/ServerUrlsRepository.kt +++ b/vector/src/main/java/im/vector/app/features/homeserver/ServerUrlsRepository.kt @@ -18,8 +18,8 @@ package im.vector.app.features.homeserver import android.content.Context import androidx.core.content.edit -import androidx.preference.PreferenceManager import im.vector.app.R +import im.vector.app.core.di.DefaultSharedPreferences /** * Object to store and retrieve home and identity server urls @@ -38,7 +38,7 @@ object ServerUrlsRepository { * Save home and identity sever urls received by the Referrer receiver */ fun setDefaultUrlsFromReferrer(context: Context, homeServerUrl: String, identityServerUrl: String) { - PreferenceManager.getDefaultSharedPreferences(context) + DefaultSharedPreferences.getInstance(context) .edit { if (homeServerUrl.isNotEmpty()) { putString(DEFAULT_REFERRER_HOME_SERVER_URL_PREF, homeServerUrl) @@ -54,7 +54,7 @@ object ServerUrlsRepository { * Save home and identity sever urls entered by the user. May be custom or default value */ fun saveServerUrls(context: Context, homeServerUrl: String, identityServerUrl: String) { - PreferenceManager.getDefaultSharedPreferences(context) + DefaultSharedPreferences.getInstance(context) .edit { putString(HOME_SERVER_URL_PREF, homeServerUrl) putString(IDENTITY_SERVER_URL_PREF, identityServerUrl) @@ -65,7 +65,7 @@ object ServerUrlsRepository { * Return last used home server url, or the default one from referrer or the default one from resources */ fun getLastHomeServerUrl(context: Context): String { - val prefs = PreferenceManager.getDefaultSharedPreferences(context) + val prefs = DefaultSharedPreferences.getInstance(context) return prefs.getString(HOME_SERVER_URL_PREF, prefs.getString(DEFAULT_REFERRER_HOME_SERVER_URL_PREF, diff --git a/vector/src/main/java/im/vector/app/features/rageshake/VectorUncaughtExceptionHandler.kt b/vector/src/main/java/im/vector/app/features/rageshake/VectorUncaughtExceptionHandler.kt index 53f10e5d54..6954b9c87b 100644 --- a/vector/src/main/java/im/vector/app/features/rageshake/VectorUncaughtExceptionHandler.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/VectorUncaughtExceptionHandler.kt @@ -19,7 +19,7 @@ package im.vector.app.features.rageshake import android.content.Context import android.os.Build import androidx.core.content.edit -import androidx.preference.PreferenceManager +import im.vector.app.core.di.DefaultSharedPreferences import im.vector.app.core.resources.VersionCodeProvider import im.vector.app.features.version.VersionProvider import org.matrix.android.sdk.api.Matrix @@ -61,7 +61,7 @@ class VectorUncaughtExceptionHandler @Inject constructor(private val bugReporter */ override fun uncaughtException(thread: Thread, throwable: Throwable) { Timber.v("Uncaught exception: $throwable") - PreferenceManager.getDefaultSharedPreferences(context).edit { + DefaultSharedPreferences.getInstance(context).edit { putBoolean(PREFS_CRASH_KEY, true) } val b = StringBuilder() @@ -115,7 +115,7 @@ class VectorUncaughtExceptionHandler @Inject constructor(private val bugReporter * @return true if the application crashed */ fun didAppCrash(context: Context): Boolean { - return PreferenceManager.getDefaultSharedPreferences(context) + return DefaultSharedPreferences.getInstance(context) .getBoolean(PREFS_CRASH_KEY, false) } @@ -123,7 +123,7 @@ class VectorUncaughtExceptionHandler @Inject constructor(private val bugReporter * Clear the crash status */ fun clearAppCrashStatus(context: Context) { - PreferenceManager.getDefaultSharedPreferences(context).edit { + DefaultSharedPreferences.getInstance(context).edit { remove(PREFS_CRASH_KEY) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/FontScale.kt b/vector/src/main/java/im/vector/app/features/settings/FontScale.kt index 5fbb021e0a..ad678ec49d 100644 --- a/vector/src/main/java/im/vector/app/features/settings/FontScale.kt +++ b/vector/src/main/java/im/vector/app/features/settings/FontScale.kt @@ -19,8 +19,8 @@ package im.vector.app.features.settings import android.content.Context import androidx.annotation.StringRes import androidx.core.content.edit -import androidx.preference.PreferenceManager import im.vector.app.R +import im.vector.app.core.di.DefaultSharedPreferences /** * Object to manage the Font Scale choice of the user @@ -56,7 +56,7 @@ object FontScale { * @return the font scale value */ fun getFontScaleValue(context: Context): FontScaleValue { - val preferences = PreferenceManager.getDefaultSharedPreferences(context) + val preferences = DefaultSharedPreferences.getInstance(context) return if (APPLICATION_FONT_SCALE_KEY !in preferences) { val fontScale = context.resources.configuration.fontScale @@ -81,7 +81,7 @@ object FontScale { * @param fontScaleValue the font scale value to store */ private fun saveFontScaleValue(context: Context, fontScaleValue: FontScaleValue) { - PreferenceManager.getDefaultSharedPreferences(context) + DefaultSharedPreferences.getInstance(context) .edit { putString(APPLICATION_FONT_SCALE_KEY, fontScaleValue.preferenceValue) } } } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt b/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt index b9d81ab005..cff4ca0cb9 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt @@ -19,9 +19,9 @@ package im.vector.app.features.settings import android.content.Context import android.content.res.Configuration import androidx.core.content.edit -import androidx.preference.PreferenceManager import im.vector.app.BuildConfig import im.vector.app.R +import im.vector.app.core.di.DefaultSharedPreferences import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import timber.log.Timber @@ -59,7 +59,7 @@ object VectorLocale { */ fun init(context: Context) { this.context = context - val preferences = PreferenceManager.getDefaultSharedPreferences(context) + val preferences = DefaultSharedPreferences.getInstance(context) if (preferences.contains(APPLICATION_LOCALE_LANGUAGE_KEY)) { applicationLocale = Locale(preferences.getString(APPLICATION_LOCALE_LANGUAGE_KEY, "")!!, @@ -85,7 +85,7 @@ object VectorLocale { fun saveApplicationLocale(locale: Locale) { applicationLocale = locale - PreferenceManager.getDefaultSharedPreferences(context).edit { + DefaultSharedPreferences.getInstance(context).edit { val language = locale.language if (language.isEmpty()) { remove(APPLICATION_LOCALE_LANGUAGE_KEY) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index 69f8540a1d..886395c1f7 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -22,10 +22,10 @@ import android.media.RingtoneManager import android.net.Uri import android.provider.MediaStore import androidx.core.content.edit -import androidx.preference.PreferenceManager import com.squareup.seismic.ShakeDetector import im.vector.app.BuildConfig import im.vector.app.R +import im.vector.app.core.di.DefaultSharedPreferences import im.vector.app.features.homeserver.ServerUrlsRepository import im.vector.app.features.themes.ThemeUtils import org.matrix.android.sdk.api.extensions.tryThis @@ -227,7 +227,7 @@ class VectorPreferences @Inject constructor(private val context: Context) { ) } - private val defaultPrefs = PreferenceManager.getDefaultSharedPreferences(context) + private val defaultPrefs = DefaultSharedPreferences.getInstance(context) /** * Clear the preferences. diff --git a/vector/src/main/java/im/vector/app/features/themes/ThemeUtils.kt b/vector/src/main/java/im/vector/app/features/themes/ThemeUtils.kt index 69a385fc47..18faa07954 100644 --- a/vector/src/main/java/im/vector/app/features/themes/ThemeUtils.kt +++ b/vector/src/main/java/im/vector/app/features/themes/ThemeUtils.kt @@ -25,8 +25,8 @@ import androidx.annotation.AttrRes import androidx.annotation.ColorInt import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.DrawableCompat -import androidx.preference.PreferenceManager import im.vector.app.R +import im.vector.app.core.di.DefaultSharedPreferences import timber.log.Timber import java.util.concurrent.atomic.AtomicReference @@ -73,8 +73,7 @@ object ThemeUtils { fun getApplicationTheme(context: Context): String { val currentTheme = this.currentTheme.get() return if (currentTheme == null) { - val themeFromPref = PreferenceManager - .getDefaultSharedPreferences(context) + val themeFromPref = DefaultSharedPreferences.getInstance(context) .getString(APPLICATION_THEME_KEY, THEME_LIGHT_VALUE) ?: THEME_LIGHT_VALUE this.currentTheme.set(themeFromPref) themeFromPref From 979c0832cf3f2e79054c544f6227a846b2bfb8ed Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 8 Sep 2020 15:29:02 +0200 Subject: [PATCH 18/89] Use realmSessionProvider in localEchoRepository --- .../internal/session/room/send/LocalEchoRepository.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt index b3188883c0..00c624a20d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.room.send import com.zhuinden.monarchy.Monarchy +import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.events.model.Content import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType @@ -27,6 +28,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageType import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.internal.crypto.MXEventDecryptionResult +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.helper.nextId import org.matrix.android.sdk.internal.database.mapper.ContentMapper import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper @@ -43,12 +45,11 @@ import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryUpdater import org.matrix.android.sdk.internal.session.room.timeline.DefaultTimeline import org.matrix.android.sdk.internal.util.awaitTransaction -import io.realm.Realm -import org.greenrobot.eventbus.EventBus import timber.log.Timber import javax.inject.Inject internal class LocalEchoRepository @Inject constructor(@SessionDatabase private val monarchy: Monarchy, + private val realmSessionProvider: RealmSessionProvider, private val roomSummaryUpdater: RoomSummaryUpdater, private val eventBus: EventBus, private val timelineEventMapper: TimelineEventMapper) { @@ -59,7 +60,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private if (event.eventId == null) { throw IllegalStateException("You should have set an eventId for your event") } - val timelineEventEntity = Realm.getInstance(monarchy.realmConfiguration).use { realm -> + val timelineEventEntity = realmSessionProvider.withRealm { realm -> val eventEntity = event.toEntity(roomId, SendState.UNSENT, System.currentTimeMillis()) val roomMemberHelper = RoomMemberHelper(realm, roomId) val myUser = roomMemberHelper.getLastRoomMember(senderId) @@ -150,7 +151,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private } fun getAllEventsWithStates(roomId: String, states : List): List { - return Realm.getInstance(monarchy.realmConfiguration).use { realm -> + return realmSessionProvider.withRealm { realm -> TimelineEventEntity .findAllInRoomWithSendStates(realm, roomId, states) .sortedByDescending { it.displayIndex } From c2880a5832ca0d445099a6ca8c0572970a7e9b5c Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 8 Sep 2020 15:38:00 +0200 Subject: [PATCH 19/89] Strict mode: add a build entry to enable whenever we want to check --- vector/build.gradle | 3 +++ .../java/im/vector/app/VectorApplication.kt | 17 ++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/vector/build.gradle b/vector/build.gradle index 6b251d5329..e0f401aaf6 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -190,6 +190,8 @@ android { resValue "bool", "debug_mode", "true" buildConfigField "boolean", "LOW_PRIVACY_LOG_ENABLE", "false" + // Set to true if you want to enable strict mode in debug + buildConfigField "boolean", "ENABLE_STRICT_MODE_LOGS", "false" signingConfig signingConfigs.debug } @@ -199,6 +201,7 @@ android { resValue "bool", "debug_mode", "false" buildConfigField "boolean", "LOW_PRIVACY_LOG_ENABLE", "false" + buildConfigField "boolean", "ENABLE_STRICT_MODE_LOGS", "false" postprocessing { removeUnusedCode true diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index bca0a028e9..c9d2c96223 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -93,13 +93,7 @@ class VectorApplication : private var fontThreadHandler: Handler? = null override fun onCreate() { - if (BuildConfig.DEBUG) { - StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder() - .detectAll() - .penaltyFlashScreen() - .penaltyLog() - .build()) - } + enableStrictModeIfNeeded() super.onCreate() appContext = this vectorComponent = DaggerVectorComponent.factory().create(this) @@ -171,6 +165,15 @@ class VectorApplication : // initKnownEmojiHashSet(appContext) } + private fun enableStrictModeIfNeeded() { + if (BuildConfig.ENABLE_STRICT_MODE_LOGS) { + StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder() + .detectAll() + .penaltyLog() + .build()) + } + } + override fun providesMatrixConfiguration() = MatrixConfiguration(BuildConfig.FLAVOR_DESCRIPTION) override fun getWorkManagerConfiguration(): WorkConfiguration { From dc04d2848d194be2a2e380694d6469b006e5dcad Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 8 Sep 2020 15:43:32 +0200 Subject: [PATCH 20/89] Default pref: make sure to use app context --- .../main/java/im/vector/app/core/di/DefaultSharedPreferences.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/core/di/DefaultSharedPreferences.kt b/vector/src/main/java/im/vector/app/core/di/DefaultSharedPreferences.kt index 745af3e16c..abee0cb2e7 100644 --- a/vector/src/main/java/im/vector/app/core/di/DefaultSharedPreferences.kt +++ b/vector/src/main/java/im/vector/app/core/di/DefaultSharedPreferences.kt @@ -26,6 +26,6 @@ object DefaultSharedPreferences { fun getInstance(context: Context): SharedPreferences = INSTANCE ?: synchronized(this) { - INSTANCE ?: PreferenceManager.getDefaultSharedPreferences(context).also { INSTANCE = it } + INSTANCE ?: PreferenceManager.getDefaultSharedPreferences(context.applicationContext).also { INSTANCE = it } } } From 8cb7260375a85ce6d426ccf2fb72a27c1edcbda4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 9 Sep 2020 12:10:46 +0200 Subject: [PATCH 21/89] Small changes (PR review) --- .../sdk/internal/database/RealmInstanceWrapper.kt | 2 +- .../sdk/internal/database/RealmSessionProvider.kt | 2 +- .../android/sdk/internal/session/SessionModule.kt | 12 ++++++------ tools/check/forbidden_strings_in_code.txt | 3 +++ 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstanceWrapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstanceWrapper.kt index 851605437f..4d02d696d8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstanceWrapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstanceWrapper.kt @@ -19,7 +19,7 @@ package org.matrix.android.sdk.internal.database import io.realm.Realm import java.io.Closeable -class RealmInstanceWrapper(private val realm: Realm, private val closeRealmOnClose: Boolean) : Closeable { +internal class RealmInstanceWrapper (private val realm: Realm, private val closeRealmOnClose: Boolean) : Closeable { override fun close() { if (closeRealmOnClose) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionProvider.kt index a232d83b6d..a7f934ffc0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionProvider.kt @@ -31,7 +31,7 @@ import kotlin.concurrent.getOrSet * instance. This does check each time if you are on the main thread or not and returns the appropriate realm instance. */ @SessionScope -class RealmSessionProvider @Inject constructor(@SessionDatabase private val monarchy: Monarchy) +internal class RealmSessionProvider @Inject constructor(@SessionDatabase private val monarchy: Monarchy) : SessionLifecycleObserver { private val realmThreadLocal = ThreadLocal() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt index e2042bfeac..5397b8d9bd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt @@ -326,27 +326,27 @@ internal abstract class SessionModule { @Binds @IntoSet - abstract fun bindIntegrationManager(observer: IntegrationManager): SessionLifecycleObserver + abstract fun bindIntegrationManager(manager: IntegrationManager): SessionLifecycleObserver @Binds @IntoSet - abstract fun bindWidgetUrlFormatter(observer: DefaultWidgetURLFormatter): SessionLifecycleObserver + abstract fun bindWidgetUrlFormatter(formatter: DefaultWidgetURLFormatter): SessionLifecycleObserver @Binds @IntoSet - abstract fun bindShieldTrustUpdated(observer: ShieldTrustUpdater): SessionLifecycleObserver + abstract fun bindShieldTrustUpdated(updater: ShieldTrustUpdater): SessionLifecycleObserver @Binds @IntoSet - abstract fun bindIdentityService(observer: DefaultIdentityService): SessionLifecycleObserver + abstract fun bindIdentityService(service: DefaultIdentityService): SessionLifecycleObserver @Binds @IntoSet - abstract fun bindDatabaseCleaner(observer: DatabaseCleaner): SessionLifecycleObserver + abstract fun bindDatabaseCleaner(cleaner: DatabaseCleaner): SessionLifecycleObserver @Binds @IntoSet - abstract fun bindRealmSessionProvider(observer: RealmSessionProvider): SessionLifecycleObserver + abstract fun bindRealmSessionProvider(provider: RealmSessionProvider): SessionLifecycleObserver @Binds abstract fun bindInitialSyncProgressService(service: DefaultInitialSyncProgressService): InitialSyncProgressService diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index b5438a0c5b..425fc5a6d6 100644 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -172,3 +172,6 @@ import org.matrix.androidsdk.crypto.data===2 ### Use `Context#getSystemService` extension function provided by `core-ktx` getSystemService\(Context + +### Use DefaultSharedPreferences.getInstance() instead for better performance +PreferenceManager\.getDefaultSharedPreferences==2 From 01a4905dc8b70c6c9d34dbff2f2da604587e1f65 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 9 Sep 2020 12:15:27 +0200 Subject: [PATCH 22/89] Changelog --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index b1a93209bc..2b8c294a7e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -20,7 +20,7 @@ Build 🧱: - Other changes: - - + - Performance: share Realm instance used on UI thread and improve SharedPreferences reading time. Changes in Element 1.0.6 (2020-09-08) =================================================== From 11fb2bcdfa1799c4ef9e14ec52bbc219d5843bce Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 9 Sep 2020 13:34:57 +0200 Subject: [PATCH 23/89] ktlint... --- .../android/sdk/internal/database/RealmInstanceWrapper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstanceWrapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstanceWrapper.kt index 4d02d696d8..e2ddbcbca8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstanceWrapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstanceWrapper.kt @@ -19,7 +19,7 @@ package org.matrix.android.sdk.internal.database import io.realm.Realm import java.io.Closeable -internal class RealmInstanceWrapper (private val realm: Realm, private val closeRealmOnClose: Boolean) : Closeable { +internal class RealmInstanceWrapper(private val realm: Realm, private val closeRealmOnClose: Boolean) : Closeable { override fun close() { if (closeRealmOnClose) { From 0cba8f3aa14b29059c9d21458cd9f7b7812beed1 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 10 Sep 2020 12:08:05 +0300 Subject: [PATCH 24/89] Start background sync even if the eventId or roomId is null. --- CHANGES.md | 2 +- .../gplay/push/fcm/VectorFirebaseMessagingService.kt | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b1a93209bc..f34a32d06b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,7 +8,7 @@ Improvements 🙌: - Bugfix 🐛: - - + - Clear the notification when the event is read elsewhere (#1822) Translations 🗣: - diff --git a/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt b/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt index be0ce86326..8fdb65c8d0 100755 --- a/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt +++ b/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt @@ -130,14 +130,9 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { Timber.i("## onMessageReceivedInternal() : $data") } - val eventId = data["event_id"] - val roomId = data["room_id"] - if (eventId == null || roomId == null) { - Timber.e("## onMessageReceivedInternal() missing eventId and/or roomId") - return - } + // update the badge counter - val unreadCount = data.get("unread")?.let { Integer.parseInt(it) } ?: 0 + val unreadCount = data["unread"]?.let { Integer.parseInt(it) } ?: 0 BadgeProxy.updateBadgeCount(applicationContext, unreadCount) val session = activeSessionHolder.getSafeActiveSession() @@ -145,6 +140,9 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { if (session == null) { Timber.w("## Can't sync from push, no current session") } else { + val eventId = data["event_id"] + val roomId = data["room_id"] + if (isEventAlreadyKnown(eventId, roomId)) { Timber.i("Ignoring push, event already known") } else { From 971b425e177f31d65f2852325c4421c84516c471 Mon Sep 17 00:00:00 2001 From: Valere Date: Tue, 8 Sep 2020 12:28:29 +0200 Subject: [PATCH 25/89] F-Droid background sync modes --- .../matrix/android/sdk/api/session/Session.kt | 2 +- .../sdk/internal/session/DefaultSession.kt | 4 +- .../sdk/internal/session/sync/SyncTask.kt | 2 +- .../internal/session/sync/job/SyncService.kt | 105 +++++++---- .../internal/session/sync/job/SyncWorker.kt | 37 ++-- vector/src/fdroid/AndroidManifest.xml | 5 + .../receiver/AlarmSyncBroadcastReceiver.kt | 39 ++-- .../java/im/vector/app/push/fcm/FcmHelper.kt | 28 ++- .../java/im/vector/app/push/fcm/FcmHelper.kt | 2 +- .../java/im/vector/app/VectorApplication.kt | 2 +- .../im/vector/app/core/extensions/Session.kt | 3 +- .../app/core/services/VectorSyncService.kt | 31 +++- .../features/settings/BackgroundSyncMode.kt | 28 +++ .../BackgroundSyncModeChooserDialog.kt | 172 ++++++++++++++++++ .../features/settings/VectorPreferences.kt | 52 ++++++ ...rSettingsNotificationPreferenceFragment.kt | 107 ++++++++++- .../layout/dialog_background_sync_mode.xml | 13 ++ .../layout/item_custom_dialog_radio_line.xml | 57 ++++++ vector/src/main/res/values/strings.xml | 2 +- .../main/res/xml/network_security_config.xml | 7 + .../res/xml/vector_settings_notifications.xml | 39 ++-- 21 files changed, 637 insertions(+), 100 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/settings/BackgroundSyncMode.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/BackgroundSyncModeChooserDialog.kt create mode 100644 vector/src/main/res/layout/dialog_background_sync_mode.xml create mode 100644 vector/src/main/res/layout/item_custom_dialog_radio_line.xml diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt index cfddf73363..f5b10a5645 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt @@ -110,7 +110,7 @@ interface Session : * This does not work in doze mode :/ * If battery optimization is on it can work in app standby but that's all :/ */ - fun startAutomaticBackgroundSync(repeatDelay: Long = 30_000L) + fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long = 30L) fun stopAnyBackgroundSync() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt index f8ba625947..004c5afe8f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt @@ -166,8 +166,8 @@ internal class DefaultSession @Inject constructor( SyncWorker.requireBackgroundSync(workManagerProvider, sessionId) } - override fun startAutomaticBackgroundSync(repeatDelay: Long) { - SyncWorker.automaticallyBackgroundSync(workManagerProvider, sessionId, 0, repeatDelay) + override fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long) { + SyncWorker.automaticallyBackgroundSync(workManagerProvider, sessionId, timeOutInSeconds, repeatDelayInSeconds) } override fun stopAnyBackgroundSync() { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt index 02afd53908..9924d44764 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt @@ -32,7 +32,7 @@ import javax.inject.Inject internal interface SyncTask : Task { - data class Params(var timeout: Long = 30_000L) + data class Params(var timeout: Long = 6_000L) } internal class DefaultSyncTask @Inject constructor( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt index 20aa409336..0ba1a672f9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt @@ -19,6 +19,12 @@ package org.matrix.android.sdk.internal.session.sync.job import android.app.Service import android.content.Intent import android.os.IBinder +import android.os.PowerManager +import androidx.core.content.getSystemService +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancelChildren +import kotlinx.coroutines.launch import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.failure.isTokenError import org.matrix.android.sdk.api.session.Session @@ -28,10 +34,6 @@ import org.matrix.android.sdk.internal.session.sync.SyncTask import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.cancelChildren -import kotlinx.coroutines.launch import timber.log.Timber import java.util.concurrent.atomic.AtomicBoolean @@ -46,6 +48,11 @@ abstract class SyncService : Service() { private var sessionId: String? = null private var mIsSelfDestroyed: Boolean = false + private var syncTimeoutSeconds: Int = 6 + private var syncDelaySeconds: Int = 60 + private var periodic: Boolean = false + private var preventReschedule: Boolean = false + private var isInitialSync: Boolean = false private lateinit var session: Session private lateinit var syncTask: SyncTask @@ -59,27 +66,51 @@ abstract class SyncService : Service() { private val serviceScope = CoroutineScope(SupervisorJob()) override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - Timber.i("onStartCommand $intent") - val isInit = initialize(intent) - if (isInit) { - onStart(isInitialSync) - doSyncIfNotAlreadyRunning() - } else { - // We should start and stop as we have to ensure to call Service.startForeground() - onStart(isInitialSync) - stopMe() + Timber.i("## Sync: onStartCommand [$this] $intent with action: ${intent?.action}") + + // We should start we have to ensure we fulfill contract to show notification + // for foreground service (as per design for this service) + // TODO can we check if it's really in foreground + onStart(isInitialSync) + when (intent?.action) { + ACTION_STOP -> { + Timber.i("## Sync: stop command received") + // If it was periodic we ensure that it will not reschedule itself + preventReschedule = true + // we don't want to cancel initial syncs, let it finish + if (!isInitialSync) { + stopMe() + } + } + else -> { + val isInit = initialize(intent) + if (isInit) { + periodic = intent?.getBooleanExtra(EXTRA_PERIODIC, false) ?: false + Timber.i("## Sync: command received, periodic: $periodic") + // default is syncing + doSyncIfNotAlreadyRunning() + } else { + Timber.i("## Sync: Failed to initialize service") + stopMe() + } + } } - // No intent just start the service, an alarm will should call with intent + return START_STICKY } override fun onDestroy() { - Timber.i("## onDestroy() : $this") + Timber.i("## Sync: onDestroy() [$this] periodic:$periodic preventReschedule:$preventReschedule") if (!mIsSelfDestroyed) { - Timber.w("## Destroy by the system : $this") + Timber.d("## Sync: Destroy by the system : $this") } - serviceScope.coroutineContext.cancelChildren() isRunning.set(false) + // Cancelling the context will trigger the catch close the doSync try + serviceScope.coroutineContext.cancelChildren() + if (!preventReschedule && periodic && sessionId != null) { + Timber.d("## Sync: Reschedule service in $syncDelaySeconds sec") + onRescheduleAsked(sessionId ?: "", false, syncTimeoutSeconds, syncDelaySeconds) + } super.onDestroy() } @@ -90,9 +121,15 @@ abstract class SyncService : Service() { private fun doSyncIfNotAlreadyRunning() { if (isRunning.get()) { - Timber.i("Received a start while was already syncing... ignore") + Timber.i("## Sync: Received a start while was already syncing... ignore") } else { isRunning.set(true) + // Acquire a lock to give enough time for the sync :/ + getSystemService()?.run { + newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "riotx:fdroidSynclock").apply { + acquire((syncTimeoutSeconds * 1000L + 10_000L)) + } + } serviceScope.launch(coroutineDispatchers.io) { doSync() } @@ -100,8 +137,8 @@ abstract class SyncService : Service() { } private suspend fun doSync() { - Timber.v("Execute sync request with timeout 0") - val params = SyncTask.Params(TIME_OUT) + Timber.v("## Sync: Execute sync request with timeout $syncTimeoutSeconds seconds") + val params = SyncTask.Params(syncTimeoutSeconds * 1000L) try { syncTask.execute(params) // Start sync if we were doing an initial sync and the syncThread is not launched yet @@ -111,28 +148,28 @@ abstract class SyncService : Service() { } stopMe() } catch (throwable: Throwable) { - Timber.e(throwable) + Timber.e(throwable, "## Sync: sync service did fail ${isRunning.get()}") if (throwable.isTokenError()) { - stopMe() - } else { - Timber.v("Should be rescheduled to avoid wasting resources") - sessionId?.also { - onRescheduleAsked(it, isInitialSync, delay = 10_000L) - } - stopMe() + // no need to retry + preventReschedule = true } + // JobCancellation could be caught here when onDestroy cancels the coroutine context + if (isRunning.get()) stopMe() } } private fun initialize(intent: Intent?): Boolean { if (intent == null) { + Timber.d("## Sync: initialize intent is null") return false } val matrix = Matrix.getInstance(applicationContext) val safeSessionId = intent.getStringExtra(EXTRA_SESSION_ID) ?: return false + syncTimeoutSeconds = intent.getIntExtra(EXTRA_TIMEOUT_SECONDS, 6) + syncDelaySeconds = intent.getIntExtra(EXTRA_DELAY_SECONDS, 60) try { val sessionComponent = matrix.sessionManager.getSessionComponent(safeSessionId) - ?: throw IllegalStateException("You should have a session to make it work") + ?: throw IllegalStateException("## Sync: You should have a session to make it work") session = sessionComponent.session() sessionId = safeSessionId syncTask = sessionComponent.syncTask() @@ -143,14 +180,14 @@ abstract class SyncService : Service() { backgroundDetectionObserver = matrix.backgroundDetectionObserver return true } catch (exception: Exception) { - Timber.e(exception, "An exception occurred during initialisation") + Timber.e(exception, "## Sync: An exception occurred during initialisation") return false } } abstract fun onStart(isInitialSync: Boolean) - abstract fun onRescheduleAsked(sessionId: String, isInitialSync: Boolean, delay: Long) + abstract fun onRescheduleAsked(sessionId: String, isInitialSync: Boolean, timeout: Int, delay: Int) override fun onBind(intent: Intent?): IBinder? { return null @@ -158,6 +195,10 @@ abstract class SyncService : Service() { companion object { const val EXTRA_SESSION_ID = "EXTRA_SESSION_ID" - private const val TIME_OUT = 0L + const val EXTRA_TIMEOUT_SECONDS = "EXTRA_TIMEOUT_SECONDS" + const val EXTRA_DELAY_SECONDS = "EXTRA_DELAY_SECONDS" + const val EXTRA_PERIODIC = "EXTRA_PERIODIC" + + const val ACTION_STOP = "ACTION_STOP" } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt index e702de3573..3e0a29ba72 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt @@ -34,7 +34,8 @@ import timber.log.Timber import java.util.concurrent.TimeUnit import javax.inject.Inject -private const val DEFAULT_LONG_POOL_TIMEOUT = 0L +private const val DEFAULT_LONG_POOL_TIMEOUT = 6L +private const val DEFAULT_DELAY_TIMEOUT = 30_000L /** * Possible previous worker: None @@ -48,13 +49,15 @@ internal class SyncWorker(context: Context, internal data class Params( override val sessionId: String, val timeout: Long = DEFAULT_LONG_POOL_TIMEOUT, - val automaticallyRetry: Boolean = false, + val delay: Long = DEFAULT_DELAY_TIMEOUT, + val periodic: Boolean = false, override val lastFailureMessage: String? = null ) : SessionWorkerParams @Inject lateinit var syncTask: SyncTask @Inject lateinit var taskExecutor: TaskExecutor @Inject lateinit var networkConnectivityChecker: NetworkConnectivityChecker + @Inject lateinit var workManagerProvider: WorkManagerProvider override suspend fun doWork(): Result { Timber.i("Sync work starting") @@ -67,11 +70,21 @@ internal class SyncWorker(context: Context, return runCatching { doSync(params.timeout) }.fold( - { Result.success() }, + { + Result.success().also { + if (params.periodic) { + // we want to schedule another one after delay + automaticallyBackgroundSync(workManagerProvider, params.sessionId, params.timeout, params.delay) + } + } + }, { failure -> - if (failure.isTokenError() || !params.automaticallyRetry) { + if (failure.isTokenError()) { Result.failure() } else { + // If the worker was stopped (when going back in foreground), a JobCancellation exception is sent + // but in this case the result is ignored, as the work is considered stopped, + // so don't worry of the retry here for this case Result.retry() } } @@ -79,7 +92,7 @@ internal class SyncWorker(context: Context, } private suspend fun doSync(timeout: Long) { - val taskParams = SyncTask.Params(timeout) + val taskParams = SyncTask.Params(timeout * 1000) syncTask.execute(taskParams) } @@ -87,25 +100,27 @@ internal class SyncWorker(context: Context, private const val BG_SYNC_WORK_NAME = "BG_SYNCP" fun requireBackgroundSync(workManagerProvider: WorkManagerProvider, sessionId: String, serverTimeout: Long = 0) { - val data = WorkerParamsFactory.toData(Params(sessionId, serverTimeout, false)) + val data = WorkerParamsFactory.toData(Params(sessionId, serverTimeout, 0L, false)) val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder() .setConstraints(WorkManagerProvider.workConstraints) .setBackoffCriteria(BackoffPolicy.LINEAR, 1_000, TimeUnit.MILLISECONDS) .setInputData(data) .build() workManagerProvider.workManager - .enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.REPLACE, workRequest) + .enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.APPEND_OR_REPLACE, workRequest) } - fun automaticallyBackgroundSync(workManagerProvider: WorkManagerProvider, sessionId: String, serverTimeout: Long = 0, delay: Long = 30_000) { - val data = WorkerParamsFactory.toData(Params(sessionId, serverTimeout, true)) + fun automaticallyBackgroundSync(workManagerProvider: WorkManagerProvider, sessionId: String, serverTimeout: Long = 0, delayInSeconds: Long = 30) { + val data = WorkerParamsFactory.toData(Params(sessionId, serverTimeout, delayInSeconds, true)) val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder() .setConstraints(WorkManagerProvider.workConstraints) .setInputData(data) - .setBackoffCriteria(BackoffPolicy.LINEAR, delay, TimeUnit.MILLISECONDS) + .setBackoffCriteria(BackoffPolicy.LINEAR, 1_000, TimeUnit.MILLISECONDS) + .setInitialDelay(delayInSeconds, TimeUnit.SECONDS) .build() + workManagerProvider.workManager - .enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.REPLACE, workRequest) + .enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.APPEND_OR_REPLACE, workRequest) } fun stopAnyBackgroundSync(workManagerProvider: WorkManagerProvider) { diff --git a/vector/src/fdroid/AndroidManifest.xml b/vector/src/fdroid/AndroidManifest.xml index 55f745ddfa..3a7c107138 100644 --- a/vector/src/fdroid/AndroidManifest.xml +++ b/vector/src/fdroid/AndroidManifest.xml @@ -4,6 +4,11 @@ + + diff --git a/vector/src/fdroid/java/im/vector/app/fdroid/receiver/AlarmSyncBroadcastReceiver.kt b/vector/src/fdroid/java/im/vector/app/fdroid/receiver/AlarmSyncBroadcastReceiver.kt index 1af92ff387..674e7dfef5 100644 --- a/vector/src/fdroid/java/im/vector/app/fdroid/receiver/AlarmSyncBroadcastReceiver.kt +++ b/vector/src/fdroid/java/im/vector/app/fdroid/receiver/AlarmSyncBroadcastReceiver.kt @@ -22,16 +22,18 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.os.Build -import android.os.PowerManager import androidx.core.content.ContextCompat +import androidx.core.content.getSystemService import im.vector.app.core.di.HasVectorInjector import im.vector.app.core.services.VectorSyncService -import androidx.core.content.getSystemService +import im.vector.app.features.settings.VectorPreferences import org.matrix.android.sdk.internal.session.sync.job.SyncService import timber.log.Timber class AlarmSyncBroadcastReceiver : BroadcastReceiver() { + lateinit var vectorPreferences: VectorPreferences + override fun onReceive(context: Context, intent: Intent) { val appContext = context.applicationContext if (appContext is HasVectorInjector) { @@ -40,41 +42,35 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() { Timber.v("No active session don't launch sync service.") return } - } - - // Acquire a lock to give enough time for the sync :/ - context.getSystemService()!!.run { - newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "riotx:fdroidSynclock").apply { - acquire((10_000).toLong()) - } + vectorPreferences = appContext.injector().vectorPreferences() } val sessionId = intent.getStringExtra(SyncService.EXTRA_SESSION_ID) ?: return // This method is called when the BroadcastReceiver is receiving an Intent broadcast. Timber.d("RestartBroadcastReceiver received intent") - VectorSyncService.newIntent(context, sessionId).let { + VectorSyncService.newPeriodicIntent(context, sessionId, vectorPreferences.backgroundSyncTimeOut(), vectorPreferences.backgroundSyncDelay()).let { try { ContextCompat.startForegroundService(context, it) } catch (ex: Throwable) { - // TODO + Timber.i("## Sync: Failed to start service, Alarm scheduled to restart service") + scheduleAlarm(context, sessionId, vectorPreferences.backgroundSyncDelay()) Timber.e(ex) } } - - scheduleAlarm(context, sessionId, 30_000L) - Timber.i("Alarm scheduled to restart service") } companion object { private const val REQUEST_CODE = 0 - fun scheduleAlarm(context: Context, sessionId: String, delay: Long) { + fun scheduleAlarm(context: Context, sessionId: String, delayInSeconds: Int) { // Reschedule + Timber.v("## Sync: Scheduling alarm for background sync in $delayInSeconds seconds") val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java).apply { putExtra(SyncService.EXTRA_SESSION_ID, sessionId) + putExtra(SyncService.EXTRA_PERIODIC, true) } val pIntent = PendingIntent.getBroadcast(context, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT) - val firstMillis = System.currentTimeMillis() + delay + val firstMillis = System.currentTimeMillis() + delayInSeconds * 1000L val alarmMgr = context.getSystemService()!! if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pIntent) @@ -84,11 +80,20 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() { } fun cancelAlarm(context: Context) { - Timber.v("Cancel alarm") + Timber.v("## Sync: Cancel alarm for background sync") val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java) val pIntent = PendingIntent.getBroadcast(context, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT) val alarmMgr = context.getSystemService()!! alarmMgr.cancel(pIntent) + + // Stop current service to restart + VectorSyncService.stopIntent(context).let { + try { + ContextCompat.startForegroundService(context, it) + } catch (ex: Throwable) { + Timber.i("## Sync: Cancel sync") + } + } } } } diff --git a/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt b/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt index 7a8c5fa134..7874d0237f 100755 --- a/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt +++ b/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt @@ -23,6 +23,7 @@ import android.content.Context import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.pushers.PushersManager import im.vector.app.fdroid.receiver.AlarmSyncBroadcastReceiver +import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.VectorPreferences import timber.log.Timber @@ -61,16 +62,35 @@ object FcmHelper { // No op } - fun onEnterForeground(context: Context) { + fun onEnterForeground(context: Context, activeSessionHolder: ActiveSessionHolder) { + // try to stop all regardless of background mode + activeSessionHolder.getSafeActiveSession()?.stopAnyBackgroundSync() AlarmSyncBroadcastReceiver.cancelAlarm(context) } fun onEnterBackground(context: Context, vectorPreferences: VectorPreferences, activeSessionHolder: ActiveSessionHolder) { // We need to use alarm in this mode if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) { - val currentSession = activeSessionHolder.getActiveSession() - AlarmSyncBroadcastReceiver.scheduleAlarm(context, currentSession.sessionId, 4_000L) - Timber.i("Alarm scheduled to restart service") + when (vectorPreferences.getFdroidSyncBackgroundMode()) { + BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY -> { + // we rely on periodic worker + Timber.i("## Sync: Work scheduled to periodically sync") + activeSessionHolder + .getSafeActiveSession() + ?.startAutomaticBackgroundSync( + vectorPreferences.backgroundSyncTimeOut().toLong(), + vectorPreferences.backgroundSyncDelay().toLong() + ) + } + BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME -> { + val currentSession = activeSessionHolder.getActiveSession() + AlarmSyncBroadcastReceiver.scheduleAlarm(context, currentSession.sessionId, vectorPreferences.backgroundSyncDelay()) + Timber.i("## Sync: Alarm scheduled to start syncing") + } + BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED -> { + // we do nothing + } + } } } } diff --git a/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt b/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt index 84ca392c45..d139cad9d3 100755 --- a/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt +++ b/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt @@ -102,7 +102,7 @@ object FcmHelper { } @Suppress("UNUSED_PARAMETER") - fun onEnterForeground(context: Context) { + fun onEnterForeground(context: Context, activeSessionHolder: ActiveSessionHolder) { // No op } diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index c9d2c96223..4b0ef66459 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -146,7 +146,7 @@ class VectorApplication : @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) fun entersForeground() { Timber.i("App entered foreground") - FcmHelper.onEnterForeground(appContext) + FcmHelper.onEnterForeground(appContext, activeSessionHolder) activeSessionHolder.getSafeActiveSession()?.also { it.stopAnyBackgroundSync() } diff --git a/vector/src/main/java/im/vector/app/core/extensions/Session.kt b/vector/src/main/java/im/vector/app/core/extensions/Session.kt index 6f0fd51525..cb87947612 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/Session.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/Session.kt @@ -37,7 +37,8 @@ fun Session.configureAndStart(context: Context) { fun Session.startSyncing(context: Context) { val applicationContext = context.applicationContext if (!hasAlreadySynced()) { - VectorSyncService.newIntent(applicationContext, sessionId).also { + // initial sync is done as a service so it can continue below app lifecycle + VectorSyncService.newOneShotIntent(applicationContext, sessionId, 0).also { try { ContextCompat.startForegroundService(applicationContext, it) } catch (ex: Throwable) { diff --git a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt index 20ceb07fb5..bbd8487ae5 100644 --- a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt +++ b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt @@ -31,9 +31,26 @@ class VectorSyncService : SyncService() { companion object { - fun newIntent(context: Context, sessionId: String): Intent { + fun newOneShotIntent(context: Context, sessionId: String, timeoutSeconds: Int): Intent { return Intent(context, VectorSyncService::class.java).also { it.putExtra(EXTRA_SESSION_ID, sessionId) + it.putExtra(EXTRA_TIMEOUT_SECONDS, timeoutSeconds) + it.putExtra(EXTRA_PERIODIC, false) + } + } + + fun newPeriodicIntent(context: Context, sessionId: String, timeoutSeconds: Int, delayInSeconds: Int): Intent { + return Intent(context, VectorSyncService::class.java).also { + it.putExtra(EXTRA_SESSION_ID, sessionId) + it.putExtra(EXTRA_TIMEOUT_SECONDS, timeoutSeconds) + it.putExtra(EXTRA_PERIODIC, true) + it.putExtra(EXTRA_DELAY_SECONDS, delayInSeconds) + } + } + + fun stopIntent(context: Context): Intent { + return Intent(context, VectorSyncService::class.java).also { + it.action = ACTION_STOP } } } @@ -55,8 +72,8 @@ class VectorSyncService : SyncService() { startForeground(NotificationUtils.NOTIFICATION_ID_FOREGROUND_SERVICE, notification) } - override fun onRescheduleAsked(sessionId: String, isInitialSync: Boolean, delay: Long) { - reschedule(sessionId, delay) + override fun onRescheduleAsked(sessionId: String, isInitialSync: Boolean, timeout: Int, delay: Int) { + reschedule(sessionId, timeout, delay) } override fun onDestroy() { @@ -69,13 +86,13 @@ class VectorSyncService : SyncService() { notificationManager.cancel(NotificationUtils.NOTIFICATION_ID_FOREGROUND_SERVICE) } - private fun reschedule(sessionId: String, delay: Long) { + private fun reschedule(sessionId: String, timeout: Int, delay: Int) { val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - PendingIntent.getForegroundService(this, 0, newIntent(this, sessionId), 0) + PendingIntent.getForegroundService(this, 0, newPeriodicIntent(this, sessionId, timeout, delay), 0) } else { - PendingIntent.getService(this, 0, newIntent(this, sessionId), 0) + PendingIntent.getService(this, 0, newPeriodicIntent(this, sessionId, timeout, delay), 0) } - val firstMillis = System.currentTimeMillis() + delay + val firstMillis = System.currentTimeMillis() + delay * 1000L val alarmMgr = getSystemService()!! if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent) diff --git a/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncMode.kt b/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncMode.kt new file mode 100644 index 0000000000..f266060053 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncMode.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020 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 im.vector.app.features.settings + +enum class BackgroundSyncMode { + FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY, + FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME, + FDROID_BACKGROUND_SYNC_MODE_DISABLED; + + companion object { + fun fromString(value: String?): BackgroundSyncMode = values().firstOrNull { it.name == value } + ?: FDROID_BACKGROUND_SYNC_MODE_DISABLED + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncModeChooserDialog.kt b/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncModeChooserDialog.kt new file mode 100644 index 0000000000..079be58fbc --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncModeChooserDialog.kt @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2020 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 im.vector.app.features.settings + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ArrayAdapter +import android.widget.ListView +import android.widget.RadioButton +import android.widget.TextView +import androidx.appcompat.app.AlertDialog +import androidx.core.view.isVisible +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.FragmentActivity +import im.vector.app.R + +class BackgroundSyncModeChooserDialog : DialogFragment() { + + var interactionListener: InteractionListener? = null + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return activity?.let { activity: FragmentActivity -> + val builder = AlertDialog.Builder(activity) + // Get the layout inflater + val inflater = activity.layoutInflater + + // Inflate and set the layout for the dialog + // Pass null as the parent view because its going in the dialog layout + val view = inflater.inflate(R.layout.dialog_background_sync_mode, null) + view.findViewById(R.id.dialog_background_sync_list)?.let { + it.adapter = Adapter( + activity, + BackgroundSyncMode.fromString(arguments?.getString(ARG_INITIAL_MODE)) + ) + } + builder.setView(view) + // Add action buttons + .setPositiveButton(R.string.ok) { dialog, _ -> + val mode = getSelectedOption() + if (mode.name == arguments?.getString(ARG_INITIAL_MODE)) { + // it's like a cancel, no changes + dialog.cancel() + } else { + interactionListener?.onOptionSelected(mode) + dialog.dismiss() + } + } + .setNegativeButton(R.string.cancel) { dialog, _ -> + interactionListener?.onCancel() + dialog.cancel() + } + builder.create() + } ?: throw IllegalStateException("Activity cannot be null") + } + + private fun getSelectedOption(): BackgroundSyncMode { + options.forEach { + if (it.isSelected) return it.mode + } + // an item is always selected, should not happen + return options[0].mode + } + + data class SyncMode(val mode: BackgroundSyncMode, val title: Int, val description: Int, var isSelected: Boolean) + + private class Adapter(context: Context, val initialMode: BackgroundSyncMode) : ArrayAdapter(context, 0, options) { + init { + // mark the currently selected option + var initialModeFound = false + options.forEach { + it.isSelected = initialMode == it.mode + initialModeFound = true + } + if (!initialModeFound) { + options[0].isSelected = true + } + } + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + val syncMode = getItem(position)!! + + // Only 3 items, let's keep it like that + val itemView = convertView + ?: LayoutInflater.from(context).inflate(R.layout.item_custom_dialog_radio_line, parent, false) + + // Lookup view for data population + itemView?.findViewById(R.id.item_generic_title_text)?.let { + it.text = context.getString(syncMode.title) + } + itemView?.findViewById(R.id.item_generic_description_text)?.let { + it.text = context.getString(syncMode.description) + it.isVisible = true + } + itemView?.findViewById(R.id.item_generic_radio)?.let { + it.isChecked = syncMode.isSelected + it.isVisible = true + // let the item click handle that + it.setOnClickListener { + toggleChangeAtPosition(position) + } + } + + itemView?.setOnClickListener { + toggleChangeAtPosition(position) + } + + // Populate the data into the template view using the data object + + return itemView + } + + private fun toggleChangeAtPosition(position: Int) { + if (getItem(position)?.isSelected == true) { + // nop + } else { + for (i in 0 until count) { + // we change the single selection + getItem(i)?.isSelected = i == position + } + notifyDataSetChanged() + } + } + } + + interface InteractionListener { + fun onCancel() {} + fun onOptionSelected(mode: BackgroundSyncMode) {} + } + + companion object { + private val options = listOf( + SyncMode(BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY, + R.string.settings_background_fdroid_sync_mode_battery, + R.string.settings_background_fdroid_sync_mode_battery_description, false), + SyncMode(BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME, + R.string.settings_background_fdroid_sync_mode_real_time, + R.string.settings_background_fdroid_sync_mode_real_time_description, false), + SyncMode(BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED, + R.string.settings_background_fdroid_sync_mode_disabled, + R.string.settings_background_fdroid_sync_mode_disabled_description, false) + ) + + private const val ARG_INITIAL_MODE = "ARG_INITIAL_MODE" + + fun newInstance(selectedMode: BackgroundSyncMode, interactionListener: InteractionListener): BackgroundSyncModeChooserDialog { + val frag = BackgroundSyncModeChooserDialog() + frag.interactionListener = interactionListener + val args = Bundle() + args.putString(ARG_INITIAL_MODE, selectedMode.name) + frag.arguments = args + return frag + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index 886395c1f7..2239efa992 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -55,6 +55,7 @@ class VectorPreferences @Inject constructor(private val context: Context) { const val SETTINGS_CONTACT_PREFERENCE_KEYS = "SETTINGS_CONTACT_PREFERENCE_KEYS" const val SETTINGS_NOTIFICATIONS_TARGETS_PREFERENCE_KEY = "SETTINGS_NOTIFICATIONS_TARGETS_PREFERENCE_KEY" const val SETTINGS_NOTIFICATIONS_TARGET_DIVIDER_PREFERENCE_KEY = "SETTINGS_NOTIFICATIONS_TARGET_DIVIDER_PREFERENCE_KEY" + const val SETTINGS_FDROID_BACKGROUND_SYNC_MODE = "SETTINGS_FDROID_BACKGROUND_SYNC_MODE" const val SETTINGS_BACKGROUND_SYNC_PREFERENCE_KEY = "SETTINGS_BACKGROUND_SYNC_PREFERENCE_KEY" const val SETTINGS_BACKGROUND_SYNC_DIVIDER_PREFERENCE_KEY = "SETTINGS_BACKGROUND_SYNC_DIVIDER_PREFERENCE_KEY" const val SETTINGS_LABS_PREFERENCE_KEY = "SETTINGS_LABS_PREFERENCE_KEY" @@ -182,6 +183,8 @@ class VectorPreferences @Inject constructor(private val context: Context) { private const val SETTINGS_UNKNOWN_DEVICE_DISMISSED_LIST = "SETTINGS_UNKNWON_DEVICE_DISMISSED_LIST" + // Background sync modes + // some preferences keys must be kept after a logout private val mKeysToKeepAfterLogout = listOf( SETTINGS_DEFAULT_MEDIA_COMPRESSION_KEY, @@ -830,4 +833,53 @@ class VectorPreferences @Inject constructor(private val context: Context) { fun useFlagPinCode(): Boolean { return defaultPrefs.getBoolean(SETTINGS_SECURITY_USE_PIN_CODE_FLAG, false) } + + fun backgroundSyncTimeOut(): Int { + return tryThis { + // The xml pref is saved as a string so use getString and parse + defaultPrefs.getString(SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY, "6")?.toInt() + } ?: 6 + } + + fun setBackgroundSyncTimeout(timeInSecond: Int) { + defaultPrefs + .edit() + .putString(SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY, timeInSecond.toString()) + .apply() + } + + fun backgroundSyncDelay(): Int { + return tryThis { + // The xml pref is saved as a string so use getString and parse + defaultPrefs.getString(SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY, "60")?.toInt() + } ?: 60 + } + + fun setBackgroundSyncDelay(timeInSecond: Int) { + defaultPrefs + .edit() + .putString(SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY, timeInSecond.toString()) + .apply() + } + + fun isBackgroundSyncEnabled(): Boolean { + return getFdroidSyncBackgroundMode() != BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED + } + + fun setFdroidSyncBackgroundMode(mode: BackgroundSyncMode) { + defaultPrefs + .edit() + .putString(SETTINGS_FDROID_BACKGROUND_SYNC_MODE, mode.name) + .apply() + } + + fun getFdroidSyncBackgroundMode(): BackgroundSyncMode { + return try { + val strPref = defaultPrefs + .getString(SETTINGS_FDROID_BACKGROUND_SYNC_MODE, BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY.name) + BackgroundSyncMode.values().firstOrNull { it.name == strPref } ?: BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY + } catch (e: Throwable) { + BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY + } + } } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt index 1cf9b0dcfa..21895e15b6 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt @@ -25,16 +25,21 @@ import android.os.Parcelable import android.widget.Toast import androidx.preference.Preference import androidx.preference.SwitchPreference -import org.matrix.android.sdk.api.MatrixCallback -import org.matrix.android.sdk.api.pushrules.RuleIds -import org.matrix.android.sdk.api.pushrules.RuleKind import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.core.preference.VectorEditTextPreference import im.vector.app.core.preference.VectorPreference +import im.vector.app.core.preference.VectorPreferenceCategory import im.vector.app.core.preference.VectorSwitchPreference import im.vector.app.core.pushers.PushersManager +import im.vector.app.core.utils.isIgnoringBatteryOptimizations +import im.vector.app.core.utils.requestDisablingBatteryOptimization import im.vector.app.features.notifications.NotificationUtils import im.vector.app.push.fcm.FcmHelper +import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.extensions.tryThis +import org.matrix.android.sdk.api.pushrules.RuleIds +import org.matrix.android.sdk.api.pushrules.RuleKind import javax.inject.Inject // Referenced in vector_settings_preferences_root.xml @@ -65,9 +70,104 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( (pref as SwitchPreference).isChecked = areNotifEnabledAtAccountLevel } + findPreference(VectorPreferences.SETTINGS_FDROID_BACKGROUND_SYNC_MODE)?.let { + it.onPreferenceClickListener = Preference.OnPreferenceClickListener { + val initialMode = vectorPreferences.getFdroidSyncBackgroundMode() + val dialogFragment = BackgroundSyncModeChooserDialog.newInstance( + initialMode, + object : BackgroundSyncModeChooserDialog.InteractionListener { + override fun onOptionSelected(mode: BackgroundSyncMode) { + // option has change, need to act + if (mode == BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME) { + // Important, Battery optim white listing is needed in this mode; + // Even if using foreground service with foreground notif, it stops to work + // in doze mode for certain devices :/ + if (!isIgnoringBatteryOptimizations(requireContext())) { + requestDisablingBatteryOptimization(requireActivity(), + this@VectorSettingsNotificationPreferenceFragment, + REQUEST_BATTERY_OPTIMIZATION) + } + } + vectorPreferences.setFdroidSyncBackgroundMode(mode) + refreshBackgroundSyncPrefs() + } + } + ) + activity?.supportFragmentManager?.let { + dialogFragment.show(it, "syncDialog") + } + true + } + } + + findPreference(VectorPreferences.SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY)?.let { + it.isEnabled = vectorPreferences.isBackgroundSyncEnabled() + it.summary = secondsToText(vectorPreferences.backgroundSyncTimeOut()) + it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + if (newValue is String) { + val syncTimeout = tryThis { Integer.parseInt(newValue) } ?: 6 + vectorPreferences.setBackgroundSyncTimeout(maxOf(0, syncTimeout)) + refreshBackgroundSyncPrefs() + } + true + } + } + + findPreference(VectorPreferences.SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY)?.let { + it.isEnabled = vectorPreferences.isBackgroundSyncEnabled() + it.summary = secondsToText(vectorPreferences.backgroundSyncDelay()) + it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + if (newValue is String) { + val syncDelay = tryThis { Integer.parseInt(newValue) } ?: 6 + vectorPreferences.setBackgroundSyncDelay(maxOf(0, syncDelay)) + refreshBackgroundSyncPrefs() + } + true + } + } + + refreshBackgroundSyncPrefs() + handleSystemPreference() } + private fun refreshBackgroundSyncPrefs() { + findPreference(VectorPreferences.SETTINGS_FDROID_BACKGROUND_SYNC_MODE)?.let { + it.summary = when (vectorPreferences.getFdroidSyncBackgroundMode()) { + BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY -> getString(R.string.settings_background_fdroid_sync_mode_battery) + BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME -> getString(R.string.settings_background_fdroid_sync_mode_real_time) + BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED -> getString(R.string.settings_background_fdroid_sync_mode_disabled) + } + } + + findPreference(VectorPreferences.SETTINGS_BACKGROUND_SYNC_PREFERENCE_KEY)?.let { + it.isVisible = !FcmHelper.isPushSupported() + } + + findPreference(VectorPreferences.SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY)?.let { + it.isEnabled = vectorPreferences.isBackgroundSyncEnabled() + it.summary = secondsToText(vectorPreferences.backgroundSyncTimeOut()) + } + findPreference(VectorPreferences.SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY)?.let { + it.isEnabled = vectorPreferences.isBackgroundSyncEnabled() + it.summary = secondsToText(vectorPreferences.backgroundSyncDelay()) + } + } + + /** + * Convert a delay in seconds to string + * + * @param seconds the delay in seconds + * @return the text + */ + private fun secondsToText(seconds: Int): String { + return if (seconds > 1) { + seconds.toString() + " " + getString(R.string.settings_seconds) + } else { + seconds.toString() + " " + getString(R.string.settings_second) + } + } + private fun handleSystemPreference() { val callNotificationsSystemOptions = findPreference(VectorPreferences.SETTINGS_SYSTEM_CALL_NOTIFICATION_PREFERENCE_KEY)!! if (NotificationUtils.supportNotificationChannels()) { @@ -234,5 +334,6 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( companion object { private const val REQUEST_NOTIFICATION_RINGTONE = 888 + private const val REQUEST_BATTERY_OPTIMIZATION = 500 } } diff --git a/vector/src/main/res/layout/dialog_background_sync_mode.xml b/vector/src/main/res/layout/dialog_background_sync_mode.xml new file mode 100644 index 0000000000..89b2aaefde --- /dev/null +++ b/vector/src/main/res/layout/dialog_background_sync_mode.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/vector/src/main/res/layout/item_custom_dialog_radio_line.xml b/vector/src/main/res/layout/item_custom_dialog_radio_line.xml new file mode 100644 index 0000000000..17d7be08ed --- /dev/null +++ b/vector/src/main/res/layout/item_custom_dialog_radio_line.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index a0abc28a4d..c191b17f7e 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -797,7 +797,7 @@ Messages sent by bot Background synchronization - Background Sync Mode (Experimental) + Background Sync Mode Optimized for battery Element will sync in background in way that preserves the device’s limited resources (battery).\nDepending on your device resource state, the sync may be deferred by the operating system. Optimized for real time diff --git a/vector/src/main/res/xml/network_security_config.xml b/vector/src/main/res/xml/network_security_config.xml index e40c61c229..1f323dffd1 100644 --- a/vector/src/main/res/xml/network_security_config.xml +++ b/vector/src/main/res/xml/network_security_config.xml @@ -13,4 +13,11 @@ 10.0.2.2 + + + + + + + diff --git a/vector/src/main/res/xml/vector_settings_notifications.xml b/vector/src/main/res/xml/vector_settings_notifications.xml index 3e19c9e9e5..52333dd81a 100644 --- a/vector/src/main/res/xml/vector_settings_notifications.xml +++ b/vector/src/main/res/xml/vector_settings_notifications.xml @@ -71,34 +71,37 @@ - From 43c24e55abfd0db2882609b3630a720a8f46bc4a Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 9 Sep 2020 10:33:34 +0200 Subject: [PATCH 26/89] Restart fdroid sync on application boot --- .../OnApplicationUpgradeOrRebootReceiver.kt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/vector/src/fdroid/java/im/vector/app/fdroid/receiver/OnApplicationUpgradeOrRebootReceiver.kt b/vector/src/fdroid/java/im/vector/app/fdroid/receiver/OnApplicationUpgradeOrRebootReceiver.kt index a8a394576b..2460e149a5 100644 --- a/vector/src/fdroid/java/im/vector/app/fdroid/receiver/OnApplicationUpgradeOrRebootReceiver.kt +++ b/vector/src/fdroid/java/im/vector/app/fdroid/receiver/OnApplicationUpgradeOrRebootReceiver.kt @@ -21,6 +21,8 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import im.vector.app.core.di.HasVectorInjector +import im.vector.app.core.extensions.vectorComponent +import im.vector.app.features.settings.BackgroundSyncMode import timber.log.Timber class OnApplicationUpgradeOrRebootReceiver : BroadcastReceiver() { @@ -30,8 +32,23 @@ class OnApplicationUpgradeOrRebootReceiver : BroadcastReceiver() { val appContext = context.applicationContext if (appContext is HasVectorInjector) { val activeSession = appContext.injector().activeSessionHolder().getSafeActiveSession() + val preferences = appContext.vectorComponent().vectorPreferences() if (activeSession != null) { - AlarmSyncBroadcastReceiver.scheduleAlarm(context, activeSession.sessionId, 10) + when (preferences.getFdroidSyncBackgroundMode()) { + BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY -> { + Timber.i("## Sync: OnBoot Work scheduled to periodically sync") + activeSession.startAutomaticBackgroundSync( + preferences.backgroundSyncTimeOut().toLong(), + preferences.backgroundSyncDelay().toLong() + ) + } + BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME -> { + AlarmSyncBroadcastReceiver.scheduleAlarm(context, activeSession.sessionId, preferences.backgroundSyncDelay()) + } + BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED -> { + // nop + } + } } } } From 3ff475af7aecd6349010ebe0fadfa593c6389f62 Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 9 Sep 2020 11:33:36 +0200 Subject: [PATCH 27/89] Avoid scheduling alarm until network is back --- .../internal/session/sync/job/SyncService.kt | 32 +++++++-- .../java/im/vector/app/push/fcm/FcmHelper.kt | 2 +- .../app/core/services/VectorSyncService.kt | 66 +++++++++++++++++++ 3 files changed, 93 insertions(+), 7 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt index 0ba1a672f9..485eca6f74 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt @@ -26,6 +26,7 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.launch import org.matrix.android.sdk.api.Matrix +import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.isTokenError import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.sync.SyncState @@ -86,17 +87,26 @@ abstract class SyncService : Service() { val isInit = initialize(intent) if (isInit) { periodic = intent?.getBooleanExtra(EXTRA_PERIODIC, false) ?: false - Timber.i("## Sync: command received, periodic: $periodic") - // default is syncing - doSyncIfNotAlreadyRunning() + val onNetworkBack = intent?.getBooleanExtra(EXTRA_NETWORK_BACK_RESTART, false) ?: false + Timber.d("## Sync: command received, periodic: $periodic networkBack: $onNetworkBack") + if (onNetworkBack && !backgroundDetectionObserver.isInBackground) { + // the restart after network occurs while the app is in foreground + // so just stop. It will be restarted when entering background + preventReschedule = true + stopMe() + } else { + // default is syncing + doSyncIfNotAlreadyRunning() + } } else { - Timber.i("## Sync: Failed to initialize service") + Timber.d("## Sync: Failed to initialize service") stopMe() } } } - return START_STICKY + // It's ok to be not sticky because we will explicitly start it again on the next alarm? + return START_NOT_STICKY } override fun onDestroy() { @@ -107,7 +117,7 @@ abstract class SyncService : Service() { isRunning.set(false) // Cancelling the context will trigger the catch close the doSync try serviceScope.coroutineContext.cancelChildren() - if (!preventReschedule && periodic && sessionId != null) { + if (!preventReschedule && periodic && sessionId != null && backgroundDetectionObserver.isInBackground) { Timber.d("## Sync: Reschedule service in $syncDelaySeconds sec") onRescheduleAsked(sessionId ?: "", false, syncTimeoutSeconds, syncDelaySeconds) } @@ -140,6 +150,7 @@ abstract class SyncService : Service() { Timber.v("## Sync: Execute sync request with timeout $syncTimeoutSeconds seconds") val params = SyncTask.Params(syncTimeoutSeconds * 1000L) try { + // never do that in foreground, let the syncThread work syncTask.execute(params) // Start sync if we were doing an initial sync and the syncThread is not launched yet if (isInitialSync && session.getSyncState() == SyncState.Idle) { @@ -153,6 +164,12 @@ abstract class SyncService : Service() { // no need to retry preventReschedule = true } + if (throwable is Failure.NetworkConnection) { + // Network is off, no need to reschedule endless alarms :/ + preventReschedule = true + // Instead start a work to restart background sync when network is back + onNetworkError(sessionId ?: "", isInitialSync, syncTimeoutSeconds, syncDelaySeconds) + } // JobCancellation could be caught here when onDestroy cancels the coroutine context if (isRunning.get()) stopMe() } @@ -189,6 +206,8 @@ abstract class SyncService : Service() { abstract fun onRescheduleAsked(sessionId: String, isInitialSync: Boolean, timeout: Int, delay: Int) + abstract fun onNetworkError(sessionId: String, isInitialSync: Boolean, timeout: Int, delay: Int) + override fun onBind(intent: Intent?): IBinder? { return null } @@ -198,6 +217,7 @@ abstract class SyncService : Service() { const val EXTRA_TIMEOUT_SECONDS = "EXTRA_TIMEOUT_SECONDS" const val EXTRA_DELAY_SECONDS = "EXTRA_DELAY_SECONDS" const val EXTRA_PERIODIC = "EXTRA_PERIODIC" + const val EXTRA_NETWORK_BACK_RESTART = "EXTRA_NETWORK_BACK_RESTART" const val ACTION_STOP = "ACTION_STOP" } diff --git a/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt b/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt index 7874d0237f..169fd9ecac 100755 --- a/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt +++ b/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt @@ -74,7 +74,7 @@ object FcmHelper { when (vectorPreferences.getFdroidSyncBackgroundMode()) { BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY -> { // we rely on periodic worker - Timber.i("## Sync: Work scheduled to periodically sync") + Timber.i("## Sync: Work scheduled to periodically sync in ${vectorPreferences.backgroundSyncDelay()} sec") activeSessionHolder .getSafeActiveSession() ?.startAutomaticBackgroundSync( diff --git a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt index bbd8487ae5..bf78d5b7fb 100644 --- a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt +++ b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt @@ -21,11 +21,21 @@ import android.app.PendingIntent import android.content.Context import android.content.Intent import android.os.Build +import androidx.core.content.ContextCompat.getSystemService import androidx.core.content.getSystemService +import androidx.work.Constraints +import androidx.work.Data +import androidx.work.NetworkType +import androidx.work.OneTimeWorkRequestBuilder +import androidx.work.WorkManager +import androidx.work.WorkRequest +import androidx.work.Worker +import androidx.work.WorkerParameters import im.vector.app.R import im.vector.app.core.extensions.vectorComponent import im.vector.app.features.notifications.NotificationUtils import org.matrix.android.sdk.internal.session.sync.job.SyncService +import timber.log.Timber class VectorSyncService : SyncService() { @@ -48,6 +58,16 @@ class VectorSyncService : SyncService() { } } + fun newPeriodicNetworkBackIntent(context: Context, sessionId: String, timeoutSeconds: Int, delayInSeconds: Int): Intent { + return Intent(context, VectorSyncService::class.java).also { + it.putExtra(EXTRA_SESSION_ID, sessionId) + it.putExtra(EXTRA_TIMEOUT_SECONDS, timeoutSeconds) + it.putExtra(EXTRA_PERIODIC, true) + it.putExtra(EXTRA_DELAY_SECONDS, delayInSeconds) + it.putExtra(EXTRA_NETWORK_BACK_RESTART, true) + } + } + fun stopIntent(context: Context): Intent { return Intent(context, VectorSyncService::class.java).also { it.action = ACTION_STOP @@ -76,6 +96,28 @@ class VectorSyncService : SyncService() { reschedule(sessionId, timeout, delay) } + override fun onNetworkError(sessionId: String, isInitialSync: Boolean, timeout: Int, delay: Int) { + Timber.d("## Sync: A network error occured during sync") + val uploadWorkRequest: WorkRequest = + OneTimeWorkRequestBuilder() + .setInputData(Data.Builder() + .putString("sessionId", sessionId) + .putInt("timeout", timeout) + .putInt("delay", delay) + .build() + ) + .setConstraints(Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() + ) + .build() + + Timber.d("## Sync: Schedule a work to restart service when network will be on") + WorkManager + .getInstance(applicationContext) + .enqueue(uploadWorkRequest) + } + override fun onDestroy() { removeForegroundNotification() super.onDestroy() @@ -100,4 +142,28 @@ class VectorSyncService : SyncService() { alarmMgr.set(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent) } } + + class RestartWhenNetworkOn(appContext: Context, workerParams: WorkerParameters) : + Worker(appContext, workerParams) { + override fun doWork(): Result { + val sessionId = inputData.getString("sessionId") ?: return Result.failure() + val timeout = inputData.getInt("timeout", 6) + val delay = inputData.getInt("delay", 60) + + val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + PendingIntent.getForegroundService(applicationContext, 0, newPeriodicNetworkBackIntent(applicationContext, sessionId, timeout, delay), 0) + } else { + PendingIntent.getService(applicationContext, 0, newPeriodicNetworkBackIntent(applicationContext, sessionId, timeout, delay), 0) + } + val firstMillis = System.currentTimeMillis() + delay * 1000L + val alarmMgr = getSystemService(applicationContext, AlarmManager::class.java)!! + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent) + } else { + alarmMgr.set(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent) + } + // Indicate whether the work finished successfully with the Result + return Result.success() + } + } } From 8ac3af327b16745283d05b424f269c8522e176a9 Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 9 Sep 2020 11:35:33 +0200 Subject: [PATCH 28/89] Update change log --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index eada6082b9..00966ef2d5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ Features ✨: Improvements 🙌: - Handle date formatting properly (show time am/pm if needed, display year when needed) + - Improve F-Droid Notification (#2055) Bugfix 🐛: - Clear the notification when the event is read elsewhere (#1822) From f4c4e84ffef55ea999fe612ea267464b61f80e86 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 10 Sep 2020 17:13:11 +0200 Subject: [PATCH 29/89] Fix false positive from code quality analysis --- tools/check/forbidden_strings_in_code.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index ebe877b301..3ced7de7e2 100644 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -151,7 +151,7 @@ android\.app\.AlertDialog new Gson\(\) ### Use matrixOneTimeWorkRequestBuilder -import androidx.work.OneTimeWorkRequestBuilder===1 +import androidx.work.OneTimeWorkRequestBuilder===2 ### Use TextUtils.formatFileSize Formatter\.formatFileSize===1 @@ -164,7 +164,7 @@ Formatter\.formatShortFileSize===1 # android\.text\.TextUtils ### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If it is ok, change the value in file forbidden_strings_in_code.txt -enum class===77 +enum class===78 ### Do not import temporary legacy classes import org.matrix.android.sdk.internal.legacy.riot===3 From 23f13b092ff82a15a1c3eebac8e64eefc3e5d870 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 10 Sep 2020 18:00:06 +0200 Subject: [PATCH 30/89] Plurals --- .../VectorSettingsNotificationPreferenceFragment.kt | 6 +----- vector/src/main/res/values/strings.xml | 4 ++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt index 21895e15b6..81036e64e1 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt @@ -161,11 +161,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( * @return the text */ private fun secondsToText(seconds: Int): String { - return if (seconds > 1) { - seconds.toString() + " " + getString(R.string.settings_seconds) - } else { - seconds.toString() + " " + getString(R.string.settings_second) - } + return resources.getQuantityString(R.plurals.seconds, seconds, seconds) } private fun handleSystemPreference() { diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index c191b17f7e..1ed36e4228 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -815,6 +815,10 @@ Delay between each Sync second seconds + + %d second + %d seconds + Version olm version From 4dc28a9d6287378aca74562b9f504fe8ef9a8259 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 10 Sep 2020 18:08:35 +0200 Subject: [PATCH 31/89] Reorder settings --- .../res/xml/vector_settings_notifications.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/vector/src/main/res/xml/vector_settings_notifications.xml b/vector/src/main/res/xml/vector_settings_notifications.xml index 52333dd81a..983ddf36f2 100644 --- a/vector/src/main/res/xml/vector_settings_notifications.xml +++ b/vector/src/main/res/xml/vector_settings_notifications.xml @@ -62,15 +62,6 @@ - - - - - - + + + + + + From db977b8109a8e305b31202327a88e71836ba7467 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 11 Sep 2020 09:43:10 +0200 Subject: [PATCH 32/89] Simplify Dialog UI and code --- .../BackgroundSyncModeChooserDialog.kt | 145 +++--------------- .../layout/dialog_background_sync_mode.xml | 84 +++++++++- .../layout/item_custom_dialog_radio_line.xml | 57 ------- 3 files changed, 103 insertions(+), 183 deletions(-) delete mode 100644 vector/src/main/res/layout/item_custom_dialog_radio_line.xml diff --git a/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncModeChooserDialog.kt b/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncModeChooserDialog.kt index 079be58fbc..8b45a06f23 100644 --- a/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncModeChooserDialog.kt +++ b/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncModeChooserDialog.kt @@ -17,147 +17,52 @@ package im.vector.app.features.settings import android.app.Dialog -import android.content.Context import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup -import android.widget.ArrayAdapter -import android.widget.ListView -import android.widget.RadioButton -import android.widget.TextView import androidx.appcompat.app.AlertDialog -import androidx.core.view.isVisible import androidx.fragment.app.DialogFragment -import androidx.fragment.app.FragmentActivity import im.vector.app.R class BackgroundSyncModeChooserDialog : DialogFragment() { - var interactionListener: InteractionListener? = null + private var interactionListener: InteractionListener? = null override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - return activity?.let { activity: FragmentActivity -> - val builder = AlertDialog.Builder(activity) - // Get the layout inflater - val inflater = activity.layoutInflater + val initialMode = BackgroundSyncMode.fromString(arguments?.getString(ARG_INITIAL_MODE)) - // Inflate and set the layout for the dialog - // Pass null as the parent view because its going in the dialog layout - val view = inflater.inflate(R.layout.dialog_background_sync_mode, null) - view.findViewById(R.id.dialog_background_sync_list)?.let { - it.adapter = Adapter( - activity, - BackgroundSyncMode.fromString(arguments?.getString(ARG_INITIAL_MODE)) - ) - } - builder.setView(view) - // Add action buttons - .setPositiveButton(R.string.ok) { dialog, _ -> - val mode = getSelectedOption() - if (mode.name == arguments?.getString(ARG_INITIAL_MODE)) { - // it's like a cancel, no changes - dialog.cancel() - } else { - interactionListener?.onOptionSelected(mode) - dialog.dismiss() - } - } - .setNegativeButton(R.string.cancel) { dialog, _ -> - interactionListener?.onCancel() - dialog.cancel() - } - builder.create() - } ?: throw IllegalStateException("Activity cannot be null") - } + val view = requireActivity().layoutInflater.inflate(R.layout.dialog_background_sync_mode, null) + val dialog = AlertDialog.Builder(requireActivity()) + .setTitle(R.string.settings_background_fdroid_sync_mode) + .setView(view) + .setPositiveButton(R.string.cancel, null) + .create() - private fun getSelectedOption(): BackgroundSyncMode { - options.forEach { - if (it.isSelected) return it.mode + view.findViewById(R.id.backgroundSyncModeBattery).setOnClickListener { + interactionListener + ?.takeIf { initialMode != BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY } + ?.onOptionSelected(BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY) + dialog.dismiss() } - // an item is always selected, should not happen - return options[0].mode - } - - data class SyncMode(val mode: BackgroundSyncMode, val title: Int, val description: Int, var isSelected: Boolean) - - private class Adapter(context: Context, val initialMode: BackgroundSyncMode) : ArrayAdapter(context, 0, options) { - init { - // mark the currently selected option - var initialModeFound = false - options.forEach { - it.isSelected = initialMode == it.mode - initialModeFound = true - } - if (!initialModeFound) { - options[0].isSelected = true - } + view.findViewById(R.id.backgroundSyncModeReal).setOnClickListener { + interactionListener + ?.takeIf { initialMode != BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME } + ?.onOptionSelected(BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME) + dialog.dismiss() } - - override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { - val syncMode = getItem(position)!! - - // Only 3 items, let's keep it like that - val itemView = convertView - ?: LayoutInflater.from(context).inflate(R.layout.item_custom_dialog_radio_line, parent, false) - - // Lookup view for data population - itemView?.findViewById(R.id.item_generic_title_text)?.let { - it.text = context.getString(syncMode.title) - } - itemView?.findViewById(R.id.item_generic_description_text)?.let { - it.text = context.getString(syncMode.description) - it.isVisible = true - } - itemView?.findViewById(R.id.item_generic_radio)?.let { - it.isChecked = syncMode.isSelected - it.isVisible = true - // let the item click handle that - it.setOnClickListener { - toggleChangeAtPosition(position) - } - } - - itemView?.setOnClickListener { - toggleChangeAtPosition(position) - } - - // Populate the data into the template view using the data object - - return itemView - } - - private fun toggleChangeAtPosition(position: Int) { - if (getItem(position)?.isSelected == true) { - // nop - } else { - for (i in 0 until count) { - // we change the single selection - getItem(i)?.isSelected = i == position - } - notifyDataSetChanged() - } + view.findViewById(R.id.backgroundSyncModeOff).setOnClickListener { + interactionListener + ?.takeIf { initialMode != BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED } + ?.onOptionSelected(BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED) + dialog.dismiss() } + return dialog } interface InteractionListener { - fun onCancel() {} - fun onOptionSelected(mode: BackgroundSyncMode) {} + fun onOptionSelected(mode: BackgroundSyncMode) } companion object { - private val options = listOf( - SyncMode(BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY, - R.string.settings_background_fdroid_sync_mode_battery, - R.string.settings_background_fdroid_sync_mode_battery_description, false), - SyncMode(BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME, - R.string.settings_background_fdroid_sync_mode_real_time, - R.string.settings_background_fdroid_sync_mode_real_time_description, false), - SyncMode(BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED, - R.string.settings_background_fdroid_sync_mode_disabled, - R.string.settings_background_fdroid_sync_mode_disabled_description, false) - ) - private const val ARG_INITIAL_MODE = "ARG_INITIAL_MODE" fun newInstance(selectedMode: BackgroundSyncMode, interactionListener: InteractionListener): BackgroundSyncModeChooserDialog { diff --git a/vector/src/main/res/layout/dialog_background_sync_mode.xml b/vector/src/main/res/layout/dialog_background_sync_mode.xml index 89b2aaefde..1ddaa3a3f6 100644 --- a/vector/src/main/res/layout/dialog_background_sync_mode.xml +++ b/vector/src/main/res/layout/dialog_background_sync_mode.xml @@ -1,13 +1,85 @@ - - + android:orientation="vertical"> - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vector/src/main/res/layout/item_custom_dialog_radio_line.xml b/vector/src/main/res/layout/item_custom_dialog_radio_line.xml deleted file mode 100644 index 17d7be08ed..0000000000 --- a/vector/src/main/res/layout/item_custom_dialog_radio_line.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - From c2be97741e78780339dfe399abd862596d5500e3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 11 Sep 2020 10:12:56 +0200 Subject: [PATCH 33/89] Restore listener after device rotation --- .../BackgroundSyncModeChooserDialog.kt | 5 +- ...rSettingsNotificationPreferenceFragment.kt | 49 ++++++++++--------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncModeChooserDialog.kt b/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncModeChooserDialog.kt index 8b45a06f23..59b8569c1e 100644 --- a/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncModeChooserDialog.kt +++ b/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncModeChooserDialog.kt @@ -25,7 +25,7 @@ import im.vector.app.R class BackgroundSyncModeChooserDialog : DialogFragment() { - private var interactionListener: InteractionListener? = null + var interactionListener: InteractionListener? = null override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val initialMode = BackgroundSyncMode.fromString(arguments?.getString(ARG_INITIAL_MODE)) @@ -65,9 +65,8 @@ class BackgroundSyncModeChooserDialog : DialogFragment() { companion object { private const val ARG_INITIAL_MODE = "ARG_INITIAL_MODE" - fun newInstance(selectedMode: BackgroundSyncMode, interactionListener: InteractionListener): BackgroundSyncModeChooserDialog { + fun newInstance(selectedMode: BackgroundSyncMode): BackgroundSyncModeChooserDialog { val frag = BackgroundSyncModeChooserDialog() - frag.interactionListener = interactionListener val args = Bundle() args.putString(ARG_INITIAL_MODE, selectedMode.name) frag.arguments = args diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt index 81036e64e1..62ecc606c4 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt @@ -47,7 +47,8 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( private val pushManager: PushersManager, private val activeSessionHolder: ActiveSessionHolder, private val vectorPreferences: VectorPreferences -) : VectorSettingsBaseFragment() { +) : VectorSettingsBaseFragment(), + BackgroundSyncModeChooserDialog.InteractionListener { override var titleRes: Int = R.string.settings_notifications override val preferenceXmlRes = R.xml.vector_settings_notifications @@ -73,28 +74,10 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( findPreference(VectorPreferences.SETTINGS_FDROID_BACKGROUND_SYNC_MODE)?.let { it.onPreferenceClickListener = Preference.OnPreferenceClickListener { val initialMode = vectorPreferences.getFdroidSyncBackgroundMode() - val dialogFragment = BackgroundSyncModeChooserDialog.newInstance( - initialMode, - object : BackgroundSyncModeChooserDialog.InteractionListener { - override fun onOptionSelected(mode: BackgroundSyncMode) { - // option has change, need to act - if (mode == BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME) { - // Important, Battery optim white listing is needed in this mode; - // Even if using foreground service with foreground notif, it stops to work - // in doze mode for certain devices :/ - if (!isIgnoringBatteryOptimizations(requireContext())) { - requestDisablingBatteryOptimization(requireActivity(), - this@VectorSettingsNotificationPreferenceFragment, - REQUEST_BATTERY_OPTIMIZATION) - } - } - vectorPreferences.setFdroidSyncBackgroundMode(mode) - refreshBackgroundSyncPrefs() - } - } - ) - activity?.supportFragmentManager?.let { - dialogFragment.show(it, "syncDialog") + val dialogFragment = BackgroundSyncModeChooserDialog.newInstance(initialMode) + dialogFragment.interactionListener = this + activity?.supportFragmentManager?.let {fm -> + dialogFragment.show(fm, "syncDialog") } true } @@ -131,6 +114,23 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( handleSystemPreference() } + // BackgroundSyncModeChooserDialog.InteractionListener + override fun onOptionSelected(mode: BackgroundSyncMode) { + // option has change, need to act + if (mode == BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME) { + // Important, Battery optim white listing is needed in this mode; + // Even if using foreground service with foreground notif, it stops to work + // in doze mode for certain devices :/ + if (!isIgnoringBatteryOptimizations(requireContext())) { + requestDisablingBatteryOptimization(requireActivity(), + this@VectorSettingsNotificationPreferenceFragment, + REQUEST_BATTERY_OPTIMIZATION) + } + } + vectorPreferences.setFdroidSyncBackgroundMode(mode) + refreshBackgroundSyncPrefs() + } + private fun refreshBackgroundSyncPrefs() { findPreference(VectorPreferences.SETTINGS_FDROID_BACKGROUND_SYNC_MODE)?.let { it.summary = when (vectorPreferences.getFdroidSyncBackgroundMode()) { @@ -251,6 +251,9 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( if (context is VectorSettingsFragmentInteractionListener) { interactionListener = context } + (activity?.supportFragmentManager + ?.findFragmentByTag("syncDialog") as BackgroundSyncModeChooserDialog?) + ?.interactionListener = this } override fun onDetach() { From e997610ef2e1111c758f440d2e4d94ce5ef7667d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 11 Sep 2020 10:33:20 +0200 Subject: [PATCH 34/89] Add documentation from PR description --- .../app/features/settings/BackgroundSyncMode.kt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncMode.kt b/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncMode.kt index f266060053..2dcb663fc1 100644 --- a/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncMode.kt +++ b/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncMode.kt @@ -16,9 +16,26 @@ package im.vector.app.features.settings +/** + * Different strategies for Background sync, only applicable to F-Droid version of the app + */ enum class BackgroundSyncMode { + /** + * In this mode background syncs are scheduled via Workers, meaning that the system will have control on the periodicity + * of syncs when battery is low or when the phone is idle (sync will occur in allowed maintenance windows). After completion + * the sync work will schedule another one. + */ FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY, + + /** + * This mode requires the app to be exempted from battery optimization. Alarms will be launched and will wake up the app + * in order to perform the background sync as a foreground service. After completion the service will schedule another alarm + */ FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME, + + /** + * The app won't sync in background + */ FDROID_BACKGROUND_SYNC_MODE_DISABLED; companion object { From da09df0e4227acc07f28080e38685bd6fe50a6c0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 11 Sep 2020 10:49:54 +0200 Subject: [PATCH 35/89] format --- .../settings/VectorSettingsNotificationPreferenceFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt index 62ecc606c4..61dbe1705e 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt @@ -76,7 +76,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( val initialMode = vectorPreferences.getFdroidSyncBackgroundMode() val dialogFragment = BackgroundSyncModeChooserDialog.newInstance(initialMode) dialogFragment.interactionListener = this - activity?.supportFragmentManager?.let {fm -> + activity?.supportFragmentManager?.let { fm -> dialogFragment.show(fm, "syncDialog") } true From 7efc58cb4256be2d3a36cd141705df00e2c057b3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 11 Sep 2020 11:02:54 +0200 Subject: [PATCH 36/89] Avoid duplication of code and fix issue on OnApplicationUpgradeOrRebootReceiver: background starts even if notification are disabled --- .../matrix/android/sdk/api/session/Session.kt | 2 +- .../app/fdroid/BackgroundSyncStarter.kt | 52 +++++++++++++++++++ .../OnApplicationUpgradeOrRebootReceiver.kt | 26 +++------- .../java/im/vector/app/push/fcm/FcmHelper.kt | 27 +--------- 4 files changed, 61 insertions(+), 46 deletions(-) create mode 100644 vector/src/fdroid/java/im/vector/app/fdroid/BackgroundSyncStarter.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt index f5b10a5645..4dfc24ddae 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt @@ -110,7 +110,7 @@ interface Session : * This does not work in doze mode :/ * If battery optimization is on it can work in app standby but that's all :/ */ - fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long = 30L) + fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long) fun stopAnyBackgroundSync() diff --git a/vector/src/fdroid/java/im/vector/app/fdroid/BackgroundSyncStarter.kt b/vector/src/fdroid/java/im/vector/app/fdroid/BackgroundSyncStarter.kt new file mode 100644 index 0000000000..7221e2b065 --- /dev/null +++ b/vector/src/fdroid/java/im/vector/app/fdroid/BackgroundSyncStarter.kt @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 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 im.vector.app.fdroid + +import android.content.Context +import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.fdroid.receiver.AlarmSyncBroadcastReceiver +import im.vector.app.features.settings.BackgroundSyncMode +import im.vector.app.features.settings.VectorPreferences +import timber.log.Timber + +object BackgroundSyncStarter { + fun start(context: Context, vectorPreferences: VectorPreferences, activeSessionHolder: ActiveSessionHolder) { + if (vectorPreferences.areNotificationEnabledForDevice()) { + val activeSession = activeSessionHolder.getSafeActiveSession() ?: return + + when (vectorPreferences.getFdroidSyncBackgroundMode()) { + BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY -> { + // we rely on periodic worker + Timber.i("## Sync: Work scheduled to periodically sync in ${vectorPreferences.backgroundSyncDelay()}s") + activeSession.startAutomaticBackgroundSync( + vectorPreferences.backgroundSyncTimeOut().toLong(), + vectorPreferences.backgroundSyncDelay().toLong() + ) + } + BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME -> { + // We need to use alarm in this mode + AlarmSyncBroadcastReceiver.scheduleAlarm(context, activeSession.sessionId, vectorPreferences.backgroundSyncDelay()) + Timber.i("## Sync: Alarm scheduled to start syncing") + } + BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED -> { + // we do nothing + Timber.i("## Sync: background sync is disabled") + } + } + } + } +} diff --git a/vector/src/fdroid/java/im/vector/app/fdroid/receiver/OnApplicationUpgradeOrRebootReceiver.kt b/vector/src/fdroid/java/im/vector/app/fdroid/receiver/OnApplicationUpgradeOrRebootReceiver.kt index 2460e149a5..797b5734a2 100644 --- a/vector/src/fdroid/java/im/vector/app/fdroid/receiver/OnApplicationUpgradeOrRebootReceiver.kt +++ b/vector/src/fdroid/java/im/vector/app/fdroid/receiver/OnApplicationUpgradeOrRebootReceiver.kt @@ -22,7 +22,7 @@ import android.content.Context import android.content.Intent import im.vector.app.core.di.HasVectorInjector import im.vector.app.core.extensions.vectorComponent -import im.vector.app.features.settings.BackgroundSyncMode +import im.vector.app.fdroid.BackgroundSyncStarter import timber.log.Timber class OnApplicationUpgradeOrRebootReceiver : BroadcastReceiver() { @@ -31,25 +31,11 @@ class OnApplicationUpgradeOrRebootReceiver : BroadcastReceiver() { Timber.v("## onReceive() ${intent.action}") val appContext = context.applicationContext if (appContext is HasVectorInjector) { - val activeSession = appContext.injector().activeSessionHolder().getSafeActiveSession() - val preferences = appContext.vectorComponent().vectorPreferences() - if (activeSession != null) { - when (preferences.getFdroidSyncBackgroundMode()) { - BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY -> { - Timber.i("## Sync: OnBoot Work scheduled to periodically sync") - activeSession.startAutomaticBackgroundSync( - preferences.backgroundSyncTimeOut().toLong(), - preferences.backgroundSyncDelay().toLong() - ) - } - BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME -> { - AlarmSyncBroadcastReceiver.scheduleAlarm(context, activeSession.sessionId, preferences.backgroundSyncDelay()) - } - BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED -> { - // nop - } - } - } + BackgroundSyncStarter.start( + context, + appContext.vectorComponent().vectorPreferences(), + appContext.injector().activeSessionHolder() + ) } } } diff --git a/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt b/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt index 169fd9ecac..5f0ee396ee 100755 --- a/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt +++ b/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt @@ -22,10 +22,9 @@ import android.app.Activity import android.content.Context import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.pushers.PushersManager +import im.vector.app.fdroid.BackgroundSyncStarter import im.vector.app.fdroid.receiver.AlarmSyncBroadcastReceiver -import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.VectorPreferences -import timber.log.Timber /** * This class has an alter ego in the gplay variant. @@ -69,28 +68,6 @@ object FcmHelper { } fun onEnterBackground(context: Context, vectorPreferences: VectorPreferences, activeSessionHolder: ActiveSessionHolder) { - // We need to use alarm in this mode - if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) { - when (vectorPreferences.getFdroidSyncBackgroundMode()) { - BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY -> { - // we rely on periodic worker - Timber.i("## Sync: Work scheduled to periodically sync in ${vectorPreferences.backgroundSyncDelay()} sec") - activeSessionHolder - .getSafeActiveSession() - ?.startAutomaticBackgroundSync( - vectorPreferences.backgroundSyncTimeOut().toLong(), - vectorPreferences.backgroundSyncDelay().toLong() - ) - } - BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME -> { - val currentSession = activeSessionHolder.getActiveSession() - AlarmSyncBroadcastReceiver.scheduleAlarm(context, currentSession.sessionId, vectorPreferences.backgroundSyncDelay()) - Timber.i("## Sync: Alarm scheduled to start syncing") - } - BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED -> { - // we do nothing - } - } - } + BackgroundSyncStarter.start(context, vectorPreferences, activeSessionHolder) } } From 2ed7be243b7ecc034fc66e08e2175f5f50137c3e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 11 Sep 2020 11:21:37 +0200 Subject: [PATCH 37/89] Restore TestBatteryOptimization --- .../troubleshoot/TestBatteryOptimization.kt | 21 ++++++++++--------- ...ificationTroubleshootTestManagerFactory.kt | 5 ++++- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/vector/src/fdroid/java/im/vector/app/fdroid/features/settings/troubleshoot/TestBatteryOptimization.kt b/vector/src/fdroid/java/im/vector/app/fdroid/features/settings/troubleshoot/TestBatteryOptimization.kt index 19a6870b2b..510ade0a33 100644 --- a/vector/src/fdroid/java/im/vector/app/fdroid/features/settings/troubleshoot/TestBatteryOptimization.kt +++ b/vector/src/fdroid/java/im/vector/app/fdroid/features/settings/troubleshoot/TestBatteryOptimization.kt @@ -15,29 +15,30 @@ */ package im.vector.app.fdroid.features.settings.troubleshoot -import androidx.fragment.app.Fragment +import androidx.appcompat.app.AppCompatActivity import im.vector.app.R +import im.vector.app.core.resources.StringProvider import im.vector.app.core.utils.isIgnoringBatteryOptimizations import im.vector.app.core.utils.requestDisablingBatteryOptimization import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager import im.vector.app.features.settings.troubleshoot.TroubleshootTest +import javax.inject.Inject -// Not used anymore -class TestBatteryOptimization(val fragment: Fragment) : TroubleshootTest(R.string.settings_troubleshoot_test_battery_title) { +class TestBatteryOptimization @Inject constructor( + private val context: AppCompatActivity, + private val stringProvider: StringProvider +) : TroubleshootTest(R.string.settings_troubleshoot_test_battery_title) { override fun perform() { - val context = fragment.context - if (context != null && isIgnoringBatteryOptimizations(context)) { - description = fragment.getString(R.string.settings_troubleshoot_test_battery_success) + if (isIgnoringBatteryOptimizations(context)) { + description = stringProvider.getString(R.string.settings_troubleshoot_test_battery_success) status = TestStatus.SUCCESS quickFix = null } else { - description = fragment.getString(R.string.settings_troubleshoot_test_battery_failed) + description = stringProvider.getString(R.string.settings_troubleshoot_test_battery_failed) quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_battery_quickfix) { override fun doFix() { - fragment.activity?.let { - requestDisablingBatteryOptimization(it, fragment, NotificationTroubleshootTestManager.REQ_CODE_FIX) - } + requestDisablingBatteryOptimization(context, null, NotificationTroubleshootTestManager.REQ_CODE_FIX) } } status = TestStatus.FAILED diff --git a/vector/src/fdroid/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt b/vector/src/fdroid/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt index ce9bad6c26..65b8609446 100644 --- a/vector/src/fdroid/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt +++ b/vector/src/fdroid/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt @@ -18,6 +18,7 @@ package im.vector.app.push.fcm import androidx.fragment.app.Fragment import im.vector.app.fdroid.features.settings.troubleshoot.TestAutoStartBoot import im.vector.app.fdroid.features.settings.troubleshoot.TestBackgroundRestrictions +import im.vector.app.fdroid.features.settings.troubleshoot.TestBatteryOptimization import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager import im.vector.app.features.settings.troubleshoot.TestAccountSettings import im.vector.app.features.settings.troubleshoot.TestDeviceSettings @@ -30,7 +31,8 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor(private val private val testDeviceSettings: TestDeviceSettings, private val testPushRulesSettings: TestPushRulesSettings, private val testAutoStartBoot: TestAutoStartBoot, - private val testBackgroundRestrictions: TestBackgroundRestrictions) { + private val testBackgroundRestrictions: TestBackgroundRestrictions, + private val testBatteryOptimization: TestBatteryOptimization) { fun create(fragment: Fragment): NotificationTroubleshootTestManager { val mgr = NotificationTroubleshootTestManager(fragment) @@ -40,6 +42,7 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor(private val mgr.addTest(testPushRulesSettings) mgr.addTest(testAutoStartBoot) mgr.addTest(testBackgroundRestrictions) + mgr.addTest(testBatteryOptimization) return mgr } } From b26d379d20603a9150a095fe02898e57e88c8572 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 11 Sep 2020 11:49:14 +0200 Subject: [PATCH 38/89] Refresh push pref after diagnostic --- ...VectorSettingsNotificationPreferenceFragment.kt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt index 61dbe1705e..e7b9c3cb2a 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt @@ -88,7 +88,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( it.summary = secondsToText(vectorPreferences.backgroundSyncTimeOut()) it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> if (newValue is String) { - val syncTimeout = tryThis { Integer.parseInt(newValue) } ?: 6 + val syncTimeout = tryThis { Integer.parseInt(newValue) } ?: 6 vectorPreferences.setBackgroundSyncTimeout(maxOf(0, syncTimeout)) refreshBackgroundSyncPrefs() } @@ -101,7 +101,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( it.summary = secondsToText(vectorPreferences.backgroundSyncDelay()) it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> if (newValue is String) { - val syncDelay = tryThis { Integer.parseInt(newValue) } ?: 6 + val syncDelay = tryThis { Integer.parseInt(newValue) } ?: 6 vectorPreferences.setBackgroundSyncDelay(maxOf(0, syncDelay)) refreshBackgroundSyncPrefs() } @@ -244,6 +244,16 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( val preference = findPreference(key) preference?.isHighlighted = true } + + refreshPref() + } + + private fun refreshPref() { + // This pref may have change from troubleshoot pref fragment + if (!FcmHelper.isPushSupported()) { + findPreference(VectorPreferences.SETTINGS_START_ON_BOOT_PREFERENCE_KEY) + ?.isChecked = vectorPreferences.autoStartOnBoot() + } } override fun onAttach(context: Context) { From 8abff412d05229477c1560ac9e39ee007ee77b25 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 11 Sep 2020 11:56:25 +0200 Subject: [PATCH 39/89] Create constant for default value and so fix a bug when setting bad value for delay. --- .../im/vector/app/features/settings/BackgroundSyncMode.kt | 3 +++ .../im/vector/app/features/settings/VectorPreferences.kt | 8 ++++---- .../VectorSettingsNotificationPreferenceFragment.kt | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncMode.kt b/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncMode.kt index 2dcb663fc1..9d8b5755b0 100644 --- a/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncMode.kt +++ b/vector/src/main/java/im/vector/app/features/settings/BackgroundSyncMode.kt @@ -39,6 +39,9 @@ enum class BackgroundSyncMode { FDROID_BACKGROUND_SYNC_MODE_DISABLED; companion object { + const val DEFAULT_SYNC_DELAY_SECONDS = 60 + const val DEFAULT_SYNC_TIMEOUT_SECONDS = 6 + fun fromString(value: String?): BackgroundSyncMode = values().firstOrNull { it.name == value } ?: FDROID_BACKGROUND_SYNC_MODE_DISABLED } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index 2239efa992..7415b57310 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -837,8 +837,8 @@ class VectorPreferences @Inject constructor(private val context: Context) { fun backgroundSyncTimeOut(): Int { return tryThis { // The xml pref is saved as a string so use getString and parse - defaultPrefs.getString(SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY, "6")?.toInt() - } ?: 6 + defaultPrefs.getString(SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY, null)?.toInt() + } ?: BackgroundSyncMode.DEFAULT_SYNC_TIMEOUT_SECONDS } fun setBackgroundSyncTimeout(timeInSecond: Int) { @@ -851,8 +851,8 @@ class VectorPreferences @Inject constructor(private val context: Context) { fun backgroundSyncDelay(): Int { return tryThis { // The xml pref is saved as a string so use getString and parse - defaultPrefs.getString(SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY, "60")?.toInt() - } ?: 60 + defaultPrefs.getString(SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY, null)?.toInt() + } ?: BackgroundSyncMode.DEFAULT_SYNC_DELAY_SECONDS } fun setBackgroundSyncDelay(timeInSecond: Int) { diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt index e7b9c3cb2a..3f74c4db75 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationPreferenceFragment.kt @@ -88,7 +88,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( it.summary = secondsToText(vectorPreferences.backgroundSyncTimeOut()) it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> if (newValue is String) { - val syncTimeout = tryThis { Integer.parseInt(newValue) } ?: 6 + val syncTimeout = tryThis { Integer.parseInt(newValue) } ?: BackgroundSyncMode.DEFAULT_SYNC_TIMEOUT_SECONDS vectorPreferences.setBackgroundSyncTimeout(maxOf(0, syncTimeout)) refreshBackgroundSyncPrefs() } @@ -101,7 +101,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( it.summary = secondsToText(vectorPreferences.backgroundSyncDelay()) it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> if (newValue is String) { - val syncDelay = tryThis { Integer.parseInt(newValue) } ?: 6 + val syncDelay = tryThis { Integer.parseInt(newValue) } ?: BackgroundSyncMode.DEFAULT_SYNC_DELAY_SECONDS vectorPreferences.setBackgroundSyncDelay(maxOf(0, syncDelay)) refreshBackgroundSyncPrefs() } From ef16485eac17bcab55dbf365ad74bfa95ed55822 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Fri, 11 Sep 2020 13:30:00 +0300 Subject: [PATCH 40/89] Always use loudspeaker while ringing and a headset is not connected. --- CHANGES.md | 1 + .../app/features/call/CallAudioManager.kt | 21 ++++++++++++++++--- .../call/WebRtcPeerConnectionManager.kt | 1 + 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index eada6082b9..01fd289038 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ Improvements 🙌: Bugfix 🐛: - Clear the notification when the event is read elsewhere (#1822) + - Speakerphone is not used for ringback tone (#1644, #1645) Translations 🗣: - diff --git a/vector/src/main/java/im/vector/app/features/call/CallAudioManager.kt b/vector/src/main/java/im/vector/app/features/call/CallAudioManager.kt index 2a773c2f9b..9b3c42ab5d 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallAudioManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallAudioManager.kt @@ -24,6 +24,7 @@ import android.content.pm.PackageManager import android.media.AudioManager import androidx.core.content.getSystemService import im.vector.app.core.services.WiredHeadsetStateReceiver +import org.matrix.android.sdk.api.session.call.CallState import org.matrix.android.sdk.api.session.call.MxCall import timber.log.Timber import java.util.concurrent.Executors @@ -116,10 +117,19 @@ class CallAudioManager( // Always disable microphone mute during a WebRTC call. setMicrophoneMute(false) + adjustCurrentSoundDevice(mxCall) + } + + private fun adjustCurrentSoundDevice(mxCall: MxCall) { + val audioManager = audioManager ?: return executor.execute { - // If there are no headset, start video output in speaker - // (you can't watch the video and have the phone close to your ear) - if (mxCall.isVideoCall && !isHeadsetOn()) { + if (mxCall.state == CallState.LocalRinging && !isHeadsetOn()) { + // Always use speaker if incoming call is in ringing state and a headset is not connected + Timber.v("##VOIP: AudioManager default to SPEAKER (it is ringing)") + setCurrentSoundDevice(SoundDevice.SPEAKER) + } else if (mxCall.isVideoCall && !isHeadsetOn()) { + // If there are no headset, start video output in speaker + // (you can't watch the video and have the phone close to your ear) Timber.v("##VOIP: AudioManager default to speaker ") setCurrentSoundDevice(SoundDevice.SPEAKER) } else { @@ -138,6 +148,11 @@ class CallAudioManager( } } + fun onCallConnected(mxCall: MxCall) { + Timber.v("##VOIP: AudioManager call answered, adjusting current sound device") + adjustCurrentSoundDevice(mxCall) + } + fun getAvailableSoundDevices(): List { return ArrayList().apply { if (isBluetoothHeadsetOn()) add(SoundDevice.WIRELESS_HEADSET) diff --git a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt index bb6312a8ce..b53be292c8 100644 --- a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt @@ -858,6 +858,7 @@ class WebRtcPeerConnectionManager @Inject constructor( */ PeerConnection.PeerConnectionState.CONNECTED -> { callContext.mxCall.state = CallState.Connected(newState) + audioManager.onCallConnected(callContext.mxCall) } /** * One or more of the ICE transports on the connection is in the "failed" state. From 3bb2034254899f2cbefd6635b3aa7b6a1fe7754e Mon Sep 17 00:00:00 2001 From: "@a2sc:matrix.org" Date: Wed, 9 Sep 2020 15:03:49 +0000 Subject: [PATCH 41/89] Translated using Weblate (German) Currently translated at 100.0% (1867 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/de/ --- vector/src/main/res/values-de/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml index 2b8ca03ecc..afba1d7fda 100644 --- a/vector/src/main/res/values-de/strings.xml +++ b/vector/src/main/res/values-de/strings.xml @@ -2053,7 +2053,7 @@ Verwahre deinen Wiederherstellungsschlüssel an einem sehr sicheren Ort wie eine Sicherheit Mehr erfahren Mehr - Raum Einstellungen + Raum-Einstellungen Benachrichtigungen Eine Person From ad969b999d3edb37fc1047c4198715fbdc8c847a Mon Sep 17 00:00:00 2001 From: Slimane Selyan AMIRI Date: Thu, 10 Sep 2020 08:28:42 +0000 Subject: [PATCH 42/89] Translated using Weblate (Kabyle) Currently translated at 56.3% (1052 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/kab/ --- vector/src/main/res/values-kab/strings.xml | 199 ++++++++++++++++++++- 1 file changed, 198 insertions(+), 1 deletion(-) diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index a532b40d25..d1119d57cb 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -1325,4 +1325,201 @@ Ur tezmireḍ ara ad tkecmeḍ ɣer yizen-a acku tiɣimit-ik·im ur tt-yeḍmin ara umazan Ur tezmire ara ad tkecmeḍ ɣer yizen-a acku amazan iɛemmed ur d-yuzin ara tisura S tumert meqqren ara ak-d-nini nbeddel isem! Asnas-ik·im yettwaleqqem, ha-t-an tkecmeḍ ɣer umiḍan-ik·im. - +Uṭṭun-a n tilifun yettusbadu yakan. + Awal-ik·im uffir yettuwennez. +\n +\nAql-ak·akem teffɣeḍ seg meṛṛa tiɣimiyin syen ur d-teṭṭifeḍ ara akk ilɣa n Push. I wakken ad talseḍ armad n yilɣa, kcem tikkelt-nniḍen ɣer yal ibenk. + Ajuṭu n unekcum i yettwafernen ur yettwassen ara + JSON ur yemsil ara akken iwata + Aṭas n yisuturen i yettwaznen + Awennez n tkamiṛat d awezɣi + tiririt ɣef usiwel seg wadeg-nniḍen + + "Ur yezmir ara " + + Element yesra tasiregt n unekcum ɣer temkarḍit-inek·inem n tewlafin d tvidyut i tuzna d usekles n tceqqufin yeddan. +\n +\nMa ulac aɣilif sireg anekcum deg yisfuyla udhimen i d-iteddun i wakken ad tizmireḍ ad tazneḍ ifuyla seg tiliɣri-inek·inem. + " +\n +\nMa ulac aɣilif sireg anekcum ɣer isfuyla udhimen i d-iteddun i wakken tizmireḍ ad tessiwleḍ." + Element yesra tasiregt n unekcum ɣer usawaḍ-inek·inem i wakken ad iseddu isawalen s umeslaw. + " +\n +\nMa ulac aɣilif sireg anekcum ɣer isfuyla udhimen i d-iteddun i wakken tizmireḍ ad tessiwleḍ." + "Element yesra tasiregt n unekcum ɣer temkarḍit-inek·inem n tewlafin d tvidyut i tuzna d usekles n tceqqufin yeddan. +\n +\n +\nMa ulac aɣilif sireg anekcum deg yisfuyla udhimen i d-iteddun i wakken ad tizmireḍ ad tazneḍ ifuyla seg tiliɣri-inek·inem. " + Element yezmer ad issenqed adlis-inek·inem n tansiwin i wakken ad d-yaf iseqdacen-nniḍen n Matrix s usenned ɣer yimaylen d wuṭṭunen n tiliɣri nsen. +\n +\nTebɣiḍ ad tebduḍ adlis-inek·inem n tansiwin i yiswi-a\? + + Nesḥassef. Tiggawt-a ur tezmir ara ad d-tili imi llant tsirag i ixuṣṣen + + Sekles i usali\? + Ldi aqerru + Tinubga-a tettwazen i %s, ur ncudd ara ɣer umiḍan-a. +\nIlaq-ak·am ad tkecmeḍ s umiḍan-nniḍen, neɣ rnu imayl-a ɣer umiḍan-ik·im. + Tettaɛraḍeḍ ad tkecmeḍ ɣer %s. Tebɣiḍ ad ternuḍ i wakken ad tettekkiḍ deg udiwenni\? + Tagi d taskant n texxamt-a. Amyigew gar texxamin yensa. + Aseqdac ur yettwazeglen ara + Tiwtilin & tfadiwin + Sentem awal-ik·im uffir + Asesteb yettusra + + Tansiwin n yimayl + Uṭṭunen n tiliɣri + Kkes %s\? + Azal n wulu s uneḍru + + Iɣewwaren n unagraw. + Ilɣa ttwaremden deg yiɣewwaren n unagraw. + Ilɣa ttusensen deg yiɣewwaren n unagraw. +\nMa ulac aɣilif senqed iɣewwaren n unagraw. + Ilɣa ttwaremden i umiḍan-ik·im. + Senqed iɣewwaren + + Asenqed n yimeẓla n tɣuri + Seqɛed imeẓla n tɣuri + + Ajuṭu Firebase + Tiririt n ujuṭu FCM tedda akken ilaq: +\n%1$s + Tiririt n ujuṭu FCM ur teddi ara: +\n%1$s + Asekles n ujuṭu + Démarrer le service + + "Bdu seg usenker " + Swel ilɣa n zzhir + Swel ilɣa n usiwel + Swel ilɣa n tsusmi + "Fren ini, ahuzzu, imesli n LED... " + + + Iznan ideg yella yisem-iw n useqdac + "Iznan deg usqerdec gar sin kan " + Iznan n yisqerdicen n ugraw + Amtawi n ugilal + Askar n umatawi n ugilal (D armitan) + Ulac amtawi n ugilal + "Bdu seg usenker " + Rmed amtawi n ugilal + tasint + tasinin + + Tiwtilin & tfadiwin + Sfeḍ tuffirt + %1$s @ %2$s + Fren tutlayt + + Awalen uffiren ur menṭaḍen ara + + Country + 3 ussan + 1 waggur + Tansiwin + Awgelhen seg yixef ɣer yixef + Dossier + Tuccḍa n uzmak + + Tinubga tamaynut + %1$s: %2$s %3$s + + Nadi amazray + + Hraw ugar + Ahrawan maḍi + Meqqeṛ + + WALI + Rmed iwiǧiten + + + Awiǧit + Sali awiǧit + Awiǧit-a yettwarna sɣur: + Aseqdec-is yezmer ad yesbadu inagan n tuqqna yerna ad yebḍu isefka d %s: + Aseqdec-is yezmer ad yebḍu isefka d %s: + Ur yeddi ara usali n yiwiǧit%s + Ales asali n yiwiǧit + Ldi deg yiminig + Sefesex anekcum i nekk + + Sewḥel kullec + Ixuṣṣ usulay_taxxamt deg usuter. + Ixuṣṣ usulay_aseqdac deg usuter. + Taxxamt %s ur d-tban ara + Aɣewwar yettusran ulac-it. + Aɣewwar mačči d ameɣtu. + Ulac amsefrak n umsidef yettusewlen. + Rnu isnasen n Matrix + Ulac iwiǧiten i yettwaremden + Kcem ɣer texxamt s yisem i d-yettunefken + Ttxil-k sekcem isem n useqdac. + Ttxil-k·m sekcem awal-ik·im uffir: + Adiwenni yettkemmil da + Sit da i wakken ad twaliḍ iznan iqburen + + Talast n yiɣbula tettuɛedda + Nermes anedbal + + Ma ulac aɣilif %s kemmel aseqdec n umeẓlu-a. + + Nesḥassef, tella-d tuccḍa. + + Sken tamnaḍt n telɣut + I tuccḍiwin kan + + Rnu tafyirt tuffirt + Tafyirt tuffirt ur temṣada ara + Ma ulac aɣilif sekcem tafyirt tuffirt + Tafyirt tuffirt ur teǧhid ara aṭas + + Ma ulac aɣilif kkes tafyirt tuffirt ma yella tebɣiḍ Element ad isirew tasarut n tririt. + Ulac tiɣimit n Matrix i yellan + + (Leqqayen) + Sbadu tafyirt tuffirt + Timerna n uḥraz + (Leqqayen) Sbadu s tsarut n tririt + Giɣ tanɣalt + Sekles tasarut n tririt + Enregistrer le fichier + Tasarut n tririt tettwasekles. + + Yella yakan uḥraz deg uqeddac-ik·im agejdan + Ma ulac aɣilif, eg anɣal + Bḍu tasarut n tririt d... + Aḥraz yebda + seqdec tasarut-ik·im n tririt + Tiririt n yizen + + Serreḥ i umazray + Kkes aḥraz... + Aḥraz n tsarut amaynut + Aseɣwen yettwanɣel \'ɣef wafus\' + + Tangalt + Ittraju %s… + Ifuyla yettwaznen + Isefka n umiḍan + Taxtirit yettefernen + Anekcum amaynut + + Sekcem tasarut tuffirt n uḥraz uffir: + Alɣu: + Tisur ttwaleqqment yakan! + + Element Android + + Isutar n tsura + + Ittraju %s… + + Aqeεεed + Afaylu n useqdac + + Kcem %s + From 0c34521791e3b1485b9c0a7a366d69fb7d83165e Mon Sep 17 00:00:00 2001 From: Kahina Messaoudi Date: Thu, 10 Sep 2020 22:00:50 +0000 Subject: [PATCH 43/89] Translated using Weblate (Kabyle) Currently translated at 56.3% (1052 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/kab/ --- vector/src/main/res/values-kab/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index d1119d57cb..0d52e317bb 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -627,7 +627,7 @@ Qqen Imayl neɣ isem n useqdac Isem n useqdac - Tansa n yimayl (d tafrayan) + Tansa imayl (d tafrayant) Uṭṭun n tiliɣri Uṭṭun n tiliɣri (d afrayan) Ales i wawal uffir From 2148411307c73226178ec57a7ee7f95dee301605 Mon Sep 17 00:00:00 2001 From: yuuki-san Date: Thu, 10 Sep 2020 11:44:49 +0000 Subject: [PATCH 44/89] Translated using Weblate (Slovak) Currently translated at 97.6% (164 of 168 strings) Translation: Element Android/Element Android Sdk Translate-URL: https://translate.riot.im/projects/element-android/element-sdk/sk/ --- .../src/main/res/values-sk/strings.xml | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/matrix-sdk-android/src/main/res/values-sk/strings.xml b/matrix-sdk-android/src/main/res/values-sk/strings.xml index da869eacc2..6eeb380ccd 100644 --- a/matrix-sdk-android/src/main/res/values-sk/strings.xml +++ b/matrix-sdk-android/src/main/res/values-sk/strings.xml @@ -71,7 +71,7 @@ %1$s a 1 ďalší %1$s a %2$d ďalší %1$s a %2$d ďalších - + @@ -118,16 +118,16 @@ %1$s vzal/a späť pozvanie %2$s. Dôvod: %3$s - %1$s pridal/a adresu %2$s pre túto miestnosť. - %1$s pridal/a adresy %2$s pre túto miestnosť. - %1$s pridal/a adresy %2$s pre túto miestnosť. - + %1$s pridal/a adresu %2$s pre túto miestnosť. + %1$s pridal/a adresy %2$s pre túto miestnosť. + %1$s pridal/a adresy %2$s pre túto miestnosť. + - %1$s odstránil/a adresu %2$s pre túto miestnosť. - %1$s odstránil/a adresy %3$s pre túto miestnosť. - %1$s odstránil/a adresy %3$s pre túto miestnosť. - + %1$s odstránil/a adresu %2$s pre túto miestnosť. + %1$s odstránil/a adresy %3$s pre túto miestnosť. + %1$s odstránil/a adresy %3$s pre túto miestnosť. + %1$s pridal/a adresy %2$s a odstránil/a adresy %3$s pre túto miestnosť. @@ -208,16 +208,16 @@ Vzali ste späť pozvanie %1$s. Dôvod: %2$s - Pridali ste adresu %1$s pre túto miestnosť. - Pridali ste adresy %1$s pre túto miestnosť. - Pridali ste adresy %1$s pre túto miestnosť. - + Pridali ste adresu %1$s pre túto miestnosť. + Pridali ste adresy %1$s pre túto miestnosť. + Pridali ste adresy %1$s pre túto miestnosť. + - Odstránili ste adresu %1$s pre túto miestnosť. - Odstránili ste adresy %2$s pre túto miestnosť. - Odstránili ste adresy %2$s pre túto miestnosť. - + Odstránili ste adresu %1$s pre túto miestnosť. + Odstránili ste adresy %2$s pre túto miestnosť. + Odstránili ste adresy %2$s pre túto miestnosť. + Pridali ste %1$s a odstránili adresy %2$s pre túto miestnosť. From c274f9b23c1905b8933d3578d033a62e998ee4e8 Mon Sep 17 00:00:00 2001 From: yuuki-san Date: Thu, 10 Sep 2020 11:37:16 +0000 Subject: [PATCH 45/89] Translated using Weblate (Slovak) Currently translated at 100.0% (3 of 3 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.riot.im/projects/element-android/element-store/sk/ --- .../play/listings/sk/full_description.txt | 25 +++++++++---------- .../play/listings/sk/short_description.txt | 2 +- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/vector/src/main/play/listings/sk/full_description.txt b/vector/src/main/play/listings/sk/full_description.txt index 6e3bff2fb5..b4c9e98777 100644 --- a/vector/src/main/play/listings/sk/full_description.txt +++ b/vector/src/main/play/listings/sk/full_description.txt @@ -1,31 +1,30 @@ -Element je inovatívny kolaboračný komunikátor ktorý: +Element je inovatívny kolaboračný komunikátor a messenger ktorý: -1. Ponecháva kontrolu nad zachovaním vašeho súkromia -2. Umožňuje komunikovať s kýmkoľvek v sieti Matrix a vďaka integráciám s aplikáciami napríklad Slack aj s mnohými ďalšími -3. Chráni vás pred reklamami, zhromažďovaním údajov a nedostatkami uzavretých platforiem +1. Ponecháva kontrolu nad vaším súkromím +2. Umožňuje komunikovať s kýmkoľvek v sieti Matrix a vďaka integráciám aj s rôznymi inými aplikáciami ako napríklad Slack +3. Chráni vás pred reklamami, zhromažďovaním údajov a uzavretými platformami 4. Posilňuje vašu bezpečnosť vďaka E2E šifrovaniu a krížovému podpisovaniu určenému na overovanie ostatných - Element sa od ostatných komunikačných a kolaboračných aplikácií odlišuje tým, že je decentralizovaný a open-source. -S elementom sa môžete pripojiť k vlastnému serveru alebo si môžete vybrať dôveryhodného poskytovateľa servera, čím si zachováte súkromie, vlastníctvo a kontrolu nad vašimi konverzáciami a údajmi. Získavate vlastne prístup do otvorenej siete a teda nie ste limitovaní na komunikáciu len s ostatnými Element používateľmi. A samozrejme komunikácia je veľmi bezpečná. +S Elementom sa môžete pripojiť k vlastnému serveru alebo si môžete vybrať server s dôveryhodným poskytovateľom, čím si zachováte súkromie, vlastníctvo a kontrolu nad vašimi konverzáciami a údajmi. Získate tak prístup do otvorenej siete a teda nie ste limitovaní na komunikáciu len s ostatnými Element používateľmi. A samozrejme je vaša komunikácia dobre zabezpečná. Element všetko toto dokáže vďaka tomu, že pracuje podľa protokolu Matrix - štandardu na otvorenú, decentralizovanú komunikáciu. -Element vám dáva kontrolu tým, že si samy vyberiete, ako budete hostovať vaše konverzácie. Priamo v aplikácii Element si môžete vybrať z rôznych spôsobov hostovania: +Element vám dáva kontrolu tým, že si samy vyberiete, ako budete spravovať (ang. host) vaše konverzácie. Priamo v aplikácii Element si môžete vybrať z rôznych spôsobov hostovania: -1. Získajte účet zdarma na verejnom servery matrix.org +1. Získajte účet zdarma na verejnom servery matrix.org od vývojárov protokolu Matrix alebo si vyberte z tísíce iných serverov hostovaných dobrovoľníkmi 2. Hostujte si účet spustením vlastného servera použitím vlastného hardvéru 3. Prihláste sa k účtu na vlastnom servery objednaním služieb na platforme Element Matrix Services -Prečo si vybrať element? +Prečo si vybrať Element? -PONECHAJTE SI VAŠE ÚDAJE: Len vy sa rozhodujete o tom, kde si budete uchovávať vaše správy a ostatné údaje. Len vy vlastníte vaše údaje a riadite zaobchádzanie s nimi, nie nejaká obrovská korporácia, ktorá z nich ťaží alebo k nim poskytuje prístup tretím stranám. +PONECHAJTE SI VAŠE ÚDAJE: Len vy rozhodujete o tom, kde si budete uchovávať vaše správy a ostatné údaje. Len vy vlastníte vaše údaje a riadite zaobchádzanie s nimi, nie nejaká megakorporácia, ktorá z nich ťaží alebo ich poskytuje tretím stranám. -OTVORENÁ KOMUNIKÁCIA a KOLABORÁCIA: Konverzovať môžete s kýmkoľvek v otvorenej sieti Matrix nezávisle na tom, či používa Element alebo inú kompatibilnú aplikáciu, alebo dokonca aj s tými, ktorí používajú iný systém určený na okamžitú komunikáciu ako sú Slack, IRC alebo XMPP. +OTVORENÁ KOMUNIKÁCIA a KOLABORÁCIA: Konverzovať môžete s kýmkoľvek v otvorenej sieti Matrix nezávisle na tom, či používa Element, inú kompatibilnú aplikáciu, ba dokkonca aj s tými, ktorí používajú úplne inú platformu určenú na okamžitú komunikáciu ako sú Slack, IRC alebo XMPP. VEĽMI VYSOKÉ ZABEZPEČENIE: Skutočné šifrovanie od zariadenia k zariadeniu (len diskutujúci môžu dešifrovať správy) a krížové podpisovanie určené na overovanie jednotlivých zariadení členov konverzácií. -KOMPLETNÁ KOMUNIKÁCIA: Okamžité správy, telefonáty a video hovory, zdieľanie súborov, zdieľanie obrazovky a veľké množstvo integrácií, botov a widgetov. Vytvorte si vlastné miestnosti, založte komunity, ostante v kontakte a vyriešte úlohy. +KOMPLETNÁ KOMUNIKÁCIA: Okamžité správy, telefonáty a video hovory, zdieľanie súborov, zdieľanie obrazovky a veľké množstvo integrácií, botov a widgetov. Vytvorte si vlastné miestnosti, založte komunity, ostante v kontakte a vyriešte problémy. -KDEKOĽVEK SA NACHÁDZATE: Ostante v kontakte kdekoľvek práve ste s plne synchronizovanou históriou konverzácií naprieč všetkými vašimi zariadeniami aj cez web na adrese https://app.element.io. +KDEKOĽVEK SA NACHÁDZATE: Ostante v kontakte kdekoľvek ste s plne synchronizovanou históriou konverzácií naprieč všetkými vašimi zariadeniami a aj cez web na adrese https://app.element.io. diff --git a/vector/src/main/play/listings/sk/short_description.txt b/vector/src/main/play/listings/sk/short_description.txt index 171222982d..7d352942bf 100644 --- a/vector/src/main/play/listings/sk/short_description.txt +++ b/vector/src/main/play/listings/sk/short_description.txt @@ -1 +1 @@ -Zabezpečené konverzácie a VoIP. Ochráňte vaše údaje pred zhromažďovaním +Zabezpečené konverzácie a VoIP. Ochráňte vaše údaje pred zhromažďovaním. From ab2a55d417c2f910e47b6dcd996564fe06c2dd49 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 11 Sep 2020 16:24:30 +0200 Subject: [PATCH 46/89] Rename member for code clarity (we also have an AudioManager) --- .../app/features/call/VectorCallViewModel.kt | 12 +++++------ .../call/WebRtcPeerConnectionManager.kt | 20 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt index cee67cd818..97a6f72177 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt @@ -146,7 +146,7 @@ class VectorCallViewModel @AssistedInject constructor( } override fun onAudioDevicesChange(mgr: WebRtcPeerConnectionManager) { - val currentSoundDevice = mgr.audioManager.getCurrentSoundDevice() + val currentSoundDevice = mgr.callAudioManager.getCurrentSoundDevice() if (currentSoundDevice == CallAudioManager.SoundDevice.PHONE) { proximityManager.start() } else { @@ -155,7 +155,7 @@ class VectorCallViewModel @AssistedInject constructor( setState { copy( - availableSoundDevices = mgr.audioManager.getAvailableSoundDevices(), + availableSoundDevices = mgr.callAudioManager.getAvailableSoundDevices(), soundDevice = currentSoundDevice ) } @@ -182,7 +182,7 @@ class VectorCallViewModel @AssistedInject constructor( mxCall.addListener(callStateListener) - val currentSoundDevice = webRtcPeerConnectionManager.audioManager.getCurrentSoundDevice() + val currentSoundDevice = webRtcPeerConnectionManager.callAudioManager.getCurrentSoundDevice() if (currentSoundDevice == CallAudioManager.SoundDevice.PHONE) { proximityManager.start() } @@ -193,7 +193,7 @@ class VectorCallViewModel @AssistedInject constructor( callState = Success(mxCall.state), otherUserMatrixItem = item?.let { Success(it) } ?: Uninitialized, soundDevice = currentSoundDevice, - availableSoundDevices = webRtcPeerConnectionManager.audioManager.getAvailableSoundDevices(), + availableSoundDevices = webRtcPeerConnectionManager.callAudioManager.getAvailableSoundDevices(), isFrontCamera = webRtcPeerConnectionManager.currentCameraType() == CameraType.FRONT, canSwitchCamera = webRtcPeerConnectionManager.canSwitchCamera(), isHD = mxCall.isVideoCall && webRtcPeerConnectionManager.currentCaptureFormat() is CaptureFormat.HD @@ -250,10 +250,10 @@ class VectorCallViewModel @AssistedInject constructor( Unit } is VectorCallViewActions.ChangeAudioDevice -> { - webRtcPeerConnectionManager.audioManager.setCurrentSoundDevice(action.device) + webRtcPeerConnectionManager.callAudioManager.setCurrentSoundDevice(action.device) setState { copy( - soundDevice = webRtcPeerConnectionManager.audioManager.getCurrentSoundDevice() + soundDevice = webRtcPeerConnectionManager.callAudioManager.getCurrentSoundDevice() ) } } diff --git a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt index b53be292c8..916df8892b 100644 --- a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt @@ -23,6 +23,9 @@ import im.vector.app.ActiveSessionDataSource import im.vector.app.core.services.BluetoothHeadsetReceiver import im.vector.app.core.services.CallService import im.vector.app.core.services.WiredHeadsetStateReceiver +import io.reactivex.disposables.Disposable +import io.reactivex.subjects.PublishSubject +import io.reactivex.subjects.ReplaySubject import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.extensions.tryThis import org.matrix.android.sdk.api.session.Session @@ -35,9 +38,6 @@ import org.matrix.android.sdk.api.session.room.model.call.CallAnswerContent import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent -import io.reactivex.disposables.Disposable -import io.reactivex.subjects.PublishSubject -import io.reactivex.subjects.ReplaySubject import org.webrtc.AudioSource import org.webrtc.AudioTrack import org.webrtc.Camera1Enumerator @@ -93,7 +93,7 @@ class WebRtcPeerConnectionManager @Inject constructor( currentCallsListeners.remove(listener) } - val audioManager = CallAudioManager(context.applicationContext) { + val callAudioManager = CallAudioManager(context.applicationContext) { currentCallsListeners.forEach { tryThis { it.onAudioDevicesChange(this) } } @@ -577,7 +577,7 @@ class WebRtcPeerConnectionManager @Inject constructor( fun close() { Timber.v("## VOIP WebRtcPeerConnectionManager close() >") CallService.onNoActiveCall(context) - audioManager.stop() + callAudioManager.stop() val callToEnd = currentCall currentCall = null // This must be done in this thread @@ -631,7 +631,7 @@ class WebRtcPeerConnectionManager @Inject constructor( val createdCall = currentSession?.callSignalingService()?.createOutgoingCall(signalingRoomId, otherUserId, isVideoCall) ?: return val callContext = CallContext(createdCall) - audioManager.startForCall(createdCall) + callAudioManager.startForCall(createdCall) currentCall = callContext val name = currentSession?.getUser(createdCall.otherUserId)?.getBestName() @@ -684,7 +684,7 @@ class WebRtcPeerConnectionManager @Inject constructor( val callContext = CallContext(mxCall) currentCall = callContext - audioManager.startForCall(mxCall) + callAudioManager.startForCall(mxCall) executor.execute { callContext.remoteCandidateSource = ReplaySubject.create() } @@ -798,12 +798,12 @@ class WebRtcPeerConnectionManager @Inject constructor( Timber.v("## VOIP onWiredDeviceEvent $event") currentCall ?: return // sometimes we received un-wanted unplugged... - audioManager.wiredStateChange(event) + callAudioManager.wiredStateChange(event) } fun onWirelessDeviceEvent(event: BluetoothHeadsetReceiver.BTHeadsetPlugEvent) { Timber.v("## VOIP onWirelessDeviceEvent $event") - audioManager.bluetoothStateChange(event.plugged) + callAudioManager.bluetoothStateChange(event.plugged) } override fun onCallAnswerReceived(callAnswerContent: CallAnswerContent) { @@ -858,7 +858,7 @@ class WebRtcPeerConnectionManager @Inject constructor( */ PeerConnection.PeerConnectionState.CONNECTED -> { callContext.mxCall.state = CallState.Connected(newState) - audioManager.onCallConnected(callContext.mxCall) + callAudioManager.onCallConnected(callContext.mxCall) } /** * One or more of the ICE transports on the connection is in the "failed" state. From 236f7f8e282322185c9967ed3c80d311b71cd21a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 11 Sep 2020 16:25:30 +0200 Subject: [PATCH 47/89] Private and typo --- .../app/features/call/VectorCallViewModel.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt index 97a6f72177..77a45628fe 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt @@ -91,23 +91,23 @@ class VectorCallViewModel @AssistedInject constructor( val proximityManager: CallProximityManager ) : VectorViewModel(initialState) { - var call: MxCall? = null + private var call: MxCall? = null - var connectionTimoutTimer: Timer? = null - var hasBeenConnectedOnce = false + private var connectionTimeoutTimer: Timer? = null + private var hasBeenConnectedOnce = false private val callStateListener = object : MxCall.StateListener { override fun onStateUpdate(call: MxCall) { val callState = call.state if (callState is CallState.Connected && callState.iceConnectionState == PeerConnection.PeerConnectionState.CONNECTED) { hasBeenConnectedOnce = true - connectionTimoutTimer?.cancel() - connectionTimoutTimer = null + connectionTimeoutTimer?.cancel() + connectionTimeoutTimer = null } else { // do we reset as long as it's moving? - connectionTimoutTimer?.cancel() + connectionTimeoutTimer?.cancel() if (hasBeenConnectedOnce) { - connectionTimoutTimer = Timer().apply { + connectionTimeoutTimer = Timer().apply { schedule(object : TimerTask() { override fun run() { session.callSignalingService().getTurnServer(object : MatrixCallback { From ba163dbf5caf773de0501e398c9e39a37b971a01 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 11 Sep 2020 16:27:11 +0200 Subject: [PATCH 48/89] Split into 4 files --- .../features/call/VectorCallViewActions.kt | 32 +++++++++++++ .../app/features/call/VectorCallViewEvents.kt | 33 +++++++++++++ .../app/features/call/VectorCallViewModel.kt | 46 ------------------- .../app/features/call/VectorCallViewState.kt | 39 ++++++++++++++++ 4 files changed, 104 insertions(+), 46 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/call/VectorCallViewActions.kt create mode 100644 vector/src/main/java/im/vector/app/features/call/VectorCallViewEvents.kt create mode 100644 vector/src/main/java/im/vector/app/features/call/VectorCallViewState.kt diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewActions.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewActions.kt new file mode 100644 index 0000000000..4ca21a0f1d --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewActions.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 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 im.vector.app.features.call + +import im.vector.app.core.platform.VectorViewModelAction + +sealed class VectorCallViewActions : VectorViewModelAction { + object EndCall : VectorCallViewActions() + object AcceptCall : VectorCallViewActions() + object DeclineCall : VectorCallViewActions() + object ToggleMute : VectorCallViewActions() + object ToggleVideo : VectorCallViewActions() + data class ChangeAudioDevice(val device: CallAudioManager.SoundDevice) : VectorCallViewActions() + object SwitchSoundDevice : VectorCallViewActions() + object HeadSetButtonPressed : VectorCallViewActions() + object ToggleCamera : VectorCallViewActions() + object ToggleHDSD : VectorCallViewActions() +} diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewEvents.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewEvents.kt new file mode 100644 index 0000000000..b79cd5d772 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewEvents.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 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 im.vector.app.features.call + +import im.vector.app.core.platform.VectorViewEvents +import org.matrix.android.sdk.api.session.call.TurnServerResponse + +sealed class VectorCallViewEvents : VectorViewEvents { + + object DismissNoCall : VectorCallViewEvents() + data class ConnectionTimeout(val turn: TurnServerResponse?) : VectorCallViewEvents() + data class ShowSoundDeviceChooser( + val available: List, + val current: CallAudioManager.SoundDevice + ) : VectorCallViewEvents() +// data class CallAnswered(val content: CallAnswerContent) : VectorCallViewEvents() +// data class CallHangup(val content: CallHangupContent) : VectorCallViewEvents() +// object CallAccepted : VectorCallViewEvents() +} diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt index 77a45628fe..e87e7b10d2 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt @@ -16,10 +16,8 @@ package im.vector.app.features.call -import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized @@ -27,9 +25,7 @@ import com.airbnb.mvrx.ViewModelContext import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.app.core.extensions.exhaustive -import im.vector.app.core.platform.VectorViewEvents import im.vector.app.core.platform.VectorViewModel -import im.vector.app.core.platform.VectorViewModelAction import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.call.CallState @@ -41,48 +37,6 @@ import org.webrtc.PeerConnection import java.util.Timer import java.util.TimerTask -data class VectorCallViewState( - val callId: String? = null, - val roomId: String = "", - val isVideoCall: Boolean, - val isAudioMuted: Boolean = false, - val isVideoEnabled: Boolean = true, - val isVideoCaptureInError: Boolean = false, - val isHD: Boolean = false, - val isFrontCamera: Boolean = true, - val canSwitchCamera: Boolean = true, - val soundDevice: CallAudioManager.SoundDevice = CallAudioManager.SoundDevice.PHONE, - val availableSoundDevices: List = emptyList(), - val otherUserMatrixItem: Async = Uninitialized, - val callState: Async = Uninitialized -) : MvRxState - -sealed class VectorCallViewActions : VectorViewModelAction { - object EndCall : VectorCallViewActions() - object AcceptCall : VectorCallViewActions() - object DeclineCall : VectorCallViewActions() - object ToggleMute : VectorCallViewActions() - object ToggleVideo : VectorCallViewActions() - data class ChangeAudioDevice(val device: CallAudioManager.SoundDevice) : VectorCallViewActions() - object SwitchSoundDevice : VectorCallViewActions() - object HeadSetButtonPressed : VectorCallViewActions() - object ToggleCamera : VectorCallViewActions() - object ToggleHDSD : VectorCallViewActions() -} - -sealed class VectorCallViewEvents : VectorViewEvents { - - object DismissNoCall : VectorCallViewEvents() - data class ConnectionTimeout(val turn: TurnServerResponse?) : VectorCallViewEvents() - data class ShowSoundDeviceChooser( - val available: List, - val current: CallAudioManager.SoundDevice - ) : VectorCallViewEvents() -// data class CallAnswered(val content: CallAnswerContent) : VectorCallViewEvents() -// data class CallHangup(val content: CallHangupContent) : VectorCallViewEvents() -// object CallAccepted : VectorCallViewEvents() -} - class VectorCallViewModel @AssistedInject constructor( @Assisted initialState: VectorCallViewState, @Assisted val args: CallArgs, diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewState.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewState.kt new file mode 100644 index 0000000000..f24e810400 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewState.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 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 im.vector.app.features.call + +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.Uninitialized +import org.matrix.android.sdk.api.session.call.CallState +import org.matrix.android.sdk.api.util.MatrixItem + +data class VectorCallViewState( + val callId: String? = null, + val roomId: String = "", + val isVideoCall: Boolean, + val isAudioMuted: Boolean = false, + val isVideoEnabled: Boolean = true, + val isVideoCaptureInError: Boolean = false, + val isHD: Boolean = false, + val isFrontCamera: Boolean = true, + val canSwitchCamera: Boolean = true, + val soundDevice: CallAudioManager.SoundDevice = CallAudioManager.SoundDevice.PHONE, + val availableSoundDevices: List = emptyList(), + val otherUserMatrixItem: Async = Uninitialized, + val callState: Async = Uninitialized +) : MvRxState From 21a42e310fa62092b8573169804696ce8de39d9a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 11 Sep 2020 16:49:11 +0200 Subject: [PATCH 49/89] Show branch name in debug build --- .../features/settings/VectorSettingsHelpAboutFragment.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsHelpAboutFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsHelpAboutFragment.kt index 129e057148..f011702dca 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsHelpAboutFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsHelpAboutFragment.kt @@ -20,6 +20,7 @@ import android.content.Intent import android.net.Uri import android.provider.Settings import androidx.preference.Preference +import im.vector.app.BuildConfig import org.matrix.android.sdk.api.Matrix import im.vector.app.R import im.vector.app.core.preference.VectorPreference @@ -58,7 +59,13 @@ class VectorSettingsHelpAboutFragment @Inject constructor( // application version findPreference(VectorPreferences.SETTINGS_VERSION_PREFERENCE_KEY)!!.let { - it.summary = versionProvider.getVersion(longFormat = false, useBuildNumber = true) + it.summary = buildString { + append(versionProvider.getVersion(longFormat = false, useBuildNumber = true)) + if (BuildConfig.DEBUG) { + append(" ") + append(BuildConfig.GIT_BRANCH_NAME) + } + } it.setOnPreferenceClickListener { pref -> copyToClipboard(requireContext(), pref.summary) From 1e0bc51fa20758f566cd70f3fcbf67b967f2d094 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 11 Sep 2020 17:09:30 +0200 Subject: [PATCH 50/89] Remove singletin instance from callback param --- .../app/features/call/VectorCallViewModel.kt | 18 +++++++++--------- .../call/WebRtcPeerConnectionManager.kt | 14 +++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt index e87e7b10d2..edb75441c8 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt @@ -90,17 +90,17 @@ class VectorCallViewModel @AssistedInject constructor( override fun onCurrentCallChange(call: MxCall?) { } - override fun onCaptureStateChanged(mgr: WebRtcPeerConnectionManager) { + override fun onCaptureStateChanged() { setState { copy( - isVideoCaptureInError = mgr.capturerIsInError, - isHD = mgr.currentCaptureFormat() is CaptureFormat.HD + isVideoCaptureInError = webRtcPeerConnectionManager.capturerIsInError, + isHD = webRtcPeerConnectionManager.currentCaptureFormat() is CaptureFormat.HD ) } } - override fun onAudioDevicesChange(mgr: WebRtcPeerConnectionManager) { - val currentSoundDevice = mgr.callAudioManager.getCurrentSoundDevice() + override fun onAudioDevicesChange() { + val currentSoundDevice = webRtcPeerConnectionManager.callAudioManager.getCurrentSoundDevice() if (currentSoundDevice == CallAudioManager.SoundDevice.PHONE) { proximityManager.start() } else { @@ -109,17 +109,17 @@ class VectorCallViewModel @AssistedInject constructor( setState { copy( - availableSoundDevices = mgr.callAudioManager.getAvailableSoundDevices(), + availableSoundDevices = webRtcPeerConnectionManager.callAudioManager.getAvailableSoundDevices(), soundDevice = currentSoundDevice ) } } - override fun onCameraChange(mgr: WebRtcPeerConnectionManager) { + override fun onCameraChange() { setState { copy( - canSwitchCamera = mgr.canSwitchCamera(), - isFrontCamera = mgr.currentCameraType() == CameraType.FRONT + canSwitchCamera = webRtcPeerConnectionManager.canSwitchCamera(), + isFrontCamera = webRtcPeerConnectionManager.currentCameraType() == CameraType.FRONT ) } } diff --git a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt index 916df8892b..c47ec4e35a 100644 --- a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt @@ -79,9 +79,9 @@ class WebRtcPeerConnectionManager @Inject constructor( interface CurrentCallListener { fun onCurrentCallChange(call: MxCall?) - fun onCaptureStateChanged(mgr: WebRtcPeerConnectionManager) {} - fun onAudioDevicesChange(mgr: WebRtcPeerConnectionManager) {} - fun onCameraChange(mgr: WebRtcPeerConnectionManager) {} + fun onCaptureStateChanged() {} + fun onAudioDevicesChange() {} + fun onCameraChange() {} } private val currentCallsListeners = emptyList().toMutableList() @@ -95,7 +95,7 @@ class WebRtcPeerConnectionManager @Inject constructor( val callAudioManager = CallAudioManager(context.applicationContext) { currentCallsListeners.forEach { - tryThis { it.onAudioDevicesChange(this) } + tryThis { it.onAudioDevicesChange() } } } @@ -174,7 +174,7 @@ class WebRtcPeerConnectionManager @Inject constructor( set(value) { field = value currentCallsListeners.forEach { - tryThis { it.onCaptureStateChanged(this) } + tryThis { it.onCaptureStateChanged() } } } @@ -741,7 +741,7 @@ class WebRtcPeerConnectionManager @Inject constructor( Timber.v("## VOIP onCameraSwitchDone isFront $isFrontCamera") cameraInUse = availableCamera.first { if (isFrontCamera) it.type == CameraType.FRONT else it.type == CameraType.BACK } currentCallsListeners.forEach { - tryThis { it.onCameraChange(this@WebRtcPeerConnectionManager) } + tryThis { it.onCameraChange() } } } @@ -767,7 +767,7 @@ class WebRtcPeerConnectionManager @Inject constructor( // videoCapturer?.stopCapture() videoCapturer?.changeCaptureFormat(format.width, format.height, format.fps) currentCaptureMode = format - currentCallsListeners.forEach { tryThis { it.onCaptureStateChanged(this) } } + currentCallsListeners.forEach { tryThis { it.onCaptureStateChanged() } } } } From 89af162c5aaaf02b54dab7a8ace2323f5cccc04a Mon Sep 17 00:00:00 2001 From: Kahina Messaoudi Date: Fri, 11 Sep 2020 13:57:18 +0000 Subject: [PATCH 51/89] Translated using Weblate (Kabyle) Currently translated at 62.5% (1167 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/kab/ --- vector/src/main/res/values-kab/strings.xml | 192 +++++++++++++++++---- 1 file changed, 157 insertions(+), 35 deletions(-) diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index 0d52e317bb..41eb7bd879 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -242,11 +242,11 @@ Iseqdacen i yettwagin Talqayt Tinarimin - Asulay n temɣiwent d arussin + Asulay n temɣiwent d arameɣtu Asentel Asulay n tqimit - Asulay n tqimit + Asulay n tɣimit Tasarut n tɣimit Asenqed Sifeḍ tisura n texxamt E2E @@ -259,17 +259,17 @@ ulac Senqed - Tabdart taberkant + Rnu ɣer tebdart taberkant Asenqed n tɣimit URL n uqeddac agejdan - %d n ulɣu - %d n ilɣa - + %d n ulɣu + %d n yilɣa + Taxxamt - Nek - Tuɣzi n tsefsit + Nekk + Teɣzi n tsefsit Amagnu Isem-ik·im yettwaskanen URL n avatar-inek·inem @@ -676,7 +676,7 @@ Sefsex asider\? Sefsex asali\? %d s - %1$dm %2$ds + %1$dsd %2$dsn Isem n texxamt Asentel n texxamt @@ -924,7 +924,7 @@ Asentem n tebzimt ur yeddi ara, ttxil-k·m aru yiwet. Sekcem PIN inek·inem Ttu PIN\? - "Wennez tabzimt " + Wennez tabzimt Tabzimt tamaynut n I uwennez n PIN-inek·inem, tesriḍ ad talseḍ anekcum syen rnu yiwen. Rmed PIN @@ -950,7 +950,7 @@ Sewḥel isawalen iɣef ur tebniḍ Suter i usentem send beddu n usiwel - "Sireg aqeddac n tallalt n yisawalen " + Sireg aqeddac n tallalt n yisawalen Suffeɣ aseqdac Ssebba n usuffeɣ Agi aseqdac @@ -978,7 +978,7 @@ Asnas yesra asireg i wakken ad iseddu tafelwit n ugilal Tinubgiwin i usiwel Seqdec takamiṛat tadigant - Azen iznan n taɣuct + Azen iznan n taɣect Bdu asenqed Bḍu war asenqed Asuter n beṭṭu n tsarut @@ -1282,9 +1282,9 @@ Asentel Alguritm - 1 texxamt - %d texxamin - + 1 n texxamt + %d n texxamin + %1$s: %2$s Meẓẓiy @@ -1325,32 +1325,32 @@ Ur tezmireḍ ara ad tkecmeḍ ɣer yizen-a acku tiɣimit-ik·im ur tt-yeḍmin ara umazan Ur tezmire ara ad tkecmeḍ ɣer yizen-a acku amazan iɛemmed ur d-yuzin ara tisura S tumert meqqren ara ak-d-nini nbeddel isem! Asnas-ik·im yettwaleqqem, ha-t-an tkecmeḍ ɣer umiḍan-ik·im. -Uṭṭun-a n tilifun yettusbadu yakan. +Uṭṭun-a n tiliɣri yettusbadu yakan. Awal-ik·im uffir yettuwennez. \n -\nAql-ak·akem teffɣeḍ seg meṛṛa tiɣimiyin syen ur d-teṭṭifeḍ ara akk ilɣa n Push. I wakken ad talseḍ armad n yilɣa, kcem tikkelt-nniḍen ɣer yal ibenk. +\nAql-ak·akem teffɣeḍ seg meṛṛa tiɣimiyin syen ur d-teṭṭifeḍ ara akk ilɣa n Push. Iwakken ad talseḍ armad n yilɣa, kcem tikkelt-nniḍen ɣer yal ibenk. Ajuṭu n unekcum i yettwafernen ur yettwassen ara JSON ur yemsil ara akken iwata Aṭas n yisuturen i yettwaznen Awennez n tkamiṛat d awezɣi tiririt ɣef usiwel seg wadeg-nniḍen - "Ur yezmir ara " + Asekles n tvidyut d awezɣi - Element yesra tasiregt n unekcum ɣer temkarḍit-inek·inem n tewlafin d tvidyut i tuzna d usekles n tceqqufin yeddan. + Element yesra tasiregt n unekcum ɣer temkarḍit-ik•im n tewlafin d tvidyutin i tuzna d usekles n tceqqufin yeddan. \n -\nMa ulac aɣilif sireg anekcum deg yisfuyla udhimen i d-iteddun i wakken ad tizmireḍ ad tazneḍ ifuyla seg tiliɣri-inek·inem. +\nTtxil sireg anekcum deg yisfuyla udhimen i d-itteddun iwakken ad tizmireḍ ad tazneḍ ifuyla seg tiliɣri-ik•im. " \n -\nMa ulac aɣilif sireg anekcum ɣer isfuyla udhimen i d-iteddun i wakken tizmireḍ ad tessiwleḍ." - Element yesra tasiregt n unekcum ɣer usawaḍ-inek·inem i wakken ad iseddu isawalen s umeslaw. +\nTtxil sireg anekcum ɣer yisfuyla udhimen i d-itteddun iwakken ad tizmireḍ ad tessiwleḍ." + Element yesra tasiregt n unekcum ɣer usawaḍ-ik•im iwakken ad isseddu isawalen imeslawen. " \n -\nMa ulac aɣilif sireg anekcum ɣer isfuyla udhimen i d-iteddun i wakken tizmireḍ ad tessiwleḍ." - "Element yesra tasiregt n unekcum ɣer temkarḍit-inek·inem n tewlafin d tvidyut i tuzna d usekles n tceqqufin yeddan. +\nTtxil sireg anekcum ɣer yisfuyla udhimen i d-itteddun iwakken ad tizmireḍ ad tessiwleḍ." + Element yesra tasiregt n unekcum ɣer temkarḍit-ik•im n tewlafin d tvidyutin i tuzna d usekles n tceqqufin yeddan. \n \n -\nMa ulac aɣilif sireg anekcum deg yisfuyla udhimen i d-iteddun i wakken ad tizmireḍ ad tazneḍ ifuyla seg tiliɣri-inek·inem. " +\nTtxil sireg anekcum deg yisfuyla udhimen i d-itteddun iwakken ad tizmireḍ ad tazneḍ ifuyla seg tiliɣri-ik•im. Element yezmer ad issenqed adlis-inek·inem n tansiwin i wakken ad d-yaf iseqdacen-nniḍen n Matrix s usenned ɣer yimaylen d wuṭṭunen n tiliɣri nsen. \n \nTebɣiḍ ad tebduḍ adlis-inek·inem n tansiwin i yiswi-a\? @@ -1421,7 +1421,7 @@ 1 waggur Tansiwin Awgelhen seg yixef ɣer yixef - Dossier + Akaram Tuccḍa n uzmak Tinubga tamaynut @@ -1431,10 +1431,10 @@ Hraw ugar Ahrawan maḍi - Meqqeṛ + Meqqer - WALI - Rmed iwiǧiten + SKEN + Iwiǧiten urmiden Awiǧit @@ -1442,20 +1442,21 @@ Awiǧit-a yettwarna sɣur: Aseqdec-is yezmer ad yesbadu inagan n tuqqna yerna ad yebḍu isefka d %s: Aseqdec-is yezmer ad yebḍu isefka d %s: - Ur yeddi ara usali n yiwiǧit%s - Ales asali n yiwiǧit + Ur yeddi ara usali n uwiǧit. +\n%s + Ales asali n uwiǧit Ldi deg yiminig Sefesex anekcum i nekk Sewḥel kullec - Ixuṣṣ usulay_taxxamt deg usuter. - Ixuṣṣ usulay_aseqdac deg usuter. - Taxxamt %s ur d-tban ara + Ixuṣṣ usulay room_id deg usuter. + Ixuṣṣ usulay user_id deg usuter. + Taxxamt %s ur d-tban ara. Aɣewwar yettusran ulac-it. Aɣewwar mačči d ameɣtu. Ulac amsefrak n umsidef yettusewlen. Rnu isnasen n Matrix - Ulac iwiǧiten i yettwaremden + Ulac iwiǧiten urmiden Kcem ɣer texxamt s yisem i d-yettunefken Ttxil-k sekcem isem n useqdac. Ttxil-k·m sekcem awal-ik·im uffir: @@ -1522,4 +1523,125 @@ Afaylu n useqdac Kcem %s + Tuqqna ur teddi ara + Ṭṭef-d tawlaft neɣ tavidyut + Element yesra anekcum ɣer tkamiṛat-ik•im i tuṭṭfa n tewlafin d yisiwlen s tvidyut. + Yal yiwen i yessnen aseɣwen n texxamt, anagar inebgawen + Yal yiwen i yessnen aseɣwen n texxamt, ula d inebgawen + + + %d n useqdec yettwagin + %d n yiseqdacen yettwagin + + + Asulay ID agensan n texxamt-a + Awgelhen seg yixef ɣer yixef yermed + Ilaq ad teffɣeḍ akken ad tzemreḍ ad tremdeḍ awgelhen. + Wgelhen kan tiɣimiyin yettwaneqden + Ur ttazen ara iznan yettwawgelhen ɣer tɣimiyin ur nettwasenqed ara deg texxamt-a seg tɣimit-a. + + Tansa tamaynut (md. #foo:matrix.org) + + Asulay ID amaynut n temɣiwent (md. +foo:matrix.org) + \'%s\' mačči d asulay ID n temɣiwent ameɣtu + + + Ur tseɛɛuḍ ara tansa tagejdant i yefran i texxamt-a. + Ilɣa n tansa tagejdant + + Sbadu-tt am tansa tagejdant + Kkes asbadu-ines am tansa tagejdant + Nɣel asulay ID n texxamt + Nɣel tansa n texxamt + + Awgelhen irmed deg texxamt-a. + Awgelhen yensa deg texxamt-a. + Rmed awgelhen +\n(Ɣur-k•m: ur yettnus ara tikkelt-nniḍen!) + + Talɣut ɣef uwgelhen seg yixef ɣer yixef + + Talɣut ɣef tedyant + Asulay n useqdac + Tasarut n tmagit Curve25519 + Talɣut ɣef tɣimit n umazan + Isem azayez + Isem azayez (yettban-d i yimdanen ukkud tettmeslayeḍ) + Isem azayez + Adsil umḍin Ed25519 + + Sifeḍ tisura ɣer ufaylu adigan + Ttxil rnu tafyirt tuffirt i uwgelhen n tsura yettwasifḍen. Ilaq ad teskecmeḍ tafyirt-a tuffirt akken ad tzemreḍ ad tketreḍ tisura. + Tisura E2E n texxamt ttwaskelsen deg \'%s\'. +\nƔur-k•m: afaylu-a izmer ad ittwakkes ma yettwakkes usnas. + Tisura ttwasifḍent akken iwata + + Tiririt n yiznan yettwawgelhen + Sefrek aklas n tsura + + Kter tisura seg ufaylu adigan + Wgelhen kan ɣer tɣimiyin yettwasneqden + Ur ttazen ara iznan yettwawgelhen ɣer tɣimiyin ur nettwasenqed ara seg tɣimit-a. + + Tasarut %1$d/%2$d tettwakter akken iwata. + Tisura %1$d/%2$d ttwaketrent akken iwata. + + + Ur ittwasenqed ara + Deg tebdart taberkant + + Tiɣimit tarussint + Tansa ip tarussint + Kkes asenqed + Kkes seg tebdart taberkant + + Taxxamt tegber tiɣimiyin tirussinin + Taxxamt-a tegber tiɣimiyin tirussinin ur nettwasenqed ara. +\nAnamek-is ulac ṭṭmana dakken tiɣimiyin-nni n yiseqdacen akken d-qqarent. +\nAxir ad tɛeddiḍ seg ukala n usenqed i yal tiɣimit send akemmel, maca tzemreḍ ad talseḍ tuzzna n yizen war asenqed ma tebɣiḍ. +\n +\nTiɣimiyin tirussinin: + + Fren akaram n texxamt + Aru aqeddac agejdan akken ad d-tbedreḍ tixxamin-is tizuyaz + Akk tixxamin deg uqeddac %s + Aru da… + + + %1$s: 1 n yizen + %1$s: %2$d n yiznan + + %1$s deg %2$s + Tadyant tamaynut + Iznan imaynuten + **Tuzzna ur teddi ara - ttxil ldi taxxamt + Meẓẓiy nezzeh + Tesriḍ tasiregt i usefrek n yiwiǧiten deg texxamt-a + Asnulfu n yiwiǧiten ur yeddi ara + Tebɣiḍ s tidet ad tekkseḍ awiǧit seg texxamt-a\? + + 1 n uwiǧit urmid + %d n yiwiǧiten urmiden + + Suref-aɣ, isawalen s usarag s Jitsi ur ttwasefraken ara deg yibenkan iqburen (ibenkan s lqem Android OS ddaw n 5.0) + Awiǧit-a ibɣa ad isseqdec tiɣbula-a: + Seqdec takamiṛat + Seqdec asawaḍ + Seqdec taqeffalt n unekcum n unasiw akken ad tazneḍ izen + Aɣewwar-a yesra asnas-nniḍen akken ad issekles iznan. + Akken ad tkemmleḍ, ilaq ad tqebleḍ tiwtilin n umeẓlu-a. + + Terniḍ tiɣimit tamaynut \'%s\', i d-yessuturen tisura n uwgelhen. + Tiɣimit tamaynut tessutur-d tisura n uwgelhen. +\nIsem n tɣimit: %1$s +\nTettwaẓra: %2$s +\nMa ur teqqineḍ ara ɣer tɣimit-nniḍen, anef i usuter-a. + Tiɣimit-ik•im ur nettwasenqed ara \'%s\' tessutur-d tisura n uwgelhen. + Tiɣimit ur nettwasenqed ara tessutur-d tisura n uwgelhen. +\nIsem n tɣimit: %1$s +\nTettwaẓra: %2$s +\nMa ur teqqineḍ ara ɣer tɣimit-nniḍen, anef i usuter-a. + + I useggem n usefrek n yisnasen n Matrix + From fbe6a2ac805802b21c023f734a70462b8fa12d6a Mon Sep 17 00:00:00 2001 From: ziriSut Date: Fri, 11 Sep 2020 23:50:36 +0000 Subject: [PATCH 52/89] Translated using Weblate (Kabyle) Currently translated at 62.5% (1167 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/kab/ --- vector/src/main/res/values-kab/strings.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index 41eb7bd879..0defd88bba 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -627,7 +627,7 @@ Qqen Imayl neɣ isem n useqdac Isem n useqdac - Tansa imayl (d tafrayant) + Tansa n yimayl (d tafrayan) Uṭṭun n tiliɣri Uṭṭun n tiliɣri (d afrayan) Ales i wawal uffir @@ -1644,4 +1644,9 @@ I useggem n usefrek n yisnasen n Matrix + "Akka d-yettban tetthuzzu s laya tiliri-inek·inem. Tebɣiḍ ad teldiḍ agdil n tuzna n wabug\? " + "Sbadu imayl i tririt n umiḍan, syen ɣer sdat ad yishil ad ak-id-afen yimdanen i ak·akem-yessnen " + "Sbadu uṭṭun n tiliɣri, syen ɣer sdat ad yishil ad ak-id-afen yimdanen i ak·akem-yessnen " + "Sbadu imayl i tririt n umiḍan. Seqdec ɣer sadt imayl neɣ uṭṭun n tiliɣri i wakken ad ak·akem-id-afen yimdanen i ak·akem-yessnen " + "Sbadu imayl i tririt n umiḍan. Seqdec ɣer sadt imayl neɣ uṭṭun n tiliɣri i wakken ad ak·akem-id-afen yimdanen i ak·akem-yessnen " From 82a1b8b4c04bb8def5583c94d79e12982b784c85 Mon Sep 17 00:00:00 2001 From: ziriSut Date: Fri, 11 Sep 2020 23:50:43 +0000 Subject: [PATCH 53/89] Translated using Weblate (Kabyle) Currently translated at 97.0% (1811 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/kab/ --- vector/src/main/res/values-kab/strings.xml | 1068 +++++++++++++++++--- 1 file changed, 937 insertions(+), 131 deletions(-) diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index 0defd88bba..caba9748d4 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -242,11 +242,11 @@ Iseqdacen i yettwagin Talqayt Tinarimin - Asulay n temɣiwent d arameɣtu + Asulay n temɣiwent d arussin Asentel Asulay n tqimit - Asulay n tɣimit + Asulay n tqimit Tasarut n tɣimit Asenqed Sifeḍ tisura n texxamt E2E @@ -259,17 +259,17 @@ ulac Senqed - Rnu ɣer tebdart taberkant + Tabdart taberkant Asenqed n tɣimit URL n uqeddac agejdan %d n ulɣu - %d n yilɣa + %d n ilɣa Taxxamt - Nekk - Teɣzi n tsefsit + Nek + Tuɣzi n tsefsit Amagnu Isem-ik·im yettwaskanen URL n avatar-inek·inem @@ -676,7 +676,7 @@ Sefsex asider\? Sefsex asali\? %d s - %1$dsd %2$dsn + %1$tesdidin %2$ds Isem n texxamt Asentel n texxamt @@ -924,7 +924,7 @@ Asentem n tebzimt ur yeddi ara, ttxil-k·m aru yiwet. Sekcem PIN inek·inem Ttu PIN\? - Wennez tabzimt + "Wennez tabzimt " Tabzimt tamaynut n I uwennez n PIN-inek·inem, tesriḍ ad talseḍ anekcum syen rnu yiwen. Rmed PIN @@ -950,7 +950,7 @@ Sewḥel isawalen iɣef ur tebniḍ Suter i usentem send beddu n usiwel - Sireg aqeddac n tallalt n yisawalen + Sireg aqeddac n tallalt n yisawalen n usellek Suffeɣ aseqdac Ssebba n usuffeɣ Agi aseqdac @@ -978,7 +978,7 @@ Asnas yesra asireg i wakken ad iseddu tafelwit n ugilal Tinubgiwin i usiwel Seqdec takamiṛat tadigant - Azen iznan n taɣect + Azen iznan n taɣuct Bdu asenqed Bḍu war asenqed Asuter n beṭṭu n tsarut @@ -1282,8 +1282,8 @@ Asentel Alguritm - 1 n texxamt - %d n texxamin + 1 texxamt + %d texxamin %1$s: %2$s @@ -1325,32 +1325,32 @@ Ur tezmireḍ ara ad tkecmeḍ ɣer yizen-a acku tiɣimit-ik·im ur tt-yeḍmin ara umazan Ur tezmire ara ad tkecmeḍ ɣer yizen-a acku amazan iɛemmed ur d-yuzin ara tisura S tumert meqqren ara ak-d-nini nbeddel isem! Asnas-ik·im yettwaleqqem, ha-t-an tkecmeḍ ɣer umiḍan-ik·im. -Uṭṭun-a n tiliɣri yettusbadu yakan. +Uṭṭun-a n tilifun yettusbadu yakan. Awal-ik·im uffir yettuwennez. \n -\nAql-ak·akem teffɣeḍ seg meṛṛa tiɣimiyin syen ur d-teṭṭifeḍ ara akk ilɣa n Push. Iwakken ad talseḍ armad n yilɣa, kcem tikkelt-nniḍen ɣer yal ibenk. +\nAql-ak·akem teffɣeḍ seg meṛṛa tiɣimiyin syen ur d-teṭṭifeḍ ara akk ilɣa n Push. I wakken ad talseḍ armad n yilɣa, kcem tikkelt-nniḍen ɣer yal ibenk. Ajuṭu n unekcum i yettwafernen ur yettwassen ara JSON ur yemsil ara akken iwata Aṭas n yisuturen i yettwaznen Awennez n tkamiṛat d awezɣi tiririt ɣef usiwel seg wadeg-nniḍen - Asekles n tvidyut d awezɣi + Ur yezmir ara ad isekles tavidyut - Element yesra tasiregt n unekcum ɣer temkarḍit-ik•im n tewlafin d tvidyutin i tuzna d usekles n tceqqufin yeddan. + Element yesra tasiregt n unekcum ɣer temkarḍit-inek·inem n tewlafin d tvidyut i tuzna d usekles n tceqqufin yeddan. \n -\nTtxil sireg anekcum deg yisfuyla udhimen i d-itteddun iwakken ad tizmireḍ ad tazneḍ ifuyla seg tiliɣri-ik•im. +\nMa ulac aɣilif sireg anekcum deg yisfuyla udhimen i d-iteddun i wakken ad tizmireḍ ad tazneḍ ifuyla seg tiliɣri-inek·inem. " \n -\nTtxil sireg anekcum ɣer yisfuyla udhimen i d-itteddun iwakken ad tizmireḍ ad tessiwleḍ." - Element yesra tasiregt n unekcum ɣer usawaḍ-ik•im iwakken ad isseddu isawalen imeslawen. +\nMa ulac aɣilif sireg anekcum ɣer isfuyla udhimen i d-iteddun i wakken tizmireḍ ad tessiwleḍ." + Element yesra tasiregt n unekcum ɣer usawaḍ-inek·inem i wakken ad iseddu isawalen s umeslaw. " \n -\nTtxil sireg anekcum ɣer yisfuyla udhimen i d-itteddun iwakken ad tizmireḍ ad tessiwleḍ." - Element yesra tasiregt n unekcum ɣer temkarḍit-ik•im n tewlafin d tvidyutin i tuzna d usekles n tceqqufin yeddan. +\nMa ulac aɣilif sireg anekcum ɣer isfuyla udhimen i d-iteddun i wakken tizmireḍ ad tessiwleḍ." + Element yesra tasiregt n unekcum ɣer temkarḍit-inek·inem n tewlafin d tvidyut i tuzna d usekles n tceqqufin yeddan. \n \n -\nTtxil sireg anekcum deg yisfuyla udhimen i d-itteddun iwakken ad tizmireḍ ad tazneḍ ifuyla seg tiliɣri-ik•im. +\nMa ulac aɣilif sireg anekcum deg yisfuyla udhimen i d-iteddun i wakken ad tizmireḍ ad tazneḍ ifuyla seg tiliɣri-inek·inem. Element yezmer ad issenqed adlis-inek·inem n tansiwin i wakken ad d-yaf iseqdacen-nniḍen n Matrix s usenned ɣer yimaylen d wuṭṭunen n tiliɣri nsen. \n \nTebɣiḍ ad tebduḍ adlis-inek·inem n tansiwin i yiswi-a\? @@ -1389,52 +1389,52 @@ Tiririt n ujuṭu FCM ur teddi ara: \n%1$s Asekles n ujuṭu - Démarrer le service + Senker ameẓlu - "Bdu seg usenker " + Bdu seg tazwara Swel ilɣa n zzhir Swel ilɣa n usiwel Swel ilɣa n tsusmi - "Fren ini, ahuzzu, imesli n LED... " + Fren ini, tasmamayt, imesli n LED… Iznan ideg yella yisem-iw n useqdac - "Iznan deg usqerdec gar sin kan " + Iznan deg usqerdec gar sin kan Iznan n yisqerdicen n ugraw Amtawi n ugilal Askar n umatawi n ugilal (D armitan) Ulac amtawi n ugilal - "Bdu seg usenker " + Bdu seg usenker Rmed amtawi n ugilal tasint tasinin Tiwtilin & tfadiwin - Sfeḍ tuffirt + Sfeḍ takatut tuffirt %1$s @ %2$s Fren tutlayt - Awalen uffiren ur menṭaḍen ara + Awalen uffiren ur mṣadan ara - Country - 3 ussan - 1 waggur + Tamurt + 3 wussan + 1 wayyur Tansiwin Awgelhen seg yixef ɣer yixef Akaram - Tuccḍa n uzmak + Tuccḍa deg uglam Tinubga tamaynut %1$s: %2$s %3$s Nadi amazray - Hraw ugar - Ahrawan maḍi + Ahrawan + Ahrawan akk Meqqer - SKEN - Iwiǧiten urmiden + WALI + Rmed iwiǧiten Awiǧit @@ -1442,23 +1442,22 @@ Awiǧit-a yettwarna sɣur: Aseqdec-is yezmer ad yesbadu inagan n tuqqna yerna ad yebḍu isefka d %s: Aseqdec-is yezmer ad yebḍu isefka d %s: - Ur yeddi ara usali n uwiǧit. -\n%s - Ales asali n uwiǧit + Ur yeddi ara usali n yiwiǧit%s + Ales asali n yiwiǧit Ldi deg yiminig Sefesex anekcum i nekk Sewḥel kullec - Ixuṣṣ usulay room_id deg usuter. - Ixuṣṣ usulay user_id deg usuter. - Taxxamt %s ur d-tban ara. + Ixuṣṣ usulay_taxxamt deg usuter. + Ixuṣṣ usulay_aseqdac deg usuter. + Taxxamt %s ur d-tban ara Aɣewwar yettusran ulac-it. Aɣewwar mačči d ameɣtu. Ulac amsefrak n umsidef yettusewlen. Rnu isnasen n Matrix - Ulac iwiǧiten urmiden + Ulac iwiǧiten i yettwaremden Kcem ɣer texxamt s yisem i d-yettunefken - Ttxil-k sekcem isem n useqdac. + Ttxil-ik·im sekcem isem n useqdac. Ttxil-k·m sekcem awal-ik·im uffir: Adiwenni yettkemmil da Sit da i wakken ad twaliḍ iznan iqburen @@ -1487,7 +1486,7 @@ (Leqqayen) Sbadu s tsarut n tririt Giɣ tanɣalt Sekles tasarut n tririt - Enregistrer le fichier + Sekles am ufaylu Tasarut n tririt tettwasekles. Yella yakan uḥraz deg uqeddac-ik·im agejdan @@ -1504,13 +1503,13 @@ Tangalt Ittraju %s… - Ifuyla yettwaznen + Isuli-d Isefka n umiḍan Taxtirit yettefernen Anekcum amaynut Sekcem tasarut tuffirt n uḥraz uffir: - Alɣu: + Ɣur-k·m! Tisur ttwaleqqment yakan! Element Android @@ -1519,134 +1518,941 @@ Ittraju %s… - Aqeεεed + "Ilɣa n urway " Afaylu n useqdac Kcem %s - Tuqqna ur teddi ara + Tuqqna n umidyat ur teddi ara Ṭṭef-d tawlaft neɣ tavidyut - Element yesra anekcum ɣer tkamiṛat-ik•im i tuṭṭfa n tewlafin d yisiwlen s tvidyut. - Yal yiwen i yessnen aseɣwen n texxamt, anagar inebgawen - Yal yiwen i yessnen aseɣwen n texxamt, ula d inebgawen + Element yesra tasiregt n unekcum er tkamiat-ik·im i wakken ad d-yeṭṭef tawlafin d yisawalen s tvidyut. + Yal win·tin yessnen aseɣwen n texxamt, slid inebgawen + Yal win·tin yessnen aseɣwen n texxamt rnu-d ɣer-sen inebgawen - %d n useqdec yettwagin - %d n yiseqdacen yettwagin + %d yezgel aseqdac + %d yezgel iseqdacen - Asulay ID agensan n texxamt-a - Awgelhen seg yixef ɣer yixef yermed - Ilaq ad teffɣeḍ akken ad tzemreḍ ad tremdeḍ awgelhen. - Wgelhen kan tiɣimiyin yettwaneqden - Ur ttazen ara iznan yettwawgelhen ɣer tɣimiyin ur nettwasenqed ara deg texxamt-a seg tɣimit-a. + Asulay n texxamt tagensant + Awgelhen seg yixef ɣer yixef yettwarmed + Tesriḍ ad teffɣeḍ i wakken ad tizmireḍ awgelhen. + Wgelhen i usenqed n tɣimiyinkan + Ur ttazen ara akk iznan yettwawgelhen ɣer tɣimiyin ur nettusenqad ara deg texxamt-a seg tɣimit-a - Tansa tamaynut (md. #foo:matrix.org) + Tansa tamaynut (am. #foo:matrix.org) - Asulay ID amaynut n temɣiwent (md. +foo:matrix.org) - \'%s\' mačči d asulay ID n temɣiwent ameɣtu + Asulay n temɣiwent tamaynut (am. #foo:matrix.org) + \'%s\' mačči d asulay n temɣiwent ameɣtu - Ur tseɛɛuḍ ara tansa tagejdant i yefran i texxamt-a. - Ilɣa n tansa tagejdant + Ur tesɛiḍ ara tansa tagejdant yettwafernen i texxamt. + Tansa tagejdant terreẓ - Sbadu-tt am tansa tagejdant - Kkes asbadu-ines am tansa tagejdant - Nɣel asulay ID n texxamt - Nɣel tansa n texxamt + Sbadu tansa tagejdant + Tansa tagejdant ur tettusbadu ara + Asulay n unɣal n texxamt + Tansa n unɣal n texxamt - Awgelhen irmed deg texxamt-a. - Awgelhen yensa deg texxamt-a. + Awgelhen yettwarmed deg texxamt-a. + Awgelhen yettusens deg texxamt-a. Rmed awgelhen -\n(Ɣur-k•m: ur yettnus ara tikkelt-nniḍen!) +\n(Ɣur-k·m: ur yezmir ara ad yettusens tikkelt-nniḍen!) - Talɣut ɣef uwgelhen seg yixef ɣer yixef + Talɣut n uwgelhen seg yixef ɣer yixef - Talɣut ɣef tedyant + Talɣut n uneḍru Asulay n useqdac - Tasarut n tmagit Curve25519 - Talɣut ɣef tɣimit n umazan + Tasarut n timagit Curve25519 + "Talɣut n umesgal n tɣimit " Isem azayez - Isem azayez (yettban-d i yimdanen ukkud tettmeslayeḍ) + Isem azayez (yettban i yimdanen wukud tettmeslayeḍ) Isem azayez - Adsil umḍin Ed25519 + Udsil umḍin Ed25519 - Sifeḍ tisura ɣer ufaylu adigan - Ttxil rnu tafyirt tuffirt i uwgelhen n tsura yettwasifḍen. Ilaq ad teskecmeḍ tafyirt-a tuffirt akken ad tzemreḍ ad tketreḍ tisura. - Tisura E2E n texxamt ttwaskelsen deg \'%s\'. -\nƔur-k•m: afaylu-a izmer ad ittwakkes ma yettwakkes usnas. - Tisura ttwasifḍent akken iwata + Sifeḍ tisura n ufaylu adigan + Ma ulac aɣilif rnu tafyirt tuffirt i uwgelhen n tsura yettwasifḍen. Tesriḍ ad teskecmeḍ tafyirt-nni kan tuffirt i wakken ad tizmireḍ ad d-tketreḍ tisura. + Tisura n texxamt E2E ttwaseklasent deg \'%s\'. +\n +\nƔur-k·m: afaylu-a yezmer ad yettwakkes ma yella asnas ur yettusebded ara. + Asifeḍ n tsura yedda akken iwata - Tiririt n yiznan yettwawgelhen - Sefrek aklas n tsura + "Iznan yettwawgelhen n tririt " + Sefrek aḥraz n tsarut - Kter tisura seg ufaylu adigan - Wgelhen kan ɣer tɣimiyin yettwasneqden - Ur ttazen ara iznan yettwawgelhen ɣer tɣimiyin ur nettwasenqed ara seg tɣimit-a. + Kter tisura n ufaylu adigan + Wgelhen i usenqed n tɣimiyinkan + Ur ttazen ara akk iznan yettwawgelhen ɣer tɣimiyin ur nettusenqad ara seg tɣimit-a. - Tasarut %1$d/%2$d tettwakter akken iwata. - Tisura %1$d/%2$d ttwaketrent akken iwata. + %1$d/%2$d tasarut tettwasifeḍ akken iwata. + %1$d/%2$d tisura ttwasifḍen akken iwata. - Ur ittwasenqed ara + Ur yettwasenqed ara Deg tebdart taberkant - Tiɣimit tarussint - Tansa ip tarussint - Kkes asenqed + tiɣimit tarussint + ip arussin + Ur yettusenqed ara Kkes seg tebdart taberkant - Taxxamt tegber tiɣimiyin tirussinin - Taxxamt-a tegber tiɣimiyin tirussinin ur nettwasenqed ara. -\nAnamek-is ulac ṭṭmana dakken tiɣimiyin-nni n yiseqdacen akken d-qqarent. -\nAxir ad tɛeddiḍ seg ukala n usenqed i yal tiɣimit send akemmel, maca tzemreḍ ad talseḍ tuzzna n yizen war asenqed ma tebɣiḍ. + Taxxamt ideg llant tɣimiyin tarussanin + "Taxxamt-a deg-s tiɣimiyin tarussinin ur nettwaselken ara. +\nAya yebɣa ad d-yini ur ttwaḍmanent ara tɣimiyin-a yerzan iseqdac i keččmen ɣer-sent. +\nAd ak·akem-nwelleh ad tuɣaleḍ ɣer ukala n uselken n yal tiɣimit send akemmel, maca tzemreḍ ad talseḍ tuzna n yizen war aselken ma yella tebɣiḍ. \n -\nTiɣimiyin tirussinin: +\nTiɣimiyin tarussinin: " Fren akaram n texxamt - Aru aqeddac agejdan akken ad d-tbedreḍ tixxamin-is tizuyaz - Akk tixxamin deg uqeddac %s - Aru da… + Aru aqeddac agejdan i wakken ad d-tbedreḍ tixxamin tizuyaz seg-s + Tixxamin meṛṛa ɣef uqeddac %s + Aru da... - %1$s: 1 n yizen - %1$s: %2$d n yiznan + %1$s: 1 yizen + %1$s: %2$d yiznan %1$s deg %2$s Tadyant tamaynut Iznan imaynuten - **Tuzzna ur teddi ara - ttxil ldi taxxamt + ** Tuzna ur teddi ara - ma ulac aɣilif ldi taxxamt Meẓẓiy nezzeh - Tesriḍ tasiregt i usefrek n yiwiǧiten deg texxamt-a - Asnulfu n yiwiǧiten ur yeddi ara - Tebɣiḍ s tidet ad tekkseḍ awiǧit seg texxamt-a\? + Tesriḍ ad tesɛuḍ tisirag i wakken ad tesferkeḍ iwiǧiten deg texxamt-a + Timerna n uwiǧit ur teddi ara + S tidet tebɣiḍ ad tekkseḍ awiǧit seg texxamt-a\? - 1 n uwiǧit urmid - %d n yiwiǧiten urmiden + 1 uwiǧit i yettwaremden + %d n yiwiǧiten i yettwaremden - Suref-aɣ, isawalen s usarag s Jitsi ur ttwasefraken ara deg yibenkan iqburen (ibenkan s lqem Android OS ddaw n 5.0) - Awiǧit-a ibɣa ad isseqdec tiɣbula-a: + "Nesḥassef, asarag s usiwel s Jitsi ur yettusefrak ara ɣef yibenkan iqburen (ibenkan s Android OS ddaw 5.0) " + Iwiǧit-a yebɣa ad isseqdec tiɣbula-a: Seqdec takamiṛat Seqdec asawaḍ - Seqdec taqeffalt n unekcum n unasiw akken ad tazneḍ izen - Aɣewwar-a yesra asnas-nniḍen akken ad issekles iznan. - Akken ad tkemmleḍ, ilaq ad tqebleḍ tiwtilin n umeẓlu-a. + "Seqdec anasiw sekcem tasarut i tuzna n yizen " + Taxtiṛit-a tesra asnas n wis tlata i usekles n yiznan. + I wakken ad tkemmleḍ tesriḍ ad tqebleḍ tiwtilin n umeẓlu-a. - Terniḍ tiɣimit tamaynut \'%s\', i d-yessuturen tisura n uwgelhen. - Tiɣimit tamaynut tessutur-d tisura n uwgelhen. + "Terniḍ tiɣimit tamaynut \'%s\', i yessuturen tisura n uwgelhen. " + "Tiɣimit tamaynut tessutur isem n key.ession n uwgelhen: %1$s +\nTimeẓriwt taneggarut: %2$s +\nMa yella ur tekcimeḍ ara ɣer tqimit-nniḍen, ttu asuter-a. " + "Terniḍ tiɣimit tamaynut \'%s\', i yessuturen tisura n uwgelhen. " + "Tiɣimit tamaynut tessutur tisura n uwgelhen. \nIsem n tɣimit: %1$s -\nTettwaẓra: %2$s -\nMa ur teqqineḍ ara ɣer tɣimit-nniḍen, anef i usuter-a. - Tiɣimit-ik•im ur nettwasenqed ara \'%s\' tessutur-d tisura n uwgelhen. - Tiɣimit ur nettwasenqed ara tessutur-d tisura n uwgelhen. -\nIsem n tɣimit: %1$s -\nTettwaẓra: %2$s -\nMa ur teqqineḍ ara ɣer tɣimit-nniḍen, anef i usuter-a. +\nTimeẓriwt taneggarut: %2$s +\nMa yella ur tekcimeḍ ara ɣer tqimit-nniḍen, ttu asuter-a. " - I useggem n usefrek n yisnasen n Matrix + "I uṣeggem n usefrek n yisnasen n Matrix " - "Akka d-yettban tetthuzzu s laya tiliri-inek·inem. Tebɣiḍ ad teldiḍ agdil n tuzna n wabug\? " - "Sbadu imayl i tririt n umiḍan, syen ɣer sdat ad yishil ad ak-id-afen yimdanen i ak·akem-yessnen " - "Sbadu uṭṭun n tiliɣri, syen ɣer sdat ad yishil ad ak-id-afen yimdanen i ak·akem-yessnen " - "Sbadu imayl i tririt n umiḍan. Seqdec ɣer sadt imayl neɣ uṭṭun n tiliɣri i wakken ad ak·akem-id-afen yimdanen i ak·akem-yessnen " - "Sbadu imayl i tririt n umiḍan. Seqdec ɣer sadt imayl neɣ uṭṭun n tiliɣri i wakken ad ak·akem-id-afen yimdanen i ak·akem-yessnen " - + Akka d-yettban tetthuzzuḍ tiliɣri s lxiq. Tebɣiḍ ad teldiḍ agdil i tuzna n wabug\? + Sbadu imayl i tririt n umiḍan, syen ɣer sdat ad yishil ad tt-afen yimdanen i ak·akem-yessnen. + Sbadu uṭṭun n tiliɣri, syen ɣer sdat ad yishil ad t-afen yimdanen i ak·akem-yessnen. + Sbadu imayl i tririt n umiḍan. Seqdec ɣer sadt imayl neɣ uṭṭun n tiliɣri i wakken ad yishil ad ak·akem-id-afen yimdanen i ak·akem-yessnen. + Sbadu imayl i tririt n umiḍan. Seqdec ɣer sadt imayl neɣ uṭṭun n tiliɣri i wakken ad yishil ak·akem-id-afen yimdanen i ak·akem-yessnen. + Ajerred s yimayl d wuṭṭun n tiliɣri ɣef tikkelt ur yettusefrak ara akka tura alamma yella API. Slid uṭṭun n tilifun ara yettwaṭṭfen deg umiḍan. +\n +\nIlaq-ak·am ad ternuḍ imayl-ik·im ɣer umaɣun-inek·inem deg yiɣewwaren. + Ibenk-inek·inem yesseqdac aneggaf n tɣellist TLS aqbur, yemzer i uḍfar s waṭas, i tɣellist-inek·inem ur tettizmireḍ ara a teqqneḍ + + Ma ulac aɣilif err Element deg yibenk-nniḍen i izemren ad yekkes awgelhen i yiznan, akken ad yizmir ad yazen tisura ɣer tɣimit-a. + + "Seqdec taṣunit n Element tamezwert i yisawalin ara d-ikecmen " + Ad isseqdec %s d tallalt mi ara yili uqeddac-ik·im agejdan ur d-imudd ara yiwen (tansa-inek·inem IP ad tettwabḍu ayen akk ara yeqqim usiwel) + "Taṣunit n usiwel i d-ikecmen " + "Fren taṣunit i yisawalen " + + Agalis anmeggag ur yessaweḍ ara ad yerfed. + Matrix yezmer ad isenqed adlis-ik·im n tansiwin i wakken ad yaf iseqdacen-nniḍen n Matrix s ttawil n yimaylen d wuṭṭunen n tiliɣri nsen. Ma yella tqebleḍ ad tebduḍ adlis-ik·im n tansiwin i waya, ma ulac aɣilif sireg anekcum deg yisfuyla udhimen i d-iteddun. + Rnu aqeddac n timagit deg yiɣewwaren-ik·im i wakken ad tesnetmeḍ tigawt-a. + S tidet tebɣiḍ ad teǧǧeḍ taxxamt\? + Tebɣiḍ s tidet ad tekkseḍ %s seg udiwenni-a\? + Ur tettizmireḍ ara ad tesfesxeḍ asnifel-a acku tessebɣaseḍ aseqdac ad yesɛu aswir n tezmert am kečč·kemm. +\nTebɣiḍ s tidet\? + + Azgal n useqdac-a ad yekkes iznan-ines seg texxamin i tebḍiḍ. +\n +\nTzemreḍ ad tbeddleḍ tigawt-a melmi i tebɣiḍ deg yiɣewwaren imuta. + Tukksa n uzgal i useqdac-a ad d-yesken akk iznan-ines i tikkel-nniḍen. + S tidet tebɣiḍ ad tesfesxeḍ tinubga i useqdac-a\? + asuffeɣ n useqdac ad t-yekkes seg texxamt-a. +\n +\nAkken ur tettɛemmideḍ ara attekki-nsen tikkelt-nniḍen, ilaq ad t-tagiḍ xiṛ. + Tegtin n useqdac ad t-isuffeɣ seg texxamt-a rnu ur as-yettɛemmid ara ad yettekki tikkelt-nniḍen. + Tukksa n tigtin i useqdac ad t-teǧǧ ad ittekki deg texxamt tikkelt-nniḍen. + + Tebɣiḍ s tidet ad d-tnecdeḍ %s ɣer udiwenni-a\? + Ma ulac aɣilif sekcem yiwet neɣ ugar n tansiwin n yimayl neɣ asulay n Matrix + Aya yebɣa ad d-yini yellawin d ugur i tikli-inek·inem s yir udem, neɣ tiliɣri-inek·inem ur yettkil ara ɣef uselkin i as-imudd uqeddac anmeggag. + Asulay ur yemsil ara akken iwata. Ilaq ad yili d tansa n yimayl neɣ d asulay n Matrix am \'@localpart:domain\' + Tebɣiḍ ad teffreḍ meṛṛa iznan n useqdac-a\? +\n +\nẒer belli tigawt-a ad tales asenker n usnas yerna ad yeṭṭef kra n wakud. + Rnu anegzum n ugdil agejdan + + Turagin n wis tlata + Ulac uṭṭun n tiliɣri i yettwarnan ɣer umiḍan-inek·inem + Sken talɣut n usnas deg yiɣewwaren n unagraw. + Ur tezmireḍ ara ad tgeḍ aya seg Element n uziraz + Ulac imayl yettwarnan ɣer umiḍan-ik·im + Ttkel tettekkaḍ ɣef useɣwen yellan deg yimayl i ak·am-n-uznen. + + Iɣewwaren n yilɣa leqqayen + Tasleḍt n taffa tgerrez. Ma mazal ur d-tremseḍ ara ilɣa, ttxil-k·m azen aneqqis n wabug i wakken ad aɣ-talleḍ ad nefru ugur. + Yiwen neɣ ugar n yisekyaden ur ddin ara, ɛreḍ iwellihen i d-yettwasumren. + Yiwen neɣ ugar n yisekyaden ur ddin ara, ma ulac aɣilif azen aneqqis n wabug i wakken ad aɣ-talleḍ ad nefru ugur. + + Ilɣa ttwasensen i umiḍan-inek·inem. +\nMa ulac aɣilif senqed iɣewwaren n umiḍan. + Ttwaremden yilɣa i tɣimit-a. + Ur ttwaremden ara yilɣa i tɣimit-a. +\nMa ulac aɣilif senqed iɣewwaren n Element. + Ẓer belli kra n yiznan yettwarun, ttusbadun ad ilin s tsusmi (ad d-neg alɣu s war imesli). + Kra n yilɣa ttusensen deg yiɣewwaren-ik·im udmawanen. + Asali n yilugan udmawanen ur yeddi ara, ma ulac aɣilif ɛreḍ tikkelt-nniḍen. + Imeẓla APK n Google Play llan rnu d imaynuten. + Element yesseqdac imeẓla n Google Play i wakken ad d-iserreḥ i yiznan push maca ur yettban ara ttusewlen akken iwata: +\n%1$s + Ajuṭu FCM yettwasekles akken iwata ɣef uqeddac agejdan. + Asekles n ujuṭu FCM ɣef uqeddac agejdan ur yeddi ara. +\n%1$s + + Ameẓlu n yilɣa + Ameẓlu n yilɣa la iteddu. + Ameẓlu n yilɣa ur iteddu ara. +\nƐreḍ ad talseḍ asenker n usnas. + Ameẓlu n yilɣa yules asenker s wudem awurman + Ameẓlu yettwanɣa syen yules asenker s wudem awurman. + Allus n usenker n umeẓlu ur yeddi ara + + Ameẓlu ad yenker mi ara yales yibenk asenker. + "Ameẓlu ur yettenker ara mi ara yales yibenk asenker, ur d-tremseḍ ara ilɣa alamma yettwaldi Element xerṣum yiwet n tikkelt." + Rmed asenker seg tnekra + + Senqed ilugan n ugilal + Iluggan n ugilal ttusensen i Element. Asekyed-a ilaq ad yeddu s useqdec n yisefka n uziraz (ulac WIFI). +\n%1$s + Ilugan n ugilal ttwaremden i Element. +\nAmahil i yettaɛraḍ usnas ad t-yeg yesɛa talast ma mazal-it yella ɣef ugilal, aya yezmer ad d-yawi ugur i yilɣa. +\n +\n%1$s + Sens ilugan + + Asefrer n tbatrit + Anef i usefrer + + Isnasen ur srin ara ad qqnen ɣer uqeddac agejdan deg ugilal, ilaq ad tesneɣseḍ aseqdec n uẓru + • Ilɣa ttwaznen s Firebase Cloud Messaging + • Ala ilɣa kan ideg llan isefka n udfer + • Agbur n yizen n wulɣ yettusres s wudem aɣelsa srid seg uqeddac agejdan n Matrix + • Ilɣa ideg yella isefka n udfer d yizen + • Ilɣa ur d-skanayen ara agbur n yizen + + Rmed ilɣa i tɣimit-a + Cɛel agdil deg 3 tsinin + Iznan ideg yella yisem-iw yettwaskanen + Mi ara d-ttunecdeɣ ɣer texxamt + Yettusesfer i uẓru + Element ad yemtawi deg ugilal akken ara yeḥrez tilisa n teɣbula n yibenk (aẓru). +\nAlmend n waddad n teɣbalut n yibenk-inek·inem, amtawi yezmer ad iɛeṭṭel seg anagraw n wammud. + Yettusesfer i wakud ilaw + Ur d-tetteṭṭfeḍ ara ulɣu n yiznan i d-ikecmen ma yili asnas ɣef ugilal i yella. + Aleqqem n yiɣewwaren ur yeddi ara. + + + Yemmed wakud n usuter n umtawi + Yesmenyaf azilal n umtawi + %s +\nAmtawi yezmer ad yettuwexxeṛ almend n teɣbula (aẓru) neɣ adda n yibenk (tasusmi). + Tanzagt gar yal amtawi + lqem n olm + Turagin n wis tlata + Ḥrez amidyat + Sfeḍ tuffirt n umidyat + + Iɣewwaren n useqdac + Imsidaf + Asefrek n tsur n uwgelhen + Isaḍasen n wulɣu + Inermisen idiganen + Tasiregt n yinermisen + Tamurt n udlis n tiliɣri + Asebter agejdan + Reṣṣi tixxamin s yilɣa i ixuṣṣen + Reṣṣi tixxamin yesεan iznan ur nettwaɣra ara + Taskant n URL srid + Sken iseɣwan deg sqerdec mi ara yili uqeddac-ik·im agejdan yessefrak tamahilt-a. + Anef i yiseqdacen-nniḍen ad ẓren aql-ak·akem tettaruḍ. + Amsal n Markdown + Sken azemzakud i meṛṛa iznan + Sken azemzakud deg umasal n 12 yisragen + Sken awwaḍen n tɣuri + Sit ɣef wawwaḍen n tɣuri i tebdart leqqayen. + Sken ineḍruyen n uttekki d wid i yeffɣen + Asnubget, asuffeɣ d ugdal ur teddun ara + Sken ineḍruyen n umiḍan + Rnu ɣer-s isnifal n avaṭar d yisem n uskan. + Smami mi ara d-yettwabder useqdac + Sken amidyat send tuzna + Azen izen s unekcum + Aḥraz aɣelsan + Wennez aḥraz aɣelsan + Sbadu ɣef yibenk-a + Sirew tasarut n tɣellist tamaynut neɣ sbadu tafyirt n tɣellist i uḥraz-inek·nem yellan. + Aya ad yuɣal deg ubdil n tsarut-ik·im neɣ n tefyirt-ik·im tamirant. + + Sens amiḍan-inu + Sefrek iɣewwaren-inek·inem n usnirem. + Tabaḍnit n wulɣu + Mudd tasiregt + Fren taxtiṛit-nniḍen + + Tuqqna n ugilal + Mudd tasiregt + + Element ileqqeḍ tasleḍt tudrigt i wakken ad aɣ-iɛawen ad nesnerni asnas. + Ma ulac aɣilif rmed tasleḍt i wakken ad aɣ-ɛiwnent ad nesnerni Element. + Ih, bɣiɣ ad d-muddeɣ tallalt! + + Askar n usekles n yisefka + Leqqem isem azayez + Aqeddac agejdan + Sireg imsidaf + Rmed \'imsidaf n usefrek\' deg yiɣewwaren i tigin n waya. + + Ulamek akk tettwasenqed tansa n yimayl. Ma ulac aɣilif senqed imayl-inek·inem syen sit ɣef useɣwen yellan deg-s. Akken ara tgeḍ aya, sit i wakken ad tkemmleḍ. + Tansa-agi n yimayl tettuseqdac yakan. + Tansa-a n yimayl ulac-it. + Uṭṭun-agi n tilifun yettuseqddac yakan. + Tella-d tuccḍa mi ara nessenqad tansa-inek·inem n yimayl. + + Leqqem awal uffir + Aleqqem n wawal uffir ur yeddi ara + Awal uffir mačči d ameɣtu + Amiḍan-ik·im yettwalqem + Sken meṛṛa iznan seg %s\? +\n +\nẒer belli tigawt-a ad yales asenker n usnas yerna yezmer ad yeṭṭef kra n wakud. + Imdanen d wuṭṭunen n tiliɣri + Sefrek imaylen d wuṭṭunen n tiliɣri i icudden ɣer umiḍan-ik·im Matrix + + "Tebɣiḍ s tidet ad tekkseḍ alɣu-a \?" + + Tebɣiḍ s tidet ad tekkseḍ %1$s %2$s\? + + Urar s umeslaw + + Akka tura ur telliḍ ara d aɛeggal ula deg yiwet temɣiwent. + + Tawlaft n texxamt + Tabzimt n texxamt + Yettucreḍ d: + + Anekcum d tmeẓriwt + Err taxxamt-a deg tebdart n ukaram n texxamt + Anekcum n texxamt + Abani n umazray n texxamt + Aseɣwen ɣer texxamt ilaq ad yesɛu tansa. + Amasal n yismawen yettwamudden d arameɣtu + \'%s\' mačči d amasal ameɣtu i yisem yettwamudden + "Tasarut n udsil umḍin Ed25519 " + La ssenqadeɣ tisura-a ma mṣadant + + Tixxamin meṛṛa tidiganin %s + + + 1 yizen i d-yettwalɣu ur yettwaɣra ara + %d yiznan i d-yettwalɣun ur ttwaɣran ara + + + 1 yizen i d-yettwalɣu ur yettwaɣra ara + %d yiznan i d-yettwalɣun ur ttwaɣran ara + + "Rnu isaragen n usiwel s jitsi " + "Ɣer DRM yemmestnen amidyat " + + "Bdu s tkamiṛat n unagraw deg ubdil n ugdil n tkamiṛat tudmawant " + "Asarag s usiwel ha-t-an yettusnernay, ur yettizmir ara ad " + + "Taladna ur nettwaṣeggem ara: %s " + "Taladna \"%s\" tesra ugar n yiɣewwaren, neɣ kra n yiɣewwaren d arimeɣta. " + Kkes azgal i useqdac s usulay i d-yettunefkan + "Rmed/Sens tacreḍt yeɣlin " + Tacreḍt yeɣlin tettwarmed. + Tacreḍt yeɣlin tettusens. + + "Anedbal n temɣiwent ur igi ara aglam ɣezzifen i temɣiwent-a " + + Tettusuffɣeḍ-d seg %1$s sɣur %2$s + Tettusuffɣeḍ-d seg %1$s sɣur %2$s + "I wakken ad tkemmleḍ aseqdec n uqeddac agejdan %1$s ilaq ad talseḍ asenqed syen ad tqebleḍ tiwtilin-nneɣ s umata. " + Ttxil-k·m ttu akk iznan i yuzneɣ mi ara senseɣ amiḍan-iw (Ɣur-k·m: aya ad yerr iseqdacen ara d-yernun ad walin idiwenniyen ur nemmid ara) + "Taxxamt-a ad tettusmelsi, dayen d tarurmidt " + Taxxamt-a d akemmel n udiwenni-nniḍen + "nermes anedbal-inek·inem n umeẓlu " + + Aqeddac-a agejdan yessaweḍ yiwet seg tlisa-ines n teɣbalut ɣef waya kra n yiseqdacen ur ttizmiren ara ad kecmen". " + Aqeddac-a agejdan yessaweḍ talast-is n useqdac n wayyur urmid ɣef waya kra n yiseqdacen ur ttizmiren ara ad kecmen. + "Ma ulac aɣilif %s ad yaweḍ ɣer talast-a " + "Ur yeddi ara usali n yiɛeggalen n ugraw " + I yiznan d tuccḍiwin + "Ulac imeẓla APK imeɣta n Google Play i yettwafen. Ilɣa ur zmiren ara ad ddun akken iwata. " + + "Iznan deg texxamt yettwawgelhen, ttusɣelsen s uwgelhen n yixef ɣer yixef. Ala kečč·kemm d useɣyad (yiseɣyaden) i yesɛan tisura i tɣuri n yiznan-a. +\n +\nAḥraz aɣelsan n tsura-inek·inem i akken tḍemneḍ ur ak·am-ttruḥun ara " + Ḍmen aḥrazen-inek·inem s tefyirt tuffirt. + Yedda! + "Tisura-inek·inem la ttwaḥrazent. " + "Tasarut-ik·im n tririt d azeṭṭa yettwaḍmanen - tzemreḍ ad tt-tesqedceḍ i wakken ad d-terreḍ anekcum ɣer yiznan-inek·inem yettwawgelhen ma yella tettuḍ tafyirt-ik·im tuffirt. +\nErr tasarut-ik·im n tririt deg wadeg aɣelsan aṭas, am umsefrak n wawalen uffire (neɣ deg usenduq) " + "Err tasarut-ik·im n tririt deg wadeg aɣelsan s waṭas, am umsefrak n wawalen uffiren (neɣ deg usenduq) " + "Tasarut n tririt tettwasekles deg \'%s\'. +\n +\nƔur-k·m: afaylu-a yezmer ad yettwakkes ma yella ur yettusebded ara usnas. " + Yettban am wakken tesbaduḍ yakan aḥraz n tsarut seg tɣimit-nniḍen. Tebɣiḍ ad tt-tesmesliḍ s yiwet ara d-ternuḍ\? + "Asirew n tsarut n tririt s useqdec n tefyirt tuffirt, aya yezmer ad yeṭṭef ddeqs n tesdidin. " + "Tuccḍa u nettwarǧa ara " + "Tisura-inek·inem n uwgelhen ha-tent-an tura ttwaḥrazent ɣef ugilal ɣef uqeddac-ik·im agejdan. Aḥraz agejdan yezmer ad yeṭṭaf ddeqs n tsinin " + + + Yezmer tesruḥeḍ anekcum ɣer yiznan-ik·im ma yella teffɣeḍ neɣ tesruḥeḍ ibenk-a. + + Seqdec tafyirt-ik·im n tririt i twaledyawt n umazray n yiznan-ik·im yettwawgelhen + Ur tessineḍ ara tafyirt-ik·im tuffirt n tririt, tzemreḍ %s. + + Seqdec tasarut-ik·im n tririt i twaledyawt n umazray n yiznan-ik·im yettwawgelhen + Sekcem tasarut tririt + + Tesruḥeḍ tasarut-ik·im n tririt\? Tzemreḍ ad tesbaduḍ yiwet seg yiɣewwaren. + Aḥraz ur yezmir ara ad yekkes awgelhen s tefyirt-a tuffirt: ttxil-k·m selken ma yella d tafyirt tuffirt tameɣtut i teskecmeḍ. + Tuccḍa deg uzeṭṭa: ma ulac aɣilif senqed tuqqna-inek·inem syen ɛreḍ tikkelt-nniḍen. + + Tiririt n uḥraz: + Askazal n tsarut n tririt... + Asali n tsura... + Aktar n tsura... + "Aḥraz yettwarr-d %s! " + + Yerra-d aḥraz s tsarut %d. + Yerra-d aḥraz s tsura %d. + + + Tisura timaynutin %d ttwarnant ɣer tɣimit. + + + + Tiririt n lqem akk aneggaru n tsura (%s) ur teddi ara. + "Awgelhen n tɣimit ur yettwarmed ara " + + + Aḥraz n tsarut yettusbadu akken iwata i tɣimit-a. + Aḥraz n tsarut ur yermid ara i tɣimit-a. + Tisura-inek·inem ur ttwaḥrazent ara seg tɣimit-a. + + Aḥraz ɣer-s azmul seg tɣimit tarussint s usulay %s. + Aḥraz ɣer-s azmul ameɣtu seg tɣimit-a. + Aḥraz ɣer-s azmul ameɣtu seg tɣimit %s yettusneqden. + Aḥraz ɣer-s azmul ameɣtu seg tɣimit ur yettusneqden ara %s + Aḥraz ɣer-s azmul arameɣtu seg tɣimit yettusneqden %s + Aḥraz ɣer-s azmul arameɣtu seg tɣimit ur yettusneqden ara %s + Awway n telɣut yettwattkalen i uḥraz (%s) ur yeddi ara. + + "I useqdec n uḥraz n tsarut deg tɣimit-a, err-d s tefyir-ik·im tuffirt neɣ s tsarut n tririt tura " + Tukksa n uḥraz (%s) ur teddi ara + + Asenqed n waddad n uḥraz + "Kkes tisura-inek·inem n uwgelhen yettwaḥerzen seg uqeddac\? Ur tettuɣaleḍ ara ad tizmireḍ ad tesqedceḍ tasarut-ik·im n tririt i tɣuri n umazray n yiznan yettwawgelhen. " + + Aḥraz n tsarut amaynut n yizen aɣelsan tettwaf-d. +\n +\nMa yella ur tesbaduḍ ara tarrayt n tririt tamaynut, amker yezmer ad yeɛreḍ ad yekcem ɣer umiḍan-ik·im. Snifel awal uffir n umiḍan-ik·im syen sbadu tarrayt n tririt tamaynut din din deg yiɣewwaren. + Aḥraz aɣelsan + "Seḥbiber iman-ik·im ɣef usruḥ n unekcum ɣer yiznann & yisefka yettwawgelhe " + + "Tisura n yizenaɣelsan timaynutin " + Sefrek deg uḥraz n tsarut + + Aḥraz n tsura-inek·inem. Aya yezmer ad yeṭṭef aṭas n tesdidin... + + + Sbadu aḥraz aɣelsan + + + Aḥraz n tsarut %d + Aḥraz n tsura %d + + + "Iɣewwaren n uqeddac uwurman ummid " + "Element yufa-d tawila n uqeddac udmawan i taɣult-inek·inem usulay n uqeddac \"%1$s\": +\n%2$s " + Seqdec tawila + + "Tettuseffɣeḍ ssebba n credentials arimeɣta neɣ yekfan " + + "Senqed s userwes n yiḍrisen imeẓẓyanen " + "Bdu asenqed " + "Aselken n tɣimit-a ad yettucreḍ fell-as tettwattkal, yerna ad tettucreḍ ula d tiɣimit-ik·im tettwattkal i bab-is. " + + "Selkem tiɣimit-a s usentem n yimujiten-a i d-yettbanen ɣef ugdil n baba-is " + "Selkem tiɣimit-a s usentem n wuṭṭunen-a i d-yettbanen ɣef ugdil n baba-is " + + Tremseḍ-d asuter n uselken i d-iteddun... + "Aṛaǧu n bab-is i usentem ..." + + Teslekneḍ taxxamt-a akken iwata. + "Ulac acu i d-yettwabnen\? Mačči akkimsaɣen ssefraken aselken amyigew ar tura. Seqdec aselken " + "Seqdec aselken " + + Tama-nniḍen tessefsax aselken. +\n%s + "Aselken yettusefsax. +\nTaɣzint: %s " + + "Aselken amyigaw n tɣimit " + %s yebɣa ad issenqed tiɣimit-inek·inem + + Aseqdac issefsax asenqed + "Akud n usenqed yemmed " + "Tiɣimit ur teẓri ara ɣef tnigawt-a " + "SAS ur imsaḍa ara " + SAS ur imsaḍa ara + "Tiɣimit termes-d izen ideg yella ccekk " + "Yettwarmes-d yizen arameɣtu " + "Tasarut temṣada swaswa " + "Aseqdac yemṣada swaswa " + Ur tesseqdaceḍ ara ula d yiwen n uqeddac n timagit + "Ulac aqeddac n timagit yettusiwlen, yettusra ad twennzeḍ awal-inek·inem uffir " + + Yettban-d am wakken tettaɛraḍeḍ ad teqqneḍ ɣer uqeddac agejdan-nniḍen. Tebɣiḍ ad teffɣeḍ\? + + Ttekki deg usarag s useqdec n usnas. + "Yuzen-ak·am-d tinubga " + "Tettwafem akken ma tellam! " + "Ur tesɛiḍ ara iznan-nniḍen ur nettwaɣra ara " + Ansuf ɣer uxxam! + "Idiwenniyen n yizen usrid ad d-ttwaskanen da " + Tixxamin-inek·inem ad d-ttwaskanent da + + "Rnu " + "Wali " + Sken-d iznan yettwakksen + Yettewekkes uneḍru sɣur aseqdac + "Aneḍru yellan s lmendad n unedbal n texxamt " + Aneggaru yettwaẓreg sɣer %1$s ɣef %2$s + + + Aneḍru ur nemsil ara, ulamek ara d-yettwaskan + Ulac azeṭṭa. Ma ulac aɣilif senqed tuqqna-inek·inem ɣer Internet. + Ma ulac aɣilif ṛǧu... + "Taxxamt-a ulamek ad tettwasenqad " + "Suffeɣ-d taxamt-a deg ukaram n texxamin " + "Taxxamt tettwarna, maca kra n tinubgiwin ur ttwaznent ara i taɣznt-a: +\n +\n%s " + + "Tella-d tuccḍa deg wawway n telɣut yettwattkalen " + "Tella-d tuccḍa deg wawway n yisefka n uḥraz n tsura " + + Kter tisura e2e seg ufaylu \"%1$s\". + + Turagin-nniḍen n wis tlata.. + Tesneqdeḍ yakan taxxamt-a! + + "Ulac ilugan n push yettusbadun " + "Glem-d isniram-inek·inem da " + Tanemmirt, isumar ttwaznen akken iwata + "Tuzna n yisumar ur teddi ara (%) " + + Awgelhen n utṛumbun... + Awgelhen n ufaylu... + Tuzna n ufaylu (%1$s / %2$s) + + Asali n ufaylu %1$s… + Afaylu %1$s yettusider-d! + + Ur nezmir ara ad d-naf ayen i tettnadiḍ\? + Rnu taxxamt tamaynut + Azen izen usrid amaynut + Ẓer akaram n texxamt + + Ulac igmaḍ i yettwafen, seqdec Rnu s usulan n Matrix i unadi ɣef uqeddac. + Bdu aru i wakken ad tesɛuḍ igmaḍ + Sizdeg s yisem n useqdac neq s usulay... + + Attekki deg texxamt... + + Ẓer amazray i yettuẓergen + + "Senqed tiwtilin " + "Ili-k tettwafeḍ sɣur wiyaḍ " + "Seqdec abuten, tileggiyin, iwiǧiten d yikemmusen n yistikar " + + Swel aqeddac n timagit + "Aql-ak·akem akka tura tesseqdaceḍ %1$s i wakken ad d-tefeḍ, dɣen ad tettwafeḍ sɣur inermisen yellan i tessneḍ " + Akka tura ur tesseqdaceḍ aqeddac n timagit. I wakken ad d-tafeḍ daɣen ad d-tettwafeḍ sɣur yinermisen yellan i tessneḍ, rnu yiwen ddaw. + "Tansiwin n yimayl yettwafen " + Tixtiṛiyin n usnirem ad d-banent akken ara ternuḍ imayl + Tixtiṛiyin n usnirem ad d-banent akken ara ternuḍ uṭṭun n tilifun + "Asefsex n tuqqna seg uqeddac-ik·im n timagit yebɣa ad d-yini ur tebɣiḍ ara ad ak·akem-id-afen wiyaḍ, ur tettizmireḍ ara daɣen ad d-tsnubegteḍ wiyaḍ s yimayl neɣ s wuṭṭun n tiliɣri. " + "Uṭṭunen n tiliɣri i d-yettbanen " + Nuzen-ak·am-n imayl n usentem ɣer %s, senqed imayl-inek·inem syen sit ɣef useɣwen n usentem + Nuzen-ak·am-n imayl n usentem ɣer %s, ttxil-k·m deg tazwara senqed imayl-inek·inem syen sit ɣef useɣwen n usentem + Sekcem URL n uqeddac n timagit + Ur nezmir ara ad neqqen ɣer uqeddac n timagit + Ma ulac aɣilif sekcem url n uqeddac n timagit + "Timagit n uqeddac ulac ɣer-s tiwtilin " + Izen n uḍris yettwazen ɣer %s. Ttxil-k·m sekcem tangalt n uselken yellan deg-s. + Tangalt n uselken d tarameɣtut. + + Tura akka tebdiḍ tansiwin n yimayl neɣ uṭṭunen n tiliɣri ɣef uqeddac n timagit %1$s. Tesriḍ ad talseḍ tuqqna ɣer %2$s i useḥbes n beṭṭu-nsen. + Qbel tiwtilin n umeẓlu n uqeddac n timagit (%s) i wakken ad tsirgeḍ iman-ik·im ad d-tettwafeḍ s yimayl neɣ s wuṭṭun n tiliɣri. + + Azen taceqquft yeddan + + "Ldi tunigin " + "Ldi umuɣ n tmerna n texxamin " + "Mdel umuɣ n tmerna n texxamin... " + Rnu adiwenni usrid amaynut + Rnu taxxamt tamaynut + "Ɛeddi ɣer usawen " + + "Azen aqbur-a " + Agbur-a yettwakter-d. +\n +\nMa yella ur tebɣiḍ ara ad twaliḍ ugar n yigburen-nniḍen sɣur aseqdac-a, tzemreḍ ad t-tesweḥleḍ i wakken ad teffreḍ iznan-ines + Agbur-a yettwakter-d d aspam. +\n +\nMa yella ur tebɣiḍ ara ad twaliḍ ugar n yigburen-nniḍen sɣur aseqdac-a, tzemreḍ ad t-tesweḥleḍ i wakken ad teffreḍ iznan-ines + Agbur-a yettwakter-d mačči d win i iwulmen. +\n +\nMa yella dayen ur tebɣiḍ ara ad twaliḍ agbur-nniḍen sɣur aseqdac-a, tzemreḍ ad t-tesweḥleḍ i wakken ad teffreḍ iznan-ines + + Element yesra tasiregt i usekles n tsura-inek·inem E2E ɣef uḍebsi. +\n +\nMa ulac aɣilif sireg anekcum ɣef yisfuyla udhimen i d-iteddun i wakken ad tizmireḍ ad tsifḍeḍ tisura-ik·im s ufus. + + "Tella tuqqna n uzeṭṭa tgerrez tura " + + "Yuzen iznan i d-yettunefken yeɣma s yiniten d ucmit " + "Ucmit " + "Rnu ɣer yimelyan baṭel ɣef uqeddac azayez ameqqran akk " + Tanezduɣt n Premium i tkebbaniyin + Iɣewwaren udmawanen & leqqayen + + Qqen ɣer yimeẓla n Element Matrix + Qqen aqeddac udmawan + Tanezduɣt n Premium i tkebbaniyin + "Sekcem tansa n Element Modular neɣ n uqeddac i tebɣiḍ ad t-tesqedceḍ " + Sekcem tansa n uqeddac neɣ n Element i tebɣiḍ ad teqqneḍ ɣer-s + Tella-d tuccḍa mi ara d-nessalay asebter: %1$s (%2$d) + Asnas ur yezmir ara ad yekcem ɣer uqeddac-a agejdan. Aqeddac agejdan yessefrak anaw-a n unekcum: %1$s. +\n +\nTebɣiḍ ad tkecmeḍ s useqdec n umsaɣ web\? + Suref-aɣ, aqeddac-a ur iqebbel ara imiḍanen imaynuten. + "Asnas ur yezmir ara ad yernu amiḍan ɣef uqeddac-a agejdan. +\n +\nTebɣiḍ ad tjerrdeḍ i useqdec n umsaɣ web\? " + + "Awal-ik·im uffir mazal ar tura ur yettusenfel ara. +\n +\nSeḥbes aseddu " + + "Sbadu imayl i wakken ad d-terreḍ amiḍan-ik·im. Ticki, tzemreḍ s wudem afrayan ad tsirgeḍ imdanen i tessneḍ ad ak·akem-afen s yimayl-inek·inem. " + Sbadu uṭṭun n tiliɣri s wudem afrayan ad tsirgeḍ imdanen i tessneḍ ad ak·akem-afen. + "Ma ulac aɣilif amasal agreɣlan. " + Aql-aɣ akken nuzen tangalt ɣer %1$s. Sekcem-it ddaw i uselken ma d kečč·kemm. + "Ma ulac aɣilif seqdec amasal agreɣlan (uṭṭun n tiliɣri ilaq ad yebdu s \'+\') " + "Uṭṭun n tiliɣri agreɣlan ilaq ad yebdu s \'+\' " + Uṭṭun n tiliɣri yettban-d d arameɣtu. Ma ulac aɣilif senqed-it + + "Amiḍan-ik·im mazal ur yettwarna ara ar tura. +\n +\nSeḥbes amulteɣ " + + "Aql-aɣ akken nuzen imayl ɣer %1$s. +\nMa ulac aɣilif sit ɣef useɣwen i yellan deg-s i wakken ad tkemmleḍ timerna. " + Tangalt yettwaskecmen d tarameɣtut. Ma ulac aɣilif senqed. + "Aqeddac agejdan yemmut " + "Aqeddac-a agejdan isselkam daɣen lqem aqbur i tuqqna ɣer-s. Suter anedbal n uqeddac-ik·im aqejden ad t-tleqqemḍ. " + + + "Aṭas n yisutar i yettwaznen. Tzemreḍ ad tɛerḍeḍ ticki deg %1$d tasint… " + "Aṭas n yisutar i yettwaznen. Tzemreḍ ad tɛerḍeḍ ticki deg %1$d tsinin… " + + + "ma yella tesɛiḍ yakan amiḍan yerna tessneḍ identifier-inek·inem n Matrix d wawal-inek·inem uffir, tzemreḍ ad tesqedceḍ tarrayt-a " + Ma yella tesbaduḍ amiḍan ɣef uqeddac agejdan, seqdec asulay-inek·inem n Matrix (am. @user:domain.com) d wawal uffir ddaw. + Ma yella ur tecfiḍ ara ɣef wawal-ik·im uffir, uɣal ɣer deffir ad t-twennzeḍ. + Wagi mačči d identifier n useqdac ameɣtu. Amasal deg-s ccekk: \'@user:homeserver.org\' + "D awezɣi ad d-naf aqeddac agejdan ameɣtu. Ma ulac aɣilif senqed identifier-inek·inem " + + "Yezmer ad yili seg waṭas n ssebbat: +\n +\n• Tbeddleḍ awal-ik·im uffir deg tɣimit-nniḍen. +\n +\n• Tekkseḍ tiɣimit-a seg tɣimit-nniḍen. +\n +\n• Anedbal n uqeddac-ik·im ur isɛedda ara anekcum-inek·inem i ssebba n tɣellist. " + "Anedbal n uqeddac-ik·im agejdan (%1$s) admin isuffeɣ-ik·ikem seg umiḍan-inek·inem %2$s (%3$s). " + "Kcem i wakken ad d-terreḍ tisura n uwgelhen i d-yettwarranɣef yibenk-a s timmad-is. Tesriḍ-tent i tɣuri n meṛṛa iznan-inek·inem iɣelsanen ɣef yal ibenk " + "Ɣur-k·m: Isefka-inek·inem udmawanen (rnu ɣer-sen tisur n uwgelhen) mazal ttukelsent ɣef yibenk-a. +\n +\nSfeḍ-iten ma yella tekfiḍ aseqdec n yibenk-a, neɣ tebɣiḍ ad tkecmeḍ ɣer umiḍan-nniḍen " + "Sfeḍ meṛṛa isefka yettukelsen melmi kan ɣef yibenk-a\? +\nKcem tikkelt-nniḍen i wakken ad tkecmeḍ ɣer yisefka d yiznan n umiḍan-inek·inem " + Aseɣwen-inek·inem n Matrix.to ur yemsil ara akken iwata + Ala igmaḍ imezwura i d-yettwaseknen, aru ugar n yisekkilen… + + "Element yezmer ad iḍeyyer ugar mi ara " + + "Taɣult-ik·im n yimayl ur tesɛi ara azref i wakken ad tettwasekles ɣef uqeddac-a " + + "Anekcum ur nettwattkal ara " + "Selken aseqdac-a s usentem n yimujit asuf i d-iteddun i d-yettbanen ɣef ugdil-ines, deg yiwem umsizwer " + "I tɣellist i ilaqen, seqdec iberdan-nniḍen yettwatteklen n teywalt neɣ eg aya s timmad-ik·im " + "Muqel shield azegzaw i wakken ad tḍemneḍ aseqdac yettuttkal. Ttkel ɣef meṛṛa iseqdacen yellan deg texamt i wakken ad tḍemneḍ taxxamt d taɣelsant " + + "Yiwen seg wayen i d-iteddun yezmer ad yettwaker: +\n +\n- Aqeddac-ik·im agejdan +\n- Aqeddac agejdan wuɣur yeqqen useqdac tesselkaneḍ +\n- Tuqqna-inek·inem n internet neɣ tin n yiseqdac-nniḍen +\n- Ibenk-inek·inem neɣ win n yiseqdac-nniḍen " + + "Freḍ tangalt d yibenk-nniḍen n useqdac i wakken ad teslekneḍ yal yiwen s wudem aɣelsan " + "Ulamek yettwafreḍ " + "Ma yella mačči d kečč·kemm s timmad-ik·im, serwes imujit deg ubdil " + + Selken s userwes n yimujiten + + Senqed s yimujit + "Ma yella ur tezmireḍ ara ad tferḍeḍ tangalt nnig, selken s uselken n yimujit amecṭuḥ d tefrayt-is tasuft " + + Tugna n tengalt QR + + Senqed %s + Yettusenqed %s + "I tɣelliset akk i ifazen, selken %s s usenqed n tengalt n tikklet deg yibenkan-inek·inem +\n +\nI tɣellist tafellayt, eg aya s timmad-ik·im " + "Iznan deg texxamt-a ttwawgelhen seg yixef ɣer yixef. +\n +\nIznan-inek·inem ttwaɣellsen s lemfatiḥ, rnu ala kečč d umesɣad i yesɛan tisura tasufin i tweldaywt-nsen " + Tigawin n unedbal + Iɣewwaren n texxamt + + Yiwen umdan + %1$d yimdanen + + Tuffɣa n texxamt... + + Imaẓragen + "Dbel deg %1$s " + D amaẓrag deg %1$s + "Amezwer deg %1$s " + D udmawan (%1$d) deg %2$s + + "Element ur isekker ara ineḍruyen n wanaw \'%1$s\'" + "Element ur isekker ara izen n wanaw \'%1$s\'" + "Element yemlal-d ugur mi ara d-yettarra agbur n uneḍru s usulay \'%1$s\' " + + Tiɣimit-a ulamek ara tebḍu aselken-a akked tqimiyin-nniḍen. +\nAselken ad yettwaseklas s wudem adigan syen yettwabḍu deg lqem i d-iteddun n usnas. + + Tixxamin n melmi kan + Tixxamin-nniḍen + + Yuzen iznan i d-yettunefken yeɣma s yiniten am teslit n Unẓar + "Yuzen tanfalit i d-yettunefken teɣma s yiniten am teslit n Unẓar " + + Amaẓrag n yizen + + Akken ara tremdeḍ awgelhen i texxamt ur yettizmir ara ad yekkes. Iznan n texxamt tawgelhant ur tent-yettwali ara uqeddac, ala wid yettekkan deg texxamt. Armad n uwgelhen ur yettaǧǧa ara kra n yiṛubuten d kra n tleggiyin ad ddun akken iwata. Issin ugar ɣef uwgelhen. + "I wakken ad tḍemneḍ taɣellist-ik·im, selken %s s usenqed n tengalt " + I wakken ad tḍemneḍ taɣellistik·im, eg ayagi s timmad-ik·im neɣ seqdec abrid n teywalt iɣef ara tettekleḍ. + + Serwes imujit ufrin, s uḍman ad d-banen deg yiwen usemizwer. + Serwes tangalt d win i d-yettwaskanen ɣef ugdil n useqdac-nniḍen. + Iznan akked useqdac-a ttwawgelhen seg yixef ɣer yixef yerna ur yezmir wis tlata ad ten-iɣer. + Azmul anmidag + Azmul anmidag yettwarmed +\nTisura tusligin ɣef yibenk. + Azmul anmidag yettwarmed +\nTisura ttwattkalent. +\nTisura tusligen ur ttwassnent ara + Azmul anmidag yettwarmed +\nTisura ttwattkalent. + Azmul anmidag ur yettwarmed ara + + Tɣimiyin turmidin + Sken meṛṛa tiɣimiyin + Sefrek tiɣimiyin + Ffeɣ seg tɣimit-a + + Ulac talɣut n uwgelhen i yellan + + Tiɣimit-a tettwattkal i yiznan iɣelsanen acku tesneqdeḍ-tt: + "Selken tiɣimit-a i wakken ad tt-tcerḍeḍ tettwattkal & anef-as ad tekcem ɣer yiznan yettwawgelhen. Ma yella ur tesriḍ ara ad tkecmeḍ ɣer tɣimit-a, amiḍan-inek·inem yezmer ad yettwaker " + + + %d tɣimit t ururmidt + %d tɣimiyin turmidin + + + Yemmed s wudem aɣelsan + + "Seqdec tiɣimit i yellan i wakken ad tesneqdeḍ tagi, s umuddu n uzref i wakken ad tekcem ɣer yiznan yettwawgelhen. " + + + Awway n tɣimiyin ur yeddi ara + Tiɣimit-a tettwattkal i yiznan iɣelsanen acku %1$s (%2$s) issenqed-itt: + %1$s (%2$s) yettuzmel deg useqdec n tɣimit tamaynut: + "Akken ara yettkel useqdac-a ɣef tɣimit-a, iznan yettwaznen ɣer neɣ i d-yettwaznen seg ad sɛun lemḥadra. Syen, tzemreḍ ad tent-slekneḍ s ufus " + + + Wennez azmul anmidag + Tangalt QR + + "Qrib ad tawḍeḍ! Kifkif %s aɣar i d-yeskanay\? " + Tuqqna ɣer uqeddac truḥ + "Askar n yermed " + + "Ifecka n yibenk " + + %d tafrant + %d tifranin + + + %d tafrant - Igmaḍ n taggara + %d tifranin - Igmaḍ n taggara + + "Yerna poll afessas " + Seqdec tafyirt tuffirt n tririt neɣ tasarut + Ma yella ur tezmireḍ ara ad tkecmeḍ ɣer tɣimit i yellan + + Ur nessaweḍ ara ad naf tuffirin deg uklas + Ilaq ad tkecmeḍ ɣer uklas uffir ala seg yibenk yetwaḍemnen + + Kkes... + Tebqiḍ ad tazneḍ taceqquft-a yaddan i %1$s\? + + "Azen tugna s teɣzi tagejdant " + "Azen tuniwin s teɣzi tagejdant " + + + Rnu taɣzint + "Taɣzint i tira " + + Yettewekkes uneḍru sɣur aseqdac, taɣzint: %1$s + "Aneḍru yellan s lmendad n unedbal n texxamt, taɣzint: %1$s " + + Serreḥ i umazray n yiznan yettwawgelhen + + Aru i usenqed d uselken + "Seqdec tiɣimit-a i usenqed tiɣimit-ik·im tamaynut, s tikci n uzref i wakken ad tekcem ɣer yiznan yettwawgelhen. " + "Mačči d nekk " + Amiḍan-ik·im yezmer ad yettwaker + + "Ma yella teffɣeḍ, ur tettizmireḍ ara ad teɣreḍ iznan yettwawgelhen ɣef yibenk-a, ula d iseqdacen-nniḍen ur t-ttamnen ara " + "Ma yella teffɣeḍ, ur tettizmireḍ ara ad teɣreḍ iznan yettwawgelhen ɣef yibenk-inek·inem amaynut, ula d iseqdacen-nniḍen ur t-ttamnen ara " + "Ur tesneqdeḍ ara %1$s (%2$s) ma yella ad teffɣeḍ tura. Bdu tikkelt-a deg umaɣun-ines n useqdac " + + "Yiwen seg wayen i d-iteddun yezmer ad yettwaker: +\n +\n-Awal-ik·im uffir +\n-Aqeddac-ik·im agejdan +\nIbenk-a, neɣ ibenk-nniḍen +\n-Tuqqna ɣer internet n yibenkan-nniḍen yettuseqdacen +\n +\nAd ak·akem-nwelleh ad tesnifleḍ awal-ik·im uffir & tsarut n tririt deg yiɣewwaren tura tura " + + Senqed ibenkan-ik·im seg yiɣewwaren. + Yettwasefsex usenqed + + Tefyirt tuffirt n tririt + Tasarut n yizen + Awal uffir n umiḍan + + Sbadu %s + Sirew tasarut n yizen + + Sentem %s + + Sekcem %s inek·inem i wakken ad tkemmleḍ. + + "Ḍmen & ldi iznan yettwawgelhen syen ttkel s %s " + Sekcem %s inek·inem i usentem-ines. + Ur sseqdac ara awal-ik·im uffir n umiḍan. + + Sekcem tafyirt n tɣellist ara tissineḍ kan keččini·kemmini, tettuseqdac i wakken ad teḍmen tuffriwin deg uqeddac-ik·im. + + Asbadu n tefyirt tuffirt n tririt ad ak·am-teḍmen taɣellist & tawaledyawt n yiznan yettwawgelhen, yettwattkalen. + Ma yella teffɣeḍ tura, yezmer ad ak·am-ruḥen yiznan yettwawgelhen d yisefka ma yella tesruḥeḍ anekcum ɣer yinekcam-inek·inem. +\n +\nTzemreḍ ad tesbaduḍ aḥraz aɣelsan rnu ad tesferkeḍ tisura-inek·inem melmi i tebɣiḍ deg yiɣewwaren. + + Iznan deg texxamt-a ttwawgelhen seg yixef ɣer yixef. Issin ugar & senqed iseqdacen deg yimuɣna-nsen. + Awgelhen yettusqedcen deg texxamt-a ur yettusefrak ara. + + %s yerna taxxamt syen iswel-itt. + Aql-ak·akem terniḍ, tsewleḍ taxxamt. + + Qrib ad tawḍeḍ! Wissen ma yella ibenk-nniḍen kifkif aɣar i d-yeskanay\? + Qrib ad tawḍeḍ! Aṛaǧu i usentem..... + Aktar n tsura ur yeddi ara + + "Aswel n yilɣa " + Sbadu azal n wulɣu s uneḍru + + Isem n useqdac d/neɣ awal uffir d arameɣtu. Awal uffir yettwaskecmen yebda neɣ yekfa s tallunt, ma ulac aɣilif senqed-it. + Izen… + + Rmed azmul anmidag + Sekcem %s inek·inem i wakken ad tkemmleḍ + Tefyirt tuffirt n tririt + Tasarut n tririt mačči d tameɣtut + Asenqed n tsarut n uḥraz + Asenqed n tsarut n uḥraz (%s) + Awway n tsarut n uzlig + "Tiririt n tuffirt n uḥraz n tsarut deg SSSS " + Sekcem tafyirt tuffirt n uḥraz n tsarut i wakken ad tkemmleḍ. + "seqdec tasarut n tririt n uḥraz n tsarut " + Ur tessineḍ ara tafyirt-ik·im tuffirt n uḥraz n tsarut, tzemreḍ %s + "Tasarut n tririt n uḥraz n tsarut " + + "Tuṭṭfiwin n ugdil n usnas i yezrin " + "Armad n uɣewwar-a ad yernu FLAG_SECURE ɣer meṛṛa irmad. Ales asenker n usnas i wakken ad yemmed usnifel " + + "Afaylu n umidyat yettwarna ɣer temsikent " + "Ur yezmir ara ad yernu afaylu n umidyat ɣer " + "Seqdec lqem akk aneggaru n Element ɣef yibenkan-inek·inem-nniḍen, Element Web, Element Desktop, Element iOS, Element i Android neɣ azmul anmidag wayeḍ i izemren i umsaɣ n Matrix " + "Fren tasarut-ik·im n tririt, neɣ err-itt s ufus s tira-ines neɣ s usenteḍ-ines seg ɣefafus-inek·inem " + Senqed amyigew s yimujit + Sentem timagit-inek·inem s usenqed n yinekcam-a, anef-as ad yekcem ɣer yiznan yettwawgelhen. + "Suref-aɣ, tigawt ulamek i tedda akka tura i yimiḍanen i yettwaqqnen s useqdec n tuqqna ɣef asuf " + + "Sit snat n tikkal ɣef useɣwen " + Aseɣwen %1$s ad ak·akem-yawi ɣer usmel-nniḍen: %2$s. +\n +\nTebɣiḍ s tidet ad tkemmleḍ\? + + Ffeɣ seg tuqqna n uqeddac n timagit %s\? + "Aqeddac-a n timagit iɛedda wazemz-ines. Element yessafrak kan API V2. " + "Tigawt-a ulamek tedda. Aqeddac agejdan yemmut " + Ma ulac aɣilif qbel deg tazwara swel aqeddac n timagit. + Ma ulac aɣilif qbel deg tazwara tiwtilin n uqeddac n timagit deg yiɣewwaren. + "I tɣellist n tbaḍnit-ik·im, Element yessefrak kan yimaylen d wuṭṭunen n tiliɣri" + "Tawsit ur teddi ara " + "Mačči d tadrut tamirant akked unaglam-a " + + "Aqeddac-ik·im agejdan (%1$s) yefka-d takti n useqdec n %2$s i uqeddac-ik·im n timagit " + tzemreḍ ad teskecmeḍ URl n uqeddac n timagit i tebɣiḍn + Sekcem URL i uqeddac n timagit + Sekcem tafyirt n tɣellist ara tissineḍ kan kečč·kemm, syen sirew tasarut i uḥraz. + + Sekcem tafyirt n tɣellist ara tissineḍ kan keččini·kemmini, tettuseqdac i wakken ad teḍmen tuffriwin deg uqeddac-ik·im. + Sekcem tafyirt-inek·inem n tɣellist tikkelt-nniḍen i usentem-ines. + + "Rǧu izen-a, yezmer ad iɛeṭṭel " + "Ur tezmireḍ ara ad teldiḍ taxxamt anisi i d-tettwasuffɣeḍ " + Ur nessaweḍ ara ad d-naf taxamt-a. Muqel ma tella d tidet. + From 709e9daf404f045f4cfb84f982f30850025502b7 Mon Sep 17 00:00:00 2001 From: Kahina Messaoudi Date: Sat, 12 Sep 2020 04:52:40 +0000 Subject: [PATCH 54/89] Translated using Weblate (Kabyle) Currently translated at 97.0% (1811 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/kab/ --- vector/src/main/res/values-kab/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index caba9748d4..2399c7e51b 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -490,7 +490,7 @@ Isem n texxamt Tura, Riot d aferdis! Sefesex tinnubga - Asent status.iml + Asentel Status.im Amtawi… Timesliwt i yineḍruyen From d429800162b0f9d4e0196bedd01dd1acc2d5a88f Mon Sep 17 00:00:00 2001 From: Kahina Messaoudi Date: Sat, 12 Sep 2020 10:50:18 +0000 Subject: [PATCH 55/89] Translated using Weblate (Kabyle) Currently translated at 97.0% (1811 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/kab/ --- vector/src/main/res/values-kab/strings.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index 2399c7e51b..75e508e829 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -1563,7 +1563,7 @@ Talɣut n uneḍru Asulay n useqdac Tasarut n timagit Curve25519 - "Talɣut n umesgal n tɣimit " + Talɣut n umazan n tɣimit Isem azayez Isem azayez (yettban i yimdanen wukud tettmeslayeḍ) Isem azayez @@ -1576,8 +1576,8 @@ \nƔur-k·m: afaylu-a yezmer ad yettwakkes ma yella asnas ur yettusebded ara. Asifeḍ n tsura yedda akken iwata - "Iznan yettwawgelhen n tririt " - Sefrek aḥraz n tsarut + Tiririt n yiznan yettwawgelhen + Sefrek aklas n tsura Kter tisura n ufaylu adigan Wgelhen i usenqed n tɣimiyinkan @@ -1853,7 +1853,7 @@ Aseɣwen ɣer texxamt ilaq ad yesɛu tansa. Amasal n yismawen yettwamudden d arameɣtu \'%s\' mačči d amasal ameɣtu i yisem yettwamudden - "Tasarut n udsil umḍin Ed25519 " + Tasarut n udsil umḍin Ed25519 La ssenqadeɣ tisura-a ma mṣadant Tixxamin meṛṛa tidiganin %s @@ -1937,7 +1937,7 @@ Tisura timaynutin %d ttwarnant ɣer tɣimit. - + Tiririt n lqem akk aneggaru n tsura (%s) ur teddi ara. From 808eb9a12abda0e9819a5f5600d96aa3b148f6d4 Mon Sep 17 00:00:00 2001 From: ziriSut Date: Sat, 12 Sep 2020 11:25:20 +0000 Subject: [PATCH 56/89] Translated using Weblate (Kabyle) Currently translated at 97.0% (1811 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/kab/ --- vector/src/main/res/values-kab/strings.xml | 106 ++++++++++----------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index 75e508e829..f70a2818bb 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -1563,7 +1563,7 @@ Talɣut n uneḍru Asulay n useqdac Tasarut n timagit Curve25519 - Talɣut n umazan n tɣimit + "Talɣut ɣef tɣimit n umazan" Isem azayez Isem azayez (yettban i yimdanen wukud tettmeslayeḍ) Isem azayez @@ -1596,11 +1596,11 @@ Kkes seg tebdart taberkant Taxxamt ideg llant tɣimiyin tarussanin - "Taxxamt-a deg-s tiɣimiyin tarussinin ur nettwaselken ara. -\nAya yebɣa ad d-yini ur ttwaḍmanent ara tɣimiyin-a yerzan iseqdac i keččmen ɣer-sent. -\nAd ak·akem-nwelleh ad tuɣaleḍ ɣer ukala n uselken n yal tiɣimit send akemmel, maca tzemreḍ ad talseḍ tuzna n yizen war aselken ma yella tebɣiḍ. + Taxxamt-a deg-s tiɣimiyin tarussinin ur nettwasenqed ara. +\nAya yebɣa ad d-yini ulac aḍman belli tɣimiyin-a d tidet n yiseqdacen i d-temmal. +\nAd ak·akem-nwelleh ad tuɣaleḍ ɣer ukala n usenqed n yal tiɣimit send akemmel, maca tzemreḍ ad talseḍ tuzna n yizen war asenqed ma yella tebɣiḍ. \n -\nTiɣimiyin tarussinin: " +\nTiɣimiyin tarussinin: Fren akaram n texxamt Aru aqeddac agejdan i wakken ad d-tbedreḍ tixxamin tizuyaz seg-s @@ -1623,25 +1623,25 @@ 1 uwiǧit i yettwaremden %d n yiwiǧiten i yettwaremden - "Nesḥassef, asarag s usiwel s Jitsi ur yettusefrak ara ɣef yibenkan iqburen (ibenkan s Android OS ddaw 5.0) " + Nesḥassef, asarag s usiwel s Jitsi ur yettusefrak ara ɣef yibenkan iqburen (ibenkan s Android OS ddaw 5.0) Iwiǧit-a yebɣa ad isseqdec tiɣbula-a: Seqdec takamiṛat Seqdec asawaḍ - "Seqdec anasiw sekcem tasarut i tuzna n yizen " + Seqdec taqeffalt n unasiw Kcem i tuzna n yizen Taxtiṛit-a tesra asnas n wis tlata i usekles n yiznan. I wakken ad tkemmleḍ tesriḍ ad tqebleḍ tiwtilin n umeẓlu-a. - "Terniḍ tiɣimit tamaynut \'%s\', i yessuturen tisura n uwgelhen. " - "Tiɣimit tamaynut tessutur isem n key.ession n uwgelhen: %1$s + Terniḍ tiɣimit tamaynut \'%s\', i yessuturen tisura n uwgelhen. + Tiɣimit tamaynut tessutur tisura n uwgelhen. Isem n tɣimit: %1$s \nTimeẓriwt taneggarut: %2$s -\nMa yella ur tekcimeḍ ara ɣer tqimit-nniḍen, ttu asuter-a. " - "Terniḍ tiɣimit tamaynut \'%s\', i yessuturen tisura n uwgelhen. " - "Tiɣimit tamaynut tessutur tisura n uwgelhen. +\nMa yella ur tekcimeḍ ara ɣer tɣimit-nniḍen, ttu asuter-a. + Tiɣimit-inek·inem ur tettwasenqed ara \'%s\', tessutur tisura n uwgelhen. + Tiɣimit ur nettwasenqed ara tessutur tisura n uwgelhen. \nIsem n tɣimit: %1$s \nTimeẓriwt taneggarut: %2$s -\nMa yella ur tekcimeḍ ara ɣer tqimit-nniḍen, ttu asuter-a. " +\nMa yella ur tekcimeḍ ara ɣer tɣimit-nniḍen, ttu asuter-a. - "I uṣeggem n usefrek n yisnasen n Matrix " + I uṣeggem n usefrek n yisnasen n Matrix Akka d-yettban tetthuzzuḍ tiliɣri s lxiq. Tebɣiḍ ad teldiḍ agdil i tuzna n wabug\? Sbadu imayl i tririt n umiḍan, syen ɣer sdat ad yishil ad tt-afen yimdanen i ak·akem-yessnen. @@ -1655,10 +1655,10 @@ Ma ulac aɣilif err Element deg yibenk-nniḍen i izemren ad yekkes awgelhen i yiznan, akken ad yizmir ad yazen tisura ɣer tɣimit-a. - "Seqdec taṣunit n Element tamezwert i yisawalin ara d-ikecmen " + Seqdec taṭenṭunt n Element tamezwert i yisawalin ara d-ikecmen Ad isseqdec %s d tallalt mi ara yili uqeddac-ik·im agejdan ur d-imudd ara yiwen (tansa-inek·inem IP ad tettwabḍu ayen akk ara yeqqim usiwel) - "Taṣunit n usiwel i d-ikecmen " - "Fren taṣunit i yisawalen " + Taṭenṭunt n usiwel i d-ikecmen + Fren taṭenṭunt i yisawalen Agalis anmeggag ur yessaweḍ ara ad yerfed. Matrix yezmer ad isenqed adlis-ik·im n tansiwin i wakken ad yaf iseqdacen-nniḍen n Matrix s ttawil n yimaylen d wuṭṭunen n tiliɣri nsen. Ma yella tqebleḍ ad tebduḍ adlis-ik·im n tansiwin i waya, ma ulac aɣilif sireg anekcum deg yisfuyla udhimen i d-iteddun. @@ -1853,7 +1853,7 @@ Aseɣwen ɣer texxamt ilaq ad yesɛu tansa. Amasal n yismawen yettwamudden d arameɣtu \'%s\' mačči d amasal ameɣtu i yisem yettwamudden - Tasarut n udsil umḍin Ed25519 + Tasarut n udsil umḍin Ed25519 tettusra La ssenqadeɣ tisura-a ma mṣadant Tixxamin meṛṛa tidiganin %s @@ -1866,52 +1866,52 @@ 1 yizen i d-yettwalɣu ur yettwaɣra ara %d yiznan i d-yettwalɣun ur ttwaɣran ara - "Rnu isaragen n usiwel s jitsi " - "Ɣer DRM yemmestnen amidyat " + Rnu isaragen s usiwel s jitsi + Ɣer amidyat yemmestnen s DRM - "Bdu s tkamiṛat n unagraw deg ubdil n ugdil n tkamiṛat tudmawant " - "Asarag s usiwel ha-t-an yettusnernay, ur yettizmir ara ad " + Bdu s tkamiṛat n unagraw deg ubdil n ugdil n tkamiṛat tudmawant. + Asarag s usiwel ha-t-an iteddu, ur yezmir ad yettwattkal fell-as. - "Taladna ur nettwaṣeggem ara: %s " - "Taladna \"%s\" tesra ugar n yiɣewwaren, neɣ kra n yiɣewwaren d arimeɣta. " + Taladna tarussint: %s + Taladna \"%s\" tesra ugar n yiɣewwaren, neɣ kra n yiɣewwaren d arimeɣta. Kkes azgal i useqdac s usulay i d-yettunefkan - "Rmed/Sens tacreḍt yeɣlin " + Rmed/Sens Markdown Tacreḍt yeɣlin tettwarmed. Tacreḍt yeɣlin tettusens. - "Anedbal n temɣiwent ur igi ara aglam ɣezzifen i temɣiwent-a " + Anedbal n temɣiwent ur d-imudd ara aglam ɣezzifen i temɣiwent-a. Tettusuffɣeḍ-d seg %1$s sɣur %2$s Tettusuffɣeḍ-d seg %1$s sɣur %2$s - "I wakken ad tkemmleḍ aseqdec n uqeddac agejdan %1$s ilaq ad talseḍ asenqed syen ad tqebleḍ tiwtilin-nneɣ s umata. " + I wakken ad tkemmleḍ aseqdec n uqeddac agejdan %1$s, ilaq ad talseḍ asenqed syen ad tqebleḍ tiwtilin-nneɣ s umata. Ttxil-k·m ttu akk iznan i yuzneɣ mi ara senseɣ amiḍan-iw (Ɣur-k·m: aya ad yerr iseqdacen ara d-yernun ad walin idiwenniyen ur nemmid ara) - "Taxxamt-a ad tettusmelsi, dayen d tarurmidt " + Taxxamt-a tettusmelsi, dayen d tarurmidt Taxxamt-a d akemmel n udiwenni-nniḍen - "nermes anedbal-inek·inem n umeẓlu " + nermes anedbal n umeẓlu-inek·inem - Aqeddac-a agejdan yessaweḍ yiwet seg tlisa-ines n teɣbalut ɣef waya kra n yiseqdacen ur ttizmiren ara ad kecmen". " + Aqeddac-a agejdan iɛedda yiwet seg tlisa-ines n teɣbalut ɣef waya kra n yiseqdacen ur ttizmiren ara ad kecmen. Aqeddac-a agejdan yessaweḍ talast-is n useqdac n wayyur urmid ɣef waya kra n yiseqdacen ur ttizmiren ara ad kecmen. - "Ma ulac aɣilif %s ad yaweḍ ɣer talast-a " - "Ur yeddi ara usali n yiɛeggalen n ugraw " + Ma ulac aɣilif %s i usnerni n talast-a. + Asali n yiɛeggalen n texxamin ẓẓayen I yiznan d tuccḍiwin - "Ulac imeẓla APK imeɣta n Google Play i yettwafen. Ilɣa ur zmiren ara ad ddun akken iwata. " + Ulac APK imeɣta n yimeẓla n Google Play i yettwafen. Ilɣa ur zmiren ara ad ddun akken iwata. - "Iznan deg texxamt yettwawgelhen, ttusɣelsen s uwgelhen n yixef ɣer yixef. Ala kečč·kemm d useɣyad (yiseɣyaden) i yesɛan tisura i tɣuri n yiznan-a. + Iznan deg texxamt yettwawgelhen, ttusɣelsen s uwgelhen n yixef ɣer yixef. Ala kečč·kemm d uɣerwaḍ (yiɣeryaḍen) i yesɛan tisura i tɣuri n yiznan-a. \n -\nAḥraz aɣelsan n tsura-inek·inem i akken tḍemneḍ ur ak·am-ttruḥun ara " +\nAḥraz aɣelsan n tsura-inek·inem i akken tḍemneḍ ur ak·am-ttruḥun ara Ḍmen aḥrazen-inek·inem s tefyirt tuffirt. Yedda! - "Tisura-inek·inem la ttwaḥrazent. " - "Tasarut-ik·im n tririt d azeṭṭa yettwaḍmanen - tzemreḍ ad tt-tesqedceḍ i wakken ad d-terreḍ anekcum ɣer yiznan-inek·inem yettwawgelhen ma yella tettuḍ tafyirt-ik·im tuffirt. -\nErr tasarut-ik·im n tririt deg wadeg aɣelsan aṭas, am umsefrak n wawalen uffire (neɣ deg usenduq) " - "Err tasarut-ik·im n tririt deg wadeg aɣelsan s waṭas, am umsefrak n wawalen uffiren (neɣ deg usenduq) " - "Tasarut n tririt tettwasekles deg \'%s\'. + Tisura-inek·inem ha-tent-an la ttwaḥrazent. + Tasarut-ik·im n tririt d azeṭṭa n tɣellist - tzemreḍ ad tt-tesqedceḍ i wakken ad d-terreḍ anekcum ɣer yiznan-inek·inem yettwawgelhen ma yella tettuḍ tafyirt-ik·im tuffirt. +\nErr tasarut-ik·im n tririt deg wadeg aɣelsan s waṭas, am umsefrak n wawalen uffire (neɣ deg usenduq). + Err tasarut-ik·im n tririt deg wadeg aɣelsan s waṭas, am umsefrak n wawalen uffiren (neɣ deg usenduq). + Tasarut n tririt tettwasekles deg \'%s\'. \n -\nƔur-k·m: afaylu-a yezmer ad yettwakkes ma yella ur yettusebded ara usnas. " +\nƔur-k·m: afaylu-a yezmer ad yettwakkes ma yella yettusefsax usebded n usnas. Yettban am wakken tesbaduḍ yakan aḥraz n tsarut seg tɣimit-nniḍen. Tebɣiḍ ad tt-tesmesliḍ s yiwet ara d-ternuḍ\? - "Asirew n tsarut n tririt s useqdec n tefyirt tuffirt, aya yezmer ad yeṭṭef ddeqs n tesdidin. " - "Tuccḍa u nettwarǧa ara " - "Tisura-inek·inem n uwgelhen ha-tent-an tura ttwaḥrazent ɣef ugilal ɣef uqeddac-ik·im agejdan. Aḥraz agejdan yezmer ad yeṭṭaf ddeqs n tsinin " + Asirew n tsarut n tririt s useqdec n tefyirt tuffirt, akal-a yezmer ad yeṭṭef ddeqs n tsinin. + Tuccḍa u nettwarǧa ara + Tisura-inek·inem n uwgelhen ha-tent-an tura ttwaḥrazent deg ugilal ɣef uqeddac-ik·im agejdan. Aḥraz agejdan yezmer ad yeṭṭaf ddeqs n tesdidin. Yezmer tesruḥeḍ anekcum ɣer yiznan-ik·im ma yella teffɣeḍ neɣ tesruḥeḍ ibenk-a. @@ -1930,7 +1930,7 @@ Askazal n tsarut n tririt... Asali n tsura... Aktar n tsura... - "Aḥraz yettwarr-d %s! " + Aḥraz yettwarr-d %s! Yerra-d aḥraz s tsarut %d. Yerra-d aḥraz s tsura %d. @@ -1941,7 +1941,7 @@ Tiririt n lqem akk aneggaru n tsura (%s) ur teddi ara. - "Awgelhen n tɣimit ur yettwarmed ara " + Awgelhan n tɣimit ur yettwarmed ara Aḥraz n tsarut yettusbadu akken iwata i tɣimit-a. @@ -1956,19 +1956,19 @@ Aḥraz ɣer-s azmul arameɣtu seg tɣimit ur yettusneqden ara %s Awway n telɣut yettwattkalen i uḥraz (%s) ur yeddi ara. - "I useqdec n uḥraz n tsarut deg tɣimit-a, err-d s tefyir-ik·im tuffirt neɣ s tsarut n tririt tura " + I useqdec n uḥraz n tsura deg tɣimit-a, err-d s tefyir-ik·im tuffirt neɣ s tsarut n tririt tura. Tukksa n uḥraz (%s) ur teddi ara Asenqed n waddad n uḥraz - "Kkes tisura-inek·inem n uwgelhen yettwaḥerzen seg uqeddac\? Ur tettuɣaleḍ ara ad tizmireḍ ad tesqedceḍ tasarut-ik·im n tririt i tɣuri n umazray n yiznan yettwawgelhen. " + Kkes tisura-inek·inem n uwgelhen yettwaḥerzen ɣef uqeddac\? Ur tettuɣaleḍ ara ad tizmireḍ ad tesqedceḍ tasarut-ik·im n tririt i tɣuri n umazray n yiznan yettwawgelhen. Aḥraz n tsarut amaynut n yizen aɣelsan tettwaf-d. \n \nMa yella ur tesbaduḍ ara tarrayt n tririt tamaynut, amker yezmer ad yeɛreḍ ad yekcem ɣer umiḍan-ik·im. Snifel awal uffir n umiḍan-ik·im syen sbadu tarrayt n tririt tamaynut din din deg yiɣewwaren. Aḥraz aɣelsan - "Seḥbiber iman-ik·im ɣef usruḥ n unekcum ɣer yiznann & yisefka yettwawgelhe " + Seḥbiber iman-ik·im mgal asruḥu n unekcum ɣer yiznann & yisefka yettwawgelhen - "Tisura n yizenaɣelsan timaynutin " + Tisura timaynutin n yizen aɣelsan Sefrek deg uḥraz n tsarut Aḥraz n tsura-inek·inem. Aya yezmer ad yeṭṭef aṭas n tesdidin... @@ -1981,9 +1981,9 @@ Aḥraz n tsura %d - "Iɣewwaren n uqeddac uwurman ummid " - "Element yufa-d tawila n uqeddac udmawan i taɣult-inek·inem usulay n uqeddac \"%1$s\": -\n%2$s " + Iɣewwaren n uqeddac ummid awurman + Element yufa-d tawila n uqeddac udmawan i taɣult usulay--inek·inem n uqeddac \"%1$s\": +\n%2$s Seqdec tawila "Tettuseffɣeḍ ssebba n credentials arimeɣta neɣ yekfan " From fc993cb7248d01c289dae7c6a5e21268cd2dc160 Mon Sep 17 00:00:00 2001 From: Slimane Selyan AMIRI Date: Sat, 12 Sep 2020 13:49:56 +0000 Subject: [PATCH 57/89] Translated using Weblate (Kabyle) Currently translated at 97.0% (1811 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/kab/ --- vector/src/main/res/values-kab/strings.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index f70a2818bb..55da4a8672 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -1986,26 +1986,26 @@ \n%2$s Seqdec tawila - "Tettuseffɣeḍ ssebba n credentials arimeɣta neɣ yekfan " + Tettuseffɣeḍ ssebba n credentials arimeɣta neɣ yekfan. - "Senqed s userwes n yiḍrisen imeẓẓyanen " - "Bdu asenqed " - "Aselken n tɣimit-a ad yettucreḍ fell-as tettwattkal, yerna ad tettucreḍ ula d tiɣimit-ik·im tettwattkal i bab-is. " + Senqed s userwes n yiḍrisen imeẓẓyanen. + Bdu asenqed + Aselken n tɣimit-a ad yettucreḍ fell-as tettwattkal, yerna ad tettucreḍ ula d tiɣimit-ik·im tettwattkal i bab-is. - "Selkem tiɣimit-a s usentem n yimujiten-a i d-yettbanen ɣef ugdil n baba-is " - "Selkem tiɣimit-a s usentem n wuṭṭunen-a i d-yettbanen ɣef ugdil n baba-is " + Selkem tiɣimit-a s usentem n yimujiten-a i d-yettbanen ɣef ugdil n baba-is + Selkem tiɣimit-a s usentem n wuṭṭunen-a i d-yettbanen ɣef ugdil n baba-is Tremseḍ-d asuter n uselken i d-iteddun... "Aṛaǧu n bab-is i usentem ..." Teslekneḍ taxxamt-a akken iwata. - "Ulac acu i d-yettwabnen\? Mačči akkimsaɣen ssefraken aselken amyigew ar tura. Seqdec aselken " - "Seqdec aselken " + Ulac acu i d-yettwabnen\? Mačči akkimsaɣen ssefraken aselken amyigew ar tura. Seqdec aselken. + Seqdec aselken. Tama-nniḍen tessefsax aselken. \n%s - "Aselken yettusefsax. -\nTaɣzint: %s " + Aselken yettusefsax. +\nTaɣzint: %s "Aselken amyigaw n tɣimit " %s yebɣa ad issenqed tiɣimit-inek·inem From a265ff3fbe810877e82b0e124353f2335b4df75d Mon Sep 17 00:00:00 2001 From: Slimane Selyan AMIRI Date: Sat, 12 Sep 2020 13:56:20 +0000 Subject: [PATCH 58/89] Translated using Weblate (Kabyle) Currently translated at 97.8% (1826 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/kab/ --- vector/src/main/res/values-kab/strings.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index 55da4a8672..411521f4fa 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -2007,16 +2007,16 @@ Aselken yettusefsax. \nTaɣzint: %s - "Aselken amyigaw n tɣimit " + Aselken amyigaw n tɣimit %s yebɣa ad issenqed tiɣimit-inek·inem Aseqdac issefsax asenqed - "Akud n usenqed yemmed " - "Tiɣimit ur teẓri ara ɣef tnigawt-a " - "SAS ur imsaḍa ara " + Akud n usenqed yemmed + Tiɣimit ur teẓri ara ɣef tnigawt-a + SAS ur imsaḍa ara SAS ur imsaḍa ara - "Tiɣimit termes-d izen ideg yella ccekk " - "Yettwarmes-d yizen arameɣtu " + Tiɣimit termes-d izen ideg yella ccekk + Yettwarmes-d yizen arameɣtu "Tasarut temṣada swaswa " "Aseqdac yemṣada swaswa " Ur tesseqdaceḍ ara ula d yiwen n uqeddac n timagit From a61b9ce1e1798d6ceb2ff04292e73502229e982e Mon Sep 17 00:00:00 2001 From: ziriSut Date: Sat, 12 Sep 2020 14:03:15 +0000 Subject: [PATCH 59/89] Translated using Weblate (Kabyle) Currently translated at 97.8% (1826 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/kab/ --- vector/src/main/res/values-kab/strings.xml | 372 +++++++++++---------- 1 file changed, 199 insertions(+), 173 deletions(-) diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index 411521f4fa..e2ef8c4254 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -924,7 +924,7 @@ Asentem n tebzimt ur yeddi ara, ttxil-k·m aru yiwet. Sekcem PIN inek·inem Ttu PIN\? - "Wennez tabzimt " + Wennez tabzimt Tabzimt tamaynut n I uwennez n PIN-inek·inem, tesriḍ ad talseḍ anekcum syen rnu yiwen. Rmed PIN @@ -1450,7 +1450,7 @@ Sewḥel kullec Ixuṣṣ usulay_taxxamt deg usuter. Ixuṣṣ usulay_aseqdac deg usuter. - Taxxamt %s ur d-tban ara + Taxxamt %s ur d-tettban ara. Aɣewwar yettusran ulac-it. Aɣewwar mačči d ameɣtu. Ulac amsefrak n umsidef yettusewlen. @@ -1458,7 +1458,7 @@ Ulac iwiǧiten i yettwaremden Kcem ɣer texxamt s yisem i d-yettunefken Ttxil-ik·im sekcem isem n useqdac. - Ttxil-k·m sekcem awal-ik·im uffir: + Ttxil-k·m sekcem awal-ik·im uffir. Adiwenni yettkemmil da Sit da i wakken ad twaliḍ iznan iqburen @@ -1467,7 +1467,7 @@ Ma ulac aɣilif %s kemmel aseqdec n umeẓlu-a. - Nesḥassef, tella-d tuccḍa. + Nesḥassef, tella-d tuccḍa Sken tamnaḍt n telɣut I tuccḍiwin kan @@ -1491,13 +1491,13 @@ Yella yakan uḥraz deg uqeddac-ik·im agejdan Ma ulac aɣilif, eg anɣal - Bḍu tasarut n tririt d... + Bḍu tasarut n tririt d… Aḥraz yebda seqdec tasarut-ik·im n tririt Tiririt n yizen Serreḥ i umazray - Kkes aḥraz... + Kkes aḥraz… Aḥraz n tsarut amaynut Aseɣwen yettwanɣel \'ɣef wafus\' @@ -1508,8 +1508,8 @@ Taxtirit yettefernen Anekcum amaynut - Sekcem tasarut tuffirt n uḥraz uffir: - Ɣur-k·m! + Sekcem tasarut tuffirt n uḥraz uffir + Ɣur-k·m: Tisur ttwaleqqment yakan! Element Android @@ -1518,7 +1518,7 @@ Ittraju %s… - "Ilɣa n urway " + Tifrat n wugur Afaylu n useqdac Kcem %s @@ -1537,7 +1537,7 @@ Awgelhen seg yixef ɣer yixef yettwarmed Tesriḍ ad teffɣeḍ i wakken ad tizmireḍ awgelhen. Wgelhen i usenqed n tɣimiyinkan - Ur ttazen ara akk iznan yettwawgelhen ɣer tɣimiyin ur nettusenqad ara deg texxamt-a seg tɣimit-a + Ur ttazen ara akk iznan yettwawgelhen ɣer tɣimiyin ur nettusenqad ara deg texxamt-a, seg tɣimit-a. Tansa tamaynut (am. #foo:matrix.org) @@ -1605,7 +1605,7 @@ Fren akaram n texxamt Aru aqeddac agejdan i wakken ad d-tbedreḍ tixxamin tizuyaz seg-s Tixxamin meṛṛa ɣef uqeddac %s - Aru da... + Aru da… %1$s: 1 yizen @@ -1658,7 +1658,7 @@ Seqdec taṭenṭunt n Element tamezwert i yisawalin ara d-ikecmen Ad isseqdec %s d tallalt mi ara yili uqeddac-ik·im agejdan ur d-imudd ara yiwen (tansa-inek·inem IP ad tettwabḍu ayen akk ara yeqqim usiwel) Taṭenṭunt n usiwel i d-ikecmen - Fren taṭenṭunt i yisawalen + Fren asṭeṭen i yisawalen: Agalis anmeggag ur yessaweḍ ara ad yerfed. Matrix yezmer ad isenqed adlis-ik·im n tansiwin i wakken ad yaf iseqdacen-nniḍen n Matrix s ttawil n yimaylen d wuṭṭunen n tiliɣri nsen. Ma yella tqebleḍ ad tebduḍ adlis-ik·im n tansiwin i waya, ma ulac aɣilif sireg anekcum deg yisfuyla udhimen i d-iteddun. @@ -1787,7 +1787,7 @@ Sken awwaḍen n tɣuri Sit ɣef wawwaḍen n tɣuri i tebdart leqqayen. Sken ineḍruyen n uttekki d wid i yeffɣen - Asnubget, asuffeɣ d ugdal ur teddun ara + Asnubget, asuffeɣ d ugdal ur teddun ara. Sken ineḍruyen n umiḍan Rnu ɣer-s isnifal n avaṭar d yisem n uskan. Smami mi ara d-yettwabder useqdac @@ -1898,13 +1898,13 @@ Iznan deg texxamt yettwawgelhen, ttusɣelsen s uwgelhen n yixef ɣer yixef. Ala kečč·kemm d uɣerwaḍ (yiɣeryaḍen) i yesɛan tisura i tɣuri n yiznan-a. \n -\nAḥraz aɣelsan n tsura-inek·inem i akken tḍemneḍ ur ak·am-ttruḥun ara +\nAḥraz aɣelsan n tsura-inek·inem i akken tḍemneḍ ur ak·am-ttruḥun ara. Ḍmen aḥrazen-inek·inem s tefyirt tuffirt. Yedda! Tisura-inek·inem ha-tent-an la ttwaḥrazent. Tasarut-ik·im n tririt d azeṭṭa n tɣellist - tzemreḍ ad tt-tesqedceḍ i wakken ad d-terreḍ anekcum ɣer yiznan-inek·inem yettwawgelhen ma yella tettuḍ tafyirt-ik·im tuffirt. -\nErr tasarut-ik·im n tririt deg wadeg aɣelsan s waṭas, am umsefrak n wawalen uffire (neɣ deg usenduq). - Err tasarut-ik·im n tririt deg wadeg aɣelsan s waṭas, am umsefrak n wawalen uffiren (neɣ deg usenduq). +\nErr tasarut-ik·im n tririt deg wadeg aɣelsan s waṭas, am umsefrak n wawalen uffire (neɣ deg usenduq) + Err tasarut-ik·im n tririt deg wadeg aɣelsan s waṭas, am umsefrak n wawalen uffiren (neɣ deg usenduq) Tasarut n tririt tettwasekles deg \'%s\'. \n \nƔur-k·m: afaylu-a yezmer ad yettwakkes ma yella yettusefsax usebded n usnas. @@ -1927,17 +1927,17 @@ Tuccḍa deg uzeṭṭa: ma ulac aɣilif senqed tuqqna-inek·inem syen ɛreḍ tikkelt-nniḍen. Tiririt n uḥraz: - Askazal n tsarut n tririt... - Asali n tsura... - Aktar n tsura... + Askazal n tsarut n tririt… + Asali n tsura… + Aktar n tsura… Aḥraz yettwarr-d %s! Yerra-d aḥraz s tsarut %d. Yerra-d aḥraz s tsura %d. - Tisura timaynutin %d ttwarnant ɣer tɣimit. - + %d tasarut tamaynut tettwarn ɣer tɣimit. + %d tisura timaynutin ttwarnant ɣer tɣimit. Tiririt n lqem akk aneggaru n tsura (%s) ur teddi ara. @@ -1971,14 +1971,14 @@ Tisura timaynutin n yizen aɣelsan Sefrek deg uḥraz n tsarut - Aḥraz n tsura-inek·inem. Aya yezmer ad yeṭṭef aṭas n tesdidin... + Aḥraz n tsura-inek·inem. Aya yezmer ad yeṭṭef aṭas n tesdidin… Sbadu aḥraz aɣelsan - Aḥraz n tsarut %d - Aḥraz n tsura %d + Aḥraz n tsarut %d… + Aḥraz n tsura %d… Iɣewwaren n uqeddac ummid awurman @@ -1986,9 +1986,9 @@ \n%2$s Seqdec tawila - Tettuseffɣeḍ ssebba n credentials arimeɣta neɣ yekfan. + Tettusuffɣeḍ ssebba n yinekcam arimeɣta neɣ yemmuten. - Senqed s userwes n yiḍrisen imeẓẓyanen. + Senqed s userwes n uzrir ameẓẓyan n uḍris. Bdu asenqed Aselken n tɣimit-a ad yettucreḍ fell-as tettwattkal, yerna ad tettucreḍ ula d tiɣimit-ik·im tettwattkal i bab-is. @@ -1996,7 +1996,7 @@ Selkem tiɣimit-a s usentem n wuṭṭunen-a i d-yettbanen ɣef ugdil n baba-is Tremseḍ-d asuter n uselken i d-iteddun... - "Aṛaǧu n bab-is i usentem ..." + Aṛaǧu n usentem sɣur bab-is… Teslekneḍ taxxamt-a akken iwata. Ulac acu i d-yettwabnen\? Mačči akkimsaɣen ssefraken aselken amyigew ar tura. Seqdec aselken. @@ -2017,53 +2017,53 @@ SAS ur imsaḍa ara Tiɣimit termes-d izen ideg yella ccekk Yettwarmes-d yizen arameɣtu - "Tasarut temṣada swaswa " - "Aseqdac yemṣada swaswa " + Ulac amṣada n tsarut + Ulac amṣada n useqdac Ur tesseqdaceḍ ara ula d yiwen n uqeddac n timagit - "Ulac aqeddac n timagit yettusiwlen, yettusra ad twennzeḍ awal-inek·inem uffir " + Ulac aqeddac n timagit yettusiwlen, yettusra ad twennzeḍ awal-inek·inem uffir. Yettban-d am wakken tettaɛraḍeḍ ad teqqneḍ ɣer uqeddac agejdan-nniḍen. Tebɣiḍ ad teffɣeḍ\? Ttekki deg usarag s useqdec n usnas. - "Yuzen-ak·am-d tinubga " - "Tettwafem akken ma tellam! " - "Ur tesɛiḍ ara iznan-nniḍen ur nettwaɣra ara " + Yuzen-ak·am-d tinubga + Tettwafem akken ma tellam! + Ur tesɛiḍ ara iznan-nniḍen ur nettwaɣra ara Ansuf ɣer uxxam! - "Idiwenniyen n yizen usrid ad d-ttwaskanen da " + Idiwenniyen-inek·inem n yizen usrid ad d-ttwaskanen da Tixxamin-inek·inem ad d-ttwaskanent da - "Rnu " - "Wali " + Rnu asedmar + Wali isedmaren Sken-d iznan yettwakksen Yettewekkes uneḍru sɣur aseqdac - "Aneḍru yellan s lmendad n unedbal n texxamt " + Aneḍru yellan s lmendad n unedbal n texxamt Aneggaru yettwaẓreg sɣer %1$s ɣef %2$s Aneḍru ur nemsil ara, ulamek ara d-yettwaskan Ulac azeṭṭa. Ma ulac aɣilif senqed tuqqna-inek·inem ɣer Internet. - Ma ulac aɣilif ṛǧu... - "Taxxamt-a ulamek ad tettwasenqad " - "Suffeɣ-d taxamt-a deg ukaram n texxamin " - "Taxxamt tettwarna, maca kra n tinubgiwin ur ttwaznent ara i taɣznt-a: + Ma ulac aɣilif ṛǧu… + Taxxamt-a ulamek tettwaskan + Suffeɣ-d taxxamt-a deg ukaram n texxamin + Taxxamt tettwarna, maca kra n tinubgiwin ur ttwaznent ara i teɣzint-a: \n -\n%s " +\n%s - "Tella-d tuccḍa deg wawway n telɣut yettwattkalen " - "Tella-d tuccḍa deg wawway n yisefka n uḥraz n tsura " + Tella-d tuccḍa deg wawway n telɣut yettwattkalen + Tella-d tuccḍa deg wawway n yisefka n uḥraz n tsura Kter tisura e2e seg ufaylu \"%1$s\". - Turagin-nniḍen n wis tlata.. + Turagin n wis tlata Tesneqdeḍ yakan taxxamt-a! - "Ulac ilugan n push yettusbadun " - "Glem-d isniram-inek·inem da " + Ulac ilugan n yilɣa yettusbadun + Glem-d isniram-inek·inem da Tanemmirt, isumar ttwaznen akken iwata - "Tuzna n yisumar ur teddi ara (%) " + Tuzna n yisumar ur teddi ara (%s) - Awgelhen n utṛumbun... - Awgelhen n ufaylu... + Awgelhen n utṛumbun… + Awgelhen n ufaylu… Tuzna n ufaylu (%1$s / %2$s) Asali n ufaylu %1$s… @@ -2076,30 +2076,30 @@ Ulac igmaḍ i yettwafen, seqdec Rnu s usulan n Matrix i unadi ɣef uqeddac. Bdu aru i wakken ad tesɛuḍ igmaḍ - Sizdeg s yisem n useqdac neq s usulay... + Sizdeg s yisem n useqdac neɣ s usulay… - Attekki deg texxamt... + Attekki deg texxamt… Ẓer amazray i yettuẓergen - "Senqed tiwtilin " - "Ili-k tettwafeḍ sɣur wiyaḍ " - "Seqdec abuten, tileggiyin, iwiǧiten d yikemmusen n yistikar " + Senqed tiwtilin + Ili-k tettwafeḍ sɣur wiyaḍ + Seqdec abuḍen, tileggiyin, iwiǧiten d yikemmusen n yistikar Swel aqeddac n timagit - "Aql-ak·akem akka tura tesseqdaceḍ %1$s i wakken ad d-tefeḍ, dɣen ad tettwafeḍ sɣur inermisen yellan i tessneḍ " + Aql-ak·akem akka tura tesseqdaceḍ %1$s i wakken ad d-tafeḍ, daɣen ad tettwafeḍ sɣur inermisen yellan i tessneḍ. Akka tura ur tesseqdaceḍ aqeddac n timagit. I wakken ad d-tafeḍ daɣen ad d-tettwafeḍ sɣur yinermisen yellan i tessneḍ, rnu yiwen ddaw. - "Tansiwin n yimayl yettwafen " - Tixtiṛiyin n usnirem ad d-banent akken ara ternuḍ imayl - Tixtiṛiyin n usnirem ad d-banent akken ara ternuḍ uṭṭun n tilifun - "Asefsex n tuqqna seg uqeddac-ik·im n timagit yebɣa ad d-yini ur tebɣiḍ ara ad ak·akem-id-afen wiyaḍ, ur tettizmireḍ ara daɣen ad d-tsnubegteḍ wiyaḍ s yimayl neɣ s wuṭṭun n tiliɣri. " - "Uṭṭunen n tiliɣri i d-yettbanen " + Tansiwin n yimayl i izemren ad ttwafent + Tixtiṛiyin n usnirem ad d-banent akken ara ternuḍ imayl. + Tixtiṛiyin n usnirem ad d-banent akken ara ternuḍ uṭṭun n tilifun. + Asefsex n tuqqna seg uqeddac-ik·im n timagit yebɣa ad d-yini ur tebɣiḍ ara ad ak·akem-id-afen wiyaḍ, ur tettizmireḍ ara daɣen ad d-tsnubegteḍ wiyaḍ s yimayl neɣ s wuṭṭun n tiliɣri. + Uṭṭunen n tiliɣri i izemren ad ttwafen Nuzen-ak·am-n imayl n usentem ɣer %s, senqed imayl-inek·inem syen sit ɣef useɣwen n usentem Nuzen-ak·am-n imayl n usentem ɣer %s, ttxil-k·m deg tazwara senqed imayl-inek·inem syen sit ɣef useɣwen n usentem Sekcem URL n uqeddac n timagit Ur nezmir ara ad neqqen ɣer uqeddac n timagit Ma ulac aɣilif sekcem url n uqeddac n timagit - "Timagit n uqeddac ulac ɣer-s tiwtilin " + Timagit n uqeddac ulac ɣer-s tiwtilin n yimeẓla Izen n uḍris yettwazen ɣer %s. Ttxil-k·m sekcem tangalt n uselken yellan deg-s. Tangalt n uselken d tarameɣtut. @@ -2108,14 +2108,14 @@ Azen taceqquft yeddan - "Ldi tunigin " - "Ldi umuɣ n tmerna n texxamin " - "Mdel umuɣ n tmerna n texxamin... " + Ldi umuɣ n tunigin + Ldi umuɣ n tmerna n texxamin + Mdel umuɣ n tmerna n texxamin… Rnu adiwenni usrid amaynut Rnu taxxamt tamaynut - "Ɛeddi ɣer usawen " + Ɛeddi ɣer ukessar n usebter - "Azen aqbur-a " + Azen aqbur-a Agbur-a yettwakter-d. \n \nMa yella ur tebɣiḍ ara ad twaliḍ ugar n yigburen-nniḍen sɣur aseqdac-a, tzemreḍ ad t-tesweḥleḍ i wakken ad teffreḍ iznan-ines @@ -2130,130 +2130,130 @@ \n \nMa ulac aɣilif sireg anekcum ɣef yisfuyla udhimen i d-iteddun i wakken ad tizmireḍ ad tsifḍeḍ tisura-ik·im s ufus. - "Tella tuqqna n uzeṭṭa tgerrez tura " + Ulac akk tuqqna n uzeṭṭa i igerrzen akka tura - "Yuzen iznan i d-yettunefken yeɣma s yiniten d ucmit " - "Ucmit " - "Rnu ɣer yimelyan baṭel ɣef uqeddac azayez ameqqran akk " + Yuzen iznen i d-yettunefken d arewway + Arewway + Rnu ɣer yimelyan n yimdanen baṭel ɣef uqeddac azayez ameqqran akk Tanezduɣt n Premium i tkebbaniyin Iɣewwaren udmawanen & leqqayen Qqen ɣer yimeẓla n Element Matrix Qqen aqeddac udmawan Tanezduɣt n Premium i tkebbaniyin - "Sekcem tansa n Element Modular neɣ n uqeddac i tebɣiḍ ad t-tesqedceḍ " + Sekcem tansa n Element Modular neɣ n uqeddac i tebɣiḍ ad t-tesqedceḍ Sekcem tansa n uqeddac neɣ n Element i tebɣiḍ ad teqqneḍ ɣer-s Tella-d tuccḍa mi ara d-nessalay asebter: %1$s (%2$d) Asnas ur yezmir ara ad yekcem ɣer uqeddac-a agejdan. Aqeddac agejdan yessefrak anaw-a n unekcum: %1$s. \n \nTebɣiḍ ad tkecmeḍ s useqdec n umsaɣ web\? Suref-aɣ, aqeddac-a ur iqebbel ara imiḍanen imaynuten. - "Asnas ur yezmir ara ad yernu amiḍan ɣef uqeddac-a agejdan. + Asnas ur yezmir ara ad yernu amiḍan ɣef uqeddac-a agejdan. \n -\nTebɣiḍ ad tjerrdeḍ i useqdec n umsaɣ web\? " +\nTebɣiḍ ad tjerrdeḍ s useqdec n umsaɣ web\? - "Awal-ik·im uffir mazal ar tura ur yettusenfel ara. + Awal-ik·im uffir mazal ar tura ur yettusenfel ara. \n -\nSeḥbes aseddu " +\nSeḥbes aseddu n usnifel\? - "Sbadu imayl i wakken ad d-terreḍ amiḍan-ik·im. Ticki, tzemreḍ s wudem afrayan ad tsirgeḍ imdanen i tessneḍ ad ak·akem-afen s yimayl-inek·inem. " + Sbadu imayl i wakken ad d-terreḍ amiḍan-ik·im. Ticki, tzemreḍ s wudem afrayan ad tsirgeḍ imdanen i tessneḍ ad ak·akem-afen s yimayl-inek·inem. Sbadu uṭṭun n tiliɣri s wudem afrayan ad tsirgeḍ imdanen i tessneḍ ad ak·akem-afen. - "Ma ulac aɣilif amasal agreɣlan. " + Ma ulac aɣilif seqdec amasal agreɣlan. Aql-aɣ akken nuzen tangalt ɣer %1$s. Sekcem-it ddaw i uselken ma d kečč·kemm. - "Ma ulac aɣilif seqdec amasal agreɣlan (uṭṭun n tiliɣri ilaq ad yebdu s \'+\') " - "Uṭṭun n tiliɣri agreɣlan ilaq ad yebdu s \'+\' " + Ma ulac aɣilif seqdec amasal agreɣlan (uṭṭun n tiliɣri ilaq ad yebdu s \'+\') + Uṭṭun n tiliɣri agreɣlan ilaq ad yebdu s \'+\' Uṭṭun n tiliɣri yettban-d d arameɣtu. Ma ulac aɣilif senqed-it - "Amiḍan-ik·im mazal ur yettwarna ara ar tura. + Amiḍan-ik·im mazal ur yettwarna ara ar tura. \n -\nSeḥbes amulteɣ " +\nSeḥbes akala n usekles\? - "Aql-aɣ akken nuzen imayl ɣer %1$s. -\nMa ulac aɣilif sit ɣef useɣwen i yellan deg-s i wakken ad tkemmleḍ timerna. " + Aql-aɣ akken nuzen imayl ɣer %1$s. +\nMa ulac aɣilif sit ɣef useɣwen i yellan deg-s i wakken ad tkemmleḍ timerna. Tangalt yettwaskecmen d tarameɣtut. Ma ulac aɣilif senqed. - "Aqeddac agejdan yemmut " - "Aqeddac-a agejdan isselkam daɣen lqem aqbur i tuqqna ɣer-s. Suter anedbal n uqeddac-ik·im aqejden ad t-tleqqemḍ. " + Aqeddac agejdan d aqbur + Aqeddac-a agejdan isselkam lqem aqbur maḍi i tuqqna ɣer-s. Suter anedbal n uqeddac-ik·im aqejden ad t-tleqqemḍ. - "Aṭas n yisutar i yettwaznen. Tzemreḍ ad tɛerḍeḍ ticki deg %1$d tasint… " - "Aṭas n yisutar i yettwaznen. Tzemreḍ ad tɛerḍeḍ ticki deg %1$d tsinin… " + Aṭas n yisutar i yettwaznen. Tzemreḍ ad tɛerḍeḍ ticki deg %1$d tasint… + Aṭas n yisutar i yettwaznen. Tzemreḍ ad tɛerḍeḍ ticki deg %1$d tsinin… - "ma yella tesɛiḍ yakan amiḍan yerna tessneḍ identifier-inek·inem n Matrix d wawal-inek·inem uffir, tzemreḍ ad tesqedceḍ tarrayt-a " + Neɣ ma ulac, ma yella tesɛiḍ yakan amiḍan yerna tessneḍ inekcam-inek·inem n Matrix d wawal-inek·inem uffir, tzemreḍ ad tesqedceḍ tarrayt-a: Ma yella tesbaduḍ amiḍan ɣef uqeddac agejdan, seqdec asulay-inek·inem n Matrix (am. @user:domain.com) d wawal uffir ddaw. Ma yella ur tecfiḍ ara ɣef wawal-ik·im uffir, uɣal ɣer deffir ad t-twennzeḍ. Wagi mačči d identifier n useqdac ameɣtu. Amasal deg-s ccekk: \'@user:homeserver.org\' - "D awezɣi ad d-naf aqeddac agejdan ameɣtu. Ma ulac aɣilif senqed identifier-inek·inem " + D awezɣi ad d-naf aqeddac agejdan ameɣtu. Ma ulac aɣilif senqed inekcam-inek·inem - "Yezmer ad yili seg waṭas n ssebbat: + Yezmer ad yili seg waṭas n ssebbat: \n \n• Tbeddleḍ awal-ik·im uffir deg tɣimit-nniḍen. \n \n• Tekkseḍ tiɣimit-a seg tɣimit-nniḍen. \n -\n• Anedbal n uqeddac-ik·im ur isɛedda ara anekcum-inek·inem i ssebba n tɣellist. " - "Anedbal n uqeddac-ik·im agejdan (%1$s) admin isuffeɣ-ik·ikem seg umiḍan-inek·inem %2$s (%3$s). " - "Kcem i wakken ad d-terreḍ tisura n uwgelhen i d-yettwarranɣef yibenk-a s timmad-is. Tesriḍ-tent i tɣuri n meṛṛa iznan-inek·inem iɣelsanen ɣef yal ibenk " - "Ɣur-k·m: Isefka-inek·inem udmawanen (rnu ɣer-sen tisur n uwgelhen) mazal ttukelsent ɣef yibenk-a. +\n• Anedbal n uqeddac-ik·im ur isɛedda ara anekcum-inek·inem i ssebba n tɣellist. + Anedbal n uqeddac-ik·im agejdan (%1$s) isuffeɣ-ik·ikem seg umiḍan-inek·inem %2$s (%3$s). + Kcem i wakken ad d-terreḍ tisura n uwgelhen i d-yettwakelsen ɣef yibenk-a kan. Tesriḍ-tent i tɣuri n meṛṛa iznan-inek·inem iɣelsanen ɣef yal ibenk. + Ɣur-k·m: Isefka-inek·inem udmawanen (rnu ɣer-sen tisura n uwgelhen) mazal ttukelsent ɣef yibenk-a. \n -\nSfeḍ-iten ma yella tekfiḍ aseqdec n yibenk-a, neɣ tebɣiḍ ad tkecmeḍ ɣer umiḍan-nniḍen " - "Sfeḍ meṛṛa isefka yettukelsen melmi kan ɣef yibenk-a\? -\nKcem tikkelt-nniḍen i wakken ad tkecmeḍ ɣer yisefka d yiznan n umiḍan-inek·inem " +\nSfeḍ-iten ma yella tekfiḍ aseqdec n yibenk-a, neɣ ma tebɣiḍ ad tkecmeḍ ɣer umiḍan-nniḍen. + Sfeḍ meṛṛa isefka yettukelsen melmi kan ɣef yibenk-a\? +\nKcem tikkelt-nniḍen i wakken ad tkecmeḍ ɣer yisefka d yiznan n umiḍan-inek·inem. Aseɣwen-inek·inem n Matrix.to ur yemsil ara akken iwata Ala igmaḍ imezwura i d-yettwaseknen, aru ugar n yisekkilen… - "Element yezmer ad iḍeyyer ugar mi ara " + Element yezmer ad yewḥel ugar n tikkal mi ara d-tili tuccḍa ur nettwaṛǧa ara - "Taɣult-ik·im n yimayl ur tesɛi ara azref i wakken ad tettwasekles ɣef uqeddac-a " + Taɣult n yimayl--ik·im ur tesɛi ara azref i wakken ad tettwasekles ɣef uqeddac-a - "Anekcum ur nettwattkal ara " - "Selken aseqdac-a s usentem n yimujit asuf i d-iteddun i d-yettbanen ɣef ugdil-ines, deg yiwem umsizwer " - "I tɣellist i ilaqen, seqdec iberdan-nniḍen yettwatteklen n teywalt neɣ eg aya s timmad-ik·im " - "Muqel shield azegzaw i wakken ad tḍemneḍ aseqdac yettuttkal. Ttkel ɣef meṛṛa iseqdacen yellan deg texamt i wakken ad tḍemneḍ taxxamt d taɣelsant " + Tuqqna ur nettwattkal ara + Senqed aseqdac-a s usentem n yimujit-a asuf i d-yettbanen ɣef ugdil-ines, deg yiwem umsizwer. + I tɣellist meqqren, seqdec ttawilat-nniḍen yettwattkalen n teywalt neɣ eg aya s timmad-ik·im. + Muqel aɣar azegzaw i wakken ad tḍemneḍ aseqdac yettwattkalen. Ttkel ɣef meṛṛa iseqdacen yellan deg texxamt i wakken ad tḍemneḍ taxxamt d taɣelsant. - "Yiwen seg wayen i d-iteddun yezmer ad yettwaker: + Yiwen seg wayen i d-iteddun yezmer ad yettwaker: \n \n- Aqeddac-ik·im agejdan -\n- Aqeddac agejdan wuɣur yeqqen useqdac tesselkaneḍ -\n- Tuqqna-inek·inem n internet neɣ tin n yiseqdac-nniḍen -\n- Ibenk-inek·inem neɣ win n yiseqdac-nniḍen " +\n- Aqeddac agejdan wuɣur yeqqen useqdac tessenqadeḍ +\n- Tuqqna-inek·inem n internet neɣ tin n useqdac-nniḍen +\n- Ibenk-inek·inem neɣ win n useqdac-nniḍen - "Freḍ tangalt d yibenk-nniḍen n useqdac i wakken ad teslekneḍ yal yiwen s wudem aɣelsan " - "Ulamek yettwafreḍ " - "Ma yella mačči d kečč·kemm s timmad-ik·im, serwes imujit deg ubdil " + Freḍ tangalt d yibenk n useqdac-nniḍen i wakken ad tesneqdeḍ yal yiwen s wudem aɣelsan + Ulamek yettwafreḍ + Ma yella mačči d kečč·kemm s timmad-ik·im, serwes imujit deg ubdil Selken s userwes n yimujiten Senqed s yimujit - "Ma yella ur tezmireḍ ara ad tferḍeḍ tangalt nnig, selken s uselken n yimujit amecṭuḥ d tefrayt-is tasuft " + Ma yella ur tezmireḍ ara ad tferḍeḍ tangalt nnig, senqed s userwes n tegrumma tamecṭuḥt, tafrayant n yimujiten. Tugna n tengalt QR Senqed %s Yettusenqed %s - "I tɣelliset akk i ifazen, selken %s s usenqed n tengalt n tikklet deg yibenkan-inek·inem + I tɣelliset akk i ifazen, senqed %s s usenqed n tengalt n useqdec asuf ɣef isin yibenkan-inek·inem. \n -\nI tɣellist tafellayt, eg aya s timmad-ik·im " - "Iznan deg texxamt-a ttwawgelhen seg yixef ɣer yixef. +\nI tɣellist meqqren, eg aya s timmad-ik·im. + Iznan deg texxamt-a ttwawgelhen seg yixef ɣer yixef. \n -\nIznan-inek·inem ttwaɣellsen s lemfatiḥ, rnu ala kečč d umesɣad i yesɛan tisura tasufin i tweldaywt-nsen " +\nIznan-inek·inem ttwasɣellsen s yizekṛunen, rnu ala kečč d uɣerwaḍ i yesɛan tisura tasufin i tweldaywt-nsen. Tigawin n unedbal Iɣewwaren n texxamt Yiwen umdan %1$d yimdanen - Tuffɣa n texxamt... + Tuffɣa seg texxamt… Imaẓragen - "Dbel deg %1$s " + Anedbal deg %1$s D amaẓrag deg %1$s - "Amezwer deg %1$s " + Amezwer deg %1$s D udmawan (%1$d) deg %2$s "Element ur isekker ara ineḍruyen n wanaw \'%1$s\'" "Element ur isekker ara izen n wanaw \'%1$s\'" - "Element yemlal-d ugur mi ara d-yettarra agbur n uneḍru s usulay \'%1$s\' " + Element yemlal-d ugur mi ara d-yettarra agbur n uneḍru s usulay \'%1$s\' Tiɣimit-a ulamek ara tebḍu aselken-a akked tqimiyin-nniḍen. \nAselken ad yettwaseklas s wudem adigan syen yettwabḍu deg lqem i d-iteddun n usnas. @@ -2262,12 +2262,12 @@ Tixxamin-nniḍen Yuzen iznan i d-yettunefken yeɣma s yiniten am teslit n Unẓar - "Yuzen tanfalit i d-yettunefken teɣma s yiniten am teslit n Unẓar " + Yuzen tasedmirt i d-yettunefken teɣma s yiniten am teslit n Unẓar Amaẓrag n yizen - Akken ara tremdeḍ awgelhen i texxamt ur yettizmir ara ad yekkes. Iznan n texxamt tawgelhant ur tent-yettwali ara uqeddac, ala wid yettekkan deg texxamt. Armad n uwgelhen ur yettaǧǧa ara kra n yiṛubuten d kra n tleggiyin ad ddun akken iwata. Issin ugar ɣef uwgelhen. - "I wakken ad tḍemneḍ taɣellist-ik·im, selken %s s usenqed n tengalt " + Akken ara tremdeḍ awgelhen i texxamt, ur yettizmir ara ad yettwakkes. Iznan n texxamt yettwaznendeg texxamt yettwawgelhen ur ten-yettwali ara uqeddac, ala wid yettekkan deg texxamt. Armad n uwgelhen ur yettaǧǧa ara kra n yiṛubuten d kra n tleggiyin ad ddun akken iwata.Issin ugar ɣef uwgelhen. + I wakken ad tḍemneḍ taɣellist-ik·im, senqed %s s userwes n tenqalt n useqdec asuf. I wakken ad tḍemneḍ taɣellistik·im, eg ayagi s timmad-ik·im neɣ seqdec abrid n teywalt iɣef ara tettekleḍ. Serwes imujit ufrin, s uḍman ad d-banen deg yiwen usemizwer. @@ -2279,8 +2279,8 @@ Azmul anmidag yettwarmed \nTisura ttwattkalent. \nTisura tusligen ur ttwassnent ara - Azmul anmidag yettwarmed -\nTisura ttwattkalent. + Azmul anmidag yettwarmed. +\nTisura ur ttwattkalent ara Azmul anmidag ur yettwarmed ara Tɣimiyin turmidin @@ -2291,7 +2291,7 @@ Ulac talɣut n uwgelhen i yellan Tiɣimit-a tettwattkal i yiznan iɣelsanen acku tesneqdeḍ-tt: - "Selken tiɣimit-a i wakken ad tt-tcerḍeḍ tettwattkal & anef-as ad tekcem ɣer yiznan yettwawgelhen. Ma yella ur tesriḍ ara ad tkecmeḍ ɣer tɣimit-a, amiḍan-inek·inem yezmer ad yettwaker " + Senqed tiɣimit-a i wakken ad tt-tcerḍeḍ tettwattkal & anef-as ad tekcem ɣer yiznan yettwawgelhen. Ma yella ur teqqineḍ ara ɣer tɣimit-a, amiḍan-inek·inem yezmer ad yettwaker: %d tɣimit t ururmidt @@ -2300,23 +2300,23 @@ Yemmed s wudem aɣelsan - "Seqdec tiɣimit i yellan i wakken ad tesneqdeḍ tagi, s umuddu n uzref i wakken ad tekcem ɣer yiznan yettwawgelhen. " + Seqdec tiɣimit i yellan i wakken ad tesneqdeḍ tagi, s umuddu n uzref i wakken ad tekcem ɣer yiznan yettwawgelhen. Awway n tɣimiyin ur yeddi ara Tiɣimit-a tettwattkal i yiznan iɣelsanen acku %1$s (%2$s) issenqed-itt: %1$s (%2$s) yettuzmel deg useqdec n tɣimit tamaynut: - "Akken ara yettkel useqdac-a ɣef tɣimit-a, iznan yettwaznen ɣer neɣ i d-yettwaznen seg ad sɛun lemḥadra. Syen, tzemreḍ ad tent-slekneḍ s ufus " + Imi mazal useqdac-a ur yettkil ara ɣef tɣimit-a, iznan yettwaznen seg-s d wid i d-yettwaznen qer-s ad sɛun tacreḍt n lemḥadra. Neɣ ma ulac, tzemreḍ ad tent-tesneqdeḍ s ufus. Wennez azmul anmidag Tangalt QR - "Qrib ad tawḍeḍ! Kifkif %s aɣar i d-yeskanay\? " + Qrib ad tawḍeḍ! Ma yella %s kifkif aɣar i d-yeskanay\? Tuqqna ɣer uqeddac truḥ - "Askar n yermed " + Askar n usafag yermed - "Ifecka n yibenk " + Ifecka n tneflit %d tafrant %d tifranin @@ -2325,45 +2325,45 @@ %d tafrant - Igmaḍ n taggara %d tifranin - Igmaḍ n taggara - "Yerna poll afessas " + Yerna assenqed afessas Seqdec tafyirt tuffirt n tririt neɣ tasarut Ma yella ur tezmireḍ ara ad tkecmeḍ ɣer tɣimit i yellan Ur nessaweḍ ara ad naf tuffirin deg uklas Ilaq ad tkecmeḍ ɣer uklas uffir ala seg yibenk yetwaḍemnen - Kkes... + Kkes… Tebqiḍ ad tazneḍ taceqquft-a yaddan i %1$s\? - "Azen tugna s teɣzi tagejdant " - "Azen tuniwin s teɣzi tagejdant " + Azen tugna s teɣzi taneẓlit + Azen tuniwin s teɣzi taneẓlit Rnu taɣzint - "Taɣzint i tira " + Taɣzint n tukksa Yettewekkes uneḍru sɣur aseqdac, taɣzint: %1$s - "Aneḍru yellan s lmendad n unedbal n texxamt, taɣzint: %1$s " + Aneḍru yella-d s lmendad n unedbal n texxamt, taɣzint: %1$s Serreḥ i umazray n yiznan yettwawgelhen Aru i usenqed d uselken - "Seqdec tiɣimit-a i usenqed tiɣimit-ik·im tamaynut, s tikci n uzref i wakken ad tekcem ɣer yiznan yettwawgelhen. " - "Mačči d nekk " + Seqdec tiɣimit-a i usenqed tiɣimit-ik·im tamaynut, ayen ara tt-yeǧǧen ad tekcem ɣer yiznan yettwawgelhen. + Mačči d nekk Amiḍan-ik·im yezmer ad yettwaker - "Ma yella teffɣeḍ, ur tettizmireḍ ara ad teɣreḍ iznan yettwawgelhen ɣef yibenk-a, ula d iseqdacen-nniḍen ur t-ttamnen ara " - "Ma yella teffɣeḍ, ur tettizmireḍ ara ad teɣreḍ iznan yettwawgelhen ɣef yibenk-inek·inem amaynut, ula d iseqdacen-nniḍen ur t-ttamnen ara " - "Ur tesneqdeḍ ara %1$s (%2$s) ma yella ad teffɣeḍ tura. Bdu tikkelt-a deg umaɣun-ines n useqdac " + Ma yella tesfesxeḍ, ur tettizmireḍ ara ad teɣreḍ iznan yettwawgelhen ɣef yibenk-a, ula d iseqdacen-nniḍen ur t-ttamnen ara + Ma yella tesfesxeḍ, ur tettizmireḍ ara ad teɣreḍ iznan yettwawgelhen ɣef yibenk-inek·inem amaynut, ula d iseqdacen-nniḍen ur t-ttamnen ara + Ur tesneqdeḍ ara %1$s (%2$s) ma yella ad tesfesxeḍ tura. Bdu tikkelt-a deg umaɣun-ines n useqdac. - "Yiwen seg wayen i d-iteddun yezmer ad yettwaker: + Yiwen seg wayen i d-iteddun yezmer ad yettwaker: \n -\n-Awal-ik·im uffir -\n-Aqeddac-ik·im agejdan -\nIbenk-a, neɣ ibenk-nniḍen -\n-Tuqqna ɣer internet n yibenkan-nniḍen yettuseqdacen +\n- Awal-ik·im uffir +\n- Aqeddac-ik·im agejdan +\n- Ibenk-a, neɣ ibenk-nniḍen +\n- Tuqqna ɣer internet yettuseqdacen seg yal ibenk \n -\nAd ak·akem-nwelleh ad tesnifleḍ awal-ik·im uffir & tsarut n tririt deg yiɣewwaren tura tura " +\nAd ak·akem-nwelleh ad tesnifleḍ awal-ik·im uffir & tsarut n tririt deg yiɣewwaren tura tura. Senqed ibenkan-ik·im seg yiɣewwaren. Yettwasefsex usenqed @@ -2379,7 +2379,7 @@ Sekcem %s inek·inem i wakken ad tkemmleḍ. - "Ḍmen & ldi iznan yettwawgelhen syen ttkel s %s " + Ḍmen & ldi iznan yettwawgelhen syen ttkel s %s. Sekcem %s inek·inem i usentem-ines. Ur sseqdac ara awal-ik·im uffir n umiḍan. @@ -2391,16 +2391,16 @@ \nTzemreḍ ad tesbaduḍ aḥraz aɣelsan rnu ad tesferkeḍ tisura-inek·inem melmi i tebɣiḍ deg yiɣewwaren. Iznan deg texxamt-a ttwawgelhen seg yixef ɣer yixef. Issin ugar & senqed iseqdacen deg yimuɣna-nsen. - Awgelhen yettusqedcen deg texxamt-a ur yettusefrak ara. + Awgelhen yettusqedcen deg texxamt-a ur yettusefrak ara %s yerna taxxamt syen iswel-itt. Aql-ak·akem terniḍ, tsewleḍ taxxamt. Qrib ad tawḍeḍ! Wissen ma yella ibenk-nniḍen kifkif aɣar i d-yeskanay\? - Qrib ad tawḍeḍ! Aṛaǧu i usentem..... + Qrib ad tawḍeḍ! Deg uṛaǧu n usentem… Aktar n tsura ur yeddi ara - "Aswel n yilɣa " + Aswel n yilɣa Sbadu azal n wulɣu s uneḍru Isem n useqdac d/neɣ awal uffir d arameɣtu. Awal uffir yettwaskecmen yebda neɣ yekfa s tallunt, ma ulac aɣilif senqed-it. @@ -2413,38 +2413,38 @@ Asenqed n tsarut n uḥraz Asenqed n tsarut n uḥraz (%s) Awway n tsarut n uzlig - "Tiririt n tuffirt n uḥraz n tsarut deg SSSS " + Aklas n tuffirt n uḥraz n tsarut deg SSSS Sekcem tafyirt tuffirt n uḥraz n tsarut i wakken ad tkemmleḍ. - "seqdec tasarut n tririt n uḥraz n tsarut " - Ur tessineḍ ara tafyirt-ik·im tuffirt n uḥraz n tsarut, tzemreḍ %s - "Tasarut n tririt n uḥraz n tsarut " + seqdec tasarut-ik·im n tririt n uḥraz n tsarut + Ur tessineḍ ara tafyirt-ik·im tuffirt n uḥraz n tsarut, tzemreḍ %s. + Tasarut n tririt n uḥraz n tsarut - "Tuṭṭfiwin n ugdil n usnas i yezrin " - "Armad n uɣewwar-a ad yernu FLAG_SECURE ɣer meṛṛa irmad. Ales asenker n usnas i wakken ad yemmed usnifel " + Sewḥel tuṭṭfiwin n ugdil n usnas + Armad n uɣewwar-a ad yernu FLAG_SECURE ɣer meṛṛa irmad. Ales asenker n usnas i wakken ad yemmed usnifel. - "Afaylu n umidyat yettwarna ɣer temsikent " - "Ur yezmir ara ad yernu afaylu n umidyat ɣer " - "Seqdec lqem akk aneggaru n Element ɣef yibenkan-inek·inem-nniḍen, Element Web, Element Desktop, Element iOS, Element i Android neɣ azmul anmidag wayeḍ i izemren i umsaɣ n Matrix " - "Fren tasarut-ik·im n tririt, neɣ err-itt s ufus s tira-ines neɣ s usenteḍ-ines seg ɣefafus-inek·inem " + Afaylu n umidyat yettwarna ɣer temsikent + D awezɣi ad yernu ufaylu n umidyat ɣer temsikent + Seqdec lqem akk aneggaru n Element ɣef yibenkan-inek·inem-nniḍen: Element Web, Element n tnarit, Element iOS, Element i Android neɣ amsaɣ-nniḍen n Matrix yessefraken azmul anmidag + Fren tasarut-ik·im n tririt, neɣ err-itt s ufus s tira-ines s uasiw neɣ s usenteḍ-ines seg ɣefafus-inek·inem Senqed amyigew s yimujit Sentem timagit-inek·inem s usenqed n yinekcam-a, anef-as ad yekcem ɣer yiznan yettwawgelhen. - "Suref-aɣ, tigawt ulamek i tedda akka tura i yimiḍanen i yettwaqqnen s useqdec n tuqqna ɣef asuf " + Suref-aɣ, tamahelt-a ulamek i tedda akka tura i yimiḍanen i yettwaqqnen s useqdec n unekcum asuf. - "Sit snat n tikkal ɣef useɣwen " + Senqed tikkelt-nniḍen aseɣwen-a Aseɣwen %1$s ad ak·akem-yawi ɣer usmel-nniḍen: %2$s. \n \nTebɣiḍ s tidet ad tkemmleḍ\? Ffeɣ seg tuqqna n uqeddac n timagit %s\? - "Aqeddac-a n timagit iɛedda wazemz-ines. Element yessafrak kan API V2. " - "Tigawt-a ulamek tedda. Aqeddac agejdan yemmut " + Aqeddac-a n timagit iɛedda d aqbur. Element yessafrak kan API V2. + Tamahekt-a ulamek tedda. Aqeddac agejdan d aqbur. Ma ulac aɣilif qbel deg tazwara swel aqeddac n timagit. Ma ulac aɣilif qbel deg tazwara tiwtilin n uqeddac n timagit deg yiɣewwaren. - "I tɣellist n tbaḍnit-ik·im, Element yessefrak kan yimaylen d wuṭṭunen n tiliɣri" - "Tawsit ur teddi ara " - "Mačči d tadrut tamirant akked unaglam-a " + I tɣellist n tbaḍnit-ik·im, Element yessefrak kan tuzna n yimaylen d wuṭṭunen n tiliɣri yettudwin i useqdac. + Assaɣ ur yeddi ara. + Akka tura ulac akk assaɣ d unekcam-a. - "Aqeddac-ik·im agejdan (%1$s) yefka-d takti n useqdec n %2$s i uqeddac-ik·im n timagit " + Aqeddac-ik·im agejdan (%1$s) yefka-d takti n useqdec n %2$s d aqeddac-ik·im n timagit tzemreḍ ad teskecmeḍ URl n uqeddac n timagit i tebɣiḍn Sekcem URL i uqeddac n timagit Sekcem tafyirt n tɣellist ara tissineḍ kan kečč·kemm, syen sirew tasarut i uḥraz. @@ -2452,7 +2452,33 @@ Sekcem tafyirt n tɣellist ara tissineḍ kan keččini·kemmini, tettuseqdac i wakken ad teḍmen tuffriwin deg uqeddac-ik·im. Sekcem tafyirt-inek·inem n tɣellist tikkelt-nniḍen i usentem-ines. - "Rǧu izen-a, yezmer ad iɛeṭṭel " - "Ur tezmireḍ ara ad teldiḍ taxxamt anisi i d-tettwasuffɣeḍ " + Araǧu n izen-a, aya yezmer ad yeṭṭef akud + Ur tezmireḍ ara ad teldiḍ taxxamt ansi i d-tettwagedleḍ. Ur nessaweḍ ara ad d-naf taxamt-a. Muqel ma tella d tidet. - +Senqes deg wazal + Element ur t-iḥuza ara usesfer n uẓru. + Tamahelt-a tesra asentem-nniḍen. +\nI ukemmel, ma ulac aɣilif sekcem awal-ik·im uffir. + %s yettaɛraḍ ad d-isali tazmilt tufrint deg tesnakudt n texxamt-a, maca ur yessaweḍ ara ad tt-naf. + + Neɣ; dmen aḥrazen-inek·inem s tefyirt tuffirt n uɛeddi, yettwaskelsen deg wadeg aɣelsan. + Tiririt n lqem n uḥraz... + Rnu iccer ara yettunefken i yilɣa ur nettwaɣra ara deg ugdil agejdan. + + Rmed iɣmisen ɣezzifen. + Ma ulac aɣilif ɛreḍ tikkelt-nniḍen mi ara tqebleḍ tiwtilin n uqeddac-ik·im agejdan. + + Mdel aɣarrac n uḥraz n tsura + Mačči d ayen ilaqen + Yettwazen d ayen ur nlaq ara + Seɣzef asiti ɣef texxamt i wakken ad twaliḍ ugar n textiṛiyin + + + Semṣer, rnu sagen tarmit-ik·im + "Am yimaylen, imiḍanen sɛan kan yiwen n uqeddac agejdan, ɣas ma tzemreḍ ad temmeslayeḍ i yal yiwen" + Ma ulac aɣilif sɛeddi akayad captcha + Ad ak·am-iruḥ unekcum ɣer yiznan iɣelsanen slid ma teqqneḍ i wakken ad d-terreḍ tisura-inek·inem n uwgelhen. + Ahuzzu n ufḍam + Talast n tifin + Huzz tiliɣri-inek·inem i wakken ad teskeydeḍ talast n tifin + From b6454b70a64cf9ed02ec9a98047670b58cdb5d48 Mon Sep 17 00:00:00 2001 From: Constantin Wartenburger Date: Mon, 14 Sep 2020 20:59:34 +0200 Subject: [PATCH 60/89] Only front camera is mirrored now --- CHANGES.md | 1 + .../vector/app/features/call/WebRtcPeerConnectionManager.kt | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index f7c7f9d044..c813a87db1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,7 @@ Improvements 🙌: Bugfix 🐛: - Clear the notification when the event is read elsewhere (#1822) - Speakerphone is not used for ringback tone (#1644, #1645) + - Back camera preview is not mirrored anymore (#1776) Translations 🗣: - diff --git a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt index b53be292c8..e3e686a45c 100644 --- a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt @@ -503,7 +503,7 @@ class WebRtcPeerConnectionManager @Inject constructor( // render local video in pip view localSurfaceRenderer.forEach { it.get()?.let { pipSurface -> - pipSurface.setMirror(true) + pipSurface.setMirror(this.cameraInUse?.type == CameraType.FRONT); // no need to check if already added, addSink is checking that currentCall?.localVideoTrack?.addSink(pipSurface) } @@ -740,6 +740,10 @@ class WebRtcPeerConnectionManager @Inject constructor( override fun onCameraSwitchDone(isFrontCamera: Boolean) { Timber.v("## VOIP onCameraSwitchDone isFront $isFrontCamera") cameraInUse = availableCamera.first { if (isFrontCamera) it.type == CameraType.FRONT else it.type == CameraType.BACK } + localSurfaceRenderer.forEach { + it.get()?.setMirror(isFrontCamera) + } + currentCallsListeners.forEach { tryThis { it.onCameraChange(this@WebRtcPeerConnectionManager) } } From 95eb6926d4153eed8afcd216ace4e4bee828dab5 Mon Sep 17 00:00:00 2001 From: ginnyTheCat Date: Mon, 14 Sep 2020 21:48:26 +0200 Subject: [PATCH 61/89] Removed unnecessary semicolon --- .../im/vector/app/features/call/WebRtcPeerConnectionManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt index e3e686a45c..655de3376c 100644 --- a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt @@ -503,7 +503,7 @@ class WebRtcPeerConnectionManager @Inject constructor( // render local video in pip view localSurfaceRenderer.forEach { it.get()?.let { pipSurface -> - pipSurface.setMirror(this.cameraInUse?.type == CameraType.FRONT); + pipSurface.setMirror(this.cameraInUse?.type == CameraType.FRONT) // no need to check if already added, addSink is checking that currentCall?.localVideoTrack?.addSink(pipSurface) } From b088c23ea222e44ca9fad64a08dd5662067690dc Mon Sep 17 00:00:00 2001 From: Safa Alfulaij Date: Sun, 13 Sep 2020 15:53:30 +0000 Subject: [PATCH 62/89] Translated using Weblate (Arabic) Currently translated at 66.1% (111 of 168 strings) Translation: Element Android/Element Android Sdk Translate-URL: https://translate.riot.im/projects/element-android/element-sdk/ar/ --- .../src/main/res/values-ar/strings.xml | 101 ++++++++++++++---- 1 file changed, 83 insertions(+), 18 deletions(-) diff --git a/matrix-sdk-android/src/main/res/values-ar/strings.xml b/matrix-sdk-android/src/main/res/values-ar/strings.xml index e9aba1721a..5f4603ec6e 100644 --- a/matrix-sdk-android/src/main/res/values-ar/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ar/strings.xml @@ -6,21 +6,21 @@ دعوة من ⁨%s⁩ دعى ⁨%1$s⁩ ⁨%2$s⁩ دعاك ⁨%1$s⁩ - انضمّ ⁨%1$s⁩ - غادر ⁨%1$s⁩ + انضمّ ⁨%1$s⁩ إلى الغرفة + غادر ⁨%1$s⁩ الغرفة رفض ⁨%1$s⁩ الدعوة طرد ⁨%1$s⁩ ⁨%2$s⁩ - رفع ⁨%1$s⁩ الحظر عن ⁨%2$s⁩ + رفع ⁨%1$s⁩ المنع عن ⁨%2$s⁩ منع ⁨%1$s⁩ ⁨%2$s⁩ غيّر ⁨%1$s⁩ صورته ضبط ⁨%1$s⁩ اسم العرض على ⁨%2$s⁩ - غيّر ⁨%1$s⁩ اسم الحساب المعروض من %2$s⁩ إلى %3$s⁩ - أزال ⁨%1$s⁩ اسم الحساب المعروض (⁨%2$s⁩) + غيّر ⁨%1$s⁩ اسم العرض من ⁨%2$s⁩ إلى ⁨%3$s⁩ + أزال ⁨%1$s⁩ اسم العرض (⁨كان ⁨%2$s⁩) غيّر ⁨%1$s⁩ الموضوع إلى: ⁨%2$s⁩ غيّر ⁨%1$s⁩ اسم الغرفة إلى: ⁨%2$s⁩ ردّ ⁨%s⁩ على المكالمة. أنهى ⁨%s⁩ المكالمة. - جعل ⁨%1$s⁩ تأريخ الغرفة مستقبلًا ظاهرا على %2$s + جعل ⁨%1$s⁩ تأريخ الغرفة مستقبلًا ظاهرًا على ⁨%2$s⁩ كل أعضاء الغرفة من لحظة دعوتهم. كل أعضاء الغرفة من لحظة انضمامهم. كل أعضاء الغرفة. @@ -46,7 +46,7 @@ خطأ في الشبكة خطأ في «ماترِكس» - ليس ممكنا الانضمام ثانيةً إلى غرفة فارغة. + لا يمكنك حاليًا الانضمام ثانيةً إلى غرفة فارغة. رسالة معمّاة @@ -54,13 +54,13 @@ رقم الهاتف ‏‏⁨%1$s⁩: ‏⁨%2$s⁩ - انسحب ⁨%1$s⁩ من الدعوة ⁨%2$s⁩ + انسحب ⁨%1$s⁩ من دعوة ⁨%2$s⁩ أجرى ⁨%s⁩ مكالمة مرئية. أجرى ⁨%s⁩ مكالمة صوتية. - قبل ⁨%1$s⁩ دعوة ⁨%2$s⁩ + قَبِل ⁨%1$s⁩ دعوة ⁨%2$s⁩ تعذر التهذيب - أرسل ⁨%1$s⁩ ملصقا. + أرسل ⁨%1$s⁩ ملصقًا. (تغيّرت الصورة أيضا) @@ -71,12 +71,77 @@ دعوة إلى غرفة - صفر - واحد - اثنان - قليل - كثير - اخرى - + + + + + + + - +أرسلت صورة. + أرسلت ملصقًا. + + دعوة منك أنت + أنشأ ⁨%1$s⁩ الغرفة + أنشأت الغرفة + دعوت ⁨%1$s⁩ + انضممت إلى الغرفة + غادرت الغرفة + رفضت الدعوة + طردت ⁨%1$s⁩ + رفعت المنع عن ⁨%1$s⁩ + منعت ⁨%1$s⁩ + انسحبت من دعوة ⁨%1$s⁩ + غيّرت صورتك + ضبطت اسم العرض على ⁨%1$s⁩ + غيّرت اسم العرض من ⁨%1$s⁩ إلى ⁨%2$s⁩ + أزلت اسم العرض (كان ⁨%1$s⁩) + غيّرت الموضوع إلى: ⁨%1$s⁩ + غيّر ⁨%1$s⁩ صورة الغرفة + غيّرت صورة الغرفة + غيّرت اسم الغرفة إلى: ⁨%1$s⁩ + أجريت مكالمة مرئية. + أجريت مكالمة صوتية. + أرسل ⁨%s⁩ البيانات لإعداد المكالمة. + أرسلت البيانات لإعداد المكالمة. + رددت على المكالمة. + أنهيت المكالمة. + جعلت تأريخ الغرفة مستقبلًا ظاهرًا على ⁨%1$s⁩ + فعّلت تعمية الطرفين (⁨%1$s⁩) + رقّى ⁨%s⁩ هذه الغرفة. + رقّيت هذه الغرفة. + + طلبت اجتماع VoIP + أزلت اسم الغرفة + أزلت موضوع الغرفة + أزال ⁨%1$s⁩ صورة الغرفة + أزلت صورة الغرفة + أُزيلت الرسالة + أزال ⁨%1$s⁩ الرسالة + أُزيلت الرسالة [السبب: ⁨%1$s⁩] + أزال ⁨%1$s⁩ الرسالة [السبب: ⁨%2$s⁩] + أرسلت دعوة إلى ⁨%1$s⁩ للانضمام إلى الغرفة + سحب ⁨%1$s⁩ دعوة ⁨%2$s⁩ للانضمام إلى الغرفة + سحبت دعوة ⁨%1$s⁩ للانضمام إلى الغرفة + قَبِلت دعوة ⁨%1$s⁩ + + أضاف ⁨%1$s⁩ الودجة ⁨%2$s⁩ + أضفت الودجة ⁨%1$s⁩ + أزال ⁨%1$s⁩ الودجة ⁨%2$s⁩ + أزلت الودجة ⁨%1$s⁩ + عدّل ⁨%1$s⁩ الودجة ⁨%2$s⁩ + عدّلت الودجة ⁨%1$s⁩ + + مدير + المبدئي + مخصّص (⁨%1$d⁩) + مخصّص + + غيّرت مستوى قوّة %1$s⁩. + غيّر ⁨%1$s⁩ مستوى قوّة %2$s⁩. + ‏⁨%1$s⁩ من ⁨%2$s⁩ إلى ⁨%3$s⁩ + + المزامنة الأولية: +\nيستورد الحساب… + From eb2166dd4c2ebe47748ad09d2e79b7ae113e0773 Mon Sep 17 00:00:00 2001 From: zeritti Date: Fri, 11 Sep 2020 15:02:06 +0000 Subject: [PATCH 63/89] Translated using Weblate (Czech) Currently translated at 100.0% (1867 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/cs/ --- vector/src/main/res/values-cs/strings.xml | 442 +++++++++++++++++----- 1 file changed, 345 insertions(+), 97 deletions(-) diff --git a/vector/src/main/res/values-cs/strings.xml b/vector/src/main/res/values-cs/strings.xml index 1db3b14c6f..ab940936a8 100644 --- a/vector/src/main/res/values-cs/strings.xml +++ b/vector/src/main/res/values-cs/strings.xml @@ -9,7 +9,7 @@ Nastavení OK Uložit - Načítání… + Načítám… Zrušit Odeslat @@ -32,31 +32,31 @@ Hlasitá oznámení Tichá oznámení - Nahlásit chybu - Detail člena + Hlášení chyby + Podrobnosti člena Historický Podrobnosti o komunitě - Naslouchat událostem + Naslouchám událostem Poslat znovu - Odebrat + Odstranit Citovat Později Trvalý odkaz - Zobraz dešifrovaný zdroj + Zobrazit dešifrovaný zdroj Nahlásit obsah Aktivní hovor Probíhající konferenční hovor. \nPřipojit se jako %1$s nebo %2$s Hlasem Videem - Nemohu spustit hovor, prosím zkusit později + Nemohu spustit hovor, zkuste, prosím, později Z důvodu chybějících práv mohou některé funkce chybět… - Potřebujete práva pro spuštění konference + Potřebujete práva k pozvání pro spuštění konference v této místnosti Nemohu spustit hovor Informace o relaci Konferenční hovory nejsou podporovány v šifrovaných místnostech - Stejně pošli + Přesto poslat Ukončit Akce Odhlásit @@ -69,7 +69,7 @@ Otevřít Zavřít Zkopírovat do schránky - Zakázat + Vyřadit Potvrzení Varování @@ -83,7 +83,7 @@ Filtrovat jména místností Filtrovat oblíbené Filtrovat lidi - Filtrovat jména místností + Filtrovat názvy místností Filtrovat jména komunit Pozvání @@ -94,7 +94,7 @@ Uživatelský adresář Pouze kontakty Matrix Žádné konverzace - Nepovolil jste přístup aplikaci Element k místním kontaktům + Nepovolil jste aplikaci Element přístup k místním kontaktům Žádné výsledky Místnosti @@ -111,17 +111,17 @@ Komunity Žádné skupiny - Odeslat logy - Odeslat chybové logy - Odeslat snímek obrazovky + Odeslat záznamy + Odeslat záznamy zřícení + Odeslat screenshot Ohlásit chybu - Popsat zde svůj problem + Zde popište svůj problém Za účelem diagnostiky problémů budou logy tohoto klienta odeslány s touto zprávou o chybě. Tato zpráva o chybě včetně logů a snímku obrazovky nebude veřejně viditelná. Pokud byste raději poslali pouze text výše, prosím odznačte: Vypadá to, že třesete telefonem z důvodu nespokojenosti. Přejete si podat hlášení o chybě? - Aplikace naposled spadla. Přejete si otevřít okno pro nahlášení chyby\? - Chyba byla úspešně odeslána - Selhalo odeslání hlášení o chybě (%s) - Postup (%s%%) + Aplikace minule spadla. Přejete si otevřít okno pro nahlášení chyby\? + Hlášení o chybě bylo úspešně odesláno + Odeslat hlášení o chybě se nezdařilo (%s) + Průběh (%s%%) Odeslat do Přečíst @@ -131,13 +131,13 @@ Založit účet Přihlásit se Odhlásit se - Adresa domácího serveru URL - Adresa serveru identit URL + Adresa URL domácího serveru + Adresa URL serveru identit Hledat Začít novou konverzaci - Začít hlasový hovor - Začít video hovor + Zahájit hlasový hovor + Zahájit video hovor Opravdu chcete začít novou konverzaci s %s\? Opravdu chcete zahájit hlasový hovor\? @@ -150,7 +150,7 @@ Přihlásit se Vytvořit účet - Potvrdit + Odeslat Přeskočit Odeslat obnovovací e-mail Návrat na přihlašovací obrazovku @@ -170,7 +170,7 @@ Chybí heslo Zdá se, že toto není platná e-mailová adresa Zdá se, že toto není platné telefonní číslo - Tato e-mailová adresa je již použita. + Tato e-mailová adresa je již zadána. Chybí e-mailová adresa Chybí telefonní číslo Chybí e-mailová adresa nebo telefonní číslo @@ -178,13 +178,13 @@ Hesla se neshodují Zapomenuté heslo? Použít vlastní možnosti serveru (pokročilé) - Prosím zkontrolujte své e-maily, abyste mohli pokračovat v registraci + Prosím, zkontrolujte své e-maily, abyste mohli pokračovat v registraci Tento domovský server by se rád přesvědčil, že nejste robot - Uživatelské jméno je použito + Uživatelské jméno již použito Domácí server: Server identity: Ověřil/a jsem svoji e-mailovou adresu - K resetování hesla vložte e-mailovou adresu spojenou s vaším účtem: + K resetování hesla zadejte e-mailovou adresu spojenou s vaším účtem: Musíte zadat e-mailovou adresu spojenou s vaším účtem. Musíte zadat nové heslo. Na adresu %s byla odeslána zpráva. Potom, co přejdete na odkaz z této zprávy, klepněte níže. @@ -197,9 +197,9 @@ Nelze se registrovat: chyba ověření vlastnictví e-mailu Prosím, zadejte platné URL - Neplatný uživatelský jméno/heslo + Neplatný uživatelské jméno/heslo Poškozený JSON - Příliš mnoho požadavků bylo odeslano + Bylo odesláno příliš mnoho požadavků Toto uživatelské jméno je již použito Motiv vzhledu Status.im @@ -218,15 +218,15 @@ Systémová upozornění - Prosím popište chybu. Jak se přihodila? Jaké bylo očekávané chování? Co se ve skutečnosti stalo? - Pokud je to možné, prosím, napište popis v angličtině. + Prosím, popište chybu. Co jste provedli\? Jaké bylo očekávané chování\? Co se ve skutečnosti stalo\? + Pokud je to možné, prosím, napište popis anglicky. Třesením oznámit chybu Odeslat hlasovou zprávu Odeslat nálepku - Momentálně nemáte žádné balíčky s nálepkami aktivní. -\n + Momentálně nemáte žádné aktivní nálepkové sady. +\n \nPřejete si nějaké přidat nyní\? pokračovat v… @@ -242,7 +242,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. \nByli jste odhlášeni ze všech relací a již nebudete dostávat oznámení. Pro opětovnou aktivaci oznámení se znovu přihlaste na každém zařízení. Prosím, přečtěte si a souhlaste s pravidly tohoto serveru: - Přistupový token nebyl rozpoznán + Zadaný přistupový token nebyl rozpoznán Neobsahuje platný JSON E-mailový odkaz, na který ještě nebylo klepnuto @@ -273,20 +273,20 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Název místnosti Téma místnosti - Volání - Použít původní vyzvánění Element pro příchozí hovory + Hovory + Použít původní vyzvánění Elementu pro příchozí hovory Vyzvánění příchozího hovoru Vybrat vyzvánění pro hovory: Hovor Hovor spojen - Spojování hovoru… + Spojuji hovor… Hovor ukončen - Vytáčení… + Vytáčím… Příchozí hovor Příchozí video hovor Příchozí hlasový hovor - Probíhá hovor… + Hovor probíhá… Protější strana hovor nepřijala. Chyba spojení médií @@ -304,12 +304,12 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. " \n \nProsím, povolte přístup na následující hlášce, abyste mohli uskutečnit hovor." - Element potřebuje oprávnění pro přístup k Vašemu mikrofonu pro uskutečňování hlasových hovorů. + Element potřebuje oprávnění pro přístup k Vašemu mikrofonu pro uskutečnění hlasových hovorů. " \n \nProsím, povolte přístup na následující hlášce, abyste mohli uskutečnit hovor." Uloženo - Uložit do Stažených souborů? + Uložit do stažených souborů\? ANO NE Pokračovat @@ -317,7 +317,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Odstranit Vstoupit Náhled - Byli jste pozváni %s ke vstupu do místnosti + Byli jste pozváni od %s ke vstupu do místnosti Žádost odeslána Prosím, spusťte Element na jiném zařízení, které může dešifrovat zprávu, aby poslalo klíče této relaci. @@ -331,7 +331,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Zobrazit členy Otevřít záhlaví - Synchronizování… + Synchronizuji… Přejít na první nepřečtenou zprávu. místnost @@ -349,10 +349,10 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. 1 člen - 1 s - %d s - %d s - + 1s + %ds + %ds + 1 min %d min @@ -372,7 +372,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Opustit místnost Opravdu chcete opustit tuto místnost\? Opravdu chcete vyhodit %s z této konverzace\? - Vytvořit + Založit On-line Off-line @@ -388,9 +388,9 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Pozvat Opustit tuto místnost Odstranit z této místnosti - Zakázat vstup - Odebrat zákaz vstupu - Vyhodit + Vykázat + Zrušit vykázání + Vykopnout Obnovit na normálního uživatele Udělat moderátorem Udělat správcem @@ -401,7 +401,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Zobrazit seznam relací Toto je náhled místnosti. Interakce s místností byla vypnuta. - Opravdu chcete zakázat vstup tohoto uživatele do této konverzace\? + Vykázání uživatele jej vykopne z této místnosti a zamezí, aby opět vstoupili. Důvod Opravdu chcete pozvat uživatele %s do této konverzace\? @@ -410,7 +410,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. %1$s %2$s Pozvat podle ID - LOKÁLNÍ KONTAKTY (%d) + MÍSTNÍ KONTAKTY (%d) ADRESÁŘ UŽIVATELŮ (%s) Jen uživatelé Matrix @@ -457,7 +457,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Záloha klíče Použít zálohu klíče - Záloha klíčů není ještě dokončena, prosím počkejte… + Záloha klíčů není ještě dokončena, čekejte, prosím… Pokud se nyní odhlásíte, přijdete o své zašifrované zprávy Probíhá záloha klíče. Pokud se nyní odhlásíte, ztratíte přístup ke svým zašifrovaným zprávám. Zabezpečená záloha klíčů by měla být aktivní na všech vašich relacích, aby se předešlo ztrátě přístupu k vašim zašifrovaným zprávám. @@ -471,10 +471,10 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Zůstat Přeskočit Hotovo - Přerušit + Zrušit Opravdu se chcete odhlásit\? - Probíhá video hovor… + Video hovor probíhá… Element potřebuje oprávnění pro přístup k Vaší kameře a mikrofonu pro uskutečnění video hovoru. \n @@ -486,21 +486,21 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Pozvánka byla odeslána na %s, což není spárováno s tímto účtem. \nPřihlaste se s jiným účtem nebo přidejte tento e-mail ke svému současnému účtu. - Snažíte se přistupovat k %s. Chcete vstoupit, abyste se mohli podílet na diskuzi\? - Tuto změnu nelze vrátit, protože povyšujete uživatele na stejnou úroveň, jakou máte vy. + Snažíte se o přístup k %s. Chcete vstoupit, abyste se mohli podílet na diskuzi\? + Tuto změnu nelze zvrátit, protože povyšujete uživatele na stejnou úroveň, jakou máte vy. \nOpravdu to chcete udělat\? - Prosím zadejte jednu nebo více e-mailových adres nebo Matrix ID + Prosím, zadejte jednu nebo více e-mailových adres nebo Matrix ID Zprávy nebyly odeslány z důvodu přítomnosti neznámých relací. %1$s nebo %2$s nyní\? Toto by mohlo znamenat, že někdo škodlivě zachytává Vaši komunikaci nebo že Váš telefon nedůvěřuje certifikátu poskytnutému vzdáleným serverem. - Pokud administrátor serveru řekl že toto je předpokládané, ujistěte se, že otisk níže se shoduje s otiskem který Vám poskytl. - Certifikát se změnil z toho, kterému Váš telefon důvěřoval. Toto je VYSOCE NEOBVYKLÉ. Je doporučeno abyste NEPŘIJÍMALI tento nový certifikát. - Certifikát se změnil z předtím důvěryhodného na nyní nedůvěryhodný. Server mohl obnovit svůj certifikát. Kontaktujte administrátora pro ověření předpokládaného otisku. - Přijměte certifikát pouze pokud administrátor serveru publikoval otisk který odpovídá tomu uvedenému výše. + Pokud administrátor serveru řekl, že toto je předpokládané, ujistěte se, že otisk níže se shoduje s otiskem který Vám poskytl. + Certifikát se změnil z toho, kterému Váš telefon důvěřoval. Toto je VELMI NEOBVYKLÉ. Je doporučeno, abyste NEPŘIJALI tento nový certifikát. + Certifikát se změnil z původně důvěryhodného na nyní nedůvěryhodný. Server patrně obnovil svůj certifikát. Kontaktujte administrátora kvůli očekávanému otisku. + Přijměte certifikát pouze pokud administrátor serveru publikoval otisk, který odpovídá tomu uvedenému výše. Neplatné ID. Mělo by být buď e-mailová adresa nebo Matrix ID např. \'@localpart:example.com\' POZVÁN - PŘIPOJEN + VSTOUPILI Důvod pro nahlášení tohoto obsahu Chcete skrýt všechny zprávy od tohoto uživatele\? @@ -509,7 +509,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Zrušit nahrávání Zrušit stahování - Vyhledávání + Vyhledat Filtrovat členy místnosti Žádné výsledky MÍSTNOSTI @@ -517,14 +517,14 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. LIDÉ SOUBORY - PŘIPOJIT + VSTOUPIT ADRESÁŘ OBLÍBENÉ MÍSTNOSTI NÍZKÁ PRIORITA POZVÁNKY Začít konverzaci - Vytvořit místnost + Založit místnost Vstoupit do místnosti Vstoupit do místnosti Zadejte ID nebo přezdívku místnosti @@ -562,7 +562,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Autorská práva Zásady ochrany osobních údajů - Profilová fotografie + Obrázek profilu Zobrazované jméno E-mail Přidat e-mailovou adresu @@ -576,7 +576,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Důležitost oznámení na základě události Spouštím služby - Ověřte relaci + Ověřit relaci Odpojit Ignorovat @@ -588,7 +588,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Žádný Zrušit Přehled - Nekonfigurován žádný ověřovací server. + Není konfigurován žádný ověřovací server. Volání se nezdařilo kvůli chybné konfiguraci serveru Prosím, požádejte administrátora homeserveru (%1$s) o konfiguraci TURN serveru, aby hovory fungovaly spolehlivě. @@ -608,18 +608,18 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Vaše zařízení používá zastaralý bezpečnostní protokol TLS, zranitelný útokem, pro Vaše bezpečí se nebudete moci spojit Povolit server fallback call assist Použiiji %s jako nápomoc, pokud Váš homeserver žádnou nenabízí (Vaše IP adresa bude sdělena během hovoru) - K provedení této akce přidat ověřovací server v nastavení. + Pro provedení této akce přidat server identit v nastavení. Potvrďte své heslo Nelze provést z Element mobile - Ověření se vyžaduje + Ověření je nutné Soukromí oznámení - Problém s oznámeními + Řešit oznámení Řešit diagnostiku Spustit testy Spouštím… (%1$d z %2$d) - Základní diagnostika je OK. Pokud stále ještě nedostáváte oznámení, pomůžete nám s vyšetřováním, nahlásíte-li nám to jako chybu. + Základní diagnostika je OK. Pokud stále ještě nedostáváte oznámení, pomůžete nám s vyšetřováním, nahlásíte-li nám chybu. Jeden či více testů selhalo, zkuste navržené opravy. Jeden či více testů selhalo, prosím, pomůžete nám s vyšetřováním, nahlásíte-li chybu. @@ -636,7 +636,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Zapnout Nastavení relací. - Oznámení jsou zapnuta pro tuto relaci. + Pro tuto relaci jsou oznámení zapnuta. Oznámení nejsou zapnuta pro tuto relaci. \nProsím, prověřte nastavení Elementu. Zapnout @@ -678,7 +678,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Spustit službu Auto-restart služby oznámení - Služba se zbořila a spustila se automaticky. + Služba byla ukončena a spustila se automaticky. Restart služby se nezdařil Spustit při zavádění @@ -721,11 +721,11 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Zprávy osahující mé veřejné jméno Zprávy osahující mé uživatelské jméno - Zprávy chatu one-to-one + Zprávy v přímých chatech Zprávy skupinových chatů Jsem-li pozván do místnosti Pozvání k hovoru - Zprávy poslány botem + Zprávy poslané botem Synchronizace na pozadí Režim synchronizace na pozadí (experimentální) @@ -803,13 +803,13 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Správa Vašich nastaveni pro odhalení. Soukromí ohledně oznámení Element může běžet na pozadí, aby spravoval Vaše oznámení bezpečně a v soukromí. To může mít vliv na baterii. - Udělit svolení + Udělit oprávnění Vybrat jinou volbu Spojení na pozadí Element potřebuje udržovat spojení na pozadí se slabým vlivem, abyste obdrželi spolehlivá oznámení. \nNa příští obrazovce budete dotázáni o svolení nechat Element vždy v chodu na pozadí, prosím, souhlaste. - Udělit svolení + Udělit oprávění Analýza Odeslat analytická data @@ -834,7 +834,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Přihlášen jako Home server - Ověřovací server + Server identit Povolit integrace Správce integrací @@ -981,7 +981,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Veřejné jméno (viditelné pro lidi, s nimiž komunikujete) Veřejné jméno relace je viditelné pro lidi, s nimiž komunikujete Veřejné jméno - ID + ID relace Klíč relace Potvrzení Otisk Ed25519 @@ -1043,10 +1043,10 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Stahuji klíče… Importuji klíče… - Obnovena záloha s %d klíčem. - Obnovena záloha s %d klíči. - Obnovena záloha s %d klíči. - + Obnovena záloha s %d klíčem. + Obnovena záloha se %d klíči. + Obnovena záloha s %d klíči. + Do této relace byl přidán %d nový klíč. Do této relace byly přidány %d nové klíče. @@ -1105,10 +1105,10 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. %1$s: %2$d zpráv - %d oznámení - %d oznámení - %d oznámení - + %d oznámení + %d oznámení + %d oznámeních + %1$s v %2$s Nová událost @@ -1618,7 +1618,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Všeobecné podmínky Pročíst všeobecné podmínky Nechte se nalézt druhými - Použijte boty, můstky, widgety a nálepky + Použijte boty, můstky, widgety a nálepkové sady Čtěte na @@ -1693,7 +1693,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Nahlásit tento obsah Důvod k nahlášení tohoto obsahu HLÁŠENÍ - ZABLOKOVAT UŽIVATELE + IGNOROVAT UŽIVATELE Obsah ohlášen Tento obsah byl ohlášen. @@ -1714,7 +1714,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Právě nyní není k dispozici žádné síťové spojení - Zablokovat uživatele + Ignorovat uživatele Všechny zprávy (hlučné) Všechny zprávy @@ -1736,7 +1736,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. %1$s nastavil místnost jen pro pozvané. Nepřečtené zprávy - Osvoboďte svou komunikaci + Je to Vaše konverzace. Vlastněte ji. Chatujte s lidmi přímo nebo ve skupinách Udržujte konverzace soukromé pomocí šifrování Rozšiřte & upravte si svůj zážitek @@ -2288,7 +2288,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Jinak, máte-li již účet a znáte-li svůj identifikátor a heslo, můžete použít tuto metodu: Přihlásit se s mým identifikátorem Matrixu Přihlásit se - Zadejte svůj identifikátor a heslo + Pokud založíte účet na homeserveru, použijte své Matrix ID (např. @user:domain.com) a heslo níže. Identifikátor uživatele To není platný identifikátor uživatele. Platný formát: \'@uživatel:homeserver.org\' Nemohu najít platný domovský server. Prosím, zkontrolujte svůj identifikátor @@ -2364,4 +2364,252 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Zadejte URL serveru identit Odeslat +Přehrát + Pozastavit + Zavrhnout + + + Nemáte povolení zahájit konferenční hovor v této místnosti + Konference již probíhá! + Zahájit video schůzku + Zahájit hlasovou schůzku + Schůzky používají pravidla zabezpečení a přístupu Jitsi. Všichni lidé nyní v místnosti uvidí pozvánku k připojení, zatímco Vaše schůzka probíhá. + Nemůžete spustit hovor se sebou + Nemůžete spustit hovor se sebou, počkejte, až účastníci přijmou pozvánku + Přidání widgetu se nezdařilo + Odstranění widgetu se nezdařilo + Přijmout + Odmítnout + Zavěsit + + Kopírovat + Podařilo se + + Oznámení + Volání Elementu se nezdařilo + Založit spojení v reálném čase se nezdařilo. +\nProsím, požádejte správce svého homeserveru o konfiguraci TURN serveru, aby volání fungovala spolehlivě. + + Vybrat zvukové zařízení + Telefon + Reproduktor + Headset + Bezdrátový headset + Přepnout fotoaparát + Přední + Zadní + Vypnout HD + Zapnout HD + + Toto telefonní číslo je již zadáno. + Chyba SSL: partnerova identita nebyla ověřena. + Chyba SSL. + Zamezit náhodnému hovoru + Žádat o potvrzení před zahájením hovoru + Aktivní hovory (%s) + Návrat k hovoru + + Zrušit pozvánku + Přejít na nižší úroveň\? + "Nebudete moci zvrátit tuto změnu, protože přejdete na nižší úroveň, jste-li poslední privilegovaný uživatel v místnosti, nebudete moci privilegia získat zpět." + Přejít na nižší úroveň + + + Ignorovat uživatele + Ignorování tohoto uživatele odstraní jejich zprávy ze sdílených místností. +\n +\nMůžete tuto akci kdykoli zvrátit v obecných nastaveních. + Odignorovat uživatele + Odignorování tohoto uživatele opět ukáže všechny jejich zprávy. + Zrušit pozvánku + Jste si jisti, že chcete zrušit pozvánku tomuto uživateli\? + Vykopnout uživatele + Důvod k vykopnutí + Vykopnutí uživatele je odstraní z této místnosti. +\n +\nAbyste mu zamezili opětovně vstoupit, měli byste jej zakázat. + Vykázat uživatele + Důvod k vykázání + Zrušit vykázání uživatele + Zrušení vykázání uživatele jim opět umožní vstoupit do místnosti. + + Žádné telefonní číslo nebylo zadáno do Vašeho účtu + Emailová adresa + Žádná emailová adresa nebyla zadána do Vašeho účtu + Telefonní čísla + Ostranit %s\? + Ujistěte se, že kliknete na odkaz v e-mailu, který jsme Vám poslali. + + Bezpečná záloha + Správa + Založit bezpečnou zálohu + Resetovat bezpečnou zálohu + Nastavit na tomto zařízení + Ochrana před ztrátou přístupu k šifrovaným zprávám & datům pomocí zálohy šifrovacích klíčů na Vašem serveru. + Generovat nový bezpečnostní klíč nebo nastavit nové bezpečnostní heslo pro existující zálohu. + To nahradí Váš nynější klíč nebo heslo. + + Integrace jsou vypnuty + Zapnout \'Povolit integrace\' v nastavení. + + Emailové adresy a telefonní čísla + Správa emailových adres a telefonních čísel spojených s Vaším účtem v Matrix + + + %d vykázaný uživatel + %d vykázaní uživatelé + %d vykázaných uživatelů + + + Klíče úspěšně exportovány + + + %1$d/%2$d klíč úspěšně importován. + %1$d/%2$d klíče úspěšně importovány. + %1$d/%2$d klíčů úspěšně importováno. + + + NÁHLED + Aktivní widgety + + + Správa integrací + Žádné aktivní widgety + Klíč pro obnovu byl uložen. + + Bezpečná záloha + Ochrana před ztrátou přístupu k šifrovaným zprávám & datům + + Nastavit bezpečnou zálohu + + Místnost byla založena, ale některé pozvánky nebyly odeslány z těchto důvodů: +\n +\n%s + + Sloučení nemohlo dešifrovat zprávy v časové ose + Přidat panel věnovaný nepřečteným oznámením na hlavní obrazovku. + + Kód + + %1$s, %2$s a %3$d další přečtena + %1$s, %2$s a %3$d další přečteny + %1$s, %2$s a %3$d dalších přečteno + + Přidat k oblíbeným + Odstranit z oblíbených + Neučinili jste žádné změny + Učinili jste místnost veřejnou komukoli, kdo zná odkaz. + Učinili jste místnost pouze pro pozvané. + Zadejte adresu serveru, jejž chcete použít + + Prosím, použijte mezinárodní formát (telefonní číslo musí začít \'+\') + Neznáte-li heslo, vraťte se zpět a resetujte je. + Nálepka + + Akce správce + Výchozí v %1$s + "Správce Vašeho serveru vypnul end-to-end šifrování jako výchozí v soukromých místnostech & přímých zprávách." + Zadejte bezpečnostní heslo, jež znáte pouze Vy, k zabezpečení tajností na Vašem serveru. + + Pokud nyní přerušíte, mohli byste přijít o šifrované zprávy & data, pokud ztratíte přístup k Vašemu účtu. +\n +\nMůžete nastavit bezpečnou zálohu & správu klíčů též v nastaveních. + + Založili a nastavili jste místnost. + + Tento účet byl deaktivován. + + Zapnout křížový podpis + Uložit mediální soubor se nezdařilo + Potvrďte svou identitu ověřením tohoto přihlášení, udělujíce přístup k šifrovaným zprávám. + Je nám líto, tato operace zatím není možná s účty připojenými pomocí Single Sign-On. + + Nastavit roli + Role + Otevřít chat + Umlčet mikrofon + Zrušit umlčení mikrofonu + Zastavit fotoaparát + Spustit fotoaparát + + Nastavit bezpečnou zálohu + + Bezpečná záloha + Ochrana před ztrátou přístupu k šifrovaným zprávám & datům pomocí zálohy šifrovacích klíčů na Vašem serveru. + Nastavit + Použít bezpečnostní klíč + Generovat bezpečnostní klíč k uložení na bezpečném místě např. správci hesel nebo sejfu. + Použít bezpečnostní heslo + Zadejte bezpečnostní heslo známé pouze Vám a generujte klíč pro zálohy. + + Uložit bezpečnostní klíč + Uložte bezpečnostní klíč na bezpečném místě, např. správci hesel nebo sejfu. + + Nastavit bezpečnostní heslo + Zadejte bezpečnostní heslo známé pouze Vám pro zabezpečení tajností na svém serveru. + Bezpečnostní heslo + Zadejte své bezpečnostní heslo znovu pro potvrzení. + + Uložit bezpečnostní klíč + Uložte své bezpečnostní heslo na bezpečném místě, např. správci hesel nebo sejfu. + + Název místnosti + Téma + Úspěšně jste změnili nastavení místnosti + + Nemůžete číst tuto zprávu + Čekám na tuto zprávu, může to chvíli trvat + Nelze dešifrovat + Kvůli end-to-end šifrování se může stát, že budete muset počkat, než zpráva dorazí, protože šifrovací klíče Vám nebyly řádně zaslány. + Nemůžete číst tuto zprávu, protože odesílatel Vás blokuje + Nemůžete číst tuto zprávu, protože Vaše relace není pro odesílatele důvěryhodná + Nemůžete číst tuto zprávu, protože odesílatel účelově neposlal klíče + Čekám na historii šifrování + + Riot je nyní Element! + Jsme nadšení, že smíme oznámit změnu jména! Vaše app je aktuální a jste přihlášeni do svého účtu. + ROZUMÍM + DOZVĚDĚT SE VÍC + + element + + + Uložit klíče pro obnovu v + + Přidat z mého adresáře + Váš adresář je prázdný + Adresář + Hledat v mých kontaktech + Načítám Vaše kontakty… + Váš seznam kontaktů je prázdný + Seznam kontaktů + + Pozvánku vzít zpět + Vzít zpět pozvánku pro %1$s\? + + Vykázán od %1$s + Nezdařilo se povolit uživatele + + Push oznámení jsou vypnuta + Projděte svá nastavení, abyste zapnuli push oznámení + + "Nesprávný kód, zbývá %d pokus" + "Nesprávný kód, zbývají %d pokusy" + "Nesprávný kód, zbývá %d pokusů" + + Varování! Zbývá poslední pokus před odhlášením! + Příliš mnoho chyb, byli jste odhlášeni + Zvolte PIN pro zabezpečení + Potvrdit PIN + Nezdařilo se prověřit PIN, prosím, zadejte nový. + Zadejte svůj PIN + Zapomněli jste PIN\? + Resetovat PIN + Nový PIN + Pro resetování svého PINu se budete muset nově přihlásit a založit nový. + Zapnout PIN + Chcete-li resetovat svůj PIN, klepněte na Zapomenutý PIN pro odhlášení a resetování. + Pro vypnutí PINu potvrďte PIN + Nemohu otevřít místnost, z níž jste byli vykázáni. + Nemohu najít tuto místnost. Ujistěte se, že existuje. From 2e88275766a5ede95d5f53c90d67709d72e48fec Mon Sep 17 00:00:00 2001 From: random Date: Sat, 12 Sep 2020 09:50:58 +0000 Subject: [PATCH 64/89] Translated using Weblate (Italian) Currently translated at 100.0% (1867 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/it/ --- vector/src/main/res/values-it/strings.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/vector/src/main/res/values-it/strings.xml b/vector/src/main/res/values-it/strings.xml index 9667dbf89c..b9c357a0ef 100644 --- a/vector/src/main/res/values-it/strings.xml +++ b/vector/src/main/res/values-it/strings.xml @@ -2654,4 +2654,22 @@ Attenzione! Ultimo tentativo rimasto prima di venire disconnesso! Troppi errori, sei stato disconnesso +Questo numero di telefono è già definito. + Nessun numero di telefono aggiunto al tuo account + Indirizzi email + Nessuna email aggiunta al tuo account + Numeri di telefono + Rimuovere %s\? + Assicurati di avere cliccato il link nell\'email che ti abbiamo inviato. + + Email e numeri di telefono + Gestisci le email e i numeri di telefono collegati al tuo account Matrix + + Codice + Si prega di usare il formato internazionale (il numero deve iniziare con \'+\') + Conferma la tua identità verificando questo accesso, dandogli l\'accesso ai messaggi cifrati. + Spiacente, questa operazione non è ancora possibile per gli account connessi tramite Single Sign-On. + + Impossibile aprire una stanza dove sei stato bandito. + Impossibile trovare questa stanza. Assicurati che esista. From a246993df3c17906272b25d6a3693bd702cefbcb Mon Sep 17 00:00:00 2001 From: ziriSut Date: Sat, 12 Sep 2020 22:39:56 +0000 Subject: [PATCH 65/89] Translated using Weblate (Kabyle) Currently translated at 100.0% (1867 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/kab/ --- vector/src/main/res/values-kab/strings.xml | 65 +++++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index e2ef8c4254..0b6e91e972 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -2445,7 +2445,7 @@ Akka tura ulac akk assaɣ d unekcam-a. Aqeddac-ik·im agejdan (%1$s) yefka-d takti n useqdec n %2$s d aqeddac-ik·im n timagit - tzemreḍ ad teskecmeḍ URl n uqeddac n timagit i tebɣiḍn + Neɣ ma ulac, tzemreḍ ad teskecmeḍ URl n uqeddac n timagit i tebɣiḍn Sekcem URL i uqeddac n timagit Sekcem tafyirt n tɣellist ara tissineḍ kan kečč·kemm, syen sirew tasarut i uḥraz. @@ -2462,7 +2462,7 @@ %s yettaɛraḍ ad d-isali tazmilt tufrint deg tesnakudt n texxamt-a, maca ur yessaweḍ ara ad tt-naf. Neɣ; dmen aḥrazen-inek·inem s tefyirt tuffirt n uɛeddi, yettwaskelsen deg wadeg aɣelsan. - Tiririt n lqem n uḥraz... + Tiririt n lqem n uḥraz… Rnu iccer ara yettunefken i yilɣa ur nettwaɣra ara deg ugdil agejdan. Rmed iɣmisen ɣezzifen. @@ -2481,4 +2481,65 @@ Ahuzzu n ufḍam Talast n tifin Huzz tiliɣri-inek·inem i wakken ad teskeydeḍ talast n tifin + Asenker n tuqqna deg wakud ilaw ur yeddi ara. +\nMa ulac aɣilif suter deg unebdal n uqeddac-iim agejdan ad yeswel aqeddac TURN i wakken ad qeɛden isawalen. + + Ma yella anedbal n uqeddac yenna-d belli aya yettuau, ẓer ma yella adsil umḍin ddaw yemṣada d udsil umḍin i d-mudden nutni. + Aselken yettubeddel deg ubdil n win yettwamanen deg tiliɣri-inek·inem. Aya MAČČI D AYEN IGERRZEN. Issefk UR TETTAQBALEḌ ARA aselkin-a amaynut. + Aselkin yettwabeddel seg win yettwamanen ɣer win ur nettwaman ara. Ahat aqeddac iɛawed-d aselkin-ines. Nermes anedbal n uqeddac ɣef udsil umḍin yetturaǧun. + Ur qebbel ara aselkin alamma isuffeɣ-d unedbal n uqeddac adsil umḍin yemṣadan d win yellan ddaw-a. + + [%1$s] +\nTuccḍa yekka nnig tezmert n Element, akken i d-yenna Google, tuccḍa-a teskan-d belli ibenk ɣer-s aqettun n yisnasen yettwaskelsen s FCM. Tuccḍa ur d-tettili ara ala ma yilin umiḍan n yisnasen aṭas, ɣef waya ur ilaq ara ad tḥaz aseqdac n tlemmast. + [%1$s] +\nTuccḍa-a tekka nnig tezmert n Element. Aya yezmer ad d-yili seg waṭas n ssebbat. Ahat ad yeddu ma yella tɛerḍeḍ tikkelt-nniḍen ticki, daɣen tzemreḍ ad tesneqdeḍ ma yella ameẓlu Google Play ur yesɛi ara talast deg useqdec n yisefka deg yiɣewwaren n unagraw, neɣ tamrilt n yibenk-inek·inem tṣeḥḥa, neɣ yezmer ad d-yili waya ɣef Rom tudmawant. + [%1$s] +\nTuccḍ-a tekka nnig tezmert n Element. Ulac amiḍan Google ɣe tiliɣri. Ma ulac aɣilif, ldi amsefrak n umiḍan syen rnu amiḍan n Google. + Ma yella aseqdac yeǧǧa ibenk ur t-isfurek ara rnu i kra n wakud, s ugdil yensan, ibenk ad yekcem deg uskar Doze. Aya ur yettaǧǧa ara isnasen ad kecmen ɣer uzeṭṭa i wakken ad aznen imahilen, amtawi d tesluɣin tiluganin nsen. + Element ad yemtawi ɣef ugilal sya ɣer da deg yiwen n wakud (yettuswal). +\nAya ad iḥaz aseqdec n ṛṛadyu d uẓru, ad yili wulɣu ad d-yettwaskanen i lebda i d-yemmalen belli Element yettɛassa ineḍruyen. + Seqdec amsefrak n yimsidaf i usefrek n yibuḍen, n tleggiyin, n yiwiǧiten d yikemmusen n ustiker. +\nImsefrak n yimsidaf temmsen-d isefka n twila, syen zemren ad snilen iwiǧiten, ad aznen tinubgiwin ɣer teamin yerna ad sbadun iswiren n tezmert s yisem-ik·im. + Msel iznan s useqdec n tseddast n markdown send ad ttwaznen. Aya ad isireg amsal leqqayen am useqdec n yizamulen n yitran i uskan n uḍris uknan. + Taqeffalt Kcem n unasiw n useɣzan ad tazen izen ideg ara teg angaz gar yizirigen + + Element yezmer ad yeddu deg ugilal i usefrek n yilɣa-inek·inem s wudem aɣelsan, uslig. Aya yezmer ad iḥaz aseqdec n uẓru. + Element yesra ad yeǧǧ tuqqna s usemdu meẓẓiyen ɣef ugilal i wakken ad d-yawi ilɣa yettwamanen. +\nƔef ugdil i d-iteddun, ad tettusnubegteḍ i wakken ad tmuddeḍ tisirag i Element ad yeddu i lebda ɣef ugilal, ttxil-k·m qbel. + Askar n usekles n yisefka yessemras imsizdeg afrayan i wakken ileqman n tihawt d yilɣa n tira ad ttwasizedgen. + + Tigi d timahilin tarmitanin i izemren ad rẓent s wayen ur nettwaṛǧa ara. Seqdec-itent maca ɣur-k·m. + Aya ad yerr amiḍan-ik·im ur yettusexdam ara i lebda. Ur tettizmireḍ ara ad tkecmeḍ, ula d amdan-nniḍen ur yettizmir ara ad yales ajerred s usulay-a n useqdac. Aya ad isuffeɣ amiḍan-ik·im seg meṛṛa tixxamin ideg ittekka, yerna ad yekkes akk talqayt n umiḍan-ik·im seg uqeddac n timagit. Ulac tuɣalin ɣer deffir deg tigawt-a. +\n +\nAsensi n umiḍăn-ik·im ur aɣ-yettarra ara s wudem amezwer ad nettu iznan i tuzneḍ. Ma yella tebɣiḍ ad ttwattun yiznaninek·inem, sit ɣef tbewwaḍt i yellan ddaw. +\n +\nAbani n yiznan deg Matrix am tin n yimaylen. Tatut-nneɣ n yiznan-inek·inem anamek-is, iznan i tuzneḍ ur ttwabḍun ara ula d yiwen n useqdac amaynut neɣ ur nettwasekles ara, maca iseqdacen yettwaskelsen i yesɛan anekcum ɣer yiznan-a mazal ad sɛun anekcum ɣer unɣal-nsen. + Asnerni n temlellit s usali n yiɛeggalen n texxamt kan lawan tmeẓriwt tamezwarut. + Aqeddac-ik·im agejdan ur yessefrak ara asali ẓẓayen n yiɛegggalen n texxamt akka tura. Ɛreḍ ticki. + + Ad nekles anɣal yettwawgelhen n tsura-inek·inem ɣef uqeddac-ik·im agejdan. Mmesten aḥraz-inek·inem s tefyirt tuffirt i wakken ad yeqqim d aɣelsan. +\n +\nI tɣellist tafellayt, ilaq ad yemgarad ɣef wawal ufiir n umiḍan-ik·im. + I tɣellidt tafellayt, yessefk ad tgeḍ aya s timmad-ik·im neɣ seqdec ttawil-nniḍen n teywalt yettwamanen. + Senqed tiɣimit-a i wakken ad tcerḍeḍ fell-as tettwaḍman. Attkal ɣef tɣimiyin n yimendiden yettakk-ak·am-d lehna n uqerru mi ara tesseqdaceḍ iznan yettwawgelhen seg yixef ɣer yixef. + Tiɣimit ur tessaweḍ ara ad teqbel amtawi n tsarut, agbar, MAC neɣ tarrayt SAS + Af-d iznan ur nettwaɣra ara da + Taskant n texxamt ara yettwaɣran deg umaḍal ur tettusefrak ara ar tura deg Element + + Ulac tinezgarin push ikelsen + + Tuzna n tenfult (%1$s / %2$s) + Rmed afraḍ i tririt deg tesnakudt + Asdukkel ur yeddi ara i tukksa n uwgelhen n yiznan deg tesnakudt + Aqeddac n timagit i tferneḍ ulac ɣer-s akk tiwtilin n yimeẓla. Ur ttkemmil ara ala ma yella tettekleḍ ɣef umeẓlu + Iɣmisen ɣezzifen ad ɛawnen ineflayen s umuddu n wugar n yiɣemisen mi ara tazneḍ aneqqis RageShake, ula ma yili yermed asnas ur yettazen ara agbur n yiznan neɣ isefka-nniḍen usligen. + + + Akka d-yettban aqeddac yettaṭṭaf aṭas n wakud ɣef tririt. Yezmer aya yekka-d seg yir tuqqna neɣ seg tuccḍa deg uqeddac. Ma ulac aɣilif ɛreḍ tikkelt-nniḍen ticki. + + Tiɣimit-a tamirant n useqdac %1$s ma d kečč·kemm ad tesnetmeḍ inekcam i useqdac %2$s. Aya ur t-yessefrak ara Element. +\nMa ulac aɣilif, deg tazwara sfeḍ isefka, syen kcem tikkelt-nniḍen s umiḍan-nniḍen. + + Askar n uneflay yermed timahilin i yeffren yerna yezmer daɣen ad yerr asnas ur yerkid ara akken iwata. I yineflayen kan! + Abrir arurad From 86603ed1a60105218b82ce849128bad5eebf9bc0 Mon Sep 17 00:00:00 2001 From: AnonymousWebHacker Date: Sat, 12 Sep 2020 16:12:23 +0000 Subject: [PATCH 66/89] Translated using Weblate (Spanish) Currently translated at 100.0% (1867 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/es/ --- vector/src/main/res/values-es/strings.xml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/vector/src/main/res/values-es/strings.xml b/vector/src/main/res/values-es/strings.xml index d3128f9e54..fc74e45c3e 100644 --- a/vector/src/main/res/values-es/strings.xml +++ b/vector/src/main/res/values-es/strings.xml @@ -1626,7 +1626,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Reacciones rápidas - General + Cuenta Experto Reglas Push No hay reglas push definidas @@ -1924,7 +1924,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu No puedes hacer una llamada contigo mismo, espera a que los participantes acepten la invitación Fallo al adicionar Widget Fallo al eliminar Widget - Prevenir llamadas por accidente + Confirmar llamada Pedir confirmacion antes de iniciar una llamda Rason de expulsion Banear usuario @@ -2129,4 +2129,17 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Para resetear su PIN, debe iniciar seccion y crear uno nuevo Establecer PIN Si decea resetear su PIN, toque Olvidé PIN para cerrar sesión y restablecer. - +Numeros telefonicos + Correos y numeros telefonicos + Administre el correo y numero telefonico de su cuenta + + Mostrar mensages eliminados + Indicar marca de mensaje eliminado + ARCHIVOS + No se han subido archivos a la sala + + Establecer notificaciones por eventos + + Establecer una nueva contraseña… + + From 6e1fc4d84eb570a2c72522f9725d293008109370 Mon Sep 17 00:00:00 2001 From: discapacidad5 Date: Sun, 13 Sep 2020 17:11:19 +0000 Subject: [PATCH 67/89] Translated using Weblate (Spanish) Currently translated at 100.0% (1867 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/es/ --- vector/src/main/res/values-es/strings.xml | 550 +++++++++++++++++++++- 1 file changed, 535 insertions(+), 15 deletions(-) diff --git a/vector/src/main/res/values-es/strings.xml b/vector/src/main/res/values-es/strings.xml index fc74e45c3e..4b965bf214 100644 --- a/vector/src/main/res/values-es/strings.xml +++ b/vector/src/main/res/values-es/strings.xml @@ -249,13 +249,13 @@ Puedes añadir tu correo electrónico a tu perfil en ajustes. Por favor permite el acceso en la próxima ventana emergente para poder enviar archivos desde tu teléfono. Element necesita permiso para acceder a tu cámara para tomar fotos y realizar llamadas de vídeo. - - -Por favor permite el acceso en la próxima ventana emergente para poder realizar la llamada. + " +\n +\nPor favor permite el acceso en la próxima ventana emergente para poder realizar la llamada." Element necesita permiso para acceder a tu micrófono para realizar llamadas de voz. - - -Por favor permite el acceso en la próxima ventana emergente para poder realizar la llamada. + " +\n +\nPor favor permite el acceso en la próxima ventana emergente para poder realizar la llamada." Element necesita permiso para acceder a tu cámara y micrófono para realizar llamadas de vídeo. Por favor permite el acceso en las próximas ventanas emergentes para poder realizar la llamada. @@ -618,7 +618,7 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Información de la sesión emisora Nombre público Nombre público - ID + ID de sesión Clave de sesión Verificación Huella digital Ed25519 @@ -781,7 +781,7 @@ Advertencia: este archivo puede ser eliminado si la aplicación se desinstala.Lista de Grupos - ¿Seguro que quieres vetar a este usuario de esta conversación? + El usuario baneado lo echará de esta sala y evitará que se unan nuevamente. Todos los mensajes (ruidoso) Todos los mensajes @@ -1557,7 +1557,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Por favor, pídele al administrador de tu servidor doméstico (%1$s) que configure un servidor TURN para que las llamadas funcionen de forma fiable. \n \nAlternativamente, puedes intentar usar el servidor público en %2$s, pero no será tan confiable, y compartirá tu dirección IP con ese servidor. También puedes cambiar esto en Configuración. - Configura un correo electrónico para la recuperación de la cuenta, y opcionalmente para encontrar personas conocidas + Configura un correo electrónico para la recuperación de la cuenta, y opcionalmente para encontrar personas conocidas. Configura un correo electrónico para la recuperación de la cuenta. Usa el correo electrónico o el teléfono más tarde para ser descubierto opcionalmente por personas que te conozcan. Configura un correo electrónico para la recuperación de la cuenta. Usa el correo electrónico o el teléfono más tarde para ser descubierto opcionalmente por personas que te conozcan. Esta no es una dirección de servidor Matrix válida @@ -1785,7 +1785,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu No hay conexión de red - Bloquear usuario + Ignorar usuario Todos los mensajes (sonido) Todos los mensajes @@ -1795,7 +1795,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Abandonar sala %1$s no ha hecho ningún cambio Envía el mensaje como spoiler - Spoiler + Revelación Escribe las palabras clave para encontrar una reacción. No hay usuarios ignorados @@ -1807,7 +1807,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu %1$s: Ahora la sala solo es accesible por invitación. Mensajes no leídos - Libera tu comunicación + Es tu conversación. Me pertenece. Envía mensajes a personas o grupos Mantén las conversaciones privadas con encriptación Extiende y personaliza tu experiencia @@ -1899,7 +1899,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Idioma actual Otros idiomas disponibles - Cargando lenguajes disponibles + Cargando lenguajes disponibles… Leer los terminos de %s Desconectarse del servidor de Identidad %s\? @@ -2126,7 +2126,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Confirmar PIN Resetear PIN Nuevo PIN - Para resetear su PIN, debe iniciar seccion y crear uno nuevo + Para resetear su PIN, debe iniciar sección y crear uno nuevo. Establecer PIN Si decea resetear su PIN, toque Olvidé PIN para cerrar sesión y restablecer. Numeros telefonicos @@ -2142,4 +2142,524 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Establecer una nueva contraseña… - + Las reuniones utilizan políticas de seguridad y permisos de Jitsi. Todas las personas que se encuentren actualmente en la sala verán una invitación para unirse mientras se lleva a cabo la reunión. + Aceptar + Declinar + Colgar + + Este número de teléfono ya está definido. + ¿Degradarte\? + No podrá deshacer este cambio ya que se está degradando, si es el último usuario privilegiado en la sala, será imposible recuperar los privilegios. + Degradar + + + Si ignora a este usuario, se eliminarán sus mensajes de las salas que comparte. +\n +\n Puede revertir esta acción en cualquier momento en la configuración general. + Dejar de ignorar al usuario + Si ignora a este usuario, se mostrarán todos sus mensajes nuevamente. + ¿Estás seguro de que deseas cancelar la invitación de este usuario\? + Patear usuario + patear al usuario los eliminará de esta sala. +\n +\nPara evitar que vuelvan a unirse, debes prohibirlos. + No se ha agregado ningún número de teléfono a su cuenta + Correos electrónicos + No se ha agregado ningún correo electrónico a su cuenta + ¿Elimina %s\? + Asegúrese de haber hecho clic en el enlace del correo electrónico que le enviamos. + + Copia de seguridad segura + Gestionar + Configurar copia de seguridad segura + Restablecer copia de seguridad segura + Configurar en este dispositivo + Protéjase contra la pérdida de acceso a los mensajes y datos cifrados haciendo una copia de seguridad de las claves de cifrado en su servidor. + Genere una nueva llave de seguridad o establezca una nueva frase de seguridad para su copia de seguridad existente. + Esto reemplazará su clave o frase actual. + + Las integraciones están deshabilitadas + Habilite \'Permitir integraciones\' en Configuración para hacer esto. + + + %d usuario prohibido + %d usuarios prohibidos + + + Claves exportadas correctamente + + + %1$d/%2$d clave importada con éxito. + %1$d/%2$d claves importadas con éxito. + + + %1$s: %2$s + %1$s: %2$s %3$s + + VER + Widgets activos + + + Gestionar integraciones + Sin widgets activos + La clave de recuperación se ha guardada. + + Copia de seguridad segura + Protéjase contra la pérdida de acceso a mensajes y datos cifrados + + Configurar copia de seguridad segura + + Mensaje borrado + Se ha creado la sala, pero algunas invitaciones no se han enviado por el siguiente motivo: +\n +\n%s + + Le enviamos un correo electrónico de confirmación %s, primero revise su correo electrónico y haga clic en el enlace de confirmación + Código + El código de verificación no es correcto. + + + %1$s, %2$s y %3$d otra lectura + %1$s, %2$s y %3$d otras lecturas + + MEDIO + No hay medios en esta sala + %1$s a %2$s + Agregar a los favoritos + Quitar de favoritos + No hiciste cambios + Hiciste que la sala fuera pública para quien conozca el enlace. + Hiciste la sala solo por invitación. + Únase a millones gratis en el servidor público más grande + Continuar con SSO + + Dirección de servicios de Element Matrix + Ingrese la dirección del servidor que desea utilizar + + Se enviará un correo electrónico de verificación a su bandeja de entrada para confirmar la configuración de su nueva contraseña. + Próximo + Email + Nueva contraseña + + ¡Advertencia! + Cambiar su contraseña restablecerá cualquier clave de cifrado de extremo a extremo en todas sus sesiones, haciendo ilegible el historial de chat cifrado. Configure Key Backup o exporte las llaves de su sala desde otra sesión antes de restablecer su contraseña. + Seguir + + Este correo electrónico no está vinculado a ninguna cuenta + + Revisa tu correo + Se envió un correo electrónico de verificación a %1$s. + Toque el enlace para confirmar su nueva contraseña. Una vez que haya seguido el enlace que contiene, haga clic a continuación. + He verificado mi dirección de correo electrónico + + ¡Éxito! + Tu contraseña ha sido restablecida. + Ha cerrado sesión en todas las sesiones y ya no recibirá notificaciones automáticas. Para volver a habilitar las notificaciones, inicie sesión nuevamente en cada dispositivo. + Volver a Iniciar sesión + + Advertencia + u contraseña aún no ha cambiado. +\n +\n¿Detener el proceso de cambio de contraseña\? + + Establecer dirección de correo electrónico + Configure un correo electrónico para recuperar su cuenta. Más tarde, opcionalmente, puede permitir que las personas que conoce lo descubran mediante su correo electrónico. + Correo electrónico + Email (opcional) + Próximo + + Establecer número de teléfono + Configure un número de teléfono para permitir que las personas que conoce lo descubran opcionalmente. + Utilice el formato internacional. + Número de teléfono + Numero de teléfono (opcional) + Próximo + + Confirmar número de teléfono + Acabamos de mandar un codigo a %1$s. Ingréselo a continuación para verificar que es usted. + Introduzca el código + Enviar de nuevo + Próximo + + Utilice el formato internacional (el número de teléfono debe comenzar con \'+\') + Los números de teléfono internacionales deben comenzar con \'+\' + El número de teléfono parece no válido. Compruébelo por favor + + Inscribirse a %1$s + Nombre de usuario o correo electrónico + Nombre de usuario + Contraseña + Próximo + Ese nombre de usuario está siendo usado + Advertencia + Tu cuenta aún no está creada. +\n +\n ¿Detener el proceso de registro\? + + Seleccione matrix.org + Seleccionar servicios de matriz de elementos + Seleccione un servidor doméstico personalizado + Realiza el desafío de captcha + Acepta los términos para continuar + + Por favor revise su correo electrónico + Acabamos de enviar un correo electrónico a %1$s. +\nHaga clic en el enlace que contiene para continuar con la creación de la cuenta. + El código introducido no es correcto. Por favor, compruebe. + Servidor doméstico obsoleto + Este servidor doméstico está ejecutando una versión demasiado antigua para conectarse. Pídale al administrador de su servidor doméstico que actualice. + + + Se han enviado demasiadas solicitudes. Puedes volver a intentarlo en %1$d segundo… + Se han enviado demasiadas solicitudes. Puedes volver a intentarlo en %1$d segundos… + + + Alternativamente, si ya tiene una cuenta y conoce su identificador Matrix y su contraseña, puede usar este método: + Iniciar sesión con Matrix ID + Iniciar sesión con Matrix ID + Si configura una cuenta en un servidor doméstico, use su ID de Matrix (por ejemplo, @user: dominio.com) y contraseña a continuación. + ID de Matrix + Si no conoce su contraseña, vuelva a restablecerla. + "Este no es un identificador de usuario válido. Formato esperado: \'@user:homeserver.org\'" + No se pudo encontrar un servidor de inicio válido. Por favor verifique su identificador + + Visto por + + Estás desconectado + Puede deberse a varias razones: +\n +\n• Has cambiado tu contraseña en otra sesión. +\n +\n• Ha eliminado esta sesión de otra sesión. +\n +\n• El administrador de su servidor ha invalidado su acceso por motivos de seguridad. + Iniciar sesión de nuevo + + Estás desconectado + Registrarse + "El administrador de su servidor doméstico (%1$s) ha cerrado la sesión de su cuenta %2$s (%3$s)." + Inicie sesión para recuperar las claves de cifrado almacenadas exclusivamente en este dispositivo. Los necesita para leer todos sus mensajes seguros en cualquier dispositivo. + Registrarse + Contraseña + Borrar datos personales + Advertencia: sus datos personales (incluidas las claves de cifrado) todavía se almacenan en este dispositivo. +\n +\nBórrelo si terminó de usar este dispositivo o si desea iniciar sesión en otra cuenta. + Borrar todos los datos + + Borrar datos + ¿Borrar todos los datos almacenados actualmente en este dispositivo\? +\nVuelva a iniciar sesión para acceder a los datos y mensajes de su cuenta. + Perderás el acceso a los mensajes seguros a menos que inicies sesión para recuperar tus claves de cifrado. + Borrar datos + La sesión actual es para el usuario %1$s y usted proporciona las credenciales para el usuario %2$s. Esto no es compatible con Element. Primero borre los datos, luego inicie sesión nuevamente con otra cuenta. + + Su enlace matrix.to estaba mal formado + El modo desarrollador activa funciones ocultas y también puede hacer que la aplicación sea menos estable. ¡Solo para desarrolladores! + Uno de los siguientes puede verse comprometido: +\n- Tu servidor doméstico +\n- El servidor doméstico al que está conectado el usuario que estás verificando +\n- La suya o la conexión a Internet de otros usuarios +\n- El suyo o el dispositivo de otros usuarios + + Para mayor seguridad, verifique %s verificando un código único en ambos dispositivos. +\n +\nPara máxima seguridad, hágalo en persona. + Los mensajes de esta sala están cifrados de extremo a extremo. +\n +\nSus mensajes están protegidos con candados y solo usted y el destinatario tienen las claves únicas para desbloquearlos. + Esta sesión no puede compartir esta verificación con sus otras sesiones. +\nLa verificación se guardará localmente y se compartirá en una versión futura de la aplicación. + + Envía el emote dado coloreado como un arcoíris + + Una vez habilitado, el cifrado de una sala no se puede deshabilitar. Los mensajes enviados en una sala cifrada no pueden ser vistos por el servidor, solo por los participantes de la sala. Habilitar el cifrado puede evitar que muchos bots y puentes funcionen correctamente. + Para estar seguro, verifique %s comprobando un código de un solo uso. + Para estar seguro, hágalo en persona o use otra forma de comunicarse. + + Compare los emoji únicos, asegurándose de que aparezcan en el mismo orden. + Compare el código con el que se muestra en la pantalla del otro usuario. + Los mensajes con este usuario están encriptados de extremo a extremo y no pueden ser leídos por terceros. + Su nueva sesión ahora está verificada. Tiene acceso a sus mensajes cifrados y otros usuarios lo verán como de confianza. + + La firma cruzada está habilitada +\n Claves privadas en el dispositivo. + La firma cruzada está habilitada +\nLas llaves son de confianza. +\nNo se conocen las claves privadas + La firma cruzada está habilitada. +\nLas claves no son de confianza + El administrador de su servidor ha desactivado el cifrado de extremo a extremo de forma predeterminada en salas privadas y mensajes directos. + No hay información criptográfica disponible + + Esta sesión es confiable para mensajería segura porque usted la verificó: + Verifique esta sesión para marcarla como confiable y otorgarle acceso a mensajes encriptados. Si no inició sesión en esta sesión, su cuenta puede verse comprometida: + + + %d sesión activa + %d sesiones activas + + + Utilice una sesión existente para verificar esta, otorgándole acceso a los mensajes cifrados. + + + "Esta sesión es confiable para mensajería segura porque %1$s (%2$s) la verificó:" + %1$s (%2$s) iniciado sesión con una nueva sesión: + Hasta que este usuario confíe en esta sesión, los mensajes enviados hacia y desde ella se etiquetan con advertencias. Alternativamente, puede verificarlo manualmente. + + + ¡Casi ahí! ¿Es %s muestra el mismo escudo\? + + %d voto + %d votos + + + %d voto - Resultados finales + %d votos - Resultados finales + + Crea una encuesta simple + Use una contraseña o clave de recuperación + Si no puede acceder a una sesión existente + + No puedo encontrar secretos almacenados + Ingrese la contraseña de almacenamiento secreta + Solo debe acceder al almacenamiento secreto desde un dispositivo confiable + + ¿Quieres enviar este adjunto a %1$s\? + + Enviar imagen con el tamaño original + Envía imágenes con el tamaño original + + + Confirmar eliminación + ¿Está seguro de que desea eliminar (eliminar) este evento\? Tenga en cuenta que si elimina el nombre de una sala o el cambio de tema, podría deshacer el cambio. + Evento eliminado por el usuario, motivo: %1$s + Evento moderado por el administrador de la sala, motivo: %1$s + + Solicitudes clave + + Desbloquear el historial de mensajes cifrados + + Utilice esta sesión para verificar su nuevo, otorgándole acceso a mensajes encriptados. + Si cancela, no podrá leer mensajes encriptados en este dispositivo y otros usuarios no confiarán en él + Si cancela, no podrá leer mensajes encriptados en su nuevo dispositivo y otros usuarios no confiarán en él + No verificarás %1$s (%2$s) si cancelas ahora. Comience de nuevo en su perfil de usuario. + + Uno de los siguientes puede verse comprometido: +\n +\n- Tu contraseña +\n- Tu servidor doméstico +\n- Este dispositivo o el otro dispositivo +\n- La conexión a Internet que está usando cualquiera de los dispositivos +\n +\nLe recomendamos que cambie su contraseña y clave de recuperación en Configuración de inmediato. + + Verifique sus dispositivos desde Configuración. + Establecer un %s + Generar una clave de mensaje + + Confirmar %s + + "Ingrese su %s para continuar." + + Proteja y desbloquee los mensajes cifrados y confíe en %s. + Ingrese su %s nuevamente para confirmarlo. + No use la contraseña de su cuenta. + + Ingrese una frase de seguridad que solo usted conozca, que se usa para proteger secretos en su servidor. + + Esto puede tardar varios segundos, tenga paciencia. + Configurando la recuperación. + Tu clave de recuperación + Manténlo seguro + Terminar + + Utilice este %1$s como red de seguridad en caso de que olvide su %2$s. + + Publicar claves de identidad creadas + Generando clave segura a partir de frase de contraseña + Definición de la clave predeterminada de SSSS + Sincronización de la llave maestra + Sincronización de la clave de usuario + Sincronización de la clave de autofirma + Configuración de copia de seguridad de claves + + + Tus %2$s y %1$s ahora están configurados. +\n +\n¡Mantenlos a salvo! Los necesitará para desbloquear mensajes cifrados y proteger la información si pierde todas sus sesiones activas. + + Imprímelo y guárdalo en un lugar seguro + Guárdelo en una llave USB o unidad de respaldo + Cópielo en su almacenamiento personal en la nube + + No puedes hacer eso desde el móvil + + Establecer una frase de contraseña de recuperación le permite proteger y desbloquear mensajes cifrados y de confianza. +\n +\nSi no desea establecer una contraseña de mensaje, genere una clave de mensaje. + Establecer una frase de contraseña de recuperación le permite proteger y desbloquear mensajes cifrados y de confianza. + Si cancela ahora, puede perder mensajes y datos cifrados si pierde el acceso a sus inicios de sesión. +\n +\nTambién puede configurar la Copia de seguridad segura y administrar sus claves en Configuración. + + Los mensajes de esta sala están cifrados de extremo a extremo. Obtenga más información y verifique a los usuarios en su perfil. + Cifrado no habilitado + El cifrado utilizado por esta sala no es compatible + + %s creado y configurado la sala. + ¡Casi ahí! ¿El otro dispositivo muestra el mismo escudo\? + ¡Casi ahí! Esperando confirmación… + No se pudieron importar las claves + + Mensajes que contienen @room + Mensajes cifrados en chats uno a uno + Mensajes cifrados en chats grupales + Cuando las salas son actualizadas + Solucionar problemas + Envía un mensaje como texto estándar, sin interpretarlo como Markdown + + Nombre de usuario y / o contraseña incorrectos. La contraseña ingresada comienza o termina con espacios, verifíquela. + Esta cuenta ha sido desactivada. + + Mejora de encriptación disponible + Habilitar la firma cruzada + Verifíquese a usted mismo y a los demás para mantener sus chats seguros + + Entrar %s + Frase de contraseña de recuperación + No es una clave de recuperación válida + Por favor introduce una clave de recuperación + + Comprobando la clave de respaldo + Comprobando la clave de respaldo (%s) + Obteniendo clave de curva + Generando clave SSSS a partir de frase de contraseña + Generando clave SSSS a partir de frase de contraseña (%s) + Generando clave SSSS a partir de clave de recuperación + Almacenar el secreto de la copia de seguridad de claves en SSSS + %1$s (%2$s) + + Ingrese su Frase de contraseña de respaldo de clave para continuar. + use su clave de recuperación de Key Backup + No conoces tu frase de contraseña de copia de seguridad clave, puedes %s. + Clave de recuperación de copia de seguridad + + Evitar capturas de pantalla de la aplicación + Al habilitar esta configuración, se agrega FLAG_SECURE a todas las actividades. Reinicie la aplicación para que el cambio surta efecto. + + Archivo multimedia agregado a la Galería + No se pudo agregar el archivo multimedia a la Galería + Utilice la última versión de Element en sus otros dispositivos, Element Web, Element Desktop, Element iOS, Element para Android u otro cliente Matrix con capacidad de firma cruzada + Elemento Web +\nElemento de escritorio + Elemento iOS +\nElemento Android + u otro cliente Matrix con capacidad de firma cruzada + Utilice la última versión de Element en sus otros dispositivos: + Obliga a descartar la sesión de grupo saliente actual en una sala cifrada + Solo se admite en salas cifradas + Use su %1$s o use su %2$s para continuar. + Usar clave de recuperación + Seleccione su clave de recuperación o introdúzcala manualmente escribiéndola o pegándola desde su portapapeles + La copia de seguridad no se pudo descifrar con esta clave de recuperación: verifique que ingresó la clave de recuperación correcta. + No se pudo acceder al almacenamiento seguro + + Sin encriptar + Cifrado por un dispositivo no verificado + Revise dónde inició sesión + Verifique todas sus sesiones para asegurarse de que su cuenta y sus mensajes estén seguros + Verifique el nuevo inicio de sesión accediendo a su cuenta: %1$s + + Verificar manualmente por texto + Verificación interactiva por emoji + Confirme su identidad verificando este inicio de sesión de una de sus otras sesiones, otorgándole acceso a los mensajes cifrados. + Confirme su identidad verificando este inicio de sesión, otorgándole acceso a los mensajes cifrados. + Marcar como de confianza + + Lo sentimos, esta operación aún no es posible para las cuentas conectadas mediante el inicio de sesión único. + + No pudimos crear tu DM. Marque los usuarios que desea invitar y vuelva a intentarlo. + + Primero acepta los términos del servidor de identidad en la configuración. + Para su privacidad, Element solo admite el envío de números de teléfono y correos electrónicos de usuario con hash. + La asociación ha fallado. + No hay asociación actual con este identificador. + + Su servidor doméstico (%1$s) propone utilizar %2$s para su servidor de identidad + Utilizar %1$s + Alternativamente, puede ingresar cualquier otra URL del servidor de identidad + Ingrese la URL de un servidor de identidad + Enviar + Establecer rol + Rol + Conversación abierta + Silenciar el micrófono + Activar el sonido del micrófono + Detén la cámara + Enciende la cámara + + Configurar copia de seguridad segura + + Respaldo seguro + Protéjase contra la pérdida de acceso a los mensajes y datos cifrados haciendo una copia de seguridad de las claves de cifrado en su servidor. + Preparar + Usa una llave de seguridad + Genere una clave de seguridad para almacenar en un lugar seguro, como un administrador de contraseñas o una caja fuerte. + Utilice una frase de seguridad + Ingrese una frase secreta que solo usted conozca y genere una clave de respaldo. + + Guarde su llave de seguridad + Guarde su llave de seguridad en un lugar seguro, como un administrador de contraseñas o una caja fuerte. + + Establecer una frase de seguridad + Ingrese una frase de seguridad que solo usted conozca, que se usa para proteger secretos en su servidor. + Frase de seguridad + Ingrese su Frase de seguridad nuevamente para confirmarla. + + Guarde su llave de seguridad + Guarde su llave de seguridad en un lugar seguro, como un administrador de contraseñas o una caja fuerte. + + Nombre de la Sala + Tema + Cambiaste la configuración de la sala con éxito + + No puedes acceder a este mensaje + Esperando este mensaje, esto puede tardar un poco + No se puede descifrar + Debido al cifrado de extremo a extremo, es posible que deba esperar a que llegue el mensaje de alguien porque las claves de cifrado no se le enviaron correctamente. + No puede acceder a este mensaje porque ha sido bloqueado por el remitente + No puede acceder a este mensaje porque el remitente no confía en su sesión + No puede acceder a este mensaje porque el remitente no envió las claves a propósito + Esperando el historial de cifrado + + ¡Nos complace anunciar que hemos cambiado de nombre! Tu aplicación está actualizada y accediste a tu cuenta. + Guardar la clave de recuperación en + + Agregar desde mi directorio telefónico + Tu directorio telefónico está vacío + Directorio telefónico + Recuperando tus contactos… + Tu libro de contactos está vacío + Libro de contactos + + ¿Revocar la invitación a %1$s\? + + Prohibido por %1$s + No se pudo anular la prohibición del usuario + + Las notificaciones push están deshabilitadas + Revise su configuración para habilitar las notificaciones push + + Código incorrecto, %d intento restante + Código incorrecto, %d intentos restantes + + ¡Advertencia! ¡Último intento restante antes de cerrar sesión! + Demasiados errores, se ha desconectado + Elija un PIN por seguridad + No se pudo validar el PIN, toque uno nuevo. + Introduce tu PIN + ¿Olvidó su PIN\? + No se puede abrir una sala en la que está prohibido. + No puedo encontrar esta sala. Asegúrate de que exista. + From dd4391941e32e710d3430ec05599edc3e085bbb6 Mon Sep 17 00:00:00 2001 From: discapacidad5 Date: Sun, 13 Sep 2020 23:10:11 +0000 Subject: [PATCH 68/89] Translated using Weblate (Spanish) Currently translated at 100.0% (168 of 168 strings) Translation: Element Android/Element Android Sdk Translate-URL: https://translate.riot.im/projects/element-android/element-sdk/es/ --- .../src/main/res/values-es/strings.xml | 96 ++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/res/values-es/strings.xml b/matrix-sdk-android/src/main/res/values-es/strings.xml index ae1f5633bf..bf965a37f3 100644 --- a/matrix-sdk-android/src/main/res/values-es/strings.xml +++ b/matrix-sdk-android/src/main/res/values-es/strings.xml @@ -147,4 +147,98 @@ %s solicita verificar su clave, pero su cliente no soporta la verificación de la clave en chat. Necesitará usar la verificación de claves clásica para poder verificar las claves. - +Enviaste una imagen. + Enviaste un sticker. + + Tu invitación + %1$s creó la habitación + Tu creaste la habitación + Invitaste a %1$s + Te uniste a la Sala + Dejaste la Sala + Rechazaste la invitación + Tu pateaste a %1$s + Tu desbanaste a %1$s + Usted prohibió a %1$s + Retiró la invitación de %1$s\'s + Cambiaste tu avatar + Establece su nombre de visualización en %1$s + Cambiaste tu nombre para mostrar de %1$s a %2$s + Quitaste tu nombre para mostrar (era %1$s) + Cambiaste el tema a: %1$s + %1$s cambió el avatar de la sala + Cambiaste el avatar de la habitación + Cambiaste el nombre de la habitación a: %1$s + Hiciste una videollamada. + Hiciste una llamada de voz. + %s envió datos para configurar la llamada. + Enviaste datos para configurar la llamada. + Respondiste la llamada. + Terminaste la llamada. + Hiciste visible el futuro historial de la %1$s + Activó el cifrado de un extremo a otro (%1$s) + Has mejorado esta habitación. + + Solicitaste una conferencia de VoIP + Quitaste el nombre de la sala + Quitaste el tema de la sala + %1$s eliminó el avatar de la habitación + Quitaste el avatar de la habitación + Actualizaste tu perfil %1$s + Enviaste una invitación a %1$s para unirse a la sala + Revocaste la invitación para que %1$s se una a la sala + Aceptaste la invitación para %1$s + + %1$s agrego el widget %2$s + Agregaste el widget %1$s + %1$s eliminó el widget %2$s + Quitaste el widget %1$s + %1$s modifico el widget %2$s + Modificaste el widget %1$s + + Administrador + Moderador + Por defecto + Personalizado (%1$d) + Personalizado + + Cambiaste el nivel de potencia de %1$s. + %1$s cambió el nivel de potencia de %2$s. + %1$s de %2$s a %3$s + + Tu invitación. Razón: %1$s + "nvitaste a %1$s. Razón: %2$s" + Te uniste a la habitación. Razón: %1$s + Dejaste la habitación. Razón: %1$s + Rechazaste la invitación. Razón: %1$s + Pateaste a %1$s. Motivo: %2$s + Has desactivado a %1$s. Motivo: %2$s + Prohibiste a %1$s. Motivo: %2$s + Enviaste una invitación a %1$s para unirse a la sala. Motivo: %2$s + Revocaste la invitación para que %1$s se una a la sala. Motivo: %2$s + Aceptaste la invitación para %1$s. Motivo: %2$s + Retiró la invitación de %1$s\'s. Motivo: %2$s + + + Agregaste %1$s como dirección para esta sala. + Agregaste %1$s como direcciones para esta sala. + + + + Quitaste %1$s como dirección para esta sala. + Quitaste %2$s como direcciones para esta sala. + + + "%1$s agregó %2$s y eliminó %3$s como direcciones para esta sala." + Agregaste %1$s y quitaste %2$s como direcciones para esta sala. + + Estableciste la dirección principal de esta sala en %1$s. + Quitaste la dirección principal de esta sala. + + Ha permitido que los invitados se unan a la sala. + Ha impedido que los invitados se unan a la sala. + + Activó el cifrado de extremo a extremo. + Activó el cifrado de un extremo a otro (algoritmo %1$s no reconocido). + + From ebde029cce8267318f4ac7e47f4474f423e1fd48 Mon Sep 17 00:00:00 2001 From: discapacidad5 Date: Sun, 13 Sep 2020 23:49:31 +0000 Subject: [PATCH 69/89] Translated using Weblate (Spanish) Currently translated at 100.0% (3 of 3 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.riot.im/projects/element-android/element-store/es/ --- .../play/listings/es/full_description.txt | 30 +++++++++++++++++++ .../play/listings/es/short_description.txt | 1 + vector/src/main/play/listings/es/title.txt | 1 + 3 files changed, 32 insertions(+) create mode 100644 vector/src/main/play/listings/es/full_description.txt create mode 100644 vector/src/main/play/listings/es/short_description.txt create mode 100644 vector/src/main/play/listings/es/title.txt diff --git a/vector/src/main/play/listings/es/full_description.txt b/vector/src/main/play/listings/es/full_description.txt new file mode 100644 index 0000000000..860a1f19c3 --- /dev/null +++ b/vector/src/main/play/listings/es/full_description.txt @@ -0,0 +1,30 @@ +Element es un nuevo tipo de aplicación de mensajería y colaboración que: + +1. Le da el control para preservar su privacidad +2. Le permite comunicarse con cualquier persona en la red Matrix e incluso más allá al integrarse con aplicaciones como Slack. +3. Te protege de la publicidad, la minería de datos y los jardines vallados. +4. Lo protege a través del cifrado de un extremo a otro, con firma cruzada para verificar a otros + +Element es completamente diferente de otras aplicaciones de mensajería y colaboración porque es descentralizado y de código abierto. + +Element le permite autohospedarse, o elegir un host, para que tenga privacidad, propiedad y control de sus datos y conversaciones. Te da acceso a una red abierta; para que no se quede atascado hablando solo con otros usuarios de Element. Y es muy seguro. + +Element puede hacer todo esto porque opera en Matrix, el estándar para la comunicación abierta y descentralizada. + +Element te da el control permitiéndote elegir quién aloja tus conversaciones. Desde la aplicación Element, puede elegir hospedar de diferentes maneras: + +1. Obtenga una cuenta gratuita en el servidor público de matrix.org alojado por los desarrolladores de Matrix, o elija entre miles de servidores públicos alojados por voluntarios +2. Autohospede su cuenta ejecutando un servidor en su propio hardware +3. Regístrese para obtener una cuenta en un servidor personalizado simplemente suscribiéndose a la plataforma de alojamiento de Element Matrix Services + +¿Por qué elegir Element? + +POSEE SUS DATOS: Tú decides dónde guardar tus datos y mensajes. Usted es el propietario y lo controla, no algún MEGACORP que extraiga sus datos o dé acceso a terceros. + +MENSAJERÍA ABIERTA Y COLABORACIÓN: Puede chatear con cualquier otra persona en la red de Matrix, ya sea que estén usando Element u otra aplicación de Matrix, e incluso si están usando un sistema de mensajería diferente como Slack, IRC o XMPP. + +SUPER SEGURO: Cifrado real de extremo a extremo (solo aquellos en la conversación pueden descifrar mensajes) y firma cruzada para verificar los dispositivos de los participantes de la conversación. + +COMUNICACIÓN COMPLETA: Mensajería, llamadas de voz y video, uso compartido de archivos, uso compartido de pantalla y un montón de integraciones, bots y widgets. Construya salas, comunidades, manténgase en contacto y haga las cosas. + +EN TODAS PARTES: Manténgase en contacto donde quiera que esté con un historial de mensajes totalmente sincronizado en todos sus dispositivos y en la web en https://app.element.io. diff --git a/vector/src/main/play/listings/es/short_description.txt b/vector/src/main/play/listings/es/short_description.txt new file mode 100644 index 0000000000..0562213351 --- /dev/null +++ b/vector/src/main/play/listings/es/short_description.txt @@ -0,0 +1 @@ +Chat y VoIP descentralizados seguros. Mantenga sus datos a salvo de terceros. diff --git a/vector/src/main/play/listings/es/title.txt b/vector/src/main/play/listings/es/title.txt new file mode 100644 index 0000000000..adc831006a --- /dev/null +++ b/vector/src/main/play/listings/es/title.txt @@ -0,0 +1 @@ +Element (anteriorment Riot.im) From 5e39d3c6fb10850052face2598637df5c67619a3 Mon Sep 17 00:00:00 2001 From: Valere Date: Tue, 15 Sep 2020 10:03:49 +0200 Subject: [PATCH 70/89] output stream not closed --- CHANGES.md | 1 + .../sdk/internal/session/DefaultFileService.kt | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index f7c7f9d044..d5c3df0521 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,7 @@ Improvements 🙌: Bugfix 🐛: - Clear the notification when the event is read elsewhere (#1822) - Speakerphone is not used for ringback tone (#1644, #1645) + - Various report of people that cannot play video (#2107) Translations 🗣: - diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt index aa4114c8c2..a163cd4809 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt @@ -144,11 +144,13 @@ internal class DefaultFileService @Inject constructor( if (elementToDecrypt != null) { Timber.v("## FileService: decrypt file") - val decryptSuccess = MXEncryptedAttachments.decryptAttachment( - source.inputStream(), - elementToDecrypt, - destFile.outputStream().buffered() - ) + val decryptSuccess = destFile.outputStream().buffered().use { + MXEncryptedAttachments.decryptAttachment( + source.inputStream(), + elementToDecrypt, + it + ) + } response.close() if (!decryptSuccess) { return@flatMap Try.Failure(IllegalStateException("Decryption error")) From 624a8ff04c9c53576cd14a330f0a87a5b9781f83 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 15 Sep 2020 12:36:27 +0200 Subject: [PATCH 71/89] Fragment transaction: allow state loss when needed --- .../im/vector/app/core/extensions/Activity.kt | 23 ++++----- .../im/vector/app/core/extensions/Fragment.kt | 48 +++++++++---------- .../app/core/extensions/FragmentManager.kt | 9 +++- .../restore/KeysBackupRestoreActivity.kt | 4 +- .../vector/app/features/home/HomeActivity.kt | 2 +- 5 files changed, 46 insertions(+), 40 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/extensions/Activity.kt b/vector/src/main/java/im/vector/app/core/extensions/Activity.kt index ee94013d1b..02806d81a9 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/Activity.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/Activity.kt @@ -22,36 +22,37 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentTransaction import im.vector.app.core.platform.VectorBaseActivity -fun VectorBaseActivity.addFragment(frameId: Int, fragment: Fragment) { - supportFragmentManager.commitTransaction { add(frameId, fragment) } +fun VectorBaseActivity.addFragment(frameId: Int, fragment: Fragment, allowStateLoss: Boolean = false) { + supportFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) } } -fun VectorBaseActivity.addFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { - supportFragmentManager.commitTransaction { +fun VectorBaseActivity.addFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, allowStateLoss: Boolean = false) { + supportFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseActivity.replaceFragment(frameId: Int, fragment: Fragment, tag: String? = null) { - supportFragmentManager.commitTransaction { replace(frameId, fragment, tag) } +fun VectorBaseActivity.replaceFragment(frameId: Int, fragment: Fragment, tag: String? = null, allowStateLoss: Boolean = false) { + supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) } } -fun VectorBaseActivity.replaceFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { - supportFragmentManager.commitTransaction { +fun VectorBaseActivity.replaceFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, allowStateLoss: Boolean = false) { + supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseActivity.addFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null) { - supportFragmentManager.commitTransaction { replace(frameId, fragment).addToBackStack(tag) } +fun VectorBaseActivity.addFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null, allowStateLoss: Boolean = false) { + supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) } } fun VectorBaseActivity.addFragmentToBackstack(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, + allowStateLoss: Boolean = false, option: ((FragmentTransaction) -> Unit)? = null) { - supportFragmentManager.commitTransaction { + supportFragmentManager.commitTransaction(allowStateLoss) { option?.invoke(this) replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag) } diff --git a/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt b/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt index 6ba250ee1b..b3e34ab6a9 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt @@ -26,62 +26,62 @@ import java.text.SimpleDateFormat import java.util.Date import java.util.Locale -fun VectorBaseFragment.addFragment(frameId: Int, fragment: Fragment) { - parentFragmentManager.commitTransaction { add(frameId, fragment) } +fun VectorBaseFragment.addFragment(frameId: Int, fragment: Fragment, allowStateLoss: Boolean = false) { + parentFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) } } -fun VectorBaseFragment.addFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { - parentFragmentManager.commitTransaction { +fun VectorBaseFragment.addFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, allowStateLoss: Boolean = false) { + parentFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseFragment.replaceFragment(frameId: Int, fragment: Fragment) { - parentFragmentManager.commitTransaction { replace(frameId, fragment) } +fun VectorBaseFragment.replaceFragment(frameId: Int, fragment: Fragment, allowStateLoss: Boolean = false) { + parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment) } } -fun VectorBaseFragment.replaceFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { - parentFragmentManager.commitTransaction { +fun VectorBaseFragment.replaceFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, allowStateLoss: Boolean = false) { + parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseFragment.addFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null) { - parentFragmentManager.commitTransaction { replace(frameId, fragment, tag).addToBackStack(tag) } +fun VectorBaseFragment.addFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null, allowStateLoss: Boolean = false) { + parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag).addToBackStack(tag) } } -fun VectorBaseFragment.addFragmentToBackstack(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { - parentFragmentManager.commitTransaction { +fun VectorBaseFragment.addFragmentToBackstack(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, allowStateLoss: Boolean = false) { + parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag) } } -fun VectorBaseFragment.addChildFragment(frameId: Int, fragment: Fragment, tag: String? = null) { - childFragmentManager.commitTransaction { add(frameId, fragment, tag) } +fun VectorBaseFragment.addChildFragment(frameId: Int, fragment: Fragment, tag: String? = null, allowStateLoss: Boolean = false) { + childFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment, tag) } } -fun VectorBaseFragment.addChildFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { - childFragmentManager.commitTransaction { +fun VectorBaseFragment.addChildFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, allowStateLoss: Boolean = false) { + childFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseFragment.replaceChildFragment(frameId: Int, fragment: Fragment, tag: String? = null) { - childFragmentManager.commitTransaction { replace(frameId, fragment, tag) } +fun VectorBaseFragment.replaceChildFragment(frameId: Int, fragment: Fragment, tag: String? = null, allowStateLoss: Boolean = false) { + childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) } } -fun VectorBaseFragment.replaceChildFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { - childFragmentManager.commitTransaction { +fun VectorBaseFragment.replaceChildFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, allowStateLoss: Boolean = false) { + childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseFragment.addChildFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null) { - childFragmentManager.commitTransaction { replace(frameId, fragment).addToBackStack(tag) } +fun VectorBaseFragment.addChildFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null, allowStateLoss: Boolean = false) { + childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) } } -fun VectorBaseFragment.addChildFragmentToBackstack(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { - childFragmentManager.commitTransaction { +fun VectorBaseFragment.addChildFragmentToBackstack(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, allowStateLoss: Boolean = false) { + childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag) } } diff --git a/vector/src/main/java/im/vector/app/core/extensions/FragmentManager.kt b/vector/src/main/java/im/vector/app/core/extensions/FragmentManager.kt index 1d437c0701..49b28fb190 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/FragmentManager.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/FragmentManager.kt @@ -27,6 +27,11 @@ inline fun androidx.fragment.app.FragmentManager.commitTransactionNow(func: Frag } } -inline fun androidx.fragment.app.FragmentManager.commitTransaction(func: FragmentTransaction.() -> FragmentTransaction) { - beginTransaction().func().commit() +inline fun androidx.fragment.app.FragmentManager.commitTransaction(allowStateLoss: Boolean = false, func: FragmentTransaction.() -> FragmentTransaction) { + val transaction = beginTransaction().func() + if (allowStateLoss) { + transaction.commitAllowingStateLoss() + } else { + transaction.commit() + } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt index bef8788f75..40953cb5f6 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt @@ -87,13 +87,13 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() { viewModel.navigateEvent.observeEvent(this) { uxStateEvent -> when (uxStateEvent) { KeysBackupRestoreSharedViewModel.NAVIGATE_TO_RECOVER_WITH_KEY -> { - addFragmentToBackstack(R.id.container, KeysBackupRestoreFromKeyFragment::class.java) + addFragmentToBackstack(R.id.container, KeysBackupRestoreFromKeyFragment::class.java, allowStateLoss = true) } KeysBackupRestoreSharedViewModel.NAVIGATE_TO_SUCCESS -> { viewModel.keyVersionResult.value?.version?.let { KeysBackupBanner.onRecoverDoneForVersion(this, it) } - replaceFragment(R.id.container, KeysBackupRestoreSuccessFragment::class.java) + replaceFragment(R.id.container, KeysBackupRestoreSuccessFragment::class.java, allowStateLoss = true) } KeysBackupRestoreSharedViewModel.NAVIGATE_TO_4S -> { launch4SActivity() diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index 76de2daf54..eb024c4db1 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -121,7 +121,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet is HomeActivitySharedAction.CloseDrawer -> drawerLayout.closeDrawer(GravityCompat.START) is HomeActivitySharedAction.OpenGroup -> { drawerLayout.closeDrawer(GravityCompat.START) - replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java) + replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true) } }.exhaustive } From 0077091175bbd34682f35cee645eaa3d0bd2c737 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 15 Sep 2020 12:56:37 +0200 Subject: [PATCH 72/89] Update CHANGES and clean files --- CHANGES.md | 1 + .../im/vector/app/core/extensions/Activity.kt | 36 ++++++-- .../im/vector/app/core/extensions/Fragment.kt | 88 ++++++++++++++++--- 3 files changed, 108 insertions(+), 17 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d8556e16bc..118917fb93 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,7 @@ Bugfix 🐛: - Speakerphone is not used for ringback tone (#1644, #1645) - Back camera preview is not mirrored anymore (#1776) - Various report of people that cannot play video (#2107) + - Fix stuck on loader when launching home Translations 🗣: - diff --git a/vector/src/main/java/im/vector/app/core/extensions/Activity.kt b/vector/src/main/java/im/vector/app/core/extensions/Activity.kt index 02806d81a9..cc67f633eb 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/Activity.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/Activity.kt @@ -22,27 +22,53 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentTransaction import im.vector.app.core.platform.VectorBaseActivity -fun VectorBaseActivity.addFragment(frameId: Int, fragment: Fragment, allowStateLoss: Boolean = false) { +fun VectorBaseActivity.addFragment( + frameId: Int, + fragment: Fragment, + allowStateLoss: Boolean = false +) { supportFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) } } -fun VectorBaseActivity.addFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, allowStateLoss: Boolean = false) { +fun VectorBaseActivity.addFragment( + frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false +) { supportFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseActivity.replaceFragment(frameId: Int, fragment: Fragment, tag: String? = null, allowStateLoss: Boolean = false) { +fun VectorBaseActivity.replaceFragment( + frameId: Int, + fragment: Fragment, + tag: String? = null, + allowStateLoss: Boolean = false +) { supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) } } -fun VectorBaseActivity.replaceFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, allowStateLoss: Boolean = false) { +fun VectorBaseActivity.replaceFragment( + frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false +) { supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseActivity.addFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null, allowStateLoss: Boolean = false) { +fun VectorBaseActivity.addFragmentToBackstack( + frameId: Int, + fragment: Fragment, + tag: String? = null, + allowStateLoss: Boolean = false +) { supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) } } diff --git a/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt b/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt index b3e34ab6a9..fbcd6900c1 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt @@ -26,61 +26,125 @@ import java.text.SimpleDateFormat import java.util.Date import java.util.Locale -fun VectorBaseFragment.addFragment(frameId: Int, fragment: Fragment, allowStateLoss: Boolean = false) { +fun VectorBaseFragment.addFragment( + frameId: Int, + fragment: Fragment, + allowStateLoss: Boolean = false +) { parentFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) } } -fun VectorBaseFragment.addFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, allowStateLoss: Boolean = false) { +fun VectorBaseFragment.addFragment( + frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false +) { parentFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseFragment.replaceFragment(frameId: Int, fragment: Fragment, allowStateLoss: Boolean = false) { +fun VectorBaseFragment.replaceFragment( + frameId: Int, + fragment: Fragment, + allowStateLoss: Boolean = false +) { parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment) } } -fun VectorBaseFragment.replaceFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, allowStateLoss: Boolean = false) { +fun VectorBaseFragment.replaceFragment( + frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false +) { parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseFragment.addFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null, allowStateLoss: Boolean = false) { +fun VectorBaseFragment.addFragmentToBackstack( + frameId: Int, + fragment: Fragment, + tag: String? = null, + allowStateLoss: Boolean = false +) { parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag).addToBackStack(tag) } } -fun VectorBaseFragment.addFragmentToBackstack(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, allowStateLoss: Boolean = false) { +fun VectorBaseFragment.addFragmentToBackstack( + frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false +) { parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag) } } -fun VectorBaseFragment.addChildFragment(frameId: Int, fragment: Fragment, tag: String? = null, allowStateLoss: Boolean = false) { +fun VectorBaseFragment.addChildFragment( + frameId: Int, + fragment: Fragment, + tag: String? = null, + allowStateLoss: Boolean = false +) { childFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment, tag) } } -fun VectorBaseFragment.addChildFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, allowStateLoss: Boolean = false) { +fun VectorBaseFragment.addChildFragment( + frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false +) { childFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseFragment.replaceChildFragment(frameId: Int, fragment: Fragment, tag: String? = null, allowStateLoss: Boolean = false) { +fun VectorBaseFragment.replaceChildFragment( + frameId: Int, + fragment: Fragment, + tag: String? = null, + allowStateLoss: Boolean = false +) { childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) } } -fun VectorBaseFragment.replaceChildFragment(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, allowStateLoss: Boolean = false) { +fun VectorBaseFragment.replaceChildFragment( + frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false +) { childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragmentClass, params.toMvRxBundle(), tag) } } -fun VectorBaseFragment.addChildFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null, allowStateLoss: Boolean = false) { +fun VectorBaseFragment.addChildFragmentToBackstack( + frameId: Int, + fragment: Fragment, + tag: String? = null, + allowStateLoss: Boolean = false +) { childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) } } -fun VectorBaseFragment.addChildFragmentToBackstack(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null, allowStateLoss: Boolean = false) { +fun VectorBaseFragment.addChildFragmentToBackstack( + frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false +) { childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag) } From abb9a0839afe29b355e606f53aff776b3b972c7a Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 15 Sep 2020 18:13:09 +0200 Subject: [PATCH 73/89] Room summary : change displayable events types --- .../room/summary/RoomSummaryConstants.kt | 33 ++++++++++++++ .../room/timeline/TimelineEventFilters.kt | 40 +++++++++++++++++ .../session/room/timeline/TimelineSettings.kt | 20 +-------- .../query/TimelineEventEntityQueries.kt | 41 ++++++++++++------ .../room/summary/RoomSummaryEventsHelper.kt | 43 +++++++++++++++++++ .../room/summary/RoomSummaryUpdater.kt | 35 +++------------ .../session/room/timeline/DefaultTimeline.kt | 26 +++-------- .../timeline/TimelineHiddenReadReceipts.kt | 10 ++--- .../room/timeline/TokenChunkEventPersistor.kt | 21 ++------- vector/build.gradle | 2 +- .../home/room/detail/RoomDetailViewModel.kt | 29 +++++++------ 11 files changed, 183 insertions(+), 117 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomSummaryConstants.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEventFilters.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryEventsHelper.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomSummaryConstants.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomSummaryConstants.kt new file mode 100644 index 0000000000..2b0132817d --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomSummaryConstants.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 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 org.matrix.android.sdk.api.session.room.summary + +import org.matrix.android.sdk.api.session.events.model.EventType + +object RoomSummaryConstants { + + val PREVIEWABLE_TYPES = listOf( + // TODO filter message type (KEY_VERIFICATION_READY, etc.) + EventType.MESSAGE, + EventType.CALL_INVITE, + EventType.CALL_HANGUP, + EventType.CALL_ANSWER, + EventType.ENCRYPTED, + EventType.STICKER, + EventType.REACTION + ) +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEventFilters.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEventFilters.kt new file mode 100644 index 0000000000..eccc46b5d8 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEventFilters.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 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 org.matrix.android.sdk.api.session.room.timeline + +data class TimelineEventFilters( + /** + * A flag to filter edit events + */ + val filterEdits: Boolean = false, + /** + * A flag to filter redacted events + */ + val filterRedacted: Boolean = false, + /** + * A flag to filter useless events, such as membership events without any change + */ + val filterUseless: Boolean = false, + /** + * A flag to filter by types. It should be used with [allowedTypes] field + */ + val filterTypes: Boolean = false, + /** + * If [filterTypes] is true, the list of types allowed by the list. + */ + val allowedTypes: List = emptyList() +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineSettings.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineSettings.kt index 4f915cb907..ab98208eed 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineSettings.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineSettings.kt @@ -26,25 +26,9 @@ data class TimelineSettings( */ val initialSize: Int, /** - * A flag to filter edit events + * Filters for timeline event */ - val filterEdits: Boolean = false, - /** - * A flag to filter redacted events - */ - val filterRedacted: Boolean = false, - /** - * A flag to filter useless events, such as membership events without any change - */ - val filterUseless: Boolean = false, - /** - * A flag to filter by types. It should be used with [allowedTypes] field - */ - val filterTypes: Boolean = false, - /** - * If [filterTypes] is true, the list of types allowed by the list. - */ - val allowedTypes: List = emptyList(), + val filters: TimelineEventFilters = TimelineEventFilters(), /** * If true, will build read receipts for each event. */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt index 83075a192c..d49b64c432 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt @@ -17,17 +17,18 @@ package org.matrix.android.sdk.internal.database.query -import org.matrix.android.sdk.api.session.room.send.SendState -import org.matrix.android.sdk.internal.database.model.ChunkEntity -import org.matrix.android.sdk.internal.database.model.RoomEntity -import org.matrix.android.sdk.internal.database.model.TimelineEventEntity -import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields import io.realm.Realm import io.realm.RealmList import io.realm.RealmQuery import io.realm.RealmResults import io.realm.Sort import io.realm.kotlin.where +import org.matrix.android.sdk.api.session.room.send.SendState +import org.matrix.android.sdk.api.session.room.timeline.TimelineEventFilters +import org.matrix.android.sdk.internal.database.model.ChunkEntity +import org.matrix.android.sdk.internal.database.model.RoomEntity +import org.matrix.android.sdk.internal.database.model.TimelineEventEntity +import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields internal fun TimelineEventEntity.Companion.where(realm: Realm, roomId: String, eventId: String): RealmQuery { return realm.where() @@ -56,16 +57,10 @@ internal fun TimelineEventEntity.Companion.findWithSenderMembershipEvent(realm: internal fun TimelineEventEntity.Companion.latestEvent(realm: Realm, roomId: String, includesSending: Boolean, - filterContentRelation: Boolean = false, - filterTypes: List = emptyList()): TimelineEventEntity? { + filters: TimelineEventFilters = TimelineEventFilters()): TimelineEventEntity? { val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: return null - val sendingTimelineEvents = roomEntity.sendingTimelineEvents.where().filterTypes(filterTypes) - val liveEvents = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId)?.timelineEvents?.where()?.filterTypes(filterTypes) - if (filterContentRelation) { - liveEvents - ?.not()?.like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.EDIT) - ?.not()?.like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.RESPONSE) - } + val sendingTimelineEvents = roomEntity.sendingTimelineEvents.where().filterEvents(filters) + val liveEvents = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId)?.timelineEvents?.where()?.filterEvents(filters) val query = if (includesSending && sendingTimelineEvents.findAll().isNotEmpty()) { sendingTimelineEvents } else { @@ -76,6 +71,24 @@ internal fun TimelineEventEntity.Companion.latestEvent(realm: Realm, ?.findFirst() } +internal fun RealmQuery.filterEvents(filters: TimelineEventFilters): RealmQuery { + if (filters.filterTypes) { + `in`(TimelineEventEntityFields.ROOT.TYPE, filters.allowedTypes.toTypedArray()) + } + if (filters.filterUseless) { + not() + .equalTo(TimelineEventEntityFields.ROOT.IS_USELESS, true) + } + if (filters.filterEdits) { + not().like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.EDIT) + not().like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.RESPONSE) + } + if (filters.filterRedacted) { + not().like(TimelineEventEntityFields.ROOT.UNSIGNED_DATA, TimelineEventFilter.Unsigned.REDACTED) + } + return this +} + internal fun RealmQuery.filterTypes(filterTypes: List): RealmQuery { return if (filterTypes.isEmpty()) { this diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryEventsHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryEventsHelper.kt new file mode 100644 index 0000000000..dd71bff436 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryEventsHelper.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 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 org.matrix.android.sdk.internal.session.room.summary + +import io.realm.Realm +import org.matrix.android.sdk.api.session.room.summary.RoomSummaryConstants +import org.matrix.android.sdk.api.session.room.timeline.TimelineEventFilters +import org.matrix.android.sdk.internal.database.model.TimelineEventEntity +import org.matrix.android.sdk.internal.database.query.latestEvent + +internal object RoomSummaryEventsHelper { + + private val previewFilters = TimelineEventFilters( + filterTypes = true, + allowedTypes = RoomSummaryConstants.PREVIEWABLE_TYPES, + filterUseless = true, + filterRedacted = false, + filterEdits = true + ) + + fun getLatestPreviewableEvent(realm: Realm, roomId: String): TimelineEventEntity? { + return TimelineEventEntity.latestEvent( + realm = realm, + roomId = roomId, + includesSending = true, + filters = previewFilters + ) + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt index 99671c232a..0aac30654a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt @@ -18,6 +18,8 @@ package org.matrix.android.sdk.internal.session.room.summary import dagger.Lazy +import io.realm.Realm +import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel @@ -40,7 +42,6 @@ import org.matrix.android.sdk.internal.database.query.findAllInRoomWithSendState import org.matrix.android.sdk.internal.database.query.getOrCreate import org.matrix.android.sdk.internal.database.query.getOrNull import org.matrix.android.sdk.internal.database.query.isEventRead -import org.matrix.android.sdk.internal.database.query.latestEvent import org.matrix.android.sdk.internal.database.query.whereType import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.room.RoomAvatarResolver @@ -49,8 +50,6 @@ import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper import org.matrix.android.sdk.internal.session.room.timeline.TimelineEventDecryptor import org.matrix.android.sdk.internal.session.sync.model.RoomSyncSummary import org.matrix.android.sdk.internal.session.sync.model.RoomSyncUnreadNotifications -import io.realm.Realm -import org.greenrobot.eventbus.EventBus import timber.log.Timber import javax.inject.Inject @@ -61,28 +60,6 @@ internal class RoomSummaryUpdater @Inject constructor( private val timelineEventDecryptor: Lazy, private val eventBus: EventBus) { - companion object { - // TODO: maybe allow user of SDK to give that list - val PREVIEWABLE_TYPES = listOf( - // TODO filter message type (KEY_VERIFICATION_READY, etc.) - EventType.MESSAGE, - EventType.STATE_ROOM_NAME, - EventType.STATE_ROOM_TOPIC, - EventType.STATE_ROOM_AVATAR, - EventType.STATE_ROOM_MEMBER, - EventType.STATE_ROOM_HISTORY_VISIBILITY, - EventType.CALL_INVITE, - EventType.CALL_HANGUP, - EventType.CALL_ANSWER, - EventType.ENCRYPTED, - EventType.STATE_ROOM_ENCRYPTION, - EventType.STATE_ROOM_THIRD_PARTY_INVITE, - EventType.STICKER, - EventType.REACTION, - EventType.STATE_ROOM_CREATE - ) - } - fun update(realm: Realm, roomId: String, membership: Membership? = null, @@ -110,9 +87,6 @@ internal class RoomSummaryUpdater @Inject constructor( roomSummaryEntity.membership = membership } - val latestPreviewableEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true, - filterTypes = PREVIEWABLE_TYPES, filterContentRelation = true) - val lastNameEvent = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_NAME, stateKey = "")?.root val lastTopicEvent = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_TOPIC, stateKey = "")?.root val lastCanonicalAliasEvent = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_CANONICAL_ALIAS, stateKey = "")?.root @@ -123,6 +97,8 @@ internal class RoomSummaryUpdater @Inject constructor( .contains(EventEntityFields.CONTENT, "\"algorithm\":\"$MXCRYPTO_ALGORITHM_MEGOLM\"") .findFirst() + val latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId) + roomSummaryEntity.hasUnreadMessages = roomSummaryEntity.notificationCount > 0 // avoid this call if we are sure there are unread events || !isEventRead(realm.configuration, userId, roomId, latestPreviewableEvent?.eventId) @@ -178,8 +154,7 @@ internal class RoomSummaryUpdater @Inject constructor( fun updateSendingInformation(realm: Realm, roomId: String) { val roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, roomId) roomSummaryEntity.updateHasFailedSending() - roomSummaryEntity.latestPreviewableEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true, - filterTypes = PREVIEWABLE_TYPES, filterContentRelation = true) + roomSummaryEntity.latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId) } fun updateShieldTrust(realm: Realm, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt index 52651af881..2dead1d9cc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt @@ -46,7 +46,7 @@ import org.matrix.android.sdk.internal.database.model.ChunkEntityFields import org.matrix.android.sdk.internal.database.model.RoomEntity import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields -import org.matrix.android.sdk.internal.database.query.TimelineEventFilter +import org.matrix.android.sdk.internal.database.query.filterEvents import org.matrix.android.sdk.internal.database.query.findAllInRoomWithSendStates import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.database.query.whereRoomId @@ -184,7 +184,7 @@ internal class DefaultTimeline( } private fun TimelineSettings.shouldHandleHiddenReadReceipts(): Boolean { - return buildReadReceipts && (filterEdits || filterTypes) + return buildReadReceipts && (filters.filterEdits || filters.filterTypes) } override fun dispose() { @@ -759,29 +759,15 @@ internal class DefaultTimeline( } private fun RealmQuery.filterEventsWithSettings(): RealmQuery { - if (settings.filterTypes) { - `in`(TimelineEventEntityFields.ROOT.TYPE, settings.allowedTypes.toTypedArray()) - } - if (settings.filterUseless) { - not() - .equalTo(TimelineEventEntityFields.ROOT.IS_USELESS, true) - } - if (settings.filterEdits) { - not().like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.EDIT) - not().like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.RESPONSE) - } - if (settings.filterRedacted) { - not().like(TimelineEventEntityFields.ROOT.UNSIGNED_DATA, TimelineEventFilter.Unsigned.REDACTED) - } - return this + return filterEvents(settings.filters) } private fun List.filterEventsWithSettings(): List { return filter { - val filterType = !settings.filterTypes || settings.allowedTypes.contains(it.root.type) + val filterType = !settings.filters.filterTypes || settings.filters.allowedTypes.contains(it.root.type) if (!filterType) return@filter false - val filterEdits = if (settings.filterEdits && it.root.type == EventType.MESSAGE) { + val filterEdits = if (settings.filters.filterEdits && it.root.type == EventType.MESSAGE) { val messageContent = it.root.content.toModel() messageContent?.relatesTo?.type != RelationType.REPLACE && messageContent?.relatesTo?.type != RelationType.RESPONSE } else { @@ -789,7 +775,7 @@ internal class DefaultTimeline( } if (!filterEdits) return@filter false - val filterRedacted = !settings.filterRedacted || it.root.isRedacted() + val filterRedacted = !settings.filters.filterRedacted || it.root.isRedacted() filterRedacted } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineHiddenReadReceipts.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineHiddenReadReceipts.kt index 426daa4b57..276e49fbdf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineHiddenReadReceipts.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineHiddenReadReceipts.kt @@ -151,23 +151,23 @@ internal class TimelineHiddenReadReceipts constructor(private val readReceiptsSu private fun RealmQuery.filterReceiptsWithSettings(): RealmQuery { beginGroup() var needOr = false - if (settings.filterTypes) { - not().`in`("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.TYPE}", settings.allowedTypes.toTypedArray()) + if (settings.filters.filterTypes) { + not().`in`("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.TYPE}", settings.filters.allowedTypes.toTypedArray()) needOr = true } - if (settings.filterUseless) { + if (settings.filters.filterUseless) { if (needOr) or() equalTo("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.IS_USELESS}", true) needOr = true } - if (settings.filterEdits) { + if (settings.filters.filterEdits) { if (needOr) or() like("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.CONTENT}", TimelineEventFilter.Content.EDIT) or() like("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.CONTENT}", TimelineEventFilter.Content.RESPONSE) needOr = true } - if (settings.filterRedacted) { + if (settings.filters.filterRedacted) { if (needOr) or() like("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.UNSIGNED_DATA}", TimelineEventFilter.Unsigned.REDACTED) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt index da4eebe142..1fefdf9b50 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.room.timeline import com.zhuinden.monarchy.Monarchy +import io.realm.Realm import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.RoomMemberContent @@ -32,19 +33,16 @@ import org.matrix.android.sdk.internal.database.model.ChunkEntity import org.matrix.android.sdk.internal.database.model.EventInsertType import org.matrix.android.sdk.internal.database.model.RoomEntity import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity -import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore import org.matrix.android.sdk.internal.database.query.create import org.matrix.android.sdk.internal.database.query.find import org.matrix.android.sdk.internal.database.query.findAllIncludingEvents import org.matrix.android.sdk.internal.database.query.findLastForwardChunkOfRoom import org.matrix.android.sdk.internal.database.query.getOrCreate -import org.matrix.android.sdk.internal.database.query.latestEvent import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase -import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryUpdater +import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryEventsHelper import org.matrix.android.sdk.internal.util.awaitTransaction -import io.realm.Realm import timber.log.Timber import javax.inject.Inject @@ -177,12 +175,7 @@ internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase pri currentChunk.isLastForward = true currentLastForwardChunk?.deleteOnCascade() RoomSummaryEntity.where(realm, roomId).findFirst()?.apply { - latestPreviewableEvent = TimelineEventEntity.latestEvent( - realm, - roomId, - includesSending = true, - filterTypes = RoomSummaryUpdater.PREVIEWABLE_TYPES - ) + latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId) } } } else { @@ -249,13 +242,7 @@ internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase pri val shouldUpdateSummary = roomSummaryEntity.latestPreviewableEvent == null || (chunksToDelete.isNotEmpty() && currentChunk.isLastForward && direction == PaginationDirection.FORWARDS) if (shouldUpdateSummary) { - val latestPreviewableEvent = TimelineEventEntity.latestEvent( - realm, - roomId, - includesSending = true, - filterTypes = RoomSummaryUpdater.PREVIEWABLE_TYPES - ) - roomSummaryEntity.latestPreviewableEvent = latestPreviewableEvent + roomSummaryEntity.latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId) } if (currentChunk.isValid) { RoomEntity.where(realm, roomId).findFirst()?.addOrUpdate(currentChunk) diff --git a/vector/build.gradle b/vector/build.gradle index e0f401aaf6..81864216b7 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -41,7 +41,7 @@ def getVersionCode() { if (gitBranchName() == "develop") { return generateVersionCodeFromTimestamp() } else { - return generateVersionCodeFromVersionName() + return generateVersionCodeFromTimestamp() } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index a77d50d767..aa628bee5b 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -62,8 +62,8 @@ import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.events.model.EventType -import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage import org.matrix.android.sdk.api.session.events.model.LocalEcho +import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage import org.matrix.android.sdk.api.session.events.model.isTextMessage import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel @@ -86,6 +86,7 @@ import org.matrix.android.sdk.api.session.room.read.ReadService import org.matrix.android.sdk.api.session.room.send.UserDraft import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +import org.matrix.android.sdk.api.session.room.timeline.TimelineEventFilters import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.api.session.room.timeline.getTextEditableContent import org.matrix.android.sdk.api.session.widgets.model.Widget @@ -122,19 +123,23 @@ class RoomDetailViewModel @AssistedInject constructor( private val invisibleEventsObservable = BehaviorRelay.create() private val visibleEventsObservable = BehaviorRelay.create() private val timelineSettings = if (userPreferencesProvider.shouldShowHiddenEvents()) { - TimelineSettings(30, - filterEdits = false, - filterRedacted = userPreferencesProvider.shouldShowRedactedMessages().not(), - filterUseless = false, - filterTypes = false, + TimelineSettings( + initialSize = 30, + filters = TimelineEventFilters( + filterEdits = false, + filterRedacted = userPreferencesProvider.shouldShowRedactedMessages().not(), + filterUseless = false, + filterTypes = false), buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts()) } else { - TimelineSettings(30, - filterEdits = true, - filterRedacted = userPreferencesProvider.shouldShowRedactedMessages().not(), - filterUseless = true, - filterTypes = true, - allowedTypes = TimelineDisplayableEvents.DISPLAYABLE_TYPES, + TimelineSettings( + initialSize = 30, + filters = TimelineEventFilters( + filterEdits = true, + filterRedacted = userPreferencesProvider.shouldShowRedactedMessages().not(), + filterUseless = true, + filterTypes = true, + allowedTypes = TimelineDisplayableEvents.DISPLAYABLE_TYPES), buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts()) } From 487a90fba590a15e84eabc9032716ca13faac01a Mon Sep 17 00:00:00 2001 From: linsui Date: Tue, 15 Sep 2020 03:07:38 +0000 Subject: [PATCH 74/89] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1867 of 1867 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.riot.im/projects/element-android/element-app/zh_Hans/ --- vector/src/main/res/values-zh-rCN/strings.xml | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/vector/src/main/res/values-zh-rCN/strings.xml b/vector/src/main/res/values-zh-rCN/strings.xml index 9aea75781e..ead5567a19 100644 --- a/vector/src/main/res/values-zh-rCN/strings.xml +++ b/vector/src/main/res/values-zh-rCN/strings.xml @@ -1877,8 +1877,8 @@ Element 在后台时的工作将被显著的限制,这可能会影响消息通 \n \n您想要通过网页客户端登录吗? 抱歉,此服务器不接受新账户。 - 应用无法再次服务器上创建账户。 -\n + 应用无法在此服务器上创建账户。 +\n \n您想要通过网页客户端注册吗? 电子邮件未关联到任何账户。 @@ -2563,4 +2563,22 @@ Element 在后台时的工作将被显著的限制,这可能会影响消息通 注意!登出前最后一次尝试! 错误次数过多,您已被登出 +此电话号码已定义。 + 您的帐户尚未添加电话号码 + 电子邮件地址 + 您的账户尚未添加电子邮件 + 电话号码 + 移除 %s? + 请确认您已点击我们向您发送的电子邮件中的链接。 + + 电子邮件和电话号码 + 管理链接到您的 Matrix 账户的电子邮件和电话号码 + + 代码 + 请使用国际格式(电话号码必须以 ‘+’ 开始) + 通过验证此登录确认您的身份,授权它访问加密信息。 + 抱歉,对于连接到单点登录的账户此操作尚不可用。 + + 无法打开您被封禁的聊天室。 + 无法找到此聊天室。请确认它存在。 From 9b8bcc4464b43c91c6d773161a2e7048cdb9433a Mon Sep 17 00:00:00 2001 From: linsui Date: Tue, 15 Sep 2020 03:56:23 +0000 Subject: [PATCH 75/89] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (3 of 3 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.riot.im/projects/element-android/element-store/zh_Hans/ --- vector/src/main/play/listings/zh_Hans/full_description.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/play/listings/zh_Hans/full_description.txt b/vector/src/main/play/listings/zh_Hans/full_description.txt index 157198a1ac..12664f7c9b 100644 --- a/vector/src/main/play/listings/zh_Hans/full_description.txt +++ b/vector/src/main/play/listings/zh_Hans/full_description.txt @@ -13,7 +13,7 @@ Element 可以做到这些因为它在 Matrix 上运行 - 开放,去中心化 Element 通过让您选择谁来托管您的会话使您掌控一切。在 Element 应用中,您可以选择不同的托管方式: -1. 在 matrix.org 公共服务器上获取免费帐户 +1. 在由 Matrix 开发者托管的 matrix.org 公共服务器上获取免费帐户,或从志愿者托管的几千个公共服务器中选择 2. 在您自己的硬件上运行服务器自托管您的会话 3. 通过简单地订阅 Element Matrix Services 托管平台在自定义服务器上注册账户 From f882986f7d97a9b79e383329a7958e651b4d8418 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 15 Sep 2020 10:11:47 +0200 Subject: [PATCH 76/89] Remove unused member --- .../app/features/settings/VectorSettingsGeneralFragment.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt index c4df3a8d6e..f538c4993b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt @@ -80,9 +80,6 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() { override var titleRes = R.string.settings_general_title override val preferenceXmlRes = R.xml.vector_settings_general - private var mDisplayedEmails = ArrayList() - private var mDisplayedPhoneNumber = ArrayList() - private var avatarCameraUri: Uri? = null private val mUserSettingsCategory by lazy { From a1f98eb6bfded775a99c82061e25ebccc15281c1 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 16 Sep 2020 15:36:48 +0200 Subject: [PATCH 77/89] Allow to filter all room member state events in timeline --- vector/build.gradle | 2 +- .../core/resources/UserPreferencesProvider.kt | 5 ++ .../home/room/detail/RoomDetailViewModel.kt | 27 ++------- .../helper/TimelineSettingsFactory.kt | 59 +++++++++++++++++++ .../features/settings/VectorPreferences.kt | 11 ++++ vector/src/main/res/values/strings.xml | 2 + .../res/xml/vector_settings_preferences.xml | 6 ++ 7 files changed, 88 insertions(+), 24 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineSettingsFactory.kt diff --git a/vector/build.gradle b/vector/build.gradle index 81864216b7..e0f401aaf6 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -41,7 +41,7 @@ def getVersionCode() { if (gitBranchName() == "develop") { return generateVersionCodeFromTimestamp() } else { - return generateVersionCodeFromTimestamp() + return generateVersionCodeFromVersionName() } } diff --git a/vector/src/main/java/im/vector/app/core/resources/UserPreferencesProvider.kt b/vector/src/main/java/im/vector/app/core/resources/UserPreferencesProvider.kt index 302e55d1e7..e49831b826 100644 --- a/vector/src/main/java/im/vector/app/core/resources/UserPreferencesProvider.kt +++ b/vector/src/main/java/im/vector/app/core/resources/UserPreferencesProvider.kt @@ -40,4 +40,9 @@ class UserPreferencesProvider @Inject constructor(private val vectorPreferences: fun neverShowLongClickOnRoomHelpAgain() { vectorPreferences.neverShowLongClickOnRoomHelpAgain() } + + fun shouldShowRoomMemberStateEvents(): Boolean { + return vectorPreferences.showRoomMemberStateEvents() + } + } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index aa628bee5b..9e00afe48a 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -41,6 +41,7 @@ import im.vector.app.features.home.room.detail.composer.rainbow.RainbowGenerator import im.vector.app.features.home.room.detail.sticker.StickerPickerActionHandler import im.vector.app.features.home.room.detail.timeline.helper.RoomSummaryHolder import im.vector.app.features.home.room.detail.timeline.helper.TimelineDisplayableEvents +import im.vector.app.features.home.room.detail.timeline.helper.TimelineSettingsFactory import im.vector.app.features.home.room.typing.TypingHelper import im.vector.app.features.powerlevel.PowerLevelsObservableFactory import im.vector.app.features.settings.VectorLocale @@ -106,7 +107,6 @@ import java.util.concurrent.atomic.AtomicBoolean class RoomDetailViewModel @AssistedInject constructor( @Assisted private val initialState: RoomDetailViewState, - userPreferencesProvider: UserPreferencesProvider, private val vectorPreferences: VectorPreferences, private val stringProvider: StringProvider, private val rainbowGenerator: RainbowGenerator, @@ -115,34 +115,15 @@ class RoomDetailViewModel @AssistedInject constructor( private val stickerPickerActionHandler: StickerPickerActionHandler, private val roomSummaryHolder: RoomSummaryHolder, private val typingHelper: TypingHelper, - private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager + private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager, + timelineSettingsFactory: TimelineSettingsFactory ) : VectorViewModel(initialState), Timeline.Listener { private val room = session.getRoom(initialState.roomId)!! private val eventId = initialState.eventId private val invisibleEventsObservable = BehaviorRelay.create() private val visibleEventsObservable = BehaviorRelay.create() - private val timelineSettings = if (userPreferencesProvider.shouldShowHiddenEvents()) { - TimelineSettings( - initialSize = 30, - filters = TimelineEventFilters( - filterEdits = false, - filterRedacted = userPreferencesProvider.shouldShowRedactedMessages().not(), - filterUseless = false, - filterTypes = false), - buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts()) - } else { - TimelineSettings( - initialSize = 30, - filters = TimelineEventFilters( - filterEdits = true, - filterRedacted = userPreferencesProvider.shouldShowRedactedMessages().not(), - filterUseless = true, - filterTypes = true, - allowedTypes = TimelineDisplayableEvents.DISPLAYABLE_TYPES), - buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts()) - } - + private val timelineSettings = timelineSettingsFactory.create() private var timelineEvents = PublishRelay.create>() val timeline = room.createTimeline(eventId, timelineSettings) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineSettingsFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineSettingsFactory.kt new file mode 100644 index 0000000000..3317612a6c --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineSettingsFactory.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 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 im.vector.app.features.home.room.detail.timeline.helper + +import im.vector.app.core.resources.UserPreferencesProvider +import org.matrix.android.sdk.api.session.events.model.EventType +import org.matrix.android.sdk.api.session.room.timeline.TimelineEventFilters +import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings +import javax.inject.Inject + +class TimelineSettingsFactory @Inject constructor(private val userPreferencesProvider: UserPreferencesProvider) { + + fun create(): TimelineSettings { + return if (userPreferencesProvider.shouldShowHiddenEvents()) { + TimelineSettings( + initialSize = 30, + filters = TimelineEventFilters( + filterEdits = false, + filterRedacted = userPreferencesProvider.shouldShowRedactedMessages().not(), + filterUseless = false, + filterTypes = false), + buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts()) + } else { + val allowedTypes = TimelineDisplayableEvents.DISPLAYABLE_TYPES.filterDisplayableTypes() + TimelineSettings( + initialSize = 30, + filters = TimelineEventFilters( + filterEdits = true, + filterRedacted = userPreferencesProvider.shouldShowRedactedMessages().not(), + filterUseless = true, + filterTypes = true, + allowedTypes = allowedTypes), + buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts()) + } + } + + private fun List.filterDisplayableTypes(): List { + return filter { type -> + when (type) { + EventType.STATE_ROOM_MEMBER -> userPreferencesProvider.shouldShowRoomMemberStateEvents() + else -> true + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index 7415b57310..9fc566aac4 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -93,6 +93,7 @@ class VectorPreferences @Inject constructor(private val context: Context) { private const val SETTINGS_12_24_TIMESTAMPS_KEY = "SETTINGS_12_24_TIMESTAMPS_KEY" private const val SETTINGS_SHOW_READ_RECEIPTS_KEY = "SETTINGS_SHOW_READ_RECEIPTS_KEY" private const val SETTINGS_SHOW_REDACTED_KEY = "SETTINGS_SHOW_REDACTED_KEY" + private const val SETTINGS_SHOW_ROOM_MEMBER_STATE_EVENTS_KEY = "SETTINGS_SHOW_ROOM_MEMBER_STATE_EVENTS_KEY" private const val SETTINGS_SHOW_JOIN_LEAVE_MESSAGES_KEY = "SETTINGS_SHOW_JOIN_LEAVE_MESSAGES_KEY" private const val SETTINGS_SHOW_AVATAR_DISPLAY_NAME_CHANGES_MESSAGES_KEY = "SETTINGS_SHOW_AVATAR_DISPLAY_NAME_CHANGES_MESSAGES_KEY" private const val SETTINGS_VIBRATE_ON_MENTION_KEY = "SETTINGS_VIBRATE_ON_MENTION_KEY" @@ -195,6 +196,7 @@ class VectorPreferences @Inject constructor(private val context: Context) { SETTINGS_ALWAYS_SHOW_TIMESTAMPS_KEY, SETTINGS_12_24_TIMESTAMPS_KEY, SETTINGS_SHOW_READ_RECEIPTS_KEY, + SETTINGS_SHOW_ROOM_MEMBER_STATE_EVENTS_KEY, SETTINGS_SHOW_JOIN_LEAVE_MESSAGES_KEY, SETTINGS_SHOW_AVATAR_DISPLAY_NAME_CHANGES_MESSAGES_KEY, SETTINGS_MEDIA_SAVING_PERIOD_KEY, @@ -343,6 +345,15 @@ class VectorPreferences @Inject constructor(private val context: Context) { return defaultPrefs.getBoolean(SETTINGS_12_24_TIMESTAMPS_KEY, false) } + /** + * Tells if all room member state events should be shown in the messages list. + * + * @return true all room member state events should be shown in the messages list. + */ + fun showRoomMemberStateEvents(): Boolean { + return defaultPrefs.getBoolean(SETTINGS_SHOW_ROOM_MEMBER_STATE_EVENTS_KEY, true) + } + /** * Tells if the join and leave membership events should be shown in the messages list. * diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 1ed36e4228..3adb7d21e2 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -857,6 +857,8 @@ Show timestamps in 12-hour format Show read receipts Click on the read receipts for a detailed list. + Show room member state events + Includes invite/join/left/kick/ban events and avatar/display name changes. Show join and leave events Invites, kicks, and bans are unaffected. Show account events diff --git a/vector/src/main/res/xml/vector_settings_preferences.xml b/vector/src/main/res/xml/vector_settings_preferences.xml index 668aa9aa2b..ba8ba0d64b 100644 --- a/vector/src/main/res/xml/vector_settings_preferences.xml +++ b/vector/src/main/res/xml/vector_settings_preferences.xml @@ -76,6 +76,12 @@ android:summary="@string/settings_show_redacted_summary" android:title="@string/settings_show_redacted" /> + + Date: Wed, 16 Sep 2020 15:48:09 +0200 Subject: [PATCH 78/89] Clean files and update CHANGES --- CHANGES.md | 2 ++ .../room/timeline/TimelineHiddenReadReceipts.kt | 11 ++++++----- .../app/core/resources/UserPreferencesProvider.kt | 1 - .../features/home/room/detail/RoomDetailViewModel.kt | 4 ---- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d8556e16bc..2f20c8b7f6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,8 @@ Bugfix 🐛: - Speakerphone is not used for ringback tone (#1644, #1645) - Back camera preview is not mirrored anymore (#1776) - Various report of people that cannot play video (#2107) + - Rooms incorrectly marked as unread (#588) + - Allow users to show/hide room member state events (#1231) Translations 🗣: - diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineHiddenReadReceipts.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineHiddenReadReceipts.kt index 276e49fbdf..f2c520a50f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineHiddenReadReceipts.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineHiddenReadReceipts.kt @@ -18,6 +18,10 @@ package org.matrix.android.sdk.internal.session.room.timeline import android.util.SparseArray +import io.realm.OrderedRealmCollectionChangeListener +import io.realm.Realm +import io.realm.RealmQuery +import io.realm.RealmResults import org.matrix.android.sdk.api.session.room.model.ReadReceipt import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.internal.database.mapper.ReadReceiptsSummaryMapper @@ -27,10 +31,6 @@ import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields import org.matrix.android.sdk.internal.database.query.TimelineEventFilter import org.matrix.android.sdk.internal.database.query.whereInRoom -import io.realm.OrderedRealmCollectionChangeListener -import io.realm.Realm -import io.realm.RealmQuery -import io.realm.RealmResults /** * This class is responsible for handling the read receipts for hidden events (check [TimelineSettings] to see filtering). @@ -152,7 +152,8 @@ internal class TimelineHiddenReadReceipts constructor(private val readReceiptsSu beginGroup() var needOr = false if (settings.filters.filterTypes) { - not().`in`("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.TYPE}", settings.filters.allowedTypes.toTypedArray()) + val allowedTypes = settings.filters.allowedTypes.toTypedArray() + not().`in`("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.TYPE}", allowedTypes) needOr = true } if (settings.filters.filterUseless) { diff --git a/vector/src/main/java/im/vector/app/core/resources/UserPreferencesProvider.kt b/vector/src/main/java/im/vector/app/core/resources/UserPreferencesProvider.kt index e49831b826..f7d7b3864e 100644 --- a/vector/src/main/java/im/vector/app/core/resources/UserPreferencesProvider.kt +++ b/vector/src/main/java/im/vector/app/core/resources/UserPreferencesProvider.kt @@ -44,5 +44,4 @@ class UserPreferencesProvider @Inject constructor(private val vectorPreferences: fun shouldShowRoomMemberStateEvents(): Boolean { return vectorPreferences.showRoomMemberStateEvents() } - } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index 9e00afe48a..8164750aa4 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -31,7 +31,6 @@ import im.vector.app.R import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider -import im.vector.app.core.resources.UserPreferencesProvider import im.vector.app.core.utils.subscribeLogError import im.vector.app.features.call.WebRtcPeerConnectionManager import im.vector.app.features.command.CommandParser @@ -40,7 +39,6 @@ import im.vector.app.features.crypto.verification.SupportedVerificationMethodsPr import im.vector.app.features.home.room.detail.composer.rainbow.RainbowGenerator import im.vector.app.features.home.room.detail.sticker.StickerPickerActionHandler import im.vector.app.features.home.room.detail.timeline.helper.RoomSummaryHolder -import im.vector.app.features.home.room.detail.timeline.helper.TimelineDisplayableEvents import im.vector.app.features.home.room.detail.timeline.helper.TimelineSettingsFactory import im.vector.app.features.home.room.typing.TypingHelper import im.vector.app.features.powerlevel.PowerLevelsObservableFactory @@ -87,8 +85,6 @@ import org.matrix.android.sdk.api.session.room.read.ReadService import org.matrix.android.sdk.api.session.room.send.UserDraft import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent -import org.matrix.android.sdk.api.session.room.timeline.TimelineEventFilters -import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.api.session.room.timeline.getTextEditableContent import org.matrix.android.sdk.api.session.widgets.model.Widget import org.matrix.android.sdk.api.session.widgets.model.WidgetType From 82bf0dcae9a3ec303ce886ed8f7c440caa5f313a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 16 Sep 2020 16:14:20 +0200 Subject: [PATCH 79/89] Create a RawService SDK side, to avoid that the SDK manage client needs --- CHANGES.md | 2 +- .../java/org/matrix/android/sdk/api/Matrix.kt | 4 + .../java/org/matrix/android/sdk/api/Matrix.kt | 4 + .../android/sdk/api/auth/data/WellKnown.kt | 24 +---- .../android/sdk/api/raw/RawCacheStrategy.kt | 30 ++++++ .../matrix/android/sdk/api/raw/RawService.kt | 43 ++++++++ .../homeserver/HomeServerCapabilities.kt | 11 +- .../database/RealmSessionStoreMigration.kt | 16 ++- .../mapper/HomeServerCapabilitiesMapper.kt | 4 +- .../model/HomeServerCapabilitiesEntity.kt | 6 +- .../internal/database/model/RawCacheEntity.kt | 31 ++++++ .../database/query/RawCacheQueries.kt | 40 +++++++ .../android/sdk/internal/di/DbQualifiers.kt | 4 + .../sdk/internal/di/MatrixComponent.kt | 14 ++- .../internal/raw/DefaultCleanRawCacheTask.kt | 41 +++++++ .../sdk/internal/raw/DefaultGetUrlTask.kt | 101 ++++++++++++++++++ .../sdk/internal/raw/DefaultRawService.kt | 60 +++++++++++ .../sdk/internal/raw/GlobalRealmModule.kt | 30 ++++++ .../matrix/android/sdk/internal/raw/RawAPI.kt | 29 +++++ .../android/sdk/internal/raw/RawModule.kt | 79 ++++++++++++++ .../DefaultGetHomeServerCapabilitiesTask.kt | 6 +- .../im/vector/app/core/di/VectorComponent.kt | 3 + .../im/vector/app/core/di/VectorModule.kt | 7 ++ .../createdirect/CreateDirectRoomViewModel.kt | 47 +++++--- .../home/room/detail/RoomDetailViewModel.kt | 13 ++- .../HomeServerCapabilitiesViewModel.kt | 49 ++++++++- .../HomeServerCapabilitiesViewState.kt | 3 +- .../app/features/homeserver/WellKnownExt.kt | 68 ++++++++++++ .../createroom/CreateRoomViewModel.kt | 38 +++++-- .../VectorSettingsSecurityPrivacyFragment.kt | 14 ++- .../userdirectory/KnownUsersFragment.kt | 7 +- 31 files changed, 741 insertions(+), 87 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawCacheStrategy.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawService.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RawCacheEntity.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RawCacheQueries.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultCleanRawCacheTask.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultGetUrlTask.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultRawService.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GlobalRealmModule.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawAPI.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawModule.kt create mode 100644 vector/src/main/java/im/vector/app/features/homeserver/WellKnownExt.kt diff --git a/CHANGES.md b/CHANGES.md index 118917fb93..ad9a362197 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -19,7 +19,7 @@ Translations 🗣: - SDK API changes ⚠️: - - + - Create a new RawService to get plain data from the server. Build 🧱: - diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/Matrix.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/Matrix.kt index df26bb1227..751b2a708c 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/Matrix.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/Matrix.kt @@ -24,6 +24,7 @@ import com.zhuinden.monarchy.Monarchy import org.matrix.android.sdk.BuildConfig import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.legacy.LegacySessionImporter +import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.common.DaggerTestMatrixComponent import org.matrix.android.sdk.internal.SessionManager import org.matrix.android.sdk.internal.network.UserAgentHolder @@ -41,6 +42,7 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo @Inject internal lateinit var legacySessionImporter: LegacySessionImporter @Inject internal lateinit var authenticationService: AuthenticationService + @Inject internal lateinit var rawService: RawService @Inject internal lateinit var userAgentHolder: UserAgentHolder @Inject internal lateinit var backgroundDetectionObserver: BackgroundDetectionObserver @Inject internal lateinit var olmManager: OlmManager @@ -61,6 +63,8 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo return authenticationService } + fun rawService() = rawService + fun legacySessionImporter(): LegacySessionImporter { return legacySessionImporter } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt index aafefa2048..e6f982682b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt @@ -25,6 +25,7 @@ import com.zhuinden.monarchy.Monarchy import org.matrix.android.sdk.BuildConfig import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.legacy.LegacySessionImporter +import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.internal.SessionManager import org.matrix.android.sdk.internal.di.DaggerMatrixComponent import org.matrix.android.sdk.internal.network.UserAgentHolder @@ -42,6 +43,7 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo @Inject internal lateinit var legacySessionImporter: LegacySessionImporter @Inject internal lateinit var authenticationService: AuthenticationService + @Inject internal lateinit var rawService: RawService @Inject internal lateinit var userAgentHolder: UserAgentHolder @Inject internal lateinit var backgroundDetectionObserver: BackgroundDetectionObserver @Inject internal lateinit var olmManager: OlmManager @@ -62,6 +64,8 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo return authenticationService } + fun rawService() = rawService + fun legacySessionImporter(): LegacySessionImporter { return legacySessionImporter } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/WellKnown.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/WellKnown.kt index b10cae6171..4f7bc75556 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/WellKnown.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/WellKnown.kt @@ -42,9 +42,6 @@ import org.matrix.android.sdk.api.util.JsonDict * } * ] * } - * "im.vector.riot.jitsi": { - * "preferredDomain": "https://jitsi.riot.im/" - * } * } * */ @@ -57,24 +54,5 @@ data class WellKnown( val identityServer: WellKnownBaseConfig? = null, @Json(name = "m.integrations") - val integrations: JsonDict? = null, - - @Json(name = "im.vector.riot.e2ee") - val e2eAdminSetting: E2EWellKnownConfig? = null, - - @Json(name = "im.vector.riot.jitsi") - val jitsiServer: WellKnownPreferredConfig? = null - -) - -@JsonClass(generateAdapter = true) -data class E2EWellKnownConfig( - @Json(name = "default") - val e2eDefault: Boolean = true -) - -@JsonClass(generateAdapter = true) -data class WellKnownPreferredConfig( - @Json(name = "preferredDomain") - val preferredDomain: String? = null + val integrations: JsonDict? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawCacheStrategy.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawCacheStrategy.kt new file mode 100644 index 0000000000..06657a9869 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawCacheStrategy.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.api.raw + +sealed class RawCacheStrategy { + // Data is always fetched from the server + object NoCache: RawCacheStrategy() + + // Once data is retrieved, it is stored for the provided amount of time. + // In case of error, and if strict is set to false, the cache can be returned if available + data class TtlCache(val validityDurationInMillis: Long, val strict: Boolean): RawCacheStrategy() + + // Once retrieved, the data is stored in cache and will be always get from the cache + object InfiniteCache: RawCacheStrategy() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawService.kt new file mode 100644 index 0000000000..5c96d175cb --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawService.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.api.raw + +import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.util.Cancelable + +/** + * Useful methods to fetch raw data from the server. The access token will not be used to fetched the data + */ +interface RawService { + /** + * Get a URL, either from cache or from the remote server, depending on the cache strategy + */ + fun getUrl(url: String, + rawCacheStrategy: RawCacheStrategy, + matrixCallback: MatrixCallback): Cancelable + + /** + * Specific case for the well-known file. Cache validity is 8 hours + */ + fun getWellknown(userId: String, matrixCallback: MatrixCallback): Cancelable + + /** + * Clear all the cache data + */ + fun clearCache(matrixCallback: MatrixCallback): Cancelable +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt index de7ac45bf3..e12d99d6b8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt @@ -33,16 +33,7 @@ data class HomeServerCapabilities( /** * Default identity server url, provided in Wellknown */ - val defaultIdentityServerUrl: String? = null, - /** - * Option to allow homeserver admins to set the default E2EE behaviour back to disabled for DMs / private rooms - * (as it was before) for various environments where this is desired. - */ - val adminE2EByDefault: Boolean = true, - /** - * Preferred Jitsi domain, provided in Wellknown - */ - val preferredJitsiDomain: String? = null + val defaultIdentityServerUrl: String? = null ) { companion object { const val MAX_UPLOAD_FILE_SIZE_UNKNOWN = -1L diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt index ad05406aa0..26ce38e322 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt @@ -28,7 +28,7 @@ import javax.inject.Inject class RealmSessionStoreMigration @Inject constructor() : RealmMigration { companion object { - const val SESSION_STORE_SCHEMA_VERSION = 4L + const val SESSION_STORE_SCHEMA_VERSION = 5L } override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { @@ -38,6 +38,7 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { if (oldVersion <= 1) migrateTo2(realm) if (oldVersion <= 2) migrateTo3(realm) if (oldVersion <= 3) migrateTo4(realm) + if (oldVersion <= 4) migrateTo5(realm) } private fun migrateTo1(realm: DynamicRealm) { @@ -54,16 +55,16 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { private fun migrateTo2(realm: DynamicRealm) { Timber.d("Step 1 -> 2") realm.schema.get("HomeServerCapabilitiesEntity") - ?.addField(HomeServerCapabilitiesEntityFields.ADMIN_E2_E_BY_DEFAULT, Boolean::class.java) + ?.addField("adminE2EByDefault", Boolean::class.java) ?.transform { obj -> - obj.setBoolean(HomeServerCapabilitiesEntityFields.ADMIN_E2_E_BY_DEFAULT, true) + obj.setBoolean("adminE2EByDefault", true) } } private fun migrateTo3(realm: DynamicRealm) { Timber.d("Step 2 -> 3") realm.schema.get("HomeServerCapabilitiesEntity") - ?.addField(HomeServerCapabilitiesEntityFields.PREFERRED_JITSI_DOMAIN, String::class.java) + ?.addField("preferredJitsiDomain", String::class.java) ?.transform { obj -> // Schedule a refresh of the capabilities obj.setLong(HomeServerCapabilitiesEntityFields.LAST_UPDATED_TIMESTAMP, 0) @@ -82,4 +83,11 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { .setRequired(PendingThreePidEntityFields.SID, true) .addField(PendingThreePidEntityFields.SUBMIT_URL, String::class.java) } + + private fun migrateTo5(realm: DynamicRealm) { + Timber.d("Step 4 -> 5") + realm.schema.get("HomeServerCapabilitiesEntity") + ?.removeField("adminE2EByDefault") + ?.removeField("preferredJitsiDomain") + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt index e5de271d93..4eb9b4b47f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt @@ -30,9 +30,7 @@ internal object HomeServerCapabilitiesMapper { canChangePassword = entity.canChangePassword, maxUploadFileSize = entity.maxUploadFileSize, lastVersionIdentityServerSupported = entity.lastVersionIdentityServerSupported, - defaultIdentityServerUrl = entity.defaultIdentityServerUrl, - adminE2EByDefault = entity.adminE2EByDefault, - preferredJitsiDomain = entity.preferredJitsiDomain + defaultIdentityServerUrl = entity.defaultIdentityServerUrl ) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt index 7e3af69436..a905dc9535 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt @@ -17,17 +17,15 @@ package org.matrix.android.sdk.internal.database.model -import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import io.realm.RealmObject +import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities internal open class HomeServerCapabilitiesEntity( var canChangePassword: Boolean = true, var maxUploadFileSize: Long = HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN, var lastVersionIdentityServerSupported: Boolean = false, var defaultIdentityServerUrl: String? = null, - var adminE2EByDefault: Boolean = true, - var lastUpdatedTimestamp: Long = 0L, - var preferredJitsiDomain: String? = null + var lastUpdatedTimestamp: Long = 0L ) : RealmObject() { companion object diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RawCacheEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RawCacheEntity.kt new file mode 100644 index 0000000000..3c0a280476 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RawCacheEntity.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2019 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.internal.database.model + +import io.realm.RealmObject +import io.realm.annotations.PrimaryKey + +internal open class RawCacheEntity( + @PrimaryKey + var url: String = "", + var data: String = "", + var lastUpdatedTimestamp: Long = 0L +) : RealmObject() { + + companion object +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RawCacheQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RawCacheQueries.kt new file mode 100644 index 0000000000..93753ff24b --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RawCacheQueries.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2019 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.internal.database.query + +import io.realm.Realm +import io.realm.kotlin.createObject +import io.realm.kotlin.where +import org.matrix.android.sdk.internal.database.model.RawCacheEntity +import org.matrix.android.sdk.internal.database.model.RawCacheEntityFields + +/** + * Get the current RawCacheEntity, return null if it does not exist + */ +internal fun RawCacheEntity.Companion.get(realm: Realm, url: String): RawCacheEntity? { + return realm.where() + .equalTo(RawCacheEntityFields.URL, url) + .findFirst() +} + +/** + * Get the current RawCacheEntity, create one if it does not exist + */ +internal fun RawCacheEntity.Companion.getOrCreate(realm: Realm, url: String): RawCacheEntity { + return get(realm, url) ?: realm.createObject(url) +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/DbQualifiers.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/DbQualifiers.kt index 9442dc4865..2380ea68b8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/DbQualifiers.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/DbQualifiers.kt @@ -23,6 +23,10 @@ import javax.inject.Qualifier @Retention(AnnotationRetention.RUNTIME) internal annotation class AuthDatabase +@Qualifier +@Retention(AnnotationRetention.RUNTIME) +internal annotation class GlobalDatabase + @Qualifier @Retention(AnnotationRetention.RUNTIME) internal annotation class SessionDatabase diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt index 816a674d81..e51d8f3ad3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt @@ -22,22 +22,30 @@ import android.content.res.Resources import com.squareup.moshi.Moshi import dagger.BindsInstance import dagger.Component +import okhttp3.OkHttpClient import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.MatrixConfiguration import org.matrix.android.sdk.api.auth.AuthenticationService +import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.internal.SessionManager import org.matrix.android.sdk.internal.auth.AuthModule import org.matrix.android.sdk.internal.auth.SessionParamsStore +import org.matrix.android.sdk.internal.raw.RawModule import org.matrix.android.sdk.internal.session.MockHttpInterceptor import org.matrix.android.sdk.internal.session.TestInterceptor import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers -import okhttp3.OkHttpClient import org.matrix.olm.OlmManager import java.io.File -@Component(modules = [MatrixModule::class, NetworkModule::class, AuthModule::class, NoOpTestModule::class]) +@Component(modules = [ + MatrixModule::class, + NetworkModule::class, + AuthModule::class, + RawModule::class, + NoOpTestModule::class +]) @MatrixScope internal interface MatrixComponent { @@ -53,6 +61,8 @@ internal interface MatrixComponent { fun authenticationService(): AuthenticationService + fun rawService(): RawService + fun context(): Context fun matrixConfiguration(): MatrixConfiguration diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultCleanRawCacheTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultCleanRawCacheTask.kt new file mode 100644 index 0000000000..7ab6645244 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultCleanRawCacheTask.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2019 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.internal.raw + +import com.zhuinden.monarchy.Monarchy +import io.realm.kotlin.where +import org.matrix.android.sdk.internal.database.model.RawCacheEntity +import org.matrix.android.sdk.internal.di.GlobalDatabase +import org.matrix.android.sdk.internal.task.Task +import org.matrix.android.sdk.internal.util.awaitTransaction +import javax.inject.Inject + +internal interface CleanRawCacheTask : Task + +internal class DefaultCleanRawCacheTask @Inject constructor( + @GlobalDatabase private val monarchy: Monarchy +) : CleanRawCacheTask { + + override suspend fun execute(params: Unit) { + monarchy.awaitTransaction { realm -> + realm.where() + .findAll() + .deleteAllFromRealm() + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultGetUrlTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultGetUrlTask.kt new file mode 100644 index 0000000000..08594a766b --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultGetUrlTask.kt @@ -0,0 +1,101 @@ +/* + * Copyright 2019 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.internal.raw + +import com.zhuinden.monarchy.Monarchy +import okhttp3.ResponseBody +import org.matrix.android.sdk.api.raw.RawCacheStrategy +import org.matrix.android.sdk.internal.database.model.RawCacheEntity +import org.matrix.android.sdk.internal.database.query.get +import org.matrix.android.sdk.internal.database.query.getOrCreate +import org.matrix.android.sdk.internal.di.GlobalDatabase +import org.matrix.android.sdk.internal.network.executeRequest +import org.matrix.android.sdk.internal.task.Task +import org.matrix.android.sdk.internal.util.awaitTransaction +import java.util.Date +import javax.inject.Inject + +internal interface GetUrlTask : Task { + data class Params( + val url: String, + val rawCacheStrategy: RawCacheStrategy + ) +} + +internal class DefaultGetUrlTask @Inject constructor( + private val rawAPI: RawAPI, + @GlobalDatabase private val monarchy: Monarchy +) : GetUrlTask { + + override suspend fun execute(params: GetUrlTask.Params): String { + return when (params.rawCacheStrategy) { + RawCacheStrategy.NoCache -> doRequest(params.url) + is RawCacheStrategy.TtlCache -> doRequestWithCache( + params.url, + params.rawCacheStrategy.validityDurationInMillis, + params.rawCacheStrategy.strict + ) + RawCacheStrategy.InfiniteCache -> doRequestWithCache( + params.url, + Long.MAX_VALUE, + true + ) + } + } + + private suspend fun doRequest(url: String): String { + return executeRequest(null) { + apiCall = rawAPI.getUrl(url) + } + .string() + } + + private suspend fun doRequestWithCache(url: String, validityDurationInMillis: Long, strict: Boolean): String { + // Get data from cache + var dataFromCache: String? = null + var isCacheValid = false + monarchy.awaitTransaction { realm -> + val entity = RawCacheEntity.get(realm, url) + dataFromCache = entity?.data + isCacheValid = entity != null && Date().time < entity.lastUpdatedTimestamp + validityDurationInMillis + } + + if (dataFromCache != null && isCacheValid) { + return dataFromCache as String + } + + // No cache or outdated cache + val data = try { + doRequest(url) + } catch (throwable: Throwable) { + // In case of error, we can return value from cache even if outdated + return dataFromCache + ?.takeIf { !strict } + ?: throw throwable + } + + // Store cache + monarchy.awaitTransaction { realm -> + val rawCacheEntity = RawCacheEntity.getOrCreate(realm, url) + rawCacheEntity.data = data + rawCacheEntity.lastUpdatedTimestamp = Date().time + } + + return data + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultRawService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultRawService.kt new file mode 100644 index 0000000000..792a0b3aa7 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultRawService.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 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 org.matrix.android.sdk.internal.raw + +import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.raw.RawCacheStrategy +import org.matrix.android.sdk.api.raw.RawService +import org.matrix.android.sdk.api.util.Cancelable +import org.matrix.android.sdk.internal.task.TaskExecutor +import org.matrix.android.sdk.internal.task.configureWith +import java.util.concurrent.TimeUnit +import javax.inject.Inject + +internal class DefaultRawService @Inject constructor( + private val taskExecutor: TaskExecutor, + private val getUrlTask: GetUrlTask, + private val cleanRawCacheTask: CleanRawCacheTask +) : RawService { + override fun getUrl(url: String, + rawCacheStrategy: RawCacheStrategy, + matrixCallback: MatrixCallback): Cancelable { + return getUrlTask + .configureWith(GetUrlTask.Params(url, rawCacheStrategy)) { + callback = matrixCallback + } + .executeBy(taskExecutor) + } + + override fun getWellknown(userId: String, + matrixCallback: MatrixCallback): Cancelable { + val homeServerDomain = userId.substringAfter(":") + return getUrl( + "https://$homeServerDomain/.well-known/matrix/client", + RawCacheStrategy.TtlCache(TimeUnit.HOURS.toMillis(8), false), + matrixCallback + ) + } + + override fun clearCache(matrixCallback: MatrixCallback): Cancelable { + return cleanRawCacheTask + .configureWith(Unit) { + callback = matrixCallback + } + .executeBy(taskExecutor) + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GlobalRealmModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GlobalRealmModule.kt new file mode 100644 index 0000000000..4df5edae88 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GlobalRealmModule.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2019 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.internal.raw + +import io.realm.annotations.RealmModule +import org.matrix.android.sdk.internal.database.model.RawCacheEntity + +/** + * Realm module for global classes + */ +@RealmModule(library = true, + classes = [ + RawCacheEntity::class + ]) +internal class GlobalRealmModule diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawAPI.kt new file mode 100644 index 0000000000..f7aa738e90 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawAPI.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.internal.raw + +import okhttp3.ResponseBody +import retrofit2.Call +import retrofit2.http.GET +import retrofit2.http.Url + +internal interface RawAPI { + @GET + fun getUrl(@Url url: String): Call +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawModule.kt new file mode 100644 index 0000000000..6863ccb0a6 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawModule.kt @@ -0,0 +1,79 @@ +/* + * Copyright 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.internal.raw + +import com.zhuinden.monarchy.Monarchy +import dagger.Binds +import dagger.Lazy +import dagger.Module +import dagger.Provides +import io.realm.RealmConfiguration +import okhttp3.OkHttpClient +import org.matrix.android.sdk.api.raw.RawService +import org.matrix.android.sdk.internal.database.RealmKeysUtils +import org.matrix.android.sdk.internal.di.GlobalDatabase +import org.matrix.android.sdk.internal.di.Unauthenticated +import org.matrix.android.sdk.internal.network.RetrofitFactory + +@Module +internal abstract class RawModule { + + @Module + companion object { + private const val DB_ALIAS = "matrix-sdk-global" + + @JvmStatic + @Provides + @GlobalDatabase + fun providesMonarchy(@GlobalDatabase realmConfiguration: RealmConfiguration): Monarchy { + return Monarchy.Builder() + .setRealmConfiguration(realmConfiguration) + .build() + } + + @JvmStatic + @Provides + @GlobalDatabase + fun providesRealmConfiguration(realmKeysUtils: RealmKeysUtils): RealmConfiguration { + return RealmConfiguration.Builder() + .apply { + realmKeysUtils.configureEncryption(this, DB_ALIAS) + } + .name("matrix-sdk-global.realm") + .modules(GlobalRealmModule()) + .build() + } + + @Provides + @JvmStatic + fun providesRawAPI(@Unauthenticated okHttpClient: Lazy, + retrofitFactory: RetrofitFactory): RawAPI { + return retrofitFactory.create(okHttpClient, "https://example.org").create(RawAPI::class.java) + } + } + + @Binds + abstract fun bindRawService(service: DefaultRawService): RawService + + @Binds + abstract fun bindGetUrlTask(task: DefaultGetUrlTask): GetUrlTask + + @Binds + abstract fun bindCleanRawCacheTask(task: DefaultCleanRawCacheTask): CleanRawCacheTask +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTask.kt index 13ce84cf90..7e1ad600e3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTask.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.homeserver import com.zhuinden.monarchy.Monarchy +import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.auth.wellknown.WellknownResult import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities @@ -32,7 +33,6 @@ import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationMan import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.util.awaitTransaction import org.matrix.android.sdk.internal.wellknown.GetWellknownTask -import org.greenrobot.eventbus.EventBus import timber.log.Timber import java.util.Date import javax.inject.Inject @@ -109,16 +109,12 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( if (getWellknownResult != null && getWellknownResult is WellknownResult.Prompt) { homeServerCapabilitiesEntity.defaultIdentityServerUrl = getWellknownResult.identityServerUrl - homeServerCapabilitiesEntity.adminE2EByDefault = getWellknownResult.wellKnown.e2eAdminSetting?.e2eDefault ?: true - homeServerCapabilitiesEntity.preferredJitsiDomain = getWellknownResult.wellKnown.jitsiServer?.preferredDomain // We are also checking for integration manager configurations val config = configExtractor.extract(getWellknownResult.wellKnown) if (config != null) { Timber.v("Extracted integration config : $config") realm.insertOrUpdate(config) } - } else { - homeServerCapabilitiesEntity.adminE2EByDefault = true } homeServerCapabilitiesEntity.lastUpdatedTimestamp = Date().time } diff --git a/vector/src/main/java/im/vector/app/core/di/VectorComponent.kt b/vector/src/main/java/im/vector/app/core/di/VectorComponent.kt index c6dfd3e10c..c750384485 100644 --- a/vector/src/main/java/im/vector/app/core/di/VectorComponent.kt +++ b/vector/src/main/java/im/vector/app/core/di/VectorComponent.kt @@ -57,6 +57,7 @@ import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.ui.UiStateRepository import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.auth.AuthenticationService +import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.session.Session import javax.inject.Singleton @@ -118,6 +119,8 @@ interface VectorComponent { fun authenticationService(): AuthenticationService + fun rawService(): RawService + fun bugReporter(): BugReporter fun vectorUncaughtExceptionHandler(): VectorUncaughtExceptionHandler diff --git a/vector/src/main/java/im/vector/app/core/di/VectorModule.kt b/vector/src/main/java/im/vector/app/core/di/VectorModule.kt index 87581628e7..1d7cd33241 100644 --- a/vector/src/main/java/im/vector/app/core/di/VectorModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/VectorModule.kt @@ -34,6 +34,7 @@ import im.vector.app.features.ui.UiStateRepository import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.legacy.LegacySessionImporter +import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.session.Session @Module @@ -78,6 +79,12 @@ abstract class VectorModule { fun providesAuthenticationService(matrix: Matrix): AuthenticationService { return matrix.authenticationService() } + + @Provides + @JvmStatic + fun providesRawService(matrix: Matrix): RawService { + return matrix.rawService() + } } @Binds diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt index a122ed2527..911faa4fb9 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt @@ -16,6 +16,7 @@ package im.vector.app.features.createdirect +import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext @@ -23,13 +24,20 @@ import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.homeserver.ElementWellKnownMapper +import im.vector.app.features.homeserver.isE2EByDefault import im.vector.app.features.userdirectory.PendingInvitee +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams +import org.matrix.android.sdk.internal.util.awaitCallback import org.matrix.android.sdk.rx.rx class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted initialState: CreateDirectRoomViewState, + private val rawService: RawService, private val session: Session) : VectorViewModel(initialState) { @@ -54,22 +62,29 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted } private fun createRoomAndInviteSelectedUsers(invitees: Set) { - val roomParams = CreateRoomParams() - .apply { - invitees.forEach { - when (it) { - is PendingInvitee.UserPendingInvitee -> invitedUserIds.add(it.user.userId) - is PendingInvitee.ThreePidPendingInvitee -> invite3pids.add(it.threePid) - }.exhaustive - } - setDirectMessage() - enableEncryptionIfInvitedUsersSupportIt = session.getHomeServerCapabilities().adminE2EByDefault - } + viewModelScope.launch(Dispatchers.IO) { + val adminE2EByDefault = awaitCallback { rawService.getWellknown(session.myUserId, it) } + .let { ElementWellKnownMapper.from(it) } + ?.isE2EByDefault() + ?: true - session.rx() - .createRoom(roomParams) - .execute { - copy(createAndInviteState = it) - } + val roomParams = CreateRoomParams() + .apply { + invitees.forEach { + when (it) { + is PendingInvitee.UserPendingInvitee -> invitedUserIds.add(it.user.userId) + is PendingInvitee.ThreePidPendingInvitee -> invite3pids.add(it.threePid) + }.exhaustive + } + setDirectMessage() + enableEncryptionIfInvitedUsersSupportIt = adminE2EByDefault + } + + session.rx() + .createRoom(roomParams) + .execute { + copy(createAndInviteState = it) + } + } } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index a77d50d767..dc322f92a7 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -42,6 +42,7 @@ import im.vector.app.features.home.room.detail.sticker.StickerPickerActionHandle import im.vector.app.features.home.room.detail.timeline.helper.RoomSummaryHolder import im.vector.app.features.home.room.detail.timeline.helper.TimelineDisplayableEvents import im.vector.app.features.home.room.typing.TypingHelper +import im.vector.app.features.homeserver.ElementWellKnownMapper import im.vector.app.features.powerlevel.PowerLevelsObservableFactory import im.vector.app.features.settings.VectorLocale import im.vector.app.features.settings.VectorPreferences @@ -59,11 +60,12 @@ import org.matrix.android.sdk.api.MatrixPatterns import org.matrix.android.sdk.api.NoOpMatrixCallback import org.matrix.android.sdk.api.extensions.tryThis import org.matrix.android.sdk.api.query.QueryStringValue +import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.events.model.EventType -import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage import org.matrix.android.sdk.api.session.events.model.LocalEcho +import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage import org.matrix.android.sdk.api.session.events.model.isTextMessage import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel @@ -110,6 +112,7 @@ class RoomDetailViewModel @AssistedInject constructor( private val stringProvider: StringProvider, private val rainbowGenerator: RainbowGenerator, private val session: Session, + private val rawService: RawService, private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider, private val stickerPickerActionHandler: StickerPickerActionHandler, private val roomSummaryHolder: RoomSummaryHolder, @@ -349,7 +352,13 @@ class RoomDetailViewModel @AssistedInject constructor( val roomId: String = room.roomId val confId = roomId.substring(1, roomId.indexOf(":") - 1) + widgetSessionId.toLowerCase(VectorLocale.applicationLocale) - val jitsiDomain = session.getHomeServerCapabilities().preferredJitsiDomain ?: stringProvider.getString(R.string.preferred_jitsi_domain) + val preferredJitsiDomain = tryThis { + awaitCallback { rawService.getWellknown(session.myUserId, it) } + .let { ElementWellKnownMapper.from(it) } + ?.jitsiServer + ?.preferredDomain + } + val jitsiDomain = preferredJitsiDomain ?: stringProvider.getString(R.string.preferred_jitsi_domain) // We use the default element wrapper for this widget // https://github.com/vector-im/element-web/blob/develop/docs/jitsi-dev.md diff --git a/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt b/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt index 672fa4c38e..43f66ebca2 100644 --- a/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt @@ -16,18 +16,42 @@ package im.vector.app.features.homeserver +import androidx.lifecycle.viewModelScope +import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject import im.vector.app.core.di.HasScreenInjector import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.userdirectory.KnownUsersFragment +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.extensions.tryThis +import org.matrix.android.sdk.api.raw.RawService +import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities +import org.matrix.android.sdk.internal.util.awaitCallback -class HomeServerCapabilitiesViewModel(initialState: HomeServerCapabilitiesViewState) - : VectorViewModel(initialState) { +class HomeServerCapabilitiesViewModel @AssistedInject constructor( + @Assisted initialState: HomeServerCapabilitiesViewState, + private val session: Session, + private val rawService: RawService +) : VectorViewModel(initialState) { + + @AssistedInject.Factory + interface Factory { + fun create(initialState: HomeServerCapabilitiesViewState): HomeServerCapabilitiesViewModel + } companion object : MvRxViewModelFactory { + @JvmStatic + override fun create(viewModelContext: ViewModelContext, state: HomeServerCapabilitiesViewState): HomeServerCapabilitiesViewModel? { + val fragment: KnownUsersFragment = (viewModelContext as FragmentViewModelContext).fragment() + return fragment.homeServerCapabilitiesViewModelFactory.create(state) + } override fun initialState(viewModelContext: ViewModelContext): HomeServerCapabilitiesViewState? { val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getSafeActiveSession() @@ -37,5 +61,26 @@ class HomeServerCapabilitiesViewModel(initialState: HomeServerCapabilitiesViewSt } } + init { + initAdminE2eByDefault() + } + + private fun initAdminE2eByDefault() { + viewModelScope.launch(Dispatchers.IO) { + val adminE2EByDefault = tryThis { + awaitCallback { rawService.getWellknown(session.myUserId, it) } + .let { ElementWellKnownMapper.from(it) } + ?.isE2EByDefault() + ?: true + } ?: true + + setState { + copy( + isE2EByDefault = adminE2EByDefault + ) + } + } + } + override fun handle(action: EmptyAction) {} } diff --git a/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewState.kt b/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewState.kt index 98df020b6b..14d19b2e6a 100644 --- a/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewState.kt +++ b/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewState.kt @@ -20,5 +20,6 @@ import com.airbnb.mvrx.MvRxState import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities data class HomeServerCapabilitiesViewState( - val capabilities: HomeServerCapabilities = HomeServerCapabilities() + val capabilities: HomeServerCapabilities = HomeServerCapabilities(), + val isE2EByDefault: Boolean = true ) : MvRxState diff --git a/vector/src/main/java/im/vector/app/features/homeserver/WellKnownExt.kt b/vector/src/main/java/im/vector/app/features/homeserver/WellKnownExt.kt new file mode 100644 index 0000000000..f5fbee29f5 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/homeserver/WellKnownExt.kt @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020 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 im.vector.app.features.homeserver + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.internal.di.MoshiProvider + +@JsonClass(generateAdapter = true) +data class ElementWellKnown( + /** + *Preferred Jitsi domain, provided in Wellknown + */ + @Json(name = "im.vector.riot.jitsi") + val jitsiServer: WellKnownPreferredConfig? = null, + + /** + * The settings above were first proposed under a im.vector.riot.e2ee key, which is now deprecated. + * Element will check for either key, preferring io.element.e2ee if both exist. + */ + @Json(name = "io.element.e2ee") + val elementE2E: E2EWellKnownConfig? = null, + + @Json(name = "im.vector.riot.e2ee") + val riotE2E: E2EWellKnownConfig? = null +) + +object ElementWellKnownMapper { + + val adapter: JsonAdapter = MoshiProvider.providesMoshi().adapter(ElementWellKnown::class.java) + + fun from(value: String): ElementWellKnown? { + return adapter.fromJson(value) + } +} + +@JsonClass(generateAdapter = true) +data class E2EWellKnownConfig( + /** + * Option to allow homeserver admins to set the default E2EE behaviour back to disabled for DMs / private rooms + * (as it was before) for various environments where this is desired. + */ + @Json(name = "default") + val e2eDefault: Boolean? = null +) + +@JsonClass(generateAdapter = true) +data class WellKnownPreferredConfig( + @Json(name = "preferredDomain") + val preferredDomain: String? = null +) + +fun ElementWellKnown.isE2EByDefault() = elementE2E?.e2eDefault ?: riotE2E?.e2eDefault ?: true diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt index a9c507ba7a..23cd9797b9 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt @@ -17,6 +17,7 @@ package im.vector.app.features.roomdirectory.createroom import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading @@ -27,15 +28,23 @@ import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.homeserver.ElementWellKnownMapper +import im.vector.app.features.homeserver.isE2EByDefault import im.vector.app.features.roomdirectory.RoomDirectoryActivity +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.extensions.tryThis +import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset +import org.matrix.android.sdk.internal.util.awaitCallback class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: CreateRoomViewState, - private val session: Session + private val session: Session, + private val rawService: RawService ) : VectorViewModel(initialState) { @AssistedInject.Factory @@ -44,11 +53,26 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr } init { - setState { - copy( - isEncrypted = !this.isPublic && session.getHomeServerCapabilities().adminE2EByDefault, - hsAdminHasDisabledE2E = !session.getHomeServerCapabilities().adminE2EByDefault - ) + initAdminE2eByDefault() + } + + private var adminE2EByDefault = true + + private fun initAdminE2eByDefault() { + viewModelScope.launch(Dispatchers.IO) { + adminE2EByDefault = tryThis { + awaitCallback { rawService.getWellknown(session.myUserId, it) } + .let { ElementWellKnownMapper.from(it) } + ?.isE2EByDefault() + ?: true + } ?: true + + setState { + copy( + isEncrypted = !isPublic && adminE2EByDefault, + hsAdminHasDisabledE2E = !adminE2EByDefault + ) + } } } @@ -81,7 +105,7 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr private fun setIsPublic(action: CreateRoomAction.SetIsPublic) = setState { copy( isPublic = action.isPublic, - isEncrypted = !action.isPublic && session.getHomeServerCapabilities().adminE2EByDefault + isEncrypted = !action.isPublic && adminE2EByDefault ) } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt index 2dc35fb653..4508836da1 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt @@ -51,6 +51,8 @@ import im.vector.app.features.crypto.keys.KeysExporter import im.vector.app.features.crypto.keys.KeysImporter import im.vector.app.features.crypto.keysbackup.settings.KeysBackupManageActivity import im.vector.app.features.crypto.recover.BootstrapBottomSheet +import im.vector.app.features.homeserver.ElementWellKnownMapper +import im.vector.app.features.homeserver.isE2EByDefault import im.vector.app.features.navigation.Navigator import im.vector.app.features.pin.PinActivity import im.vector.app.features.pin.PinCodeStore @@ -151,8 +153,14 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( disposables.add(it) } - val e2eByDefault = session.getHomeServerCapabilities().adminE2EByDefault - findPreference(VectorPreferences.SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT)?.isVisible = !e2eByDefault + vectorActivity.getVectorComponent() + .rawService() + .getWellknown(session.myUserId, object : MatrixCallback { + override fun onSuccess(data: String) { + findPreference(VectorPreferences.SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT)?.isVisible = + ElementWellKnownMapper.from(data)?.isE2EByDefault() == false + } + }) } private val secureBackupCategory by lazy { @@ -273,8 +281,6 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( text = getString(R.string.settings_hs_admin_e2e_disabled) textColor = ContextCompat.getColor(requireContext(), R.color.riotx_destructive_accent) } - - it.isVisible = session.getHomeServerCapabilities().adminE2EByDefault } } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt b/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt index 07c77bfdd4..c832fe4833 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt @@ -29,7 +29,6 @@ import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import com.google.android.material.chip.Chip import com.jakewharton.rxbinding3.widget.textChanges -import org.matrix.android.sdk.api.session.user.model.User import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith @@ -39,12 +38,14 @@ import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.DimensionConverter import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel import kotlinx.android.synthetic.main.fragment_known_users.* +import org.matrix.android.sdk.api.session.user.model.User import javax.inject.Inject class KnownUsersFragment @Inject constructor( val userDirectoryViewModelFactory: UserDirectoryViewModel.Factory, private val knownUsersController: KnownUsersController, - private val dimensionConverter: DimensionConverter + private val dimensionConverter: DimensionConverter, + val homeServerCapabilitiesViewModelFactory: HomeServerCapabilitiesViewModel.Factory ) : VectorBaseFragment(), KnownUsersController.Callback { private val args: KnownUsersFragmentArgs by args() @@ -71,7 +72,7 @@ class KnownUsersFragment @Inject constructor( setupCloseView() homeServerCapabilitiesViewModel.subscribe { - knownUsersE2EbyDefaultDisabled.isVisible = !it.capabilities.adminE2EByDefault + knownUsersE2EbyDefaultDisabled.isVisible = !it.isE2EByDefault } viewModel.selectSubscribe(this, UserDirectoryViewState::pendingInvitees) { From 161470794366e75362dd3155560939a1f165664e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 16 Sep 2020 16:58:27 +0200 Subject: [PATCH 80/89] Ganfra's review --- .../sdk/internal/raw/DefaultGetUrlTask.kt | 2 +- .../createdirect/CreateDirectRoomViewModel.kt | 8 ++--- .../home/room/detail/RoomDetailViewModel.kt | 5 ++-- .../HomeServerCapabilitiesViewModel.kt | 6 ++-- .../wellknown/ElementWellKnown.kt} | 17 ++--------- .../raw/wellknown/ElementWellKnownExt.kt | 27 +++++++++++++++++ .../raw/wellknown/ElementWellKnownMapper.kt | 29 +++++++++++++++++++ .../createroom/CreateRoomViewModel.kt | 8 ++--- .../VectorSettingsSecurityPrivacyFragment.kt | 4 +-- 9 files changed, 72 insertions(+), 34 deletions(-) rename vector/src/main/java/im/vector/app/features/{homeserver/WellKnownExt.kt => raw/wellknown/ElementWellKnown.kt} (77%) create mode 100644 vector/src/main/java/im/vector/app/features/raw/wellknown/ElementWellKnownExt.kt create mode 100644 vector/src/main/java/im/vector/app/features/raw/wellknown/ElementWellKnownMapper.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultGetUrlTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultGetUrlTask.kt index 08594a766b..1733abccd4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultGetUrlTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultGetUrlTask.kt @@ -69,7 +69,7 @@ internal class DefaultGetUrlTask @Inject constructor( // Get data from cache var dataFromCache: String? = null var isCacheValid = false - monarchy.awaitTransaction { realm -> + monarchy.doWithRealm { realm -> val entity = RawCacheEntity.get(realm, url) dataFromCache = entity?.data isCacheValid = entity != null && Date().time < entity.lastUpdatedTimestamp + validityDurationInMillis diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt index 911faa4fb9..56114cdb4b 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt @@ -24,15 +24,14 @@ import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel -import im.vector.app.features.homeserver.ElementWellKnownMapper -import im.vector.app.features.homeserver.isE2EByDefault +import im.vector.app.features.raw.wellknown.getElementWellknown +import im.vector.app.features.raw.wellknown.isE2EByDefault import im.vector.app.features.userdirectory.PendingInvitee import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams -import org.matrix.android.sdk.internal.util.awaitCallback import org.matrix.android.sdk.rx.rx class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted @@ -63,8 +62,7 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted private fun createRoomAndInviteSelectedUsers(invitees: Set) { viewModelScope.launch(Dispatchers.IO) { - val adminE2EByDefault = awaitCallback { rawService.getWellknown(session.myUserId, it) } - .let { ElementWellKnownMapper.from(it) } + val adminE2EByDefault = rawService.getElementWellknown(session.myUserId) ?.isE2EByDefault() ?: true diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index dc322f92a7..4395acc153 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -42,8 +42,8 @@ import im.vector.app.features.home.room.detail.sticker.StickerPickerActionHandle import im.vector.app.features.home.room.detail.timeline.helper.RoomSummaryHolder import im.vector.app.features.home.room.detail.timeline.helper.TimelineDisplayableEvents import im.vector.app.features.home.room.typing.TypingHelper -import im.vector.app.features.homeserver.ElementWellKnownMapper import im.vector.app.features.powerlevel.PowerLevelsObservableFactory +import im.vector.app.features.raw.wellknown.getElementWellknown import im.vector.app.features.settings.VectorLocale import im.vector.app.features.settings.VectorPreferences import io.reactivex.Observable @@ -353,8 +353,7 @@ class RoomDetailViewModel @AssistedInject constructor( val confId = roomId.substring(1, roomId.indexOf(":") - 1) + widgetSessionId.toLowerCase(VectorLocale.applicationLocale) val preferredJitsiDomain = tryThis { - awaitCallback { rawService.getWellknown(session.myUserId, it) } - .let { ElementWellKnownMapper.from(it) } + rawService.getElementWellknown(session.myUserId) ?.jitsiServer ?.preferredDomain } diff --git a/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt b/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt index 43f66ebca2..0252f20425 100644 --- a/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt @@ -26,6 +26,8 @@ import im.vector.app.core.di.HasScreenInjector import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.raw.wellknown.getElementWellknown +import im.vector.app.features.raw.wellknown.isE2EByDefault import im.vector.app.features.userdirectory.KnownUsersFragment import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -33,7 +35,6 @@ import org.matrix.android.sdk.api.extensions.tryThis import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities -import org.matrix.android.sdk.internal.util.awaitCallback class HomeServerCapabilitiesViewModel @AssistedInject constructor( @Assisted initialState: HomeServerCapabilitiesViewState, @@ -68,8 +69,7 @@ class HomeServerCapabilitiesViewModel @AssistedInject constructor( private fun initAdminE2eByDefault() { viewModelScope.launch(Dispatchers.IO) { val adminE2EByDefault = tryThis { - awaitCallback { rawService.getWellknown(session.myUserId, it) } - .let { ElementWellKnownMapper.from(it) } + rawService.getElementWellknown(session.myUserId) ?.isE2EByDefault() ?: true } ?: true diff --git a/vector/src/main/java/im/vector/app/features/homeserver/WellKnownExt.kt b/vector/src/main/java/im/vector/app/features/raw/wellknown/ElementWellKnown.kt similarity index 77% rename from vector/src/main/java/im/vector/app/features/homeserver/WellKnownExt.kt rename to vector/src/main/java/im/vector/app/features/raw/wellknown/ElementWellKnown.kt index f5fbee29f5..dc8090bc7c 100644 --- a/vector/src/main/java/im/vector/app/features/homeserver/WellKnownExt.kt +++ b/vector/src/main/java/im/vector/app/features/raw/wellknown/ElementWellKnown.kt @@ -14,17 +14,15 @@ * limitations under the License. */ -package im.vector.app.features.homeserver +package im.vector.app.features.raw.wellknown import com.squareup.moshi.Json -import com.squareup.moshi.JsonAdapter import com.squareup.moshi.JsonClass -import org.matrix.android.sdk.internal.di.MoshiProvider @JsonClass(generateAdapter = true) data class ElementWellKnown( /** - *Preferred Jitsi domain, provided in Wellknown + * Preferred Jitsi domain */ @Json(name = "im.vector.riot.jitsi") val jitsiServer: WellKnownPreferredConfig? = null, @@ -40,15 +38,6 @@ data class ElementWellKnown( val riotE2E: E2EWellKnownConfig? = null ) -object ElementWellKnownMapper { - - val adapter: JsonAdapter = MoshiProvider.providesMoshi().adapter(ElementWellKnown::class.java) - - fun from(value: String): ElementWellKnown? { - return adapter.fromJson(value) - } -} - @JsonClass(generateAdapter = true) data class E2EWellKnownConfig( /** @@ -64,5 +53,3 @@ data class WellKnownPreferredConfig( @Json(name = "preferredDomain") val preferredDomain: String? = null ) - -fun ElementWellKnown.isE2EByDefault() = elementE2E?.e2eDefault ?: riotE2E?.e2eDefault ?: true diff --git a/vector/src/main/java/im/vector/app/features/raw/wellknown/ElementWellKnownExt.kt b/vector/src/main/java/im/vector/app/features/raw/wellknown/ElementWellKnownExt.kt new file mode 100644 index 0000000000..82f989342e --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/raw/wellknown/ElementWellKnownExt.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 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 im.vector.app.features.raw.wellknown + +import org.matrix.android.sdk.api.raw.RawService +import org.matrix.android.sdk.internal.util.awaitCallback + +suspend fun RawService.getElementWellknown(userId: String): ElementWellKnown? { + return awaitCallback { getWellknown(userId, it) } + .let { ElementWellKnownMapper.from(it) } +} + +fun ElementWellKnown.isE2EByDefault() = elementE2E?.e2eDefault ?: riotE2E?.e2eDefault ?: true diff --git a/vector/src/main/java/im/vector/app/features/raw/wellknown/ElementWellKnownMapper.kt b/vector/src/main/java/im/vector/app/features/raw/wellknown/ElementWellKnownMapper.kt new file mode 100644 index 0000000000..07e496f85f --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/raw/wellknown/ElementWellKnownMapper.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 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 im.vector.app.features.raw.wellknown + +import com.squareup.moshi.JsonAdapter +import org.matrix.android.sdk.internal.di.MoshiProvider + +object ElementWellKnownMapper { + + val adapter: JsonAdapter = MoshiProvider.providesMoshi().adapter(ElementWellKnown::class.java) + + fun from(value: String): ElementWellKnown? { + return adapter.fromJson(value) + } +} diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt index 23cd9797b9..be4bbed15b 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt @@ -28,8 +28,8 @@ import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel -import im.vector.app.features.homeserver.ElementWellKnownMapper -import im.vector.app.features.homeserver.isE2EByDefault +import im.vector.app.features.raw.wellknown.getElementWellknown +import im.vector.app.features.raw.wellknown.isE2EByDefault import im.vector.app.features.roomdirectory.RoomDirectoryActivity import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -40,7 +40,6 @@ import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset -import org.matrix.android.sdk.internal.util.awaitCallback class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: CreateRoomViewState, private val session: Session, @@ -61,8 +60,7 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr private fun initAdminE2eByDefault() { viewModelScope.launch(Dispatchers.IO) { adminE2EByDefault = tryThis { - awaitCallback { rawService.getWellknown(session.myUserId, it) } - .let { ElementWellKnownMapper.from(it) } + rawService.getElementWellknown(session.myUserId) ?.isE2EByDefault() ?: true } ?: true diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt index 4508836da1..034fa617f0 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt @@ -51,13 +51,13 @@ import im.vector.app.features.crypto.keys.KeysExporter import im.vector.app.features.crypto.keys.KeysImporter import im.vector.app.features.crypto.keysbackup.settings.KeysBackupManageActivity import im.vector.app.features.crypto.recover.BootstrapBottomSheet -import im.vector.app.features.homeserver.ElementWellKnownMapper -import im.vector.app.features.homeserver.isE2EByDefault import im.vector.app.features.navigation.Navigator import im.vector.app.features.pin.PinActivity import im.vector.app.features.pin.PinCodeStore import im.vector.app.features.pin.PinLocker import im.vector.app.features.pin.PinMode +import im.vector.app.features.raw.wellknown.ElementWellKnownMapper +import im.vector.app.features.raw.wellknown.isE2EByDefault import im.vector.app.features.themes.ThemeUtils import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable From b97aed0723c8f44137c5572ff0ef63e63bf5e74b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 16 Sep 2020 17:00:14 +0200 Subject: [PATCH 81/89] Ganfra's review --- .../main/java/org/matrix/android/sdk/internal/raw/RawModule.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawModule.kt index 6863ccb0a6..95de057f04 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawModule.kt @@ -28,6 +28,7 @@ import okhttp3.OkHttpClient import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.internal.database.RealmKeysUtils import org.matrix.android.sdk.internal.di.GlobalDatabase +import org.matrix.android.sdk.internal.di.MatrixScope import org.matrix.android.sdk.internal.di.Unauthenticated import org.matrix.android.sdk.internal.network.RetrofitFactory @@ -50,6 +51,7 @@ internal abstract class RawModule { @JvmStatic @Provides @GlobalDatabase + @MatrixScope fun providesRealmConfiguration(realmKeysUtils: RealmKeysUtils): RealmConfiguration { return RealmConfiguration.Builder() .apply { From 762fd02eb793b39e64e1bd9eebe5ab985a5ddcd4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 16 Sep 2020 19:32:03 +0200 Subject: [PATCH 82/89] Format strings.xml --- .../src/main/res/values-ar/strings.xml | 18 +-- .../src/main/res/values-es/strings.xml | 16 +-- .../src/main/res/values-sk/strings.xml | 34 +++--- vector/src/main/res/values-cs/strings.xml | 58 +++++----- vector/src/main/res/values-de/strings.xml | 2 +- vector/src/main/res/values-es/strings.xml | 56 ++++----- vector/src/main/res/values-et/strings.xml | 2 +- vector/src/main/res/values-it/strings.xml | 2 +- vector/src/main/res/values-kab/strings.xml | 108 +++++++++--------- vector/src/main/res/values-ru/strings.xml | 34 +++--- vector/src/main/res/values-sv/strings.xml | 2 +- vector/src/main/res/values-zh-rCN/strings.xml | 2 +- vector/src/main/res/values-zh-rTW/strings.xml | 2 +- 13 files changed, 168 insertions(+), 168 deletions(-) diff --git a/matrix-sdk-android/src/main/res/values-ar/strings.xml b/matrix-sdk-android/src/main/res/values-ar/strings.xml index 5f4603ec6e..0fc7bd1b49 100644 --- a/matrix-sdk-android/src/main/res/values-ar/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ar/strings.xml @@ -71,15 +71,15 @@ دعوة إلى غرفة - - - - - - - + + + + + + + -أرسلت صورة. + أرسلت صورة. أرسلت ملصقًا. دعوة منك أنت @@ -144,4 +144,4 @@ المزامنة الأولية: \nيستورد الحساب… - + diff --git a/matrix-sdk-android/src/main/res/values-es/strings.xml b/matrix-sdk-android/src/main/res/values-es/strings.xml index bf965a37f3..1b1935602c 100644 --- a/matrix-sdk-android/src/main/res/values-es/strings.xml +++ b/matrix-sdk-android/src/main/res/values-es/strings.xml @@ -147,7 +147,7 @@ %s solicita verificar su clave, pero su cliente no soporta la verificación de la clave en chat. Necesitará usar la verificación de claves clásica para poder verificar las claves. -Enviaste una imagen. + Enviaste una imagen. Enviaste un sticker. Tu invitación @@ -220,14 +220,14 @@ Retiró la invitación de %1$s\'s. Motivo: %2$s - Agregaste %1$s como dirección para esta sala. - Agregaste %1$s como direcciones para esta sala. - + Agregaste %1$s como dirección para esta sala. + Agregaste %1$s como direcciones para esta sala. + - Quitaste %1$s como dirección para esta sala. - Quitaste %2$s como direcciones para esta sala. - + Quitaste %1$s como dirección para esta sala. + Quitaste %2$s como direcciones para esta sala. + "%1$s agregó %2$s y eliminó %3$s como direcciones para esta sala." Agregaste %1$s y quitaste %2$s como direcciones para esta sala. @@ -241,4 +241,4 @@ Activó el cifrado de extremo a extremo. Activó el cifrado de un extremo a otro (algoritmo %1$s no reconocido). - + diff --git a/matrix-sdk-android/src/main/res/values-sk/strings.xml b/matrix-sdk-android/src/main/res/values-sk/strings.xml index 6eeb380ccd..da869eacc2 100644 --- a/matrix-sdk-android/src/main/res/values-sk/strings.xml +++ b/matrix-sdk-android/src/main/res/values-sk/strings.xml @@ -71,7 +71,7 @@ %1$s a 1 ďalší %1$s a %2$d ďalší %1$s a %2$d ďalších - + @@ -118,16 +118,16 @@ %1$s vzal/a späť pozvanie %2$s. Dôvod: %3$s - %1$s pridal/a adresu %2$s pre túto miestnosť. - %1$s pridal/a adresy %2$s pre túto miestnosť. - %1$s pridal/a adresy %2$s pre túto miestnosť. - + %1$s pridal/a adresu %2$s pre túto miestnosť. + %1$s pridal/a adresy %2$s pre túto miestnosť. + %1$s pridal/a adresy %2$s pre túto miestnosť. + - %1$s odstránil/a adresu %2$s pre túto miestnosť. - %1$s odstránil/a adresy %3$s pre túto miestnosť. - %1$s odstránil/a adresy %3$s pre túto miestnosť. - + %1$s odstránil/a adresu %2$s pre túto miestnosť. + %1$s odstránil/a adresy %3$s pre túto miestnosť. + %1$s odstránil/a adresy %3$s pre túto miestnosť. + %1$s pridal/a adresy %2$s a odstránil/a adresy %3$s pre túto miestnosť. @@ -208,16 +208,16 @@ Vzali ste späť pozvanie %1$s. Dôvod: %2$s - Pridali ste adresu %1$s pre túto miestnosť. - Pridali ste adresy %1$s pre túto miestnosť. - Pridali ste adresy %1$s pre túto miestnosť. - + Pridali ste adresu %1$s pre túto miestnosť. + Pridali ste adresy %1$s pre túto miestnosť. + Pridali ste adresy %1$s pre túto miestnosť. + - Odstránili ste adresu %1$s pre túto miestnosť. - Odstránili ste adresy %2$s pre túto miestnosť. - Odstránili ste adresy %2$s pre túto miestnosť. - + Odstránili ste adresu %1$s pre túto miestnosť. + Odstránili ste adresy %2$s pre túto miestnosť. + Odstránili ste adresy %2$s pre túto miestnosť. + Pridali ste %1$s a odstránili adresy %2$s pre túto miestnosť. diff --git a/vector/src/main/res/values-cs/strings.xml b/vector/src/main/res/values-cs/strings.xml index ab940936a8..9a36defc05 100644 --- a/vector/src/main/res/values-cs/strings.xml +++ b/vector/src/main/res/values-cs/strings.xml @@ -349,10 +349,10 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. 1 člen - 1s - %ds - %ds - + 1s + %ds + %ds + 1 min %d min @@ -1043,10 +1043,10 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Stahuji klíče… Importuji klíče… - Obnovena záloha s %d klíčem. - Obnovena záloha se %d klíči. - Obnovena záloha s %d klíči. - + Obnovena záloha s %d klíčem. + Obnovena záloha se %d klíči. + Obnovena záloha s %d klíči. + Do této relace byl přidán %d nový klíč. Do této relace byly přidány %d nové klíče. @@ -1105,10 +1105,10 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. %1$s: %2$d zpráv - %d oznámení - %d oznámení - %d oznámeních - + %d oznámení + %d oznámení + %d oznámeních + %1$s v %2$s Nová událost @@ -2364,7 +2364,7 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Zadejte URL serveru identit Odeslat -Přehrát + Přehrát Pozastavit Zavrhnout @@ -2456,18 +2456,18 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Správa emailových adres a telefonních čísel spojených s Vaším účtem v Matrix - %d vykázaný uživatel - %d vykázaní uživatelé - %d vykázaných uživatelů - + %d vykázaný uživatel + %d vykázaní uživatelé + %d vykázaných uživatelů + Klíče úspěšně exportovány - %1$d/%2$d klíč úspěšně importován. - %1$d/%2$d klíče úspěšně importovány. - %1$d/%2$d klíčů úspěšně importováno. - + %1$d/%2$d klíč úspěšně importován. + %1$d/%2$d klíče úspěšně importovány. + %1$d/%2$d klíčů úspěšně importováno. + NÁHLED Aktivní widgety @@ -2491,10 +2491,10 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Kód - %1$s, %2$s a %3$d další přečtena - %1$s, %2$s a %3$d další přečteny - %1$s, %2$s a %3$d dalších přečteno - + %1$s, %2$s a %3$d další přečtena + %1$s, %2$s a %3$d další přečteny + %1$s, %2$s a %3$d dalších přečteno + Přidat k oblíbeným Odstranit z oblíbených Neučinili jste žádné změny @@ -2593,10 +2593,10 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. Push oznámení jsou vypnuta Projděte svá nastavení, abyste zapnuli push oznámení - "Nesprávný kód, zbývá %d pokus" - "Nesprávný kód, zbývají %d pokusy" - "Nesprávný kód, zbývá %d pokusů" - + "Nesprávný kód, zbývá %d pokus" + "Nesprávný kód, zbývají %d pokusy" + "Nesprávný kód, zbývá %d pokusů" + Varování! Zbývá poslední pokus před odhlášením! Příliš mnoho chyb, byli jste odhlášeni Zvolte PIN pro zabezpečení diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml index afba1d7fda..87bce39b88 100644 --- a/vector/src/main/res/values-de/strings.xml +++ b/vector/src/main/res/values-de/strings.xml @@ -2658,7 +2658,7 @@ Verwahre deinen Wiederherstellungsschlüssel an einem sehr sicheren Ort wie eine Warnung! Letzter Versuch bevor du ausgeloggt wirst! Zu viele Fehler, du bist ausgeloggt worden -Diese Telefonnummer ist bereits registriert. + Diese Telefonnummer ist bereits registriert. Deinem Konto wurde keine Telefonnummer hinzugefügt E-mail-Adressen Deinem Konto wurde keine E-Mail hinzugefügt diff --git a/vector/src/main/res/values-es/strings.xml b/vector/src/main/res/values-es/strings.xml index 4b965bf214..ff7cc505ef 100644 --- a/vector/src/main/res/values-es/strings.xml +++ b/vector/src/main/res/values-es/strings.xml @@ -2129,7 +2129,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Para resetear su PIN, debe iniciar sección y crear uno nuevo. Establecer PIN Si decea resetear su PIN, toque Olvidé PIN para cerrar sesión y restablecer. -Numeros telefonicos + Numeros telefonicos Correos y numeros telefonicos Administre el correo y numero telefonico de su cuenta @@ -2182,16 +2182,16 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Habilite \'Permitir integraciones\' en Configuración para hacer esto. - %d usuario prohibido - %d usuarios prohibidos - + %d usuario prohibido + %d usuarios prohibidos + Claves exportadas correctamente - %1$d/%2$d clave importada con éxito. - %1$d/%2$d claves importadas con éxito. - + %1$d/%2$d clave importada con éxito. + %1$d/%2$d claves importadas con éxito. + %1$s: %2$s %1$s: %2$s %3$s @@ -2219,9 +2219,9 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu El código de verificación no es correcto. - %1$s, %2$s y %3$d otra lectura - %1$s, %2$s y %3$d otras lecturas - + %1$s, %2$s y %3$d otra lectura + %1$s, %2$s y %3$d otras lecturas + MEDIO No hay medios en esta sala %1$s a %2$s @@ -2310,9 +2310,9 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Este servidor doméstico está ejecutando una versión demasiado antigua para conectarse. Pídale al administrador de su servidor doméstico que actualice. - Se han enviado demasiadas solicitudes. Puedes volver a intentarlo en %1$d segundo… - Se han enviado demasiadas solicitudes. Puedes volver a intentarlo en %1$d segundos… - + Se han enviado demasiadas solicitudes. Puedes volver a intentarlo en %1$d segundo… + Se han enviado demasiadas solicitudes. Puedes volver a intentarlo en %1$d segundos… + Alternativamente, si ya tiene una cuenta y conoce su identificador Matrix y su contraseña, puede usar este método: Iniciar sesión con Matrix ID @@ -2396,9 +2396,9 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Verifique esta sesión para marcarla como confiable y otorgarle acceso a mensajes encriptados. Si no inició sesión en esta sesión, su cuenta puede verse comprometida: - %d sesión activa - %d sesiones activas - + %d sesión activa + %d sesiones activas + Utilice una sesión existente para verificar esta, otorgándole acceso a los mensajes cifrados. @@ -2410,13 +2410,13 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu ¡Casi ahí! ¿Es %s muestra el mismo escudo\? - %d voto - %d votos - + %d voto + %d votos + - %d voto - Resultados finales - %d votos - Resultados finales - + %d voto - Resultados finales + %d votos - Resultados finales + Crea una encuesta simple Use una contraseña o clave de recuperación Si no puede acceder a una sesión existente @@ -2427,9 +2427,9 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu ¿Quieres enviar este adjunto a %1$s\? - Enviar imagen con el tamaño original - Envía imágenes con el tamaño original - + Enviar imagen con el tamaño original + Envía imágenes con el tamaño original + Confirmar eliminación ¿Está seguro de que desea eliminar (eliminar) este evento\? Tenga en cuenta que si elimina el nombre de una sala o el cambio de tema, podría deshacer el cambio. @@ -2651,9 +2651,9 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Las notificaciones push están deshabilitadas Revise su configuración para habilitar las notificaciones push - Código incorrecto, %d intento restante - Código incorrecto, %d intentos restantes - + Código incorrecto, %d intento restante + Código incorrecto, %d intentos restantes + ¡Advertencia! ¡Último intento restante antes de cerrar sesión! Demasiados errores, se ha desconectado Elija un PIN por seguridad diff --git a/vector/src/main/res/values-et/strings.xml b/vector/src/main/res/values-et/strings.xml index 2825586f55..0e7d171a5c 100644 --- a/vector/src/main/res/values-et/strings.xml +++ b/vector/src/main/res/values-et/strings.xml @@ -2526,7 +2526,7 @@ Hoiatus! Viimane katse enne väljalogimist! Liiga palju vigu PIN-koodi sisestamisel ning sa oled nüüd välja logitud -See telefoninumber on juba määratletud. + See telefoninumber on juba määratletud. Ühtegi telefoninumbrit pole sinu kasutajakontoga seotud E-posti aadressid Ühtegi e-posti aadressi pole sinu kasutajakontoga seotud diff --git a/vector/src/main/res/values-it/strings.xml b/vector/src/main/res/values-it/strings.xml index b9c357a0ef..d5502208c7 100644 --- a/vector/src/main/res/values-it/strings.xml +++ b/vector/src/main/res/values-it/strings.xml @@ -2654,7 +2654,7 @@ Attenzione! Ultimo tentativo rimasto prima di venire disconnesso! Troppi errori, sei stato disconnesso -Questo numero di telefono è già definito. + Questo numero di telefono è già definito. Nessun numero di telefono aggiunto al tuo account Indirizzi email Nessuna email aggiunta al tuo account diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index 0b6e91e972..e435c7cdb9 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -263,9 +263,9 @@ Asenqed n tɣimit URL n uqeddac agejdan - %d n ulɣu - %d n ilɣa - + %d n ulɣu + %d n ilɣa + Taxxamt Nek @@ -1282,9 +1282,9 @@ Asentel Alguritm - 1 texxamt - %d texxamin - + 1 texxamt + %d texxamin + %1$s: %2$s Meẓẓiy @@ -1325,7 +1325,7 @@ Ur tezmireḍ ara ad tkecmeḍ ɣer yizen-a acku tiɣimit-ik·im ur tt-yeḍmin ara umazan Ur tezmire ara ad tkecmeḍ ɣer yizen-a acku amazan iɛemmed ur d-yuzin ara tisura S tumert meqqren ara ak-d-nini nbeddel isem! Asnas-ik·im yettwaleqqem, ha-t-an tkecmeḍ ɣer umiḍan-ik·im. -Uṭṭun-a n tilifun yettusbadu yakan. + Uṭṭun-a n tilifun yettusbadu yakan. Awal-ik·im uffir yettuwennez. \n \nAql-ak·akem teffɣeḍ seg meṛṛa tiɣimiyin syen ur d-teṭṭifeḍ ara akk ilɣa n Push. I wakken ad talseḍ armad n yilɣa, kcem tikkelt-nniḍen ɣer yal ibenk. @@ -1529,9 +1529,9 @@ Yal win·tin yessnen aseɣwen n texxamt rnu-d ɣer-sen inebgawen - %d yezgel aseqdac - %d yezgel iseqdacen - + %d yezgel aseqdac + %d yezgel iseqdacen + Asulay n texxamt tagensant Awgelhen seg yixef ɣer yixef yettwarmed @@ -1583,9 +1583,9 @@ Wgelhen i usenqed n tɣimiyinkan Ur ttazen ara akk iznan yettwawgelhen ɣer tɣimiyin ur nettusenqad ara seg tɣimit-a. - %1$d/%2$d tasarut tettwasifeḍ akken iwata. - %1$d/%2$d tisura ttwasifḍen akken iwata. - + %1$d/%2$d tasarut tettwasifeḍ akken iwata. + %1$d/%2$d tisura ttwasifḍen akken iwata. + Ur yettwasenqed ara Deg tebdart taberkant @@ -1608,9 +1608,9 @@ Aru da… - %1$s: 1 yizen - %1$s: %2$d yiznan - + %1$s: 1 yizen + %1$s: %2$d yiznan + %1$s deg %2$s Tadyant tamaynut Iznan imaynuten @@ -1620,9 +1620,9 @@ Timerna n uwiǧit ur teddi ara S tidet tebɣiḍ ad tekkseḍ awiǧit seg texxamt-a\? - 1 uwiǧit i yettwaremden - %d n yiwiǧiten i yettwaremden - + 1 uwiǧit i yettwaremden + %d n yiwiǧiten i yettwaremden + Nesḥassef, asarag s usiwel s Jitsi ur yettusefrak ara ɣef yibenkan iqburen (ibenkan s Android OS ddaw 5.0) Iwiǧit-a yebɣa ad isseqdec tiɣbula-a: Seqdec takamiṛat @@ -1859,13 +1859,13 @@ Tixxamin meṛṛa tidiganin %s - 1 yizen i d-yettwalɣu ur yettwaɣra ara - %d yiznan i d-yettwalɣun ur ttwaɣran ara - + 1 yizen i d-yettwalɣu ur yettwaɣra ara + %d yiznan i d-yettwalɣun ur ttwaɣran ara + - 1 yizen i d-yettwalɣu ur yettwaɣra ara - %d yiznan i d-yettwalɣun ur ttwaɣran ara - + 1 yizen i d-yettwalɣu ur yettwaɣra ara + %d yiznan i d-yettwalɣun ur ttwaɣran ara + Rnu isaragen s usiwel s jitsi Ɣer amidyat yemmestnen s DRM @@ -1932,13 +1932,13 @@ Aktar n tsura… Aḥraz yettwarr-d %s! - Yerra-d aḥraz s tsarut %d. - Yerra-d aḥraz s tsura %d. - + Yerra-d aḥraz s tsarut %d. + Yerra-d aḥraz s tsura %d. + - %d tasarut tamaynut tettwarn ɣer tɣimit. - %d tisura timaynutin ttwarnant ɣer tɣimit. - + %d tasarut tamaynut tettwarn ɣer tɣimit. + %d tisura timaynutin ttwarnant ɣer tɣimit. + Tiririt n lqem akk aneggaru n tsura (%s) ur teddi ara. Awgelhan n tɣimit ur yettwarmed ara @@ -1977,9 +1977,9 @@ Sbadu aḥraz aɣelsan - Aḥraz n tsarut %d… - Aḥraz n tsura %d… - + Aḥraz n tsarut %d… + Aḥraz n tsura %d… + Iɣewwaren n uqeddac ummid awurman Element yufa-d tawila n uqeddac udmawan i taɣult usulay--inek·inem n uqeddac \"%1$s\": @@ -2175,9 +2175,9 @@ Aqeddac-a agejdan isselkam lqem aqbur maḍi i tuqqna ɣer-s. Suter anedbal n uqeddac-ik·im aqejden ad t-tleqqemḍ. - Aṭas n yisutar i yettwaznen. Tzemreḍ ad tɛerḍeḍ ticki deg %1$d tasint… - Aṭas n yisutar i yettwaznen. Tzemreḍ ad tɛerḍeḍ ticki deg %1$d tsinin… - + Aṭas n yisutar i yettwaznen. Tzemreḍ ad tɛerḍeḍ ticki deg %1$d tasint… + Aṭas n yisutar i yettwaznen. Tzemreḍ ad tɛerḍeḍ ticki deg %1$d tsinin… + Neɣ ma ulac, ma yella tesɛiḍ yakan amiḍan yerna tessneḍ inekcam-inek·inem n Matrix d wawal-inek·inem uffir, tzemreḍ ad tesqedceḍ tarrayt-a: Ma yella tesbaduḍ amiḍan ɣef uqeddac agejdan, seqdec asulay-inek·inem n Matrix (am. @user:domain.com) d wawal uffir ddaw. @@ -2240,9 +2240,9 @@ Tigawin n unedbal Iɣewwaren n texxamt - Yiwen umdan - %1$d yimdanen - + Yiwen umdan + %1$d yimdanen + Tuffɣa seg texxamt… Imaẓragen @@ -2294,9 +2294,9 @@ Senqed tiɣimit-a i wakken ad tt-tcerḍeḍ tettwattkal & anef-as ad tekcem ɣer yiznan yettwawgelhen. Ma yella ur teqqineḍ ara ɣer tɣimit-a, amiḍan-inek·inem yezmer ad yettwaker: - %d tɣimit t ururmidt - %d tɣimiyin turmidin - + %d tɣimit t ururmidt + %d tɣimiyin turmidin + Yemmed s wudem aɣelsan @@ -2318,13 +2318,13 @@ Ifecka n tneflit - %d tafrant - %d tifranin - + %d tafrant + %d tifranin + - %d tafrant - Igmaḍ n taggara - %d tifranin - Igmaḍ n taggara - + %d tafrant - Igmaḍ n taggara + %d tifranin - Igmaḍ n taggara + Yerna assenqed afessas Seqdec tafyirt tuffirt n tririt neɣ tasarut Ma yella ur tezmireḍ ara ad tkecmeḍ ɣer tɣimit i yellan @@ -2335,9 +2335,9 @@ Kkes… Tebqiḍ ad tazneḍ taceqquft-a yaddan i %1$s\? - Azen tugna s teɣzi taneẓlit - Azen tuniwin s teɣzi taneẓlit - + Azen tugna s teɣzi taneẓlit + Azen tuniwin s teɣzi taneẓlit + Rnu taɣzint Taɣzint n tukksa @@ -2455,7 +2455,7 @@ Araǧu n izen-a, aya yezmer ad yeṭṭef akud Ur tezmireḍ ara ad teldiḍ taxxamt ansi i d-tettwagedleḍ. Ur nessaweḍ ara ad d-naf taxamt-a. Muqel ma tella d tidet. -Senqes deg wazal + Senqes deg wazal Element ur t-iḥuza ara usesfer n uẓru. Tamahelt-a tesra asentem-nniḍen. \nI ukemmel, ma ulac aɣilif sekcem awal-ik·im uffir. @@ -2542,4 +2542,4 @@ Askar n uneflay yermed timahilin i yeffren yerna yezmer daɣen ad yerr asnas ur yerkid ara akken iwata. I yineflayen kan! Abrir arurad - + diff --git a/vector/src/main/res/values-ru/strings.xml b/vector/src/main/res/values-ru/strings.xml index 695d7d5451..01a89c77d0 100644 --- a/vector/src/main/res/values-ru/strings.xml +++ b/vector/src/main/res/values-ru/strings.xml @@ -100,7 +100,7 @@ %d пользователь %d пользователя %d пользователей - + Отправить логи @@ -836,13 +836,13 @@ %d комната %d комнаты %d комнат - + %d комната %d комнаты %d комнат - + %1$s в %2$s @@ -850,7 +850,7 @@ %d активный виджет %d активных виджета %d активных виджетов - + @@ -860,45 +860,45 @@ %d активный участник %d активных участника %d активных участников - + %d участник %d участника %d участников - + %d новое сообщение %d новых сообщения %d новых сообщений - + %1$s комната найдена для %2$s %1$s комнаты найдено для %2$s %1$s комнат найдено для %2$s - + %d изменение членства %d изменения членства %d изменений членства - + %d непрочитанное уведомление %d непрочитанных уведомления %d непрочитанных уведомлений - + %d непрочитанное уведомление %d непрочитанных уведомления %d непрочитанных уведомлений - + Получить аватар Заметка аватара @@ -1033,20 +1033,20 @@ %d выбран %d выбрано %d выбраны - + %d участник %d участника %d участников - + %d комната %d комнаты %d комнат - + Системные оповещения @@ -1307,7 +1307,7 @@ %d новый ключ был добавлен к этому устройству. %d новых ключа были добавлены к этому устройству. %d новых ключей были добавлены к этому устройству. - + @@ -1358,7 +1358,7 @@ Резервное копирование %d ключа… Резервное копирование %d ключей… Резервное копирование %d ключей… - + Все ключи сохранены @@ -2701,7 +2701,7 @@ Предупреждение! Последняя оставшаяся попытка перед выходом из системы! Слишком много ошибок, вы вышли из системы -Этот номер телефона уже определён. + Этот номер телефона уже определён. В ваш аккаунт не добавлен номер телефона Адрес электронной почты В ваш аккаунт не добавлен адрес электронной почты diff --git a/vector/src/main/res/values-sv/strings.xml b/vector/src/main/res/values-sv/strings.xml index 29429ee208..651495e01c 100644 --- a/vector/src/main/res/values-sv/strings.xml +++ b/vector/src/main/res/values-sv/strings.xml @@ -2532,7 +2532,7 @@ Aktivera PIN Om du vill återställa din PIN-kod, tryck på \"Glömt PIN\?\" för att logga ut och återställa. Bekräfta PIN för att återställa PIN -Det här telefonnumret är redan definierat. + Det här telefonnumret är redan definierat. Inget telefonnummer har lagts till till ditt konto E-postadresser Ingen e-postadress har lagts till till ditt konto diff --git a/vector/src/main/res/values-zh-rCN/strings.xml b/vector/src/main/res/values-zh-rCN/strings.xml index ead5567a19..8162c84042 100644 --- a/vector/src/main/res/values-zh-rCN/strings.xml +++ b/vector/src/main/res/values-zh-rCN/strings.xml @@ -2563,7 +2563,7 @@ Element 在后台时的工作将被显著的限制,这可能会影响消息通 注意!登出前最后一次尝试! 错误次数过多,您已被登出 -此电话号码已定义。 + 此电话号码已定义。 您的帐户尚未添加电话号码 电子邮件地址 您的账户尚未添加电子邮件 diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml index ae01b55ab9..18d5d2248f 100644 --- a/vector/src/main/res/values-zh-rTW/strings.xml +++ b/vector/src/main/res/values-zh-rTW/strings.xml @@ -2547,7 +2547,7 @@ Matrix 中的消息可見度類似于電子郵件。我們忘記您的郵件意 警告!登出前的最後一次嘗試! 太多錯誤,您已被登出 -此電話號碼已被定義。 + 此電話號碼已被定義。 未新增電話號碼到您的帳號 電子郵件地址 未傳送電子郵件到您的帳號 From 7e62e8e2cd377fc705c3635392e4ebcd44895d86 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 16 Sep 2020 19:35:39 +0200 Subject: [PATCH 83/89] Fix typo --- vector/src/main/res/values-es/strings.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vector/src/main/res/values-es/strings.xml b/vector/src/main/res/values-es/strings.xml index ff7cc505ef..5482c2547b 100644 --- a/vector/src/main/res/values-es/strings.xml +++ b/vector/src/main/res/values-es/strings.xml @@ -1953,7 +1953,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Mostrando solo el primer resultado, agregue mas letras… - Fallar rapido (Test) + Fallar rápido (Test) Element puede fallar con más frecuencia cuando ocurre un error inesperado Antepone ¯\\_(ツ)_/¯ a un mensaje de texto sin formato @@ -2004,7 +2004,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Verificar %s Verificado %s Esperando por %s… - Los mensages en esta sala no estan encriptados punto a punto. + Los mensages en esta sala no están encriptados punto a punto. Seguridad Saber mas Mas @@ -2042,7 +2042,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Otras salas Envía el mensaje dado en colores - Linea de tiempo + Línea de tiempo Editor de mensage @@ -2082,7 +2082,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu No Sin conexión - Modo Avion Activado + Modo Avión Activado Herramientas de desarrollo Datos de cuenta From 4c6bb93eaf42e036c8e559c1e449b842b08d3209 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 16 Sep 2020 19:36:26 +0200 Subject: [PATCH 84/89] ellipsis --- vector/src/main/res/values-kab/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index e435c7cdb9..72cb86e8c5 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -1995,7 +1995,7 @@ Selkem tiɣimit-a s usentem n yimujiten-a i d-yettbanen ɣef ugdil n baba-is Selkem tiɣimit-a s usentem n wuṭṭunen-a i d-yettbanen ɣef ugdil n baba-is - Tremseḍ-d asuter n uselken i d-iteddun... + Tremseḍ-d asuter n uselken i d-iteddun… Aṛaǧu n usentem sɣur bab-is… Teslekneḍ taxxamt-a akken iwata. From bfa4e00fe7b77f1542d4aaef51a4a0ab9c3867fa Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 16 Sep 2020 19:38:08 +0200 Subject: [PATCH 85/89] Hyphen can be replaced with dash --- vector/src/main/res/values-kab/strings.xml | 4 ++-- vector/src/main/res/values-ru/strings.xml | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index 72cb86e8c5..2fabc8a44e 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -1982,7 +1982,7 @@ Iɣewwaren n uqeddac ummid awurman - Element yufa-d tawila n uqeddac udmawan i taɣult usulay--inek·inem n uqeddac \"%1$s\": + Element yufa-d tawila n uqeddac udmawan i taɣult usulay—inek·inem n uqeddac \"%1$s\": \n%2$s Seqdec tawila @@ -2204,7 +2204,7 @@ Element yezmer ad yewḥel ugar n tikkal mi ara d-tili tuccḍa ur nettwaṛǧa ara - Taɣult n yimayl--ik·im ur tesɛi ara azref i wakken ad tettwasekles ɣef uqeddac-a + Taɣult n yimayl—ik·im ur tesɛi ara azref i wakken ad tettwasekles ɣef uqeddac-a Tuqqna ur nettwattkal ara Senqed aseqdac-a s usentem n yimujit-a asuf i d-yettbanen ɣef ugdil-ines, deg yiwem umsizwer. diff --git a/vector/src/main/res/values-ru/strings.xml b/vector/src/main/res/values-ru/strings.xml index 01a89c77d0..8f7084402d 100644 --- a/vector/src/main/res/values-ru/strings.xml +++ b/vector/src/main/res/values-ru/strings.xml @@ -2228,10 +2228,10 @@ Не безопасно Одно из следующих условий может быть скомпрометировано: \n -\n-- Ваш домашний сервер -\n-- Домашний сервер, к которому подключен пользователь, которого вы проверяете -\n-- Ваше или подключение к интернету других пользователей -\n-- Ваше или устройство других пользователей +\n— Ваш домашний сервер +\n— Домашний сервер, к которому подключен пользователь, которого вы проверяете +\n— Ваше или подключение к интернету других пользователей +\n— Ваше или устройство других пользователей Видео. Изображение. From 36899af36b39624d0badd5cec54191dec0032518 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 16 Sep 2020 19:41:24 +0200 Subject: [PATCH 86/89] Strings has been replaced by a plurals --- vector/src/main/res/values-ar/strings.xml | 2 -- vector/src/main/res/values-b+sr+Latn/strings.xml | 2 -- vector/src/main/res/values-bg/strings.xml | 3 --- vector/src/main/res/values-bn-rIN/strings.xml | 2 -- vector/src/main/res/values-bs/strings.xml | 2 -- vector/src/main/res/values-ca/strings.xml | 2 -- vector/src/main/res/values-cs/strings.xml | 2 -- vector/src/main/res/values-da/strings.xml | 2 -- vector/src/main/res/values-de/strings.xml | 2 -- vector/src/main/res/values-eo/strings.xml | 2 -- vector/src/main/res/values-es-rMX/strings.xml | 2 -- vector/src/main/res/values-es/strings.xml | 2 -- vector/src/main/res/values-et/strings.xml | 2 -- vector/src/main/res/values-eu/strings.xml | 2 -- vector/src/main/res/values-fa/strings.xml | 2 -- vector/src/main/res/values-fi/strings.xml | 2 -- vector/src/main/res/values-fr/strings.xml | 2 -- vector/src/main/res/values-gl/strings.xml | 3 --- vector/src/main/res/values-hr/strings.xml | 2 -- vector/src/main/res/values-hu/strings.xml | 2 -- vector/src/main/res/values-id/strings.xml | 2 -- vector/src/main/res/values-in/strings.xml | 2 -- vector/src/main/res/values-is/strings.xml | 3 --- vector/src/main/res/values-it/strings.xml | 2 -- vector/src/main/res/values-ja/strings.xml | 2 -- vector/src/main/res/values-kab/strings.xml | 2 -- vector/src/main/res/values-ko/strings.xml | 2 -- vector/src/main/res/values-lv/strings.xml | 2 -- vector/src/main/res/values-nb-rNO/strings.xml | 1 - vector/src/main/res/values-nl/strings.xml | 2 -- vector/src/main/res/values-nn/strings.xml | 2 -- vector/src/main/res/values-pl/strings.xml | 2 -- vector/src/main/res/values-pt-rBR/strings.xml | 2 -- vector/src/main/res/values-pt/strings.xml | 2 -- vector/src/main/res/values-ru/strings.xml | 2 -- vector/src/main/res/values-sk/strings.xml | 2 -- vector/src/main/res/values-sq/strings.xml | 2 -- vector/src/main/res/values-sv/strings.xml | 2 -- vector/src/main/res/values-te/strings.xml | 2 -- vector/src/main/res/values-tr/strings.xml | 2 -- vector/src/main/res/values-uk/strings.xml | 2 -- vector/src/main/res/values-zh-rCN/strings.xml | 2 -- vector/src/main/res/values-zh-rTW/strings.xml | 2 -- vector/src/main/res/values/strings.xml | 2 -- 44 files changed, 90 deletions(-) diff --git a/vector/src/main/res/values-ar/strings.xml b/vector/src/main/res/values-ar/strings.xml index 3c2998adfa..1c6f0d9fb5 100644 --- a/vector/src/main/res/values-ar/strings.xml +++ b/vector/src/main/res/values-ar/strings.xml @@ -955,8 +955,6 @@ %d محدّدة %d محدّدة - من الثواني - من الثواني عايِن الوسيط قبل إرساله diff --git a/vector/src/main/res/values-b+sr+Latn/strings.xml b/vector/src/main/res/values-b+sr+Latn/strings.xml index f95c885c1d..0710775d57 100644 --- a/vector/src/main/res/values-b+sr+Latn/strings.xml +++ b/vector/src/main/res/values-b+sr+Latn/strings.xml @@ -239,8 +239,6 @@ Sinhronizacija u pozadini Optimizovano za potrošnju baterije Bez sinhronizacije u pozadini - sekundu - sekundi Verzija olm verzija diff --git a/vector/src/main/res/values-bg/strings.xml b/vector/src/main/res/values-bg/strings.xml index fd2a5d09ee..ad0d85116a 100644 --- a/vector/src/main/res/values-bg/strings.xml +++ b/vector/src/main/res/values-bg/strings.xml @@ -414,9 +414,6 @@ Покани за разговор Съобщения изпратени от бот - секунда - секунди - Версия Olm версия Правила и условия diff --git a/vector/src/main/res/values-bn-rIN/strings.xml b/vector/src/main/res/values-bn-rIN/strings.xml index e00ba760e6..349450990f 100644 --- a/vector/src/main/res/values-bn-rIN/strings.xml +++ b/vector/src/main/res/values-bn-rIN/strings.xml @@ -708,8 +708,6 @@ ব্যাকগ্রাউন্ড সিঙ্ক সক্ষম করুন সিঙ্ক অনুরোধ সময়সীমার প্রতিটি সিঙ্কের মধ্যে বিলম্ব - সেকেন্ড - সেকেন্ড সংস্করণ olm সংস্করণ diff --git a/vector/src/main/res/values-bs/strings.xml b/vector/src/main/res/values-bs/strings.xml index 14727bd2ec..98747e2ff7 100644 --- a/vector/src/main/res/values-bs/strings.xml +++ b/vector/src/main/res/values-bs/strings.xml @@ -420,8 +420,6 @@ Da li ste sigurani? Omogući pozadinsku sinkronizaciju Sinkronizacijski zahtjev istekao Napravi pauzu između dva sinkronizacijska zahtjeva - sekunda - sekunde Verzija olm verzija diff --git a/vector/src/main/res/values-ca/strings.xml b/vector/src/main/res/values-ca/strings.xml index 56bea320aa..8126cd1c2b 100644 --- a/vector/src/main/res/values-ca/strings.xml +++ b/vector/src/main/res/values-ca/strings.xml @@ -473,8 +473,6 @@ Tingueu en compte que aquesta acció reiniciarà l\'aplicació i que pot trigar Habilita la sincronització en segon pla Temps màxim d\'espera de la petició de sincronització Retard entre cada petició - segon - segons Versió Versió d\'OLM diff --git a/vector/src/main/res/values-cs/strings.xml b/vector/src/main/res/values-cs/strings.xml index 9a36defc05..a62d1996d0 100644 --- a/vector/src/main/res/values-cs/strings.xml +++ b/vector/src/main/res/values-cs/strings.xml @@ -747,8 +747,6 @@ Vaši e-mailovou adresu můžete přidat k profilu v nastavení. %s \nSync může být odložen v závislosti na zdrojích (baterie) nebo stavu zařízení (spánek). Prodleva mezi jednotlivými syncy - vteřina - vteřiny Verze verze olm diff --git a/vector/src/main/res/values-da/strings.xml b/vector/src/main/res/values-da/strings.xml index 676f4eebe3..af4cb6d4cc 100644 --- a/vector/src/main/res/values-da/strings.xml +++ b/vector/src/main/res/values-da/strings.xml @@ -472,8 +472,6 @@ Er du sikker? Aktiver baggrundssynkronisering Timeout for synkroniseringskald Pause mellem to synkroniseringskald - sekund - sekunder Version Anvendelsesbetingelser diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml index 87bce39b88..455021aabe 100644 --- a/vector/src/main/res/values-de/strings.xml +++ b/vector/src/main/res/values-de/strings.xml @@ -449,8 +449,6 @@ Beachte: Diese Aktion wird die App neu starten und einige Zeit brauchen.Hintergrundsynchronisierung aktivieren Timeout für Synchronisierungsanfragen Verzögerung zwischen jeder Synchronisierung - Sekunde - Sekunden Version OLM Version diff --git a/vector/src/main/res/values-eo/strings.xml b/vector/src/main/res/values-eo/strings.xml index 1800e756d8..21a805c2ad 100644 --- a/vector/src/main/res/values-eo/strings.xml +++ b/vector/src/main/res/values-eo/strings.xml @@ -361,8 +361,6 @@ %s \nLa spegulado povas esti prokrastita, depende de la rimedoj (baterio) aŭ la stato de la aparato (dormeto). Prokrasto inter ĉiu spegulado - sekundo - sekundoj Versio Versio de olm diff --git a/vector/src/main/res/values-es-rMX/strings.xml b/vector/src/main/res/values-es-rMX/strings.xml index f63a1cffc4..950425648c 100644 --- a/vector/src/main/res/values-es-rMX/strings.xml +++ b/vector/src/main/res/values-es-rMX/strings.xml @@ -435,8 +435,6 @@ Encender sincronización interna Vencimiento de peticiones de sincronización Demora entre cada petición de sincronización - segundo - segundos Versión versión olm diff --git a/vector/src/main/res/values-es/strings.xml b/vector/src/main/res/values-es/strings.xml index 5482c2547b..b57b03e6d9 100644 --- a/vector/src/main/res/values-es/strings.xml +++ b/vector/src/main/res/values-es/strings.xml @@ -453,8 +453,6 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Habilitar sincronización en segundo plano Venció el tiempo de espera para la solicitud de sincronización Retraso entre cada sincronización - segundo - segundos Versión versión de olm diff --git a/vector/src/main/res/values-et/strings.xml b/vector/src/main/res/values-et/strings.xml index 0e7d171a5c..7243557176 100644 --- a/vector/src/main/res/values-et/strings.xml +++ b/vector/src/main/res/values-et/strings.xml @@ -1297,8 +1297,6 @@ %s \nSünkroniseerimine võib jääda vahele, kui aku täituvus on madal või seade energiasäästurežiimil. Viivitus sünkroonimiste vahel - sekund - sekundit Versioon olm-teegi versioon diff --git a/vector/src/main/res/values-eu/strings.xml b/vector/src/main/res/values-eu/strings.xml index db7cf62893..ccb7568ca9 100644 --- a/vector/src/main/res/values-eu/strings.xml +++ b/vector/src/main/res/values-eu/strings.xml @@ -410,8 +410,6 @@ Kontuan izan ekintza honek aplikazioa berrabiaraziko duela eta denbora bat behar Gaitu bigarren planoko sinkronizazioa Sinkronizazio eskaerak debora-muga gainditu du Sinkronizazioen arteko itxaronaldia - segundo - segundo Bertsioa: olm bertsioa diff --git a/vector/src/main/res/values-fa/strings.xml b/vector/src/main/res/values-fa/strings.xml index 6e5955ae32..335d2d9c66 100644 --- a/vector/src/main/res/values-fa/strings.xml +++ b/vector/src/main/res/values-fa/strings.xml @@ -410,8 +410,6 @@ پیکربندی أگاهی‌های تماس پیکربندی أگاهی‌های صامت تأخیر بین همگام‌سازی‌ها - ثانیه - ثانیه نگارش نگارش olm diff --git a/vector/src/main/res/values-fi/strings.xml b/vector/src/main/res/values-fi/strings.xml index 6179d13df1..aa16c14542 100644 --- a/vector/src/main/res/values-fi/strings.xml +++ b/vector/src/main/res/values-fi/strings.xml @@ -455,8 +455,6 @@ Käytä taustasynkronointia Synkronointipyynnön aikakatkaisu Viive synkronointien välillä - sekunti - sekuntia Versio olm-versio diff --git a/vector/src/main/res/values-fr/strings.xml b/vector/src/main/res/values-fr/strings.xml index 167139cbb2..c092beff9f 100644 --- a/vector/src/main/res/values-fr/strings.xml +++ b/vector/src/main/res/values-fr/strings.xml @@ -294,8 +294,6 @@ Activer la synchronisation en arrière-plan Délai d’attente de la requête de synchronisation Délai entre chaque synchronisation - seconde - secondes Version Version de olm diff --git a/vector/src/main/res/values-gl/strings.xml b/vector/src/main/res/values-gl/strings.xml index a2200a88bf..c6cc39ceae 100644 --- a/vector/src/main/res/values-gl/strings.xml +++ b/vector/src/main/res/values-gl/strings.xml @@ -283,9 +283,6 @@ Pode engadir a dirección de correo na sección de configuración de perfil.Activar notificacións para esta conta Mensaxes enviadas por bot - segundo - segundos - Versión versións anteriores Limpar o caché diff --git a/vector/src/main/res/values-hr/strings.xml b/vector/src/main/res/values-hr/strings.xml index acd24b2491..84dc520db1 100644 --- a/vector/src/main/res/values-hr/strings.xml +++ b/vector/src/main/res/values-hr/strings.xml @@ -725,8 +725,6 @@ %s \nSinkronizacija može biti odgođena ovisno o sredstvima (baterija) ili stanju uređaja (spavanje). Razmak između dvije sinkronizacije - sekunda - sekunde Inačica Inačica olm-a diff --git a/vector/src/main/res/values-hu/strings.xml b/vector/src/main/res/values-hu/strings.xml index 1b5fb84870..712a465ad3 100644 --- a/vector/src/main/res/values-hu/strings.xml +++ b/vector/src/main/res/values-hu/strings.xml @@ -410,8 +410,6 @@ Vedd figyelembe, hogy az alkalmazás újraindul ami sok időt vehet igénybe."< Háttérben történő szinkronizáció engedélyezése Szinkronizáció kérelem időtúllépés Késleltetés a szinkronizációk között - másodperc - másodperc Verzió olm verzió diff --git a/vector/src/main/res/values-id/strings.xml b/vector/src/main/res/values-id/strings.xml index a8fe21f19e..76accdfe0c 100644 --- a/vector/src/main/res/values-id/strings.xml +++ b/vector/src/main/res/values-id/strings.xml @@ -554,8 +554,6 @@ Perhatikan bahwa tindakan ini akan memulai ulang aplikasi dan mungkin cukup mema Perbolehkan sinkronisasi di balik layar Batas waktu permohonan sinkronisasi Masa tunda sebelum permohonan berikutnya - detik - detik Versi versi olm diff --git a/vector/src/main/res/values-in/strings.xml b/vector/src/main/res/values-in/strings.xml index a8fe21f19e..76accdfe0c 100644 --- a/vector/src/main/res/values-in/strings.xml +++ b/vector/src/main/res/values-in/strings.xml @@ -554,8 +554,6 @@ Perhatikan bahwa tindakan ini akan memulai ulang aplikasi dan mungkin cukup mema Perbolehkan sinkronisasi di balik layar Batas waktu permohonan sinkronisasi Masa tunda sebelum permohonan berikutnya - detik - detik Versi versi olm diff --git a/vector/src/main/res/values-is/strings.xml b/vector/src/main/res/values-is/strings.xml index 202f2f399e..a148e3c855 100644 --- a/vector/src/main/res/values-is/strings.xml +++ b/vector/src/main/res/values-is/strings.xml @@ -275,9 +275,6 @@ Kerfisupplýsingar forrits Upplýsingar um forrit - sekúnda - sekúndur - Útgáfa Útgáfa olm Skilmálar og kvaðir diff --git a/vector/src/main/res/values-it/strings.xml b/vector/src/main/res/values-it/strings.xml index d5502208c7..b566ac5733 100644 --- a/vector/src/main/res/values-it/strings.xml +++ b/vector/src/main/res/values-it/strings.xml @@ -458,8 +458,6 @@ Abilita la sincronizzazione in background La richiesta di sincronizzazione sta impiegando troppo tempo Ritardo tra ogni sincronizzazione - secondo - secondi Versione Versione olm diff --git a/vector/src/main/res/values-ja/strings.xml b/vector/src/main/res/values-ja/strings.xml index dacaa03450..b5080e4d17 100644 --- a/vector/src/main/res/values-ja/strings.xml +++ b/vector/src/main/res/values-ja/strings.xml @@ -191,8 +191,6 @@ 端末起動時に開始 アプリを閉じているときの動作 - - アプリを閉じても新着を確認 新着確認を失敗とするまでの時間 diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index 2fabc8a44e..56fa00d017 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -1406,8 +1406,6 @@ Ulac amtawi n ugilal Bdu seg usenker Rmed amtawi n ugilal - tasint - tasinin Tiwtilin & tfadiwin Sfeḍ takatut tuffirt diff --git a/vector/src/main/res/values-ko/strings.xml b/vector/src/main/res/values-ko/strings.xml index aec1a93bb5..defc379c1a 100644 --- a/vector/src/main/res/values-ko/strings.xml +++ b/vector/src/main/res/values-ko/strings.xml @@ -669,8 +669,6 @@ 백그라운드 동기화 켜기 동기화 요청 시간 초과 각 동기화 간 딜레이 - - 버전 olm 버전 diff --git a/vector/src/main/res/values-lv/strings.xml b/vector/src/main/res/values-lv/strings.xml index d057245a53..f716d62c9f 100644 --- a/vector/src/main/res/values-lv/strings.xml +++ b/vector/src/main/res/values-lv/strings.xml @@ -457,8 +457,6 @@ Vai vēlies turpināt? Iespējot sinhronizāciju fonā Sinhronizācijas pieprasījuma noildze Intervāls starp 2 sinhronizācijas pieprasījumiem - sekunde - sekundes Versija Olm versija diff --git a/vector/src/main/res/values-nb-rNO/strings.xml b/vector/src/main/res/values-nb-rNO/strings.xml index d830d40686..55f5c22460 100644 --- a/vector/src/main/res/values-nb-rNO/strings.xml +++ b/vector/src/main/res/values-nb-rNO/strings.xml @@ -192,7 +192,6 @@ Vanlig Varslingslyd - sekunder Versjon Opphavsrettighet diff --git a/vector/src/main/res/values-nl/strings.xml b/vector/src/main/res/values-nl/strings.xml index 3c0624cdf4..1b07f38bd0 100644 --- a/vector/src/main/res/values-nl/strings.xml +++ b/vector/src/main/res/values-nl/strings.xml @@ -451,8 +451,6 @@ Achtergrondssynchronisatie inschakelen Synchronisatieverzoek is verlopen Pauze tussen elk synchronisatie - seconde - seconden Versie olm-versie diff --git a/vector/src/main/res/values-nn/strings.xml b/vector/src/main/res/values-nn/strings.xml index a5d25f6505..fc94d52b74 100644 --- a/vector/src/main/res/values-nn/strings.xml +++ b/vector/src/main/res/values-nn/strings.xml @@ -515,8 +515,6 @@ Skru på bakgrunnsamstilling Samstillingsfyrespurnaden fekk tidsavbrot Forsinkelse mellom kvar synkronisering - sekund - sekund Versjon olm versjon diff --git a/vector/src/main/res/values-pl/strings.xml b/vector/src/main/res/values-pl/strings.xml index 79764d864e..aadfc09bf5 100644 --- a/vector/src/main/res/values-pl/strings.xml +++ b/vector/src/main/res/values-pl/strings.xml @@ -368,8 +368,6 @@ Zauważ, że ta czynność spowoduje ponowne uruchomienie aplikacji i może to t Rozpocznij przy uruchomieniu systemu Synchronizacja w tle Włącz synchronizację w tle - sekunda - sekundy Wersja Zasady użytkowania diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml index 9409459279..ef44f53cf4 100644 --- a/vector/src/main/res/values-pt-rBR/strings.xml +++ b/vector/src/main/res/values-pt-rBR/strings.xml @@ -454,8 +454,6 @@ Ativar a sincronização em segundo plano Tempo expirado na solicitação de sincronização Demora entre cada solicitação - segundo - segundos Versão Versão do olm diff --git a/vector/src/main/res/values-pt/strings.xml b/vector/src/main/res/values-pt/strings.xml index ca5d93e702..03dc9f385a 100644 --- a/vector/src/main/res/values-pt/strings.xml +++ b/vector/src/main/res/values-pt/strings.xml @@ -451,8 +451,6 @@ Note que esta acção irá reiniciar a aplicação e poderá levar algum tempo.< Ativar sincronização em segundo plano Tempo do pedido de sincronização esgotou Tempo entre duas solicitações de sincronização - segundo - segundos Versão versão olm diff --git a/vector/src/main/res/values-ru/strings.xml b/vector/src/main/res/values-ru/strings.xml index 8f7084402d..60e5f6c388 100644 --- a/vector/src/main/res/values-ru/strings.xml +++ b/vector/src/main/res/values-ru/strings.xml @@ -449,8 +449,6 @@ Включить фоновую синхронизацию Таймаут синхронизации Задержка между каждой синхронизацией - секунда - секунд Версия Версия OLM diff --git a/vector/src/main/res/values-sk/strings.xml b/vector/src/main/res/values-sk/strings.xml index bbb398cbba..e8a9495b1f 100644 --- a/vector/src/main/res/values-sk/strings.xml +++ b/vector/src/main/res/values-sk/strings.xml @@ -428,8 +428,6 @@ Pozor! Vykonaním tejto akcie reštartujete aplikáciu a opätovné načítanie Povoliť synchronizáciu na pozadí Časový limit požiadavky na synchronizáciu Oneskorenie medzi jednotlivými synchronizáciami - sekunda - sekúnd Verzia Verzia knižnice olm diff --git a/vector/src/main/res/values-sq/strings.xml b/vector/src/main/res/values-sq/strings.xml index f4b2799591..ea84d963d1 100644 --- a/vector/src/main/res/values-sq/strings.xml +++ b/vector/src/main/res/values-sq/strings.xml @@ -404,8 +404,6 @@ Aktivizo njëkohësim në prapaskenë Mbarim kohe për kërkesë njëkohësimi Vonesë mes çdo Njëkohësimi - sekondë - sekonda Version Terma & kushte diff --git a/vector/src/main/res/values-sv/strings.xml b/vector/src/main/res/values-sv/strings.xml index 651495e01c..8b42d3db9f 100644 --- a/vector/src/main/res/values-sv/strings.xml +++ b/vector/src/main/res/values-sv/strings.xml @@ -1567,8 +1567,6 @@ %s \nSynkroniseringen kan skjutas upp beroende på resurserna (batteri) eller status för enheten (vila). Fördröjning mellan varje synkronisering - sekund - sekunder Lokala kontakter Kontaktbehörighet diff --git a/vector/src/main/res/values-te/strings.xml b/vector/src/main/res/values-te/strings.xml index 907bc862df..28609a17f7 100644 --- a/vector/src/main/res/values-te/strings.xml +++ b/vector/src/main/res/values-te/strings.xml @@ -329,8 +329,6 @@ నేపథ్య సమకాలీకరణను చేతనపరుచు సమకాలీకరణ అభ్యర్థన సమయం ముగిసింది రెండు సమకాలీకరణ అభ్యర్థనల మధ్య ఆలస్యం - క్షణం - క్షణాలు వెర్షన్ olm వెర్షన్ diff --git a/vector/src/main/res/values-tr/strings.xml b/vector/src/main/res/values-tr/strings.xml index 98638c7226..e906dafb39 100644 --- a/vector/src/main/res/values-tr/strings.xml +++ b/vector/src/main/res/values-tr/strings.xml @@ -700,8 +700,6 @@ Eğer yeni kurtarma yöntemini siz ayarlamadıysanız, bir saldırgan hesabını Arkaplanda eşzamanlamayı etkinleştir Eşzamanlama talep süresi doldu Her senkronizasyon arası gecikme - saniye - saniye Sürüm olm sürümü diff --git a/vector/src/main/res/values-uk/strings.xml b/vector/src/main/res/values-uk/strings.xml index 9c27392e81..5a0d12bd76 100644 --- a/vector/src/main/res/values-uk/strings.xml +++ b/vector/src/main/res/values-uk/strings.xml @@ -456,8 +456,6 @@ Увімкнути фонову синхронізацію Таймаут синхронізації Інтервал між запитами синхронізації - секунда - секунд Версія Версія OLM diff --git a/vector/src/main/res/values-zh-rCN/strings.xml b/vector/src/main/res/values-zh-rCN/strings.xml index 8162c84042..6122f746e3 100644 --- a/vector/src/main/res/values-zh-rCN/strings.xml +++ b/vector/src/main/res/values-zh-rCN/strings.xml @@ -300,8 +300,6 @@ 启用后台同步 同步请求超时 每次同步请求之间的间隔 - - 版权 隐私政策 diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml index 18d5d2248f..6bba7c9f11 100644 --- a/vector/src/main/res/values-zh-rTW/strings.xml +++ b/vector/src/main/res/values-zh-rTW/strings.xml @@ -510,8 +510,6 @@ 開啓後臺同步 同步請求超時 每次同步間的延遲 - - 版本 olm 版本 diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 3adb7d21e2..d130bc910b 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -813,8 +813,6 @@ Preferred Sync Interval %s\nThe sync might be deferred depending on the resources (battery) or state of the device (sleep). Delay between each Sync - second - seconds %d second %d seconds From a77069297d054c9c6c1330e397628b8161c63f01 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 16 Sep 2020 19:51:43 +0200 Subject: [PATCH 87/89] Remove R.string.copy, use R.string.action_copy (Fix clash with androidx.preferences private resource) --- .../home/room/detail/timeline/action/EventSharedAction.kt | 2 +- vector/src/main/res/values-ar/strings.xml | 1 - vector/src/main/res/values-b+sr+Latn/strings.xml | 1 - vector/src/main/res/values-bg/strings.xml | 1 - vector/src/main/res/values-bn-rIN/strings.xml | 1 - vector/src/main/res/values-bs/strings.xml | 1 - vector/src/main/res/values-ca/strings.xml | 1 - vector/src/main/res/values-cs/strings.xml | 1 - vector/src/main/res/values-da/strings.xml | 1 - vector/src/main/res/values-de/strings.xml | 1 - vector/src/main/res/values-el/strings.xml | 1 - vector/src/main/res/values-eo/strings.xml | 1 - vector/src/main/res/values-es-rMX/strings.xml | 1 - vector/src/main/res/values-es/strings.xml | 1 - vector/src/main/res/values-et/strings.xml | 1 - vector/src/main/res/values-eu/strings.xml | 1 - vector/src/main/res/values-fa/strings.xml | 1 - vector/src/main/res/values-fi/strings.xml | 1 - vector/src/main/res/values-fr/strings.xml | 1 - vector/src/main/res/values-fy/strings.xml | 1 - vector/src/main/res/values-gl/strings.xml | 1 - vector/src/main/res/values-hr/strings.xml | 1 - vector/src/main/res/values-hu/strings.xml | 1 - vector/src/main/res/values-id/strings.xml | 1 - vector/src/main/res/values-in/strings.xml | 1 - vector/src/main/res/values-is/strings.xml | 1 - vector/src/main/res/values-it/strings.xml | 1 - vector/src/main/res/values-ja/strings.xml | 1 - vector/src/main/res/values-kab/strings.xml | 1 - vector/src/main/res/values-ko/strings.xml | 1 - vector/src/main/res/values-lv/strings.xml | 1 - vector/src/main/res/values-nb-rNO/strings.xml | 1 - vector/src/main/res/values-nl/strings.xml | 1 - vector/src/main/res/values-nn/strings.xml | 1 - vector/src/main/res/values-pl/strings.xml | 1 - vector/src/main/res/values-pt-rBR/strings.xml | 1 - vector/src/main/res/values-pt/strings.xml | 1 - vector/src/main/res/values-ru/strings.xml | 1 - vector/src/main/res/values-sk/strings.xml | 1 - vector/src/main/res/values-sq/strings.xml | 1 - vector/src/main/res/values-sr/strings.xml | 1 - vector/src/main/res/values-sv/strings.xml | 1 - vector/src/main/res/values-te/strings.xml | 1 - vector/src/main/res/values-th/strings.xml | 1 - vector/src/main/res/values-tlh/strings.xml | 1 - vector/src/main/res/values-tr/strings.xml | 1 - vector/src/main/res/values-uk/strings.xml | 1 - vector/src/main/res/values-zh-rCN/strings.xml | 1 - vector/src/main/res/values-zh-rTW/strings.xml | 1 - vector/src/main/res/values/strings.xml | 1 - 50 files changed, 1 insertion(+), 50 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/EventSharedAction.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/EventSharedAction.kt index cffd576057..7693d97c35 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/EventSharedAction.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/EventSharedAction.kt @@ -36,7 +36,7 @@ sealed class EventSharedAction(@StringRes val titleRes: Int, EventSharedAction(R.string.message_add_reaction, R.drawable.ic_add_reaction) data class Copy(val content: String) : - EventSharedAction(R.string.copy, R.drawable.ic_copy) + EventSharedAction(R.string.action_copy, R.drawable.ic_copy) data class Edit(val eventId: String) : EventSharedAction(R.string.edit, R.drawable.ic_edit) diff --git a/vector/src/main/res/values-ar/strings.xml b/vector/src/main/res/values-ar/strings.xml index 1c6f0d9fb5..f7c6abea4e 100644 --- a/vector/src/main/res/values-ar/strings.xml +++ b/vector/src/main/res/values-ar/strings.xml @@ -20,7 +20,6 @@ احفظ اترك أرسِل - انسخ أعِد الإرسال اقتبس شارِك diff --git a/vector/src/main/res/values-b+sr+Latn/strings.xml b/vector/src/main/res/values-b+sr+Latn/strings.xml index 0710775d57..c66e754216 100644 --- a/vector/src/main/res/values-b+sr+Latn/strings.xml +++ b/vector/src/main/res/values-b+sr+Latn/strings.xml @@ -43,7 +43,6 @@ Napusti Ostani Pošalji - Kopiraj Pošalji ponovo Ukloni Podeli diff --git a/vector/src/main/res/values-bg/strings.xml b/vector/src/main/res/values-bg/strings.xml index ad0d85116a..2dfb212dcb 100644 --- a/vector/src/main/res/values-bg/strings.xml +++ b/vector/src/main/res/values-bg/strings.xml @@ -82,7 +82,6 @@ Запази Напусни Изпрати - Копирай Изпрати отново Премахни Цитирай diff --git a/vector/src/main/res/values-bn-rIN/strings.xml b/vector/src/main/res/values-bn-rIN/strings.xml index 349450990f..a0c0f92cb5 100644 --- a/vector/src/main/res/values-bn-rIN/strings.xml +++ b/vector/src/main/res/values-bn-rIN/strings.xml @@ -45,7 +45,6 @@ ত্যাগ থাক পাঠান - অনুলিপি আবার পাঠান অপসারণ উদ্ধৃতি diff --git a/vector/src/main/res/values-bs/strings.xml b/vector/src/main/res/values-bs/strings.xml index 98747e2ff7..4d342912a0 100644 --- a/vector/src/main/res/values-bs/strings.xml +++ b/vector/src/main/res/values-bs/strings.xml @@ -24,7 +24,6 @@ Snimi Napusti Pošalji - Kopiraj Pošalji Ponovo Uredi Citat diff --git a/vector/src/main/res/values-ca/strings.xml b/vector/src/main/res/values-ca/strings.xml index 8126cd1c2b..d711d778ca 100644 --- a/vector/src/main/res/values-ca/strings.xml +++ b/vector/src/main/res/values-ca/strings.xml @@ -32,7 +32,6 @@ Desa Abandona la sala Envia - Còpia Reenvia Suprimeix Cita diff --git a/vector/src/main/res/values-cs/strings.xml b/vector/src/main/res/values-cs/strings.xml index a62d1996d0..f20bdff2d3 100644 --- a/vector/src/main/res/values-cs/strings.xml +++ b/vector/src/main/res/values-cs/strings.xml @@ -15,7 +15,6 @@ Odeslat Opustit Sdílet - Kopírovat Předat Zobrazit zdroj Odstranit diff --git a/vector/src/main/res/values-da/strings.xml b/vector/src/main/res/values-da/strings.xml index af4cb6d4cc..2fa102399a 100644 --- a/vector/src/main/res/values-da/strings.xml +++ b/vector/src/main/res/values-da/strings.xml @@ -21,7 +21,6 @@ Gem Forlad Send - Kopier Send igen Tilbagehold Citér diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml index 455021aabe..da2e2886a1 100644 --- a/vector/src/main/res/values-de/strings.xml +++ b/vector/src/main/res/values-de/strings.xml @@ -22,7 +22,6 @@ Speichern Verlassen Senden - Kopieren Erneut senden Entfernen Zitieren diff --git a/vector/src/main/res/values-el/strings.xml b/vector/src/main/res/values-el/strings.xml index 4abc074d4b..499f4a0549 100644 --- a/vector/src/main/res/values-el/strings.xml +++ b/vector/src/main/res/values-el/strings.xml @@ -67,7 +67,6 @@ Άδειες τρίτων - Αντιγραφή Αργότερα Μπροστά Διαγαρφή diff --git a/vector/src/main/res/values-eo/strings.xml b/vector/src/main/res/values-eo/strings.xml index 21a805c2ad..c648efaf2a 100644 --- a/vector/src/main/res/values-eo/strings.xml +++ b/vector/src/main/res/values-eo/strings.xml @@ -28,7 +28,6 @@ Konservi Eliri Sendi - Kopii Resendi Forigi Citi diff --git a/vector/src/main/res/values-es-rMX/strings.xml b/vector/src/main/res/values-es-rMX/strings.xml index 950425648c..7981f1e4f8 100644 --- a/vector/src/main/res/values-es-rMX/strings.xml +++ b/vector/src/main/res/values-es-rMX/strings.xml @@ -18,7 +18,6 @@ Guardar Salir Enviar - Copiar Reenviar Borrar Citar diff --git a/vector/src/main/res/values-es/strings.xml b/vector/src/main/res/values-es/strings.xml index b57b03e6d9..4687fffa77 100644 --- a/vector/src/main/res/values-es/strings.xml +++ b/vector/src/main/res/values-es/strings.xml @@ -18,7 +18,6 @@ Guardar Salir Enviar - Copiar Reenviar Eliminar Citar diff --git a/vector/src/main/res/values-et/strings.xml b/vector/src/main/res/values-et/strings.xml index 7243557176..778abdb290 100644 --- a/vector/src/main/res/values-et/strings.xml +++ b/vector/src/main/res/values-et/strings.xml @@ -50,7 +50,6 @@ Lahku Jää Saada - Kopeeri Saada uuesti Eemalda Tsiteeri diff --git a/vector/src/main/res/values-eu/strings.xml b/vector/src/main/res/values-eu/strings.xml index ccb7568ca9..12d437d6c3 100644 --- a/vector/src/main/res/values-eu/strings.xml +++ b/vector/src/main/res/values-eu/strings.xml @@ -14,7 +14,6 @@ Gorde Atera Bidali - Kopiatu Birbidali Kendu Aipua diff --git a/vector/src/main/res/values-fa/strings.xml b/vector/src/main/res/values-fa/strings.xml index 335d2d9c66..34aaeb3599 100644 --- a/vector/src/main/res/values-fa/strings.xml +++ b/vector/src/main/res/values-fa/strings.xml @@ -20,7 +20,6 @@ ذخیره ترک کردن ارسال - روگرفت ارسال مجدد نقل قول اشتراک گذاری diff --git a/vector/src/main/res/values-fi/strings.xml b/vector/src/main/res/values-fi/strings.xml index aa16c14542..07a5d3f84a 100644 --- a/vector/src/main/res/values-fi/strings.xml +++ b/vector/src/main/res/values-fi/strings.xml @@ -18,7 +18,6 @@ Säästä Poistu Lähetä - Kopioi Lähetä uudelleen Poista Lainaa diff --git a/vector/src/main/res/values-fr/strings.xml b/vector/src/main/res/values-fr/strings.xml index c092beff9f..d58f22b399 100644 --- a/vector/src/main/res/values-fr/strings.xml +++ b/vector/src/main/res/values-fr/strings.xml @@ -14,7 +14,6 @@ Annuler Enregistrer Envoyer - Copier Renvoyer Partager Plus tard diff --git a/vector/src/main/res/values-fy/strings.xml b/vector/src/main/res/values-fy/strings.xml index b0999ff8e7..d43f2d5b01 100644 --- a/vector/src/main/res/values-fy/strings.xml +++ b/vector/src/main/res/values-fy/strings.xml @@ -48,7 +48,6 @@ Ferlitte Bliuwe Ferstjoere - Kopiearje Opnij ferstjoere Fuortsmite Sitearje diff --git a/vector/src/main/res/values-gl/strings.xml b/vector/src/main/res/values-gl/strings.xml index c6cc39ceae..6ef0b9437d 100644 --- a/vector/src/main/res/values-gl/strings.xml +++ b/vector/src/main/res/values-gl/strings.xml @@ -26,7 +26,6 @@ Gardar Saír Enviar - Copiar Enviar de novo Redactar Citar diff --git a/vector/src/main/res/values-hr/strings.xml b/vector/src/main/res/values-hr/strings.xml index 84dc520db1..83a479d79f 100644 --- a/vector/src/main/res/values-hr/strings.xml +++ b/vector/src/main/res/values-hr/strings.xml @@ -48,7 +48,6 @@ Napusti Ostani Pošalji - Kopiraj Pošalji ponovno Ukloni Citiraj diff --git a/vector/src/main/res/values-hu/strings.xml b/vector/src/main/res/values-hu/strings.xml index 712a465ad3..2516d203e0 100644 --- a/vector/src/main/res/values-hu/strings.xml +++ b/vector/src/main/res/values-hu/strings.xml @@ -15,7 +15,6 @@ Mentés Elhagyás Küldés - Másolás Újraküldés Törlés Idézés diff --git a/vector/src/main/res/values-id/strings.xml b/vector/src/main/res/values-id/strings.xml index 76accdfe0c..a05fde63f7 100644 --- a/vector/src/main/res/values-id/strings.xml +++ b/vector/src/main/res/values-id/strings.xml @@ -69,7 +69,6 @@ Nomor Telpon (piihan) Ulangi password Konfirmasi password baru - Gandakan Kirim Ulang Teruskan Tampilkan Sumber diff --git a/vector/src/main/res/values-in/strings.xml b/vector/src/main/res/values-in/strings.xml index 76accdfe0c..a05fde63f7 100644 --- a/vector/src/main/res/values-in/strings.xml +++ b/vector/src/main/res/values-in/strings.xml @@ -69,7 +69,6 @@ Nomor Telpon (piihan) Ulangi password Konfirmasi password baru - Gandakan Kirim Ulang Teruskan Tampilkan Sumber diff --git a/vector/src/main/res/values-is/strings.xml b/vector/src/main/res/values-is/strings.xml index a148e3c855..e20805590b 100644 --- a/vector/src/main/res/values-is/strings.xml +++ b/vector/src/main/res/values-is/strings.xml @@ -27,7 +27,6 @@ Vista Fara út Senda - Afrita Endursenda Ritstýra Tilvitnun diff --git a/vector/src/main/res/values-it/strings.xml b/vector/src/main/res/values-it/strings.xml index b566ac5733..190e1610aa 100644 --- a/vector/src/main/res/values-it/strings.xml +++ b/vector/src/main/res/values-it/strings.xml @@ -19,7 +19,6 @@ Salva Esci Invia - Copia Rispedisci Rimuovi Citazione diff --git a/vector/src/main/res/values-ja/strings.xml b/vector/src/main/res/values-ja/strings.xml index b5080e4d17..66c6eb53d3 100644 --- a/vector/src/main/res/values-ja/strings.xml +++ b/vector/src/main/res/values-ja/strings.xml @@ -12,7 +12,6 @@ 保存 退室 送信 - コピー 再送信 削除 共有 diff --git a/vector/src/main/res/values-kab/strings.xml b/vector/src/main/res/values-kab/strings.xml index 56fa00d017..75e1f19aa6 100644 --- a/vector/src/main/res/values-kab/strings.xml +++ b/vector/src/main/res/values-kab/strings.xml @@ -22,7 +22,6 @@ Sekles Ffeɣ Azen - Nɣel Ɛawed azen Sfeḍ Tanebdurt diff --git a/vector/src/main/res/values-ko/strings.xml b/vector/src/main/res/values-ko/strings.xml index defc379c1a..b2273a5782 100644 --- a/vector/src/main/res/values-ko/strings.xml +++ b/vector/src/main/res/values-ko/strings.xml @@ -24,7 +24,6 @@ 저장 떠나기 보내기 - 복사 다시 보내기 감추기 인용 diff --git a/vector/src/main/res/values-lv/strings.xml b/vector/src/main/res/values-lv/strings.xml index f716d62c9f..0a82c6882c 100644 --- a/vector/src/main/res/values-lv/strings.xml +++ b/vector/src/main/res/values-lv/strings.xml @@ -16,7 +16,6 @@ Saglabāt Atstāt Nosūtīt - Kopēt Sūtīt atkārtoti Rediģēt Citāts diff --git a/vector/src/main/res/values-nb-rNO/strings.xml b/vector/src/main/res/values-nb-rNO/strings.xml index 55f5c22460..48f9e87737 100644 --- a/vector/src/main/res/values-nb-rNO/strings.xml +++ b/vector/src/main/res/values-nb-rNO/strings.xml @@ -24,7 +24,6 @@ Lagre Forlat Send - Kopier Send på nytt Fjern Sitering diff --git a/vector/src/main/res/values-nl/strings.xml b/vector/src/main/res/values-nl/strings.xml index 1b07f38bd0..f10458970e 100644 --- a/vector/src/main/res/values-nl/strings.xml +++ b/vector/src/main/res/values-nl/strings.xml @@ -18,7 +18,6 @@ Opslaan Verlaten Versturen - Kopiëren Opnieuw versturen Verwijderen Citeren diff --git a/vector/src/main/res/values-nn/strings.xml b/vector/src/main/res/values-nn/strings.xml index fc94d52b74..fcd0ba9e15 100644 --- a/vector/src/main/res/values-nn/strings.xml +++ b/vector/src/main/res/values-nn/strings.xml @@ -30,7 +30,6 @@ Lagra Forlat Send - Kopier Send på nytt Fjern Siter diff --git a/vector/src/main/res/values-pl/strings.xml b/vector/src/main/res/values-pl/strings.xml index aadfc09bf5..690849ff6a 100644 --- a/vector/src/main/res/values-pl/strings.xml +++ b/vector/src/main/res/values-pl/strings.xml @@ -11,7 +11,6 @@ Zapisz Opuść Wyślij - Kopiuj Wyślij ponownie Usuń Cytuj diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml index ef44f53cf4..4032fe0764 100644 --- a/vector/src/main/res/values-pt-rBR/strings.xml +++ b/vector/src/main/res/values-pt-rBR/strings.xml @@ -22,7 +22,6 @@ Salvar Sair da sala Enviar - Copiar Reenviar Apagar Citar diff --git a/vector/src/main/res/values-pt/strings.xml b/vector/src/main/res/values-pt/strings.xml index 03dc9f385a..52c7512b7c 100644 --- a/vector/src/main/res/values-pt/strings.xml +++ b/vector/src/main/res/values-pt/strings.xml @@ -18,7 +18,6 @@ Guardar Sair Enviar - Copiar Reenviar Apagar Citar diff --git a/vector/src/main/res/values-ru/strings.xml b/vector/src/main/res/values-ru/strings.xml index 60e5f6c388..457999e554 100644 --- a/vector/src/main/res/values-ru/strings.xml +++ b/vector/src/main/res/values-ru/strings.xml @@ -22,7 +22,6 @@ Сохранить Покинуть Отправить - Копировать Повторить отправку Удалить Цитировать diff --git a/vector/src/main/res/values-sk/strings.xml b/vector/src/main/res/values-sk/strings.xml index e8a9495b1f..66ba1f354d 100644 --- a/vector/src/main/res/values-sk/strings.xml +++ b/vector/src/main/res/values-sk/strings.xml @@ -25,7 +25,6 @@ Uložiť Opustiť Odoslať - Kopírovať Odoslať znovu Vymazať Citovať diff --git a/vector/src/main/res/values-sq/strings.xml b/vector/src/main/res/values-sq/strings.xml index ea84d963d1..43506d8798 100644 --- a/vector/src/main/res/values-sq/strings.xml +++ b/vector/src/main/res/values-sq/strings.xml @@ -26,7 +26,6 @@ Ruaje Dil Dërgoje - Kopjoje Ridërgoje Citim Shkarkoje diff --git a/vector/src/main/res/values-sr/strings.xml b/vector/src/main/res/values-sr/strings.xml index 121589a6cd..8701fc6eeb 100644 --- a/vector/src/main/res/values-sr/strings.xml +++ b/vector/src/main/res/values-sr/strings.xml @@ -43,7 +43,6 @@ Напусти Остани Пошаљи - Копирај Пошаљи поново Уклони Подели diff --git a/vector/src/main/res/values-sv/strings.xml b/vector/src/main/res/values-sv/strings.xml index 8b42d3db9f..3db9d3c48d 100644 --- a/vector/src/main/res/values-sv/strings.xml +++ b/vector/src/main/res/values-sv/strings.xml @@ -48,7 +48,6 @@ Lämna Stanna Skicka - Kopiera Skicka igen Ta bort Citat diff --git a/vector/src/main/res/values-te/strings.xml b/vector/src/main/res/values-te/strings.xml index 28609a17f7..c73b9f7b9c 100644 --- a/vector/src/main/res/values-te/strings.xml +++ b/vector/src/main/res/values-te/strings.xml @@ -16,7 +16,6 @@ చారిత్రిక వదిలివేయు - నకలుతీయు తిరిగిపంపు సందేశాలు అమరికలు diff --git a/vector/src/main/res/values-th/strings.xml b/vector/src/main/res/values-th/strings.xml index 3ca04aae89..fe0d0ff6f7 100644 --- a/vector/src/main/res/values-th/strings.xml +++ b/vector/src/main/res/values-th/strings.xml @@ -29,7 +29,6 @@ บันทึก ออก ส่ง - คัดลอก ดาวน์โหลด แชร์ พูด diff --git a/vector/src/main/res/values-tlh/strings.xml b/vector/src/main/res/values-tlh/strings.xml index 407e507396..5b9af280df 100644 --- a/vector/src/main/res/values-tlh/strings.xml +++ b/vector/src/main/res/values-tlh/strings.xml @@ -27,7 +27,6 @@ choq mej ngeH - velqa\' chenmoH ngeHqa\' jatlhqa\' lI\' diff --git a/vector/src/main/res/values-tr/strings.xml b/vector/src/main/res/values-tr/strings.xml index e906dafb39..31efd3eba7 100644 --- a/vector/src/main/res/values-tr/strings.xml +++ b/vector/src/main/res/values-tr/strings.xml @@ -33,7 +33,6 @@ Ayrıl Gönder - Kopyala Tekrar gönder Sil Alıntı diff --git a/vector/src/main/res/values-uk/strings.xml b/vector/src/main/res/values-uk/strings.xml index 5a0d12bd76..7ed1791908 100644 --- a/vector/src/main/res/values-uk/strings.xml +++ b/vector/src/main/res/values-uk/strings.xml @@ -29,7 +29,6 @@ Зберегти Залишити Надіслати - Копіювати Надіслати ще раз Прибрати Цитата diff --git a/vector/src/main/res/values-zh-rCN/strings.xml b/vector/src/main/res/values-zh-rCN/strings.xml index 6122f746e3..3cbcbb0875 100644 --- a/vector/src/main/res/values-zh-rCN/strings.xml +++ b/vector/src/main/res/values-zh-rCN/strings.xml @@ -66,7 +66,6 @@ 保存 离开 发送 - 复制 查看源代码 查看解密后的源代码 diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml index 6bba7c9f11..9fa649b6da 100644 --- a/vector/src/main/res/values-zh-rTW/strings.xml +++ b/vector/src/main/res/values-zh-rTW/strings.xml @@ -35,7 +35,6 @@ 歷史 社群細節 - 複製 移除 引用 稍後 diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index d130bc910b..167655f800 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -56,7 +56,6 @@ Leave Stay Send - Copy Resend Remove Quote From 43f34f6330ea07d0fdb3bc5cc6a93ab185d5e5b0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 16 Sep 2020 20:40:05 +0200 Subject: [PATCH 88/89] Fix issue on test compilation --- .../matrix/android/sdk/common/TestMatrixComponent.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixComponent.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixComponent.kt index 50290e1d63..e2ab16cad3 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixComponent.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixComponent.kt @@ -25,8 +25,16 @@ import org.matrix.android.sdk.internal.di.MatrixComponent import org.matrix.android.sdk.internal.di.MatrixModule import org.matrix.android.sdk.internal.di.MatrixScope import org.matrix.android.sdk.internal.di.NetworkModule +import org.matrix.android.sdk.internal.raw.RawModule -@Component(modules = [TestModule::class, MatrixModule::class, NetworkModule::class, AuthModule::class, TestNetworkModule::class]) +@Component(modules = [ + TestModule::class, + MatrixModule::class, + NetworkModule::class, + AuthModule::class, + RawModule::class, + TestNetworkModule::class +]) @MatrixScope internal interface TestMatrixComponent : MatrixComponent { From 01af5115a25a1959d03f357390ce36f7601f5dfd Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 17 Sep 2020 09:31:09 +0200 Subject: [PATCH 89/89] Prepare release 1.0.7 --- CHANGES.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index f373a4edfd..638e7f586c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,9 +1,6 @@ -Changes in Element 1.0.7 (2020-XX-XX) +Changes in Element 1.0.7 (2020-09-17) =================================================== -Features ✨: - - - Improvements 🙌: - Handle date formatting properly (show time am/pm if needed, display year when needed) - Improve F-Droid Notification (#2055) @@ -17,15 +14,9 @@ Bugfix 🐛: - Allow users to show/hide room member state events (#1231) - Fix stuck on loader when launching home -Translations 🗣: - - - SDK API changes ⚠️: - Create a new RawService to get plain data from the server. -Build 🧱: - - - Other changes: - Performance: share Realm instance used on UI thread and improve SharedPreferences reading time.