diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 89a7c466fd..523496e317 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -7,15 +7,6 @@
-
diff --git a/.travis.yml b/.travis.yml
index 85bddac7f3..6e67639284 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,4 @@
-# FTR: Configuration on https://travis-ci.org/vector-im/riotX-android/settings
+# FTR: Configuration on https://travis-ci.org/github/vector-im/element-android/settings
#
# - Build only if .travis.yml is present -> On
# - Limit concurrent jobs -> Off
@@ -8,53 +8,11 @@
# - Auto cancel branch builds -> On
# - Auto cancel pull request builds -> On
-language: android
-jdk: oraclejdk8
sudo: false
notifications:
email: false
-android:
- components:
- # Uncomment the lines below if you want to
- # use the latest revision of Android SDK Tools
- - tools
- - platform-tools
-
- # The BuildTools version used by your project
- - build-tools-29.0.3
-
- # The SDK version used to compile your project
- - android-29
-
-before_cache:
- - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- - rm -fr $HOME/.gradle/caches/*/plugin-resolution/
-
-cache:
- directories:
- - $HOME/.gradle/caches/
- - $HOME/.gradle/wrapper/
- - $HOME/.android/build-cache
-
-# Build with the development SDK
-before_script:
- # Not necessary for the moment
- # - /bin/sh ./set_debug_env.sh
-
-# Just build the project for now
+# Just run a simple script here
script:
- # Build app (assembleGplayRelease assembleFdroidRelease)
- # Build Android test (assembleAndroidTest) (disabled for now)
- # Code quality (lintGplayRelease lintFdroidRelease)
- # Split into two steps because if a task contain Fdroid, PlayService will be disabled
- # Done by Buildkite now: - ./gradlew clean assembleGplayRelease lintGplayRelease --stacktrace
- # Done by Buildkite now: - ./gradlew clean assembleFdroidRelease lintFdroidRelease --stacktrace
- # Run unitary test (Disable for now, see https://travis-ci.org/vector-im/riot-android/builds/502504370)
- # - ./gradlew testGplayReleaseUnitTest --stacktrace
- # Other code quality check
- # Done by Buildkite now: - ./tools/check/check_code_quality.sh
- ./tools/travis/check_pr.sh
- # Check that indonesians file are identical. Due to Android issue, the resource folder must be value-in/, and Weblate export data into value-id/.
- # Done by Buildkite now: - diff ./vector/src/main/res/values-id/strings.xml ./vector/src/main/res/values-in/strings.xml
diff --git a/CHANGES.md b/CHANGES.md
index ae5c24a578..3dda2fcb18 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,4 +1,35 @@
-Changes in Element 1.1.7 (2021-XX-XX)
+Changes in Element 1.1.8 (2021-XX-XX)
+===================================================
+
+Features ✨:
+ -
+
+Improvements 🙌:
+ -
+
+Bugfix 🐛:
+ - Space Invite by link not always displayed for public space (#3345)
+ - Wrong copy in share space bottom sheet (#3346)
+ - Fix a problem with database migration on nightly builds (#3335)
+
+Translations 🗣:
+ -
+
+SDK API changes ⚠️:
+ -
+
+Build 🧱:
+ - Compile with Kotlin 1.5.
+ - Upgrade some dependencies: gradle wrapper, third party lib, etc.
+ - Sign APK with build tools 30.0.3
+
+Test:
+ -
+
+Other changes:
+ - Add documentation on LoginWizard and RegistrationWizard (#3303)
+
+Changes in Element 1.1.7 (2021-05-12)
===================================================
Features ✨:
@@ -12,6 +43,7 @@ Improvements 🙌:
- Improve file too big error detection (#3245)
- User can now select video when selecting Gallery to send attachments to a room
- Add option to record a video from the camera
+ - Add the public icon on the rooms in the room list (#3292)
Bugfix 🐛:
- Message states cosmetic changes (#3007)
@@ -25,9 +57,8 @@ Bugfix 🐛:
- Fix read marker not updating automatically (#3267)
- Sent video does not contains duration (#3272)
- Properly clean the back stack if the user cancel registration when waiting for email validation
-
-Translations 🗣:
- -
+ - Fix read marker visibility/position when filtering some events
+ - Fix user invitation in case of restricted profile api (#3306)
SDK API changes ⚠️:
- RegistrationWizard.createAccount() parameters are now all optional, following Matrix spec (#3205)
@@ -35,9 +66,7 @@ SDK API changes ⚠️:
Build 🧱:
- Upgrade to gradle 7
- https://github.com/Piasy/BigImageViewer is now hosted on mavenCentral()
-
-Test:
- -
+ - Upgrade Realm to version 10.4.0
Other changes:
- New store descriptions
@@ -70,7 +99,7 @@ Changes in Element 1.1.4 (2021-04-09)
Improvements 🙌:
- Split network request `/keys/query` into smaller requests (250 users max) (#2925)
- - Crypto improvement | Bulk send NO_OLM withheld code
+ - Crypto improvement | Bulk send NO_OLM withheld code
- Display the room shield in all room setting screens
- Improve message with Emoji only detection (#3017)
- Picture preview when replying. Also add the image preview in the message detail bottomsheet (#2916)
@@ -629,7 +658,7 @@ Improvements 🙌:
- Sending events is now retried only 3 times, so we avoid blocking the sending queue too long.
- Display warning when fail to send events in room list
- Improve UI of edit role action in member profile
- - Moderation | New screen to display list of banned users in room settings, with unban action
+ - Moderation | New screen to display list of banned users in room settings, with unban action
Bugfix 🐛:
- Fix theme issue on Room directory screen (#1613)
diff --git a/attachment-viewer/build.gradle b/attachment-viewer/build.gradle
index 0ac8ac4a9a..aa35f06767 100644
--- a/attachment-viewer/build.gradle
+++ b/attachment-viewer/build.gradle
@@ -47,7 +47,7 @@ android {
}
dependencies {
- implementation 'com.github.chrisbanes:PhotoView:2.1.4'
+ implementation 'com.github.chrisbanes:PhotoView:2.3.0'
implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
diff --git a/build.gradle b/build.gradle
index 9c9e7a6c20..470e9a06b4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,8 +2,8 @@
buildscript {
// Ref: https://kotlinlang.org/releases.html
- ext.kotlin_version = '1.4.32'
- ext.kotlin_coroutines_version = "1.4.2"
+ ext.kotlin_version = '1.5.0'
+ ext.kotlin_coroutines_version = "1.5.0-RC"
repositories {
google()
jcenter()
@@ -12,10 +12,10 @@ buildscript {
}
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.1.3'
- classpath 'com.google.gms:google-services:4.3.5'
+ classpath 'com.android.tools.build:gradle:4.2.1'
+ classpath 'com.google.gms:google-services:4.3.8'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.1.1'
+ classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.2.0'
classpath 'com.google.android.gms:oss-licenses-plugin:0.10.4'
classpath "com.likethesalad.android:string-reference:1.2.2"
diff --git a/fastlane/metadata/android/cs/changelogs/40101020.txt b/fastlane/metadata/android/cs/changelogs/40101020.txt
new file mode 100644
index 0000000000..5e90e49daa
--- /dev/null
+++ b/fastlane/metadata/android/cs/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: vylepšení výkonnosti a opravy chyb!
+Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/cs/changelogs/40101030.txt b/fastlane/metadata/android/cs/changelogs/40101030.txt
new file mode 100644
index 0000000000..0e624ba6d1
--- /dev/null
+++ b/fastlane/metadata/android/cs/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: vylepšení výkonnosti a opravy chyb!
+Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/cs/changelogs/40101040.txt b/fastlane/metadata/android/cs/changelogs/40101040.txt
new file mode 100644
index 0000000000..1818c92ba8
--- /dev/null
+++ b/fastlane/metadata/android/cs/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: vylepšení výkonnosti a opravy chyb!
+Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/cs/changelogs/40101050.txt b/fastlane/metadata/android/cs/changelogs/40101050.txt
new file mode 100644
index 0000000000..3e33cd8d07
--- /dev/null
+++ b/fastlane/metadata/android/cs/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: nutné opravy pro 1.1.4
+Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/cs/changelogs/40101060.txt b/fastlane/metadata/android/cs/changelogs/40101060.txt
new file mode 100644
index 0000000000..d148a9bc37
--- /dev/null
+++ b/fastlane/metadata/android/cs/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: nutné opravy chyb pro 1.1.5!
+Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/cs/short_description.txt b/fastlane/metadata/android/cs/short_description.txt
index a654a9ea6a..d14ac49efa 100644
--- a/fastlane/metadata/android/cs/short_description.txt
+++ b/fastlane/metadata/android/cs/short_description.txt
@@ -1 +1 @@
-Zabezpečený decentralizovaný chat a VoIP. Uchovejte svá data v bezpečí.
+Skupinový messenger - šifrovaná komunikace, skupinový chat a video hovory
diff --git a/fastlane/metadata/android/cs/title.txt b/fastlane/metadata/android/cs/title.txt
index 76943289ad..2fedfecb15 100644
--- a/fastlane/metadata/android/cs/title.txt
+++ b/fastlane/metadata/android/cs/title.txt
@@ -1 +1 @@
-Element (dříve Riot.im)
+Element - bezpečný messenger
diff --git a/fastlane/metadata/android/de/changelogs/40100110.txt b/fastlane/metadata/android/de/changelogs/40100110.txt
index 24bc6e518c..120f04a3f9 100644
--- a/fastlane/metadata/android/de/changelogs/40100110.txt
+++ b/fastlane/metadata/android/de/changelogs/40100110.txt
@@ -1,2 +1,2 @@
-Diese neue Version enthält hauptsächlich Verbesserungen der Benutzeroberfläche und der Handhabung. Du kannst jetzt ganz schnell Freund*innen einladen und DMs erstellen, indem du schlicht einen QR-Code scannst.
+Diese neue Version enthält hauptsächlich Verbesserungen der Benutzeroberfläche und der Handhabung. Du kannst jetzt ganz schnell Freunde einladen und DMs erstellen, indem du schlicht einen QR-Code scannst.
Vollständige Versionshinweise: https://github.com/vector-im/element-android/releases/tag/v1.0.11
diff --git a/fastlane/metadata/android/de/changelogs/40101040.txt b/fastlane/metadata/android/de/changelogs/40101040.txt
new file mode 100644
index 0000000000..eaa8db1409
--- /dev/null
+++ b/fastlane/metadata/android/de/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Hauptänderungen in dieser Version: Leistungsverbesserung und Fehlerbehebungen!
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/de/changelogs/40101050.txt b/fastlane/metadata/android/de/changelogs/40101050.txt
new file mode 100644
index 0000000000..de6352961a
--- /dev/null
+++ b/fastlane/metadata/android/de/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Hauptänderungen in dieser Version: Wichtige Fehlerbehebungen für 1.1.4!
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/de/changelogs/40101060.txt b/fastlane/metadata/android/de/changelogs/40101060.txt
new file mode 100644
index 0000000000..775c016b3d
--- /dev/null
+++ b/fastlane/metadata/android/de/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Hauptänderungen in dieser Version: Wichtige Fehlerbehebungen für 1.1.5!
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/de/full_description.txt b/fastlane/metadata/android/de/full_description.txt
index 568ae61875..69343cf0e3 100644
--- a/fastlane/metadata/android/de/full_description.txt
+++ b/fastlane/metadata/android/de/full_description.txt
@@ -1,30 +1,39 @@
-Element ist eine neuartige Messaging- und Kollaborationsapp:
+Element ist mehr als ein sicherer Messenger. Es ist ein produktives Kolaborationsapp für das Team und eignet sich ideal für den Gruppenchat beim Arbeiten von zuhause aus. Mit eingebauter Ende-zu-Ende-Verschlüsselung ermöglicht Element umfangreiche und sichere Videokonferenzen, das Teilen von Dokumenten/Dateien und Videoanrufe.
-1. Volle Kontrolle über deine Privatssphäre
-2. Kommuniziere mit jedem aus dem Matrix-Netzwerk und mit der Integration von z.B. Slack sogar über Matrix hinaus
-3. Schutz vor Werbung, Datamining und geschlossenen Platformen
-4. Absicherung durch Ende-zu-Ende-Verschlüsselung, und Cross-Signing um andere zu verifizieren
+Element enthält folgende Funktionen:
+- Fortgeschrittene Werkzeuge für die Online-Kommunikation
+- Vollverschlüsselte Nachrichten um eine sichere Kommunikation innerhalb und außerhalb des Unternehmens zu ermöglichen
+- Dezentralisierte Chats basierend auf das quelloffene Matrix-Framework
+- Sichere und kontrollierte Dateienfreigabe durch verschlüsselte Daten beim verwalten von Projekten
+- Videochats über VoIP und Bildschirmübertragung
+- Einfache Einbindungen mit Ihren favorisierten Online-Kolaborationswerkzeugen, Projektverwaltungswerkzeugen, VoIP-Diensten und andere Kommunikationsapps für Ihren Team
-Element unterscheidet sich durch Dezentralität und Open Source deutlich von anderen Messaging- und Kollaborationsapps.
+Element unterscheidet sich deutlich von anderen Kommunikations- und Kollaborationsapps. Es läuft auf Matrix, ein offenes Netzwerk für eine sichere und dezentralisierte Kommunikation. Es erlaubt den Nutzern ihre eigenen Matrix-Dienste zu betreiben und gibt ihnen damit die vollständige Kontrolle und Besitz über ihre eigenen Daten und Nachrichten.
-Element ermöglicht es einen eigenen Server zu betreiben - oder einen beliebigen auszuwählen, sodass du nicht nur Privatssphäre gewinnst, sondern auch deine Daten und Konversationen in deiner Hand sind und du sie kontrollieren kannst. Du hast Zugriff auf ein offenes Netzwerk, und kannst daher nicht nur mit Element-Nutzern schreiben. Und es ist sehr sicher.
+Privatsphäre/Datenschutz und verschlüsselte Kommunikation
+Element schützt Ihnen vor unerwünschte Werbung, das Datenschürfen und geschlossene unentkommbare Dienste. Auch schützt es all Ihre Daten, Video und Sprachkommunikation unter vier Augen durch Ende-zu-Ende-Verschlüsselung und das Quersignieren von Geräten zur Verifizierung.
-Element ist zu all diesem in der Lage, weil es Matrix nutzt - einen Standard für offene, dezentrale Kommunikation.
+Element gibt Ihnen die Kontrolle über Ihre Privatsphäre, während es Ihnen ermöglicht mit jeden auf dem Matrix-Netzwerk oder andere geschäftliche Kollaborationswerkzeuge durch das Einbinden von Apps wie Slack sicher zu kommunizieren.
-Element gibt dir die Kontrolle, indem es dir die Wahl darüber lässt, wer deine Konversationen hostet. In der Element-App kannst du zwischen verschiedenen Möglichkeiten auswählen:
+Element kann man selber betreiben
+Um mehr Kontrolle über Ihre sensiblen Daten und Konversationen zu ermöglichen, kann man Element selbst betreiben oder Sie wählen irgendeinen Matrix-basierten Dienst - der standard für quelloffene, dezentralisierte Kommunikation. Element gibt Ihnen Privatsphäre, Sicherheitskonformität und die Flexibilität zum Integrieren.
+Besitzen Sie Ihre Daten
+Sie entscheiden wo Sie Ihre Daten und Nachrichten aufbewahren, ohne das Risiko des Datenschürfens oder des Zugriffes Dritter.
+
+Element gibt Ihnen die Kontrolle durch verschiedene Wege:
1. Kostenlos auf dem öffentlichen matrix.org Server registrieren, der von den Matrix-Entwicklern gehostet wird, oder wähle aus Tausenden von öffentlichen Servern, die von Freiwilligen gehostet werden
-2. Einen Konto auf einem eigenen Server auf eigener Hardware betreiben
+2. Einen Konto auf einem eigenen Server in der eigenen IT-Infrastruktur betreiben
3. Einen Konto auf einem benutzerdefinierten Server erstellen, zum Beispiel durch ein Abonnement bei Element Matrix Services (kurz EMS)
-Wieso Element nutzen?
+Offene Kommunikation und Zusammenarbeit
+Sie können mit jeden auf dem Matrix-Netzwerk chatten, egal ob sie Element, eine Matrix-App oder sogar eine andere Kommunikationsapp nutzen.
-BESITZE DEINE DATEN: Du entscheidest wo deine Daten und Nachrichten gespeichert werden. Du besitzt und kontrollierst sie, anstatt ein Großkonzern, der deine Daten analysiert und Dritten Zugriff gibt.
+Super sicher
+Reale Ende-zu-Ende-Verschlüsselung (nur die Personen in der Konversation können die Nachricht entschüsseln) und Quersignierung von Geräten zur Verifizierung.
-OFFENE KOMMUNIKATION UND KOLLABORATION: Du kannst mit jedem im Matrix-Netzwerk schreiben, ob sie nun Element oder eine andere Matrix-App nutzen, oder gar ein anderes Kommunikationssystem wie z.B. Slack, IRC oder XMPP.
+Vollständige Kommunikation und Integration
+Kurznachrichten, Sprach- und Videoanrufe, kontrollierte Dateifreigaben, Bildschirmübertragungen und eine ganze Reihe an Integrationen, Bots and Widgets. Schaffe Räume, Gemeinschaften, bleibe auf dem Laufenden und erledige Sachen.
-SUPER SICHER: Echte Ende-zu-Ende-Verschlüsselung (nur Personen in der Konversation können die Nachrichten entschlüsseln), und Cross-Signing um die Geräte der anderen Personen zu verifizieren.
-
-VOLLSTÄNDIGE KOMMUNIKATION: Nachrichten, Telefonate und Videoanrufe, Teilen von Dateien oder dem eigenen Bildschirm und viele andere Integrationen, Bots und Widgets. Erstelle Räume, Communities, bleib in Kontakt und sei produktiv.
-
-ÜBERALL WO DU BIST: Bleib in Kontakt wo auch immer du bist - mit einem vollständig synchronisierten Nachrichtenverlauf über alle Geräte und im Netz auf https://app.element.io.
+Das Stehengelassene später wieder aufgreifen
+Bleibe auf dem Laufenden, egal wo Sie sind, mit vollständig synchronisierter Nachrichtenverlauf quer über all Ihrer Geräte und im Netz auf https://app.element.io
diff --git a/fastlane/metadata/android/de/short_description.txt b/fastlane/metadata/android/de/short_description.txt
index d2c30d4167..d27bd3ef12 100644
--- a/fastlane/metadata/android/de/short_description.txt
+++ b/fastlane/metadata/android/de/short_description.txt
@@ -1 +1 @@
-Sicherer dezentraler Chat und Telefonie. Schütze deine Daten vor Dritten.
+Gruppen-Messenger - verschlüsselte Kommunikation, Gruppenchat und Videoanrufe
diff --git a/fastlane/metadata/android/de/title.txt b/fastlane/metadata/android/de/title.txt
index ec25e8a631..6304f37925 100644
--- a/fastlane/metadata/android/de/title.txt
+++ b/fastlane/metadata/android/de/title.txt
@@ -1 +1 @@
-Element (zuvor Riot.im)
+Element - Sicherer Messenger
diff --git a/fastlane/metadata/android/en-US/changelogs/40101070.txt b/fastlane/metadata/android/en-US/changelogs/40101070.txt
new file mode 100644
index 0000000000..254e4c0f62
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40101070.txt
@@ -0,0 +1,2 @@
+Main changes in this version: beta support for Spaces. Compress video before sending.
+Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.1.7
\ No newline at end of file
diff --git a/fastlane/metadata/android/et/changelogs/40101040.txt b/fastlane/metadata/android/et/changelogs/40101040.txt
new file mode 100644
index 0000000000..2e7849db9e
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: jõudluse parandused ja pisikohendused.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/et/changelogs/40101050.txt b/fastlane/metadata/android/et/changelogs/40101050.txt
new file mode 100644
index 0000000000..9aa2f4e10c
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: kiirparandused versioon 1.1.4 jaoks.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/et/changelogs/40101060.txt b/fastlane/metadata/android/et/changelogs/40101060.txt
new file mode 100644
index 0000000000..0577bf452d
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: kiirparandused versioon 1.1.5 jaoks.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/et/full_description.txt b/fastlane/metadata/android/et/full_description.txt
index 7c7f7195a8..ee0adef9ac 100644
--- a/fastlane/metadata/android/et/full_description.txt
+++ b/fastlane/metadata/android/et/full_description.txt
@@ -1,30 +1,39 @@
-Element on uut tüüpi suhtlus- ja koostöörakendus, mis:
+Element on nii suhtlus- ja koostöörakendus, mis sobib ideaalselt rühmavestlusteks kaugtöö ajal. Läbiv krüptimine on kasutusel sõnumivahetuseks, videokõnedeks, häälkõnedeks ja failide jagamiseks.
-1. Võimaldab täielikku kontrolli privaatsuse üle
-2. Võimaldab suhelda kõigiga Matrixi võrgus ja isegi väljaspool seda, olles integreeritud selliste rakendustega nagu Slack
-3. Kaitseb sind reklaamide ja andmekogumise eest
-4. Tagab turvalisuse läbiva krüptimise abil, kasutades risttunnustamist vestlejate tuvastamiseks
+Element pakub muu hulgas selliseid võimalusi
+- moodsad võrgupõhised suhtlusvahendid
+- läbivalt krüptitud sõnumid võimaldavad turvalist suhtlust, sealhulgas kaugtöötajatega
+- Matrix'i protokollil põhinev hajutatud suhtlusvõrk
+- projektide jaoks vajalike failide jagamine turvaliselt ja krüptitult
+- VoIP'i põhised videokõned ja ekraani jagamine
+- lihtne lõimimine harjumispäraste võrgupõhiste koostöövahenditega, projektihalduse rakendustega, VoIP-teenustega ja muude ühistöörakendustega
-Element erineb täielikult teistest sõnumside- ja koostöörakendustest, kuna see on detsentraliseeritud ja avatud lähtekoodiga.
+Element erineb teistest sõnumi- ja koostöörakendustest. Tema aluseks on Matrix - avatud võrk turvalise ja hajutatud suhtluse jaoks.
-Element võimaldab ise hostida - või valida hosti -, et oleks tagatud privaatsus ja kontroll oma andmete ja vestluste üle. Element annab ka juurdepääsu avatud võrgule, nii et te ei pea vaid Elemendi kasutajatega rääkima. Ning kogu süsteem on väga turvaline.
+Privaatsus ja krüptitud sõnumivahetus
+Element tagab, et sa ei ole seotud reklaamidega, andmekogumisega ja suletud süsteemidega. Kasutades läbivat krüptimist ja risttunnustamisel põhinevat verifitseerimist on sinu sõnumid, andmed, kahepoolsed videokõned ja häälkõned turvatud.
-Element töötab Matrixil - avatud, detsentraliseeritud suhtlus-standardil.
+Lubades suhelda turvaliselt ükspuha kellega Matrix'i võrgus või muude ärikeskondades kasutatavate koostöörakendustega nagu Slack, jätab Element sulle kontrolli oma privaatsuse üle.
-Võimaldades valida, kes vestlusi korraldab, annab Element annab kontrolli sinule. Rakendust Element saad kasutada mitmel viisil.
+Võid kasutada Element'i jaoks oma serverid
+Kui vajad suuremat kontrolli oma suhtluse ja andmete üle, siis võid kasutada oma serverit või tellida teenuse ükspuha missuguselt Matrix'i-teenuse pakkujalt. Matrix on standard avatud lähtekoodil põhineva detsentraliseeritud suhtluse jaoks.
-1. Tasuta konto Matrixi arendajate hostitud avalikus serveris matrix.org või vali tuhandete avalike serverite hulgast, mida haldavad vabatahtlikud
-2. Hosti oma kontot ise, paigaldades serveri oma riistvarale
-3. Registreeruge serveris olevale kontole, tellides Element Matrix Services teenuseplatvormi
+Andmed on Sinu omad
+Sina otsustad seda, kus hoiad oma sõnumeid ja andmeid. Ning seejuures puudub andmekaevandamise risk ja ligipääs kolmandatele osapooltele.
- Miks valida element?
+Element annab kontrolli sinule valikuga mitme võimaluse vahel:
+1. tasuta konto Matrix'i arendajate hostitud avalikus serveris matrix.org või vali tuhandete avalike serverite hulgast, mida haldavad vabatahtlikud
+2. hosti oma kontot ise, paigaldades serveri oma IT-taristule
+3. telli tasuline kasutajakonto Element Matrix Services teenuseplatvormilt
- KONTROLL ANDMETE ÜLE: otsustad ise, kus oma andmeid ja sõnumeid hoida. Need kuuluvad sulle ja sinu käes on kontroll, mitte mõne MEGAFIRMA käes, mis andmeid oma kasuks kaevandab või kolmandatele isikutele juurdepääsu annab.
+Avatud suhtlus ja koostöö
+Saad vestelda kõigi teistega Matrix'i võrgus, olenemata sellest, kas nad kasutavad Elementi või mõnda muud Matrixi rakendust ja isegi kui nad kasutavad mõnda teistsugust suhtlussüsteemi.
- AVATUD SUHTLUS JA KOOSTÖÖ : saad vestelda kõigi teistega Matrixi võrgus, olenemata sellest, kas nad kasutavad Elementi või mõnda muud Matrixi rakendust, ja isegi kui nad kasutavad teistsugust suhtlussüsteemi nagu Slack, IRC või XMPP.
+Üliturvaline
+Tõeline läbiv krüptimine (ainult vestluses osalejad saavad sõnumeid lugeda) ja risttunnustamine vestluses osalejate tuvastamiseks.
- ÜLITURVALINE : tõeline läbiv krüptimine (ainult vestluses osalejad saavad sõnumeid lugeda) ja risttunnustamine vestluses osalejate tuvastamiseks.
+Kõik suhtlusvõimalused
+Sõnumid, hääl- ja videokõned, failide jagamine, ekraani jagamine ja terve hulk lõiminguid, roboteid ja vidinaid. Loo tubasid, kogukondi, hoia ühendust ja saa asjad aetud.
- KÕIK SUHTLUSVÕIMALUSED: sõnumid, hääl- ja videokõned, failide jagamine, ekraani jagamine ja terve hulk lõiminguid, roboteid ja vidinaid. Loo tubasid, kogukondi, hoia ühendust ja saa asjad aetud.
-
- KÕIKJAL, KUS VIIBITE: saad suhelda kõigis oma seadmetes ja ka veebis aadressil https://app.element.io ning sealjuures täielikult sünkroonitud sõnumite ajalooga.
+Jätka sealt, kus pooleli jäid
+Saad suhelda kõigis oma seadmetes ja ka veebis aadressil https://app.element.io ning sealjuures täielikult sünkroonitud sõnumite ajalooga.
diff --git a/fastlane/metadata/android/et/short_description.txt b/fastlane/metadata/android/et/short_description.txt
index 4075c1f7cf..5352464a7a 100644
--- a/fastlane/metadata/android/et/short_description.txt
+++ b/fastlane/metadata/android/et/short_description.txt
@@ -1 +1 @@
-Turvalised ning hajutatud vestlused ja VoIP-kõned. Sinu suhtlus on üliturvaline.
+Vestlus- ja koostöörakendus: krüptitud sõnumid, rühmavestlused ja videokõned
diff --git a/fastlane/metadata/android/et/title.txt b/fastlane/metadata/android/et/title.txt
index f74f9ff18f..b0bf39ba23 100644
--- a/fastlane/metadata/android/et/title.txt
+++ b/fastlane/metadata/android/et/title.txt
@@ -1 +1 @@
-Element (varem Riot.im)
+Element - turvaline sõnumiklient
diff --git a/fastlane/metadata/android/fr/changelogs/40101040.txt b/fastlane/metadata/android/fr/changelogs/40101040.txt
new file mode 100644
index 0000000000..0af0cf55d8
--- /dev/null
+++ b/fastlane/metadata/android/fr/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : amélioration des performances et corrections de bugs !
+Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/fr/changelogs/40101050.txt b/fastlane/metadata/android/fr/changelogs/40101050.txt
new file mode 100644
index 0000000000..dd6e8468af
--- /dev/null
+++ b/fastlane/metadata/android/fr/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Corrections de bugs sur la 1.1.4
+Liste de tous les changements : https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/fr/changelogs/40101060.txt b/fastlane/metadata/android/fr/changelogs/40101060.txt
new file mode 100644
index 0000000000..e10a8aa4f3
--- /dev/null
+++ b/fastlane/metadata/android/fr/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Corrections de bugs sur la 1.1.5
+Liste de tous les changements : https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/fr/short_description.txt b/fastlane/metadata/android/fr/short_description.txt
index 2fb9762e97..6d86b77a6b 100644
--- a/fastlane/metadata/android/fr/short_description.txt
+++ b/fastlane/metadata/android/fr/short_description.txt
@@ -1 +1 @@
-Chat & VoIP sûr et décentralisé. Gardez vos données en sécurité.
+Messagerie de groupes - messages chiffrés, groupés et appels vidéos
diff --git a/fastlane/metadata/android/fr/title.txt b/fastlane/metadata/android/fr/title.txt
index 87cbc3b858..9152e92cfa 100644
--- a/fastlane/metadata/android/fr/title.txt
+++ b/fastlane/metadata/android/fr/title.txt
@@ -1 +1 @@
-Element (anciennement Riot.im)
+Element - Messagerie sécurisée
diff --git a/fastlane/metadata/android/fy/changelogs/40100100.txt b/fastlane/metadata/android/fy/changelogs/40100100.txt
new file mode 100644
index 0000000000..dc2eda9234
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40100100.txt
@@ -0,0 +1,2 @@
+Disse nije ferzje bestjit foar in grut diel út breksoplossings en ferbetteringen. Berjochten stjoere giet no in soad flugger.
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.0.10
diff --git a/fastlane/metadata/android/fy/changelogs/40100110.txt b/fastlane/metadata/android/fy/changelogs/40100110.txt
new file mode 100644
index 0000000000..8249b5c409
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40100110.txt
@@ -0,0 +1,2 @@
+Disse nije ferzje bestjit foar in grut diel út brûkersinterfaasje en brûkersûnderfingsferbetteringen. No kinst freonen útnûgje, en gau DM's meitsje troch QR koades te scannen.
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.0.11
diff --git a/fastlane/metadata/android/fy/changelogs/40100120.txt b/fastlane/metadata/android/fy/changelogs/40100120.txt
new file mode 100644
index 0000000000..9605ce2a75
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40100120.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: URL ynsjen, nij emoji toetseboerd, nij keamer ynstellings moochlikheden, en snie foar kryst.
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.0.12
diff --git a/fastlane/metadata/android/fy/changelogs/40100130.txt b/fastlane/metadata/android/fy/changelogs/40100130.txt
new file mode 100644
index 0000000000..ebc7285193
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40100130.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: URL ynsjen, nij emoji toetseboerd, nij keamer ynstellings moochlikheden, en snie foar kryst.
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.0.13
diff --git a/fastlane/metadata/android/fy/changelogs/40100140.txt b/fastlane/metadata/android/fy/changelogs/40100140.txt
new file mode 100644
index 0000000000..6886848889
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40100140.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: Keamer fjochten feroarje, automatysk ljocht/tsjuster tema, en breksferbetteringen.
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.0.14
diff --git a/fastlane/metadata/android/fy/changelogs/40100150.txt b/fastlane/metadata/android/fy/changelogs/40100150.txt
new file mode 100644
index 0000000000..d291da0475
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40100150.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: Stipe foar sosjaal ynlogge!
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.0.15
diff --git a/fastlane/metadata/android/fy/changelogs/40100160.txt b/fastlane/metadata/android/fy/changelogs/40100160.txt
new file mode 100644
index 0000000000..eb2be2d09c
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40100160.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: Stipe foar sosjaal ynlogge!
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.0.15 and https://github.com/vector-im/element-android/releases/tag/v1.0.16
diff --git a/fastlane/metadata/android/fy/changelogs/40100170.txt b/fastlane/metadata/android/fy/changelogs/40100170.txt
new file mode 100644
index 0000000000..281b087584
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40100170.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: Breksoplossings!
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.0.17
diff --git a/fastlane/metadata/android/fy/changelogs/40101000.txt b/fastlane/metadata/android/fy/changelogs/40101000.txt
new file mode 100644
index 0000000000..a860b7b468
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40101000.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: VoIP (lûds en video skilje yn DM) ferbetteringen en breksoplossings!
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.1.0
diff --git a/fastlane/metadata/android/fy/changelogs/40101010.txt b/fastlane/metadata/android/fy/changelogs/40101010.txt
new file mode 100644
index 0000000000..2369fc4d22
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40101010.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: Prestaasje feroaringen en breksoplossings!
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.1.1
diff --git a/fastlane/metadata/android/fy/changelogs/40101020.txt b/fastlane/metadata/android/fy/changelogs/40101020.txt
new file mode 100644
index 0000000000..13aa172071
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: Prestaasje feroaringen en breksoplossings!
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/fastlane/metadata/android/fy/changelogs/40101030.txt b/fastlane/metadata/android/fy/changelogs/40101030.txt
new file mode 100644
index 0000000000..595cbdf104
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: Prestaasje feroaringen en breksoplossings!
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/fastlane/metadata/android/fy/changelogs/40101040.txt b/fastlane/metadata/android/fy/changelogs/40101040.txt
new file mode 100644
index 0000000000..e86e7ce3e3
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: Prestaasje feroaringen en breksoplossings!
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/fy/changelogs/40101050.txt b/fastlane/metadata/android/fy/changelogs/40101050.txt
new file mode 100644
index 0000000000..fdf5f98eb7
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: feroaringen foar 1.1.4
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/fy/changelogs/40101060.txt b/fastlane/metadata/android/fy/changelogs/40101060.txt
new file mode 100644
index 0000000000..47ac5692d5
--- /dev/null
+++ b/fastlane/metadata/android/fy/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Haadferoaring yn disse ferzje: feroaringen foar 1.1.5
+Folsleine feroaringslist: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/fy/short_description.txt b/fastlane/metadata/android/fy/short_description.txt
new file mode 100644
index 0000000000..ddc559b59c
--- /dev/null
+++ b/fastlane/metadata/android/fy/short_description.txt
@@ -0,0 +1 @@
+Groepsberjochtetsjinst - fersifere berjochten, groeps petearen en fideo skilje
diff --git a/fastlane/metadata/android/fy/title.txt b/fastlane/metadata/android/fy/title.txt
new file mode 100644
index 0000000000..c4b5b596fc
--- /dev/null
+++ b/fastlane/metadata/android/fy/title.txt
@@ -0,0 +1 @@
+Element - Feilige Berjochtetsjinst
diff --git a/fastlane/metadata/android/it/changelogs/40101040.txt b/fastlane/metadata/android/it/changelogs/40101040.txt
new file mode 100644
index 0000000000..93aac046a1
--- /dev/null
+++ b/fastlane/metadata/android/it/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: prestazioni migliorate e correzione di errori!
+Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/it/changelogs/40101050.txt b/fastlane/metadata/android/it/changelogs/40101050.txt
new file mode 100644
index 0000000000..7fa5ba20df
--- /dev/null
+++ b/fastlane/metadata/android/it/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: correzioni per la 1.1.4
+Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/it/changelogs/40101060.txt b/fastlane/metadata/android/it/changelogs/40101060.txt
new file mode 100644
index 0000000000..d915bf2d8f
--- /dev/null
+++ b/fastlane/metadata/android/it/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: correzioni per la 1.1.5
+Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/it/full_description.txt b/fastlane/metadata/android/it/full_description.txt
index b6f7cf449c..dd7716ffbf 100644
--- a/fastlane/metadata/android/it/full_description.txt
+++ b/fastlane/metadata/android/it/full_description.txt
@@ -1,30 +1,39 @@
-Element è un nuovo tipo di app di messaggistica e collaborazione che:
+Element è sia un messenger sicuro sia un'app collaborativa per team di produttività, ideale per chat di gruppo durante il lavoro da remoto. Questa app usa una crittografia end-to-end per fornire videoconferenze, condivisione di file e videochiamate.
-1. Ti mette al controllo per preservare la tua privacy
-2. Ti lascia comunicare con chiunque nella rete Matrix e oltre, integrandosi con app come Slack
-3. Ti protegge da pubblicità, raccolta di dati e piattaforme chiuse
-4. Ti protegge con la crittografia end-to-end, con la firma incrociata per verificare gli altri
+Tra le caratteristiche di Element ci sono:
+- Strumenti di comunicazione online avanzati
+- Messaggi totalmente cifrati per consentire comunicazioni aziendali più sicure, anche per i lavoratori remoti
+- Chat decentralizzate basate sull'infrastruttura open source Matrix
+- Condivisione sicura di file con dati crittografati durante la gestione dei progetti
+- Videochiamate con "Voice over IP" e condivisione dello schermo
+- Facile integrazione con i tuoi strumenti collaborativi online preferiti, strumenti di gestione progetti, servizi VoIP ed altre app di messaggistica tra team
-Element è completamente diverso dalle altre app di messaggistica e collaborazione perchè è decentralizzato e open source.
+Element è completamente diverso dalle altre app di messaggistica e collaborazione. Funziona su Matrix, una rete aperta per messaggi sicuri e comunicazioni decentralizzate. Può essere installato in locale per dare agli utenti il pieno possesso e controllo dei propri dati e messaggi.
-Element può essere gestito in locale - o puoi scegliere un host - in modo che tu abbia privacy, possesso e controllo dei tuoi dati e conversazioni. Ti dà accesso ad una rete aperta, quindi non sei limitato a parlare solo con altri utenti Element. Ed è molto sicuro.
+Privacy e messaggi privati
+Element ti protegge da pubblicità indesiderate, dalla raccolta di dati e dalle piattaforme chiuse. Protegge tutti i tuoi dati e comunicazioni uno-ad-uno, attraverso la crittografia end-to-end e la verifica a firma incrociata tra dispositivi.
-Element può fare tutto ciò perchè funziona su Matrix - lo standard per comunicazioni aperte e decentralizzate.
+Element ti dà il controllo della tua privacy consentendoti di comunicazre in modo sicuro con chiunque nella rete di Matrix, o con altri strumenti collaborativi aziendali, integrandosi con app come Slack.
-Element ti mette al controllo lasciandoti scegliere chi gestisce il server delle tue conversazioni. Dall'app Element, hai diverse opzioni:
+Element può essere installato in locale
+Per consentire un maggiore controllo dei tuoi dati sensibili e delle conversazioni, Element può essere gestito in locale o puoi scegliere un qualsiasi host basato su Matrix - lo standard per le comunicazioni open source e decentralizzate. Element ti offre privacy, conformità alla sicurezza e flessibilità di integrazione.
+Possiedi i tuoi dati
+Decidi tu dove tenere i tuoi dati e messaggi. Senza il rischio di raccolta di dati o accessi da terze parti.
+
+Element ti mette al controllo in diversi modi:
1. Crea un account gratuito sul server pubblico matrix.org gestito dagli sviluppatori di Matrix, o scegli tra migliaia di server pubblici gestiti da volontari
-2. Gestisci autonomamente un account installando un server sul tuo hardware
+2. Gestisci autonomamente un account installando un server nella tua infrastruttura informatica
3. Registra un account su un server personalizzato iscrivendoti alla piattaforma Element Matrix Services
-Perchè scegliere Element?
+Messaggistica e collaborazioni aperte
+Puoi chattare con chiunque nella rete Matrix, sia che stiano usando Element, un'altra app Matrix, o anche un'app di messaggistica diversa.
-POSSIEDI I TUOI DATI: decidi dove tenere i tuoi dati e messaggi. Sono tuoi e li controlli tu, non qualche MEGADITTA che raccoglie i tuoi dati o ne dà l'accesso a terze parti.
+Super sicuro
+Vera crittografia end-to-end (solo chi è nella conversazione può decifrare i messaggi) e verifica di dispositivi a firma incrociata.
-MESSAGGISTICA E COLLABORAZIONE APERTE: puoi chattare con chiunque nella rete Matrix, usando Element o un'altra app Matrix, o anche se si sta usando un sistema di messaggistica diverso come Slack, IRC o XMPP.
+Comunicazioni ed integrazioni complete
+Messaggi, chiamate audio e video, condivisione file e schermo, un vasto numero di integrazioni, bot e widget. Crea stanze, comunità, resta in contatto e porta a termine gli obiettivi.
-SUPER SICURO: vera crittografia end-to-end (solo chi è nella conversazione può decifrare i messaggi) e firma incrociata per verificare i dispositivi dei partecipanti.
-
-COMUNICAZIONE COMPLETA: messaggi, chiamate audio e video, condivisione file e schermo, un vasto numero di integrazioni, bot e widget. Crea stanze, comunità, resta in contatto e porta a termine gli impegni.
-
-OVUNQUE TU SIA: resta in contatto ovunque tu sia con la cronologia dei messaggi sincronizzata tra tutti i tuoi dispositivi e in rete su https://app.element.io.
+Riprendi da dove ti eri fermato
+Resta in contatto ovunque tu sia con la cronologia dei messaggi sincronizzata tra tutti i tuoi dispositivi e in rete su https://app.element.io
diff --git a/fastlane/metadata/android/it/short_description.txt b/fastlane/metadata/android/it/short_description.txt
index 8c0c8fbee0..5050d0c1c5 100644
--- a/fastlane/metadata/android/it/short_description.txt
+++ b/fastlane/metadata/android/it/short_description.txt
@@ -1 +1 @@
-Chat e VoIP decentralizzati sicuri. Tieni lontani i tuoi dati dalle terze parti.
+Messenger di gruppo - messaggi cifrati, chat di gruppo e videochiamate
diff --git a/fastlane/metadata/android/it/title.txt b/fastlane/metadata/android/it/title.txt
index 54e3b456c7..c426a480d3 100644
--- a/fastlane/metadata/android/it/title.txt
+++ b/fastlane/metadata/android/it/title.txt
@@ -1 +1 @@
-Element (ex Riot.im)
+Element - Messaggi sicuri
diff --git a/fastlane/metadata/android/sv/changelogs/40101040.txt b/fastlane/metadata/android/sv/changelogs/40101040.txt
new file mode 100644
index 0000000000..46a004ec54
--- /dev/null
+++ b/fastlane/metadata/android/sv/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: prestandaförbättringar och buggfixar!
+Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/sv/changelogs/40101050.txt b/fastlane/metadata/android/sv/changelogs/40101050.txt
new file mode 100644
index 0000000000..158e2032b7
--- /dev/null
+++ b/fastlane/metadata/android/sv/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: hotfixar för 1.1.4
+Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/sv/changelogs/40101060.txt b/fastlane/metadata/android/sv/changelogs/40101060.txt
new file mode 100644
index 0000000000..cc7a9b84b6
--- /dev/null
+++ b/fastlane/metadata/android/sv/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: hotfixar för 1.1.5
+Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/sv/full_description.txt b/fastlane/metadata/android/sv/full_description.txt
index d130e9214a..5302976ed7 100644
--- a/fastlane/metadata/android/sv/full_description.txt
+++ b/fastlane/metadata/android/sv/full_description.txt
@@ -1,30 +1,39 @@
-Element är en ny sorts meddelande- och samarbetsapp som:
+Element är både en säker meddelandeapp och en samarbetsapp för produktivitet som är ideal för gruppchattar vid distansarbete. Appen använder totalsträckskryptering för att tillhandahålla kraftfulla videogruppsamtal, fildelning och röstsamtal.
-1. Sätter dig i kontroll för att kunna säkerställa ditt privatliv
-2. Låter dig kommunicera med vem som helst i Matrix-nätverket, och till och med bortom det genom integrationer med appar som Slack
-3. Skyddar dig från reklam, datainsamling och inlåsning
-4. Säkrar dig genom totalsträckskryptering, med korssingering för att verifiera andra
+Elements funktioner inkluderar:
+- Avancerade kommunikationsverktyg
+- Fullt krypterade meddelanden för att tillåta säkrare företagskommunikation, även för distansarbetare
+- Decentraliserad chatt baserad på det öppna ramverket Matrix
+- Säker fildelning med krypterad data vid hantering av projekt
+- Videochattar med Voice over IP och skärmdelning
+- Enkel integration med dina föredragna onlinesamarbetsverktyg, projektledningsverktyg, VoIP-tjänster och andra teammeddelandeappar
-Element skiljer sig helt från andra meddelande- och samarbetsappar genom att vara decentraliserad och öppen källkod.
+Element är helt olik andra meddelande- och samarbetsappar. Den använder Matrix, ett öppet nätverk för säkra meddelanden och decentraliserad kommunikation. Den låter dig driva en igen server för att ge användare maximalt ägandeskap över sin data och sina meddelanden.
-Element låter dig driva en egen server - eller välja en värd - så att du har sekretess, ägande och kontroll över din data och dina konversationer. Den ger dig tillgång till ett öppet nätverk; så att du inte kan prata bara med Element-användare. Och den är väldigt säker.
+Sekretess och krypterade meddelanden
+Element skyddar dig från oönskad reklam, datainsamling och inlåsning. Den skyddar även all din data, en-till-en-video- och röstkommunikation genom totalsträckskryptering och korssignerad enhetsverifiering.
-Element kan göra allt detta för att den använder Matrix - standarden för öppen decentraliserad kommunikation.
+Element sätter dig i kontroll över ditt privatliv och låter dig kommunicera säkert med vem som helst i Matrix-nätverket, eller andra samarbetsverktyg genom att integrera med appar som Slack.
-Element sätter dig i kontroll genom att låta dig välja att vara värd för dina konversationer. Från appen Element kan du välja att ansluta på följande sätt:
+Du kan driva Element själv
+För att tillåta större kontroll över din känsliga data och konversationer, så kan du lägga Element på en egen server eller använda valfri Matrix-baserad värd - standarden för open source-baserad, decentraliserad kommunikation. Element ger dig sekretess, säkerhetsefterlevnad och integrationsflexibilitet.
-1. Skaffa ett gratis konto på den publika servern på matrix.org, vilken drivs av Matrix-utvecklarna, eller välj bland tusentals offentliga servrar som drivs av volontärer
-2. Var värd för ditt eget konto genom att driva en server på din egen hårdvara
-3. Skapa ett konto på en anpassad server genom att registrera dig på värdplattformen Element Matrix Services
+Äg din data
+Du bestämmer vart du vill lagra din data och dina meddelanden, utan rist för datainsamling eller åtkomst av tredje parter.
-Varför välja Element?
+Element sätter dig i kontroll på olika sätt:
+1. Få ett gratiskonto på den offentliga servern matrix.org som drivas av Matrixutvecklarna, eller välj bland tusentals offentliga servrar som drivs av volontärer
+2. Självdriv ditt konto genom att driva en server på din egen IT-infrastruktur
+3. Skapa ett konto på en anpassad server genom att abonnera på värdplattformen Element Matrix Services
-ÄG DIN DATA: Du väljer var du vill ha din data och dina meddelanden. Du äger den och kontrollerar den, inte nåt stort företag som samlar in din data och ger den till tredje parter.
+Öppen meddelandehantering och kommunikation
+Du kan chatta med vem som helst i Matrix-nätverket, oavsett om de använder Matrix, en annan Matrix-app eller till och med en annan meddelandeapp.
-ÖPPEN KOMMUNIKATION OCH ÖPPET SAMARBETE: Du kan chatta med vem som helst på Matrix-nätverket, oavsett om de använder Element eller en annan Matrix-app, och till och med om de använder ett annat meddelandesystem som Slack, IRC eller XMPP.
+Supersäker
+Riktig totalsträckskryptering (bara de i konversationen kan avkryptera meddelanden), och korssignerad enhetsverifiering.
-SUPERSÄKER: Riktig totalsträckskryptering (bara de in konversationen kan avkryptera meddelandena), och korssingering för att verifiera konversationsmedlemmars enheter.
+Komplett kommunikation och integration
+Meddelanden, röst- och videosamtal, fildelning, skärmdelning och massa integrationer, bottar och widgets. Bygg rum och gemenskaper, håll kontakten och få saker gjorda.
-KOMPLETT KOMMUNIKATION: Meddelanden, röst- och videosamtal, fildelning, skärmdelning och massa integrationer, bottar och widgets. Skapa rum och gemenskaper, håll kontakten och få saker gjorda.
-
-ÖVERALLT DÄR DU ÄR: Håll kontakten vart du än befinner dig med fullständigt synkroniserad meddelandehistorik på alla dina enheter och på webben på https://app.element.io.
+Fortsätt där du lämnade
+Håll kontakten vart du än är med fullt synkroniserad meddelandehistorik på alla dina enheter och på webben på https://app.element.io
diff --git a/fastlane/metadata/android/sv/short_description.txt b/fastlane/metadata/android/sv/short_description.txt
index ddfc5dcbfb..c16da5c761 100644
--- a/fastlane/metadata/android/sv/short_description.txt
+++ b/fastlane/metadata/android/sv/short_description.txt
@@ -1 +1 @@
-Säker decentraliserad chatt och VoIP. Håll din data säker från tredje parter.
+Gruppmeddelandeapp - krypterade meddelanden, gruppchatt och videosamtal
diff --git a/fastlane/metadata/android/sv/title.txt b/fastlane/metadata/android/sv/title.txt
index 573e27fab9..4fc189de15 100644
--- a/fastlane/metadata/android/sv/title.txt
+++ b/fastlane/metadata/android/sv/title.txt
@@ -1 +1 @@
-Element (före detta Riot.im)
+Element - Säker meddelandeapp
diff --git a/fastlane/metadata/android/zh-Hant/changelogs/40101040.txt b/fastlane/metadata/android/zh-Hant/changelogs/40101040.txt
new file mode 100644
index 0000000000..1786691c42
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hant/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:效能改善與錯誤修復!
+完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/fastlane/metadata/android/zh-Hant/changelogs/40101050.txt b/fastlane/metadata/android/zh-Hant/changelogs/40101050.txt
new file mode 100644
index 0000000000..899ce72c9a
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hant/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:1.1.4 的快速修補
+完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/fastlane/metadata/android/zh-Hant/changelogs/40101060.txt b/fastlane/metadata/android/zh-Hant/changelogs/40101060.txt
new file mode 100644
index 0000000000..838dc6d731
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hant/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:1.1.5 的快速修補
+完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/fastlane/metadata/android/zh-Hant/full_description.txt b/fastlane/metadata/android/zh-Hant/full_description.txt
index 2fdf6fa478..90c0eb4c4c 100644
--- a/fastlane/metadata/android/zh-Hant/full_description.txt
+++ b/fastlane/metadata/android/zh-Hant/full_description.txt
@@ -1,30 +1,39 @@
-Element 是一種新型態的即時通訊軟體與協作應用程式:
+Element 同時是安全的通訊軟體,也是生產力團隊協作應用程式,非常適合在遠端工作時進行群組聊天。此聊天應用程式使用了端到端加密來提供強大的視訊會議、檔案分享與語音通話。
-1. 自己的隱私自己掌控
-2. 讓您與任何在 Matrix 網路中的人通訊,甚至可與如 Slack 等的應用程式整合
-3. 保護您免受廣告、資料採礦與圍牆花園的侵害
-4. 透過端到端加密保護您,並使用交叉簽章來驗證其他人
+Element 的功能包含了:
+- 進階線上通訊工具
+- 完全加密的訊息,即使對於遠端工作者,也可以有更安全的公司通訊
+- 以 Matrix 開放原始碼框架為基礎的去中心化的聊天
+- 在管理專案時透過加密資料安全地分享檔案
+- 包含了 VoIP 與畫面分享的視訊聊天
+- 與您最喜歡的協作工具、專案管理工具、VoIP 服務與其他團隊訊息應用程式輕鬆整合
-Element 是去中心化且開放原始碼的應用程式,因此與其他即時通訊與協作軟體完全不同。
+Element 與其他訊息傳遞與協作應用程式完全不同。它在 Matrix(一個用於安全傳遞訊息與去中心化通訊的開放網路)上執行。其可以自架,讓使用者對他們的資料與訊息有最大的所有權與控制權。
-Element 讓您可以自架(或是自行選擇服務提供者)所以您擁有您資料與對話的隱私、所有權與控制權。它讓您可以存取開放的網路;因此,您不僅可以與其他 Matrix 使用者聊天。而且非常安全。
+隱私與加密訊息傳遞
+Element 保護您不受不想要的廣告、資料挖礦與圍牆花園侵擾。其也透過端到端加密與交叉簽章裝置驗證保護了您所有的資料,並提供一對一視訊以及語音通訊。
-Element 能作到這些事情是因為它在 Matrix 上執行,這是一個開放的去中心化通訊的標準。
+Element 透過與其他商業協作工具,如 Slack 等應用程式整合,讓您可以在控制您的隱私的同時,也可以與 Matrix 網路上的任何人安全地通訊。
-Element 讓您選擇您要在哪裡託管您的對話來將控制權還給您。在 Element 應用程式中,您可以選擇其他方式來託管:
+Element 可以自架
+為了可以完整控制您的敏感資料與對話,Element 可以自架,您也可以選擇任何以 Matrix 為基礎的服務提供商,開放原始碼、去中心化的通訊標準。Element 為您提供隱私、安全合規與整合活性。
-1. 在由 Matrix 開發者架設的 matrix.org 公開伺服器上取得免費的帳號,或是從數千個由志願者所架設的公開伺服器中選擇
-2. 在您自己的硬體上自行架設伺服器並建立帳號
-3. 訂閱 Element Matrix 服務託管平台並在自訂伺服氣上註冊帳號
+擁有您的資料
+您可以決定將您的資料與訊息儲存在何處。沒有資料挖礦或被第三方存取的風險。
-為何選擇 Element?
+Element 透過不同的方式讓您掌控一切:
+1. 在 Matrix 開發者架設的 matrix.org 公開伺服器上取得免費帳號,或是從數千個由志願者架設的公開伺服器中選擇
+2. 在您自己的 IT 基礎架構上執行伺服器來自行託管您的帳號
+3. 只要訂閱 Element Matrix Services 託管平台就可以在自訂的伺服器上註冊帳號
-擁有您的資料:您決定您的資料與訊息要放在哪裡。您擁有並控制它,而非某些科技巨頭會挖掘您的資料並將其售予第三方。
+開放訊息傳遞與協作
+您可以與 Matrix 網路上的任何人聊天,不論他們是使用 Element、其他 Matrix 應用程式或其他通訊應用程式。
-開放的即時通訊與協作:您可以與 Matrix 網路中的任何人聊天,不管他們是使用 Element 或其他 Matrix 應用程式都可以,或甚至是其他的訊息系統,如 Slack、IRC 或 XMPP 也都可以。
+超級安全
+真的端到端加密(僅有那些在對話中的可以解密訊息)以及交叉簽章裝置驗證。
-超級安全:即時的端到端加密(僅有參與對話的人可以解密訊息),以及交叉簽章以驗證對話參與者的裝置。
+完整的通訊與整合Complete communication and integration
+訊息傳遞、語音與視訊通話、檔案分享、畫面分享與超多的整合、機器人與小工具。建構聊天室、社群、保持聯絡並完成工作。
-完整通訊:即時通訊、語音與視訊通話、檔案分享、畫面分享與超多的整合、機器人與小工具。建立聊天室、保持聯繫並完成工作。
-
-無論您身在何處:無論您身在何處,都可以透過 https://app.element.io 來在所有裝置與網路上保持訊息歷史同步。
+從上次離開的地方開始
+無論您身在何處,都可以透過在您所有裝置與網頁 https://app.element.io 間完全同步的訊息歷史保持聯絡
diff --git a/fastlane/metadata/android/zh-Hant/short_description.txt b/fastlane/metadata/android/zh-Hant/short_description.txt
index 23bb82c04e..0d1f5bb7cd 100644
--- a/fastlane/metadata/android/zh-Hant/short_description.txt
+++ b/fastlane/metadata/android/zh-Hant/short_description.txt
@@ -1 +1 @@
-安全的去中心化聊天與 VoIP。確保您的資料不受第三方的影響。
+群組通訊軟體 - 訊息加密、群組聊天與視訊通話
diff --git a/fastlane/metadata/android/zh-Hant/title.txt b/fastlane/metadata/android/zh-Hant/title.txt
index 3be2260b73..47d8a6b3ad 100644
--- a/fastlane/metadata/android/zh-Hant/title.txt
+++ b/fastlane/metadata/android/zh-Hant/title.txt
@@ -1 +1 @@
-Element(曾名為 Riot.im)
+Element - 安全的通訊軟體
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 9d174797f7..e1e2fd2c75 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionSha256Sum=81003f83b0056d20eedf48cddd4f52a9813163d4ba185bcf8abd34b8eeea4cbd
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip
+distributionSha256Sum=13bf8d3cf8eeeb5770d19741a59bde9bd966dd78d17f1bbad787a05ef19d1c2d
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle
index 4059004394..a65dc6298e 100644
--- a/matrix-sdk-android/build.gradle
+++ b/matrix-sdk-android/build.gradle
@@ -6,13 +6,10 @@ apply plugin: 'realm-android'
buildscript {
repositories {
- // mavenCentral()
- //noinspection GrDeprecatedAPIUsage
- jcenter()
+ mavenCentral()
}
dependencies {
- // Stick to this version until https://github.com/realm/realm-java/issues/7402 is fixed
- classpath "io.realm:realm-gradle-plugin:10.3.1"
+ classpath "io.realm:realm-gradle-plugin:10.5.0"
}
}
@@ -115,7 +112,7 @@ dependencies {
def lifecycle_version = '2.2.0'
def arch_version = '2.1.0'
def markwon_version = '3.1.0'
- def daggerVersion = '2.35'
+ def daggerVersion = '2.35.1'
def work_version = '2.5.0'
def retrofit_version = '2.9.0'
@@ -172,7 +169,7 @@ dependencies {
implementation 'com.otaliastudios:transcoder:0.10.3'
// Phone number https://github.com/google/libphonenumber
- implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.22'
+ implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.23'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.5.1'
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeTest.kt
index ee604fc9ab..76bf6dc040 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeTest.kt
@@ -226,12 +226,12 @@ class QrCodeTest : InstrumentedTest {
private fun checkHeader(byteArray: ByteArray) {
// MATRIX
- byteArray[0] shouldBeEqualTo 'M'.toByte()
- byteArray[1] shouldBeEqualTo 'A'.toByte()
- byteArray[2] shouldBeEqualTo 'T'.toByte()
- byteArray[3] shouldBeEqualTo 'R'.toByte()
- byteArray[4] shouldBeEqualTo 'I'.toByte()
- byteArray[5] shouldBeEqualTo 'X'.toByte()
+ byteArray[0] shouldBeEqualTo 'M'.code.toByte()
+ byteArray[1] shouldBeEqualTo 'A'.code.toByte()
+ byteArray[2] shouldBeEqualTo 'T'.code.toByte()
+ byteArray[3] shouldBeEqualTo 'R'.code.toByte()
+ byteArray[4] shouldBeEqualTo 'I'.code.toByte()
+ byteArray[5] shouldBeEqualTo 'X'.code.toByte()
// Version
byteArray[6] shouldBeEqualTo 2
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt
index a7f5163774..5e35917243 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt
@@ -51,11 +51,15 @@ interface AuthenticationService {
/**
* Return a LoginWizard, to login to the homeserver. The login flow has to be retrieved first.
+ *
+ * See [LoginWizard] for more details
*/
fun getLoginWizard(): LoginWizard
/**
* Return a RegistrationWizard, to create an matrix account on the homeserver. The login flow has to be retrieved first.
+ *
+ * See [RegistrationWizard] for more details.
*/
fun getRegistrationWizard(): RegistrationWizard
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt
index 9c96cba40c..da6eb0c3ac 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt
@@ -17,34 +17,46 @@
package org.matrix.android.sdk.api.auth.login
import org.matrix.android.sdk.api.session.Session
-import org.matrix.android.sdk.api.util.Cancelable
+/**
+ * Set of methods to be able to login to an existing account on a homeserver.
+ *
+ * More documentation can be found in the file https://github.com/vector-im/element-android/blob/main/docs/signin.md
+ */
interface LoginWizard {
-
/**
- * @param login the login field
- * @param password the password field
+ * Login to the homeserver.
+ *
+ * @param login the login field. Can be a user name, or a msisdn (email or phone number) associated to the account
+ * @param password the password of the account
* @param deviceName the initial device name
- * @param callback the matrix callback on which you'll receive the result of authentication.
- * @return a [Cancelable]
+ * @return a [Session] if the login is successful
*/
suspend fun login(login: String,
password: String,
deviceName: String): Session
/**
- * Exchange a login token to an access token
+ * Exchange a login token to an access token.
+ *
+ * @param loginToken login token, obtain when login has happen in a WebView, using SSO
+ * @return a [Session] if the login is successful
*/
suspend fun loginWithToken(loginToken: String): Session
/**
- * Reset user password
+ * Ask the homeserver to reset the user password. The password will not be reset until
+ * [resetPasswordMailConfirmed] is successfully called.
+ *
+ * @param email an email previously associated to the account the user wants the password to be reset.
+ * @param newPassword the desired new password
*/
suspend fun resetPassword(email: String,
newPassword: String)
/**
* Confirm the new password, once the user has checked their email
+ * When this method succeed, tha account password will be effectively modified.
*/
suspend fun resetPasswordMailConfirmed()
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationWizard.kt
index f059bf26c4..621253faa5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationWizard.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationWizard.kt
@@ -16,32 +16,98 @@
package org.matrix.android.sdk.api.auth.registration
+/**
+ * Set of methods to be able to create an account on a homeserver.
+ *
+ * Common scenario to register an account successfully:
+ * - Call [getRegistrationFlow] to check that you application supports all the mandatory registration stages
+ * - Call [createAccount] to start the account creation
+ * - Fulfill all mandatory stages using the methods [performReCaptcha] [acceptTerms] [dummy], etc.
+ *
+ * More documentation can be found in the file https://github.com/vector-im/element-android/blob/main/docs/signup.md
+ * and https://matrix.org/docs/spec/client_server/latest#account-registration-and-management
+ */
interface RegistrationWizard {
-
+ /**
+ * Call this method to get the possible registration flow of the current homeserver.
+ * It can be useful to ensure that your application implementation supports all the stages
+ * required to create an account. If it is not the case, you will have to use the web fallback
+ * to let the user create an account with your application.
+ * See [org.matrix.android.sdk.api.auth.AuthenticationService.getFallbackUrl]
+ */
suspend fun getRegistrationFlow(): RegistrationResult
+ /**
+ * Can be call to check is the desired userName is available for registration on the current homeserver.
+ * It may also fails if the desired userName is not correctly formatted or does not follow any restriction on
+ * the homeserver. Ex: userName with only digits may be rejected.
+ * @param userName the desired username. Ex: "alice"
+ */
+ suspend fun registrationAvailable(userName: String): RegistrationAvailability
+
+ /**
+ * This is the first method to call in order to create an account and start the registration process.
+ *
+ * @param userName the desired username. Ex: "alice"
+ * @param password the desired password
+ * @param initialDeviceDisplayName the device display name
+ */
suspend fun createAccount(userName: String?,
password: String?,
initialDeviceDisplayName: String?): RegistrationResult
+ /**
+ * Perform the "m.login.recaptcha" stage.
+ *
+ * @param response the response from ReCaptcha
+ */
suspend fun performReCaptcha(response: String): RegistrationResult
+ /**
+ * Perform the "m.login.terms" stage.
+ */
suspend fun acceptTerms(): RegistrationResult
+ /**
+ * Perform the "m.login.dummy" stage.
+ */
suspend fun dummy(): RegistrationResult
+ /**
+ * Perform the "m.login.email.identity" or "m.login.msisdn" stage.
+ *
+ * @param threePid the threePid to add to the account. If this is an email, the homeserver will send an email
+ * to validate it. For a msisdn a SMS will be sent.
+ */
suspend fun addThreePid(threePid: RegisterThreePid): RegistrationResult
+ /**
+ * Ask the homeserver to send again the current threePid (email or msisdn).
+ */
suspend fun sendAgainThreePid(): RegistrationResult
+ /**
+ * Send the code received by SMS to validate a msisdn.
+ * If the code is correct, the registration request will be executed to validate the msisdn.
+ */
suspend fun handleValidateThreePid(code: String): RegistrationResult
+ /**
+ * Useful to poll the homeserver when waiting for the email to be validated by the user.
+ * Once the email is validated, this method will return successfully.
+ * @param delayMillis the SDK can wait before sending the request
+ */
suspend fun checkIfEmailHasBeenValidated(delayMillis: Long): RegistrationResult
- suspend fun registrationAvailable(userName: String): RegistrationAvailability
-
+ /**
+ * This is the current ThreePid, waiting for validation. The SDK will store it in database, so it can be
+ * restored even if the app has been killed during the registration
+ */
val currentThreePid: String?
- // True when login and password has been sent with success to the homeserver
+ /**
+ * True when login and password have been sent with success to the homeserver, i.e. [createAccount] has been
+ * called successfully.
+ */
val isRegistrationStarted: Boolean
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt
index e493adeaf2..05fa24946a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt
@@ -66,6 +66,7 @@ interface ProfileService {
/**
* Get the combined profile information for this user.
* This may return keys which are not limited to displayname or avatar_url.
+ * If server is configured as limit_profile_requests_to_users_who_share_rooms: true then response can be HTTP 403.
* @param userId the userId param to look for
*
*/
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 f3eeb902a8..8c434fc440 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
@@ -83,7 +83,7 @@ interface Room :
* @param beforeLimit how many events before the result are returned.
* @param afterLimit how many events after the result are returned.
* @param includeProfile requests that the server returns the historic profile information for the users that sent the events that were returned.
- * @param callback Callback to get the search result
+ * @return The search result
*/
suspend fun search(searchTerm: String,
nextBatch: String?,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt
index d324cff246..cae4775e71 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt
@@ -26,7 +26,7 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
* This class holds some data of a 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 RoomSummary constructor(
+data class RoomSummary(
val roomId: String,
// Computed display name
val displayName: String = "",
@@ -35,6 +35,7 @@ data class RoomSummary constructor(
val avatarUrl: String = "",
val canonicalAlias: String? = null,
val aliases: List = emptyList(),
+ val joinRules: RoomJoinRules? = null,
val isDirect: Boolean = false,
val directUserId: String? = null,
val joinedMembersCount: Int? = 0,
@@ -74,6 +75,9 @@ data class RoomSummary constructor(
val isFavorite: Boolean
get() = hasTag(RoomTag.ROOM_TAG_FAVOURITE)
+ val isPublic: Boolean
+ get() = joinRules == RoomJoinRules.PUBLIC
+
fun hasTag(tag: String) = tags.any { it.name == tag }
val canStartCall: Boolean
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/SpaceChildInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/SpaceChildInfo.kt
index fd5fbf7bb0..2d31930b33 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/SpaceChildInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/SpaceChildInfo.kt
@@ -29,5 +29,6 @@ data class SpaceChildInfo(
val activeMemberCount: Int?,
val autoJoin: Boolean,
val viaServers: List,
- val parentRoomId: String?
+ val parentRoomId: String?,
+ val suggested: Boolean?
)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt
index 9dba4f90af..db25762c2f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt
@@ -33,7 +33,7 @@ interface Space {
fun spaceSummary(): RoomSummary?
suspend fun addChildren(roomId: String,
- viaServers: List,
+ viaServers: List?,
order: String?,
autoJoin: Boolean = false,
suggested: Boolean? = false)
@@ -46,5 +46,8 @@ interface Space {
@Throws
suspend fun setChildrenAutoJoin(roomId: String, autoJoin: Boolean)
+ @Throws
+ suspend fun setChildrenSuggested(roomId: String, suggested: Boolean)
+
// fun getChildren() : List
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/model/WidgetContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/model/WidgetContent.kt
index 2c4c03b7d4..7a4231c277 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/model/WidgetContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/model/WidgetContent.kt
@@ -20,6 +20,7 @@ import android.annotation.SuppressLint
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.util.JsonDict
+import org.matrix.android.sdk.internal.util.safeCapitalize
/**
* Ref: https://github.com/matrix-org/matrix-doc/issues/1236
@@ -39,6 +40,6 @@ data class WidgetContent(
@SuppressLint("DefaultLocale")
fun getHumanName(): String {
- return (name ?: type ?: "").capitalize()
+ return (name ?: type ?: "").safeCapitalize()
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt
index 7b2fae86ef..3bf3f66e40 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt
@@ -117,22 +117,22 @@ sealed class MatrixItem(
var first = dn[startIndex]
// LEFT-TO-RIGHT MARK
- if (dn.length >= 2 && 0x200e == first.toInt()) {
+ if (dn.length >= 2 && 0x200e == first.code) {
startIndex++
first = dn[startIndex]
}
// check if it’s the start of a surrogate pair
- if (first.toInt() in 0xD800..0xDBFF && dn.length > startIndex + 1) {
+ if (first.code in 0xD800..0xDBFF && dn.length > startIndex + 1) {
val second = dn[startIndex + 1]
- if (second.toInt() in 0xDC00..0xDFFF) {
+ if (second.code in 0xDC00..0xDFFF) {
length++
}
}
dn.substring(startIndex, startIndex + length)
}
- .toUpperCase(Locale.ROOT)
+ .uppercase(Locale.ROOT)
}
companion object {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
index 2163b2a5e0..7f5cfe8df1 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
@@ -545,14 +545,14 @@ internal class DefaultCryptoService @Inject constructor(
val existingAlgorithm = cryptoStore.getRoomAlgorithm(roomId)
if (!existingAlgorithm.isNullOrEmpty() && existingAlgorithm != algorithm) {
- Timber.e("## CRYPTO | setEncryptionInRoom() : Ignoring m.room.encryption event which requests a change of config in $roomId")
+ Timber.e("## CRYPTO | setEncryptionInRoom() : Ignoring m.room.encryption event which requests a change of config in $roomId")
return false
}
val encryptingClass = MXCryptoAlgorithms.hasEncryptorClassForAlgorithm(algorithm)
if (!encryptingClass) {
- Timber.e("## CRYPTO | setEncryptionInRoom() : Unable to encrypt room $roomId with $algorithm")
+ Timber.e("## CRYPTO | setEncryptionInRoom() : Unable to encrypt room $roomId with $algorithm")
return false
}
@@ -649,17 +649,17 @@ internal class DefaultCryptoService @Inject constructor(
val safeAlgorithm = alg
if (safeAlgorithm != null) {
val t0 = System.currentTimeMillis()
- Timber.v("## CRYPTO | encryptEventContent() starts")
+ Timber.v("## CRYPTO | encryptEventContent() starts")
runCatching {
val content = safeAlgorithm.encryptEventContent(eventContent, eventType, userIds)
- Timber.v("## CRYPTO | encryptEventContent() : succeeds after ${System.currentTimeMillis() - t0} ms")
+ Timber.v("## CRYPTO | encryptEventContent() : succeeds after ${System.currentTimeMillis() - t0} ms")
MXEncryptEventContentResult(content, EventType.ENCRYPTED)
}.foldToCallback(callback)
} else {
val algorithm = getEncryptionAlgorithm(roomId)
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON,
algorithm ?: MXCryptoError.NO_MORE_ALGORITHM_REASON)
- Timber.e("## CRYPTO | encryptEventContent() : $reason")
+ Timber.e("## CRYPTO | encryptEventContent() : $reason")
callback.onFailure(Failure.CryptoError(MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_ENCRYPT, reason)))
}
}
@@ -769,7 +769,7 @@ internal class DefaultCryptoService @Inject constructor(
}
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(roomKeyContent.roomId, roomKeyContent.algorithm)
if (alg == null) {
- Timber.e("## CRYPTO | GOSSIP onRoomKeyEvent() : Unable to handle keys for ${roomKeyContent.algorithm}")
+ Timber.e("## CRYPTO | GOSSIP onRoomKeyEvent() : Unable to handle keys for ${roomKeyContent.algorithm}")
return
}
alg.onRoomKeyEvent(event, keysBackupService)
@@ -777,7 +777,7 @@ internal class DefaultCryptoService @Inject constructor(
private fun onKeyWithHeldReceived(event: Event) {
val withHeldContent = event.getClearContent().toModel() ?: return Unit.also {
- Timber.i("## CRYPTO | Malformed onKeyWithHeldReceived() : missing fields")
+ Timber.i("## CRYPTO | Malformed onKeyWithHeldReceived() : missing fields")
}
Timber.i("## CRYPTO | onKeyWithHeldReceived() received from:${event.senderId}, content <$withHeldContent>")
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(withHeldContent.roomId, withHeldContent.algorithm)
@@ -790,16 +790,16 @@ internal class DefaultCryptoService @Inject constructor(
}
private fun onSecretSendReceived(event: Event) {
- Timber.i("## CRYPTO | GOSSIP onSecretSend() from ${event.senderId} : onSecretSendReceived ${event.content?.get("sender_key")}")
+ Timber.i("## CRYPTO | GOSSIP onSecretSend() from ${event.senderId} : onSecretSendReceived ${event.content?.get("sender_key")}")
if (!event.isEncrypted()) {
// secret send messages must be encrypted
- Timber.e("## CRYPTO | GOSSIP onSecretSend() :Received unencrypted secret send event")
+ Timber.e("## CRYPTO | GOSSIP onSecretSend() :Received unencrypted secret send event")
return
}
// Was that sent by us?
if (event.senderId != userId) {
- Timber.e("## CRYPTO | GOSSIP onSecretSend() : Ignore secret from other user ${event.senderId}")
+ Timber.e("## CRYPTO | GOSSIP onSecretSend() : Ignore secret from other user ${event.senderId}")
return
}
@@ -809,13 +809,13 @@ internal class DefaultCryptoService @Inject constructor(
.getOutgoingSecretKeyRequests().firstOrNull { it.requestId == secretContent.requestId }
if (existingRequest == null) {
- Timber.i("## CRYPTO | GOSSIP onSecretSend() : Ignore secret that was not requested: ${secretContent.requestId}")
+ Timber.i("## CRYPTO | GOSSIP onSecretSend() : Ignore secret that was not requested: ${secretContent.requestId}")
return
}
if (!handleSDKLevelGossip(existingRequest.secretName, secretContent.secretValue)) {
// TODO Ask to application layer?
- Timber.v("## CRYPTO | onSecretSend() : secret not handled by SDK")
+ Timber.v("## CRYPTO | onSecretSend() : secret not handled by SDK")
}
}
@@ -972,13 +972,13 @@ internal class DefaultCryptoService @Inject constructor(
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
runCatching {
withContext(coroutineDispatchers.crypto) {
- Timber.v("## CRYPTO | importRoomKeys starts")
+ Timber.v("## CRYPTO | importRoomKeys starts")
val t0 = System.currentTimeMillis()
val roomKeys = MXMegolmExportEncryption.decryptMegolmKeyFile(roomKeysAsArray, password)
val t1 = System.currentTimeMillis()
- Timber.v("## CRYPTO | importRoomKeys : decryptMegolmKeyFile done in ${t1 - t0} ms")
+ Timber.v("## CRYPTO | importRoomKeys : decryptMegolmKeyFile done in ${t1 - t0} ms")
val importedSessions = MoshiProvider.providesMoshi()
.adapter>(Types.newParameterizedType(List::class.java, MegolmSessionData::class.java))
@@ -986,7 +986,7 @@ internal class DefaultCryptoService @Inject constructor(
val t2 = System.currentTimeMillis()
- Timber.v("## CRYPTO | importRoomKeys : JSON parsing ${t2 - t1} ms")
+ Timber.v("## CRYPTO | importRoomKeys : JSON parsing ${t2 - t1} ms")
if (importedSessions == null) {
throw Exception("Error")
@@ -1125,7 +1125,7 @@ internal class DefaultCryptoService @Inject constructor(
*/
override fun reRequestRoomKeyForEvent(event: Event) {
val wireContent = event.content.toModel() ?: return Unit.also {
- Timber.e("## CRYPTO | reRequestRoomKeyForEvent Failed to re-request key, null content")
+ Timber.e("## CRYPTO | reRequestRoomKeyForEvent Failed to re-request key, null content")
}
val requestBody = RoomKeyRequestBody(
@@ -1140,18 +1140,18 @@ internal class DefaultCryptoService @Inject constructor(
override fun requestRoomKeyForEvent(event: Event) {
val wireContent = event.content.toModel() ?: return Unit.also {
- Timber.e("## CRYPTO | requestRoomKeyForEvent Failed to request key, null content eventId: ${event.eventId}")
+ Timber.e("## CRYPTO | requestRoomKeyForEvent Failed to request key, null content eventId: ${event.eventId}")
}
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
// if (!isStarted()) {
-// Timber.v("## CRYPTO | requestRoomKeyForEvent() : wait after e2e init")
+// Timber.v("## CRYPTO | requestRoomKeyForEvent() : wait after e2e init")
// internalStart(false)
// }
roomDecryptorProvider
.getOrCreateRoomDecryptor(event.roomId, wireContent.algorithm)
?.requestKeysForEvent(event, false) ?: run {
- Timber.v("## CRYPTO | requestRoomKeyForEvent() : No room decryptor for roomId:${event.roomId} algorithm:${wireContent.algorithm}")
+ Timber.v("## CRYPTO | requestRoomKeyForEvent() : No room decryptor for roomId:${event.roomId} algorithm:${wireContent.algorithm}")
}
}
}
@@ -1180,11 +1180,11 @@ internal class DefaultCryptoService @Inject constructor(
// val lastForcedDate = lastNewSessionForcedDates.getObject(senderId, deviceKey) ?: 0
// val now = System.currentTimeMillis()
// if (now - lastForcedDate < CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS) {
-// Timber.d("## CRYPTO | markOlmSessionForUnwedging: New session already forced with device at $lastForcedDate. Not forcing another")
+// Timber.d("## CRYPTO | markOlmSessionForUnwedging: New session already forced with device at $lastForcedDate. Not forcing another")
// return
// }
//
-// Timber.d("## CRYPTO | markOlmSessionForUnwedging from $senderId:${deviceInfo.deviceId}")
+// Timber.d("## CRYPTO | markOlmSessionForUnwedging from $senderId:${deviceInfo.deviceId}")
// lastNewSessionForcedDates.setObject(senderId, deviceKey, now)
//
// cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
@@ -1201,7 +1201,7 @@ internal class DefaultCryptoService @Inject constructor(
// val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
// val sendToDeviceMap = MXUsersDevicesMap()
// sendToDeviceMap.setObject(senderId, deviceInfo.deviceId, encodedPayload)
-// Timber.v("## CRYPTO | markOlmSessionForUnwedging() : sending to $senderId:${deviceInfo.deviceId}")
+// Timber.v("## CRYPTO | markOlmSessionForUnwedging() : sending to $senderId:${deviceInfo.deviceId}")
// val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
// sendToDeviceTask.execute(sendToDeviceParams)
// }
@@ -1290,12 +1290,12 @@ internal class DefaultCryptoService @Inject constructor(
override fun prepareToEncrypt(roomId: String, callback: MatrixCallback) {
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
- Timber.d("## CRYPTO | prepareToEncrypt() : Check room members up to date")
+ Timber.d("## CRYPTO | prepareToEncrypt() : Check room members up to date")
// Ensure to load all room members
try {
loadRoomMembersTask.execute(LoadRoomMembersTask.Params(roomId))
} catch (failure: Throwable) {
- Timber.e("## CRYPTO | prepareToEncrypt() : Failed to load room members")
+ Timber.e("## CRYPTO | prepareToEncrypt() : Failed to load room members")
callback.onFailure(failure)
return@launch
}
@@ -1308,7 +1308,7 @@ internal class DefaultCryptoService @Inject constructor(
if (alg == null) {
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON, MXCryptoError.NO_MORE_ALGORITHM_REASON)
- Timber.e("## CRYPTO | prepareToEncrypt() : $reason")
+ Timber.e("## CRYPTO | prepareToEncrypt() : $reason")
callback.onFailure(IllegalArgumentException("Missing algorithm"))
return@launch
}
@@ -1318,7 +1318,7 @@ internal class DefaultCryptoService @Inject constructor(
}.fold(
{ callback.onSuccess(Unit) },
{
- Timber.e("## CRYPTO | prepareToEncrypt() failed.")
+ Timber.e("## CRYPTO | prepareToEncrypt() failed.")
callback.onFailure(it)
}
)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt
index e5f1c011f8..63f15aaf6e 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt
@@ -111,7 +111,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
res = !notReadyToRetryHS.contains(userId.substringAfter(':'))
}
} catch (e: Exception) {
- Timber.e(e, "## CRYPTO | canRetryKeysDownload() failed")
+ Timber.e(e, "## CRYPTO | canRetryKeysDownload() failed")
}
}
@@ -150,7 +150,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
for (userId in userIds) {
if (!deviceTrackingStatuses.containsKey(userId) || TRACKING_STATUS_NOT_TRACKED == deviceTrackingStatuses[userId]) {
- Timber.v("## CRYPTO | startTrackingDeviceList() : Now tracking device list for $userId")
+ Timber.v("## CRYPTO | startTrackingDeviceList() : Now tracking device list for $userId")
deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
isUpdated = true
}
@@ -178,7 +178,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
for (userId in changed) {
if (deviceTrackingStatuses.containsKey(userId)) {
- Timber.v("## CRYPTO | handleDeviceListsChanges() : Marking device list outdated for $userId")
+ Timber.v("## CRYPTO | handleDeviceListsChanges() : Marking device list outdated for $userId")
deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
isUpdated = true
}
@@ -186,7 +186,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
for (userId in left) {
if (deviceTrackingStatuses.containsKey(userId)) {
- Timber.v("## CRYPTO | handleDeviceListsChanges() : No longer tracking device list for $userId")
+ Timber.v("## CRYPTO | handleDeviceListsChanges() : No longer tracking device list for $userId")
deviceTrackingStatuses[userId] = TRACKING_STATUS_NOT_TRACKED
isUpdated = true
}
@@ -276,7 +276,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
* @param forceDownload Always download the keys even if cached.
*/
suspend fun downloadKeys(userIds: List?, forceDownload: Boolean): MXUsersDevicesMap {
- Timber.v("## CRYPTO | downloadKeys() : forceDownload $forceDownload : $userIds")
+ Timber.v("## CRYPTO | downloadKeys() : forceDownload $forceDownload : $userIds")
// Map from userId -> deviceId -> MXDeviceInfo
val stored = MXUsersDevicesMap()
@@ -305,13 +305,13 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
}
}
return if (downloadUsers.isEmpty()) {
- Timber.v("## CRYPTO | downloadKeys() : no new user device")
+ Timber.v("## CRYPTO | downloadKeys() : no new user device")
stored
} else {
- Timber.v("## CRYPTO | downloadKeys() : starts")
+ Timber.v("## CRYPTO | downloadKeys() : starts")
val t0 = System.currentTimeMillis()
val result = doKeyDownloadForUsers(downloadUsers)
- Timber.v("## CRYPTO | downloadKeys() : doKeyDownloadForUsers succeeds after ${System.currentTimeMillis() - t0} ms")
+ Timber.v("## CRYPTO | downloadKeys() : doKeyDownloadForUsers succeeds after ${System.currentTimeMillis() - t0} ms")
result.also {
it.addEntriesFromMap(stored)
}
@@ -324,7 +324,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
* @param downloadUsers the user ids list
*/
private suspend fun doKeyDownloadForUsers(downloadUsers: List): MXUsersDevicesMap {
- Timber.v("## CRYPTO | doKeyDownloadForUsers() : doKeyDownloadForUsers ${downloadUsers.logLimit()}")
+ Timber.v("## CRYPTO | doKeyDownloadForUsers() : doKeyDownloadForUsers ${downloadUsers.logLimit()}")
// get the user ids which did not already trigger a keys download
val filteredUsers = downloadUsers.filter { MatrixPatterns.isUserId(it) }
if (filteredUsers.isEmpty()) {
@@ -335,16 +335,16 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
val response = try {
downloadKeysForUsersTask.execute(params)
} catch (throwable: Throwable) {
- Timber.e(throwable, "## CRYPTO | doKeyDownloadForUsers(): error")
+ Timber.e(throwable, "## CRYPTO | doKeyDownloadForUsers(): error")
onKeysDownloadFailed(filteredUsers)
throw throwable
}
- Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for " + filteredUsers.size + " users")
+ Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for " + filteredUsers.size + " users")
for (userId in filteredUsers) {
// al devices =
val models = response.deviceKeys?.get(userId)?.mapValues { entry -> CryptoInfoMapper.map(entry.value) }
- Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for $userId : $models")
+ Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for $userId : $models")
if (!models.isNullOrEmpty()) {
val workingCopy = models.toMutableMap()
for ((deviceId, deviceInfo) in models) {
@@ -377,13 +377,13 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
}
val masterKey = response.masterKeys?.get(userId)?.toCryptoModel().also {
- Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : MSK ${it?.unpaddedBase64PublicKey}")
+ Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : MSK ${it?.unpaddedBase64PublicKey}")
}
val selfSigningKey = response.selfSigningKeys?.get(userId)?.toCryptoModel()?.also {
- Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : SSK ${it.unpaddedBase64PublicKey}")
+ Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : SSK ${it.unpaddedBase64PublicKey}")
}
val userSigningKey = response.userSigningKeys?.get(userId)?.toCryptoModel()?.also {
- Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : USK ${it.unpaddedBase64PublicKey}")
+ Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : USK ${it.unpaddedBase64PublicKey}")
}
cryptoStore.storeUserCrossSigningKeys(
userId,
@@ -411,28 +411,28 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
*/
private fun validateDeviceKeys(deviceKeys: CryptoDeviceInfo?, userId: String, deviceId: String, previouslyStoredDeviceKeys: CryptoDeviceInfo?): Boolean {
if (null == deviceKeys) {
- Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys is null from $userId:$deviceId")
+ Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys is null from $userId:$deviceId")
return false
}
if (null == deviceKeys.keys) {
- Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys.keys is null from $userId:$deviceId")
+ Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys.keys is null from $userId:$deviceId")
return false
}
if (null == deviceKeys.signatures) {
- Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys.signatures is null from $userId:$deviceId")
+ Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys.signatures is null from $userId:$deviceId")
return false
}
// Check that the user_id and device_id in the received deviceKeys are correct
if (deviceKeys.userId != userId) {
- Timber.e("## CRYPTO | validateDeviceKeys() : Mismatched user_id ${deviceKeys.userId} from $userId:$deviceId")
+ Timber.e("## CRYPTO | validateDeviceKeys() : Mismatched user_id ${deviceKeys.userId} from $userId:$deviceId")
return false
}
if (deviceKeys.deviceId != deviceId) {
- Timber.e("## CRYPTO | validateDeviceKeys() : Mismatched device_id ${deviceKeys.deviceId} from $userId:$deviceId")
+ Timber.e("## CRYPTO | validateDeviceKeys() : Mismatched device_id ${deviceKeys.deviceId} from $userId:$deviceId")
return false
}
@@ -440,21 +440,21 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
val signKey = deviceKeys.keys[signKeyId]
if (null == signKey) {
- Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} has no ed25519 key")
+ Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} has no ed25519 key")
return false
}
val signatureMap = deviceKeys.signatures[userId]
if (null == signatureMap) {
- Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} has no map for $userId")
+ Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} has no map for $userId")
return false
}
val signature = signatureMap[signKeyId]
if (null == signature) {
- Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} is not signed")
+ Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} is not signed")
return false
}
@@ -469,7 +469,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
}
if (!isVerified) {
- Timber.e("## CRYPTO | validateDeviceKeys() : Unable to verify signature on device " + userId + ":"
+ Timber.e("## CRYPTO | validateDeviceKeys() : Unable to verify signature on device " + userId + ":"
+ deviceKeys.deviceId + " with error " + errorMessage)
return false
}
@@ -480,12 +480,12 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
// best off sticking with the original keys.
//
// Should we warn the user about it somehow?
- Timber.e("## CRYPTO | validateDeviceKeys() : WARNING:Ed25519 key for device " + userId + ":"
+ Timber.e("## CRYPTO | validateDeviceKeys() : WARNING:Ed25519 key for device " + userId + ":"
+ deviceKeys.deviceId + " has changed : "
+ previouslyStoredDeviceKeys.fingerprint() + " -> " + signKey)
- Timber.e("## CRYPTO | validateDeviceKeys() : $previouslyStoredDeviceKeys -> $deviceKeys")
- Timber.e("## CRYPTO | validateDeviceKeys() : ${previouslyStoredDeviceKeys.keys} -> ${deviceKeys.keys}")
+ Timber.e("## CRYPTO | validateDeviceKeys() : $previouslyStoredDeviceKeys -> $deviceKeys")
+ Timber.e("## CRYPTO | validateDeviceKeys() : ${previouslyStoredDeviceKeys.keys} -> ${deviceKeys.keys}")
return false
}
@@ -499,7 +499,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
* This method must be called on getEncryptingThreadHandler() thread.
*/
suspend fun refreshOutdatedDeviceLists() {
- Timber.v("## CRYPTO | refreshOutdatedDeviceLists()")
+ Timber.v("## CRYPTO | refreshOutdatedDeviceLists()")
val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
val users = deviceTrackingStatuses.keys.filterTo(mutableListOf()) { userId ->
@@ -518,10 +518,10 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
doKeyDownloadForUsers(users)
}.fold(
{
- Timber.v("## CRYPTO | refreshOutdatedDeviceLists() : done")
+ Timber.v("## CRYPTO | refreshOutdatedDeviceLists() : done")
},
{
- Timber.e(it, "## CRYPTO | refreshOutdatedDeviceLists() : ERROR updating device keys for users $users")
+ Timber.e(it, "## CRYPTO | refreshOutdatedDeviceLists() : ERROR updating device keys for users $users")
}
)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt
index 32324896fa..8d86380e39 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt
@@ -92,20 +92,20 @@ internal class EventDecryptor @Inject constructor(
private fun internalDecryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
val eventContent = event.content
if (eventContent == null) {
- Timber.e("## CRYPTO | decryptEvent : empty event content")
+ Timber.e("## CRYPTO | decryptEvent : empty event content")
throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE, MXCryptoError.BAD_ENCRYPTED_MESSAGE_REASON)
} else {
val algorithm = eventContent["algorithm"]?.toString()
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(event.roomId, algorithm)
if (alg == null) {
val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, algorithm)
- Timber.e("## CRYPTO | decryptEvent() : $reason")
+ Timber.e("## CRYPTO | decryptEvent() : $reason")
throw MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_DECRYPT, reason)
} else {
try {
return alg.decryptEvent(event, timeline)
} catch (mxCryptoError: MXCryptoError) {
- Timber.v("## CRYPTO | internalDecryptEvent : Failed to decrypt ${event.eventId} reason: $mxCryptoError")
+ Timber.v("## CRYPTO | internalDecryptEvent : Failed to decrypt ${event.eventId} reason: $mxCryptoError")
if (algorithm == MXCRYPTO_ALGORITHM_OLM) {
if (mxCryptoError is MXCryptoError.Base
&& mxCryptoError.errorType == MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE) {
@@ -119,7 +119,7 @@ internal class EventDecryptor @Inject constructor(
markOlmSessionForUnwedging(event.senderId ?: "", it)
}
?: run {
- Timber.i("## CRYPTO | internalDecryptEvent() : Failed to find sender crypto device for unwedging")
+ Timber.i("## CRYPTO | internalDecryptEvent() : Failed to find sender crypto device for unwedging")
}
}
}
@@ -137,18 +137,18 @@ internal class EventDecryptor @Inject constructor(
val lastForcedDate = lastNewSessionForcedDates.getObject(senderId, deviceKey) ?: 0
val now = System.currentTimeMillis()
if (now - lastForcedDate < DefaultCryptoService.CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS) {
- Timber.w("## CRYPTO | markOlmSessionForUnwedging: New session already forced with device at $lastForcedDate. Not forcing another")
+ Timber.w("## CRYPTO | markOlmSessionForUnwedging: New session already forced with device at $lastForcedDate. Not forcing another")
return
}
- Timber.i("## CRYPTO | markOlmSessionForUnwedging from $senderId:${deviceInfo.deviceId}")
+ Timber.i("## CRYPTO | markOlmSessionForUnwedging from $senderId:${deviceInfo.deviceId}")
lastNewSessionForcedDates.setObject(senderId, deviceKey, now)
// offload this from crypto thread (?)
cryptoCoroutineScope.launch(coroutineDispatchers.computation) {
val ensured = ensureOlmSessionsForDevicesAction.handle(mapOf(senderId to listOf(deviceInfo)), force = true)
- Timber.i("## CRYPTO | markOlmSessionForUnwedging() : ensureOlmSessionsForDevicesAction isEmpty:${ensured.isEmpty}")
+ Timber.i("## CRYPTO | markOlmSessionForUnwedging() : ensureOlmSessionsForDevicesAction isEmpty:${ensured.isEmpty}")
// Now send a blank message on that session so the other side knows about it.
// (The keyshare request is sent in the clear so that won't do)
@@ -161,13 +161,13 @@ internal class EventDecryptor @Inject constructor(
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
val sendToDeviceMap = MXUsersDevicesMap()
sendToDeviceMap.setObject(senderId, deviceInfo.deviceId, encodedPayload)
- Timber.i("## CRYPTO | markOlmSessionForUnwedging() : sending dummy to $senderId:${deviceInfo.deviceId}")
+ Timber.i("## CRYPTO | markOlmSessionForUnwedging() : sending dummy to $senderId:${deviceInfo.deviceId}")
withContext(coroutineDispatchers.io) {
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
try {
sendToDeviceTask.execute(sendToDeviceParams)
} catch (failure: Throwable) {
- Timber.e(failure, "## CRYPTO | markOlmSessionForUnwedging() : failed to send dummy to $senderId:${deviceInfo.deviceId}")
+ Timber.e(failure, "## CRYPTO | markOlmSessionForUnwedging() : failed to send dummy to $senderId:${deviceInfo.deviceId}")
}
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt
index 787d16defc..a29ac457fb 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt
@@ -74,7 +74,7 @@ internal class MXMegolmDecryption(private val userId: String,
@Throws(MXCryptoError::class)
private fun decryptEvent(event: Event, timeline: String, requestKeysOnFail: Boolean): MXEventDecryptionResult {
- Timber.v("## CRYPTO | decryptEvent ${event.eventId} , requestKeysOnFail:$requestKeysOnFail")
+ Timber.v("## CRYPTO | decryptEvent ${event.eventId}, requestKeysOnFail:$requestKeysOnFail")
if (event.roomId.isNullOrBlank()) {
throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON)
}
@@ -360,7 +360,7 @@ internal class MXMegolmDecryption(private val userId: String,
},
{
// TODO
- Timber.e(it, "## CRYPTO | shareKeysWithDevice: failed to get session for request $body")
+ Timber.e(it, "## CRYPTO | shareKeysWithDevice: failed to get session for request $body")
}
)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt
index 697711d051..a756444475 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt
@@ -80,9 +80,9 @@ internal class MXMegolmEncryption(
eventType: String,
userIds: List): Content {
val ts = System.currentTimeMillis()
- Timber.v("## CRYPTO | encryptEventContent : getDevicesInRoom")
+ Timber.v("## CRYPTO | encryptEventContent : getDevicesInRoom")
val devices = getDevicesInRoom(userIds)
- Timber.v("## CRYPTO | encryptEventContent ${System.currentTimeMillis() - ts}: getDevicesInRoom ${devices.allowedDevices.map}")
+ Timber.v("## CRYPTO | encryptEventContent ${System.currentTimeMillis() - ts}: getDevicesInRoom ${devices.allowedDevices.map}")
val outboundSession = ensureOutboundSession(devices.allowedDevices)
return encryptContent(outboundSession, eventType, eventContent)
@@ -91,7 +91,7 @@ internal class MXMegolmEncryption(
// annoyingly we have to serialize again the saved outbound session to store message index :/
// if not we would see duplicate message index errors
olmDevice.storeOutboundGroupSessionForRoom(roomId, outboundSession.sessionId)
- Timber.v("## CRYPTO | encryptEventContent: Finished in ${System.currentTimeMillis() - ts} millis")
+ Timber.v("## CRYPTO | encryptEventContent: Finished in ${System.currentTimeMillis() - ts} millis")
}
}
@@ -118,13 +118,13 @@ internal class MXMegolmEncryption(
override suspend fun preshareKey(userIds: List) {
val ts = System.currentTimeMillis()
- Timber.v("## CRYPTO | preshareKey : getDevicesInRoom")
+ Timber.v("## CRYPTO | preshareKey : getDevicesInRoom")
val devices = getDevicesInRoom(userIds)
val outboundSession = ensureOutboundSession(devices.allowedDevices)
notifyWithheldForSession(devices.withHeldDevices, outboundSession)
- Timber.v("## CRYPTO | preshareKey ${System.currentTimeMillis() - ts} millis")
+ Timber.v("## CRYPTO | preshareKey ${System.currentTimeMillis() - ts} millis")
}
/**
@@ -133,7 +133,7 @@ internal class MXMegolmEncryption(
* @return the session description
*/
private fun prepareNewSessionInRoom(): MXOutboundSessionInfo {
- Timber.v("## CRYPTO | prepareNewSessionInRoom() ")
+ Timber.v("## CRYPTO | prepareNewSessionInRoom() ")
val sessionId = olmDevice.createOutboundGroupSessionForRoom(roomId)
val keysClaimedMap = HashMap()
@@ -153,7 +153,7 @@ internal class MXMegolmEncryption(
* @param devicesInRoom the devices list
*/
private suspend fun ensureOutboundSession(devicesInRoom: MXUsersDevicesMap): MXOutboundSessionInfo {
- Timber.v("## CRYPTO | ensureOutboundSession start")
+ Timber.v("## CRYPTO | ensureOutboundSession start")
var session = outboundSession
if (session == null
// Need to make a brand new session?
@@ -190,7 +190,7 @@ internal class MXMegolmEncryption(
devicesByUsers: Map>) {
// nothing to send, the task is done
if (devicesByUsers.isEmpty()) {
- Timber.v("## CRYPTO | shareKey() : nothing more to do")
+ Timber.v("## CRYPTO | shareKey() : nothing more to do")
return
}
// reduce the map size to avoid request timeout when there are too many devices (Users size * devices per user)
@@ -203,7 +203,7 @@ internal class MXMegolmEncryption(
break
}
}
- Timber.v("## CRYPTO | shareKey() ; sessionId<${session.sessionId}> userId ${subMap.keys}")
+ Timber.v("## CRYPTO | shareKey() ; sessionId<${session.sessionId}> userId ${subMap.keys}")
shareUserDevicesKey(session, subMap)
val remainingDevices = devicesByUsers - subMap.keys
shareKey(session, remainingDevices)
@@ -232,11 +232,11 @@ internal class MXMegolmEncryption(
payload["content"] = submap
var t0 = System.currentTimeMillis()
- Timber.v("## CRYPTO | shareUserDevicesKey() : starts")
+ Timber.v("## CRYPTO | shareUserDevicesKey() : starts")
val results = ensureOlmSessionsForDevicesAction.handle(devicesByUser)
Timber.v(
- """## CRYPTO | shareUserDevicesKey(): ensureOlmSessionsForDevices succeeds after ${System.currentTimeMillis() - t0} ms"""
+ """## CRYPTO | shareUserDevicesKey(): ensureOlmSessionsForDevices succeeds after ${System.currentTimeMillis() - t0} ms"""
.trimMargin()
)
val contentMap = MXUsersDevicesMap()
@@ -257,7 +257,7 @@ internal class MXMegolmEncryption(
noOlmToNotify.add(UserDevice(userId, deviceID))
continue
}
- Timber.i("## CRYPTO | shareUserDevicesKey() : Add to share keys contentMap for $userId:$deviceID")
+ Timber.i("## CRYPTO | shareUserDevicesKey() : Add to share keys contentMap for $userId:$deviceID")
contentMap.setObject(userId, deviceID, messageEncrypter.encryptMessage(payload, listOf(sessionResult.deviceInfo)))
haveTargets = true
}
@@ -289,17 +289,17 @@ internal class MXMegolmEncryption(
if (haveTargets) {
t0 = System.currentTimeMillis()
- Timber.i("## CRYPTO | shareUserDevicesKey() ${session.sessionId} : has target")
+ Timber.i("## CRYPTO | shareUserDevicesKey() ${session.sessionId} : has target")
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, contentMap)
try {
sendToDeviceTask.execute(sendToDeviceParams)
- Timber.i("## CRYPTO | shareUserDevicesKey() : sendToDevice succeeds after ${System.currentTimeMillis() - t0} ms")
+ Timber.i("## CRYPTO | shareUserDevicesKey() : sendToDevice succeeds after ${System.currentTimeMillis() - t0} ms")
} catch (failure: Throwable) {
// What to do here...
- Timber.e("## CRYPTO | shareUserDevicesKey() : Failed to share session <${session.sessionId}> with $devicesByUser ")
+ Timber.e("## CRYPTO | shareUserDevicesKey() : Failed to share session <${session.sessionId}> with $devicesByUser ")
}
} else {
- Timber.i("## CRYPTO | shareUserDevicesKey() : no need to sharekey")
+ Timber.i("## CRYPTO | shareUserDevicesKey() : no need to sharekey")
}
if (noOlmToNotify.isNotEmpty()) {
@@ -317,7 +317,7 @@ internal class MXMegolmEncryption(
sessionId: String,
senderKey: String?,
code: WithHeldCode) {
- Timber.i("## CRYPTO | notifyKeyWithHeld() :sending withheld key for $targets session:$sessionId and code $code")
+ Timber.i("## CRYPTO | notifyKeyWithHeld() :sending withheld key for $targets session:$sessionId and code $code")
val withHeldContent = RoomKeyWithHeldContent(
roomId = roomId,
senderKey = senderKey,
@@ -336,7 +336,7 @@ internal class MXMegolmEncryption(
try {
sendToDeviceTask.execute(params)
} catch (failure: Throwable) {
- Timber.e("## CRYPTO | notifyKeyWithHeld() : Failed to notify withheld key for $targets session: $sessionId ")
+ Timber.e("## CRYPTO | notifyKeyWithHeld() : Failed to notify withheld key for $targets session: $sessionId ")
}
}
@@ -473,7 +473,7 @@ internal class MXMegolmEncryption(
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
val sendToDeviceMap = MXUsersDevicesMap()
sendToDeviceMap.setObject(userId, deviceId, encodedPayload)
- Timber.i("## CRYPTO | reshareKey() : sending session $sessionId to $userId:$deviceId")
+ Timber.i("## CRYPTO | reshareKey() : sending session $sessionId to $userId:$deviceId")
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
return try {
sendToDeviceTask.execute(sendToDeviceParams)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/HkdfSha256.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/HkdfSha256.kt
index 6d52e682bc..6839ccd326 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/HkdfSha256.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/HkdfSha256.kt
@@ -57,7 +57,7 @@ object HkdfSha256 {
/*
The output OKM is calculated as follows:
- Notation | -> When the message is composed of several elements we use concatenation (denoted |) in the second argument;
+ Notation | -> When the message is composed of several elements we use concatenation (denoted |) in the second argument;
N = ceil(L/HashLen)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt
index c7885ce449..4bf01a2809 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt
@@ -345,7 +345,7 @@ internal abstract class SASDefaultVerificationTransaction(
}
protected fun hashUsingAgreedHashMethod(toHash: String): String? {
- if ("sha256" == accepted?.hash?.toLowerCase(Locale.ROOT)) {
+ if ("sha256" == accepted?.hash?.lowercase(Locale.ROOT)) {
val olmUtil = OlmUtility()
val hashBytes = olmUtil.sha256(toHash)
olmUtil.releaseUtility()
@@ -355,7 +355,7 @@ internal abstract class SASDefaultVerificationTransaction(
}
private fun macUsingAgreedMethod(message: String, info: String): String? {
- return when (accepted?.messageAuthenticationCode?.toLowerCase(Locale.ROOT)) {
+ return when (accepted?.messageAuthenticationCode?.lowercase(Locale.ROOT)) {
SAS_MAC_SHA256_LONGKDF -> getSAS().calculateMacLongKdf(message, info)
SAS_MAC_SHA256 -> getSAS().calculateMac(message, info)
else -> null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt
index 6bc3483e65..76e88442b6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt
@@ -48,7 +48,7 @@ fun QrCodeData.toEncodedString(): String {
// TransactionId
transactionId.forEach {
- result += it.toByte()
+ result += it.code.toByte()
}
// Keys
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 05213b40e5..d810c8b1a8 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
@@ -20,6 +20,7 @@ import io.realm.DynamicRealm
import io.realm.FieldAttribute
import io.realm.RealmMigration
import org.matrix.android.sdk.api.session.events.model.EventType
+import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
@@ -33,9 +34,9 @@ import org.matrix.android.sdk.internal.database.model.RoomEntityFields
import org.matrix.android.sdk.internal.database.model.RoomMembersLoadStatusType
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.RoomTagEntityFields
-import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
import org.matrix.android.sdk.internal.database.model.SpaceChildSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.SpaceParentSummaryEntityFields
+import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
import org.matrix.android.sdk.internal.di.MoshiProvider
import timber.log.Timber
import javax.inject.Inject
@@ -43,7 +44,7 @@ import javax.inject.Inject
class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
companion object {
- const val SESSION_STORE_SCHEMA_VERSION = 11L
+ const val SESSION_STORE_SCHEMA_VERSION = 13L
}
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
@@ -60,6 +61,8 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
if (oldVersion <= 8) migrateTo9(realm)
if (oldVersion <= 9) migrateTo10(realm)
if (oldVersion <= 10) migrateTo11(realm)
+ if (oldVersion <= 11) migrateTo12(realm)
+ if (oldVersion <= 12) migrateTo13(realm)
}
private fun migrateTo1(realm: DynamicRealm) {
@@ -144,10 +147,6 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
Timber.d("Step 7 -> 8")
val editionOfEventSchema = realm.schema.create("EditionOfEvent")
- .apply {
- // setEmbedded does not return `this`...
- isEmbedded = true
- }
.addField(EditionOfEventFields.CONTENT, String::class.java)
.addField(EditionOfEventFields.EVENT_ID, String::class.java)
.setRequired(EditionOfEventFields.EVENT_ID, true)
@@ -162,6 +161,10 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
?.removeField("lastEditTs")
?.removeField("sourceLocalEchoEvents")
?.addRealmListField(EditAggregatedSummaryEntityFields.EDITIONS.`$`, editionOfEventSchema)
+
+ // This has to be done once a parent use the model as a child
+ // See https://github.com/realm/realm-java/issues/7402
+ editionOfEventSchema.isEmbedded = true
}
private fun migrateTo9(realm: DynamicRealm) {
@@ -247,4 +250,39 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
realm.schema.get("EventEntity")
?.addField(EventEntityFields.SEND_STATE_DETAILS, String::class.java)
}
+
+ private fun migrateTo12(realm: DynamicRealm) {
+ Timber.d("Step 11 -> 12")
+
+ val joinRulesContentAdapter = MoshiProvider.providesMoshi().adapter(RoomJoinRulesContent::class.java)
+ realm.schema.get("RoomSummaryEntity")
+ ?.addField(RoomSummaryEntityFields.JOIN_RULES_STR, String::class.java)
+ ?.transform { obj ->
+ val joinRulesEvent = realm.where("CurrentStateEventEntity")
+ .equalTo(CurrentStateEventEntityFields.ROOM_ID, obj.getString(RoomSummaryEntityFields.ROOM_ID))
+ .equalTo(CurrentStateEventEntityFields.TYPE, EventType.STATE_ROOM_JOIN_RULES)
+ .findFirst()
+
+ val roomJoinRules = joinRulesEvent?.getObject(CurrentStateEventEntityFields.ROOT.`$`)
+ ?.getString(EventEntityFields.CONTENT)?.let {
+ joinRulesContentAdapter.fromJson(it)?.joinRules
+ }
+
+ obj.setString(RoomSummaryEntityFields.JOIN_RULES_STR, roomJoinRules?.name)
+ }
+
+ realm.schema.get("SpaceChildSummaryEntity")
+ ?.addField(SpaceChildSummaryEntityFields.SUGGESTED, Boolean::class.java)
+ ?.setNullable(SpaceChildSummaryEntityFields.SUGGESTED, true)
+ }
+
+ private fun migrateTo13(realm: DynamicRealm) {
+ Timber.d("Step 12 -> 13")
+
+ // Fix issue with the nightly build. Eventually play again the migration which has been included in migrateTo12()
+ realm.schema.get("SpaceChildSummaryEntity")
+ ?.takeIf { !it.hasField(SpaceChildSummaryEntityFields.SUGGESTED) }
+ ?.addField(SpaceChildSummaryEntityFields.SUGGESTED, Boolean::class.java)
+ ?.setNullable(SpaceChildSummaryEntityFields.SUGGESTED, true)
+ }
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt
index 92aff0a140..fbecbf37be 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt
@@ -44,6 +44,7 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa
name = roomSummaryEntity.name ?: "",
topic = roomSummaryEntity.topic ?: "",
avatarUrl = roomSummaryEntity.avatarUrl ?: "",
+ joinRules = roomSummaryEntity.joinRules,
isDirect = roomSummaryEntity.isDirect,
directUserId = roomSummaryEntity.directUserId,
latestPreviewableEvent = latestEvent,
@@ -88,7 +89,8 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa
order = it.order,
autoJoin = it.autoJoin ?: false,
viaServers = it.viaServers.toList(),
- parentRoomId = roomSummaryEntity.roomId
+ parentRoomId = roomSummaryEntity.roomId,
+ suggested = it.suggested
)
},
flattenParentIds = roomSummaryEntity.flattenParentIds?.split("|") ?: emptyList()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomSummaryEntity.kt
index 4f47032c4d..1001f9cd66 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomSummaryEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomSummaryEntity.kt
@@ -21,7 +21,9 @@ import io.realm.RealmObject
import io.realm.annotations.Index
import io.realm.annotations.PrimaryKey
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
+import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.VersioningState
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
@@ -242,6 +244,19 @@ internal open class RoomSummaryEntity(
}
}
+ private var joinRulesStr: String? = null
+ var joinRules: RoomJoinRules?
+ get() {
+ return joinRulesStr?.let {
+ tryOrNull { RoomJoinRules.valueOf(it) }
+ }
+ }
+ set(value) {
+ if (value?.name != joinRulesStr) {
+ joinRulesStr = value?.name
+ }
+ }
+
var roomEncryptionTrustLevel: RoomEncryptionTrustLevel?
get() {
return roomEncryptionTrustLevelStr?.let {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceChildSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceChildSummaryEntity.kt
index 982c9ece6a..ce1afbb507 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceChildSummaryEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceChildSummaryEntity.kt
@@ -29,6 +29,8 @@ internal open class SpaceChildSummaryEntity(
var autoJoin: Boolean? = null,
+ var suggested: Boolean? = null,
+
var childRoomId: String? = null,
// Link to the actual space summary if it is known locally
var childSummaryEntity: RoomSummaryEntity? = null,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt
index 891858d857..a284d976d0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt
@@ -291,7 +291,7 @@ internal class DefaultFileService @Inject constructor(
Timber.v("Get size of ${it.absolutePath}")
true
}
- .sumBy { it.length().toInt() }
+ .sumOf { it.length().toInt() }
}
override fun clearCache() {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt
index 4f6e906766..114695062c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt
@@ -117,7 +117,7 @@ internal class DefaultIdentityBulkLookupTask @Inject constructor(
return withOlmUtility { olmUtility ->
threePids.map { threePid ->
base64ToBase64Url(
- olmUtility.sha256(threePid.value.toLowerCase(Locale.ROOT)
+ olmUtility.sha256(threePid.value.lowercase(Locale.ROOT)
+ " " + threePid.toMedium() + " " + pepper)
)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt
index 71a6e224bf..970752449a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt
@@ -18,19 +18,13 @@ package org.matrix.android.sdk.internal.session.permalinks
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.permalinks.PermalinkService.Companion.MATRIX_TO_URL_BASE
-import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
-import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.internal.di.UserId
-import org.matrix.android.sdk.internal.session.room.RoomGetter
-import java.net.URLEncoder
import javax.inject.Inject
-import javax.inject.Provider
internal class PermalinkFactory @Inject constructor(
@UserId
private val userId: String,
- // Use a provider to fix circular Dagger dependency
- private val roomGetterProvider: Provider
+ private val viaParameterFinder: ViaParameterFinder
) {
fun createPermalink(event: Event): String? {
@@ -50,12 +44,12 @@ internal class PermalinkFactory @Inject constructor(
return if (roomId.isEmpty()) {
null
} else {
- MATRIX_TO_URL_BASE + escape(roomId) + computeViaParams(userId, roomId)
+ MATRIX_TO_URL_BASE + escape(roomId) + viaParameterFinder.computeViaParams(userId, roomId)
}
}
fun createPermalink(roomId: String, eventId: String): String {
- return MATRIX_TO_URL_BASE + escape(roomId) + "/" + escape(eventId) + computeViaParams(userId, roomId)
+ return MATRIX_TO_URL_BASE + escape(roomId) + "/" + escape(eventId) + viaParameterFinder.computeViaParams(userId, roomId)
}
fun getLinkedId(url: String): String? {
@@ -66,25 +60,6 @@ internal class PermalinkFactory @Inject constructor(
} else null
}
- /**
- * Compute the via parameters.
- * Take up to 3 homeserver domains, taking the most representative one regarding room members and including the
- * current user one.
- */
- private fun computeViaParams(userId: String, roomId: String): String {
- val userHomeserver = userId.substringAfter(":")
- return getUserIdsOfJoinedMembers(roomId)
- .map { it.substringAfter(":") }
- .groupBy { it }
- .mapValues { it.value.size }
- .toMutableMap()
- // Ensure the user homeserver will be included
- .apply { this[userHomeserver] = Int.MAX_VALUE }
- .let { map -> map.keys.sortedByDescending { map[it] } }
- .take(3)
- .joinToString(prefix = "?via=", separator = "&via=") { URLEncoder.encode(it, "utf-8") }
- }
-
/**
* Escape '/' in id, because it is used as a separator
*
@@ -104,15 +79,4 @@ internal class PermalinkFactory @Inject constructor(
private fun unescape(id: String): String {
return id.replace("%2F", "/")
}
-
- /**
- * Get a set of userIds of joined members of a room
- */
- private fun getUserIdsOfJoinedMembers(roomId: String): Set {
- return roomGetterProvider.get().getRoom(roomId)
- ?.getRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.JOIN) })
- ?.map { it.userId }
- .orEmpty()
- .toSet()
- }
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt
new file mode 100644
index 0000000000..0da60e9ba2
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2021 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.session.permalinks
+
+import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
+import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.internal.di.UserId
+import org.matrix.android.sdk.internal.session.room.RoomGetter
+import java.net.URLEncoder
+import javax.inject.Inject
+import javax.inject.Provider
+
+internal class ViaParameterFinder @Inject constructor(
+ @UserId private val userId: String,
+ private val roomGetterProvider: Provider
+) {
+
+ fun computeViaParams(roomId: String, max: Int): List {
+ return computeViaParams(userId, roomId, max)
+ }
+
+ /**
+ * Compute the via parameters.
+ * Take up to 3 homeserver domains, taking the most representative one regarding room members and including the
+ * current user one.
+ */
+ fun computeViaParams(userId: String, roomId: String): String {
+ return computeViaParams(userId, roomId, 3)
+ .joinToString(prefix = "?via=", separator = "&via=") { URLEncoder.encode(it, "utf-8") }
+ }
+
+ fun computeViaParams(userId: String, roomId: String, max: Int): List {
+ val userHomeserver = userId.substringAfter(":")
+ return getUserIdsOfJoinedMembers(roomId)
+ .map { it.substringAfter(":") }
+ .groupBy { it }
+ .mapValues { it.value.size }
+ .toMutableMap()
+ // Ensure the user homeserver will be included
+ .apply { this[userHomeserver] = Int.MAX_VALUE }
+ .let { map -> map.keys.sortedByDescending { map[it] } }
+ .take(max)
+ }
+
+ /**
+ * Get a set of userIds of joined members of a room
+ */
+ private fun getUserIdsOfJoinedMembers(roomId: String): Set {
+ return roomGetterProvider.get().getRoom(roomId)
+ ?.getRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.JOIN) })
+ ?.map { it.userId }
+ .orEmpty()
+ .toSet()
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt
index 5113b821e8..485a4973ca 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt
@@ -33,6 +33,7 @@ internal interface ProfileAPI {
* Get the combined profile information for this user.
* This API may be used to fetch the user's own profile information or other users; either locally or on remote homeservers.
* This API may return keys which are not limited to displayname or avatar_url.
+ * If server is configured as limit_profile_requests_to_users_who_share_rooms: true then response can be HTTP 403.
* @param userId the user id to fetch profile info
*/
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "profile/{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 c6059f84ea..a5e066dae8 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
@@ -40,6 +40,7 @@ import org.matrix.android.sdk.api.session.search.SearchResult
import org.matrix.android.sdk.api.session.space.Space
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
+import org.matrix.android.sdk.internal.session.permalinks.ViaParameterFinder
import org.matrix.android.sdk.internal.session.room.state.SendStateTask
import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource
import org.matrix.android.sdk.internal.session.search.SearchTask
@@ -66,6 +67,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
private val roomMembersService: MembershipService,
private val roomPushRuleService: RoomPushRuleService,
private val sendStateTask: SendStateTask,
+ private val viaParameterFinder: ViaParameterFinder,
private val searchTask: SearchTask) :
Room,
TimelineService by timelineService,
@@ -154,6 +156,6 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
override fun asSpace(): Space? {
if (roomSummary()?.roomType != RoomType.SPACE) return null
- return DefaultSpace(this, roomSummaryDataSource)
+ return DefaultSpace(this, roomSummaryDataSource, viaParameterFinder)
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt
index 90640b4700..3f743c2922 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt
@@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.room
import org.matrix.android.sdk.api.session.crypto.CryptoService
import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.internal.session.SessionScope
+import org.matrix.android.sdk.internal.session.permalinks.ViaParameterFinder
import org.matrix.android.sdk.internal.session.room.alias.DefaultAliasService
import org.matrix.android.sdk.internal.session.room.call.DefaultRoomCallService
import org.matrix.android.sdk.internal.session.room.draft.DefaultDraftService
@@ -60,6 +61,7 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService:
private val membershipServiceFactory: DefaultMembershipService.Factory,
private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory,
private val sendStateTask: SendStateTask,
+ private val viaParameterFinder: ViaParameterFinder,
private val searchTask: SearchTask) :
RoomFactory {
@@ -83,7 +85,8 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService:
roomMembersService = membershipServiceFactory.create(roomId),
roomPushRuleService = roomPushRuleServiceFactory.create(roomId),
sendStateTask = sendStateTask,
- searchTask = searchTask
+ searchTask = searchTask,
+ viaParameterFinder = viaParameterFinder
)
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt
index f580a7f354..cac0d715f5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt
@@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomAliasesContent
import org.matrix.android.sdk.api.session.room.model.RoomCanonicalAliasContent
+import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
import org.matrix.android.sdk.api.session.room.model.RoomNameContent
import org.matrix.android.sdk.api.session.room.model.RoomTopicContent
import org.matrix.android.sdk.api.session.room.model.RoomType
@@ -104,6 +105,7 @@ internal class RoomSummaryUpdater @Inject constructor(
val lastCanonicalAliasEvent = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_CANONICAL_ALIAS, stateKey = "")?.root
val lastAliasesEvent = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_ALIASES, stateKey = "")?.root
val roomCreateEvent = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_CREATE, stateKey = "")?.root
+ val joinRulesEvent = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_JOIN_RULES, stateKey = "")?.root
val roomType = ContentMapper.map(roomCreateEvent?.content).toModel()?.type
roomSummaryEntity.roomType = roomType
@@ -130,6 +132,7 @@ internal class RoomSummaryUpdater @Inject constructor(
roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(realm, roomId)
roomSummaryEntity.name = ContentMapper.map(lastNameEvent?.content).toModel()?.name
roomSummaryEntity.topic = ContentMapper.map(lastTopicEvent?.content).toModel()?.topic
+ roomSummaryEntity.joinRules = ContentMapper.map(joinRulesEvent?.content).toModel()?.joinRules
roomSummaryEntity.latestPreviewableEvent = latestPreviewableEvent
roomSummaryEntity.canonicalAlias = ContentMapper.map(lastCanonicalAliasEvent?.content).toModel()
?.canonicalAlias
@@ -361,6 +364,8 @@ internal class RoomSummaryUpdater @Inject constructor(
realm.where(RoomSummaryEntity::class.java)
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, listOf(Membership.JOIN))
.notEqualTo(RoomSummaryEntityFields.ROOM_TYPE, RoomType.SPACE)
+ // also we do not count DM in here, because home space will already show them
+ .equalTo(RoomSummaryEntityFields.IS_DIRECT, false)
.contains(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, space.roomId)
.findAll().forEach {
highlightCount += it.highlightCount
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt
index 93cb9d9d34..70c52bf4ae 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt
@@ -24,11 +24,13 @@ import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.space.Space
import org.matrix.android.sdk.api.session.space.model.SpaceChildContent
+import org.matrix.android.sdk.internal.session.permalinks.ViaParameterFinder
import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource
internal class DefaultSpace(
private val room: Room,
- private val spaceSummaryDataSource: RoomSummaryDataSource
+ private val spaceSummaryDataSource: RoomSummaryDataSource,
+ private val viaParameterFinder: ViaParameterFinder
) : Space {
override fun asRoom(): Room {
@@ -46,15 +48,17 @@ internal class DefaultSpace(
}
override suspend fun addChildren(roomId: String,
- viaServers: List,
+ viaServers: List?,
order: String?,
autoJoin: Boolean,
suggested: Boolean?) {
+ // Find best via
+
room.sendStateEvent(
eventType = EventType.STATE_SPACE_CHILD,
stateKey = roomId,
body = SpaceChildContent(
- via = viaServers,
+ via = viaServers ?: viaParameterFinder.computeViaParams(roomId, 3),
autoJoin = autoJoin,
order = order,
suggested = suggested
@@ -63,20 +67,21 @@ internal class DefaultSpace(
}
override suspend fun removeChildren(roomId: String) {
- val existing = room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId))
- .firstOrNull()
- ?.content.toModel()
- ?: // should we throw here?
- return
+// val existing = room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId))
+// .firstOrNull()
+// ?.content.toModel()
+// ?: // should we throw here?
+// return
// edit state event and set via to null
room.sendStateEvent(
eventType = EventType.STATE_SPACE_CHILD,
stateKey = roomId,
body = SpaceChildContent(
- order = existing.order,
+ order = null,
via = null,
- autoJoin = existing.autoJoin
+ autoJoin = null,
+ suggested = null
).toContent()
)
}
@@ -94,7 +99,8 @@ internal class DefaultSpace(
body = SpaceChildContent(
order = order,
via = existing.via,
- autoJoin = existing.autoJoin
+ autoJoin = existing.autoJoin,
+ suggested = existing.suggested
).toContent()
)
}
@@ -105,6 +111,11 @@ internal class DefaultSpace(
?.content.toModel()
?: throw IllegalArgumentException("$roomId is not a child of this space")
+ if (existing.autoJoin == autoJoin) {
+ // nothing to do?
+ return
+ }
+
// edit state event and set via to null
room.sendStateEvent(
eventType = EventType.STATE_SPACE_CHILD,
@@ -112,7 +123,31 @@ internal class DefaultSpace(
body = SpaceChildContent(
order = existing.order,
via = existing.via,
- autoJoin = autoJoin
+ autoJoin = autoJoin,
+ suggested = existing.suggested
+ ).toContent()
+ )
+ }
+
+ override suspend fun setChildrenSuggested(roomId: String, suggested: Boolean) {
+ val existing = room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId))
+ .firstOrNull()
+ ?.content.toModel()
+ ?: throw IllegalArgumentException("$roomId is not a child of this space")
+
+ if (existing.suggested == suggested) {
+ // nothing to do?
+ return
+ }
+ // edit state event and set via to null
+ room.sendStateEvent(
+ eventType = EventType.STATE_SPACE_CHILD,
+ stateKey = roomId,
+ body = SpaceChildContent(
+ order = existing.order,
+ via = existing.via,
+ autoJoin = existing.autoJoin,
+ suggested = suggested
).toContent()
)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt
index 8fdc563edb..f7fd77c528 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt
@@ -127,24 +127,31 @@ internal class DefaultSpaceService @Inject constructor(
),
second = response.rooms
?.filter { it.roomId != spaceId }
- ?.map { childSummary ->
- val childStateEv = response.events
- ?.firstOrNull { it.stateKey == childSummary.roomId && it.type == EventType.STATE_SPACE_CHILD }
- val childStateEvContent = childStateEv?.content.toModel()
- SpaceChildInfo(
- childRoomId = childSummary.roomId,
- isKnown = true,
- roomType = childSummary.roomType,
- name = childSummary.name,
- topic = childSummary.topic,
- avatarUrl = childSummary.avatarUrl,
- order = childStateEvContent?.order,
- autoJoin = childStateEvContent?.autoJoin ?: false,
- viaServers = childStateEvContent?.via ?: emptyList(),
- activeMemberCount = childSummary.numJoinedMembers,
- parentRoomId = childStateEv?.roomId
- )
- }.orEmpty()
+ ?.flatMap { childSummary ->
+ response.events
+ ?.filter { it.stateKey == childSummary.roomId && it.type == EventType.STATE_SPACE_CHILD }
+ ?.mapNotNull { childStateEv ->
+ // create a child entry for everytime this room is the child of a space
+ // beware that a room could appear then twice in this list
+ childStateEv.content.toModel()?.let { childStateEvContent ->
+ SpaceChildInfo(
+ childRoomId = childSummary.roomId,
+ isKnown = true,
+ roomType = childSummary.roomType,
+ name = childSummary.name,
+ topic = childSummary.topic,
+ avatarUrl = childSummary.avatarUrl,
+ order = childStateEvContent.order,
+ autoJoin = childStateEvContent.autoJoin ?: false,
+ viaServers = childStateEvContent.via.orEmpty(),
+ activeMemberCount = childSummary.numJoinedMembers,
+ parentRoomId = childStateEv.roomId,
+ suggested = childStateEvContent.suggested
+ )
+ }
+ }.orEmpty()
+ }
+ .orEmpty()
)
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/JoinSpaceTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/JoinSpaceTask.kt
index 5e1b829249..e9d5ba5193 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/JoinSpaceTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/JoinSpaceTask.kt
@@ -83,7 +83,7 @@ internal class DefaultJoinSpaceTask @Inject constructor(
Timber.v("## Space: > Sync done ...")
// after that i should have the children (? do I need to paginate to get state)
val summary = roomSummaryDataSource.getSpaceSummary(params.roomIdOrAlias)
- Timber.v("## Space: Found space summary Name:[${summary?.name}] children: ${summary?.spaceChildren?.size}")
+ Timber.v("## Space: Found space summary Name:[${summary?.name}] children: ${summary?.spaceChildren?.size}")
summary?.spaceChildren?.forEach {
// val childRoomSummary = it.roomSummary ?: return@forEach
Timber.v("## Space: Processing child :[${it.childRoomId}] autoJoin:${it.autoJoin}")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/CryptoSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/CryptoSyncHandler.kt
index ae60faf905..411a9c5c06 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/CryptoSyncHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/CryptoSyncHandler.kt
@@ -64,7 +64,7 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService:
* @return true if the event has been decrypted
*/
private fun decryptToDeviceEvent(event: Event, timelineId: String?): Boolean {
- Timber.v("## CRYPTO | decryptToDeviceEvent")
+ Timber.v("## CRYPTO | decryptToDeviceEvent")
if (event.getClearType() == EventType.ENCRYPTED) {
var result: MXEventDecryptionResult? = null
try {
@@ -76,7 +76,7 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService:
val deviceId = cryptoService.getCryptoDeviceInfo(event.senderId!!).firstOrNull {
it.identityKey() == senderKey
}?.deviceId ?: senderKey
- Timber.e("## CRYPTO | Failed to decrypt to device event from ${event.senderId}|$deviceId reason:<${event.mCryptoError ?: exception}>")
+ Timber.e("## CRYPTO | Failed to decrypt to device event from ${event.senderId}|$deviceId reason:<${event.mCryptoError ?: exception}>")
}
if (null != result) {
@@ -89,7 +89,7 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService:
return true
} else {
// should not happen
- Timber.e("## CRYPTO | ERROR NULL DECRYPTION RESULT from ${event.senderId}")
+ Timber.e("## CRYPTO | ERROR NULL DECRYPTION RESULT from ${event.senderId}")
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Hash.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Hash.kt
index e19b1bcca7..47f20913ec 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Hash.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Hash.kt
@@ -27,7 +27,7 @@ fun String.md5() = try {
digest.update(toByteArray())
digest.digest()
.joinToString("") { String.format("%02X", it) }
- .toLowerCase(Locale.ROOT)
+ .lowercase(Locale.ROOT)
} catch (exc: Exception) {
// Should not happen, but just in case
hashCode().toString()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringUtils.kt
index 2fabca4be8..aa0b92aa45 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringUtils.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringUtils.kt
@@ -17,6 +17,7 @@
package org.matrix.android.sdk.internal.util
import timber.log.Timber
+import java.util.Locale
/**
* Convert a string to an UTF8 String
@@ -24,7 +25,7 @@ import timber.log.Timber
* @param s the string to convert
* @return the utf-8 string
*/
-fun convertToUTF8(s: String): String {
+internal fun convertToUTF8(s: String): String {
return try {
val bytes = s.toByteArray(Charsets.UTF_8)
String(bytes)
@@ -40,7 +41,7 @@ fun convertToUTF8(s: String): String {
* @param s the string to convert
* @return the utf-16 string
*/
-fun convertFromUTF8(s: String): String {
+internal fun convertFromUTF8(s: String): String {
return try {
val bytes = s.toByteArray()
String(bytes, Charsets.UTF_8)
@@ -56,7 +57,7 @@ fun convertFromUTF8(s: String): String {
* @param subString the string to search for
* @return whether a match was found
*/
-fun String.caseInsensitiveFind(subString: String): Boolean {
+internal fun String.caseInsensitiveFind(subString: String): Boolean {
// add sanity checks
if (subString.isEmpty() || isEmpty()) {
return false
@@ -78,3 +79,14 @@ internal val spaceChars = "[\u00A0\u2000-\u200B\u2800\u3000]".toRegex()
* Strip all the UTF-8 chars which are actually spaces
*/
internal fun String.replaceSpaceChars() = replace(spaceChars, "")
+
+// String.capitalize is now deprecated
+internal fun String.safeCapitalize(): String {
+ return replaceFirstChar { char ->
+ if (char.isLowerCase()) {
+ char.titlecase(Locale.getDefault())
+ } else {
+ char.toString()
+ }
+ }
+}
diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt
index 8f9cc852a7..b55487e8c0 100644
--- a/tools/check/forbidden_strings_in_code.txt
+++ b/tools/check/forbidden_strings_in_code.txt
@@ -161,7 +161,7 @@ Formatter\.formatShortFileSize===1
# android\.text\.TextUtils
### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt
-enum class===99
+enum class===100
### Do not import temporary legacy classes
import org.matrix.android.sdk.internal.legacy.riot===3
diff --git a/tools/release/sign_apk.sh b/tools/release/sign_apk.sh
index 77af5823c4..7697f58ceb 100755
--- a/tools/release/sign_apk.sh
+++ b/tools/release/sign_apk.sh
@@ -17,7 +17,7 @@ PARAM_KEYSTORE_PATH=$1
PARAM_APK=$2
# Other params
-BUILD_TOOLS_VERSION="29.0.3"
+BUILD_TOOLS_VERSION="30.0.3"
MIN_SDK_VERSION=21
echo "Signing APK with build-tools version ${BUILD_TOOLS_VERSION} for min SDK version ${MIN_SDK_VERSION}..."
diff --git a/tools/release/sign_apk_unsafe.sh b/tools/release/sign_apk_unsafe.sh
index b145ad45da..af5b0f0e32 100755
--- a/tools/release/sign_apk_unsafe.sh
+++ b/tools/release/sign_apk_unsafe.sh
@@ -23,7 +23,7 @@ PARAM_KS_PASS=$3
PARAM_KEY_PASS=$4
# Other params
-BUILD_TOOLS_VERSION="29.0.3"
+BUILD_TOOLS_VERSION="30.0.3"
MIN_SDK_VERSION=21
echo "Signing APK with build-tools version ${BUILD_TOOLS_VERSION} for min SDK version ${MIN_SDK_VERSION}..."
diff --git a/vector/build.gradle b/vector/build.gradle
index 3ecdcea524..a9a8ba0924 100644
--- a/vector/build.gradle
+++ b/vector/build.gradle
@@ -14,7 +14,7 @@ kapt {
// Note: 2 digits max for each value
ext.versionMajor = 1
ext.versionMinor = 1
-ext.versionPatch = 7
+ext.versionPatch = 8
static def getGitTimestamp() {
def cmd = 'git show -s --format=%ct'
@@ -297,7 +297,7 @@ dependencies {
def big_image_viewer_version = '1.8.0'
def glide_version = '4.12.0'
def moshi_version = '1.12.0'
- def daggerVersion = '2.35'
+ def daggerVersion = '2.35.1'
def autofill_version = "1.1.0"
def work_version = '2.5.0'
def arch_version = '2.1.0'
@@ -326,7 +326,7 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation "androidx.sharetarget:sharetarget:1.1.0"
implementation 'androidx.core:core-ktx:1.3.2'
- implementation "androidx.media:media:1.3.0"
+ implementation "androidx.media:media:1.3.1"
implementation "org.threeten:threetenbp:1.4.0:no-tzdb"
implementation "com.gabrielittner.threetenbp:lazythreetenbp:0.9.0"
@@ -343,7 +343,7 @@ dependencies {
implementation 'com.facebook.stetho:stetho:1.6.0'
// Phone number https://github.com/google/libphonenumber
- implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.22'
+ implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.23'
// rx
implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
@@ -406,7 +406,7 @@ dependencies {
implementation "com.github.piasy:GlideImageViewFactory:$big_image_viewer_version"
// implementation 'com.github.MikeOrtiz:TouchImageView:3.0.2'
- implementation 'com.github.chrisbanes:PhotoView:2.1.4'
+ implementation 'com.github.chrisbanes:PhotoView:2.3.0'
implementation "com.github.bumptech.glide:glide:$glide_version"
kapt "com.github.bumptech.glide:compiler:$glide_version"
@@ -417,14 +417,14 @@ dependencies {
implementation 'me.leolin:ShortcutBadger:1.1.22@aar'
// Chat effects
- implementation 'nl.dionsegijn:konfetti:1.2.6'
- implementation 'com.github.jetradarmobile:android-snowfall:1.2.0'
+ implementation 'nl.dionsegijn:konfetti:1.3.2'
+ implementation 'com.github.jetradarmobile:android-snowfall:1.2.1'
// DI
implementation "com.google.dagger:dagger:$daggerVersion"
kapt "com.google.dagger:dagger-compiler:$daggerVersion"
// gplay flavor only
- gplayImplementation('com.google.firebase:firebase-messaging:21.1.0') {
+ gplayImplementation('com.google.firebase:firebase-messaging:22.0.0') {
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/sampledata/matrix.json b/vector/sampledata/messages.json
similarity index 57%
rename from vector/sampledata/matrix.json
rename to vector/sampledata/messages.json
index c69e0201ad..8145277f6b 100644
--- a/vector/sampledata/matrix.json
+++ b/vector/sampledata/messages.json
@@ -1,58 +1,22 @@
{
"data": [
{
- "displayName": "Long display name useful to test layout with a long display name",
- "mxid": "@longmatrixidbecausesometimesuserschooselongmxid:matrix.org",
- "message": "William Shakespeare (bapt. 26 April 1564 – 23 April 1616) was an English poet, playwright and actor, widely regarded as the greatest writer in the English language and the world's greatest dramatist. He is often called England's national poet and the \"Bard of Avon\". His extant works, including collaborations, consist of approximately 39 plays, 154 sonnets, two long narrative poems, and a few other verses, some of uncertain authorship. His plays have been translated into every major living language and are performed more often than those of any other playwright.\n\nShakespeare was born and raised in Stratford-upon-Avon, Warwickshire. At the age of 18, he married Anne Hathaway, with whom he had three children: Susanna and twins Hamnet and Judith. Sometime between 1585 and 1592, he began a successful career in London as an actor, writer, and part-owner of a playing company called the Lord Chamberlain's Men, later known as the King's Men. At age 49 (around 1613), he appears to have retired to Stratford, where he died three years later. Few records of Shakespeare's private life survive; this has stimulated considerable speculation about such matters as his physical appearance, his sexuality, his religious beliefs, and whether the works attributed to him were written by others. Such theories are often criticised for failing to adequately note that few records survive of most commoners of the period.\n\nShakespeare produced most of his known works between 1589 and 1613. His early plays were primarily comedies and histories and are regarded as some of the best work produced in these genres. Until about 1608, he wrote mainly tragedies, among them Hamlet, Othello, King Lear, and Macbeth, all considered to be among the finest works in the English language. In the last phase of his life, he wrote tragicomedies (also known as romances) and collaborated with other playwrights.\n\nMany of Shakespeare's plays were published in editions of varying quality and accuracy in his lifetime. However, in 1623, two fellow actors and friends of Shakespeare's, John Heminges and Henry Condell, published a more definitive text known as the First Folio, a posthumous collected edition of Shakespeare's dramatic works that included all but two of his plays. The volume was prefaced with a poem by Ben Jonson, in which Jonson presciently hails Shakespeare in a now-famous quote as \"not of an age, but for all time\".\n\nThroughout the 20th and 21st centuries, Shakespeare's works have been continually adapted and rediscovered by new movements in scholarship and performance. His plays remain popular and are studied, performed, and reinterpreted through various cultural and political contexts around the world.",
- "roomName": "Matrix HQ",
- "roomAlias": "#matrix:matrix.org",
- "spaceName": "Runner's world",
- "roomTopic": "Welcome to Matrix HQ! Here is the rest of the room topic, with a https://www.example.org url and a phone number: 0102030405 which should not be clickable."
+ "message": "William Shakespeare (bapt. 26 April 1564 – 23 April 1616) was an English poet, playwright and actor, widely regarded as the greatest writer in the English language and the world's greatest dramatist. He is often called England's national poet and the \"Bard of Avon\". His extant works, including collaborations, consist of approximately 39 plays, 154 sonnets, two long narrative poems, and a few other verses, some of uncertain authorship. His plays have been translated into every major living language and are performed more often than those of any other playwright.\n\nShakespeare was born and raised in Stratford-upon-Avon, Warwickshire. At the age of 18, he married Anne Hathaway, with whom he had three children: Susanna and twins Hamnet and Judith. Sometime between 1585 and 1592, he began a successful career in London as an actor, writer, and part-owner of a playing company called the Lord Chamberlain's Men, later known as the King's Men. At age 49 (around 1613), he appears to have retired to Stratford, where he died three years later. Few records of Shakespeare's private life survive; this has stimulated considerable speculation about such matters as his physical appearance, his sexuality, his religious beliefs, and whether the works attributed to him were written by others. Such theories are often criticised for failing to adequately note that few records survive of most commoners of the period.\n\nShakespeare produced most of his known works between 1589 and 1613. His early plays were primarily comedies and histories and are regarded as some of the best work produced in these genres. Until about 1608, he wrote mainly tragedies, among them Hamlet, Othello, King Lear, and Macbeth, all considered to be among the finest works in the English language. In the last phase of his life, he wrote tragicomedies (also known as romances) and collaborated with other playwrights.\n\nMany of Shakespeare's plays were published in editions of varying quality and accuracy in his lifetime. However, in 1623, two fellow actors and friends of Shakespeare's, John Heminges and Henry Condell, published a more definitive text known as the First Folio, a posthumous collected edition of Shakespeare's dramatic works that included all but two of his plays. The volume was prefaced with a poem by Ben Jonson, in which Jonson presciently hails Shakespeare in a now-famous quote as \"not of an age, but for all time\".\n\nThroughout the 20th and 21st centuries, Shakespeare's works have been continually adapted and rediscovered by new movements in scholarship and performance. His plays remain popular and are studied, performed, and reinterpreted through various cultural and political contexts around the world."
},
{
- "displayName": "benoit",
- "mxid": "@benoit:matrix.org",
- "message": "Hello!",
- "roomName": "Room name very loooooooong with some details",
- "roomAlias": "#matrix:matrix.org",
- "spaceName": "Matrix Org",
- "roomTopic": "Room topic very loooooooong with some details"
+ "message": "Hello!"
},
{
- "displayName": "ganfra",
- "mxid": "@ganfra:matrix.org",
- "message": "How are you?",
- "roomName": "Room name very loooooooong with some details",
- "roomAlias": "#matrix:matrix.org",
- "spaceName": "Rennes",
- "roomTopic": "Room topic very loooooooong with some details"
+ "message": "How are you?"
},
{
- "displayName": "Manu",
- "mxid": "@manu:matrix.org",
- "message": "Great weather today!",
- "roomName": "Room name very loooooooong with some details",
- "roomAlias": "#matrix:matrix.org",
- "spaceName": "Est London",
- "roomTopic": "Room topic very loooooooong with some details"
+ "message": "Great weather today!"
},
{
- "displayName": "Giom",
- "mxid": "@giom:matrix.org",
- "message": "Let's do a picnic",
- "roomName": "Room name very loooooooong with some details",
- "roomAlias": "#matrix:matrix.org",
- "spaceName": "Element HQ",
- "roomTopic": "Room topic very loooooooong with some details"
+ "message": "Let's do a picnic"
},
{
- "displayName": "Nad",
- "mxid": "@nadonomy:matrix.org",
- "message": "Yes, great idea",
- "roomName": "Room name very loooooooong with some details",
- "roomAlias": "#matrix:matrix.org",
- "spaceName": "My Company",
- "roomTopic": "Room topic very loooooooong with some details"
+ "message": "Yes, great idea"
}
]
}
diff --git a/vector/sampledata/room_round_avatars/0_element_rainbow.png b/vector/sampledata/room_round_avatars/0_element_rainbow.png
new file mode 100644
index 0000000000..2efdc02312
Binary files /dev/null and b/vector/sampledata/room_round_avatars/0_element_rainbow.png differ
diff --git a/vector/sampledata/room_round_avatars/element_black.png b/vector/sampledata/room_round_avatars/element_black.png
new file mode 100644
index 0000000000..3b7430b5c1
Binary files /dev/null and b/vector/sampledata/room_round_avatars/element_black.png differ
diff --git a/vector/sampledata/room_round_avatars/element_ems.png b/vector/sampledata/room_round_avatars/element_ems.png
new file mode 100644
index 0000000000..63cdf3ccae
Binary files /dev/null and b/vector/sampledata/room_round_avatars/element_ems.png differ
diff --git a/vector/sampledata/room_round_avatars/element_multi.png b/vector/sampledata/room_round_avatars/element_multi.png
new file mode 100644
index 0000000000..ab0657768a
Binary files /dev/null and b/vector/sampledata/room_round_avatars/element_multi.png differ
diff --git a/vector/sampledata/room_round_avatars/element_sky.png b/vector/sampledata/room_round_avatars/element_sky.png
new file mode 100644
index 0000000000..16c1be7316
Binary files /dev/null and b/vector/sampledata/room_round_avatars/element_sky.png differ
diff --git a/vector/sampledata/room_round_avatars/element_verde.png b/vector/sampledata/room_round_avatars/element_verde.png
new file mode 100644
index 0000000000..778ad83725
Binary files /dev/null and b/vector/sampledata/room_round_avatars/element_verde.png differ
diff --git a/vector/sampledata/room_round_avatars/element_web.png b/vector/sampledata/room_round_avatars/element_web.png
new file mode 100644
index 0000000000..c99a34f1a2
Binary files /dev/null and b/vector/sampledata/room_round_avatars/element_web.png differ
diff --git a/vector/sampledata/room_round_avatars/element_x.png b/vector/sampledata/room_round_avatars/element_x.png
new file mode 100644
index 0000000000..bc95bf28f3
Binary files /dev/null and b/vector/sampledata/room_round_avatars/element_x.png differ
diff --git a/vector/sampledata/room_round_avatars/matrix.png b/vector/sampledata/room_round_avatars/matrix.png
new file mode 100644
index 0000000000..a3b8f89a8a
Binary files /dev/null and b/vector/sampledata/room_round_avatars/matrix.png differ
diff --git a/vector/sampledata/room_round_avatars/new_vector.png b/vector/sampledata/room_round_avatars/new_vector.png
new file mode 100644
index 0000000000..16a51c6788
Binary files /dev/null and b/vector/sampledata/room_round_avatars/new_vector.png differ
diff --git a/vector/sampledata/room_round_avatars/ops.png b/vector/sampledata/room_round_avatars/ops.png
new file mode 100644
index 0000000000..6809885cc9
Binary files /dev/null and b/vector/sampledata/room_round_avatars/ops.png differ
diff --git a/vector/sampledata/room_round_avatars/write_club.png b/vector/sampledata/room_round_avatars/write_club.png
new file mode 100644
index 0000000000..1284472581
Binary files /dev/null and b/vector/sampledata/room_round_avatars/write_club.png differ
diff --git a/vector/sampledata/rooms.json b/vector/sampledata/rooms.json
new file mode 100644
index 0000000000..9304aa308d
--- /dev/null
+++ b/vector/sampledata/rooms.json
@@ -0,0 +1,14 @@
+{
+ "data": [
+ {
+ "name": "Matrix HQ",
+ "alias": "#matrix:matrix.org",
+ "topic": "Welcome to Matrix HQ! Here is the rest of the room topic, with a https://www.example.org url and a phone number: 0102030405 which should not be clickable."
+ },
+ {
+ "name": "Room name very loooooooong with some details",
+ "alias": "#matrix:matrix.org",
+ "topic": "Room topic very loooooooong with some details"
+ }
+ ]
+}
diff --git a/vector/sampledata/space_avatars/car.png b/vector/sampledata/space_avatars/car.png
new file mode 100644
index 0000000000..7e8af6b71d
Binary files /dev/null and b/vector/sampledata/space_avatars/car.png differ
diff --git a/vector/sampledata/space_avatars/face.png b/vector/sampledata/space_avatars/face.png
new file mode 100644
index 0000000000..8bec44153c
Binary files /dev/null and b/vector/sampledata/space_avatars/face.png differ
diff --git a/vector/sampledata/space_avatars/london.png b/vector/sampledata/space_avatars/london.png
new file mode 100644
index 0000000000..e77ddaaccc
Binary files /dev/null and b/vector/sampledata/space_avatars/london.png differ
diff --git a/vector/sampledata/space_avatars/paris.png b/vector/sampledata/space_avatars/paris.png
new file mode 100644
index 0000000000..4506794b4a
Binary files /dev/null and b/vector/sampledata/space_avatars/paris.png differ
diff --git a/vector/sampledata/space_avatars/runner.png b/vector/sampledata/space_avatars/runner.png
new file mode 100644
index 0000000000..ceaa047f79
Binary files /dev/null and b/vector/sampledata/space_avatars/runner.png differ
diff --git a/vector/sampledata/space_avatars/snow.png b/vector/sampledata/space_avatars/snow.png
new file mode 100644
index 0000000000..b523cf3066
Binary files /dev/null and b/vector/sampledata/space_avatars/snow.png differ
diff --git a/vector/sampledata/spaces.json b/vector/sampledata/spaces.json
new file mode 100644
index 0000000000..f58c2ca5da
--- /dev/null
+++ b/vector/sampledata/spaces.json
@@ -0,0 +1,28 @@
+{
+ "data": [
+ {
+ "name": "Runner's world",
+ "topic": "Space about running around the world!"
+ },
+ {
+ "name": "Matrix Org",
+ "topic": "Space about matrix.org!"
+ },
+ {
+ "name": "Rennes",
+ "topic": "Venez visiter Rennes!"
+ },
+ {
+ "name": "Est London",
+ "topic": "All about Est London!"
+ },
+ {
+ "name": "Element HQ",
+ "topic": "All about Element!"
+ },
+ {
+ "name": "My Company",
+ "topic": "All about My company!"
+ }
+ ]
+}
diff --git a/vector/sampledata/user_round_avatars/0_amandine.png b/vector/sampledata/user_round_avatars/0_amandine.png
new file mode 100644
index 0000000000..2a279852b3
Binary files /dev/null and b/vector/sampledata/user_round_avatars/0_amandine.png differ
diff --git a/vector/sampledata/user_round_avatars/1_benoit.png b/vector/sampledata/user_round_avatars/1_benoit.png
new file mode 100644
index 0000000000..6c51a1bb5a
Binary files /dev/null and b/vector/sampledata/user_round_avatars/1_benoit.png differ
diff --git a/vector/sampledata/user_round_avatars/2_gaelle.png b/vector/sampledata/user_round_avatars/2_gaelle.png
new file mode 100644
index 0000000000..a679639e00
Binary files /dev/null and b/vector/sampledata/user_round_avatars/2_gaelle.png differ
diff --git a/vector/sampledata/user_round_avatars/3_manu.png b/vector/sampledata/user_round_avatars/3_manu.png
new file mode 100644
index 0000000000..0cf9229614
Binary files /dev/null and b/vector/sampledata/user_round_avatars/3_manu.png differ
diff --git a/vector/sampledata/user_round_avatars/4_matthew.png b/vector/sampledata/user_round_avatars/4_matthew.png
new file mode 100644
index 0000000000..13d8eb3cfc
Binary files /dev/null and b/vector/sampledata/user_round_avatars/4_matthew.png differ
diff --git a/vector/sampledata/user_round_avatars/5_nad.png b/vector/sampledata/user_round_avatars/5_nad.png
new file mode 100644
index 0000000000..e60f9f3325
Binary files /dev/null and b/vector/sampledata/user_round_avatars/5_nad.png differ
diff --git a/vector/sampledata/user_round_avatars/ben.png b/vector/sampledata/user_round_avatars/ben.png
new file mode 100644
index 0000000000..14839da426
Binary files /dev/null and b/vector/sampledata/user_round_avatars/ben.png differ
diff --git a/vector/sampledata/user_round_avatars/bruno.png b/vector/sampledata/user_round_avatars/bruno.png
new file mode 100644
index 0000000000..c0278ea73d
Binary files /dev/null and b/vector/sampledata/user_round_avatars/bruno.png differ
diff --git a/vector/sampledata/user_round_avatars/nique.png b/vector/sampledata/user_round_avatars/nique.png
new file mode 100644
index 0000000000..41480b4bb4
Binary files /dev/null and b/vector/sampledata/user_round_avatars/nique.png differ
diff --git a/vector/sampledata/user_round_avatars/toml.png b/vector/sampledata/user_round_avatars/toml.png
new file mode 100644
index 0000000000..1abeb74d94
Binary files /dev/null and b/vector/sampledata/user_round_avatars/toml.png differ
diff --git a/vector/sampledata/user_round_avatars/victor.png b/vector/sampledata/user_round_avatars/victor.png
new file mode 100644
index 0000000000..f1f91bda4f
Binary files /dev/null and b/vector/sampledata/user_round_avatars/victor.png differ
diff --git a/vector/sampledata/users.json b/vector/sampledata/users.json
new file mode 100644
index 0000000000..0a49d27450
--- /dev/null
+++ b/vector/sampledata/users.json
@@ -0,0 +1,28 @@
+{
+ "data": [
+ {
+ "displayName": "amandine",
+ "id": "@amandine:matrix.org"
+ },
+ {
+ "displayName": "benoit",
+ "id": "@benoit:matrix.org"
+ },
+ {
+ "displayName": "gaelle",
+ "id": "@gawa:matrix.org"
+ },
+ {
+ "displayName": "Manu",
+ "id": "@manu:matrix.org"
+ },
+ {
+ "displayName": "Matthew",
+ "id": "@matthew:matrix.org"
+ },
+ {
+ "displayName": "Nad",
+ "id": "@nadonomy:matrix.org"
+ }
+ ]
+}
diff --git a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPushFromPushGateway.kt b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPushFromPushGateway.kt
index 15c7e88bac..d429b293b2 100644
--- a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPushFromPushGateway.kt
+++ b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPushFromPushGateway.kt
@@ -19,13 +19,14 @@ import android.content.Intent
import androidx.activity.result.ActivityResultLauncher
import androidx.appcompat.app.AppCompatActivity
import im.vector.app.R
+import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.pushers.PushersManager
import im.vector.app.core.resources.StringProvider
+import im.vector.app.features.session.coroutineScope
import im.vector.app.features.settings.troubleshoot.TroubleshootTest
import im.vector.app.push.fcm.FcmHelper
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -38,7 +39,8 @@ import javax.inject.Inject
class TestPushFromPushGateway @Inject constructor(private val context: AppCompatActivity,
private val stringProvider: StringProvider,
private val errorFormatter: ErrorFormatter,
- private val pushersManager: PushersManager)
+ private val pushersManager: PushersManager,
+ private val activeSessionHolder: ActiveSessionHolder)
: TroubleshootTest(R.string.settings_troubleshoot_test_push_loop_title) {
private var action: Job? = null
@@ -50,7 +52,7 @@ class TestPushFromPushGateway @Inject constructor(private val context: AppCompat
status = TestStatus.FAILED
return
}
- action = GlobalScope.launch {
+ action = activeSessionHolder.getActiveSession().coroutineScope.launch {
val result = runCatching { pushersManager.testPush(fcmToken) }
withContext(Dispatchers.Main) {
diff --git a/vector/src/main/java/im/vector/app/AppStateHandler.kt b/vector/src/main/java/im/vector/app/AppStateHandler.kt
index cbe29d1900..edbd14d5d4 100644
--- a/vector/src/main/java/im/vector/app/AppStateHandler.kt
+++ b/vector/src/main/java/im/vector/app/AppStateHandler.kt
@@ -23,13 +23,13 @@ import arrow.core.Option
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.utils.BehaviorDataSource
import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider
+import im.vector.app.features.session.coroutineScope
import im.vector.app.features.ui.UiStateRepository
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.addTo
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.Session
@@ -71,30 +71,30 @@ class AppStateHandler @Inject constructor(
fun getCurrentRoomGroupingMethod(): RoomGroupingMethod? = selectedSpaceDataSource.currentValue?.orNull()
fun setCurrentSpace(spaceId: String?, session: Session? = null) {
- val uSession = session ?: activeSessionHolder.getSafeActiveSession()
+ val uSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return
if (selectedSpaceDataSource.currentValue?.orNull() is RoomGroupingMethod.BySpace
&& spaceId == selectedSpaceDataSource.currentValue?.orNull()?.space()?.roomId) return
- val spaceSum = spaceId?.let { uSession?.getRoomSummary(spaceId) }
+ val spaceSum = spaceId?.let { uSession.getRoomSummary(spaceId) }
selectedSpaceDataSource.post(Option.just(RoomGroupingMethod.BySpace(spaceSum)))
if (spaceId != null) {
- GlobalScope.launch(Dispatchers.IO) {
+ uSession.coroutineScope.launch(Dispatchers.IO) {
tryOrNull {
- uSession?.getRoom(spaceId)?.loadRoomMembersIfNeeded()
+ uSession.getRoom(spaceId)?.loadRoomMembersIfNeeded()
}
}
}
}
fun setCurrentGroup(groupId: String?, session: Session? = null) {
- val uSession = session ?: activeSessionHolder.getSafeActiveSession()
+ val uSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return
if (selectedSpaceDataSource.currentValue?.orNull() is RoomGroupingMethod.ByLegacyGroup
&& groupId == selectedSpaceDataSource.currentValue?.orNull()?.group()?.groupId) return
- val activeGroup = groupId?.let { uSession?.getGroupSummary(groupId) }
+ val activeGroup = groupId?.let { uSession.getGroupSummary(groupId) }
selectedSpaceDataSource.post(Option.just(RoomGroupingMethod.ByLegacyGroup(activeGroup)))
if (groupId != null) {
- GlobalScope.launch {
+ uSession.coroutineScope.launch {
tryOrNull {
- uSession?.getGroup(groupId)?.fetchGroupData()
+ uSession.getGroup(groupId)?.fetchGroupData()
}
}
}
diff --git a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt
index c685231756..25c8a07597 100644
--- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt
+++ b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt
@@ -125,6 +125,8 @@ import im.vector.app.features.spaces.create.CreateSpaceDefaultRoomsFragment
import im.vector.app.features.spaces.create.CreateSpaceDetailsFragment
import im.vector.app.features.spaces.explore.SpaceDirectoryFragment
import im.vector.app.features.spaces.manage.SpaceAddRoomFragment
+import im.vector.app.features.spaces.manage.SpaceManageRoomsFragment
+import im.vector.app.features.spaces.manage.SpaceSettingsFragment
import im.vector.app.features.spaces.people.SpacePeopleFragment
import im.vector.app.features.spaces.preview.SpacePreviewFragment
import im.vector.app.features.terms.ReviewTermsFragment
@@ -684,4 +686,14 @@ interface FragmentModule {
@IntoMap
@FragmentKey(SpacePeopleFragment::class)
fun bindSpacePeopleFragment(fragment: SpacePeopleFragment): Fragment
+
+ @Binds
+ @IntoMap
+ @FragmentKey(SpaceSettingsFragment::class)
+ fun bindSpaceSettingsFragment(fragment: SpaceSettingsFragment): Fragment
+
+ @Binds
+ @IntoMap
+ @FragmentKey(SpaceManageRoomsFragment::class)
+ fun bindSpaceManageRoomsFragment(fragment: SpaceManageRoomsFragment): Fragment
}
diff --git a/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt b/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt
index c16c602530..dbfbcbdd1e 100644
--- a/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt
+++ b/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt
@@ -78,12 +78,12 @@ import im.vector.app.features.settings.devices.DeviceVerificationInfoBottomSheet
import im.vector.app.features.share.IncomingShareActivity
import im.vector.app.features.signout.soft.SoftLogoutActivity
import im.vector.app.features.spaces.InviteRoomSpaceChooserBottomSheet
-import im.vector.app.features.spaces.ShareSpaceBottomSheet
import im.vector.app.features.spaces.SpaceCreationActivity
import im.vector.app.features.spaces.SpaceExploreActivity
-import im.vector.app.features.spaces.invite.SpaceInviteBottomSheet
import im.vector.app.features.spaces.SpaceSettingsMenuBottomSheet
+import im.vector.app.features.spaces.invite.SpaceInviteBottomSheet
import im.vector.app.features.spaces.manage.SpaceManageActivity
+import im.vector.app.features.spaces.share.ShareSpaceBottomSheet
import im.vector.app.features.terms.ReviewTermsActivity
import im.vector.app.features.ui.UiStateRepository
import im.vector.app.features.usercode.UserCodeActivity
diff --git a/vector/src/main/java/im/vector/app/core/epoxy/VectorEpoxyFormExt.kt b/vector/src/main/java/im/vector/app/core/epoxy/VectorEpoxyFormExt.kt
new file mode 100644
index 0000000000..f93b07a98d
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/epoxy/VectorEpoxyFormExt.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2021 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.epoxy
+
+import android.widget.CompoundButton
+import com.google.android.material.switchmaterial.SwitchMaterial
+import com.google.android.material.textfield.TextInputEditText
+
+fun VectorEpoxyHolder.setValueOnce(textInputEditText: TextInputEditText, value: String?) {
+ if (view.isAttachedToWindow) {
+ // the view is attached to the window
+ // So it is a rebind of new data and you could ignore it assuming this is text that was already inputted into the view.
+ // Downside is if you ever wanted to programmatically change the content of the edit text while it is on screen you would not be able to
+ } else {
+ textInputEditText.setText(value)
+ }
+}
+
+fun VectorEpoxyHolder.setValueOnce(switchView: SwitchMaterial, switchChecked: Boolean, listener: CompoundButton.OnCheckedChangeListener) {
+ if (view.isAttachedToWindow) {
+ // the view is attached to the window
+ // So it is a rebind of new data and you could ignore it assuming this is value that was already inputted into the view.
+ } else {
+ switchView.isChecked = switchChecked
+ switchView.setOnCheckedChangeListener(listener)
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/core/extensions/EditText.kt b/vector/src/main/java/im/vector/app/core/extensions/EditText.kt
index 33e7199334..05b70def3d 100644
--- a/vector/src/main/java/im/vector/app/core/extensions/EditText.kt
+++ b/vector/src/main/java/im/vector/app/core/extensions/EditText.kt
@@ -57,15 +57,3 @@ fun EditText.setupAsSearch(@DrawableRes searchIconRes: Int = R.drawable.ic_searc
return@OnTouchListener false
})
}
-
-/**
- * Update the edit text value, only if necessary and move the cursor to the end of the text
- */
-fun EditText.setTextSafe(value: String?) {
- if (value != null && text.toString() != value) {
- setText(value)
- // To fix jumping cursor to the start https://github.com/airbnb/epoxy/issues/426
- // Note: there is still a known bug if deleting char in the middle of the text, by long pressing on the backspace button.
- setSelection(value.length)
- }
-}
diff --git a/vector/src/main/java/im/vector/app/core/intent/VectorMimeType.kt b/vector/src/main/java/im/vector/app/core/intent/VectorMimeType.kt
index 1299f4086b..e68b5e1b07 100644
--- a/vector/src/main/java/im/vector/app/core/intent/VectorMimeType.kt
+++ b/vector/src/main/java/im/vector/app/core/intent/VectorMimeType.kt
@@ -45,7 +45,7 @@ fun getMimeTypeFromUri(context: Context, uri: Uri): String? {
if (null != mimeType) {
// the mimetype is sometimes in uppercase.
- mimeType = mimeType.toLowerCase(Locale.ROOT)
+ mimeType = mimeType.lowercase(Locale.ROOT)
}
} catch (e: Exception) {
Timber.e(e, "Failed to open resource input stream")
diff --git a/vector/src/main/java/im/vector/app/core/ui/list/GenericItemHeader.kt b/vector/src/main/java/im/vector/app/core/ui/list/GenericItemHeader.kt
index d0c65aff95..bc5446e836 100644
--- a/vector/src/main/java/im/vector/app/core/ui/list/GenericItemHeader.kt
+++ b/vector/src/main/java/im/vector/app/core/ui/list/GenericItemHeader.kt
@@ -16,12 +16,14 @@
package im.vector.app.core.ui.list
import android.widget.TextView
+import androidx.annotation.ColorInt
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.app.R
import im.vector.app.core.epoxy.VectorEpoxyHolder
import im.vector.app.core.epoxy.VectorEpoxyModel
import im.vector.app.core.extensions.setTextOrHide
+import im.vector.app.features.themes.ThemeUtils
/**
* A generic list item header left aligned with notice color.
@@ -32,9 +34,18 @@ abstract class GenericItemHeader : VectorEpoxyModel()
@EpoxyAttribute
var text: String? = null
+ @EpoxyAttribute
+ @ColorInt
+ var textColor: Int? = null
+
override fun bind(holder: Holder) {
super.bind(holder)
holder.text.setTextOrHide(text)
+ if (textColor != null) {
+ holder.text.setTextColor(textColor!!)
+ } else {
+ holder.text.setTextColor(ThemeUtils.getColor(holder.view.context, R.attr.vctr_notice_text_color))
+ }
}
class Holder : VectorEpoxyHolder() {
diff --git a/vector/src/main/java/im/vector/app/core/ui/list/GenericPillItem.kt b/vector/src/main/java/im/vector/app/core/ui/list/GenericPillItem.kt
new file mode 100644
index 0000000000..ce9e35c007
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/ui/list/GenericPillItem.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2019 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.ui.list
+
+import android.content.res.ColorStateList
+import android.view.Gravity
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.annotation.DrawableRes
+import androidx.core.view.isVisible
+import androidx.core.widget.ImageViewCompat
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.app.R
+import im.vector.app.core.epoxy.VectorEpoxyHolder
+import im.vector.app.core.epoxy.VectorEpoxyModel
+import im.vector.app.core.extensions.setTextOrHide
+import im.vector.app.features.themes.ThemeUtils
+
+/**
+ * A generic list item with a rounded corner background and an optional icon
+ */
+@EpoxyModelClass(layout = R.layout.item_generic_pill_footer)
+abstract class GenericPillItem : VectorEpoxyModel() {
+
+ @EpoxyAttribute
+ var text: CharSequence? = null
+
+ @EpoxyAttribute
+ var style: ItemStyle = ItemStyle.NORMAL_TEXT
+
+ @EpoxyAttribute
+ var itemClickAction: GenericItem.Action? = null
+
+ @EpoxyAttribute
+ var centered: Boolean = false
+
+ @EpoxyAttribute
+ @DrawableRes
+ var imageRes: Int? = null
+
+ @EpoxyAttribute
+ var tintIcon: Boolean = true
+
+ override fun bind(holder: Holder) {
+ super.bind(holder)
+
+ holder.textView.setTextOrHide(text)
+ holder.textView.typeface = style.toTypeFace()
+ holder.textView.textSize = style.toTextSize()
+ holder.textView.gravity = if (centered) Gravity.CENTER_HORIZONTAL else Gravity.START
+
+ if (imageRes != null) {
+ holder.imageView.setImageResource(imageRes!!)
+ holder.imageView.isVisible = true
+ } else {
+ holder.imageView.isVisible = false
+ }
+ if (tintIcon) {
+ val iconTintColor = ThemeUtils.getColor(holder.view.context, R.attr.riotx_text_secondary)
+ ImageViewCompat.setImageTintList(holder.imageView, ColorStateList.valueOf(iconTintColor))
+ } else {
+ ImageViewCompat.setImageTintList(holder.imageView, null)
+ }
+
+ holder.view.setOnClickListener {
+ itemClickAction?.perform?.run()
+ }
+ }
+
+ class Holder : VectorEpoxyHolder() {
+ val imageView by bind(R.id.itemGenericPillImage)
+ val textView by bind(R.id.itemGenericPillText)
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/core/utils/Emoji.kt b/vector/src/main/java/im/vector/app/core/utils/Emoji.kt
index 66907ded10..d73af1e917 100644
--- a/vector/src/main/java/im/vector/app/core/utils/Emoji.kt
+++ b/vector/src/main/java/im/vector/app/core/utils/Emoji.kt
@@ -42,13 +42,13 @@ fun CharSequence.splitEmoji(): List {
while (index < length) {
val firstChar = get(index)
- if (firstChar.toInt() == 0x200e) {
+ if (firstChar.code == 0x200e) {
// Left to right mark. What should I do with it?
- } else if (firstChar.toInt() in 0xD800..0xDBFF && index + 1 < length) {
+ } else if (firstChar.code in 0xD800..0xDBFF && index + 1 < length) {
// We have the start of a surrogate pair
val secondChar = get(index + 1)
- if (secondChar.toInt() in 0xDC00..0xDFFF) {
+ if (secondChar.code in 0xDC00..0xDFFF) {
// We have an emoji
result.add("$firstChar$secondChar")
index++
diff --git a/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt b/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt
index 859df7d714..d82de1b4ed 100644
--- a/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt
+++ b/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt
@@ -43,8 +43,7 @@ import im.vector.app.R
import im.vector.app.features.notifications.NotificationUtils
import im.vector.app.features.themes.ThemeUtils
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import okio.buffer
import okio.sink
import okio.source
@@ -57,6 +56,7 @@ import timber.log.Timber
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
+import java.lang.IllegalStateException
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
@@ -344,90 +344,93 @@ private fun appendTimeToFilename(name: String): String {
return """${filename}_$dateExtension.$fileExtension"""
}
-fun saveMedia(context: Context, file: File, title: String, mediaMimeType: String?, notificationUtils: NotificationUtils) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- val filename = appendTimeToFilename(title)
+suspend fun saveMedia(context: Context, file: File, title: String, mediaMimeType: String?, notificationUtils: NotificationUtils) {
+ withContext(Dispatchers.IO) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ val filename = appendTimeToFilename(title)
- val values = ContentValues().apply {
- put(MediaStore.Images.Media.TITLE, filename)
- put(MediaStore.Images.Media.DISPLAY_NAME, filename)
- put(MediaStore.Images.Media.MIME_TYPE, mediaMimeType)
- put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis())
- put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
- }
- val externalContentUri = when {
- mediaMimeType?.isMimeTypeImage() == true -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
- mediaMimeType?.isMimeTypeVideo() == true -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
- mediaMimeType?.isMimeTypeAudio() == true -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
- else -> MediaStore.Downloads.EXTERNAL_CONTENT_URI
- }
+ val values = ContentValues().apply {
+ put(MediaStore.Images.Media.TITLE, filename)
+ put(MediaStore.Images.Media.DISPLAY_NAME, filename)
+ put(MediaStore.Images.Media.MIME_TYPE, mediaMimeType)
+ put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis())
+ put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
+ }
+ val externalContentUri = when {
+ mediaMimeType?.isMimeTypeImage() == true -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
+ mediaMimeType?.isMimeTypeVideo() == true -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
+ mediaMimeType?.isMimeTypeAudio() == true -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
+ else -> MediaStore.Downloads.EXTERNAL_CONTENT_URI
+ }
- val uri = context.contentResolver.insert(externalContentUri, values)
- if (uri == null) {
- Toast.makeText(context, R.string.error_saving_media_file, Toast.LENGTH_LONG).show()
- } else {
- val source = file.inputStream().source().buffer()
- context.contentResolver.openOutputStream(uri)?.sink()?.buffer()?.let { sink ->
- source.use { input ->
- sink.use { output ->
- output.writeAll(input)
+ val uri = context.contentResolver.insert(externalContentUri, values)
+ if (uri == null) {
+ Toast.makeText(context, R.string.error_saving_media_file, Toast.LENGTH_LONG).show()
+ throw IllegalStateException(context.getString(R.string.error_saving_media_file))
+ } else {
+ val source = file.inputStream().source().buffer()
+ context.contentResolver.openOutputStream(uri)?.sink()?.buffer()?.let { sink ->
+ source.use { input ->
+ sink.use { output ->
+ output.writeAll(input)
+ }
}
}
+ notificationUtils.buildDownloadFileNotification(
+ uri,
+ filename,
+ mediaMimeType ?: MimeTypes.OctetStream
+ ).let { notification ->
+ notificationUtils.showNotificationMessage("DL", uri.hashCode(), notification)
+ }
}
- notificationUtils.buildDownloadFileNotification(
- uri,
- filename,
- mediaMimeType ?: MimeTypes.OctetStream
- ).let { notification ->
- notificationUtils.showNotificationMessage("DL", uri.hashCode(), notification)
- }
+ } else {
+ saveMediaLegacy(context, mediaMimeType, title, file)
}
- } else {
- saveMediaLegacy(context, mediaMimeType, title, file)
}
}
@Suppress("DEPRECATION")
-private fun saveMediaLegacy(context: Context, mediaMimeType: String?, title: String, file: File) {
+private fun saveMediaLegacy(context: Context,
+ mediaMimeType: String?,
+ title: String,
+ file: File) {
val state = Environment.getExternalStorageState()
if (Environment.MEDIA_MOUNTED != state) {
context.toast(context.getString(R.string.error_saving_media_file))
- return
+ throw IllegalStateException(context.getString(R.string.error_saving_media_file))
}
- GlobalScope.launch(Dispatchers.IO) {
- val dest = when {
- mediaMimeType?.isMimeTypeImage() == true -> Environment.DIRECTORY_PICTURES
- mediaMimeType?.isMimeTypeVideo() == true -> Environment.DIRECTORY_MOVIES
- mediaMimeType?.isMimeTypeAudio() == true -> Environment.DIRECTORY_MUSIC
- else -> Environment.DIRECTORY_DOWNLOADS
+ val dest = when {
+ mediaMimeType?.isMimeTypeImage() == true -> Environment.DIRECTORY_PICTURES
+ mediaMimeType?.isMimeTypeVideo() == true -> Environment.DIRECTORY_MOVIES
+ mediaMimeType?.isMimeTypeAudio() == true -> Environment.DIRECTORY_MUSIC
+ else -> Environment.DIRECTORY_DOWNLOADS
+ }
+ val downloadDir = Environment.getExternalStoragePublicDirectory(dest)
+ try {
+ val outputFilename = if (title.substringAfterLast('.', "").isEmpty()) {
+ val extension = mediaMimeType?.let { MimeTypeMap.getSingleton().getExtensionFromMimeType(it) }
+ "$title.$extension"
+ } else {
+ title
}
- val downloadDir = Environment.getExternalStoragePublicDirectory(dest)
- try {
- val outputFilename = if (title.substringAfterLast('.', "").isEmpty()) {
- val extension = mediaMimeType?.let { MimeTypeMap.getSingleton().getExtensionFromMimeType(it) }
- "$title.$extension"
- } else {
- title
- }
- val savedFile = saveFileIntoLegacy(file, downloadDir, outputFilename)
- if (savedFile != null) {
- val downloadManager = context.getSystemService()
- downloadManager?.addCompletedDownload(
- savedFile.name,
- title,
- true,
- mediaMimeType ?: MimeTypes.OctetStream,
- savedFile.absolutePath,
- savedFile.length(),
- true)
- addToGallery(savedFile, mediaMimeType, context)
- }
- } catch (error: Throwable) {
- GlobalScope.launch(Dispatchers.Main) {
- context.toast(context.getString(R.string.error_saving_media_file))
- }
+ val savedFile = saveFileIntoLegacy(file, downloadDir, outputFilename)
+ if (savedFile != null) {
+ val downloadManager = context.getSystemService()
+ downloadManager?.addCompletedDownload(
+ savedFile.name,
+ title,
+ true,
+ mediaMimeType ?: MimeTypes.OctetStream,
+ savedFile.absolutePath,
+ savedFile.length(),
+ true)
+ addToGallery(savedFile, mediaMimeType, context)
}
+ } catch (error: Throwable) {
+ context.toast(context.getString(R.string.error_saving_media_file))
+ throw error
}
}
@@ -509,7 +512,7 @@ fun selectTxtFileToWrite(
* @param sourceFile the file source path
* @param dstDirPath the dst path
* @param outputFilename optional the output filename
- * @param callback the asynchronous callback
+ * @return the created file
*/
@Suppress("DEPRECATION")
fun saveFileIntoLegacy(sourceFile: File, dstDirPath: File, outputFilename: String?): File? {
diff --git a/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt b/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt
index b5ce922487..7ce6dd1c67 100644
--- a/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt
+++ b/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt
@@ -112,7 +112,7 @@ fun getFileExtension(fileUri: String): String? {
val ext = filename.substring(dotPos + 1)
if (ext.isNotBlank()) {
- return ext.toLowerCase(Locale.ROOT)
+ return ext.lowercase(Locale.ROOT)
}
}
}
@@ -131,5 +131,5 @@ fun getSizeOfFiles(root: File): Int {
Timber.v("Get size of ${it.absolutePath}")
true
}
- .sumBy { it.length().toInt() }
+ .sumOf { it.length().toInt() }
}
diff --git a/vector/src/main/java/im/vector/app/core/utils/StringUtils.kt b/vector/src/main/java/im/vector/app/core/utils/StringUtils.kt
new file mode 100644
index 0000000000..6d681007ce
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/utils/StringUtils.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2021 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 java.util.Locale
+
+// String.capitalize is now deprecated
+fun String.safeCapitalize(locale: Locale): String {
+ return replaceFirstChar { char ->
+ if (char.isLowerCase()) {
+ char.titlecase(locale)
+ } else {
+ char.toString()
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt
index fcd6bf0a77..a3a1a29c4b 100644
--- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt
+++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt
@@ -33,11 +33,12 @@ import im.vector.app.features.call.utils.awaitCreateOffer
import im.vector.app.features.call.utils.awaitSetLocalDescription
import im.vector.app.features.call.utils.awaitSetRemoteDescription
import im.vector.app.features.call.utils.mapToCallCandidate
+import im.vector.app.features.session.coroutineScope
import io.reactivex.disposables.Disposable
import io.reactivex.subjects.PublishSubject
import io.reactivex.subjects.ReplaySubject
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -103,6 +104,9 @@ class WebRtcCall(val mxCall: MxCall,
private val listeners = CopyOnWriteArrayList()
+ private val sessionScope: CoroutineScope?
+ get() = sessionProvider.get()?.coroutineScope
+
fun addListener(listener: Listener) {
listeners.add(listener)
}
@@ -191,7 +195,7 @@ class WebRtcCall(val mxCall: MxCall,
fun onIceCandidate(iceCandidate: IceCandidate) = iceCandidateSource.onNext(iceCandidate)
fun onRenegotiationNeeded(restartIce: Boolean) {
- GlobalScope.launch(dispatcher) {
+ sessionScope?.launch(dispatcher) {
if (mxCall.state != CallState.CreateOffer && mxCall.opponentVersion == 0) {
Timber.v("Opponent does not support renegotiation: ignoring onRenegotiationNeeded event")
return@launch
@@ -262,7 +266,7 @@ class WebRtcCall(val mxCall: MxCall,
localSurfaceRenderers.addIfNeeded(localViewRenderer)
remoteSurfaceRenderers.addIfNeeded(remoteViewRenderer)
- GlobalScope.launch(dispatcher) {
+ sessionScope?.launch(dispatcher) {
when (mode) {
VectorCallActivity.INCOMING_ACCEPT -> {
internalAcceptIncomingCall()
@@ -283,7 +287,7 @@ class WebRtcCall(val mxCall: MxCall,
}
fun acceptIncomingCall() {
- GlobalScope.launch {
+ sessionScope?.launch {
Timber.v("## VOIP acceptIncomingCall from state ${mxCall.state}")
if (mxCall.state == CallState.LocalRinging) {
internalAcceptIncomingCall()
@@ -564,7 +568,7 @@ class WebRtcCall(val mxCall: MxCall,
}
fun updateRemoteOnHold(onHold: Boolean) {
- GlobalScope.launch(dispatcher) {
+ sessionScope?.launch(dispatcher) {
if (remoteOnHold == onHold) return@launch
val direction: RtpTransceiver.RtpTransceiverDirection
if (onHold) {
@@ -688,7 +692,7 @@ class WebRtcCall(val mxCall: MxCall,
}
fun onAddStream(stream: MediaStream) {
- GlobalScope.launch(dispatcher) {
+ sessionScope?.launch(dispatcher) {
// reportError("Weird-looking stream: " + stream);
if (stream.audioTracks.size > 1 || stream.videoTracks.size > 1) {
Timber.e("## VOIP StreamObserver weird looking stream: $stream")
@@ -712,7 +716,7 @@ class WebRtcCall(val mxCall: MxCall,
}
fun onRemoveStream() {
- GlobalScope.launch(dispatcher) {
+ sessionScope?.launch(dispatcher) {
remoteSurfaceRenderers
.mapNotNull { it.get() }
.forEach { remoteVideoTrack?.removeSink(it) }
@@ -734,7 +738,7 @@ class WebRtcCall(val mxCall: MxCall,
}
val wasRinging = mxCall.state is CallState.LocalRinging
mxCall.state = CallState.Terminated
- GlobalScope.launch(dispatcher) {
+ sessionScope?.launch(dispatcher) {
release()
}
onCallEnded(callId)
@@ -750,7 +754,7 @@ class WebRtcCall(val mxCall: MxCall,
// Call listener
fun onCallIceCandidateReceived(iceCandidatesContent: CallCandidatesContent) {
- GlobalScope.launch(dispatcher) {
+ sessionScope?.launch(dispatcher) {
iceCandidatesContent.candidates.forEach {
if (it.sdpMid.isNullOrEmpty() || it.candidate.isNullOrEmpty()) {
return@forEach
@@ -763,7 +767,7 @@ class WebRtcCall(val mxCall: MxCall,
}
fun onCallAnswerReceived(callAnswerContent: CallAnswerContent) {
- GlobalScope.launch(dispatcher) {
+ sessionScope?.launch(dispatcher) {
Timber.v("## VOIP onCallAnswerReceived ${callAnswerContent.callId}")
val sdp = SessionDescription(SessionDescription.Type.ANSWER, callAnswerContent.answer.sdp)
try {
@@ -779,7 +783,7 @@ class WebRtcCall(val mxCall: MxCall,
}
fun onCallNegotiateReceived(callNegotiateContent: CallNegotiateContent) {
- GlobalScope.launch(dispatcher) {
+ sessionScope?.launch(dispatcher) {
val description = callNegotiateContent.description
val type = description?.type
val sdpText = description?.sdp
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keys/KeysExporter.kt b/vector/src/main/java/im/vector/app/features/crypto/keys/KeysExporter.kt
index 282f7b1a71..c7e4c26385 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keys/KeysExporter.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keys/KeysExporter.kt
@@ -18,8 +18,8 @@ package im.vector.app.features.crypto.keys
import android.content.Context
import android.net.Uri
+import im.vector.app.features.session.coroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixCallback
@@ -33,7 +33,7 @@ class KeysExporter(private val session: Session) {
* Export keys and return the file path with the callback
*/
fun export(context: Context, password: String, uri: Uri, callback: MatrixCallback) {
- GlobalScope.launch(Dispatchers.Main) {
+ session.coroutineScope.launch(Dispatchers.Main) {
runCatching {
withContext(Dispatchers.IO) {
val data = awaitCallback { session.cryptoService().exportRoomKeys(password, it) }
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keys/KeysImporter.kt b/vector/src/main/java/im/vector/app/features/crypto/keys/KeysImporter.kt
index 8932bb9489..3d93b26edd 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keys/KeysImporter.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keys/KeysImporter.kt
@@ -20,8 +20,8 @@ import android.content.Context
import android.net.Uri
import im.vector.app.core.intent.getMimeTypeFromUri
import im.vector.app.core.resources.openResource
+import im.vector.app.features.session.coroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixCallback
@@ -41,7 +41,7 @@ class KeysImporter(private val session: Session) {
mimetype: String?,
password: String,
callback: MatrixCallback) {
- GlobalScope.launch(Dispatchers.Main) {
+ session.coroutineScope.launch(Dispatchers.Main) {
runCatching {
withContext(Dispatchers.IO) {
val resource = openResource(context, uri, mimetype ?: getMimeTypeFromUri(context, uri))
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt
index 9a3b5fa874..8833702e35 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt
@@ -25,6 +25,7 @@ import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
import arrow.core.Try
import com.google.android.material.bottomsheet.BottomSheetDialog
import im.vector.app.R
@@ -37,7 +38,6 @@ import im.vector.app.core.utils.startSharePlainTextIntent
import im.vector.app.databinding.FragmentKeysBackupSetupStep3Binding
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.IOException
@@ -163,7 +163,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment
if (activityResult.resultCode == Activity.RESULT_OK) {
val uri = activityResult.data?.data ?: return@registerStartForActivityResult
- GlobalScope.launch(Dispatchers.IO) {
+ lifecycleScope.launch(Dispatchers.IO) {
try {
sharedViewModel.handle(BootstrapActions.SaveKeyToUri(requireContext().contentResolver!!.openOutputStream(uri)!!))
} catch (failure: Throwable) {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt
index a67cb96d37..8e21412715 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt
@@ -33,7 +33,6 @@ import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.session.Session
@@ -427,7 +426,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
}
private fun tentativeRestoreBackup(res: Map?) {
- GlobalScope.launch(Dispatchers.IO) {
+ viewModelScope.launch(Dispatchers.IO) {
try {
val secret = res?.get(KEYBACKUP_SECRET_SSSS_NAME) ?: return@launch Unit.also {
Timber.v("## Keybackup secret not restored from SSSS")
diff --git a/vector/src/main/java/im/vector/app/features/form/FormEditTextItem.kt b/vector/src/main/java/im/vector/app/features/form/FormEditTextItem.kt
index fdac8afaed..f8bcbddd34 100644
--- a/vector/src/main/java/im/vector/app/features/form/FormEditTextItem.kt
+++ b/vector/src/main/java/im/vector/app/features/form/FormEditTextItem.kt
@@ -27,7 +27,7 @@ import com.google.android.material.textfield.TextInputLayout
import im.vector.app.R
import im.vector.app.core.epoxy.VectorEpoxyHolder
import im.vector.app.core.epoxy.VectorEpoxyModel
-import im.vector.app.core.extensions.setTextSafe
+import im.vector.app.core.epoxy.setValueOnce
import im.vector.app.core.platform.SimpleTextWatcher
@EpoxyModelClass(layout = R.layout.item_form_text_input)
@@ -60,7 +60,7 @@ abstract class FormEditTextItem : VectorEpoxyModel() {
@EpoxyAttribute
var endIconMode: Int? = null
- @EpoxyAttribute
+ @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
var onTextChange: ((String) -> Unit)? = null
private val onTextChangeListener = object : SimpleTextWatcher() {
@@ -76,8 +76,8 @@ abstract class FormEditTextItem : VectorEpoxyModel() {
holder.textInputLayout.error = errorMessage
holder.textInputLayout.endIconMode = endIconMode ?: TextInputLayout.END_ICON_NONE
- // Update only if text is different and value is not null
- holder.textInputEditText.setTextSafe(value)
+ holder.setValueOnce(holder.textInputEditText, value)
+
holder.textInputEditText.isEnabled = enabled
inputType?.let { holder.textInputEditText.inputType = it }
holder.textInputEditText.isSingleLine = singleLine ?: false
diff --git a/vector/src/main/java/im/vector/app/features/form/FormEditTextWithButtonItem.kt b/vector/src/main/java/im/vector/app/features/form/FormEditTextWithButtonItem.kt
index 08fc435e11..6cf862b10b 100644
--- a/vector/src/main/java/im/vector/app/features/form/FormEditTextWithButtonItem.kt
+++ b/vector/src/main/java/im/vector/app/features/form/FormEditTextWithButtonItem.kt
@@ -26,7 +26,7 @@ import com.google.android.material.textfield.TextInputLayout
import im.vector.app.R
import im.vector.app.core.epoxy.VectorEpoxyHolder
import im.vector.app.core.epoxy.VectorEpoxyModel
-import im.vector.app.core.extensions.setTextSafe
+import im.vector.app.core.epoxy.setValueOnce
import im.vector.app.core.platform.SimpleTextWatcher
@EpoxyModelClass(layout = R.layout.item_form_text_input_with_button)
@@ -61,8 +61,8 @@ abstract class FormEditTextWithButtonItem : VectorEpoxyModel Unit)? = null
private val onTextChangeListener = object : SimpleTextWatcher() {
@@ -76,8 +76,8 @@ abstract class FormMultiLineEditTextItem : VectorEpoxyModel() {
var switchChecked: Boolean = false
@EpoxyAttribute
- var title: String? = null
+ var title: CharSequence? = null
@EpoxyAttribute
var summary: String? = null
@@ -61,11 +62,10 @@ abstract class FormSwitchItem : VectorEpoxyModel() {
holder.switchView.isEnabled = enabled
- holder.switchView.setOnCheckedChangeListener(null)
- holder.switchView.isChecked = switchChecked
- holder.switchView.setOnCheckedChangeListener { _, isChecked ->
+ holder.setValueOnce(holder.switchView, switchChecked) { _, isChecked ->
listener?.invoke(isChecked)
}
+
holder.divider.isVisible = showDivider
}
diff --git a/vector/src/main/java/im/vector/app/features/grouplist/HomeSpaceSummaryItem.kt b/vector/src/main/java/im/vector/app/features/grouplist/HomeSpaceSummaryItem.kt
index 553f82e98f..ddda38aa9c 100644
--- a/vector/src/main/java/im/vector/app/features/grouplist/HomeSpaceSummaryItem.kt
+++ b/vector/src/main/java/im/vector/app/features/grouplist/HomeSpaceSummaryItem.kt
@@ -18,6 +18,7 @@
package im.vector.app.features.grouplist
import android.content.res.ColorStateList
+import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
@@ -35,8 +36,9 @@ import im.vector.app.features.themes.ThemeUtils
abstract class HomeSpaceSummaryItem : VectorEpoxyModel() {
@EpoxyAttribute var selected: Boolean = false
- @EpoxyAttribute var listener: (() -> Unit)? = null
+ @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: (() -> Unit)? = null
@EpoxyAttribute var countState : UnreadCounterBadgeView.State = UnreadCounterBadgeView.State(0, false)
+ @EpoxyAttribute var showSeparator: Boolean = false
override fun getViewType(): Int {
// mm.. it's reusing the same layout for basic space item
@@ -56,6 +58,7 @@ abstract class HomeSpaceSummaryItem : VectorEpoxyModel(R.id.itemGroupLayout)
val leaveView by bind(R.id.groupTmpLeave)
val counterBadgeView by bind(R.id.groupCounterBadge)
+ val bottomSeparator by bind(R.id.groupBottomSeparator)
}
}
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 1de1ff1c3e..7714a69196 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
@@ -55,14 +55,15 @@ import im.vector.app.features.permalink.PermalinkHandler
import im.vector.app.features.popup.DefaultVectorAlert
import im.vector.app.features.popup.PopupAlertManager
import im.vector.app.features.popup.VerificationVectorAlert
+import im.vector.app.features.rageshake.ReportType
import im.vector.app.features.rageshake.VectorUncaughtExceptionHandler
import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.settings.VectorSettingsActivity
-import im.vector.app.features.spaces.ShareSpaceBottomSheet
import im.vector.app.features.spaces.SpaceCreationActivity
import im.vector.app.features.spaces.SpacePreviewActivity
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.workers.signout.ServerBackupStatusViewModel
import im.vector.app.features.workers.signout.ServerBackupStatusViewState
@@ -216,6 +217,9 @@ class HomeActivity :
SpaceInviteBottomSheet.newInstance(sharedAction.spaceId)
.show(supportFragmentManager, "SPACE_INVITE")
}
+ HomeActivitySharedAction.SendSpaceFeedBack -> {
+ bugReporter.openBugReportScreen(this, ReportType.SPACE_BETA_FEEDBACK)
+ }
}.exhaustive
}
.disposeOnDestroy()
@@ -449,11 +453,11 @@ class HomeActivity :
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.menu_home_suggestion -> {
- bugReporter.openBugReportScreen(this, true)
+ bugReporter.openBugReportScreen(this, ReportType.SUGGESTION)
return true
}
R.id.menu_home_report_bug -> {
- bugReporter.openBugReportScreen(this, false)
+ bugReporter.openBugReportScreen(this, ReportType.BUG_REPORT)
return true
}
R.id.menu_home_init_sync_legacy -> {
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivitySharedAction.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivitySharedAction.kt
index d79f24fc4c..6047a1e55e 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeActivitySharedAction.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeActivitySharedAction.kt
@@ -29,4 +29,5 @@ sealed class HomeActivitySharedAction : VectorSharedAction {
data class OpenSpacePreview(val spaceId: String) : HomeActivitySharedAction()
data class OpenSpaceInvite(val spaceId: String) : HomeActivitySharedAction()
data class ShowSpaceSettings(val spaceId: String) : HomeActivitySharedAction()
+ object SendSpaceFeedBack : HomeActivitySharedAction()
}
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 447a567cf4..bfedbd6f52 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
@@ -27,9 +27,9 @@ import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.login.ReAuthHelper
+import im.vector.app.features.session.coroutineScope
import im.vector.app.features.settings.VectorPreferences
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.auth.UIABaseAuth
@@ -184,7 +184,7 @@ class HomeActivityViewModel @AssistedInject constructor(
private fun maybeBootstrapCrossSigningAfterInitialSync() {
// We do not use the viewModel context because we do not want to tie this action to activity view model
- GlobalScope.launch(Dispatchers.IO) {
+ activeSessionHolder.getSafeActiveSession()?.coroutineScope?.launch(Dispatchers.IO) {
val session = activeSessionHolder.getSafeActiveSession() ?: return@launch
tryOrNull("## MaybeBootstrapCrossSigning: Failed to download keys") {
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt
index be5c72330e..836c63e85b 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt
@@ -202,7 +202,7 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
setState {
copy(
notificationCountCatchup = dmRooms.totalCount + otherRooms.totalCount + roomsInvite + dmInvites,
- notificationHighlightCatchup = dmRooms.isHighlight || otherRooms.isHighlight,
+ notificationHighlightCatchup = dmRooms.isHighlight || otherRooms.isHighlight || (dmInvites + roomsInvite) > 0,
notificationCountPeople = dmRooms.totalCount + dmInvites,
notificationHighlightPeople = dmRooms.isHighlight || dmInvites > 0,
notificationCountRooms = otherRooms.totalCount + roomsInvite,
diff --git a/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt
index 43c878624b..9b506b6ed7 100644
--- a/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt
@@ -29,6 +29,7 @@ import im.vector.app.RoomGroupingMethod
import im.vector.app.core.platform.EmptyAction
import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel
+import im.vector.app.features.settings.VectorPreferences
import io.reactivex.Observable
import io.reactivex.schedulers.Schedulers
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
@@ -52,6 +53,7 @@ data class CountInfo(
class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initialState: UnreadMessagesState,
session: Session,
+ private val vectorPreferences: VectorPreferences,
appStateHandler: AppStateHandler)
: VectorViewModel(initialState) {
@@ -126,12 +128,24 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia
}
is RoomGroupingMethod.BySpace -> {
val selectedSpace = appStateHandler.safeActiveSpaceId()
- val counts = session.getNotificationCountForRooms(
+
+ val inviteCount = session.getRoomSummaries(
+ roomSummaryQueryParams { this.memberships = listOf(Membership.INVITE) }
+ ).size
+
+ val totalCount = session.getNotificationCountForRooms(
roomSummaryQueryParams {
this.memberships = listOf(Membership.JOIN)
- this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null)
+ this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null).takeIf {
+ vectorPreferences.labsSpacesOnlyOrphansInHome()
+ } ?: ActiveSpaceFilter.None
}
)
+
+ val counts = RoomAggregateNotificationCount(
+ totalCount.notificationCount + inviteCount,
+ totalCount.highlightCount + inviteCount
+ )
val rootCounts = session.spaceService().getRootSpaceSummaries()
.filter {
// filter out current selection
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
index cabd69ecf9..1f3f527be8 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
@@ -93,9 +93,9 @@ import im.vector.app.core.platform.showOptimizedSnackbar
import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.ui.views.ActiveConferenceView
import im.vector.app.core.ui.views.CurrentCallsView
+import im.vector.app.core.ui.views.FailedMessagesWarningView
import im.vector.app.core.ui.views.JumpToReadMarkerView
import im.vector.app.core.ui.views.KnownCallsViewHolder
-import im.vector.app.core.ui.views.FailedMessagesWarningView
import im.vector.app.core.ui.views.NotificationAreaView
import im.vector.app.core.utils.Debouncer
import im.vector.app.core.utils.DimensionConverter
@@ -164,7 +164,7 @@ import im.vector.app.features.session.coroutineScope
import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.settings.VectorSettingsActivity
import im.vector.app.features.share.SharedData
-import im.vector.app.features.spaces.ShareSpaceBottomSheet
+import im.vector.app.features.spaces.share.ShareSpaceBottomSheet
import im.vector.app.features.themes.ThemeUtils
import im.vector.app.features.widgets.WidgetActivity
import im.vector.app.features.widgets.WidgetArgs
@@ -677,7 +677,7 @@ class RoomDetailFragment @Inject constructor(
private fun handleSpaceShare() {
roomDetailArgs.openShareSpaceForId?.let { spaceId ->
- ShareSpaceBottomSheet.show(childFragmentManager, spaceId)
+ ShareSpaceBottomSheet.show(childFragmentManager, spaceId, true)
view?.post {
handleChatEffect(ChatEffect.CONFETTI)
}
@@ -1745,20 +1745,19 @@ class RoomDetailFragment @Inject constructor(
session.coroutineScope.launch {
val result = runCatching { session.fileService().downloadFile(messageContent = action.messageContent) }
if (!isAdded) return@launch
- result.fold(
- {
- saveMedia(
- context = requireContext(),
- file = it,
- title = action.messageContent.body,
- mediaMimeType = action.messageContent.mimeType ?: getMimeTypeFromUri(requireContext(), it.toUri()),
- notificationUtils = notificationUtils
- )
- },
- {
+ result.mapCatching {
+ saveMedia(
+ context = requireContext(),
+ file = it,
+ title = action.messageContent.body,
+ mediaMimeType = action.messageContent.mimeType ?: getMimeTypeFromUri(requireContext(), it.toUri()),
+ notificationUtils = notificationUtils
+ )
+ }
+ .onFailure {
+ if (!isAdded) return@onFailure
showErrorInSnackbar(it)
}
- )
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt
index 52779c863d..3a9969b43c 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt
@@ -449,7 +449,7 @@ class RoomDetailViewModel @AssistedInject constructor(
widgetSessionId = widgetSessionId.substring(0, 7)
}
val roomId: String = room.roomId
- val confId = roomId.substring(1, roomId.indexOf(":") - 1) + widgetSessionId.toLowerCase(VectorLocale.applicationLocale)
+ val confId = roomId.substring(1, roomId.indexOf(":") - 1) + widgetSessionId.lowercase(VectorLocale.applicationLocale)
val preferredJitsiDomain = tryOrNull {
rawService.getElementWellknown(session.myUserId)
@@ -832,7 +832,7 @@ class RoomDetailViewModel @AssistedInject constructor(
session.spaceService().getSpace(spaceId)
?.addChildren(
state.roomId,
- listOf(session.sessionParams.homeServerHost ?: ""),
+ null,
null,
true
)
@@ -849,7 +849,7 @@ class RoomDetailViewModel @AssistedInject constructor(
session.spaceService().getSpace(slashCommandResult.spaceId)
?.addChildren(
room.roomId,
- listOf(session.sessionParams.homeServerHost ?: ""),
+ null,
null,
false
)
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MatrixItemColorProvider.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MatrixItemColorProvider.kt
index dcbfb13dcc..2defc7bd30 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MatrixItemColorProvider.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MatrixItemColorProvider.kt
@@ -83,7 +83,7 @@ class MatrixItemColorProvider @Inject constructor(
fun getColorFromUserId(userId: String?): Int {
var hash = 0
- userId?.toList()?.map { chr -> hash = (hash shl 5) - hash + chr.toInt() }
+ userId?.toList()?.map { chr -> hash = (hash shl 5) - hash + chr.code }
return getUserColorByIndex(abs(hash))
}
@@ -104,7 +104,7 @@ class MatrixItemColorProvider @Inject constructor(
@ColorRes
private fun getColorFromRoomId(roomId: String?): Int {
- return when ((roomId?.toList()?.sumBy { it.toInt() } ?: 0) % 3) {
+ return when ((roomId?.toList()?.sumOf { it.code } ?: 0) % 3) {
1 -> R.color.riotx_avatar_fill_2
2 -> R.color.riotx_avatar_fill_3
else -> R.color.riotx_avatar_fill_1
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineControllerInterceptorHelper.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineControllerInterceptorHelper.kt
index 72fdef9f7d..389dd15413 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineControllerInterceptorHelper.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineControllerInterceptorHelper.kt
@@ -62,6 +62,7 @@ class TimelineControllerInterceptorHelper(private val positionOfReadMarker: KMut
val firstUnreadEventId = (unreadState as? UnreadState.HasUnread)?.firstUnreadEventId
var atLeastOneVisibleItemSinceLastDaySeparator = false
var atLeastOneVisibleItemsBeforeReadMarker = false
+ var appendReadMarker = false
// Then iterate on models so we have the exact positions in the adapter
modelsIterator.forEach { epoxyModel ->
@@ -72,11 +73,7 @@ class TimelineControllerInterceptorHelper(private val positionOfReadMarker: KMut
}
epoxyModel.getEventIds().forEach { eventId ->
adapterPositionMapping[eventId] = index
- if (epoxyModel.canAppendReadMarker() && eventId == firstUnreadEventId && atLeastOneVisibleItemsBeforeReadMarker) {
- modelsIterator.addReadMarkerItem(callback)
- index++
- positionOfReadMarker.set(index)
- }
+ appendReadMarker = epoxyModel.canAppendReadMarker() && eventId == firstUnreadEventId && atLeastOneVisibleItemsBeforeReadMarker
}
}
if (epoxyModel is DaySeparatorItem) {
@@ -91,6 +88,12 @@ class TimelineControllerInterceptorHelper(private val positionOfReadMarker: KMut
atLeastOneVisibleItemSinceLastDaySeparator = true
}
}
+ if (appendReadMarker) {
+ modelsIterator.addReadMarkerItem(callback)
+ index++
+ positionOfReadMarker.set(index)
+ appendReadMarker = false
+ }
index++
}
previousModelsSize = models.size
@@ -103,8 +106,6 @@ class TimelineControllerInterceptorHelper(private val positionOfReadMarker: KMut
it.setOnVisibilityStateChanged(ReadMarkerVisibilityStateChangedListener(callback))
}
add(readMarker)
- // Use next as we still have some process to do before the next iterator loop
- next()
}
private fun MutableListIterator>.removeCallItemIfNeeded(
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 bc24705e13..246d5052cf 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
@@ -69,12 +69,12 @@ class RoomListViewModel @Inject constructor(
* Filter the rooms if they are part of the current space (children and grand children).
* If current space is null, will return orphan rooms only
*/
- NORMAL,
+ ORPHANS_IF_SPACE_NULL,
/**
* Special case when we don't want to discriminate rooms when current space is null.
* In this case return all.
*/
- NOT_IF_ALL,
+ ALL_IF_SPACE_NULL,
/** Do not filter based on space*/
NONE
}
@@ -131,7 +131,8 @@ class RoomListViewModel @Inject constructor(
},
{
updatableQuery = it
- }
+ },
+ vectorPreferences.labsSpacesOnlyOrphansInHome()
).buildSections(initialState.displayMode)
} else {
GroupRoomListSectionBuilder(
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 06f55d3952..d099ac16b7 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
@@ -50,6 +50,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel() {
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) lateinit var lastFormattedEvent: CharSequence
@EpoxyAttribute lateinit var lastEventTime: CharSequence
@EpoxyAttribute var encryptionTrustLevel: RoomEncryptionTrustLevel? = null
+ @EpoxyAttribute var izPublic: Boolean = false
@EpoxyAttribute var unreadNotificationCount: Int = 0
@EpoxyAttribute var hasUnreadMessage: Boolean = false
@EpoxyAttribute var hasDraft: Boolean = false
@@ -74,6 +75,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel() {
holder.draftView.isVisible = hasDraft
avatarRenderer.render(matrixItem, holder.avatarImageView)
holder.roomAvatarDecorationImageView.render(encryptionTrustLevel)
+ holder.roomAvatarPublicDecorationImageView.isVisible = izPublic
holder.roomAvatarFailSendingImageView.isVisible = hasFailedSending
renderSelection(holder, showSelected)
holder.typingView.setTextOrHide(typingMessage)
@@ -110,6 +112,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel() {
val avatarCheckedImageView by bind(R.id.roomAvatarCheckedImageView)
val avatarImageView by bind(R.id.roomAvatarImageView)
val roomAvatarDecorationImageView by bind(R.id.roomAvatarDecorationImageView)
+ val roomAvatarPublicDecorationImageView by bind(R.id.roomAvatarPublicDecorationImageView)
val roomAvatarFailSendingImageView by bind(R.id.roomAvatarFailSendingImageView)
val rootView by bind(R.id.itemRoomLayout)
}
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 283ed0ac85..e4826af04c 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
@@ -112,6 +112,7 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
.avatarRenderer(avatarRenderer)
// We do not display shield in the room list anymore
// .encryptionTrustLevel(roomSummary.roomEncryptionTrustLevel)
+ .izPublic(roomSummary.isPublic)
.matrixItem(roomSummary.toMatrixItem())
.lastEventTime(latestEventTime)
.typingMessage(typingMessage)
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt
index f7e527a710..266adf6b0c 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt
@@ -41,6 +41,7 @@ import org.matrix.android.sdk.api.session.Session
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.summary.RoomAggregateNotificationCount
import org.matrix.android.sdk.rx.asObservable
class SpaceRoomListSectionBuilder(
@@ -50,7 +51,8 @@ class SpaceRoomListSectionBuilder(
val viewModelScope: CoroutineScope,
private val suggestedRoomJoiningState: LiveData