diff --git a/.github/workflows/post-pr.yml b/.github/workflows/post-pr.yml
index 5cde95e625..bf948064ed 100644
--- a/.github/workflows/post-pr.yml
+++ b/.github/workflows/post-pr.yml
@@ -31,7 +31,7 @@ jobs:
ui-tests:
name: UI Tests (Synapse)
needs: should-i-run
- runs-on: macos-latest
+ runs-on: buildjet-4vcpu-ubuntu-2204
strategy:
fail-fast: false
matrix:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index cd7e26f3cf..fb8e3080ae 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -13,7 +13,10 @@ env:
jobs:
tests:
name: Runs all tests
- runs-on: macos-latest # for the emulator
+ runs-on: buildjet-4vcpu-ubuntu-2204
+ strategy:
+ matrix:
+ api-level: [28]
# Allow all jobs on main and develop. Just one per PR.
concurrency:
group: ${{ github.ref == 'refs/heads/main' && format('unit-tests-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('unit-tests-develop-{0}', github.sha) || format('unit-tests-{0}', github.ref) }}
@@ -36,40 +39,70 @@ jobs:
httpPort: 8080
disableRateLimiting: true
public_baseurl: "http://10.0.2.2:8080/"
+
+ - name: AVD cache
+ uses: actions/cache@v3
+ id: avd-cache
+ with:
+ path: |
+ ~/.android/avd/*
+ ~/.android/adb*
+ key: avd-${{ matrix.api-level }}
+
+ - name: create AVD and generate snapshot for caching
+ if: steps.avd-cache.outputs.cache-hit != 'true'
+ uses: reactivecircus/android-emulator-runner@v2
+ with:
+ api-level: ${{ matrix.api-level }}
+ arch: x86
+ profile: Nexus 5X
+ force-avd-creation: true # Is set to false in the doc https://github.com/ReactiveCircus/android-emulator-runner
+ emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
+ disable-animations: true
+ script: echo "Generated AVD snapshot for caching."
+
- name: Run all the codecoverage tests at once
- id: tests
uses: reactivecircus/android-emulator-runner@v2
- continue-on-error: true
+ # continue-on-error: true
with:
- api-level: 28
+ api-level: ${{ matrix.api-level }}
arch: x86
profile: Nexus 5X
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
- emulator-build: 7425822
+ # emulator-build: 7425822
script: |
./gradlew gatherGplayDebugStringTemplates $CI_GRADLE_ARG_PROPERTIES
./gradlew unitTestsWithCoverage $CI_GRADLE_ARG_PROPERTIES
./gradlew instrumentationTestsWithCoverage $CI_GRADLE_ARG_PROPERTIES
./gradlew generateCoverageReport $CI_GRADLE_ARG_PROPERTIES
- # NB: continue-on-error marks steps.tests.conclusion = 'success' but leaves stes.tests.outcome = 'failure'
- - name: Run all the codecoverage tests at once (retry if emulator failed)
- uses: reactivecircus/android-emulator-runner@v2
- if: always() && steps.tests.outcome == 'failure' # don't run if previous step succeeded.
+ # NB: continue-on-error marks steps.tests.conclusion = 'success' but leaves steps.tests.outcome = 'failure'
+ ### - name: Run all the codecoverage tests at once (retry if emulator failed)
+ ### uses: reactivecircus/android-emulator-runner@v2
+ ### if: always() && steps.tests.outcome == 'failure' # don't run if previous step succeeded.
+ ### with:
+ ### api-level: 28
+ ### arch: x86
+ ### profile: Nexus 5X
+ ### force-avd-creation: false
+ ### emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
+ ### disable-animations: true
+ ### emulator-build: 7425822
+ ### script: |
+ ### ./gradlew gatherGplayDebugStringTemplates $CI_GRADLE_ARG_PROPERTIES
+ ### ./gradlew unitTestsWithCoverage $CI_GRADLE_ARG_PROPERTIES
+ ### ./gradlew instrumentationTestsWithCoverage $CI_GRADLE_ARG_PROPERTIES
+ ### ./gradlew generateCoverageReport $CI_GRADLE_ARG_PROPERTIES
+
+ - name: Upload Integration Test Report Log
+ uses: actions/upload-artifact@v3
+ if: always()
with:
- api-level: 28
- arch: x86
- profile: Nexus 5X
- force-avd-creation: false
- emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
- disable-animations: true
- emulator-build: 7425822
- script: |
- ./gradlew gatherGplayDebugStringTemplates $CI_GRADLE_ARG_PROPERTIES
- ./gradlew unitTestsWithCoverage $CI_GRADLE_ARG_PROPERTIES
- ./gradlew instrumentationTestsWithCoverage $CI_GRADLE_ARG_PROPERTIES
- ./gradlew generateCoverageReport $CI_GRADLE_ARG_PROPERTIES
+ name: integration-test-error-results
+ path: |
+ */build/outputs/androidTest-results/connected/
+ */build/reports/androidTests/connected/
# we may have failed a previous step and retried, that's OK
- name: Publish results to Sonar
diff --git a/changelog.d/6970.wip b/changelog.d/6970.wip
new file mode 100644
index 0000000000..4ec53e0d53
--- /dev/null
+++ b/changelog.d/6970.wip
@@ -0,0 +1 @@
+Create DM room only on first message - Add a spinner when sending the first message
diff --git a/changelog.d/7045.wip b/changelog.d/7045.wip
new file mode 100644
index 0000000000..8976ca9744
--- /dev/null
+++ b/changelog.d/7045.wip
@@ -0,0 +1 @@
+[Device Manager] Filter Other Sessions
diff --git a/changelog.d/7079.bugfix b/changelog.d/7079.bugfix
new file mode 100644
index 0000000000..b63d491e4b
--- /dev/null
+++ b/changelog.d/7079.bugfix
@@ -0,0 +1 @@
+Fixed problem when room list's scroll did jump after rooms placeholders were replaced with rooms summary items
diff --git a/changelog.d/7108.misc b/changelog.d/7108.misc
new file mode 100644
index 0000000000..165bd52e57
--- /dev/null
+++ b/changelog.d/7108.misc
@@ -0,0 +1 @@
+Move some GitHub actions to buildjet runners, and remove the second attempt to run integration tests.
diff --git a/changelog.d/7153.wip b/changelog.d/7153.wip
new file mode 100644
index 0000000000..fd12a4197b
--- /dev/null
+++ b/changelog.d/7153.wip
@@ -0,0 +1 @@
+Create DM room only on first message - Handle the local rooms within the new AppLayout
diff --git a/changelog.d/7166.misc b/changelog.d/7166.misc
new file mode 100644
index 0000000000..d223208853
--- /dev/null
+++ b/changelog.d/7166.misc
@@ -0,0 +1 @@
+New App Layout is now enabled by default! Go to the Settings > Labs to toggle this
diff --git a/changelog.d/7180.feature b/changelog.d/7180.feature
new file mode 100644
index 0000000000..bdfe090ceb
--- /dev/null
+++ b/changelog.d/7180.feature
@@ -0,0 +1 @@
+Deferred DMs - Enable and move the feature to labs settings
diff --git a/changelog.d/7186.bugfix b/changelog.d/7186.bugfix
new file mode 100644
index 0000000000..418dbbda9f
--- /dev/null
+++ b/changelog.d/7186.bugfix
@@ -0,0 +1 @@
+Fixes Room List not getting updated when fragment is not in focus
diff --git a/library/ui-strings/src/main/res/values-ar/strings.xml b/library/ui-strings/src/main/res/values-ar/strings.xml
index 70b9a33ab5..073f961cb6 100644
--- a/library/ui-strings/src/main/res/values-ar/strings.xml
+++ b/library/ui-strings/src/main/res/values-ar/strings.xml
@@ -320,7 +320,7 @@
السمة
خطأ في فكّ التعمية
اسم الجهاز
- معرّف الجهاز
+ معرّف الجهاز
مفتاح الجهاز
صدّر مفاتيح الغرفة
صدّر المفاتيح إلى ملف محلي
diff --git a/library/ui-strings/src/main/res/values-bg/strings.xml b/library/ui-strings/src/main/res/values-bg/strings.xml
index d3e9e599bc..b29823040f 100644
--- a/library/ui-strings/src/main/res/values-bg/strings.xml
+++ b/library/ui-strings/src/main/res/values-bg/strings.xml
@@ -396,7 +396,7 @@
Тема
Грешка при разшифроване
Публично име
- Сесийно ID
+ Сесийно ID
Ключ на устройство
Експортирай E2E ключове за стая
Експортиране на ключове за стая
diff --git a/library/ui-strings/src/main/res/values-bn-rBD/strings.xml b/library/ui-strings/src/main/res/values-bn-rBD/strings.xml
index 7897da934e..2f068f1bf8 100644
--- a/library/ui-strings/src/main/res/values-bn-rBD/strings.xml
+++ b/library/ui-strings/src/main/res/values-bn-rBD/strings.xml
@@ -789,7 +789,7 @@
রুমের কুঞ্জিগুলি এক্সপোর্ট করুন
শেষ থেকে শেষ রুমের কুঞ্জিগুলি এক্সপোর্ট করুন
সেশানের কুঞ্জি
- আইডি
+ আইডি
সর্বজনীন নাম
ডিক্রিপশন সমস্যা
থিম
diff --git a/library/ui-strings/src/main/res/values-bn-rIN/strings.xml b/library/ui-strings/src/main/res/values-bn-rIN/strings.xml
index 56bde36977..828bc3bd34 100644
--- a/library/ui-strings/src/main/res/values-bn-rIN/strings.xml
+++ b/library/ui-strings/src/main/res/values-bn-rIN/strings.xml
@@ -693,7 +693,7 @@
ডিক্রিপশন সমস্যা
সর্বজনীন নাম
- আইডি
+ আইডি
সেশানের কুঞ্জি
শেষ থেকে শেষ রুমের কুঞ্জিগুলি এক্সপোর্ট করুন
diff --git a/library/ui-strings/src/main/res/values-ca/strings.xml b/library/ui-strings/src/main/res/values-ca/strings.xml
index 77d9fc10d5..13a5b6c119 100644
--- a/library/ui-strings/src/main/res/values-ca/strings.xml
+++ b/library/ui-strings/src/main/res/values-ca/strings.xml
@@ -448,7 +448,7 @@
Tema
Error al desxifrar
Nom públic
- ID de sessió
+ ID de sessió
Clau de sessió
Exporta les claus de la sala E2E
Exporta les claus de la sala
diff --git a/library/ui-strings/src/main/res/values-cs/strings.xml b/library/ui-strings/src/main/res/values-cs/strings.xml
index ed5a05f38a..b7bfeac444 100644
--- a/library/ui-strings/src/main/res/values-cs/strings.xml
+++ b/library/ui-strings/src/main/res/values-cs/strings.xml
@@ -635,7 +635,7 @@
Motiv vzhledu
Chyba dešifrování
Veřejné jméno
- ID relace
+ ID relace
Klíč relace
Export E2E klíčů místností
Export klíčů místností
diff --git a/library/ui-strings/src/main/res/values-de/strings.xml b/library/ui-strings/src/main/res/values-de/strings.xml
index 05ae25c5f7..3753cedff2 100644
--- a/library/ui-strings/src/main/res/values-de/strings.xml
+++ b/library/ui-strings/src/main/res/values-de/strings.xml
@@ -418,7 +418,7 @@
Als Hauptadresse aufheben
Entschlüsselungsfehler
Öffentlicher Name
- Sitzungs-ID
+ Sitzungs-ID
Sitzungsschlüssel
Ende-zu-Ende-Raumschlüssel exportieren
Raumschlüssel exportieren
diff --git a/library/ui-strings/src/main/res/values-el/strings.xml b/library/ui-strings/src/main/res/values-el/strings.xml
index f4973f4b95..092a01bff4 100644
--- a/library/ui-strings/src/main/res/values-el/strings.xml
+++ b/library/ui-strings/src/main/res/values-el/strings.xml
@@ -172,7 +172,7 @@
Θέμα
Σφάλμα αποκρυπτογράφησης
Όνομα συσκευής
- Αναγνωριστικό συσκευής
+ Αναγνωριστικό συσκευής
Εξαγωγή
Εισαγωγή
Επιλέξτε ένα ευρετήριο δωματίων
diff --git a/library/ui-strings/src/main/res/values-eo/strings.xml b/library/ui-strings/src/main/res/values-eo/strings.xml
index f536ca00f9..7e1925f708 100644
--- a/library/ui-strings/src/main/res/values-eo/strings.xml
+++ b/library/ui-strings/src/main/res/values-eo/strings.xml
@@ -1084,7 +1084,7 @@
Elporti ŝlosilojn de ĉambroj
Elporti tutvoje ĉifrajn ŝlosilojn de ĉambroj
Ŝlosilo de salutaĵo
- Identigilo de salutaĵo
+ Identigilo de salutaĵo
Publika nomo
Eraris malĉifrado
Haŭto
diff --git a/library/ui-strings/src/main/res/values-es-rMX/strings.xml b/library/ui-strings/src/main/res/values-es-rMX/strings.xml
index c82f9aff61..0b38fa6a19 100644
--- a/library/ui-strings/src/main/res/values-es-rMX/strings.xml
+++ b/library/ui-strings/src/main/res/values-es-rMX/strings.xml
@@ -249,7 +249,7 @@
Desescojer como Dirección Principal
Error en descifrar
Nombre del dispositivo
- Identificación del dispositivo
+ Identificación del dispositivo
Clave del dispositivo
Exportar claves de cifrado de extremo-a-extremo de salas
Exportar claves de salas
diff --git a/library/ui-strings/src/main/res/values-es/strings.xml b/library/ui-strings/src/main/res/values-es/strings.xml
index fcdd3f90a0..4eec90fbd6 100644
--- a/library/ui-strings/src/main/res/values-es/strings.xml
+++ b/library/ui-strings/src/main/res/values-es/strings.xml
@@ -415,7 +415,7 @@
Dejar de Establecer como dirección principal
Error de descifrado
Nombre público
- ID de sesión
+ ID de sesión
Clave de sesión
Exportar claves de salas con cifrado Extremo-a-Extremo
Exportar claves de sala
diff --git a/library/ui-strings/src/main/res/values-et/strings.xml b/library/ui-strings/src/main/res/values-et/strings.xml
index 495f32415f..55fb9dfef0 100644
--- a/library/ui-strings/src/main/res/values-et/strings.xml
+++ b/library/ui-strings/src/main/res/values-et/strings.xml
@@ -612,7 +612,7 @@
Need on alles katsejärgus olevad funktsionaalsused. Ole kasutamisel ettevaatlik.
Dekrüptimise viga
Avalik nimi
- Sessiooni tunnus
+ Sessiooni tunnus
Sessiooni võti
Ekspordi jututubade läbiva krüptimise võtmed
Ekspordi jututoa võtmed
diff --git a/library/ui-strings/src/main/res/values-eu/strings.xml b/library/ui-strings/src/main/res/values-eu/strings.xml
index f1f834ee04..7b27d1cc1d 100644
--- a/library/ui-strings/src/main/res/values-eu/strings.xml
+++ b/library/ui-strings/src/main/res/values-eu/strings.xml
@@ -406,7 +406,7 @@ Kontuan izan ekintza honek aplikazioa berrabiaraziko duela eta denbora bat behar
Deszifratze errorea
Izen publikoa
- IDa
+ IDa
Saioaren gakoa
Esportatu E2E geletako gakoak
diff --git a/library/ui-strings/src/main/res/values-fa/strings.xml b/library/ui-strings/src/main/res/values-fa/strings.xml
index be6d4b97b7..e104225389 100644
--- a/library/ui-strings/src/main/res/values-fa/strings.xml
+++ b/library/ui-strings/src/main/res/values-fa/strings.xml
@@ -678,7 +678,7 @@
اینها ویژگیهای آزمایشیای هستند که ممکن است به روشهای نامنتظرهای حراب شوندا. با احتیاط استفاده کنید.
تنظیم به عنوان نشانی اصلی
نام عمومی
- شناسهٔ نشست
+ شناسهٔ نشست
کلید نشست
برونریزی کلیدهای اتاقهای سرتاسری
برونریزی کلیدهای اتاقها
diff --git a/library/ui-strings/src/main/res/values-fi/strings.xml b/library/ui-strings/src/main/res/values-fi/strings.xml
index a576e7f0dc..fde2502ae0 100644
--- a/library/ui-strings/src/main/res/values-fi/strings.xml
+++ b/library/ui-strings/src/main/res/values-fi/strings.xml
@@ -366,7 +366,7 @@
Kumoa pääosoitteeksi asettaminen
Salauksenpurkuvirhe
Julkinen nimi
- Istunnon tunnus
+ Istunnon tunnus
Istunnon avain
Vie salatun huoneen avaimet
Vie huoneen avaimet
diff --git a/library/ui-strings/src/main/res/values-fr-rCA/strings.xml b/library/ui-strings/src/main/res/values-fr-rCA/strings.xml
index 94db2935a7..29a618f415 100644
--- a/library/ui-strings/src/main/res/values-fr-rCA/strings.xml
+++ b/library/ui-strings/src/main/res/values-fr-rCA/strings.xml
@@ -778,7 +778,7 @@
Exporter les clés des salons
Exporter les clés E2E des salons
Clé de la session
- Identifiant de session
+ Identifiant de session
Nom public
Erreur de déchiffrement
Thème
diff --git a/library/ui-strings/src/main/res/values-fr/strings.xml b/library/ui-strings/src/main/res/values-fr/strings.xml
index d4738f7b2f..55b5f88134 100644
--- a/library/ui-strings/src/main/res/values-fr/strings.xml
+++ b/library/ui-strings/src/main/res/values-fr/strings.xml
@@ -346,7 +346,7 @@
Désactiver comme adresse principale
Erreur de déchiffrement
Nom public
- Identifiant de session
+ Identifiant de session
Clé de la session
Exporter les clés E2E des salons
Exporter les clés des salons
diff --git a/library/ui-strings/src/main/res/values-gl/strings.xml b/library/ui-strings/src/main/res/values-gl/strings.xml
index c1e4e40a81..e6d26a63e5 100644
--- a/library/ui-strings/src/main/res/values-gl/strings.xml
+++ b/library/ui-strings/src/main/res/values-gl/strings.xml
@@ -380,7 +380,7 @@
Tema
Fallo ao descifrar
Nome do dispositivo
- ID de sesión
+ ID de sesión
Chave do dispositivo
Exportar chaves E2E da sala
Exportar chaves da sala
diff --git a/library/ui-strings/src/main/res/values-hr/strings.xml b/library/ui-strings/src/main/res/values-hr/strings.xml
index 6d52e5cd96..dc5930b933 100644
--- a/library/ui-strings/src/main/res/values-hr/strings.xml
+++ b/library/ui-strings/src/main/res/values-hr/strings.xml
@@ -572,7 +572,7 @@
Tema
Greška u dešifriranju
Javni naziv
- Identitet
+ Identitet
Ključ sesije
Izvezi sobne ključeve za E2E
Izvezi sobne ključeve
diff --git a/library/ui-strings/src/main/res/values-hu/strings.xml b/library/ui-strings/src/main/res/values-hu/strings.xml
index 5a4d951dc1..af8bf26b2e 100644
--- a/library/ui-strings/src/main/res/values-hu/strings.xml
+++ b/library/ui-strings/src/main/res/values-hu/strings.xml
@@ -351,7 +351,7 @@
Kiszedés fő címek közül
Visszafejtés hiba
Nyilvános név
- Munkamenet-azonosító
+ Munkamenet-azonosító
Munkamenet kulcs
E2E szoba kulcsok exportálása
Szoba kulcsok exportálása
diff --git a/library/ui-strings/src/main/res/values-in/strings.xml b/library/ui-strings/src/main/res/values-in/strings.xml
index d2861a326b..d1e68b4529 100644
--- a/library/ui-strings/src/main/res/values-in/strings.xml
+++ b/library/ui-strings/src/main/res/values-in/strings.xml
@@ -301,7 +301,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Tema
Kesalahan dekripsi
Nama perangkat
- ID Sesi
+ ID Sesi
Kunci perangkat
Ekspor kunci ruangan terenkripsi
Ekspor ruangan kunci
diff --git a/library/ui-strings/src/main/res/values-is/strings.xml b/library/ui-strings/src/main/res/values-is/strings.xml
index d25d66bfba..7818761145 100644
--- a/library/ui-strings/src/main/res/values-is/strings.xml
+++ b/library/ui-strings/src/main/res/values-is/strings.xml
@@ -193,7 +193,7 @@
Þema
Afkóðunarvilla
Heiti tækis
- Auðkenni setu
+ Auðkenni setu
Dulritunarlykill setu
Flytja út
Settu inn lykilsetningu
diff --git a/library/ui-strings/src/main/res/values-it/strings.xml b/library/ui-strings/src/main/res/values-it/strings.xml
index 984837679a..ecb29d1586 100644
--- a/library/ui-strings/src/main/res/values-it/strings.xml
+++ b/library/ui-strings/src/main/res/values-it/strings.xml
@@ -430,7 +430,7 @@
Tema
Errore di decriptazione
Nome pubblico
- ID sessione
+ ID sessione
Chiave sessione
Esporta le chiavi di crittografia E2E delle stanze
Esporta le chiavi delle stanze
diff --git a/library/ui-strings/src/main/res/values-iw/strings.xml b/library/ui-strings/src/main/res/values-iw/strings.xml
index ff19310c8e..6d9533852b 100644
--- a/library/ui-strings/src/main/res/values-iw/strings.xml
+++ b/library/ui-strings/src/main/res/values-iw/strings.xml
@@ -542,7 +542,7 @@
יצא מפתחות חדר
ייצא מפתחות חדר E2E
מזהה מפתח
- מזהה מושב
+ מזהה מושב
שם ציבורי
שגיאת פענוח
ערכת נושא
diff --git a/library/ui-strings/src/main/res/values-ja/strings.xml b/library/ui-strings/src/main/res/values-ja/strings.xml
index 3e817e398c..b781e4d7f0 100644
--- a/library/ui-strings/src/main/res/values-ja/strings.xml
+++ b/library/ui-strings/src/main/res/values-ja/strings.xml
@@ -197,7 +197,7 @@
これらは予期しない不具合が生じるかもしれない実験的機能です。慎重に使用してください。
メインアドレスとして設定
メインアドレスとしての設定を解除
- セッションID
+ セッションID
文字の大きさ
とても小さい
小さい
diff --git a/library/ui-strings/src/main/res/values-kab/strings.xml b/library/ui-strings/src/main/res/values-kab/strings.xml
index 353fb99f53..a79b72efde 100644
--- a/library/ui-strings/src/main/res/values-kab/strings.xml
+++ b/library/ui-strings/src/main/res/values-kab/strings.xml
@@ -291,7 +291,7 @@
Talqayt
Tinarimin
Asentel
- Asulay n tqimit
+ Asulay n tqimit
Tasarut n tɣimit
Sifeḍ tisura n texxamt E2E
Sifeḍ tisura n texxamt
diff --git a/library/ui-strings/src/main/res/values-ko/strings.xml b/library/ui-strings/src/main/res/values-ko/strings.xml
index 37e8849fa8..ba0cbe5abd 100644
--- a/library/ui-strings/src/main/res/values-ko/strings.xml
+++ b/library/ui-strings/src/main/res/values-ko/strings.xml
@@ -431,7 +431,7 @@
테마
암호 복호화 오류
공개 이름
- ID
+ ID
기기 키
종단간 암호화 방 키 내보내기
방 키 내보내기
diff --git a/library/ui-strings/src/main/res/values-lo/strings.xml b/library/ui-strings/src/main/res/values-lo/strings.xml
index a92adb0225..1a9a2820b8 100644
--- a/library/ui-strings/src/main/res/values-lo/strings.xml
+++ b/library/ui-strings/src/main/res/values-lo/strings.xml
@@ -909,7 +909,7 @@
ສົ່ງອອກກະແຈຫ້ອງ
ສົ່ງອອກກະແຈຫ້ອງ E2E
ລະຫັດລະບົບ
- ID ລະບົບ
+ ID ລະບົບ
ຊື່ສາທາລະນະ
ການຖອດລະຫັດຜິດພາດ
ຫົວຂໍ້
diff --git a/library/ui-strings/src/main/res/values-lv/strings.xml b/library/ui-strings/src/main/res/values-lv/strings.xml
index 1787653fae..f1fa1502c1 100644
--- a/library/ui-strings/src/main/res/values-lv/strings.xml
+++ b/library/ui-strings/src/main/res/values-lv/strings.xml
@@ -469,7 +469,7 @@
Tēma
Atšifrēšanas kļūda
Ierīces nosaukums
- Sesijas ID
+ Sesijas ID
Sesijas atslēga
Eksportēt istabas šifrēšanas atslēgas
Eksportēt istabas atslēgas
diff --git a/library/ui-strings/src/main/res/values-nb-rNO/strings.xml b/library/ui-strings/src/main/res/values-nb-rNO/strings.xml
index 7af718d920..031b380c7e 100644
--- a/library/ui-strings/src/main/res/values-nb-rNO/strings.xml
+++ b/library/ui-strings/src/main/res/values-nb-rNO/strings.xml
@@ -119,7 +119,7 @@
Bannlyste brukere
Avansert
Tema
- Økt-ID
+ Økt-ID
Øktnøkkel
Eksporter
Importer
diff --git a/library/ui-strings/src/main/res/values-nl/strings.xml b/library/ui-strings/src/main/res/values-nl/strings.xml
index 2669143a7e..b1d239963e 100644
--- a/library/ui-strings/src/main/res/values-nl/strings.xml
+++ b/library/ui-strings/src/main/res/values-nl/strings.xml
@@ -275,7 +275,7 @@
Niet instellen als hoofdadres
Ontsleutelingsfout
Publieke naam
- Sessie ID
+ Sessie ID
Sessiesleutel
E2E-gesprekssleutels exporteren
Gesprekssleutels exporteren
diff --git a/library/ui-strings/src/main/res/values-nn/strings.xml b/library/ui-strings/src/main/res/values-nn/strings.xml
index 45c8679736..a56ba0ac30 100644
--- a/library/ui-strings/src/main/res/values-nn/strings.xml
+++ b/library/ui-strings/src/main/res/values-nn/strings.xml
@@ -310,7 +310,7 @@
Preg
Noko gjekk gale med dekrypteringa
Offentleg namn
- Økt-ID
+ Økt-ID
Sesjonsnøkkel
Eksporter E2E-romnøkklar
Eksporter romnøkklar
diff --git a/library/ui-strings/src/main/res/values-pl/strings.xml b/library/ui-strings/src/main/res/values-pl/strings.xml
index ce8b22bcd2..a657709543 100644
--- a/library/ui-strings/src/main/res/values-pl/strings.xml
+++ b/library/ui-strings/src/main/res/values-pl/strings.xml
@@ -231,7 +231,7 @@
Ustaw jako główny adres
Motyw
Nazwa publiczna
- ID sesji
+ ID sesji
Eksportuj
Wprowadź hasło
Potwierdź hasło
diff --git a/library/ui-strings/src/main/res/values-pt-rBR/strings.xml b/library/ui-strings/src/main/res/values-pt-rBR/strings.xml
index e9d0c66fd9..08c41db365 100644
--- a/library/ui-strings/src/main/res/values-pt-rBR/strings.xml
+++ b/library/ui-strings/src/main/res/values-pt-rBR/strings.xml
@@ -418,7 +418,7 @@
Des-definir como endereço principal
Erro de decriptação
Nome público
- ID de sessão
+ ID de sessão
Chave de sessão
Exportar chaves de sala E2E
Exportar chaves de sala
diff --git a/library/ui-strings/src/main/res/values-pt/strings.xml b/library/ui-strings/src/main/res/values-pt/strings.xml
index 87b6297b2b..4daaef83b0 100644
--- a/library/ui-strings/src/main/res/values-pt/strings.xml
+++ b/library/ui-strings/src/main/res/values-pt/strings.xml
@@ -246,7 +246,7 @@ Note que esta acção irá reiniciar a aplicação e poderá levar algum tempo.<
Erro de decifragem
Nome do dispositivo
- ID do dispositivo
+ ID do dispositivo
Chave do dispositivo
Exportar chaves E2E da sala
Exportar chaves de sala
diff --git a/library/ui-strings/src/main/res/values-ru/strings.xml b/library/ui-strings/src/main/res/values-ru/strings.xml
index 9bbb1dc1c9..8d223bae5e 100644
--- a/library/ui-strings/src/main/res/values-ru/strings.xml
+++ b/library/ui-strings/src/main/res/values-ru/strings.xml
@@ -432,7 +432,7 @@
Сбросить основной адрес
Ошибка дешифровки
Публичное имя
- ID сессии
+ ID сессии
Ключ сессии
Экспорт E2E ключей комнаты
Экспорт ключей комнаты
diff --git a/library/ui-strings/src/main/res/values-sk/strings.xml b/library/ui-strings/src/main/res/values-sk/strings.xml
index 328cbb78cb..2cc2d0280e 100644
--- a/library/ui-strings/src/main/res/values-sk/strings.xml
+++ b/library/ui-strings/src/main/res/values-sk/strings.xml
@@ -388,7 +388,7 @@
Vzhľad
Chyba dešifrovania
Verejné meno
- ID relácie
+ ID relácie
Kľúč relácie
Exportovať šifrovacie kľúče miestnosti
Exportovať kľúče miestnosti
diff --git a/library/ui-strings/src/main/res/values-sq/strings.xml b/library/ui-strings/src/main/res/values-sq/strings.xml
index a6af0a4921..8fdf4ee310 100644
--- a/library/ui-strings/src/main/res/values-sq/strings.xml
+++ b/library/ui-strings/src/main/res/values-sq/strings.xml
@@ -431,7 +431,7 @@
Temë
Gabim shfshehtëzimi
Emër publik
- ID Sesioni
+ ID Sesioni
Kyç sesioni
Eksporto kyçe dhome E2E
Eksporto kyçe dhome
diff --git a/library/ui-strings/src/main/res/values-sv/strings.xml b/library/ui-strings/src/main/res/values-sv/strings.xml
index 30b63c213c..025713272c 100644
--- a/library/ui-strings/src/main/res/values-sv/strings.xml
+++ b/library/ui-strings/src/main/res/values-sv/strings.xml
@@ -918,7 +918,7 @@
Sätt upp på den här enheten
Generera en ny säkerhetskopia eller sätt en ny lösenfras för din existerande säkerhetskopia.
Detta är experimentella funktioner som kan gå sönder på oväntade sätt. Använd varsamt.
- Sessions-ID
+ Sessions-ID
Sessionsnyckel
Exportera krypteringsnycklar
Exportera rumsnycklar
diff --git a/library/ui-strings/src/main/res/values-te/strings.xml b/library/ui-strings/src/main/res/values-te/strings.xml
index 0154d54c2e..5ed2462ce8 100644
--- a/library/ui-strings/src/main/res/values-te/strings.xml
+++ b/library/ui-strings/src/main/res/values-te/strings.xml
@@ -260,7 +260,7 @@
ప్రధాన చిరునామాగా సెట్ చేయండి
పరికరం పేరు
- పరికరం ID
+ పరికరం ID
పరికరం కీ
E2E గది కీలను ఎగుమతి చేయండి
diff --git a/library/ui-strings/src/main/res/values-tr/strings.xml b/library/ui-strings/src/main/res/values-tr/strings.xml
index 1f0e5be153..c097bfce6a 100644
--- a/library/ui-strings/src/main/res/values-tr/strings.xml
+++ b/library/ui-strings/src/main/res/values-tr/strings.xml
@@ -376,7 +376,7 @@
Tema
Çözme hatası
Görünür Ad
- Oturum kimliği
+ Oturum kimliği
Oturum anahtarı
E2E Oda anahtarlarını dışa aktar
Oda anahtarlarını dışa aktar
diff --git a/library/ui-strings/src/main/res/values-uk/strings.xml b/library/ui-strings/src/main/res/values-uk/strings.xml
index 8e390801f3..1c809fff3e 100644
--- a/library/ui-strings/src/main/res/values-uk/strings.xml
+++ b/library/ui-strings/src/main/res/values-uk/strings.xml
@@ -354,7 +354,7 @@
Зробити не основною адресою
Помилка розшифрування
Загальнодоступна назва
- ID сеансу
+ ID сеансу
Ключ сеансу
Експортувати E2E ключі кімнати
Експортувати ключі кімнати
diff --git a/library/ui-strings/src/main/res/values-vi/strings.xml b/library/ui-strings/src/main/res/values-vi/strings.xml
index c6dc97f782..2803128843 100644
--- a/library/ui-strings/src/main/res/values-vi/strings.xml
+++ b/library/ui-strings/src/main/res/values-vi/strings.xml
@@ -594,7 +594,7 @@
Hủy tài khoản
Xem lại ngay
Chìa khóa phiên
- Mã phiên
+ Mã phiên
Tên công khai
Lỗi giải mã
Những chức năng này mang tính thí nghiệm có thể còn nhiều lỗi. Lưu ý khi dùng.
diff --git a/library/ui-strings/src/main/res/values-zh-rCN/strings.xml b/library/ui-strings/src/main/res/values-zh-rCN/strings.xml
index e92aafc8c6..ee0e95d648 100644
--- a/library/ui-strings/src/main/res/values-zh-rCN/strings.xml
+++ b/library/ui-strings/src/main/res/values-zh-rCN/strings.xml
@@ -242,7 +242,7 @@
你的密码已更新
解密错误
公开名称
- 会话 ID
+ 会话 ID
会话密钥
导入
已验证
diff --git a/library/ui-strings/src/main/res/values-zh-rTW/strings.xml b/library/ui-strings/src/main/res/values-zh-rTW/strings.xml
index 4f699b1c02..0f5208bcde 100644
--- a/library/ui-strings/src/main/res/values-zh-rTW/strings.xml
+++ b/library/ui-strings/src/main/res/values-zh-rTW/strings.xml
@@ -469,7 +469,7 @@
主題
解密錯誤
公開名稱
- 工作階段 ID
+ 工作階段 ID
工作階段金鑰
匯出聊天室的端到端加密金鑰
匯出聊天室的加密金鑰
diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml
index fbe35f57ce..1c6150bf9c 100644
--- a/library/ui-strings/src/main/res/values/strings.xml
+++ b/library/ui-strings/src/main/res/values/strings.xml
@@ -442,6 +442,9 @@
Enable new layout
A simplified Element with optional tabs
+ Enable deferred DMs
+ Create DM only on first message
+
Invites
Low priority
@@ -2361,7 +2364,9 @@
Manage Sessions
Sign out of this session
Sessions
+
Other sessions
+
For best security, verify your sessions and sign out from any session that you don’t recognize or use anymore.
Server name
@@ -3265,10 +3270,36 @@
Device
Last activity %1$s
+ Filter
+ All sessions
+ Verified
+ Ready for secure messaging
+ Unverified
+ Not ready for secure messaging
+ Inactive
+
+ - Inactive for %1$d day or longer
+ - Inactive for %1$d days or longer
+
+ Filter
+ Verified
+ For best security, sign out from any session that you don’t recognize or use anymore.
+ Unverified
+ Verify your sessions for enhanced secure messaging or sign out from those you don’t recognize or use anymore.
+ Inactive
+
+ - Consider signing out from old sessions (%1$d day or more) you don’t use anymore.
+ - Consider signing out from old sessions (%1$d days or more) you don’t use anymore.
+
+ No verified sessions found.
+ No unverified sessions found.
+ No inactive sessions found.
+ Clear Filter
Session details
Application, device, and activity information.
Session name
- Session ID
+
+ Session ID
Last activity
IP address
diff --git a/library/ui-styles/src/main/res/values/colors.xml b/library/ui-styles/src/main/res/values/colors.xml
index 01af740d43..3d6bc91f2e 100644
--- a/library/ui-styles/src/main/res/values/colors.xml
+++ b/library/ui-styles/src/main/res/values/colors.xml
@@ -141,6 +141,7 @@
#0DBD8B
+ #0F0DBD8B
#17191C
#FF4B55
#0FFF4B55
diff --git a/library/ui-styles/src/main/res/values/stylable_other_sessions_security_recommendation_view.xml b/library/ui-styles/src/main/res/values/stylable_other_sessions_security_recommendation_view.xml
new file mode 100644
index 0000000000..6a46132b13
--- /dev/null
+++ b/library/ui-styles/src/main/res/values/stylable_other_sessions_security_recommendation_view.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowRoom.kt b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowRoom.kt
index 8be8e83569..a6b4cc98a6 100644
--- a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowRoom.kt
+++ b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowRoom.kt
@@ -25,6 +25,7 @@ import org.matrix.android.sdk.api.session.room.getStateEvent
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.api.session.room.members.RoomMemberQueryParams
import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary
+import org.matrix.android.sdk.api.session.room.model.LocalRoomSummary
import org.matrix.android.sdk.api.session.room.model.ReadReceipt
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary
@@ -46,6 +47,13 @@ class FlowRoom(private val room: Room) {
}
}
+ fun liveLocalRoomSummary(): Flow> {
+ return room.getLocalRoomSummaryLive().asFlow()
+ .startWith(room.coroutineDispatchers.io) {
+ room.localRoomSummary().toOptional()
+ }
+ }
+
fun liveRoomMembers(queryParams: RoomMemberQueryParams): Flow> {
return room.membershipService().getRoomMembersLive(queryParams).asFlow()
.startWith(room.coroutineDispatchers.io) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt
index 5d2769ac3c..8031fcaeea 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt
@@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.session.room.call.RoomCallService
import org.matrix.android.sdk.api.session.room.crypto.RoomCryptoService
import org.matrix.android.sdk.api.session.room.location.LocationSharingService
import org.matrix.android.sdk.api.session.room.members.MembershipService
+import org.matrix.android.sdk.api.session.room.model.LocalRoomSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.relation.RelationService
import org.matrix.android.sdk.api.session.room.notification.RoomPushRuleService
@@ -60,11 +61,22 @@ interface Room {
*/
fun getRoomSummaryLive(): LiveData>
+ /**
+ * A live [LocalRoomSummary] associated with the room.
+ * You can observe this summary to get dynamic data from this room.
+ */
+ fun getLocalRoomSummaryLive(): LiveData>
+
/**
* A current snapshot of [RoomSummary] associated with the room.
*/
fun roomSummary(): RoomSummary?
+ /**
+ * A current snapshot of [LocalRoomSummary] associated with the room.
+ */
+ fun localRoomSummary(): LocalRoomSummary?
+
/**
* Use this room as a Space, if the type is correct.
*/
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt
index ad8106c9c1..65383f1007 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt
@@ -22,6 +22,7 @@ import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.identity.model.SignInvitationResult
import org.matrix.android.sdk.api.session.room.alias.RoomAliasDescription
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
+import org.matrix.android.sdk.api.session.room.model.LocalRoomSummary
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary
@@ -117,6 +118,12 @@ interface RoomService {
*/
fun getRoomSummaryLive(roomId: String): LiveData>
+ /**
+ * A live [LocalRoomSummary] associated with the room with id [roomId].
+ * You can observe this summary to get dynamic data from this room, even if the room is not joined yet
+ */
+ fun getLocalRoomSummaryLive(roomId: String): LiveData>
+
/**
* Get a snapshot list of room summaries.
* @return the immutable list of [RoomSummary]
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LocalRoomCreationState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LocalRoomCreationState.kt
new file mode 100644
index 0000000000..4fc99225c4
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LocalRoomCreationState.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2022 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.session.room.model
+
+enum class LocalRoomCreationState {
+ NOT_CREATED,
+ CREATING,
+ FAILURE,
+ CREATED
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LocalRoomSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LocalRoomSummary.kt
new file mode 100644
index 0000000000..eced1dd581
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/LocalRoomSummary.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2022 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.session.room.model
+
+import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
+
+/**
+ * This class holds some data of a local room.
+ * It can be retrieved by [org.matrix.android.sdk.api.session.room.Room] and [org.matrix.android.sdk.api.session.room.RoomService]
+ */
+data class LocalRoomSummary(
+ /**
+ * The roomId of the room.
+ */
+ val roomId: String,
+ /**
+ * The room summary of the room.
+ */
+ val roomSummary: RoomSummary?,
+ /**
+ * The creation params attached to the room.
+ */
+ val createRoomParams: CreateRoomParams?,
+ /**
+ * The roomId of the created room (ie. created on the server), if any.
+ */
+ val replacementRoomId: String?,
+ /**
+ * The creation state of the room.
+ */
+ val creationState: LocalRoomCreationState,
+)
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 0b11863864..2693ca474c 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
@@ -53,6 +53,7 @@ import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo033
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo034
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo035
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo036
+import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo037
import org.matrix.android.sdk.internal.util.Normalizer
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
import javax.inject.Inject
@@ -61,7 +62,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
private val normalizer: Normalizer
) : MatrixRealmMigration(
dbName = "Session",
- schemaVersion = 36L,
+ schemaVersion = 37L,
) {
/**
* Forces all RealmSessionStoreMigration instances to be equal.
@@ -107,5 +108,6 @@ internal class RealmSessionStoreMigration @Inject constructor(
if (oldVersion < 34) MigrateSessionTo034(realm).perform()
if (oldVersion < 35) MigrateSessionTo035(realm).perform()
if (oldVersion < 36) MigrateSessionTo036(realm).perform()
+ if (oldVersion < 37) MigrateSessionTo037(realm).perform()
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LocalRoomSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LocalRoomSummaryMapper.kt
new file mode 100644
index 0000000000..09cb5985f3
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LocalRoomSummaryMapper.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2022 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.mapper
+
+import org.matrix.android.sdk.api.session.room.model.LocalRoomSummary
+import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntity
+import javax.inject.Inject
+
+internal class LocalRoomSummaryMapper @Inject constructor(
+ private val roomSummaryMapper: RoomSummaryMapper,
+) {
+
+ fun map(localRoomSummaryEntity: LocalRoomSummaryEntity): LocalRoomSummary {
+ return LocalRoomSummary(
+ roomId = localRoomSummaryEntity.roomId,
+ roomSummary = localRoomSummaryEntity.roomSummaryEntity?.let { roomSummaryMapper.map(it) },
+ createRoomParams = localRoomSummaryEntity.createRoomParams,
+ replacementRoomId = localRoomSummaryEntity.replacementRoomId,
+ creationState = localRoomSummaryEntity.creationState
+ )
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo037.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo037.kt
new file mode 100644
index 0000000000..cdb0b6c682
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo037.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2022 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.migration
+
+import io.realm.DynamicRealm
+import org.matrix.android.sdk.api.session.room.model.LocalRoomCreationState
+import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntityFields
+import org.matrix.android.sdk.internal.util.database.RealmMigrator
+
+internal class MigrateSessionTo037(realm: DynamicRealm) : RealmMigrator(realm, 37) {
+
+ override fun doMigrate(realm: DynamicRealm) {
+ realm.schema.get("LocalRoomSummaryEntity")
+ ?.addField(LocalRoomSummaryEntityFields.REPLACEMENT_ROOM_ID, String::class.java)
+ ?.addField(LocalRoomSummaryEntityFields.STATE_STR, String::class.java)
+ ?.transform { obj ->
+ obj.set(LocalRoomSummaryEntityFields.STATE_STR, LocalRoomCreationState.NOT_CREATED.name)
+ }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/LocalRoomSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/LocalRoomSummaryEntity.kt
index fd8331e986..a978e3719d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/LocalRoomSummaryEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/LocalRoomSummaryEntity.kt
@@ -18,15 +18,24 @@ package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
+import org.matrix.android.sdk.api.session.room.model.LocalRoomCreationState
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.room.model.create.toJSONString
internal open class LocalRoomSummaryEntity(
@PrimaryKey var roomId: String = "",
var roomSummaryEntity: RoomSummaryEntity? = null,
- private var createRoomParamsStr: String? = null
+ var replacementRoomId: String? = null,
) : RealmObject() {
+ private var stateStr: String = LocalRoomCreationState.NOT_CREATED.name
+ var creationState: LocalRoomCreationState
+ get() = LocalRoomCreationState.valueOf(stateStr)
+ set(value) {
+ stateStr = value.name
+ }
+
+ private var createRoomParamsStr: String? = null
var createRoomParams: CreateRoomParams?
get() {
return CreateRoomParams.fromJson(createRoomParamsStr)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LocalRoomSummaryEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LocalRoomSummaryEntityQueries.kt
index 527350bedc..44730eb75d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LocalRoomSummaryEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LocalRoomSummaryEntityQueries.kt
@@ -22,10 +22,6 @@ import io.realm.kotlin.where
import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntity
import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntityFields
-internal fun LocalRoomSummaryEntity.Companion.where(realm: Realm, roomId: String? = null): RealmQuery {
- val query = realm.where()
- if (roomId != null) {
- query.equalTo(LocalRoomSummaryEntityFields.ROOM_ID, roomId)
- }
- return query
+internal fun LocalRoomSummaryEntity.Companion.where(realm: Realm, roomId: String): RealmQuery {
+ return realm.where().equalTo(LocalRoomSummaryEntityFields.ROOM_ID, roomId)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadReceiptEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadReceiptEntityQueries.kt
index b180c06e2c..170814d3f2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadReceiptEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadReceiptEntityQueries.kt
@@ -33,6 +33,11 @@ internal fun ReadReceiptEntity.Companion.whereUserId(realm: Realm, userId: Strin
.equalTo(ReadReceiptEntityFields.USER_ID, userId)
}
+internal fun ReadReceiptEntity.Companion.whereRoomId(realm: Realm, roomId: String): RealmQuery {
+ return realm.where()
+ .equalTo(ReadReceiptEntityFields.ROOM_ID, roomId)
+}
+
internal fun ReadReceiptEntity.Companion.createUnmanaged(roomId: String, eventId: String, userId: String, originServerTs: Double): ReadReceiptEntity {
return ReadReceiptEntity().apply {
this.primaryKey = "${roomId}_$userId"
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt
index abea2d34cd..262c111b73 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt
@@ -25,6 +25,7 @@ import org.matrix.android.sdk.api.session.room.call.RoomCallService
import org.matrix.android.sdk.api.session.room.crypto.RoomCryptoService
import org.matrix.android.sdk.api.session.room.location.LocationSharingService
import org.matrix.android.sdk.api.session.room.members.MembershipService
+import org.matrix.android.sdk.api.session.room.model.LocalRoomSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.RoomType
import org.matrix.android.sdk.api.session.room.model.relation.RelationService
@@ -82,6 +83,14 @@ internal class DefaultRoom(
return roomSummaryDataSource.getRoomSummary(roomId)
}
+ override fun getLocalRoomSummaryLive(): LiveData> {
+ return roomSummaryDataSource.getLocalRoomSummaryLive(roomId)
+ }
+
+ override fun localRoomSummary(): LocalRoomSummary? {
+ return roomSummaryDataSource.getLocalRoomSummary(roomId)
+ }
+
override fun asSpace(): Space? {
if (roomSummary()?.roomType != RoomType.SPACE) return null
return DefaultSpace(this, roomSummaryDataSource, viaParameterFinder)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt
index 989bcaee44..6d72b8ef20 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt
@@ -29,10 +29,12 @@ import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
import org.matrix.android.sdk.api.session.room.alias.RoomAliasDescription
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
+import org.matrix.android.sdk.api.session.room.model.LocalRoomSummary
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
+import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho
import org.matrix.android.sdk.api.session.room.peeking.PeekResult
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
@@ -106,6 +108,10 @@ internal class DefaultRoomService @Inject constructor(
return roomSummaryDataSource.getRoomSummaryLive(roomId)
}
+ override fun getLocalRoomSummaryLive(roomId: String): LiveData> {
+ return roomSummaryDataSource.getLocalRoomSummaryLive(roomId)
+ }
+
override fun getRoomSummaries(
queryParams: RoomSummaryQueryParams,
sortOrder: RoomSortOrder
@@ -173,7 +179,10 @@ internal class DefaultRoomService @Inject constructor(
}
override suspend fun onRoomDisplayed(roomId: String) {
- updateBreadcrumbsTask.execute(UpdateBreadcrumbsTask.Params(roomId))
+ // Do not add local rooms to the recent rooms list as they should not be known by the server
+ if (!RoomLocalEcho.isLocalEchoId(roomId)) {
+ updateBreadcrumbsTask.execute(UpdateBreadcrumbsTask.Params(roomId))
+ }
}
override suspend fun joinRoom(roomIdOrAlias: String, reason: String?, viaServers: List) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomFromLocalRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomFromLocalRoomTask.kt
index 02538a5cc3..2245eb8513 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomFromLocalRoomTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomFromLocalRoomTask.kt
@@ -17,38 +17,23 @@
package org.matrix.android.sdk.internal.session.room.create
import com.zhuinden.monarchy.Monarchy
-import io.realm.kotlin.where
import kotlinx.coroutines.TimeoutCancellationException
-import org.matrix.android.sdk.api.extensions.orFalse
-import org.matrix.android.sdk.api.query.QueryStringValue
-import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.api.session.events.model.toContent
-import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
+import org.matrix.android.sdk.api.session.room.model.LocalRoomCreationState
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
-import org.matrix.android.sdk.api.session.room.model.tombstone.RoomTombstoneContent
-import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
-import org.matrix.android.sdk.internal.database.mapper.toEntity
-import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
import org.matrix.android.sdk.internal.database.model.EventEntity
import org.matrix.android.sdk.internal.database.model.EventEntityFields
-import org.matrix.android.sdk.internal.database.model.EventInsertType
import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntity
-import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntityFields
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.copyToRealmOrIgnore
-import org.matrix.android.sdk.internal.database.query.getOrCreate
+import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.database.query.whereRoomId
import org.matrix.android.sdk.internal.di.SessionDatabase
-import org.matrix.android.sdk.internal.di.UserId
-import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
+import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource
import org.matrix.android.sdk.internal.task.Task
-import org.matrix.android.sdk.internal.util.awaitTransaction
-import org.matrix.android.sdk.internal.util.time.Clock
-import java.util.UUID
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@@ -56,94 +41,100 @@ import javax.inject.Inject
* Create a room on the server from a local room.
* The configuration of the local room will be use to configure the new room.
* The potential local room members will also be invited to this new room.
- *
- * A local tombstone event will be created to indicate that the local room has been replacing by the new one.
*/
internal interface CreateRoomFromLocalRoomTask : Task {
data class Params(val localRoomId: String)
}
internal class DefaultCreateRoomFromLocalRoomTask @Inject constructor(
- @UserId private val userId: String,
@SessionDatabase private val monarchy: Monarchy,
private val createRoomTask: CreateRoomTask,
- private val stateEventDataSource: StateEventDataSource,
- private val clock: Clock,
+ private val roomSummaryDataSource: RoomSummaryDataSource,
) : CreateRoomFromLocalRoomTask {
private val realmConfiguration
get() = monarchy.realmConfiguration
override suspend fun execute(params: CreateRoomFromLocalRoomTask.Params): String {
- val replacementRoomId = stateEventDataSource.getStateEvent(params.localRoomId, EventType.STATE_ROOM_TOMBSTONE, QueryStringValue.IsEmpty)
- ?.content.toModel()
- ?.replacementRoomId
+ val localRoomSummary = roomSummaryDataSource.getLocalRoomSummary(params.localRoomId)
+ ?: error("## CreateRoomFromLocalRoomTask - Cannot retrieve LocalRoomSummary with roomId ${params.localRoomId}")
- if (replacementRoomId != null) {
- return replacementRoomId
+ // If a room has already been created for the given local room, return the existing roomId
+ if (localRoomSummary.replacementRoomId != null) {
+ return localRoomSummary.replacementRoomId
}
- var createRoomParams: CreateRoomParams? = null
- var isEncrypted = false
- monarchy.doWithRealm { realm ->
- realm.where()
- .equalTo(LocalRoomSummaryEntityFields.ROOM_ID, params.localRoomId)
- .findFirst()
- ?.let {
- createRoomParams = it.createRoomParams
- isEncrypted = it.roomSummaryEntity?.isEncrypted.orFalse()
- }
+ if (localRoomSummary.createRoomParams != null && localRoomSummary.roomSummary != null) {
+ return createRoom(params.localRoomId, localRoomSummary.roomSummary, localRoomSummary.createRoomParams)
+ } else {
+ error("## CreateRoomFromLocalRoomTask - Invalid LocalRoomSummary: $localRoomSummary")
}
- val roomId = createRoomTask.execute(createRoomParams!!)
+ }
+ /**
+ * Create a room on the server for the given local room.
+ *
+ * @param localRoomId the local room identifier.
+ * @param localRoomSummary the RoomSummary of the local room.
+ * @param createRoomParams the CreateRoomParams object which was used to configure the local room.
+ *
+ * @return the identifier of the created room.
+ */
+ private suspend fun createRoom(localRoomId: String, localRoomSummary: RoomSummary, createRoomParams: CreateRoomParams): String {
+ updateCreationState(localRoomId, LocalRoomCreationState.CREATING)
+ val replacementRoomId = runCatching {
+ createRoomTask.execute(createRoomParams)
+ }.fold(
+ { it },
+ {
+ updateCreationState(localRoomId, LocalRoomCreationState.FAILURE)
+ throw it
+ }
+ )
+ updateReplacementRoomId(localRoomId, replacementRoomId)
+ waitForRoomEvents(replacementRoomId, localRoomSummary)
+ updateCreationState(localRoomId, LocalRoomCreationState.CREATED)
+ return replacementRoomId
+ }
+
+ /**
+ * Wait for all the room events before triggering the created state.
+ *
+ * @param replacementRoomId the identifier of the created room
+ * @param localRoomSummary the RoomSummary of the local room.
+ */
+ private suspend fun waitForRoomEvents(replacementRoomId: String, localRoomSummary: RoomSummary) {
try {
- // Wait for all the room events before triggering the replacement room
awaitNotEmptyResult(realmConfiguration, TimeUnit.MINUTES.toMillis(1L)) { realm ->
realm.where(RoomSummaryEntity::class.java)
- .equalTo(RoomSummaryEntityFields.ROOM_ID, roomId)
- .equalTo(RoomSummaryEntityFields.INVITED_MEMBERS_COUNT, createRoomParams?.invitedUserIds?.size ?: 0)
+ .equalTo(RoomSummaryEntityFields.ROOM_ID, replacementRoomId)
+ .equalTo(RoomSummaryEntityFields.INVITED_MEMBERS_COUNT, localRoomSummary.invitedMembersCount)
}
awaitNotEmptyResult(realmConfiguration, TimeUnit.MINUTES.toMillis(1L)) { realm ->
- EventEntity.whereRoomId(realm, roomId)
+ EventEntity.whereRoomId(realm, replacementRoomId)
.equalTo(EventEntityFields.TYPE, EventType.STATE_ROOM_HISTORY_VISIBILITY)
}
- if (isEncrypted) {
+ if (localRoomSummary.isEncrypted) {
awaitNotEmptyResult(realmConfiguration, TimeUnit.MINUTES.toMillis(1L)) { realm ->
- EventEntity.whereRoomId(realm, roomId)
+ EventEntity.whereRoomId(realm, replacementRoomId)
.equalTo(EventEntityFields.TYPE, EventType.STATE_ROOM_ENCRYPTION)
}
}
} catch (exception: TimeoutCancellationException) {
- throw CreateRoomFailure.CreatedWithTimeout(roomId)
+ updateCreationState(localRoomSummary.roomId, LocalRoomCreationState.FAILURE)
+ throw CreateRoomFailure.CreatedWithTimeout(replacementRoomId)
}
-
- createTombstoneEvent(params, roomId)
- return roomId
}
- /**
- * Create a Tombstone event to indicate that the local room has been replaced by a new one.
- */
- private suspend fun createTombstoneEvent(params: CreateRoomFromLocalRoomTask.Params, roomId: String) {
- val now = clock.epochMillis()
- val event = Event(
- type = EventType.STATE_ROOM_TOMBSTONE,
- senderId = userId,
- originServerTs = now,
- stateKey = "",
- eventId = UUID.randomUUID().toString(),
- content = RoomTombstoneContent(
- replacementRoomId = roomId
- ).toContent()
- )
- monarchy.awaitTransaction { realm ->
- val eventEntity = event.toEntity(params.localRoomId, SendState.SYNCED, now).copyToRealmOrIgnore(realm, EventInsertType.INCREMENTAL_SYNC)
- if (event.stateKey != null && event.type != null && event.eventId != null) {
- CurrentStateEventEntity.getOrCreate(realm, params.localRoomId, event.stateKey, event.type).apply {
- eventId = event.eventId
- root = eventEntity
- }
- }
+ private fun updateCreationState(roomId: String, creationState: LocalRoomCreationState) {
+ monarchy.runTransactionSync { realm ->
+ LocalRoomSummaryEntity.where(realm, roomId).findFirst()?.creationState = creationState
+ }
+ }
+
+ private fun updateReplacementRoomId(localRoomId: String, replacementRoomId: String) {
+ monarchy.runTransactionSync { realm ->
+ LocalRoomSummaryEntity.where(realm, localRoomId).findFirst()?.replacementRoomId = replacementRoomId
}
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/delete/DeleteLocalRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/delete/DeleteLocalRoomTask.kt
index 49951d2da0..a60c7e6a27 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/delete/DeleteLocalRoomTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/delete/DeleteLocalRoomTask.kt
@@ -22,12 +22,15 @@ import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
import org.matrix.android.sdk.internal.database.model.EventEntity
import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntity
+import org.matrix.android.sdk.internal.database.model.ReadReceiptEntity
+import org.matrix.android.sdk.internal.database.model.ReadReceiptsSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
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.model.deleteOnCascade
import org.matrix.android.sdk.internal.database.query.where
+import org.matrix.android.sdk.internal.database.query.whereInRoom
import org.matrix.android.sdk.internal.database.query.whereRoomId
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.session.room.delete.DeleteLocalRoomTask.Params
@@ -50,6 +53,12 @@ internal class DefaultDeleteLocalRoomTask @Inject constructor(
if (RoomLocalEcho.isLocalEchoId(roomId)) {
monarchy.awaitTransaction { realm ->
Timber.i("## DeleteLocalRoomTask - delete local room id $roomId")
+ ReadReceiptsSummaryEntity.whereInRoom(realm, roomId = roomId).findAll()
+ ?.also { Timber.i("## DeleteLocalRoomTask - ReadReceiptsSummaryEntity - delete ${it.size} entries") }
+ ?.deleteAllFromRealm()
+ ReadReceiptEntity.whereRoomId(realm, roomId = roomId).findAll()
+ ?.also { Timber.i("## DeleteLocalRoomTask - ReadReceiptEntity - delete ${it.size} entries") }
+ ?.deleteAllFromRealm()
RoomMemberSummaryEntity.where(realm, roomId = roomId).findAll()
?.also { Timber.i("## DeleteLocalRoomTask - RoomMemberSummaryEntity - delete ${it.size} entries") }
?.deleteAllFromRealm()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt
index afc1d5012f..5c4ed8012b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt
@@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.session.room.ResultBoundaries
import org.matrix.android.sdk.api.session.room.RoomSortOrder
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
+import org.matrix.android.sdk.api.session.room.model.LocalRoomSummary
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.RoomType
@@ -43,7 +44,9 @@ import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotification
import org.matrix.android.sdk.api.session.space.SpaceSummaryQueryParams
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.api.util.toOptional
+import org.matrix.android.sdk.internal.database.mapper.LocalRoomSummaryMapper
import org.matrix.android.sdk.internal.database.mapper.RoomSummaryMapper
+import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntity
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.findByAlias
@@ -57,6 +60,7 @@ import javax.inject.Inject
internal class RoomSummaryDataSource @Inject constructor(
@SessionDatabase private val monarchy: Monarchy,
private val roomSummaryMapper: RoomSummaryMapper,
+ private val localRoomSummaryMapper: LocalRoomSummaryMapper,
private val queryStringValueProcessor: QueryStringValueProcessor,
) {
@@ -95,6 +99,25 @@ internal class RoomSummaryDataSource @Inject constructor(
)
}
+ fun getLocalRoomSummary(roomId: String): LocalRoomSummary? {
+ return monarchy
+ .fetchCopyMap({
+ LocalRoomSummaryEntity.where(it, roomId).findFirst()
+ }, { entity, _ ->
+ localRoomSummaryMapper.map(entity)
+ })
+ }
+
+ fun getLocalRoomSummaryLive(roomId: String): LiveData> {
+ val liveData = monarchy.findAllMappedWithChanges(
+ { realm -> LocalRoomSummaryEntity.where(realm, roomId) },
+ { localRoomSummaryMapper.map(it) }
+ )
+ return Transformations.map(liveData) { results ->
+ results.firstOrNull().toOptional()
+ }
+ }
+
fun getRoomSummariesLive(
queryParams: RoomSummaryQueryParams,
sortOrder: RoomSortOrder = RoomSortOrder.NONE
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/create/DefaultCreateRoomFromLocalRoomTaskTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/create/DefaultCreateRoomFromLocalRoomTaskTest.kt
index d3732363b5..9e34280437 100644
--- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/create/DefaultCreateRoomFromLocalRoomTaskTest.kt
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/create/DefaultCreateRoomFromLocalRoomTaskTest.kt
@@ -22,21 +22,22 @@ import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
+import io.mockk.spyk
import io.mockk.unmockkAll
+import io.mockk.verify
+import io.mockk.verifyOrder
import io.realm.kotlin.where
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.amshove.kluent.shouldBeEqualTo
+import org.amshove.kluent.shouldBeNull
import org.junit.After
import org.junit.Before
import org.junit.Test
-import org.matrix.android.sdk.api.query.QueryStringValue
-import org.matrix.android.sdk.api.session.events.model.Event
-import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.api.session.events.model.toContent
-import org.matrix.android.sdk.api.session.events.model.toModel
+import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.session.room.model.LocalRoomCreationState
+import org.matrix.android.sdk.api.session.room.model.LocalRoomSummary
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
-import org.matrix.android.sdk.api.session.room.model.tombstone.RoomTombstoneContent
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
import org.matrix.android.sdk.internal.database.model.EventEntity
@@ -44,29 +45,24 @@ import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntity
import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntityFields
import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore
import org.matrix.android.sdk.internal.database.query.getOrCreate
-import org.matrix.android.sdk.internal.util.time.DefaultClock
import org.matrix.android.sdk.test.fakes.FakeMonarchy
-import org.matrix.android.sdk.test.fakes.FakeStateEventDataSource
+import org.matrix.android.sdk.test.fakes.FakeRoomSummaryDataSource
private const val A_LOCAL_ROOM_ID = "local.a-local-room-id"
private const val AN_EXISTING_ROOM_ID = "an-existing-room-id"
private const val A_ROOM_ID = "a-room-id"
-private const val MY_USER_ID = "my-user-id"
@ExperimentalCoroutinesApi
internal class DefaultCreateRoomFromLocalRoomTaskTest {
private val fakeMonarchy = FakeMonarchy()
- private val clock = DefaultClock()
private val createRoomTask = mockk()
- private val fakeStateEventDataSource = FakeStateEventDataSource()
+ private val fakeRoomSummaryDataSource = FakeRoomSummaryDataSource()
private val defaultCreateRoomFromLocalRoomTask = DefaultCreateRoomFromLocalRoomTask(
- userId = MY_USER_ID,
monarchy = fakeMonarchy.instance,
createRoomTask = createRoomTask,
- stateEventDataSource = fakeStateEventDataSource.instance,
- clock = clock
+ roomSummaryDataSource = fakeRoomSummaryDataSource.instance,
)
@Before
@@ -91,13 +87,12 @@ internal class DefaultCreateRoomFromLocalRoomTaskTest {
@Test
fun `given a local room id when execute then the existing room id is kept`() = runTest {
// Given
- givenATombstoneEvent(
- Event(
- roomId = A_LOCAL_ROOM_ID,
- type = EventType.STATE_ROOM_TOMBSTONE,
- stateKey = "",
- content = RoomTombstoneContent(replacementRoomId = AN_EXISTING_ROOM_ID).toContent()
- )
+ val aCreateRoomParams = mockk(relaxed = true)
+ givenALocalRoomSummary(aCreateRoomParams = aCreateRoomParams, aCreationState = LocalRoomCreationState.CREATED, aReplacementRoomId = AN_EXISTING_ROOM_ID)
+ val aLocalRoomSummaryEntity = givenALocalRoomSummaryEntity(
+ aCreateRoomParams = aCreateRoomParams,
+ aCreationState = LocalRoomCreationState.CREATED,
+ aReplacementRoomId = AN_EXISTING_ROOM_ID
)
// When
@@ -105,20 +100,18 @@ internal class DefaultCreateRoomFromLocalRoomTaskTest {
val result = defaultCreateRoomFromLocalRoomTask.execute(params)
// Then
- verifyTombstoneEvent(AN_EXISTING_ROOM_ID)
+ fakeRoomSummaryDataSource.verifyGetLocalRoomSummary(A_LOCAL_ROOM_ID)
result shouldBeEqualTo AN_EXISTING_ROOM_ID
+ aLocalRoomSummaryEntity.replacementRoomId shouldBeEqualTo AN_EXISTING_ROOM_ID
+ aLocalRoomSummaryEntity.creationState shouldBeEqualTo LocalRoomCreationState.CREATED
}
@Test
fun `given a local room id when execute then it is correctly executed`() = runTest {
// Given
- val aCreateRoomParams = mockk()
- val aLocalRoomSummaryEntity = mockk {
- every { roomSummaryEntity } returns mockk(relaxed = true)
- every { createRoomParams } returns aCreateRoomParams
- }
- givenATombstoneEvent(null)
- givenALocalRoomSummaryEntity(aLocalRoomSummaryEntity)
+ val aCreateRoomParams = mockk(relaxed = true)
+ givenALocalRoomSummary(aCreateRoomParams = aCreateRoomParams, aReplacementRoomId = null)
+ val aLocalRoomSummaryEntity = givenALocalRoomSummaryEntity(aCreateRoomParams = aCreateRoomParams, aReplacementRoomId = null)
coEvery { createRoomTask.execute(any()) } returns A_ROOM_ID
@@ -127,32 +120,84 @@ internal class DefaultCreateRoomFromLocalRoomTaskTest {
val result = defaultCreateRoomFromLocalRoomTask.execute(params)
// Then
- verifyTombstoneEvent(null)
+ fakeRoomSummaryDataSource.verifyGetLocalRoomSummary(A_LOCAL_ROOM_ID)
// CreateRoomTask has been called with the initial CreateRoomParams
coVerify { createRoomTask.execute(aCreateRoomParams) }
// The resulting roomId matches the roomId returned by the createRoomTask
result shouldBeEqualTo A_ROOM_ID
- // A tombstone state event has been created
- coVerify { CurrentStateEventEntity.getOrCreate(realm = any(), roomId = A_LOCAL_ROOM_ID, stateKey = any(), type = EventType.STATE_ROOM_TOMBSTONE) }
+ // The room creation state has correctly been updated
+ verifyOrder {
+ aLocalRoomSummaryEntity.creationState = LocalRoomCreationState.CREATING
+ aLocalRoomSummaryEntity.creationState = LocalRoomCreationState.CREATED
+ }
+ // The local room summary has been updated with the created room id
+ verify { aLocalRoomSummaryEntity.replacementRoomId = A_ROOM_ID }
+ aLocalRoomSummaryEntity.replacementRoomId shouldBeEqualTo A_ROOM_ID
+ aLocalRoomSummaryEntity.creationState shouldBeEqualTo LocalRoomCreationState.CREATED
}
- private fun givenATombstoneEvent(event: Event?) {
- fakeStateEventDataSource.givenGetStateEventReturns(event)
+ @Test
+ fun `given a local room id when execute with an exception then the creation state is correctly updated`() = runTest {
+ // Given
+ val aCreateRoomParams = mockk(relaxed = true)
+ givenALocalRoomSummary(aCreateRoomParams = aCreateRoomParams, aReplacementRoomId = null)
+ val aLocalRoomSummaryEntity = givenALocalRoomSummaryEntity(aCreateRoomParams = aCreateRoomParams, aReplacementRoomId = null)
+
+ coEvery { createRoomTask.execute(any()) }.throws(mockk())
+
+ // When
+ val params = CreateRoomFromLocalRoomTask.Params(A_LOCAL_ROOM_ID)
+ tryOrNull { defaultCreateRoomFromLocalRoomTask.execute(params) }
+
+ // Then
+ fakeRoomSummaryDataSource.verifyGetLocalRoomSummary(A_LOCAL_ROOM_ID)
+ // CreateRoomTask has been called with the initial CreateRoomParams
+ coVerify { createRoomTask.execute(aCreateRoomParams) }
+ // The room creation state has correctly been updated
+ verifyOrder {
+ aLocalRoomSummaryEntity.creationState = LocalRoomCreationState.CREATING
+ aLocalRoomSummaryEntity.creationState = LocalRoomCreationState.FAILURE
+ }
+ // The local room summary has been updated with the created room id
+ aLocalRoomSummaryEntity.replacementRoomId.shouldBeNull()
+ aLocalRoomSummaryEntity.creationState shouldBeEqualTo LocalRoomCreationState.FAILURE
}
- private fun givenALocalRoomSummaryEntity(localRoomSummaryEntity: LocalRoomSummaryEntity) {
+ private fun givenALocalRoomSummary(
+ aCreateRoomParams: CreateRoomParams,
+ aCreationState: LocalRoomCreationState = LocalRoomCreationState.NOT_CREATED,
+ aReplacementRoomId: String? = null
+ ): LocalRoomSummary {
+ val aLocalRoomSummary = LocalRoomSummary(
+ roomId = A_LOCAL_ROOM_ID,
+ roomSummary = mockk(relaxed = true),
+ createRoomParams = aCreateRoomParams,
+ creationState = aCreationState,
+ replacementRoomId = aReplacementRoomId,
+ )
+ fakeRoomSummaryDataSource.givenGetLocalRoomSummaryReturns(A_LOCAL_ROOM_ID, aLocalRoomSummary)
+ return aLocalRoomSummary
+ }
+
+ private fun givenALocalRoomSummaryEntity(
+ aCreateRoomParams: CreateRoomParams,
+ aCreationState: LocalRoomCreationState = LocalRoomCreationState.NOT_CREATED,
+ aReplacementRoomId: String? = null
+ ): LocalRoomSummaryEntity {
+ val aLocalRoomSummaryEntity = spyk(LocalRoomSummaryEntity(
+ roomId = A_LOCAL_ROOM_ID,
+ roomSummaryEntity = mockk(relaxed = true),
+ replacementRoomId = aReplacementRoomId,
+ ).apply {
+ createRoomParams = aCreateRoomParams
+ creationState = aCreationState
+ })
every {
fakeMonarchy.fakeRealm.instance
.where()
.equalTo(LocalRoomSummaryEntityFields.ROOM_ID, A_LOCAL_ROOM_ID)
.findFirst()
- } returns localRoomSummaryEntity
- }
-
- private fun verifyTombstoneEvent(expectedRoomId: String?) {
- fakeStateEventDataSource.verifyGetStateEvent(A_LOCAL_ROOM_ID, EventType.STATE_ROOM_TOMBSTONE, QueryStringValue.IsEmpty)
- fakeStateEventDataSource.instance.getStateEvent(A_LOCAL_ROOM_ID, EventType.STATE_ROOM_TOMBSTONE, QueryStringValue.IsEmpty)
- ?.content.toModel()
- ?.replacementRoomId shouldBeEqualTo expectedRoomId
+ } returns aLocalRoomSummaryEntity
+ return aLocalRoomSummaryEntity
}
}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeMonarchy.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeMonarchy.kt
index 2d501f12af..93999458c6 100644
--- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeMonarchy.kt
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeMonarchy.kt
@@ -47,6 +47,11 @@ internal class FakeMonarchy {
} coAnswers {
firstArg().doWithRealm(fakeRealm.instance)
}
+ coEvery {
+ instance.runTransactionSync(any())
+ } coAnswers {
+ firstArg().execute(fakeRealm.instance)
+ }
every { instance.realmConfiguration } returns mockk()
}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRoomSummaryDataSource.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRoomSummaryDataSource.kt
new file mode 100644
index 0000000000..c7b70a3ad5
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRoomSummaryDataSource.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022 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.test.fakes
+
+import io.mockk.every
+import io.mockk.mockk
+import io.mockk.verify
+import org.matrix.android.sdk.api.session.room.model.LocalRoomSummary
+import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource
+
+internal class FakeRoomSummaryDataSource {
+
+ val instance: RoomSummaryDataSource = mockk()
+
+ fun givenGetLocalRoomSummaryReturns(roomId: String?, localRoomSummary: LocalRoomSummary?) {
+ every { instance.getLocalRoomSummary(roomId = roomId ?: any()) } returns localRoomSummary
+ }
+
+ fun verifyGetLocalRoomSummary(roomId: String) {
+ verify { instance.getLocalRoomSummary(roomId) }
+ }
+}
diff --git a/tools/emojis/emoji_picker_datasource_formatted.json b/tools/emojis/emoji_picker_datasource_formatted.json
index 551ec824b7..c00bd10371 100644
--- a/tools/emojis/emoji_picker_datasource_formatted.json
+++ b/tools/emojis/emoji_picker_datasource_formatted.json
@@ -54,6 +54,7 @@
"grimacing-face",
"face-exhaling",
"lying-face",
+ "shaking-face",
"relieved-face",
"pensive-face",
"sleepy-face",
@@ -104,7 +105,7 @@
"tired-face",
"yawning-face",
"face-with-steam-from-nose",
- "pouting-face",
+ "enraged-face",
"angry-face",
"face-with-symbols-on-mouth",
"smiling-face-with-horns",
@@ -131,7 +132,6 @@
"seenoevil-monkey",
"hearnoevil-monkey",
"speaknoevil-monkey",
- "kiss-mark",
"love-letter",
"heart-with-arrow",
"heart-with-ribbon",
@@ -146,14 +146,18 @@
"heart-on-fire",
"mending-heart",
"red-heart",
+ "pink-heart",
"orange-heart",
"yellow-heart",
"green-heart",
"blue-heart",
+ "light-blue-heart",
"purple-heart",
"brown-heart",
"black-heart",
+ "grey-heart",
"white-heart",
+ "kiss-mark",
"hundred-points",
"anger-symbol",
"collision",
@@ -161,7 +165,6 @@
"sweat-droplets",
"dashing-away",
"hole",
- "bomb",
"speech-balloon",
"eye-in-speech-bubble",
"left-speech-bubble",
@@ -183,6 +186,8 @@
"leftwards-hand",
"palm-down-hand",
"palm-up-hand",
+ "leftwards-pushing-hand",
+ "rightwards-pushing-hand",
"ok-hand",
"pinched-fingers",
"pinching-hand",
@@ -561,6 +566,8 @@
"tiger",
"leopard",
"horse-face",
+ "moose",
+ "donkey",
"horse",
"unicorn",
"zebra",
@@ -623,6 +630,9 @@
"flamingo",
"peacock",
"parrot",
+ "wing",
+ "black-bird",
+ "goose",
"frog",
"crocodile",
"turtle",
@@ -643,6 +653,7 @@
"octopus",
"spiral-shell",
"coral",
+ "jellyfish",
"snail",
"butterfly",
"bug",
@@ -670,6 +681,7 @@
"sunflower",
"blossom",
"tulip",
+ "hyacinth",
"seedling",
"potted-plant",
"evergreen-tree",
@@ -684,7 +696,8 @@
"fallen-leaf",
"leaf-fluttering-in-wind",
"empty-nest",
- "nest-with-eggs"
+ "nest-with-eggs",
+ "mushroom"
]
},
{
@@ -722,10 +735,11 @@
"broccoli",
"garlic",
"onion",
- "mushroom",
"peanuts",
"beans",
"chestnut",
+ "ginger-root",
+ "pea-pod",
"bread",
"croissant",
"baguette-bread",
@@ -1110,11 +1124,10 @@
"bullseye",
"yoyo",
"kite",
+ "water-pistol",
"pool-8-ball",
"crystal-ball",
"magic-wand",
- "nazar-amulet",
- "hamsa",
"video-game",
"joystick",
"slot-machine",
@@ -1165,6 +1178,7 @@
"shorts",
"bikini",
"womans-clothes",
+ "folding-hand-fan",
"purse",
"handbag",
"clutch-bag",
@@ -1179,6 +1193,7 @@
"womans-sandal",
"ballet-shoes",
"womans-boot",
+ "hair-pick",
"crown",
"womans-hat",
"top-hat",
@@ -1217,6 +1232,8 @@
"banjo",
"drum",
"long-drum",
+ "maracas",
+ "flute",
"mobile-phone",
"mobile-phone-with-arrow",
"telephone",
@@ -1336,7 +1353,7 @@
"hammer-and-wrench",
"dagger",
"crossed-swords",
- "water-pistol",
+ "bomb",
"boomerang",
"bow-and-arrow",
"shield",
@@ -1397,6 +1414,8 @@
"coffin",
"headstone",
"funeral-urn",
+ "nazar-amulet",
+ "hamsa",
"moai",
"placard",
"identification-card"
@@ -1465,6 +1484,7 @@
"peace-symbol",
"menorah",
"dotted-sixpointed-star",
+ "khanda",
"aries",
"taurus",
"gemini",
@@ -1500,6 +1520,7 @@
"dim-button",
"bright-button",
"antenna-bars",
+ "wireless",
"vibration-mode",
"mobile-phone-off",
"female-sign",
@@ -2050,7 +2071,7 @@
]
},
"melting-face": {
- "a": "⊛ Melting Face",
+ "a": "Melting Face",
"b": "1FAE0",
"j": [
"disappear",
@@ -2345,7 +2366,7 @@
]
},
"face-with-open-eyes-and-hand-over-mouth": {
- "a": "⊛ Face with Open Eyes and Hand over Mouth",
+ "a": "Face with Open Eyes and Hand over Mouth",
"b": "1FAE2",
"j": [
"amazement",
@@ -2360,7 +2381,7 @@
]
},
"face-with-peeking-eye": {
- "a": "⊛ Face with Peeking Eye",
+ "a": "Face with Peeking Eye",
"b": "1FAE3",
"j": [
"captivated",
@@ -2394,10 +2415,10 @@
]
},
"saluting-face": {
- "a": "⊛ Saluting Face",
+ "a": "Saluting Face",
"b": "1FAE1",
"j": [
- "ok",
+ "OK",
"salute",
"sunny",
"troops",
@@ -2470,7 +2491,7 @@
]
},
"dotted-line-face": {
- "a": "⊛ Dotted Line Face",
+ "a": "Dotted Line Face",
"b": "1FAE5",
"j": [
"depressed",
@@ -2570,6 +2591,17 @@
"pinocchio"
]
},
+ "shaking-face": {
+ "a": "⊛ Shaking Face",
+ "b": "1FAE8",
+ "j": [
+ "earthquake",
+ "face",
+ "shaking",
+ "shock",
+ "vibrate"
+ ]
+ },
"relieved-face": {
"a": "Relieved Face",
"b": "1F60C",
@@ -2599,6 +2631,7 @@
"b": "1F62A",
"j": [
"face",
+ "good night",
"sleep",
"tired",
"rest",
@@ -2618,11 +2651,13 @@
"b": "1F634",
"j": [
"face",
+ "good night",
"sleep",
- "zzz",
+ "ZZZ",
"tired",
"sleepy",
- "night"
+ "night",
+ "zzz"
]
},
"face-with-medical-mask": {
@@ -2852,9 +2887,10 @@
"a": "Face with Monocle",
"b": "1F9D0",
"j": [
+ "face",
+ "monocle",
"stuffy",
- "wealthy",
- "face"
+ "wealthy"
]
},
"confused-face": {
@@ -2872,7 +2908,7 @@
]
},
"face-with-diagonal-mouth": {
- "a": "⊛ Face with Diagonal Mouth",
+ "a": "Face with Diagonal Mouth",
"b": "1FAE4",
"j": [
"disappointed",
@@ -2981,7 +3017,7 @@
]
},
"face-holding-back-tears": {
- "a": "⊛ Face Holding Back Tears",
+ "a": "Face Holding Back Tears",
"b": "1F979",
"j": [
"angry",
@@ -3192,16 +3228,18 @@
"pride"
]
},
- "pouting-face": {
- "a": "Pouting Face",
+ "enraged-face": {
+ "a": "Enraged Face",
"b": "1F621",
"j": [
"angry",
+ "enraged",
"face",
"mad",
"pouting",
"rage",
"red",
+ "pouting_face",
"hate",
"despise"
]
@@ -3579,19 +3617,6 @@
"omg"
]
},
- "kiss-mark": {
- "a": "Kiss Mark",
- "b": "1F48B",
- "j": [
- "kiss",
- "lips",
- "face",
- "love",
- "like",
- "affection",
- "valentines"
- ]
- },
"love-letter": {
"a": "Love Letter",
"b": "1F48C",
@@ -3765,6 +3790,17 @@
"valentines"
]
},
+ "pink-heart": {
+ "a": "⊛ Pink Heart",
+ "b": "1FA77",
+ "j": [
+ "cute",
+ "heart",
+ "like",
+ "love",
+ "pink"
+ ]
+ },
"orange-heart": {
"a": "Orange Heart",
"b": "1F9E1",
@@ -3809,6 +3845,17 @@
"valentines"
]
},
+ "light-blue-heart": {
+ "a": "⊛ Light Blue Heart",
+ "b": "1FA75",
+ "j": [
+ "cyan",
+ "heart",
+ "light blue",
+ "light blue heart",
+ "teal"
+ ]
+ },
"purple-heart": {
"a": "Purple Heart",
"b": "1F49C",
@@ -3838,6 +3885,17 @@
"wicked"
]
},
+ "grey-heart": {
+ "a": "⊛ Grey Heart",
+ "b": "1FA76",
+ "j": [
+ "gray",
+ "grey heart",
+ "heart",
+ "silver",
+ "slate"
+ ]
+ },
"white-heart": {
"a": "White Heart",
"b": "1F90D",
@@ -3847,6 +3905,19 @@
"pure"
]
},
+ "kiss-mark": {
+ "a": "Kiss Mark",
+ "b": "1F48B",
+ "j": [
+ "kiss",
+ "lips",
+ "face",
+ "love",
+ "like",
+ "affection",
+ "valentines"
+ ]
+ },
"hundred-points": {
"a": "Hundred Points",
"b": "1F4AF",
@@ -3931,17 +4002,6 @@
"embarrassing"
]
},
- "bomb": {
- "a": "Bomb",
- "b": "1F4A3",
- "j": [
- "comic",
- "boom",
- "explode",
- "explosion",
- "terrorism"
- ]
- },
"speech-balloon": {
"a": "Speech Balloon",
"b": "1F4AC",
@@ -3961,8 +4021,10 @@
"a": "Eye in Speech Bubble",
"b": "1F441-FE0F-200D-1F5E8-FE0F",
"j": [
+ "balloon",
+ "bubble",
"eye",
- "speech bubble",
+ "speech",
"witness",
"info"
]
@@ -3971,6 +4033,8 @@
"a": "Left Speech Bubble",
"b": "1F5E8",
"j": [
+ "balloon",
+ "bubble",
"dialog",
"speech",
"words",
@@ -4011,7 +4075,9 @@
"b": "1F4A4",
"j": [
"comic",
+ "good night",
"sleep",
+ "ZZZ",
"sleepy",
"tired",
"dream"
@@ -4081,7 +4147,7 @@
]
},
"rightwards-hand": {
- "a": "⊛ Rightwards Hand",
+ "a": "Rightwards Hand",
"b": "1FAF1",
"j": [
"hand",
@@ -4092,7 +4158,7 @@
]
},
"leftwards-hand": {
- "a": "⊛ Leftwards Hand",
+ "a": "Leftwards Hand",
"b": "1FAF2",
"j": [
"hand",
@@ -4103,7 +4169,7 @@
]
},
"palm-down-hand": {
- "a": "⊛ Palm Down Hand",
+ "a": "Palm Down Hand",
"b": "1FAF3",
"j": [
"dismiss",
@@ -4113,7 +4179,7 @@
]
},
"palm-up-hand": {
- "a": "⊛ Palm Up Hand",
+ "a": "Palm Up Hand",
"b": "1FAF4",
"j": [
"beckon",
@@ -4124,6 +4190,32 @@
"demand"
]
},
+ "leftwards-pushing-hand": {
+ "a": "⊛ Leftwards Pushing Hand",
+ "b": "1FAF7",
+ "j": [
+ "high five",
+ "leftward",
+ "leftwards pushing hand",
+ "push",
+ "refuse",
+ "stop",
+ "wait"
+ ]
+ },
+ "rightwards-pushing-hand": {
+ "a": "⊛ Rightwards Pushing Hand",
+ "b": "1FAF8",
+ "j": [
+ "high five",
+ "push",
+ "refuse",
+ "rightward",
+ "rightwards pushing hand",
+ "stop",
+ "wait"
+ ]
+ },
"ok-hand": {
"a": "Ok Hand",
"b": "1F44C",
@@ -4187,7 +4279,7 @@
]
},
"hand-with-index-finger-and-thumb-crossed": {
- "a": "⊛ Hand with Index Finger and Thumb Crossed",
+ "a": "Hand with Index Finger and Thumb Crossed",
"b": "1FAF0",
"j": [
"expensive",
@@ -4229,6 +4321,8 @@
"j": [
"call",
"hand",
+ "hang loose",
+ "Shaka",
"hands",
"gesture",
"shaka"
@@ -4314,7 +4408,7 @@
]
},
"index-pointing-at-the-viewer": {
- "a": "⊛ Index Pointing at the Viewer",
+ "a": "Index Pointing at the Viewer",
"b": "1FAF5",
"j": [
"point",
@@ -4430,7 +4524,7 @@
]
},
"heart-hands": {
- "a": "⊛ Heart Hands",
+ "a": "Heart Hands",
"b": "1FAF6",
"j": [
"love",
@@ -4687,7 +4781,7 @@
]
},
"biting-lip": {
- "a": "⊛ Biting Lip",
+ "a": "Biting Lip",
"b": "1FAE6",
"j": [
"anxious",
@@ -6089,7 +6183,7 @@
]
},
"person-with-crown": {
- "a": "⊛ Person with Crown",
+ "a": "Person with Crown",
"b": "1FAC5",
"j": [
"monarch",
@@ -6263,7 +6357,7 @@
]
},
"pregnant-man": {
- "a": "⊛ Pregnant Man",
+ "a": "Pregnant Man",
"b": "1FAC3",
"j": [
"belly",
@@ -6274,7 +6368,7 @@
]
},
"pregnant-person": {
- "a": "⊛ Pregnant Person",
+ "a": "Pregnant Person",
"b": "1FAC4",
"j": [
"belly",
@@ -6670,7 +6764,7 @@
]
},
"troll": {
- "a": "⊛ Troll",
+ "a": "Troll",
"b": "1F9CC",
"j": [
"fairy tale",
@@ -7634,6 +7728,7 @@
"a": "Person in Bed",
"b": "1F6CC",
"j": [
+ "good night",
"hotel",
"sleep",
"bed",
@@ -8515,6 +8610,30 @@
"nature"
]
},
+ "moose": {
+ "a": "⊛ Moose",
+ "b": "1FACE",
+ "j": [
+ "animal",
+ "antlers",
+ "elk",
+ "mammal",
+ "moose"
+ ]
+ },
+ "donkey": {
+ "a": "⊛ Donkey",
+ "b": "1FACF",
+ "j": [
+ "animal",
+ "ass",
+ "burro",
+ "donkey",
+ "mammal",
+ "mule",
+ "stubborn"
+ ]
+ },
"horse": {
"a": "Horse",
"b": "1F40E",
@@ -9181,6 +9300,40 @@
"nature"
]
},
+ "wing": {
+ "a": "⊛ Wing",
+ "b": "1FABD",
+ "j": [
+ "angelic",
+ "aviation",
+ "bird",
+ "flying",
+ "mythology",
+ "wing"
+ ]
+ },
+ "black-bird": {
+ "a": "⊛ Black Bird",
+ "b": "1F426-200D-2B1B",
+ "j": [
+ "bird",
+ "black",
+ "crow",
+ "raven",
+ "rook"
+ ]
+ },
+ "goose": {
+ "a": "⊛ Goose",
+ "b": "1FABF",
+ "j": [
+ "bird",
+ "fowl",
+ "goose",
+ "honk",
+ "silly"
+ ]
+ },
"frog": {
"a": "Frog",
"b": "1F438",
@@ -9411,7 +9564,7 @@
]
},
"coral": {
- "a": "⊛ Coral",
+ "a": "Coral",
"b": "1FAB8",
"j": [
"ocean",
@@ -9419,6 +9572,19 @@
"sea"
]
},
+ "jellyfish": {
+ "a": "⊛ Jellyfish",
+ "b": "1FABC",
+ "j": [
+ "burn",
+ "invertebrate",
+ "jelly",
+ "jellyfish",
+ "marine",
+ "ouch",
+ "stinger"
+ ]
+ },
"snail": {
"a": "Snail",
"b": "1F40C",
@@ -9622,7 +9788,7 @@
]
},
"lotus": {
- "a": "⊛ Lotus",
+ "a": "Lotus",
"b": "1FAB7",
"j": [
"Buddhism",
@@ -9711,6 +9877,18 @@
"spring"
]
},
+ "hyacinth": {
+ "a": "⊛ Hyacinth",
+ "b": "1FABB",
+ "j": [
+ "bluebonnet",
+ "flower",
+ "hyacinth",
+ "lavender",
+ "lupine",
+ "snapdragon"
+ ]
+ },
"seedling": {
"a": "Seedling",
"b": "1F331",
@@ -9875,7 +10053,7 @@
]
},
"empty-nest": {
- "a": "⊛ Empty Nest",
+ "a": "Empty Nest",
"b": "1FAB9",
"j": [
"nesting",
@@ -9883,13 +10061,22 @@
]
},
"nest-with-eggs": {
- "a": "⊛ Nest with Eggs",
+ "a": "Nest with Eggs",
"b": "1FABA",
"j": [
"nesting",
"bird"
]
},
+ "mushroom": {
+ "a": "Mushroom",
+ "b": "1F344",
+ "j": [
+ "toadstool",
+ "plant",
+ "vegetable"
+ ]
+ },
"grapes": {
"a": "Grapes",
"b": "1F347",
@@ -10201,15 +10388,6 @@
"spice"
]
},
- "mushroom": {
- "a": "Mushroom",
- "b": "1F344",
- "j": [
- "toadstool",
- "plant",
- "vegetable"
- ]
- },
"peanuts": {
"a": "Peanuts",
"b": "1F95C",
@@ -10221,7 +10399,7 @@
]
},
"beans": {
- "a": "⊛ Beans",
+ "a": "Beans",
"b": "1FAD8",
"j": [
"food",
@@ -10238,6 +10416,28 @@
"squirrel"
]
},
+ "ginger-root": {
+ "a": "⊛ Ginger Root",
+ "b": "1FADA",
+ "j": [
+ "beer",
+ "ginger root",
+ "root",
+ "spice"
+ ]
+ },
+ "pea-pod": {
+ "a": "⊛ Pea Pod",
+ "b": "1FADB",
+ "j": [
+ "beans",
+ "edamame",
+ "legume",
+ "pea",
+ "pod",
+ "vegetable"
+ ]
+ },
"bread": {
"a": "Bread",
"b": "1F35E",
@@ -11258,7 +11458,7 @@
]
},
"pouring-liquid": {
- "a": "⊛ Pouring Liquid",
+ "a": "Pouring Liquid",
"b": "1FAD7",
"j": [
"drink",
@@ -11387,7 +11587,7 @@
]
},
"jar": {
- "a": "⊛ Jar",
+ "a": "Jar",
"b": "1FAD9",
"j": [
"condiment",
@@ -12078,7 +12278,7 @@
]
},
"playground-slide": {
- "a": "⊛ Playground Slide",
+ "a": "Playground Slide",
"b": "1F6DD",
"j": [
"amusement park",
@@ -12609,7 +12809,7 @@
]
},
"wheel": {
- "a": "⊛ Wheel",
+ "a": "Wheel",
"b": "1F6DE",
"j": [
"circle",
@@ -12691,7 +12891,7 @@
]
},
"ring-buoy": {
- "a": "⊛ Ring Buoy",
+ "a": "Ring Buoy",
"b": "1F6DF",
"j": [
"float",
@@ -14686,6 +14886,20 @@
"wind"
]
},
+ "water-pistol": {
+ "a": "Water Pistol",
+ "b": "1F52B",
+ "j": [
+ "gun",
+ "handgun",
+ "pistol",
+ "revolver",
+ "tool",
+ "water",
+ "weapon",
+ "violence"
+ ]
+ },
"pool-8-ball": {
"a": "Pool 8 Ball",
"b": "1F3B1",
@@ -14729,30 +14943,6 @@
"power"
]
},
- "nazar-amulet": {
- "a": "Nazar Amulet",
- "b": "1F9FF",
- "j": [
- "bead",
- "charm",
- "evil-eye",
- "nazar",
- "talisman"
- ]
- },
- "hamsa": {
- "a": "⊛ Hamsa",
- "b": "1FAAC",
- "j": [
- "amulet",
- "Fatima",
- "hand",
- "Mary",
- "Miriam",
- "protection",
- "religion"
- ]
- },
"video-game": {
"a": "Video Game",
"b": "1F3AE",
@@ -14834,7 +15024,7 @@
]
},
"mirror-ball": {
- "a": "⊛ Mirror Ball",
+ "a": "Mirror Ball",
"b": "1FAA9",
"j": [
"dance",
@@ -15255,6 +15445,19 @@
"female"
]
},
+ "folding-hand-fan": {
+ "a": "⊛ Folding Hand Fan",
+ "b": "1FAAD",
+ "j": [
+ "cooling",
+ "dance",
+ "fan",
+ "flutter",
+ "folding hand fan",
+ "hot",
+ "shy"
+ ]
+ },
"purse": {
"a": "Purse",
"b": "1F45B",
@@ -15429,6 +15632,16 @@
"fashion"
]
},
+ "hair-pick": {
+ "a": "⊛ Hair Pick",
+ "b": "1FAAE",
+ "j": [
+ "Afro",
+ "comb",
+ "hair",
+ "pick"
+ ]
+ },
"crown": {
"a": "Crown",
"b": "1F451",
@@ -15867,6 +16080,30 @@
"music"
]
},
+ "maracas": {
+ "a": "⊛ Maracas",
+ "b": "1FA87",
+ "j": [
+ "instrument",
+ "maracas",
+ "music",
+ "percussion",
+ "rattle",
+ "shake"
+ ]
+ },
+ "flute": {
+ "a": "⊛ Flute",
+ "b": "1FA88",
+ "j": [
+ "fife",
+ "flute",
+ "music",
+ "pipe",
+ "recorder",
+ "woodwind"
+ ]
+ },
"mobile-phone": {
"a": "Mobile Phone",
"b": "1F4F1",
@@ -15944,7 +16181,7 @@
]
},
"low-battery": {
- "a": "⊛ Low Battery",
+ "a": "Low Battery",
"b": "1FAAB",
"j": [
"electronic",
@@ -16057,7 +16294,7 @@
"a": "Optical Disk",
"b": "1F4BF",
"j": [
- "cd",
+ "CD",
"computer",
"disk",
"optical",
@@ -16071,9 +16308,10 @@
"a": "Dvd",
"b": "1F4C0",
"j": [
- "blu-ray",
+ "Blu-ray",
"computer",
"disk",
+ "DVD",
"optical",
"cd",
"disc"
@@ -17261,18 +17499,15 @@
"weapon"
]
},
- "water-pistol": {
- "a": "Water Pistol",
- "b": "1F52B",
+ "bomb": {
+ "a": "Bomb",
+ "b": "1F4A3",
"j": [
- "gun",
- "handgun",
- "pistol",
- "revolver",
- "tool",
- "water",
- "weapon",
- "violence"
+ "comic",
+ "boom",
+ "explode",
+ "explosion",
+ "terrorism"
]
},
"boomerang": {
@@ -17587,7 +17822,7 @@
]
},
"crutch": {
- "a": "⊛ Crutch",
+ "a": "Crutch",
"b": "1FA7C",
"j": [
"cane",
@@ -17610,7 +17845,7 @@
]
},
"xray": {
- "a": "⊛ X-Ray",
+ "a": "X-Ray",
"b": "1FA7B",
"j": [
"bones",
@@ -17817,7 +18052,7 @@
]
},
"bubbles": {
- "a": "⊛ Bubbles",
+ "a": "Bubbles",
"b": "1FAE7",
"j": [
"burp",
@@ -17920,6 +18155,30 @@
"rip"
]
},
+ "nazar-amulet": {
+ "a": "Nazar Amulet",
+ "b": "1F9FF",
+ "j": [
+ "bead",
+ "charm",
+ "evil-eye",
+ "nazar",
+ "talisman"
+ ]
+ },
+ "hamsa": {
+ "a": "Hamsa",
+ "b": "1FAAC",
+ "j": [
+ "amulet",
+ "Fatima",
+ "hand",
+ "Mary",
+ "Miriam",
+ "protection",
+ "religion"
+ ]
+ },
"moai": {
"a": "Moai",
"b": "1F5FF",
@@ -17943,7 +18202,7 @@
]
},
"identification-card": {
- "a": "⊛ Identification Card",
+ "a": "Identification Card",
"b": "1FAAA",
"j": [
"credentials",
@@ -17957,7 +18216,7 @@
"a": "Atm Sign",
"b": "1F3E7",
"j": [
- "atm",
+ "ATM",
"ATM sign",
"automated",
"bank",
@@ -18009,13 +18268,15 @@
"a": "Men’S Room",
"b": "1F6B9",
"j": [
+ "bathroom",
"lavatory",
"man",
"men’s room",
"restroom",
- "wc",
- "men_s_room",
"toilet",
+ "WC",
+ "men_s_room",
+ "wc",
"blue-square",
"gender",
"male"
@@ -18025,15 +18286,16 @@
"a": "Women’S Room",
"b": "1F6BA",
"j": [
+ "bathroom",
"lavatory",
"restroom",
- "wc",
+ "toilet",
+ "WC",
"woman",
"women’s room",
"women_s_room",
"purple-square",
"female",
- "toilet",
"loo",
"gender"
]
@@ -18042,10 +18304,11 @@
"a": "Restroom",
"b": "1F6BB",
"j": [
+ "bathroom",
"lavatory",
+ "toilet",
"WC",
"blue-square",
- "toilet",
"refresh",
"wc",
"gender"
@@ -18065,12 +18328,13 @@
"a": "Water Closet",
"b": "1F6BE",
"j": [
+ "bathroom",
"closet",
"lavatory",
"restroom",
- "water",
- "wc",
"toilet",
+ "water",
+ "WC",
"blue-square"
]
},
@@ -18507,8 +18771,7 @@
"b": "1F519",
"j": [
"arrow",
- "back",
- "BACK arrow",
+ "BACK",
"words",
"return"
]
@@ -18518,8 +18781,7 @@
"b": "1F51A",
"j": [
"arrow",
- "end",
- "END arrow",
+ "END",
"words"
]
},
@@ -18529,8 +18791,8 @@
"j": [
"arrow",
"mark",
- "on",
- "ON! arrow",
+ "ON",
+ "ON!",
"words"
]
},
@@ -18539,8 +18801,7 @@
"b": "1F51C",
"j": [
"arrow",
- "soon",
- "SOON arrow",
+ "SOON",
"words"
]
},
@@ -18549,8 +18810,7 @@
"b": "1F51D",
"j": [
"arrow",
- "top",
- "TOP arrow",
+ "TOP",
"up",
"words",
"blue-square"
@@ -18692,6 +18952,15 @@
"hexagram"
]
},
+ "khanda": {
+ "a": "⊛ Khanda",
+ "b": "1FAAF",
+ "j": [
+ "khanda",
+ "religion",
+ "Sikh"
+ ]
+ },
"aries": {
"a": "Aries",
"b": "2648",
@@ -18969,7 +19238,6 @@
"j": [
"arrow",
"button",
- "red",
"blue-square",
"triangle",
"direction",
@@ -18996,7 +19264,6 @@
"arrow",
"button",
"down",
- "red",
"blue-square",
"direction",
"bottom"
@@ -19106,6 +19373,16 @@
"bars"
]
},
+ "wireless": {
+ "a": "⊛ Wireless",
+ "b": "1F6DC",
+ "j": [
+ "computer",
+ "internet",
+ "network",
+ "wireless"
+ ]
+ },
"vibration-mode": {
"a": "Vibration Mode",
"b": "1F4F3",
@@ -19216,7 +19493,7 @@
]
},
"heavy-equals-sign": {
- "a": "⊛ Heavy Equals Sign",
+ "a": "Heavy Equals Sign",
"b": "1F7F0",
"j": [
"equality",
@@ -19595,7 +19872,7 @@
"a": "Copyright",
"b": "00A9",
"j": [
- "c",
+ "C",
"ip",
"license",
"circle",
@@ -19607,7 +19884,7 @@
"a": "Registered",
"b": "00AE",
"j": [
- "r",
+ "R",
"alphabet",
"circle"
]
@@ -19617,7 +19894,7 @@
"b": "2122",
"j": [
"mark",
- "tm",
+ "TM",
"trademark",
"brand",
"law",
@@ -19815,7 +20092,7 @@
"a": "A Button (Blood Type)",
"b": "1F170",
"j": [
- "a",
+ "A",
"A button (blood type)",
"blood type",
"a_button",
@@ -19828,7 +20105,7 @@
"a": "Ab Button (Blood Type)",
"b": "1F18E",
"j": [
- "ab",
+ "AB",
"AB button (blood type)",
"blood type",
"ab_button",
@@ -19840,7 +20117,7 @@
"a": "B Button (Blood Type)",
"b": "1F171",
"j": [
- "b",
+ "B",
"B button (blood type)",
"blood type",
"b_button",
@@ -19853,7 +20130,7 @@
"a": "Cl Button",
"b": "1F191",
"j": [
- "cl",
+ "CL",
"CL button",
"alphabet",
"words",
@@ -19864,7 +20141,7 @@
"a": "Cool Button",
"b": "1F192",
"j": [
- "cool",
+ "COOL",
"COOL button",
"words",
"blue-square"
@@ -19874,7 +20151,7 @@
"a": "Free Button",
"b": "1F193",
"j": [
- "free",
+ "FREE",
"FREE button",
"blue-square",
"words"
@@ -19894,7 +20171,7 @@
"a": "Id Button",
"b": "1F194",
"j": [
- "id",
+ "ID",
"ID button",
"identity",
"purple-square",
@@ -19907,7 +20184,7 @@
"j": [
"circle",
"circled M",
- "m",
+ "M",
"alphabet",
"blue-circle",
"letter"
@@ -19917,7 +20194,7 @@
"a": "New Button",
"b": "1F195",
"j": [
- "new",
+ "NEW",
"NEW button",
"blue-square",
"words",
@@ -19928,7 +20205,7 @@
"a": "Ng Button",
"b": "1F196",
"j": [
- "ng",
+ "NG",
"NG button",
"blue-square",
"words",
@@ -19941,7 +20218,7 @@
"b": "1F17E",
"j": [
"blood type",
- "o",
+ "O",
"O button (blood type)",
"o_button",
"alphabet",
@@ -19965,6 +20242,7 @@
"a": "P Button",
"b": "1F17F",
"j": [
+ "P",
"P button",
"parking",
"cars",
@@ -19978,7 +20256,7 @@
"b": "1F198",
"j": [
"help",
- "sos",
+ "SOS",
"SOS button",
"red-square",
"words",
@@ -19991,7 +20269,8 @@
"b": "1F199",
"j": [
"mark",
- "up",
+ "UP",
+ "UP!",
"UP! button",
"blue-square",
"above",
@@ -20003,7 +20282,7 @@
"b": "1F19A",
"j": [
"versus",
- "vs",
+ "VS",
"VS button",
"words",
"orange-square"
diff --git a/vector-app/build.gradle b/vector-app/build.gradle
index f0f1bb81b8..ef1f5a42df 100644
--- a/vector-app/build.gradle
+++ b/vector-app/build.gradle
@@ -370,9 +370,9 @@ dependencies {
debugImplementation 'com.facebook.soloader:soloader:0.10.4'
debugImplementation "com.kgurgul.flipper:flipper-realm-android:2.2.0"
- gplayImplementation "com.google.android.gms:play-services-location:16.0.0"
+ gplayImplementation "com.google.android.gms:play-services-location:20.0.0"
// UnifiedPush gplay flavor only
- gplayImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:2.1.2') {
+ gplayImplementation('com.google.firebase:firebase-messaging:23.0.8') {
exclude group: 'com.google.firebase', module: 'firebase-core'
exclude group: 'com.google.firebase', module: 'firebase-analytics'
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
diff --git a/vector-app/src/androidTest/java/im/vector/app/VerifySessionInteractiveTest.kt b/vector-app/src/androidTest/java/im/vector/app/VerifySessionInteractiveTest.kt
index da13e49e84..901ef8e4c1 100644
--- a/vector-app/src/androidTest/java/im/vector/app/VerifySessionInteractiveTest.kt
+++ b/vector-app/src/androidTest/java/im/vector/app/VerifySessionInteractiveTest.kt
@@ -225,8 +225,8 @@ class VerifySessionInteractiveTest : VerificationTestBase() {
// Wait until local secrets are known (gossip)
withIdlingResource(allSecretsKnownIdling(uiSession)) {
- onView(withId(R.id.groupToolbarAvatarImageView))
- .perform(click())
+ onView(withId(R.id.roomListContainer))
+ .check(matches(isDisplayed()))
}
}
diff --git a/vector-app/src/androidTest/java/im/vector/app/ui/robot/ElementRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/ElementRobot.kt
index b70fcfec25..d9dfb0facf 100644
--- a/vector-app/src/androidTest/java/im/vector/app/ui/robot/ElementRobot.kt
+++ b/vector-app/src/androidTest/java/im/vector/app/ui/robot/ElementRobot.kt
@@ -50,7 +50,7 @@ import im.vector.app.withIdlingResource
import timber.log.Timber
class ElementRobot(
- private val labsPreferences: LabFeaturesPreferences = LabFeaturesPreferences(false)
+ private val labsPreferences: LabFeaturesPreferences = LabFeaturesPreferences(true)
) {
fun onboarding(block: OnboardingRobot.() -> Unit) {
block(OnboardingRobot())
@@ -110,9 +110,6 @@ class ElementRobot(
closeSoftKeyboard()
block(NewDirectMessageRobot())
pressBack()
- if (labsPreferences.isNewAppLayoutEnabled) {
- pressBack() // close create dialog
- }
waitUntilViewVisible(withId(R.id.roomListContainer))
}
@@ -121,9 +118,6 @@ class ElementRobot(
clickOn(R.id.bottom_action_rooms)
}
RoomListRobot(labsPreferences).newRoom { block() }
- if (labsPreferences.isNewAppLayoutEnabled) {
- pressBack() // close create dialog
- }
waitUntilViewVisible(withId(R.id.roomListContainer))
}
diff --git a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt
index 9b2711a8c3..9118dea1e3 100644
--- a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt
+++ b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt
@@ -80,11 +80,6 @@ class DebugFeaturesStateFactory @Inject constructor(
key = DebugFeatureKeys.forceUsageOfOpusEncoder,
factory = VectorFeatures::forceUsageOfOpusEncoder
),
- createBooleanFeature(
- label = "Start DM on first message",
- key = DebugFeatureKeys.startDmOnFirstMsg,
- factory = VectorFeatures::shouldStartDmOnFirstMessage
- ),
createBooleanFeature(
label = "Enable New App Layout",
key = DebugFeatureKeys.newAppLayoutEnabled,
diff --git a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt
index bb4cae3201..c01c058fc6 100644
--- a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt
+++ b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt
@@ -73,9 +73,6 @@ class DebugVectorFeatures(
override fun forceUsageOfOpusEncoder(): Boolean = read(DebugFeatureKeys.forceUsageOfOpusEncoder)
?: vectorFeatures.forceUsageOfOpusEncoder()
- override fun shouldStartDmOnFirstMessage(): Boolean = read(DebugFeatureKeys.startDmOnFirstMsg)
- ?: vectorFeatures.shouldStartDmOnFirstMessage()
-
override fun isNewAppLayoutFeatureEnabled(): Boolean = read(DebugFeatureKeys.newAppLayoutEnabled)
?: vectorFeatures.isNewAppLayoutFeatureEnabled()
diff --git a/vector-config/src/main/res/values/config-settings.xml b/vector-config/src/main/res/values/config-settings.xml
index 1701fd45b0..c69452e3d0 100755
--- a/vector-config/src/main/res/values/config-settings.xml
+++ b/vector-config/src/main/res/values/config-settings.xml
@@ -37,8 +37,10 @@
true
+ true
+ true
false
- false
+ true
true
false
diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml
index c7c0d40dd7..bb8ca8cf5f 100644
--- a/vector/src/main/AndroidManifest.xml
+++ b/vector/src/main/AndroidManifest.xml
@@ -323,6 +323,7 @@
+
diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
index 9d2b6c8196..6fb2505386 100644
--- a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
+++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
@@ -89,6 +89,7 @@ import im.vector.app.features.settings.crosssigning.CrossSigningSettingsViewMode
import im.vector.app.features.settings.devices.DeviceVerificationInfoBottomSheetViewModel
import im.vector.app.features.settings.devices.DevicesViewModel
import im.vector.app.features.settings.devices.v2.details.SessionDetailsViewModel
+import im.vector.app.features.settings.devices.v2.othersessions.OtherSessionsViewModel
import im.vector.app.features.settings.devices.v2.overview.SessionOverviewViewModel
import im.vector.app.features.settings.devtools.AccountDataViewModel
import im.vector.app.features.settings.devtools.GossipingEventsPaperTrailViewModel
@@ -643,6 +644,11 @@ interface MavericksViewModelModule {
@MavericksViewModelKey(SessionOverviewViewModel::class)
fun sessionOverviewViewModelFactory(factory: SessionOverviewViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+ @Binds
+ @IntoMap
+ @MavericksViewModelKey(OtherSessionsViewModel::class)
+ fun otherSessionsViewModelFactory(factory: OtherSessionsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
@Binds
@IntoMap
@MavericksViewModelKey(SessionDetailsViewModel::class)
diff --git a/vector/src/main/java/im/vector/app/core/utils/FirstItemUpdatedObserver.kt b/vector/src/main/java/im/vector/app/core/utils/FirstItemUpdatedObserver.kt
new file mode 100644
index 0000000000..25901cdf95
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/utils/FirstItemUpdatedObserver.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022 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.utils
+
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+
+/**
+ * This observer detects when item was added or moved to the first position of the adapter, while recyclerView is scrolled to the top. This is necessary
+ * to force recycler to scroll to the top to make such item visible, because by default it will keep items on screen, while adding new item to the top,
+ * outside of the viewport
+ * @param layoutManager - [LinearLayoutManager] of the recycler view, which displays items
+ * @property onItemUpdated - callback to be called, when observer detects event
+ */
+class FirstItemUpdatedObserver(
+ layoutManager: LinearLayoutManager,
+ private val onItemUpdated: () -> Unit
+) : RecyclerView.AdapterDataObserver() {
+
+ val layoutManager: LinearLayoutManager? by weak(layoutManager)
+
+ override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
+ if ((toPosition == 0 || fromPosition == 0) && layoutManager?.findFirstCompletelyVisibleItemPosition() == 0) {
+ onItemUpdated.invoke()
+ }
+ }
+
+ override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
+ if (positionStart == 0 && layoutManager?.findFirstCompletelyVisibleItemPosition() == 0) {
+ onItemUpdated.invoke()
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt
index dbdb0ba1c7..e1c083db29 100644
--- a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt
+++ b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt
@@ -33,7 +33,6 @@ interface VectorFeatures {
fun isScreenSharingEnabled(): Boolean
fun isLocationSharingEnabled(): Boolean
fun forceUsageOfOpusEncoder(): Boolean
- fun shouldStartDmOnFirstMessage(): Boolean
/**
* This is only to enable if the labs flag should be visible and effective.
@@ -56,7 +55,6 @@ class DefaultVectorFeatures : VectorFeatures {
override fun isScreenSharingEnabled(): Boolean = true
override fun isLocationSharingEnabled() = Config.ENABLE_LOCATION_SHARING
override fun forceUsageOfOpusEncoder(): Boolean = false
- override fun shouldStartDmOnFirstMessage(): Boolean = false
override fun isNewAppLayoutFeatureEnabled(): Boolean = true
override fun isNewDeviceManagementEnabled(): Boolean = false
}
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 61ebc82767..3f67708a28 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
@@ -26,11 +26,11 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.mvrx.runCatchingToAsync
import im.vector.app.core.platform.VectorViewModel
-import im.vector.app.features.VectorFeatures
import im.vector.app.features.analytics.AnalyticsTracker
import im.vector.app.features.analytics.plan.CreatedRoom
import im.vector.app.features.raw.wellknown.getElementWellknown
import im.vector.app.features.raw.wellknown.isE2EByDefault
+import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.userdirectory.PendingSelection
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -45,9 +45,9 @@ import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
class CreateDirectRoomViewModel @AssistedInject constructor(
@Assisted initialState: CreateDirectRoomViewState,
private val rawService: RawService,
+ private val vectorPreferences: VectorPreferences,
val session: Session,
val analyticsTracker: AnalyticsTracker,
- val vectorFeatures: VectorFeatures
) :
VectorViewModel(initialState) {
@@ -124,7 +124,7 @@ class CreateDirectRoomViewModel @AssistedInject constructor(
}
val result = runCatchingToAsync {
- if (vectorFeatures.shouldStartDmOnFirstMessage()) {
+ if (vectorPreferences.isDeferredDmEnabled()) {
session.roomService().createLocalRoom(roomParams)
} else {
analyticsTracker.capture(CreatedRoom(isDM = roomParams.isDirect.orFalse()))
diff --git a/vector/src/main/java/im/vector/app/features/createdirect/DirectRoomHelper.kt b/vector/src/main/java/im/vector/app/features/createdirect/DirectRoomHelper.kt
index c2cc13920f..466aca1176 100644
--- a/vector/src/main/java/im/vector/app/features/createdirect/DirectRoomHelper.kt
+++ b/vector/src/main/java/im/vector/app/features/createdirect/DirectRoomHelper.kt
@@ -16,11 +16,11 @@
package im.vector.app.features.createdirect
-import im.vector.app.features.VectorFeatures
import im.vector.app.features.analytics.AnalyticsTracker
import im.vector.app.features.analytics.plan.CreatedRoom
import im.vector.app.features.raw.wellknown.getElementWellknown
import im.vector.app.features.raw.wellknown.isE2EByDefault
+import im.vector.app.features.settings.VectorPreferences
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.raw.RawService
@@ -32,7 +32,7 @@ class DirectRoomHelper @Inject constructor(
private val rawService: RawService,
private val session: Session,
private val analyticsTracker: AnalyticsTracker,
- private val vectorFeatures: VectorFeatures,
+ private val vectorPreferences: VectorPreferences,
) {
suspend fun ensureDMExists(userId: String): String {
@@ -50,7 +50,7 @@ class DirectRoomHelper @Inject constructor(
setDirectMessage()
enableEncryptionIfInvitedUsersSupportIt = adminE2EByDefault
}
- roomId = if (vectorFeatures.shouldStartDmOnFirstMessage()) {
+ roomId = if (vectorPreferences.isDeferredDmEnabled()) {
session.roomService().createLocalRoom(roomParams)
} else {
analyticsTracker.capture(CreatedRoom(isDM = roomParams.isDirect.orFalse()))
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 dd27b5550c..8fb73d6571 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
@@ -84,6 +84,7 @@ import im.vector.app.features.spaces.SpaceSettingsMenuBottomSheet
import im.vector.app.features.spaces.invite.SpaceInviteBottomSheet
import im.vector.app.features.spaces.share.ShareSpaceBottomSheet
import im.vector.app.features.themes.ThemeUtils
+import im.vector.app.features.usercode.UserCodeActivity
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -634,10 +635,18 @@ class HomeActivity :
launchInviteFriends()
true
}
+ R.id.menu_home_qr -> {
+ launchQrCode()
+ true
+ }
else -> false
}
}
+ private fun launchQrCode() {
+ startActivity(UserCodeActivity.newIntent(this, sharedActionViewModel.session.myUserId))
+ }
+
private fun launchInviteFriends() {
activeSessionHolder.getSafeActiveSession()?.permalinkService()?.createPermalink(sharedActionViewModel.session.myUserId)?.let { permalink ->
analyticsTracker.screen(MobileScreen(screenName = MobileScreen.ScreenName.InviteFriends))
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
index cbe531ea71..a08298e402 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
@@ -119,17 +119,19 @@ class HomeActivityViewModel @AssistedInject constructor(
}
private fun observeReleaseNotes() = withState { state ->
- // we don't want to show release notes for new users or after relogin
- if (state.authenticationDescription == null && vectorPreferences.isNewAppLayoutEnabled()) {
- releaseNotesPreferencesStore.appLayoutOnboardingShown.onEach { isAppLayoutOnboardingShown ->
- if (!isAppLayoutOnboardingShown) {
- _viewEvents.post(HomeActivityViewEvents.ShowReleaseNotes)
+ if (vectorPreferences.isNewAppLayoutEnabled()) {
+ // we don't want to show release notes for new users or after relogin
+ if (state.authenticationDescription == null) {
+ releaseNotesPreferencesStore.appLayoutOnboardingShown.onEach { isAppLayoutOnboardingShown ->
+ if (!isAppLayoutOnboardingShown) {
+ _viewEvents.post(HomeActivityViewEvents.ShowReleaseNotes)
+ }
+ }.launchIn(viewModelScope)
+ } else {
+ // we assume that users which came from auth flow either have seen updates already (relogin) or don't need them (new user)
+ viewModelScope.launch {
+ releaseNotesPreferencesStore.setAppLayoutOnboardingShown(true)
}
- }.launchIn(viewModelScope)
- } else {
- // we assume that users which came from auth flow either have seen updates already (relogin) or don't need them (new user)
- viewModelScope.launch {
- releaseNotesPreferencesStore.setAppLayoutOnboardingShown(true)
}
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt
index 3af849e965..399d5e0abe 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt
@@ -51,7 +51,7 @@ sealed class RoomDetailViewEvents : VectorViewEvents {
object OpenRoomProfile : RoomDetailViewEvents()
data class ShowRoomAvatarFullScreen(val matrixItem: MatrixItem?, val view: View?) : RoomDetailViewEvents()
- object ShowWaitingView : RoomDetailViewEvents()
+ data class ShowWaitingView(val text: String? = null) : RoomDetailViewEvents()
object HideWaitingView : RoomDetailViewEvents()
data class DownloadFileState(
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
index 8b6429abb1..5eb90dde4b 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
@@ -493,7 +493,7 @@ class TimelineFragment :
is RoomDetailViewEvents.ShowInfoOkDialog -> showDialogWithMessage(it.message)
is RoomDetailViewEvents.JoinJitsiConference -> joinJitsiRoom(it.widget, it.withVideo)
RoomDetailViewEvents.LeaveJitsiConference -> leaveJitsiConference()
- RoomDetailViewEvents.ShowWaitingView -> vectorBaseActivity.showWaitingView()
+ is RoomDetailViewEvents.ShowWaitingView -> vectorBaseActivity.showWaitingView(it.text)
RoomDetailViewEvents.HideWaitingView -> vectorBaseActivity.hideWaitingView()
is RoomDetailViewEvents.RequestNativeWidgetPermission -> requestNativeWidgetPermission(it)
is RoomDetailViewEvents.OpenRoom -> handleOpenRoom(it)
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt
index 535a949cd3..02dd2604e1 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt
@@ -39,6 +39,7 @@ import im.vector.app.core.utils.BehaviorDataSource
import im.vector.app.features.analytics.AnalyticsTracker
import im.vector.app.features.analytics.DecryptionFailureTracker
import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom
+import im.vector.app.features.analytics.plan.CreatedRoom
import im.vector.app.features.analytics.plan.JoinedRoom
import im.vector.app.features.call.conference.ConferenceEvent
import im.vector.app.features.call.conference.JitsiActiveConferenceHolder
@@ -78,12 +79,12 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixPatterns
+import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.extensions.tryOrNull
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.Event
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.LocalEcho
import org.matrix.android.sdk.api.session.events.model.RelationType
@@ -100,9 +101,11 @@ import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.api.session.room.location.UpdateLiveLocationShareResult
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
+import org.matrix.android.sdk.api.session.room.model.LocalRoomCreationState
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary
+import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
import org.matrix.android.sdk.api.session.room.model.tombstone.RoomTombstoneContent
@@ -185,6 +188,7 @@ class TimelineViewModel @AssistedInject constructor(
init {
// This method will take care of a null room to update the state.
observeRoomSummary()
+ observeLocalRoomSummary()
if (room == null) {
timeline = null
} else {
@@ -617,7 +621,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleAddJitsiConference(action: RoomDetailAction.AddJitsiWidget) {
- _viewEvents.post(RoomDetailViewEvents.ShowWaitingView)
+ _viewEvents.post(RoomDetailViewEvents.ShowWaitingView())
viewModelScope.launch(Dispatchers.IO) {
try {
val widget = jitsiService.createJitsiWidget(initialState.roomId, action.withVideo)
@@ -637,7 +641,7 @@ class TimelineViewModel @AssistedInject constructor(
if (isJitsiWidget) {
setState { copy(jitsiState = jitsiState.copy(deleteWidgetInProgress = true)) }
} else {
- _viewEvents.post(RoomDetailViewEvents.ShowWaitingView)
+ _viewEvents.post(RoomDetailViewEvents.ShowWaitingView())
}
session.widgetService().destroyRoomWidget(initialState.roomId, widgetId)
// local echo
@@ -1231,6 +1235,32 @@ class TimelineViewModel @AssistedInject constructor(
}
}
+ private fun observeLocalRoomSummary() {
+ if (room != null && RoomLocalEcho.isLocalEchoId(room.roomId)) {
+ room.flow().liveLocalRoomSummary()
+ .unwrap()
+ .map { it.creationState }
+ .distinctUntilChanged()
+ .onEach { creationState ->
+ when (creationState) {
+ LocalRoomCreationState.NOT_CREATED -> Unit
+ LocalRoomCreationState.CREATING ->
+ _viewEvents.post(RoomDetailViewEvents.ShowWaitingView(stringProvider.getString(R.string.creating_direct_room)))
+ LocalRoomCreationState.FAILURE -> {
+ _viewEvents.post(RoomDetailViewEvents.HideWaitingView)
+ }
+ LocalRoomCreationState.CREATED -> {
+ room.localRoomSummary()?.let {
+ analyticsTracker.capture(CreatedRoom(isDM = it.roomSummary?.isDirect.orFalse()))
+ _viewEvents.post(RoomDetailViewEvents.OpenRoom(it.replacementRoomId!!, true))
+ }
+ }
+ }
+ }
+ .launchIn(viewModelScope)
+ }
+ }
+
private fun getUnreadState() {
if (room == null) return
combine(
@@ -1322,26 +1352,11 @@ class TimelineViewModel @AssistedInject constructor(
}
}
room.getStateEvent(EventType.STATE_ROOM_TOMBSTONE, QueryStringValue.IsEmpty)?.also {
- onRoomTombstoneUpdated(it)
+ setState { copy(tombstoneEvent = it) }
}
}
}
- private var roomTombstoneHandled = false
- private fun onRoomTombstoneUpdated(tombstoneEvent: Event) = withState { state ->
- if (roomTombstoneHandled) return@withState
- if (state.isLocalRoom()) {
- // Local room has been replaced, so navigate to the new room
- val roomId = tombstoneEvent.getClearContent()?.toModel()
- ?.replacementRoomId
- ?: return@withState
- _viewEvents.post(RoomDetailViewEvents.OpenRoom(roomId, closeCurrentRoom = true))
- roomTombstoneHandled = true
- } else {
- setState { copy(tombstoneEvent = tombstoneEvent) }
- }
- }
-
/**
* Navigates to the appropriate event (by paginating the thread timeline until the event is found
* in the snapshot. The main reason for this function is to support the /relations api
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListAction.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListAction.kt
index e6b6b34503..aa982741f7 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListAction.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListAction.kt
@@ -31,4 +31,5 @@ sealed class RoomListAction : VectorViewModelAction {
data class LeaveRoom(val roomId: String) : RoomListAction()
data class JoinSuggestedRoom(val roomId: String, val viaServers: List?) : RoomListAction()
data class ShowRoomDetails(val roomId: String, val viaServers: List?) : RoomListAction()
+ object DeleteAllLocalRoom : RoomListAction()
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt
index 2c876273ea..9591048725 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt
@@ -149,10 +149,13 @@ class RoomListFragment :
(it.contentEpoxyController as? RoomSummaryPagedController)?.roomChangeMembershipStates = ms
}
}
- roomListViewModel.onEach(RoomListViewState::localRoomIds) {
- // Local rooms should not exist anymore when the room list is shown
- roomListViewModel.deleteLocalRooms(it)
- }
+ }
+
+ override fun onStart() {
+ super.onStart()
+
+ // Local rooms should not exist anymore when the room list is shown
+ roomListViewModel.handle(RoomListAction.DeleteAllLocalRoom)
}
private fun refreshCollapseStates() {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt
index 8283447a4d..74b55d435d 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt
@@ -97,7 +97,6 @@ class RoomListViewModel @AssistedInject constructor(
init {
observeMembershipChanges()
- observeLocalRooms()
spaceStateHandler.getSelectedSpaceFlow()
.distinctUntilChanged()
@@ -125,16 +124,6 @@ class RoomListViewModel @AssistedInject constructor(
}
}
- private fun observeLocalRooms() {
- session
- .flow()
- .liveRoomSummaries(roomSummaryQueryParams {
- roomId = QueryStringValue.Contains(RoomLocalEcho.PREFIX)
- })
- .map { page -> page.map { it.roomId } }
- .setOnEach { copy(localRoomIds = it) }
- }
-
companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory()
private val roomListSectionBuilder = RoomListSectionBuilder(
@@ -166,6 +155,7 @@ class RoomListViewModel @AssistedInject constructor(
is RoomListAction.ToggleSection -> handleToggleSection(action.section)
is RoomListAction.JoinSuggestedRoom -> handleJoinSuggestedRoom(action)
is RoomListAction.ShowRoomDetails -> handleShowRoomDetails(action)
+ RoomListAction.DeleteAllLocalRoom -> handleDeleteLocalRooms()
}
}
@@ -173,14 +163,6 @@ class RoomListViewModel @AssistedInject constructor(
return session.getRoom(roomId)?.stateService()?.isPublic().orFalse()
}
- fun deleteLocalRooms(roomsIds: Iterable) {
- viewModelScope.launch {
- roomsIds.forEach {
- session.roomService().deleteLocalRoom(it)
- }
- }
- }
-
// PRIVATE METHODS *****************************************************************************
private fun handleSelectRoom(action: RoomListAction.SelectRoom) = withState {
@@ -338,4 +320,16 @@ class RoomListViewModel @AssistedInject constructor(
_viewEvents.post(value)
}
}
+
+ private fun handleDeleteLocalRooms() {
+ val localRoomIds = session.roomService()
+ .getRoomSummaries(roomSummaryQueryParams { roomId = QueryStringValue.Contains(RoomLocalEcho.PREFIX) })
+ .map { it.roomId }
+
+ viewModelScope.launch {
+ localRoomIds.forEach {
+ session.roomService().deleteLocalRoom(it)
+ }
+ }
+ }
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewState.kt
index 5f62cba948..d897225fd6 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewState.kt
@@ -31,7 +31,6 @@ data class RoomListViewState(
val asyncSuggestedRooms: Async> = Uninitialized,
val currentUserName: String? = null,
val asyncSelectedSpace: Async = Uninitialized,
- val localRoomIds: List = emptyList()
) : MavericksState {
constructor(args: RoomListParams) : this(displayMode = args.displayMode)
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItem.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItem.kt
index 58ae6520cf..e6d162e8c3 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItem.kt
@@ -103,6 +103,9 @@ abstract class RoomSummaryItem : VectorEpoxyModel(R.layo
@EpoxyAttribute
var showSelected: Boolean = false
+ @EpoxyAttribute
+ var useSingleLineForLastEvent: Boolean = false
+
override fun bind(holder: Holder) {
super.bind(holder)
@@ -122,6 +125,10 @@ abstract class RoomSummaryItem : VectorEpoxyModel(R.layo
holder.roomAvatarFailSendingImageView.isVisible = hasFailedSending
renderSelection(holder, showSelected)
holder.roomAvatarPresenceImageView.render(showPresence, userPresence)
+
+ if (useSingleLineForLastEvent) {
+ holder.subtitleView.setLines(1)
+ }
}
private fun renderDisplayMode(holder: Holder) = when (displayMode) {
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 85879e6807..290b66e576 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
@@ -51,7 +51,8 @@ class RoomSummaryItemFactory @Inject constructor(
roomChangeMembershipStates: Map,
selectedRoomIds: Set,
displayMode: RoomListDisplayMode,
- listener: RoomListListener?
+ listener: RoomListListener?,
+ singleLineLastEvent: Boolean = false
): VectorEpoxyModel<*> {
return when (roomSummary.membership) {
Membership.INVITE -> {
@@ -59,7 +60,7 @@ class RoomSummaryItemFactory @Inject constructor(
createInvitationItem(roomSummary, changeMembershipState, listener)
}
else -> createRoomItem(
- roomSummary, selectedRoomIds, displayMode, listener?.let { it::onRoomClicked }, listener?.let { it::onRoomLongClicked }
+ roomSummary, selectedRoomIds, displayMode, singleLineLastEvent, listener?.let { it::onRoomClicked }, listener?.let { it::onRoomLongClicked }
)
}
}
@@ -118,8 +119,9 @@ class RoomSummaryItemFactory @Inject constructor(
roomSummary: RoomSummary,
selectedRoomIds: Set,
displayMode: RoomListDisplayMode,
+ singleLineLastEvent: Boolean,
onClick: ((RoomSummary) -> Unit)?,
- onLongClick: ((RoomSummary) -> Boolean)?
+ onLongClick: ((RoomSummary) -> Boolean)?,
): VectorEpoxyModel<*> {
val subtitle = getSearchResultSubtitle(roomSummary)
val unreadCount = roomSummary.notificationCount
@@ -140,7 +142,7 @@ class RoomSummaryItemFactory @Inject constructor(
} else {
createRoomSummaryItem(
roomSummary, displayMode, subtitle, latestEventTime, typingMessage,
- latestFormattedEvent, showHighlighted, showSelected, unreadCount, onClick, onLongClick
+ latestFormattedEvent, showHighlighted, showSelected, unreadCount, singleLineLastEvent, onClick, onLongClick
)
}
}
@@ -155,6 +157,7 @@ class RoomSummaryItemFactory @Inject constructor(
showHighlighted: Boolean,
showSelected: Boolean,
unreadCount: Int,
+ singleLineLastEvent: Boolean,
onClick: ((RoomSummary) -> Unit)?,
onLongClick: ((RoomSummary) -> Boolean)?
) = RoomSummaryItem_()
@@ -177,6 +180,7 @@ class RoomSummaryItemFactory @Inject constructor(
.unreadNotificationCount(unreadCount)
.hasUnreadMessage(roomSummary.hasUnreadMessages)
.hasDraft(roomSummary.userDrafts.isNotEmpty())
+ .useSingleLineForLastEvent(singleLineLastEvent)
.itemLongClickListener { _ -> onLongClick?.invoke(roomSummary) ?: false }
.itemClickListener { onClick?.invoke(roomSummary) }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemPlaceHolder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemPlaceHolder.kt
index d4683f78a5..df191bc2ec 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemPlaceHolder.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemPlaceHolder.kt
@@ -16,6 +16,8 @@
package im.vector.app.features.home.room.list
+import android.widget.TextView
+import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.app.R
import im.vector.app.core.epoxy.VectorEpoxyHolder
@@ -23,5 +25,18 @@ import im.vector.app.core.epoxy.VectorEpoxyModel
@EpoxyModelClass
abstract class RoomSummaryItemPlaceHolder : VectorEpoxyModel(R.layout.item_room_placeholder) {
- class Holder : VectorEpoxyHolder()
+
+ @EpoxyAttribute
+ var useSingleLineForLastEvent: Boolean = false
+
+ override fun bind(holder: Holder) {
+ super.bind(holder)
+ if (useSingleLineForLastEvent) {
+ holder.subtitleView.setLines(1)
+ }
+ }
+
+ class Holder : VectorEpoxyHolder() {
+ val subtitleView by bind(R.id.subtitleView)
+ }
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryListController.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryListController.kt
index 2eb8921fd5..a2b6ed51d9 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryListController.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryListController.kt
@@ -17,18 +17,26 @@
package im.vector.app.features.home.room.list
import im.vector.app.features.home.RoomListDisplayMode
+import im.vector.app.features.settings.FontScalePreferences
import org.matrix.android.sdk.api.session.room.model.RoomSummary
class RoomSummaryListController(
private val roomSummaryItemFactory: RoomSummaryItemFactory,
- private val displayMode: RoomListDisplayMode
+ private val displayMode: RoomListDisplayMode,
+ fontScalePreferences: FontScalePreferences
) : CollapsableTypedEpoxyController>() {
var listener: RoomListListener? = null
+ private val shouldUseSingleLine: Boolean
+
+ init {
+ val fontScale = fontScalePreferences.getResolvedFontScaleValue()
+ shouldUseSingleLine = fontScale.scale > FontScalePreferences.SCALE_LARGE
+ }
override fun buildModels(data: List?) {
data?.forEach {
- add(roomSummaryItemFactory.create(it, emptyMap(), emptySet(), displayMode, listener))
+ add(roomSummaryItemFactory.create(it, emptyMap(), emptySet(), displayMode, listener, shouldUseSingleLine))
}
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryPagedController.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryPagedController.kt
index 445438eec9..10d7ef425c 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryPagedController.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryPagedController.kt
@@ -20,18 +20,26 @@ import com.airbnb.epoxy.EpoxyModel
import com.airbnb.epoxy.paging.PagedListEpoxyController
import im.vector.app.core.utils.createUIHandler
import im.vector.app.features.home.RoomListDisplayMode
+import im.vector.app.features.settings.FontScalePreferences
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.model.RoomSummary
class RoomSummaryPagedController(
private val roomSummaryItemFactory: RoomSummaryItemFactory,
- private val displayMode: RoomListDisplayMode
+ private val displayMode: RoomListDisplayMode,
+ fontScalePreferences: FontScalePreferences
) : PagedListEpoxyController(
// Important it must match the PageList builder notify Looper
modelBuildingHandler = createUIHandler()
), CollapsableControllerExtension {
var listener: RoomListListener? = null
+ private val shouldUseSingleLine: Boolean
+
+ init {
+ val fontScale = fontScalePreferences.getResolvedFontScaleValue()
+ shouldUseSingleLine = fontScale.scale > FontScalePreferences.SCALE_LARGE
+ }
var roomChangeMembershipStates: Map? = null
set(value) {
@@ -57,8 +65,14 @@ class RoomSummaryPagedController(
}
override fun buildItemModel(currentPosition: Int, item: RoomSummary?): EpoxyModel<*> {
- // for place holder if enabled
- item ?: return RoomSummaryItemPlaceHolder_().apply { id(currentPosition) }
- return roomSummaryItemFactory.create(item, roomChangeMembershipStates.orEmpty(), emptySet(), displayMode, listener)
+ return if (item == null) {
+ val host = this
+ RoomSummaryItemPlaceHolder_().apply {
+ id(currentPosition)
+ useSingleLineForLastEvent(host.shouldUseSingleLine)
+ }
+ } else {
+ roomSummaryItemFactory.create(item, roomChangeMembershipStates.orEmpty(), emptySet(), displayMode, listener, shouldUseSingleLine)
+ }
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryPagedControllerFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryPagedControllerFactory.kt
index f72698048d..c5edd9c063 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryPagedControllerFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryPagedControllerFactory.kt
@@ -17,18 +17,20 @@
package im.vector.app.features.home.room.list
import im.vector.app.features.home.RoomListDisplayMode
+import im.vector.app.features.settings.FontScalePreferences
import javax.inject.Inject
class RoomSummaryPagedControllerFactory @Inject constructor(
- private val roomSummaryItemFactory: RoomSummaryItemFactory
+ private val roomSummaryItemFactory: RoomSummaryItemFactory,
+ private val fontScalePreferences: FontScalePreferences
) {
fun createRoomSummaryPagedController(displayMode: RoomListDisplayMode): RoomSummaryPagedController {
- return RoomSummaryPagedController(roomSummaryItemFactory, displayMode)
+ return RoomSummaryPagedController(roomSummaryItemFactory, displayMode, fontScalePreferences)
}
fun createRoomSummaryListController(displayMode: RoomListDisplayMode): RoomSummaryListController {
- return RoomSummaryListController(roomSummaryItemFactory, displayMode)
+ return RoomSummaryListController(roomSummaryItemFactory, displayMode, fontScalePreferences)
}
fun createSuggestedRoomListController(): SuggestedRoomListController {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeFilteredRoomsController.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeFilteredRoomsController.kt
index ae0f9d328f..2b4a514750 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeFilteredRoomsController.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeFilteredRoomsController.kt
@@ -16,6 +16,7 @@
package im.vector.app.features.home.room.list.home
+import androidx.paging.PagedList
import com.airbnb.epoxy.EpoxyModel
import com.airbnb.epoxy.paging.PagedListEpoxyController
import im.vector.app.core.platform.StateView
@@ -24,12 +25,14 @@ import im.vector.app.features.home.RoomListDisplayMode
import im.vector.app.features.home.room.list.RoomListListener
import im.vector.app.features.home.room.list.RoomSummaryItemFactory
import im.vector.app.features.home.room.list.RoomSummaryItemPlaceHolder_
+import im.vector.app.features.settings.FontScalePreferences
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import javax.inject.Inject
class HomeFilteredRoomsController @Inject constructor(
private val roomSummaryItemFactory: RoomSummaryItemFactory,
+ fontScalePreferences: FontScalePreferences
) : PagedListEpoxyController(
// Important it must match the PageList builder notify Looper
modelBuildingHandler = createUIHandler()
@@ -47,6 +50,13 @@ class HomeFilteredRoomsController @Inject constructor(
private var emptyStateData: StateView.State.Empty? = null
private var currentState: StateView.State = StateView.State.Content
+ private val shouldUseSingleLine: Boolean
+
+ init {
+ val fontScale = fontScalePreferences.getResolvedFontScaleValue()
+ shouldUseSingleLine = fontScale.scale > FontScalePreferences.SCALE_LARGE
+ }
+
override fun addModels(models: List>) {
if (models.isEmpty() && emptyStateData != null) {
emptyStateData?.let { emptyState ->
@@ -66,8 +76,22 @@ class HomeFilteredRoomsController @Inject constructor(
this.emptyStateData = state
}
+ fun submitPagedList(newList: PagedList) {
+ submitList(newList)
+ if (newList.isEmpty()) {
+ requestForcedModelBuild()
+ }
+ }
+
override fun buildItemModel(currentPosition: Int, item: RoomSummary?): EpoxyModel<*> {
- item ?: return RoomSummaryItemPlaceHolder_().apply { id(currentPosition) }
- return roomSummaryItemFactory.create(item, roomChangeMembershipStates.orEmpty(), emptySet(), RoomListDisplayMode.ROOMS, listener)
+ return if (item == null) {
+ val host = this
+ RoomSummaryItemPlaceHolder_().apply {
+ id(currentPosition)
+ useSingleLineForLastEvent(host.shouldUseSingleLine)
+ }
+ } else {
+ roomSummaryItemFactory.create(item, roomChangeMembershipStates.orEmpty(), emptySet(), RoomListDisplayMode.ROOMS, listener, shouldUseSingleLine)
+ }
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListAction.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListAction.kt
index b7ade559da..5760874812 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListAction.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListAction.kt
@@ -27,4 +27,5 @@ sealed class HomeRoomListAction : VectorViewModelAction {
data class ToggleTag(val roomId: String, val tag: String) : HomeRoomListAction()
data class LeaveRoom(val roomId: String) : HomeRoomListAction()
data class ChangeRoomFilter(val filter: HomeRoomFilter) : HomeRoomListAction()
+ object DeleteAllLocalRoom : HomeRoomListAction()
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt
index 4ae2c7d514..9b8a686f37 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt
@@ -24,7 +24,6 @@ import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
import com.airbnb.epoxy.OnModelBuildFinishedListener
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
@@ -36,6 +35,7 @@ import im.vector.app.core.extensions.cleanup
import im.vector.app.core.platform.StateView
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.resources.UserPreferencesProvider
+import im.vector.app.core.utils.FirstItemUpdatedObserver
import im.vector.app.databinding.FragmentRoomListBinding
import im.vector.app.features.analytics.plan.ViewRoom
import im.vector.app.features.home.room.list.RoomListAnimator
@@ -66,6 +66,7 @@ class HomeRoomListFragment :
private val roomListViewModel: HomeRoomListViewModel by fragmentViewModel()
private lateinit var sharedQuickActionsViewModel: RoomListQuickActionsSharedActionViewModel
private var concatAdapter = ConcatAdapter()
+ private lateinit var firstItemObserver: FirstItemUpdatedObserver
private var modelBuildListener: OnModelBuildFinishedListener? = null
private lateinit var stateRestorer: LayoutManagerStateRestorer
@@ -82,6 +83,13 @@ class HomeRoomListFragment :
setupRecyclerView()
}
+ override fun onStart() {
+ super.onStart()
+
+ // Local rooms should not exist anymore when the room list is shown
+ roomListViewModel.handle(HomeRoomListAction.DeleteAllLocalRoom)
+ }
+
private fun setupObservers() {
sharedQuickActionsViewModel = activityViewModelProvider[RoomListQuickActionsSharedActionViewModel::class.java]
sharedQuickActionsViewModel
@@ -130,6 +138,9 @@ class HomeRoomListFragment :
private fun setupRecyclerView() {
val layoutManager = LinearLayoutManager(context)
+ firstItemObserver = FirstItemUpdatedObserver(layoutManager) {
+ layoutManager.scrollToPosition(0)
+ }
stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
views.roomListView.layoutManager = layoutManager
views.roomListView.itemAnimator = RoomListAnimator()
@@ -141,10 +152,10 @@ class HomeRoomListFragment :
headersController.submitData(it)
}
- roomListViewModel.onEach(HomeRoomListViewState::roomsLivePagedList) { roomsListLive ->
- roomsListLive?.observe(viewLifecycleOwner) { roomsList ->
- roomsController.submitList(roomsList)
- if (roomsList.isEmpty()) {
+ roomListViewModel.onEach(HomeRoomListViewState::roomsPagedList) { roomsList ->
+ roomsList?.let {
+ roomsController.submitPagedList(it)
+ if (it.isEmpty()) {
roomsController.requestForcedModelBuild()
}
}
@@ -158,14 +169,7 @@ class HomeRoomListFragment :
views.roomListView.adapter = concatAdapter
- // we need to force scroll when recents/filter tabs are added to make them visible
- concatAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
- override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
- if (positionStart == 0) {
- layoutManager.scrollToPosition(0)
- }
- }
- })
+ concatAdapter.registerAdapterDataObserver(firstItemObserver)
}
override fun invalidate() = withState(roomListViewModel) { state ->
@@ -233,6 +237,8 @@ class HomeRoomListFragment :
roomsController.listener = null
+ concatAdapter.unregisterAdapterDataObserver(firstItemObserver)
+
super.onDestroyView()
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt
index e06815b5fd..ad2656cec1 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt
@@ -17,8 +17,8 @@
package im.vector.app.features.home.room.list.home
import android.widget.ImageView
+import androidx.lifecycle.asFlow
import androidx.paging.PagedList
-import arrow.core.Option
import arrow.core.toOption
import com.airbnb.mvrx.MavericksViewModelFactory
import dagger.assisted.Assisted
@@ -35,6 +35,7 @@ import im.vector.app.core.resources.StringProvider
import im.vector.app.features.displayname.getBestName
import im.vector.app.features.home.room.list.home.header.HomeRoomFilter
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
@@ -49,6 +50,7 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.extensions.orFalse
+import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.query.RoomCategoryFilter
import org.matrix.android.sdk.api.query.RoomTagQueryFilter
import org.matrix.android.sdk.api.query.toActiveSpaceOrNoFilter
@@ -60,12 +62,14 @@ import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomSummary
+import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.state.isPublic
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.api.util.toMatrixItem
import org.matrix.android.sdk.flow.flow
+import java.util.concurrent.CancellationException
class HomeRoomListViewModel @AssistedInject constructor(
@Assisted initialState: HomeRoomListViewState,
@@ -83,7 +87,6 @@ class HomeRoomListViewModel @AssistedInject constructor(
companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory()
- private var roomsFlow: Flow