Merge branch 'develop' into feature/fga/pinned_message_banner_logic

This commit is contained in:
ganfra 2024-08-05 20:46:24 +02:00
commit 229c02e895
45 changed files with 994 additions and 606 deletions

View file

@ -1,7 +1,7 @@
[![Latest build](https://github.com/element-hq/element-x-android/actions/workflows/build.yml/badge.svg?query=branch%3Adevelop)](https://github.com/element-hq/element-x-android/actions/workflows/build.yml?query=branch%3Adevelop)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vector-im_element-x-android&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android)
[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=vector-im_element-x-android&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android)
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=vector-im_element-x-android&metric=bugs)](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=element-x-android&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=element-x-android)
[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=element-x-android&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=element-x-android)
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=element-x-android&metric=bugs)](https://sonarcloud.io/summary/new_code?id=element-x-android)
[![codecov](https://codecov.io/github/element-hq/element-x-android/branch/develop/graph/badge.svg?token=ecwvia7amV)](https://codecov.io/github/vector-im/element-x-android)
[![Element X Android Matrix room #element-x-android:matrix.org](https://img.shields.io/matrix/element-x-android:matrix.org.svg?label=%23element-x-android:matrix.org&logo=matrix&server_fqdn=matrix.org)](https://matrix.to/#/#element-x-android:matrix.org)
[![Localazy](https://img.shields.io/endpoint?url=https%3A%2F%2Fconnect.localazy.com%2Fstatus%2Felement%2Fdata%3Fcontent%3Dall%26title%3Dlocalazy%26logo%3Dtrue)](https://localazy.com/p/element)

View file

@ -129,11 +129,11 @@ dependencyAnalysis {
// To run a sonar analysis:
// Run './gradlew sonar -Dsonar.login=<SONAR_LOGIN>'
// The SONAR_LOGIN is stored in passbolt as Token Sonar Cloud Bma
// Sonar result can be found here: https://sonarcloud.io/project/overview?id=vector-im_element-x-android
// Sonar result can be found here: https://sonarcloud.io/project/overview?id=element-x-android
sonar {
properties {
property("sonar.projectName", "element-x-android")
property("sonar.projectKey", "vector-im_element-x-android")
property("sonar.projectKey", "element-x-android")
property("sonar.host.url", "https://sonarcloud.io")
property("sonar.projectVersion", "1.0") // TODO project(":app").android.defaultConfig.versionName)
property("sonar.sourceEncoding", "UTF-8")
@ -141,7 +141,7 @@ sonar {
property("sonar.links.ci", "https://github.com/element-hq/element-x-android/actions")
property("sonar.links.scm", "https://github.com/element-hq/element-x-android/")
property("sonar.links.issue", "https://github.com/element-hq/element-x-android/issues")
property("sonar.organization", "new_vector_ltd_organization")
property("sonar.organization", "element-hq")
property("sonar.login", if (project.hasProperty("SONAR_LOGIN")) project.property("SONAR_LOGIN")!! else "invalid")
// exclude source code from analyses separated by a colon (:)

View file

@ -36,6 +36,7 @@ import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.matrix.test.sync.FakeSyncService
import io.element.android.libraries.matrix.test.widget.FakeMatrixWidgetDriver
import io.element.android.libraries.network.useragent.UserAgentProvider
import io.element.android.services.analytics.api.ScreenTracker
@ -43,11 +44,13 @@ import io.element.android.services.analytics.test.FakeScreenTracker
import io.element.android.services.toolbox.api.systemclock.SystemClock
import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.consumeItemsUntilTimeout
import io.element.android.tests.testutils.lambda.assert
import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.value
import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.test.TestScope
@ -86,8 +89,9 @@ class CallScreenPresenterTest {
@Test
fun `present - with CallType RoomCall sets call as active, loads URL, runs WidgetDriver and notifies the other clients a call started`() = runTest {
val sendCallNotificationIfNeededLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
val syncService = FakeSyncService(MutableStateFlow(SyncState.Running))
val fakeRoom = FakeMatrixRoom(sendCallNotificationIfNeededResult = sendCallNotificationIfNeededLambda)
val client = FakeMatrixClient().apply {
val client = FakeMatrixClient(syncService = syncService).apply {
givenGetRoomResult(A_ROOM_ID, fakeRoom)
}
val widgetDriver = FakeMatrixWidgetDriver()
@ -216,7 +220,12 @@ class CallScreenPresenterTest {
fun `present - automatically starts the Matrix client sync when on RoomCall`() = runTest {
val navigator = FakeCallScreenNavigator()
val widgetDriver = FakeMatrixWidgetDriver()
val matrixClient = FakeMatrixClient()
val syncStateFlow = MutableStateFlow(SyncState.Idle)
val startSyncLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
val syncService = FakeSyncService(syncStateFlow = syncStateFlow).apply {
this.startSyncLambda = startSyncLambda
}
val matrixClient = FakeMatrixClient(syncService = syncService)
val presenter = createCallScreenPresenter(
callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID),
widgetDriver = widgetDriver,
@ -230,7 +239,7 @@ class CallScreenPresenterTest {
}.test {
consumeItemsUntilTimeout()
assertThat(matrixClient.syncService().syncState.value).isEqualTo(SyncState.Running)
assert(startSyncLambda).isCalledOnce()
cancelAndIgnoreRemainingEvents()
}
@ -240,7 +249,12 @@ class CallScreenPresenterTest {
fun `present - automatically stops the Matrix client sync on dispose`() = runTest {
val navigator = FakeCallScreenNavigator()
val widgetDriver = FakeMatrixWidgetDriver()
val matrixClient = FakeMatrixClient()
val syncStateFlow = MutableStateFlow(SyncState.Running)
val stopSyncLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
val syncService = FakeSyncService(syncStateFlow = syncStateFlow).apply {
this.stopSyncLambda = stopSyncLambda
}
val matrixClient = FakeMatrixClient(syncService = syncService)
val presenter = createCallScreenPresenter(
callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID),
widgetDriver = widgetDriver,
@ -262,7 +276,7 @@ class CallScreenPresenterTest {
job.cancelAndJoin()
assertThat(matrixClient.syncService().syncState.value).isEqualTo(SyncState.Terminated)
assert(stopSyncLambda).isCalledOnce()
}
private fun TestScope.createCallScreenPresenter(

View file

@ -95,6 +95,7 @@ import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Rule
@ -219,7 +220,7 @@ class RoomListPresenterTest {
val encryptionService = FakeEncryptionService().apply {
emitRecoveryState(RecoveryState.INCOMPLETE)
}
val syncService = FakeSyncService(initialState = SyncState.Running)
val syncService = FakeSyncService(MutableStateFlow(SyncState.Running))
val presenter = createRoomListPresenter(
client = FakeMatrixClient(roomListService = roomListService, encryptionService = encryptionService, syncService = syncService),
coroutineScope = scope,
@ -250,7 +251,7 @@ class RoomListPresenterTest {
sessionVerificationService = FakeSessionVerificationService().apply {
givenNeedsSessionVerification(false)
},
syncService = FakeSyncService(initialState = SyncState.Running)
syncService = FakeSyncService(MutableStateFlow(SyncState.Running))
)
val scope = CoroutineScope(context = coroutineContext + SupervisorJob())
val presenter = createRoomListPresenter(

View file

@ -3,6 +3,7 @@
<string name="screen_identity_confirmation_create_new_recovery_key">"Стварыць новы ключ аднаўлення"</string>
<string name="screen_identity_confirmation_subtitle">"Пацвердзіце гэтую прыладу, каб наладзіць бяспечны абмен паведамленнямі."</string>
<string name="screen_identity_confirmation_title">"Пацвердзіце, што гэта вы"</string>
<string name="screen_identity_confirmation_use_another_device">"Выкарыстоўвайце іншую прыладу"</string>
<string name="screen_identity_confirmed_subtitle">"Цяпер вы можаце бяспечна чытаць і адпраўляць паведамленні, і ўсе, з кім вы маеце зносіны ў чаце, таксама могуць давяраць гэтай прыладзе."</string>
<string name="screen_identity_confirmed_title">"Прылада праверана"</string>
<string name="screen_identity_use_another_device">"Выкарыстоўвайце іншую прыладу"</string>

View file

@ -3,6 +3,7 @@
<string name="screen_identity_confirmation_create_new_recovery_key">"Vytvoření nového klíče pro obnovení"</string>
<string name="screen_identity_confirmation_subtitle">"Ověřte toto zařízení a nastavte zabezpečené zasílání zpráv."</string>
<string name="screen_identity_confirmation_title">"Potvrďte, že jste to vy"</string>
<string name="screen_identity_confirmation_use_another_device">"Použít jiné zařízení"</string>
<string name="screen_identity_confirmed_subtitle">"Nyní můžete bezpečně číst nebo odesílat zprávy, a kdokoli, s kým chatujete, může tomuto zařízení důvěřovat."</string>
<string name="screen_identity_confirmed_title">"Zařízení ověřeno"</string>
<string name="screen_identity_use_another_device">"Použít jiné zařízení"</string>

View file

@ -3,6 +3,7 @@
<string name="screen_identity_confirmation_create_new_recovery_key">"Erstelle einen neuen Wiederherstellungsschlüssel"</string>
<string name="screen_identity_confirmation_subtitle">"Verifiziere dieses Gerät, um sicheres Messaging einzurichten."</string>
<string name="screen_identity_confirmation_title">"Bestätige, dass du es bist"</string>
<string name="screen_identity_confirmation_use_another_device">"Ein anderes Gerät verwenden"</string>
<string name="screen_identity_confirmed_subtitle">"Du kannst nun verschlüsselte Nachrichten lesen oder versenden."</string>
<string name="screen_identity_confirmed_title">"Gerät verifiziert"</string>
<string name="screen_identity_use_another_device">"Ein anderes Gerät verwenden"</string>

View file

@ -3,6 +3,7 @@
<string name="screen_identity_confirmation_create_new_recovery_key">"Δημιουργία νέου κλειδιού ανάκτησης"</string>
<string name="screen_identity_confirmation_subtitle">"Επαλήθευσε αυτήν τη συσκευή για να ρυθμίσεις την ασφαλή επικοινωνία."</string>
<string name="screen_identity_confirmation_title">"Επιβεβαίωσε ότι είσαι εσύ"</string>
<string name="screen_identity_confirmation_use_another_device">"Χρήση άλλης συσκευής"</string>
<string name="screen_identity_confirmed_subtitle">"Τώρα μπορείς να διαβάζεις ή να στέλνεις μηνύματα με ασφάλεια και επίσης μπορεί να εμπιστευτεί αυτήν τη συσκευή οποιοσδήποτε με τον οποίο συνομιλείς."</string>
<string name="screen_identity_confirmed_title">"Επαληθευμένη συσκευή"</string>
<string name="screen_identity_use_another_device">"Χρήση άλλης συσκευής"</string>

View file

@ -2,8 +2,10 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_identity_confirmation_subtitle">"Verifica este dispositivo para configurar la mensajería segura."</string>
<string name="screen_identity_confirmation_title">"Confirma que eres tú"</string>
<string name="screen_identity_confirmation_use_another_device">"Usar otro dispositivo"</string>
<string name="screen_identity_confirmed_subtitle">"Ahora puedes leer o enviar mensajes de forma segura y cualquier persona con la que chatees también puede confiar en este dispositivo."</string>
<string name="screen_identity_confirmed_title">"Dispositivo verificado"</string>
<string name="screen_identity_use_another_device">"Usar otro dispositivo"</string>
<string name="screen_session_verification_cancelled_subtitle">"Algo no fue bien. Se agotó el tiempo de espera de la solicitud o se rechazó."</string>
<string name="screen_session_verification_compare_emojis_subtitle">"Confirma que los emojis que aparecen a continuación coinciden con los que aparecen en tu otra sesión."</string>
<string name="screen_session_verification_compare_emojis_title">"Comparar emojis"</string>

View file

@ -1,11 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_identity_confirmation_cannot_confirm">"Kas kinnitamine pole võimalik?"</string>
<string name="screen_identity_confirmation_create_new_recovery_key">"Loo uus taastevõti"</string>
<string name="screen_identity_confirmation_subtitle">"Krüptitud sõnumivahetuse tagamiseks verifitseeri see seade."</string>
<string name="screen_identity_confirmation_title">"Kinnita, et see oled sina"</string>
<string name="screen_identity_confirmation_use_another_device">"Kasuta teist seadet"</string>
<string name="screen_identity_confirmation_use_recovery_key">"Kasuta taastevõtit"</string>
<string name="screen_identity_confirmed_subtitle">"Nüüd saad saata või lugeda sõnumeid turvaliselt ning kõik sinu vestluspartnerid võivad usaldada seda seadet."</string>
<string name="screen_identity_confirmed_title">"Seade on verifitseeritud"</string>
<string name="screen_identity_use_another_device">"Kasuta mõnda muud seadet"</string>
<string name="screen_identity_use_another_device">"Kasuta teist seadet"</string>
<string name="screen_identity_waiting_on_other_device">"Ootame teise seadme järgi…"</string>
<string name="screen_session_verification_cancelled_subtitle">"Olukord pole päris õige. Päring kas aegus või teine osapool keeldus päringule vastamast."</string>
<string name="screen_session_verification_compare_emojis_subtitle">"Kinnita, et kõik järgnevalt kuvatud emojid on täpselt samad, mida sa näed oma teises sessioonis."</string>

View file

@ -3,6 +3,7 @@
<string name="screen_identity_confirmation_create_new_recovery_key">"Créer une nouvelle clé de récupération"</string>
<string name="screen_identity_confirmation_subtitle">"Vérifier cette session pour configurer votre messagerie sécurisée."</string>
<string name="screen_identity_confirmation_title">"Confirmez votre identité"</string>
<string name="screen_identity_confirmation_use_another_device">"Utiliser une autre session"</string>
<string name="screen_identity_confirmed_subtitle">"Vous pouvez désormais lire ou envoyer des messages en toute sécurité, et toute personne avec qui vous discutez peut également faire confiance à cette session."</string>
<string name="screen_identity_confirmed_title">"Session vérifiée"</string>
<string name="screen_identity_use_another_device">"Utiliser une autre session"</string>

View file

@ -3,6 +3,7 @@
<string name="screen_identity_confirmation_create_new_recovery_key">"Új helyreállítási kulcs létrehozása"</string>
<string name="screen_identity_confirmation_subtitle">"A biztonságos üzenetkezelés beállításához ellenőrizze ezt az eszközt."</string>
<string name="screen_identity_confirmation_title">"Erősítse meg, hogy Ön az"</string>
<string name="screen_identity_confirmation_use_another_device">"Másik eszköz használata"</string>
<string name="screen_identity_confirmed_subtitle">"Mostantól biztonságosan olvashat vagy küldhet üzeneteket, és bármelyik csevegőpartnere megbízhat ebben az eszközben."</string>
<string name="screen_identity_confirmed_title">"Eszköz ellenőrizve"</string>
<string name="screen_identity_use_another_device">"Másik eszköz használata"</string>

View file

@ -3,6 +3,7 @@
<string name="screen_identity_confirmation_create_new_recovery_key">"Buat kunci pemulihan baru"</string>
<string name="screen_identity_confirmation_subtitle">"Verifikasi perangkat ini untuk menyiapkan perpesanan aman."</string>
<string name="screen_identity_confirmation_title">"Konfirmasi bahwa ini Anda"</string>
<string name="screen_identity_confirmation_use_another_device">"Gunakan perangkat lain"</string>
<string name="screen_identity_confirmed_subtitle">"Sekarang Anda dapat membaca atau mengirim pesan dengan aman, dan siapa pun yang mengobrol dengan Anda juga dapat mempercayai perangkat ini."</string>
<string name="screen_identity_confirmed_title">"Perangkat terverifikasi"</string>
<string name="screen_identity_use_another_device">"Gunakan perangkat lain"</string>

View file

@ -3,6 +3,7 @@
<string name="screen_identity_confirmation_create_new_recovery_key">"Crea una nuova chiave di recupero"</string>
<string name="screen_identity_confirmation_subtitle">"Verifica questo dispositivo per segnare i tuoi messaggi come sicuri."</string>
<string name="screen_identity_confirmation_title">"Conferma la tua identità"</string>
<string name="screen_identity_confirmation_use_another_device">"Usa un altro dispositivo"</string>
<string name="screen_identity_confirmed_subtitle">"Ora puoi leggere o inviare messaggi in tutta sicurezza e anche chi chatta con te può fidarsi di questo dispositivo."</string>
<string name="screen_identity_confirmed_title">"Dispositivo verificato"</string>
<string name="screen_identity_use_another_device">"Usa un altro dispositivo"</string>

View file

@ -3,6 +3,7 @@
<string name="screen_identity_confirmation_create_new_recovery_key">"Utwórz nowy klucz przywracania"</string>
<string name="screen_identity_confirmation_subtitle">"Zweryfikuj to urządzenie, aby skonfigurować bezpieczne przesyłanie wiadomości."</string>
<string name="screen_identity_confirmation_title">"Potwierdź, że to Ty"</string>
<string name="screen_identity_confirmation_use_another_device">"Użyj innego urządzenia"</string>
<string name="screen_identity_confirmed_subtitle">"Teraz możesz bezpiecznie czytać i wysyłać wiadomości, każdy z kim czatujesz również może ufać temu urządzeniu."</string>
<string name="screen_identity_confirmed_title">"Urządzenie zweryfikowane"</string>
<string name="screen_identity_use_another_device">"Użyj innego urządzenia"</string>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_identity_confirmation_use_another_device">"Usar outro dispositivo"</string>
<string name="screen_identity_confirmed_title">"Dispositivo verificado"</string>
<string name="screen_identity_use_another_device">"Usar outro dispositivo"</string>
<string name="screen_session_verification_cancelled_subtitle">"Algo não parece certo. Ou a solicitação atingiu o tempo limite ou a solicitação foi negada."</string>

View file

@ -1,8 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_identity_confirmation_cannot_confirm">"Não é possível confirmar?"</string>
<string name="screen_identity_confirmation_create_new_recovery_key">"Criar uma nova chave de recuperação"</string>
<string name="screen_identity_confirmation_subtitle">"Verifica este dispositivo para configurar o envio seguro de mensagens."</string>
<string name="screen_identity_confirmation_title">"Confirma que és tu"</string>
<string name="screen_identity_confirmation_use_another_device">"Utilizar outro dispositivo"</string>
<string name="screen_identity_confirmation_use_recovery_key">"Utilizar chave de recuperação"</string>
<string name="screen_identity_confirmed_subtitle">"Agora podes ler ou enviar mensagens de forma segura, e qualquer pessoa com quem converses também pode confiar neste dispositivo."</string>
<string name="screen_identity_confirmed_title">"Dispositivo verificado"</string>
<string name="screen_identity_use_another_device">"Utilizar outro dispositivo"</string>

View file

@ -3,6 +3,7 @@
<string name="screen_identity_confirmation_create_new_recovery_key">"Creați o nouă cheie de recuperare"</string>
<string name="screen_identity_confirmation_subtitle">"Verificați acest dispozitiv pentru a configura mesagerie securizată."</string>
<string name="screen_identity_confirmation_title">"Confirmați că sunteți dumneavoastră"</string>
<string name="screen_identity_confirmation_use_another_device">"Utilizați un alt dispozitiv"</string>
<string name="screen_identity_confirmed_subtitle">"Acum puteți citi sau trimite mesaje în siguranță, iar oricine cu care conversați poate avea încredere în acest dispozitiv."</string>
<string name="screen_identity_confirmed_title">"Dispozitiv verificat"</string>
<string name="screen_identity_use_another_device">"Utilizați un alt dispozitiv"</string>

View file

@ -1,11 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_identity_confirmation_cannot_confirm">"Не можете подтвердить?"</string>
<string name="screen_identity_confirmation_create_new_recovery_key">
"Создайте новый "
<b>"ключ восстановления"</b>
</string>
<string name="screen_identity_confirmation_subtitle">"Подтвердите это устройство, чтобы настроить безопасный обмен сообщениями."</string>
<string name="screen_identity_confirmation_title">"Подтвердите, что это вы"</string>
<string name="screen_identity_confirmation_use_another_device">"Используйте другое устройство"</string>
<string name="screen_identity_confirmation_use_recovery_key">"Используйте recovery key"</string>
<string name="screen_identity_confirmed_subtitle">"Теперь вы можете безопасно читать и отправлять сообщения, и все, с кем вы общаетесь в чате, также могут доверять этому устройству."</string>
<string name="screen_identity_confirmed_title">"Устройство проверено"</string>
<string name="screen_identity_use_another_device">"Используйте другое устройство"</string>

View file

@ -1,11 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_identity_confirmation_cannot_confirm">"Nemôžete potvrdiť?"</string>
<string name="screen_identity_confirmation_create_new_recovery_key">"Vytvoriť nový kľúč na obnovenie"</string>
<string name="screen_identity_confirmation_subtitle">"Ak chcete nastaviť zabezpečené správy, overte toto zariadenie."</string>
<string name="screen_identity_confirmation_title">"Potvrďte, že ste to vy"</string>
<string name="screen_identity_confirmation_use_another_device">"Použite iné zariadenie"</string>
<string name="screen_identity_confirmation_use_recovery_key">"Použiť kľúč na obnovenie"</string>
<string name="screen_identity_confirmed_subtitle">"Teraz môžete bezpečne čítať alebo odosielať správy a tomuto zariadeniu môže dôverovať aj ktokoľvek, s kým konverzujete."</string>
<string name="screen_identity_confirmed_title">"Zariadenie overené"</string>
<string name="screen_identity_use_another_device">"Použiť iné zariadenie"</string>
<string name="screen_identity_use_another_device">"Použite iné zariadenie"</string>
<string name="screen_identity_waiting_on_other_device">"Čaká sa na druhom zariadení…"</string>
<string name="screen_session_verification_cancelled_subtitle">"Zdá sa, že niečo nie je v poriadku. Časový limit žiadosti vypršal alebo bola žiadosť zamietnutá."</string>
<string name="screen_session_verification_compare_emojis_subtitle">"Skontrolujte, či sa emotikony uvedené nižšie zhodujú s emotikonmi zobrazenými vo vašej druhej relácii."</string>

View file

@ -3,6 +3,7 @@
<string name="screen_identity_confirmation_create_new_recovery_key">"Skapa en ny återställningsnyckel"</string>
<string name="screen_identity_confirmation_subtitle">"Verifiera den här enheten för att konfigurera säkra meddelanden."</string>
<string name="screen_identity_confirmation_title">"Bekräfta att det är du"</string>
<string name="screen_identity_confirmation_use_another_device">"Använd en annan enhet"</string>
<string name="screen_identity_confirmed_subtitle">"Nu kan du läsa eller skicka meddelanden säkert, och alla du chattar med kan också lita på den här enheten."</string>
<string name="screen_identity_confirmed_title">"Enhet verifierad"</string>
<string name="screen_identity_use_another_device">"Använd en annan enhet"</string>

View file

@ -3,6 +3,7 @@
<string name="screen_identity_confirmation_create_new_recovery_key">"建立新的復原金鑰"</string>
<string name="screen_identity_confirmation_subtitle">"驗證這部裝置以設定安全通訊。"</string>
<string name="screen_identity_confirmation_title">"確認這是你本人"</string>
<string name="screen_identity_confirmation_use_another_device">"使用另一部裝置"</string>
<string name="screen_identity_confirmed_subtitle">"您可以安全地讀取和發送訊息了,與您聊天的人也可以信任這部裝置。"</string>
<string name="screen_identity_confirmed_title">"裝置已驗證"</string>
<string name="screen_identity_use_another_device">"使用另一部裝置"</string>

View file

@ -3,6 +3,7 @@
<string name="screen_identity_confirmation_create_new_recovery_key">"创建新的恢复密钥"</string>
<string name="screen_identity_confirmation_subtitle">"验证此设备以开始安全地收发消息。"</string>
<string name="screen_identity_confirmation_title">"确认这是你"</string>
<string name="screen_identity_confirmation_use_another_device">"使用其他设备"</string>
<string name="screen_identity_confirmed_subtitle">"现在,您可以安全地阅读或发送消息,与您聊天的人也会信任此设备。"</string>
<string name="screen_identity_confirmed_title">"设备已验证"</string>
<string name="screen_identity_use_another_device">"使用其他设备"</string>

View file

@ -1,8 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_identity_confirmation_cannot_confirm">"Can\'t confirm?"</string>
<string name="screen_identity_confirmation_create_new_recovery_key">"Create a new recovery key"</string>
<string name="screen_identity_confirmation_subtitle">"Verify this device to set up secure messaging."</string>
<string name="screen_identity_confirmation_title">"Confirm that it\'s you"</string>
<string name="screen_identity_confirmation_use_another_device">"Use another device"</string>
<string name="screen_identity_confirmation_use_recovery_key">"Use recovery key"</string>
<string name="screen_identity_confirmed_subtitle">"Now you can read or send messages securely, and anyone you chat with can also trust this device."</string>
<string name="screen_identity_confirmed_title">"Device verified"</string>
<string name="screen_identity_use_another_device">"Use another device"</string>

View file

@ -163,7 +163,7 @@ jsoup = "org.jsoup:jsoup:1.18.1"
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
molecule-runtime = "app.cash.molecule:molecule-runtime:2.0.0"
timber = "com.jakewharton.timber:timber:5.0.1"
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.35"
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.36"
matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" }
sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }

View file

@ -45,6 +45,12 @@
<string name="state_event_room_name_removed_by_you">"Вы выдалілі назву пакоя"</string>
<string name="state_event_room_none">"%1$s не зрабіў(-ла) ніякіх змен"</string>
<string name="state_event_room_none_by_you">"Вы не зрабілі ніякіх змен"</string>
<string name="state_event_room_pinned_events_changed">"%1$s змяніў(-ла) замацаваныя паведамленні"</string>
<string name="state_event_room_pinned_events_changed_by_you">"Вы змянілі замацаваныя паведамленні"</string>
<string name="state_event_room_pinned_events_pinned">"%1$s замацаваў(-ла) паведамленне"</string>
<string name="state_event_room_pinned_events_pinned_by_you">"Вы замацавалі паведамленне"</string>
<string name="state_event_room_pinned_events_unpinned">"%1$s адмацаваў(-ла) паведамленне"</string>
<string name="state_event_room_pinned_events_unpinned_by_you">"Вы адмацавалі паведамленне"</string>
<string name="state_event_room_reject">"%1$s адхіліў(-ла) запрашэнне"</string>
<string name="state_event_room_reject_by_you">"Вы адхілілі запрашэнне"</string>
<string name="state_event_room_remove">"%1$s выдаліў(-ла) %2$s"</string>

View file

@ -45,6 +45,12 @@
<string name="state_event_room_name_removed_by_you">"Sina eemaldasid jututoa nime"</string>
<string name="state_event_room_none">"%1$s ei teinud ühtegi muudatust"</string>
<string name="state_event_room_none_by_you">"Sina ei teinud ühtegi muudatust"</string>
<string name="state_event_room_pinned_events_changed">"%1$s muutis klammerdatud sõnumeid"</string>
<string name="state_event_room_pinned_events_changed_by_you">"Sina muutsid klammerdatud sõnumeid"</string>
<string name="state_event_room_pinned_events_pinned">"%1$s klammerdas sõnumi"</string>
<string name="state_event_room_pinned_events_pinned_by_you">"Sina klammerdasid sõnumi"</string>
<string name="state_event_room_pinned_events_unpinned">"%1$s eemaldas klammerdatud sõnumi"</string>
<string name="state_event_room_pinned_events_unpinned_by_you">"Sina eemaldasid klammerdatud sõnumi"</string>
<string name="state_event_room_reject">"%1$s lükkas kutse tagasi"</string>
<string name="state_event_room_reject_by_you">"Sina lükkasid kutse tagasi"</string>
<string name="state_event_room_remove">"%1$s eemaldas jututoast kasutaja %2$s"</string>

View file

@ -45,6 +45,12 @@
<string name="state_event_room_name_removed_by_you">"Removeste o nome da sala"</string>
<string name="state_event_room_none">"%1$s não fiz nenhuma alteração"</string>
<string name="state_event_room_none_by_you">"Não fizeste nenhuma alteração"</string>
<string name="state_event_room_pinned_events_changed">"%1$s alterou as mensagens afixadas"</string>
<string name="state_event_room_pinned_events_changed_by_you">"Alteraste as mensagens afixadas"</string>
<string name="state_event_room_pinned_events_pinned">"%1$s afixou uma mensagem"</string>
<string name="state_event_room_pinned_events_pinned_by_you">"Afixaste uma mensagem"</string>
<string name="state_event_room_pinned_events_unpinned">"%1$s desafixou uma mensagem"</string>
<string name="state_event_room_pinned_events_unpinned_by_you">"Desafixaste uma mensagem"</string>
<string name="state_event_room_reject">"%1$s rejeitou o convite"</string>
<string name="state_event_room_reject_by_you">"Rejeitaste o convite"</string>
<string name="state_event_room_remove">"%1$s removeu %2$s"</string>

View file

@ -45,6 +45,12 @@
<string name="state_event_room_name_removed_by_you">"Вы удалили название комнаты"</string>
<string name="state_event_room_none">"%1$s ничего не изменил"</string>
<string name="state_event_room_none_by_you">"Вы не внесли никаких изменений"</string>
<string name="state_event_room_pinned_events_changed">"%1$s изменил закрепленные сообщения"</string>
<string name="state_event_room_pinned_events_changed_by_you">"Вы изменили закрепленные сообщения"</string>
<string name="state_event_room_pinned_events_pinned">"%1$s закрепил сообщение"</string>
<string name="state_event_room_pinned_events_pinned_by_you">"Вы закрепили сообщение"</string>
<string name="state_event_room_pinned_events_unpinned">"%1$s открепил сообщение"</string>
<string name="state_event_room_pinned_events_unpinned_by_you">"Вы открепили сообщение"</string>
<string name="state_event_room_reject">"%1$s отклонил приглашение"</string>
<string name="state_event_room_reject_by_you">"Вы отклонили приглашение"</string>
<string name="state_event_room_remove">"%1$s удалил %2$s"</string>

View file

@ -45,6 +45,12 @@
<string name="state_event_room_name_removed_by_you">"Odstránili ste názov miestnosti"</string>
<string name="state_event_room_none">"%1$s nevykonal/a žiadne zmeny"</string>
<string name="state_event_room_none_by_you">"Nevykonali ste žiadne zmeny"</string>
<string name="state_event_room_pinned_events_changed">"%1$s zmenil/a pripnuté správy"</string>
<string name="state_event_room_pinned_events_changed_by_you">"Zmenili ste pripnuté správy"</string>
<string name="state_event_room_pinned_events_pinned">"%1$s pripol/la správu"</string>
<string name="state_event_room_pinned_events_pinned_by_you">"Pripli ste správu"</string>
<string name="state_event_room_pinned_events_unpinned">"%1$s zrušil/a pripnutie správy"</string>
<string name="state_event_room_pinned_events_unpinned_by_you">"Zrušili ste pripnutie správy"</string>
<string name="state_event_room_reject">"%1$s odmietol/a pozvánku"</string>
<string name="state_event_room_reject_by_you">"Odmietli ste pozvánku"</string>
<string name="state_event_room_remove">"%1$s odstránil/a %2$s"</string>

View file

@ -45,6 +45,12 @@
<string name="state_event_room_name_removed_by_you">"You removed the room name"</string>
<string name="state_event_room_none">"%1$s made no changes"</string>
<string name="state_event_room_none_by_you">"You made no changes"</string>
<string name="state_event_room_pinned_events_changed">"%1$s changed the pinned messages"</string>
<string name="state_event_room_pinned_events_changed_by_you">"You changed the pinned messages"</string>
<string name="state_event_room_pinned_events_pinned">"%1$s pinned a message"</string>
<string name="state_event_room_pinned_events_pinned_by_you">"You pinned a message"</string>
<string name="state_event_room_pinned_events_unpinned">"%1$s unpinned a message"</string>
<string name="state_event_room_pinned_events_unpinned_by_you">"You unpinned a message"</string>
<string name="state_event_room_reject">"%1$s rejected the invitation"</string>
<string name="state_event_room_reject_by_you">"You rejected the invitation"</string>
<string name="state_event_room_remove">"%1$s removed %2$s"</string>

View file

@ -140,6 +140,7 @@ class FakeMatrixRoom(
private val saveComposerDraftLambda: (ComposerDraft) -> Result<Unit> = { _: ComposerDraft -> Result.success(Unit) },
private val loadComposerDraftLambda: () -> Result<ComposerDraft?> = { Result.success<ComposerDraft?>(null) },
private val clearComposerDraftLambda: () -> Result<Unit> = { Result.success(Unit) },
private val subscribeToSyncLambda: () -> Unit = { lambdaError() },
) : MatrixRoom {
private val _roomInfoFlow: MutableSharedFlow<MatrixRoomInfo> = MutableSharedFlow(replay = 1)
override val roomInfoFlow: Flow<MatrixRoomInfo> = _roomInfoFlow
@ -186,7 +187,9 @@ class FakeMatrixRoom(
pinnedEventsTimelineResult()
}
override suspend fun subscribeToSync() = Unit
override suspend fun subscribeToSync() {
subscribeToSyncLambda()
}
override suspend fun powerLevels(): Result<MatrixRoomPowerLevels> {
return powerLevelsResult()

View file

@ -22,22 +22,16 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
class FakeSyncService(
initialState: SyncState = SyncState.Idle
syncStateFlow: MutableStateFlow<SyncState> = MutableStateFlow(SyncState.Idle)
) : SyncService {
private val syncStateFlow = MutableStateFlow(initialState)
fun simulateError() {
syncStateFlow.value = SyncState.Error
}
var startSyncLambda: () -> Result<Unit> = { Result.success(Unit) }
override suspend fun startSync(): Result<Unit> {
syncStateFlow.value = SyncState.Running
return Result.success(Unit)
return startSyncLambda()
}
var stopSyncLambda: () -> Result<Unit> = { Result.success(Unit) }
override suspend fun stopSync(): Result<Unit> {
syncStateFlow.value = SyncState.Terminated
return Result.success(Unit)
return stopSyncLambda()
}
override val syncState: StateFlow<SyncState> = syncStateFlow

View file

@ -82,4 +82,6 @@ dependencies {
testImplementation(projects.services.appnavstate.test)
testImplementation(projects.services.toolbox.impl)
testImplementation(projects.services.toolbox.test)
testImplementation(projects.libraries.featureflag.test)
testImplementation(libs.kotlinx.collections.immutable)
}

View file

@ -18,9 +18,6 @@ package io.element.android.libraries.push.impl.push
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.matrix.api.MatrixClientProvider
import io.element.android.libraries.push.impl.notifications.DefaultNotificationDrawerManager
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
import kotlinx.coroutines.CoroutineScope
@ -35,23 +32,12 @@ interface OnNotifiableEventReceived {
class DefaultOnNotifiableEventReceived @Inject constructor(
private val defaultNotificationDrawerManager: DefaultNotificationDrawerManager,
private val coroutineScope: CoroutineScope,
private val matrixClientProvider: MatrixClientProvider,
private val featureFlagService: FeatureFlagService,
private val syncOnNotifiableEvent: SyncOnNotifiableEvent,
) : OnNotifiableEventReceived {
override fun onNotifiableEventReceived(notifiableEvent: NotifiableEvent) {
coroutineScope.launch {
subscribeToRoomIfNeeded(notifiableEvent)
launch { syncOnNotifiableEvent(notifiableEvent) }
defaultNotificationDrawerManager.onNotifiableEventReceived(notifiableEvent)
}
}
private fun CoroutineScope.subscribeToRoomIfNeeded(notifiableEvent: NotifiableEvent) = launch {
if (!featureFlagService.isFeatureEnabled(FeatureFlags.SyncOnPush)) {
return@launch
}
val client = matrixClientProvider.getOrRestore(notifiableEvent.sessionId).getOrNull() ?: return@launch
client.getRoom(notifiableEvent.roomId)?.use { room ->
room.subscribeToSync()
}
}
}

View file

@ -0,0 +1,87 @@
/*
* Copyright (c) 2024 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
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.push.impl.push
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.matrix.api.MatrixClientProvider
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.sync.SyncService
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
import io.element.android.services.appnavstate.api.AppForegroundStateService
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
import java.util.concurrent.atomic.AtomicInteger
import javax.inject.Inject
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
class SyncOnNotifiableEvent @Inject constructor(
private val matrixClientProvider: MatrixClientProvider,
private val featureFlagService: FeatureFlagService,
private val appForegroundStateService: AppForegroundStateService,
private val dispatchers: CoroutineDispatchers,
) {
private var syncCounter = AtomicInteger(0)
suspend operator fun invoke(notifiableEvent: NotifiableEvent) = withContext(dispatchers.io) {
if (!featureFlagService.isFeatureEnabled(FeatureFlags.SyncOnPush)) {
return@withContext
}
val client = matrixClientProvider.getOrRestore(notifiableEvent.sessionId).getOrNull() ?: return@withContext
client.getRoom(notifiableEvent.roomId)?.use { room ->
room.subscribeToSync()
// If the app is in foreground, sync is already running, so just add the subscription.
if (!appForegroundStateService.isInForeground.value) {
val syncService = client.syncService()
syncService.startSyncIfNeeded()
room.waitsUntilEventIsKnown(eventId = notifiableEvent.eventId, timeout = 10.seconds)
syncService.stopSyncIfNeeded()
}
}
}
private suspend fun MatrixRoom.waitsUntilEventIsKnown(eventId: EventId, timeout: Duration) {
withTimeoutOrNull(timeout) {
liveTimeline.timelineItems.first { timelineItems ->
timelineItems.any { timelineItem ->
when (timelineItem) {
is MatrixTimelineItem.Event -> timelineItem.eventId == eventId
else -> false
}
}
}
}
}
private suspend fun SyncService.startSyncIfNeeded() {
if (syncCounter.getAndIncrement() == 0) {
startSync()
}
}
private suspend fun SyncService.stopSyncIfNeeded() {
if (syncCounter.decrementAndGet() == 0 && !appForegroundStateService.isInForeground.value) {
stopSync()
}
}
}

View file

@ -0,0 +1,151 @@
/*
* Copyright (c) 2024 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
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.push.impl.push
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.sync.SyncState
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_UNIQUE_ID
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.matrix.test.sync.FakeSyncService
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
import io.element.android.tests.testutils.lambda.assert
import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Test
class SyncOnNotifiableEventTest {
private val timelineItems = MutableStateFlow<List<MatrixTimelineItem>>(emptyList())
private val syncStateFlow = MutableStateFlow(SyncState.Idle)
private val startSyncLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
private val stopSyncLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
private val subscribeToSyncLambda = lambdaRecorder<Unit> { }
private val liveTimeline = FakeTimeline(
timelineItems = timelineItems,
)
private val room = FakeMatrixRoom(
roomId = A_ROOM_ID,
liveTimeline = liveTimeline,
subscribeToSyncLambda = subscribeToSyncLambda
)
private val syncService = FakeSyncService(syncStateFlow).also {
it.startSyncLambda = startSyncLambda
it.stopSyncLambda = stopSyncLambda
}
private val client = FakeMatrixClient(
syncService = syncService,
).apply {
givenGetRoomResult(A_ROOM_ID, room)
}
private val notifiableEvent = aNotifiableMessageEvent()
@Test
fun `when feature flag is disabled, nothing happens`() = runTest {
val sut = createSyncOnNotifiableEvent(client = client, isSyncOnPushEnabled = false)
sut(notifiableEvent)
assert(startSyncLambda).isNeverCalled()
assert(stopSyncLambda).isNeverCalled()
assert(subscribeToSyncLambda).isNeverCalled()
}
@Test
fun `when feature flag is enabled and app is in foreground, sync is not started`() = runTest {
val sut = createSyncOnNotifiableEvent(client = client, isAppInForeground = true, isSyncOnPushEnabled = true)
sut(notifiableEvent)
assert(startSyncLambda).isNeverCalled()
assert(stopSyncLambda).isNeverCalled()
assert(subscribeToSyncLambda).isCalledOnce()
}
@Test
fun `when feature flag is enabled and app is in background, sync is started and stopped`() = runTest {
val sut = createSyncOnNotifiableEvent(client = client, isAppInForeground = false, isSyncOnPushEnabled = true)
timelineItems.emit(
listOf(MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem()))
)
syncStateFlow.emit(SyncState.Running)
sut(notifiableEvent)
assert(startSyncLambda).isCalledOnce()
assert(stopSyncLambda).isCalledOnce()
assert(subscribeToSyncLambda).isCalledOnce()
}
@Test
fun `when feature flag is enabled and app is in background, running multiple time only call once`() = runTest {
val sut = createSyncOnNotifiableEvent(client = client, isAppInForeground = false, isSyncOnPushEnabled = true)
coroutineScope {
launch { sut(notifiableEvent) }
launch { sut(notifiableEvent) }
launch {
delay(1)
timelineItems.emit(
listOf(MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem()))
)
}
}
assert(startSyncLambda).isCalledOnce()
assert(stopSyncLambda).isCalledOnce()
assert(subscribeToSyncLambda).isCalledExactly(2)
}
private fun TestScope.createSyncOnNotifiableEvent(
client: MatrixClient = FakeMatrixClient(),
isSyncOnPushEnabled: Boolean = true,
isAppInForeground: Boolean = true,
): SyncOnNotifiableEvent {
val featureFlagService = FakeFeatureFlagService(
initialState = mapOf(
FeatureFlags.SyncOnPush.key to isSyncOnPushEnabled
)
)
val appForegroundStateService = FakeAppForegroundStateService(
initialValue = isAppInForeground
)
val matrixClientProvider = FakeMatrixClientProvider { Result.success(client) }
return SyncOnNotifiableEvent(
matrixClientProvider = matrixClientProvider,
featureFlagService = featureFlagService,
appForegroundStateService = appForegroundStateService,
dispatchers = testCoroutineDispatchers(),
)
}
}

View file

@ -91,6 +91,7 @@
<string name="action_report_bug">"Teata veast"</string>
<string name="action_report_content">"Teata sisust haldurile"</string>
<string name="action_reset">"Lähtesta"</string>
<string name="action_reset_identity">"Lähtesta on identiteet"</string>
<string name="action_retry">"Proovi uuesti"</string>
<string name="action_retry_decryption">"Proovi dekrüptimist uuesti"</string>
<string name="action_save">"Salvesta"</string>
@ -266,9 +267,21 @@ Põhjus: %1$s."</string>
<string name="invite_friends_text">"Hei, suhtle minuga %1$s võrgus: %2$s"</string>
<string name="login_initial_device_name_android">"%1$s Android"</string>
<string name="preference_rageshake">"Veast teatamiseks raputa nutiseadet ägedalt"</string>
<string name="screen_encryption_reset_bullet_1">"Sinu kasutajakonto andmed, kontaktid, eelistused ja vestluste loend säiluvad"</string>
<string name="screen_encryption_reset_bullet_2">"Sa kaotad seniste sõnumite ajaloo"</string>
<string name="screen_encryption_reset_bullet_3">"Sa pead kõik oma olemasolevad seadmed ja kontaktid uuesti verifitseerima"</string>
<string name="screen_encryption_reset_footer">"Lähtesta oma identiteet vaid siis, kui sul pole ligipääsu mitte ühelegi oma seadmele ja sa oled kaotanud oma taastevõtme."</string>
<string name="screen_encryption_reset_subtitle">"Kui sa soovid jätkata selle rakenduse kasutamist ja sa pole mitte üheski seadmes sisse logitud ning oled kaotanud oma taastevõtme, siis tõesti pead lähtestama oma identiteedi. "</string>
<string name="screen_encryption_reset_title">"Kui sa ühtegi muud võimalust ei leia, siis lähtesta oma identiteet."</string>
<string name="screen_media_picker_error_failed_selection">"Meediafaili valimine ei õnnestunud. Palun proovi uuesti."</string>
<string name="screen_media_upload_preview_error_failed_processing">"Meediafaili töötlemine enne üleslaadimist ei õnnestunud. Palun proovi uuesti."</string>
<string name="screen_media_upload_preview_error_failed_sending">"Meediafaili üleslaadimine ei õnnestunud. Palun proovi uuesti."</string>
<string name="screen_reset_encryption_confirmation_alert_action">"Jah, lähtesta nüüd"</string>
<string name="screen_reset_encryption_confirmation_alert_subtitle">"See tegevus on tagasipöördumatu."</string>
<string name="screen_reset_encryption_confirmation_alert_title">"Kas sa oled kindel, et soovid oma andmete krüptimist lähtestada?"</string>
<string name="screen_reset_encryption_password_placeholder">"Sisesta…"</string>
<string name="screen_reset_encryption_password_subtitle">"Palun kinnita, et soovid oma andmete krüptimist lähtestada."</string>
<string name="screen_reset_encryption_password_title">"Jätkamaks sisesta oma kasutajakonto salasõna"</string>
<string name="screen_room_error_failed_processing_media">"Meediafaili töötlemine enne üleslaadimist ei õnnestunud. Palun proovi uuesti."</string>
<string name="screen_room_error_failed_retrieving_user_details">"Kasutaja andmete laadimine ei õnnestunud"</string>
<string name="screen_room_member_details_block_alert_action">"Blokeeri"</string>

View file

@ -80,6 +80,7 @@
<string name="action_ok">"OK"</string>
<string name="action_open_settings">"Configurações"</string>
<string name="action_open_with">"Abrir com"</string>
<string name="action_pin">"Afixar"</string>
<string name="action_quick_reply">"Resposta rápida"</string>
<string name="action_quote">"Citação"</string>
<string name="action_react">"Reagir"</string>
@ -90,6 +91,7 @@
<string name="action_report_bug">"Comunicar problema"</string>
<string name="action_report_content">"Denunciar conteúdo"</string>
<string name="action_reset">"Repor"</string>
<string name="action_reset_identity">"Repor identidade"</string>
<string name="action_retry">"Tentar novamente"</string>
<string name="action_retry_decryption">"Tentar decifragem novamente"</string>
<string name="action_save">"Guardar"</string>
@ -109,6 +111,7 @@
<string name="action_take_photo">"Tirar foto"</string>
<string name="action_tap_for_options">"Toca para ver as opções"</string>
<string name="action_try_again">"Tentar novamente"</string>
<string name="action_unpin">"Desafixar"</string>
<string name="action_view_source">"Ver fonte"</string>
<string name="action_yes">"Sim"</string>
<string name="common_about">"Sobre"</string>
@ -168,6 +171,7 @@ Razão: %1$s."</string>
<string name="common_no_results">"Sem resultados"</string>
<string name="common_no_room_name">"Sala sem nome"</string>
<string name="common_offline">"Desligado"</string>
<string name="common_open_source_licenses">"Licenças de código aberto"</string>
<string name="common_or">"ou"</string>
<string name="common_password">"Senha"</string>
<string name="common_people">"Pessoas"</string>
@ -255,13 +259,29 @@ Razão: %1$s."</string>
<string name="error_missing_microphone_voice_rationale_android">"A %1$s não tem permissão para aceder ao teu microfone. Permite o acesso para gravar uma mensagem de voz."</string>
<string name="error_some_messages_have_not_been_sent">"Algumas mensagens não foram enviadas"</string>
<string name="error_unknown">"Ocorreu um erro, desculpa"</string>
<string name="event_shield_reason_authenticity_not_guaranteed">"A autenticidade desta mensagem cifrada não pode ser garantida neste dispositivo."</string>
<string name="event_shield_reason_unknown_device">"Cifragem com origem num dispositivo eliminado ou desconhecido."</string>
<string name="event_shield_reason_unsigned_device">"Cifragem com origem num dispositivo não verificado pelo seu dono."</string>
<string name="event_shield_reason_unverified_identity">"Cifragem com origem num utilizador não verificado."</string>
<string name="invite_friends_rich_title">"🔐️ Junta-te a mim na %1$s"</string>
<string name="invite_friends_text">"Alô! Fala comigo na %1$s: %2$s"</string>
<string name="login_initial_device_name_android">"%1$s Android"</string>
<string name="preference_rageshake">"Agita o dispositivo em fúria para comunicar um problema"</string>
<string name="screen_encryption_reset_bullet_1">"Os detalhes da tua conta, contactos, preferências e lista de conversas serão mantidos."</string>
<string name="screen_encryption_reset_bullet_2">"Perderás o acesso ao teu histórico de mensagens existente"</string>
<string name="screen_encryption_reset_bullet_3">"Necessitarás de verificar todos os teus dispositivos e contactos novamente."</string>
<string name="screen_encryption_reset_footer">"Repõe a tua identidade apenas se não tiveres acesso a mais nenhum dispositivo com sessão iniciada e se tiveres perdido a tua chave de recuperação."</string>
<string name="screen_encryption_reset_subtitle">"Se não tiveres sessão iniciada em nenhum outro dispositivo e perdeste o acesso à tua chave de recuperação, precisarás de repor a tua identidade para continuares a usar a aplicação. "</string>
<string name="screen_encryption_reset_title">"Repõe a tua identidade caso não consigas confirmar de outra forma"</string>
<string name="screen_media_picker_error_failed_selection">"Falha ao selecionar multimédia, por favor tente novamente."</string>
<string name="screen_media_upload_preview_error_failed_processing">"Falha ao processar multimédia para carregamento, por favor tente novamente."</string>
<string name="screen_media_upload_preview_error_failed_sending">"Falhar ao carregar multimédia, por favor tente novamente."</string>
<string name="screen_reset_encryption_confirmation_alert_action">"Sim, repor agora"</string>
<string name="screen_reset_encryption_confirmation_alert_subtitle">"Este processo é irreversível."</string>
<string name="screen_reset_encryption_confirmation_alert_title">"Tens a certeza que pretendes repor a tua cifra?"</string>
<string name="screen_reset_encryption_password_placeholder">"Inserir…"</string>
<string name="screen_reset_encryption_password_subtitle">"Confirma que pretendes realmente repor a tua cifra."</string>
<string name="screen_reset_encryption_password_title">"Insere a tua palavra-passe para continuares"</string>
<string name="screen_room_error_failed_processing_media">"Falha ao processar multimédia para carregamento, por favor tente novamente."</string>
<string name="screen_room_error_failed_retrieving_user_details">"Não foi possível obter os detalhes de utilizador."</string>
<string name="screen_room_member_details_block_alert_action">"Bloquear"</string>
@ -271,6 +291,9 @@ Razão: %1$s."</string>
<string name="screen_room_member_details_unblock_alert_action">"Desbloquear"</string>
<string name="screen_room_member_details_unblock_alert_description">"Poderás voltar a ver todas as suas mensagens."</string>
<string name="screen_room_member_details_unblock_user">"Desbloquear utilizador"</string>
<string name="screen_room_pinned_banner_indicator">"%1$s de %2$s"</string>
<string name="screen_room_pinned_banner_indicator_description">"%1$s mensagens afixadas"</string>
<string name="screen_room_pinned_banner_view_all_button_title">"Ver todas"</string>
<string name="screen_room_title">"Conversa"</string>
<string name="screen_share_location_title">"Partilhar localização"</string>
<string name="screen_share_my_location_action">"Partilhar a minha localização"</string>

View file

@ -93,6 +93,7 @@
<string name="action_report_bug">"Сообщить об ошибке"</string>
<string name="action_report_content">"Пожаловаться на содержание"</string>
<string name="action_reset">"Сбросить"</string>
<string name="action_reset_identity">"Сбросить идентификацию"</string>
<string name="action_retry">"Повторить"</string>
<string name="action_retry_decryption">"Повторите расшифровку"</string>
<string name="action_save">"Сохранить"</string>
@ -272,9 +273,21 @@
<string name="invite_friends_text">"Привет, поговори со мной по %1$s: %2$s"</string>
<string name="login_initial_device_name_android">"%1$s Android"</string>
<string name="preference_rageshake">"Встряхните устройство, чтобы сообщить об ошибке"</string>
<string name="screen_encryption_reset_bullet_1">"Данные вашей учетной записи, контакты, настройки и список чатов будут сохранены"</string>
<string name="screen_encryption_reset_bullet_2">"Вы потеряете существующую историю сообщений"</string>
<string name="screen_encryption_reset_bullet_3">"Вам нужно будет заново подтвердить все существующие устройства и контакты."</string>
<string name="screen_encryption_reset_footer">"Сбрасывайте данные только в том случае, если у вас нет доступа к другому устройству, на котором выполнен вход, и вы потеряли ключ восстановления."</string>
<string name="screen_encryption_reset_subtitle">"Если вы не вошли в систему на других устройствах и потеряли ключ восстановления, вам необходимо сбросить учетные данные, чтобы продолжить использование приложения. "</string>
<string name="screen_encryption_reset_title">"Сбросьте ключи подтверждения, если вы не можете подтвердить свою личность другим способом."</string>
<string name="screen_media_picker_error_failed_selection">"Не удалось выбрать носитель, попробуйте еще раз."</string>
<string name="screen_media_upload_preview_error_failed_processing">"Не удалось обработать медиафайл для загрузки, попробуйте еще раз."</string>
<string name="screen_media_upload_preview_error_failed_sending">"Не удалось загрузить медиафайлы, попробуйте еще раз."</string>
<string name="screen_reset_encryption_confirmation_alert_action">"Да, сбросить сейчас"</string>
<string name="screen_reset_encryption_confirmation_alert_subtitle">"Этот процесс необратим."</string>
<string name="screen_reset_encryption_confirmation_alert_title">"Вы действительно хотите сбросить шифрование?"</string>
<string name="screen_reset_encryption_password_placeholder">"Ввод…"</string>
<string name="screen_reset_encryption_password_subtitle">"Подтвердите, что вы хотите сбросить шифрование."</string>
<string name="screen_reset_encryption_password_title">"Введите пароль своей учетной записи, чтобы продолжить"</string>
<string name="screen_room_error_failed_processing_media">"Не удалось обработать медиафайл для загрузки, попробуйте еще раз."</string>
<string name="screen_room_error_failed_retrieving_user_details">"Не удалось получить данные о пользователе"</string>
<string name="screen_room_member_details_block_alert_action">"Заблокировать"</string>

View file

@ -93,6 +93,7 @@
<string name="action_report_bug">"Nahlásiť chybu"</string>
<string name="action_report_content">"Nahlásiť obsah"</string>
<string name="action_reset">"Obnoviť"</string>
<string name="action_reset_identity">"Obnoviť identitu"</string>
<string name="action_retry">"Skúsiť znova"</string>
<string name="action_retry_decryption">"Opakovať dešifrovanie"</string>
<string name="action_save">"Uložiť"</string>
@ -270,9 +271,21 @@ Dôvod: %1$s."</string>
<string name="invite_friends_text">"Ahoj, porozprávajte sa so mnou na %1$s: %2$s"</string>
<string name="login_initial_device_name_android">"%1$s Android"</string>
<string name="preference_rageshake">"Zúrivo potriasť pre nahlásenie chyby"</string>
<string name="screen_encryption_reset_bullet_1">"Údaje o vašom účte, kontakty, predvoľby a zoznam konverzácií budú zachované"</string>
<string name="screen_encryption_reset_bullet_2">"Stratíte svoju existujúcu históriu správ"</string>
<string name="screen_encryption_reset_bullet_3">"Budete musieť znova overiť všetky existujúce zariadenia a kontakty"</string>
<string name="screen_encryption_reset_footer">"Obnovte svoju totožnosť iba vtedy, ak nemáte prístup k inému prihlásenému zariadeniu a stratili ste kľúč na obnovenie."</string>
<string name="screen_encryption_reset_subtitle">"Ak nie ste prihlásení do žiadneho iného zariadenia a stratili ste kľúč na obnovenie, budete musieť znovu obnoviť svoju identitu, aby ste mohli pokračovať v používaní aplikácie. "</string>
<string name="screen_encryption_reset_title">"Znovu nastavte svoju totožnosť v prípade, že ju nemôžete potvrdiť iným spôsobom"</string>
<string name="screen_media_picker_error_failed_selection">"Nepodarilo sa vybrať médium, skúste to prosím znova."</string>
<string name="screen_media_upload_preview_error_failed_processing">"Nepodarilo sa spracovať médiá na odoslanie, skúste to prosím znova."</string>
<string name="screen_media_upload_preview_error_failed_sending">"Nepodarilo sa nahrať médiá, skúste to prosím znova."</string>
<string name="screen_reset_encryption_confirmation_alert_action">"Áno, znovu nastaviť teraz"</string>
<string name="screen_reset_encryption_confirmation_alert_subtitle">"Tento proces je nezvratný."</string>
<string name="screen_reset_encryption_confirmation_alert_title">"Naozaj chcete obnoviť svoje šifrovanie?"</string>
<string name="screen_reset_encryption_password_placeholder">"Zadajte…"</string>
<string name="screen_reset_encryption_password_subtitle">"Potvrďte, že chcete obnoviť svoje šifrovanie."</string>
<string name="screen_reset_encryption_password_title">"Ak chcete pokračovať, zadajte heslo účtu"</string>
<string name="screen_room_error_failed_processing_media">"Nepodarilo sa spracovať médiá na odoslanie, skúste to prosím znova."</string>
<string name="screen_room_error_failed_retrieving_user_details">"Nepodarilo sa získať údaje o používateľovi"</string>
<string name="screen_room_member_details_block_alert_action">"Zablokovať"</string>

View file

@ -91,6 +91,7 @@
<string name="action_report_bug">"Report bug"</string>
<string name="action_report_content">"Report content"</string>
<string name="action_reset">"Reset"</string>
<string name="action_reset_identity">"Reset identity"</string>
<string name="action_retry">"Retry"</string>
<string name="action_retry_decryption">"Retry decryption"</string>
<string name="action_save">"Save"</string>
@ -266,9 +267,21 @@ Reason: %1$s."</string>
<string name="invite_friends_text">"Hey, talk to me on %1$s: %2$s"</string>
<string name="login_initial_device_name_android">"%1$s Android"</string>
<string name="preference_rageshake">"Rageshake to report bug"</string>
<string name="screen_encryption_reset_bullet_1">"Your account details, contacts, preferences, and chat list will be kept"</string>
<string name="screen_encryption_reset_bullet_2">"You will lose your existing message history"</string>
<string name="screen_encryption_reset_bullet_3">"You will need to verify all your existing devices and contacts again"</string>
<string name="screen_encryption_reset_footer">"Only reset your identity if you dont have access to another signed-in device and youve lost your recovery key."</string>
<string name="screen_encryption_reset_subtitle">"If youre not signed in to any other devices and youve lost your recovery key, then youll need to reset your identity to continue using the app. "</string>
<string name="screen_encryption_reset_title">"Reset your identity in case you cant confirm another way"</string>
<string name="screen_media_picker_error_failed_selection">"Failed selecting media, please try again."</string>
<string name="screen_media_upload_preview_error_failed_processing">"Failed processing media to upload, please try again."</string>
<string name="screen_media_upload_preview_error_failed_sending">"Failed uploading media, please try again."</string>
<string name="screen_reset_encryption_confirmation_alert_action">"Yes, reset now"</string>
<string name="screen_reset_encryption_confirmation_alert_subtitle">"This process is irreversible."</string>
<string name="screen_reset_encryption_confirmation_alert_title">"Are you sure you want to reset your encryption?"</string>
<string name="screen_reset_encryption_password_placeholder">"Enter…"</string>
<string name="screen_reset_encryption_password_subtitle">"Confirm that you want to reset your encryption."</string>
<string name="screen_reset_encryption_password_title">"Enter your account password to continue"</string>
<string name="screen_room_error_failed_processing_media">"Failed processing media to upload, please try again."</string>
<string name="screen_room_error_failed_retrieving_user_details">"Could not retrieve user details"</string>
<string name="screen_room_member_details_block_alert_action">"Block"</string>

File diff suppressed because it is too large Load diff

View file

@ -31,6 +31,7 @@ import io.element.android.services.appnavstate.test.A_ROOM_OWNER
import io.element.android.services.appnavstate.test.A_SESSION_OWNER
import io.element.android.services.appnavstate.test.A_SPACE_OWNER
import io.element.android.services.appnavstate.test.A_THREAD_OWNER
import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
import io.element.android.tests.testutils.runCancellableScopeTest
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.first

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.element.android.services.appnavstate.impl
package io.element.android.services.appnavstate.test
import io.element.android.services.appnavstate.api.AppForegroundStateService
import kotlinx.coroutines.flow.MutableStateFlow