diff --git a/.github/ISSUE_TEMPLATE/release.yml b/.github/ISSUE_TEMPLATE/release.yml
index b063c93530..b28dbbde69 100644
--- a/.github/ISSUE_TEMPLATE/release.yml
+++ b/.github/ISSUE_TEMPLATE/release.yml
@@ -21,6 +21,8 @@ body:
- [ ] While Weblate is locked, and after the PR from Weblate has been merged, handle all the TODOs in the main `strings.xml` file
- [ ] Run the script `./tools/release/pushPlayStoreMetaData.sh`. You can check in the GooglePlay console the Activity log to check the effect.
+ - [ ] Ensure all [the required PRs](https://github.com/vector-im/element-android/pulls?q=is%3Aopen+is%3Apr+label%3AZ-NextRelease) have been merged
+
### Do the release
- [ ] Make sure `develop` and `main` are up to date (git pull)
diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml
index a1d754b4de..8a892b9b15 100644
--- a/.github/workflows/danger.yml
+++ b/.github/workflows/danger.yml
@@ -11,8 +11,10 @@ jobs:
- run: |
npm install --save-dev @babel/plugin-transform-flow-strip-types
- name: Danger
- uses: danger/danger-js@11.1.1
+ uses: danger/danger-js@11.1.2
with:
args: "--dangerfile tools/danger/dangerfile.js"
env:
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
+ # Fallback for forks
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml
index 6e5e2e4d67..70669596bb 100644
--- a/.github/workflows/quality.yml
+++ b/.github/workflows/quality.yml
@@ -66,11 +66,13 @@ jobs:
yarn add danger-plugin-lint-report --dev
- name: Danger lint
if: always()
- uses: danger/danger-js@11.1.1
+ uses: danger/danger-js@11.1.2
with:
args: "--dangerfile tools/danger/dangerfile-lint.js"
env:
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
+ # Fallback for forks
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Gradle dependency analysis using https://github.com/autonomousapps/dependency-analysis-android-gradle-plugin
dependency-analysis:
diff --git a/.github/workflows/triage-labelled.yml b/.github/workflows/triage-labelled.yml
index 90f03779a6..f478d2bd7b 100644
--- a/.github/workflows/triage-labelled.yml
+++ b/.github/workflows/triage-labelled.yml
@@ -98,7 +98,8 @@ jobs:
# Skip in forks
if: >
github.repository == 'vector-im/element-android' &&
- (contains(github.event.issue.labels.*.name, 'Team: Delight'))
+ (contains(github.event.issue.labels.*.name, 'Team: Delight') ||
+ contains(github.event.issue.labels.*.name, 'Z-AppLayout'))
steps:
- uses: octokit/graphql-action@v2.x
with:
diff --git a/CHANGES.md b/CHANGES.md
index 829b1a0caa..4615ec8ff0 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,51 @@
+Changes in Element v1.4.34 (2022-08-23)
+=======================================
+
+Features ✨
+----------
+ - [Notification] - Handle creation of notification for live location and poll start ([#6746](https://github.com/vector-im/element-android/issues/6746))
+
+Bugfixes 🐛
+----------
+ - Fixes onboarding requiring matrix.org to be accessible on the first step, the server can now be manually changed ([#6718](https://github.com/vector-im/element-android/issues/6718))
+ - Fixing sign in/up for homeservers that rely on the SSO fallback url ([#6827](https://github.com/vector-im/element-android/issues/6827))
+ - Fixes uncaught exceptions in the SyncWorker to cause the worker to become stuck in the failure state ([#6836](https://github.com/vector-im/element-android/issues/6836))
+ - Fixes onboarding captcha crashing when no WebView is available by showing an error with information instead ([#6855](https://github.com/vector-im/element-android/issues/6855))
+ - Removes ability to continue registration after the app has been destroyed, fixes the next steps crashing due to missing information from the previous steps ([#6860](https://github.com/vector-im/element-android/issues/6860))
+ - Fixes crash when exiting the login or registration entry screens whilst they're loading ([#6861](https://github.com/vector-im/element-android/issues/6861))
+ - Fixes server selection being unable to trust certificates ([#6864](https://github.com/vector-im/element-android/issues/6864))
+ - Ensure SyncThread is started when the app is launched after a Push has been received. ([#6884](https://github.com/vector-im/element-android/issues/6884))
+ - Fixes missing firebase notifications after logging in when UnifiedPush distributor is installed ([#6891](https://github.com/vector-im/element-android/issues/6891))
+
+In development 🚧
+----------------
+ - Create DM room only on first message - Trigger the flow when the "Direct Message" action is selected from the room member details screen ([#5525](https://github.com/vector-im/element-android/issues/5525))
+ - added filter tabs for new App layout's Home screen ([#6505](https://github.com/vector-im/element-android/issues/6505))
+ - [App Layout] added dialog to configure app layout ([#6506](https://github.com/vector-im/element-android/issues/6506))
+ - Adds space list bottom sheet for new app layout ([#6749](https://github.com/vector-im/element-android/issues/6749))
+ - [App Layout] Dialpad moved from bottom navigation tab to a separate activity accessed via home screen context menu ([#6787](https://github.com/vector-im/element-android/issues/6787))
+ - Makes toolbar switch title based on space in New App Layout ([#6795](https://github.com/vector-im/element-android/issues/6795))
+ - [Devices management] Add a feature flag and empty screen for future new layout ([#6798](https://github.com/vector-im/element-android/issues/6798))
+ - Adds new chat bottom sheet as the click action of the main FAB in the new app layout ([#6801](https://github.com/vector-im/element-android/issues/6801))
+ - [Devices management] Other sessions section in new layout ([#6806](https://github.com/vector-im/element-android/issues/6806))
+ - [New Layout] Adds space settings accessible through clicking the toolbar ([#6859](https://github.com/vector-im/element-android/issues/6859))
+ - Adds New App Layout FABs (hidden behind feature flag) ([#6693](https://github.com/vector-im/element-android/issues/6693))
+
+SDK API changes ⚠️
+------------------
+ - Rename `DebugService.logDbUsageInfo` (resp. `Session.logDbUsageInfo`) to `DebugService.getDbUsageInfo` (resp. `Session.getDbUsageInfo`) and return a String instead of logging. The caller may want to log the String. ([#6884](https://github.com/vector-im/element-android/issues/6884))
+
+Other changes
+-------------
+ - Removes the Login2 proof of concept - replaced by the FTUE changes ([#5974](https://github.com/vector-im/element-android/issues/5974))
+ - Enable auto-capitalization for Room creation Title field ([#6645](https://github.com/vector-im/element-android/issues/6645))
+ - Decouples the variant logic from the vector module ([#6783](https://github.com/vector-im/element-android/issues/6783))
+ - Add a developer setting to enable LeakCanary at runtime ([#6786](https://github.com/vector-im/element-android/issues/6786))
+ - [Create Room] Reduce some boilerplate with room state event contents ([#6799](https://github.com/vector-im/element-android/issues/6799))
+ - [Call] Memory leak after a call ([#6808](https://github.com/vector-im/element-android/issues/6808))
+ - Fix some string template ([#6843](https://github.com/vector-im/element-android/issues/6843))
+
+
Changes in Element v1.4.32 (2022-08-10)
=======================================
diff --git a/build.gradle b/build.gradle
index afe51cc734..aa8a3e2c4c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -24,12 +24,12 @@ buildscript {
classpath libs.gradle.gradlePlugin
classpath libs.gradle.kotlinPlugin
classpath libs.gradle.hiltPlugin
- classpath 'com.google.firebase:firebase-appdistribution-gradle:3.0.2'
+ classpath 'com.google.firebase:firebase-appdistribution-gradle:3.0.3'
classpath 'com.google.gms:google-services:4.3.13'
classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513'
classpath 'com.google.android.gms:oss-licenses-plugin:0.10.5'
classpath "com.likethesalad.android:stem-plugin:2.1.1"
- classpath 'org.owasp:dependency-check-gradle:7.1.1'
+ classpath 'org.owasp:dependency-check-gradle:7.1.2'
classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.7.10"
classpath "org.jetbrains.kotlinx:kotlinx-knit:0.4.0"
// NOTE: Do not place your application dependencies here; they belong
@@ -44,7 +44,7 @@ plugins {
id "io.gitlab.arturbosch.detekt" version "1.21.0"
// Dependency Analysis
- id 'com.autonomousapps.dependency-analysis' version "1.11.2"
+ id 'com.autonomousapps.dependency-analysis' version "1.12.0"
}
// https://github.com/jeremylong/DependencyCheck
@@ -151,6 +151,8 @@ allprojects {
"experimental:comment-wrapping",
// - A KDoc comment after any other element on the same line must be separated by a new line
"experimental:kdoc-wrapping",
+ // Ignore error "Redundant curly braces", since we use it to fix false positives, for instance in "elementLogs.${i}.txt"
+ "string-template",
]
}
diff --git a/changelog.d/5525.wip b/changelog.d/5525.wip
new file mode 100644
index 0000000000..0d54c06b6a
--- /dev/null
+++ b/changelog.d/5525.wip
@@ -0,0 +1 @@
+Create DM room only on first message - Create the DM and navigate to the new room after sending an event
diff --git a/changelog.d/6505.wip b/changelog.d/6505.wip
deleted file mode 100644
index 1109c5fff1..0000000000
--- a/changelog.d/6505.wip
+++ /dev/null
@@ -1 +0,0 @@
-added filter tabs for new App layout's Home screen
diff --git a/changelog.d/6565.wip b/changelog.d/6565.wip
new file mode 100644
index 0000000000..0e89c63e75
--- /dev/null
+++ b/changelog.d/6565.wip
@@ -0,0 +1 @@
+[App Layout] Bottom navigation tabs are removed for new home screen
diff --git a/changelog.d/6645.misc b/changelog.d/6645.misc
deleted file mode 100644
index b24655879d..0000000000
--- a/changelog.d/6645.misc
+++ /dev/null
@@ -1 +0,0 @@
-Enable auto-capitalization for Room creation Title field
diff --git a/changelog.d/6693.feature b/changelog.d/6693.feature
deleted file mode 100644
index 5e905766a9..0000000000
--- a/changelog.d/6693.feature
+++ /dev/null
@@ -1 +0,0 @@
-Adds New App Layout FABs (hidden behind feature flag)
diff --git a/changelog.d/6746.feature b/changelog.d/6746.feature
deleted file mode 100644
index 7869e7f57a..0000000000
--- a/changelog.d/6746.feature
+++ /dev/null
@@ -1 +0,0 @@
-[Notification] - Handle creation of notification for live location and poll start
diff --git a/changelog.d/6750.wip b/changelog.d/6750.wip
new file mode 100644
index 0000000000..2e18110c97
--- /dev/null
+++ b/changelog.d/6750.wip
@@ -0,0 +1 @@
+[App Layout] fixed space switching dialog measured with wrong height sometimes
diff --git a/changelog.d/6783.misc b/changelog.d/6783.misc
deleted file mode 100644
index d1095c1203..0000000000
--- a/changelog.d/6783.misc
+++ /dev/null
@@ -1 +0,0 @@
-Decouples the variant logic from the vector module
diff --git a/changelog.d/6786.misc b/changelog.d/6786.misc
deleted file mode 100644
index a916336ae4..0000000000
--- a/changelog.d/6786.misc
+++ /dev/null
@@ -1 +0,0 @@
-Add a developer setting to enable LeakCanary at runtime
diff --git a/changelog.d/6798.wip b/changelog.d/6798.wip
deleted file mode 100644
index a16270666b..0000000000
--- a/changelog.d/6798.wip
+++ /dev/null
@@ -1 +0,0 @@
-[Devices management] Add a feature flag and empty screen for future new layout
diff --git a/changelog.d/6799.misc b/changelog.d/6799.misc
deleted file mode 100644
index b756c2c07b..0000000000
--- a/changelog.d/6799.misc
+++ /dev/null
@@ -1 +0,0 @@
-[Create Room] Reduce some boilerplate with room state event contents
diff --git a/changelog.d/6806.wip b/changelog.d/6806.wip
deleted file mode 100644
index 9b00139c62..0000000000
--- a/changelog.d/6806.wip
+++ /dev/null
@@ -1 +0,0 @@
-[Devices management] Other sessions section in new layout
diff --git a/changelog.d/6808.misc b/changelog.d/6808.misc
deleted file mode 100644
index 06eeff862b..0000000000
--- a/changelog.d/6808.misc
+++ /dev/null
@@ -1 +0,0 @@
-[Call] Memory leak after a call
diff --git a/changelog.d/6889.wip b/changelog.d/6889.wip
new file mode 100644
index 0000000000..067973aad9
--- /dev/null
+++ b/changelog.d/6889.wip
@@ -0,0 +1 @@
+[App Layout] new room invites screen
diff --git a/changelog.d/6894.misc b/changelog.d/6894.misc
new file mode 100644
index 0000000000..abb1a69a71
--- /dev/null
+++ b/changelog.d/6894.misc
@@ -0,0 +1 @@
+Remove FragmentModule and the Fragment factory. No need to Inject the constructor on your Fragment, just add @AndroidEntryPoint annotation and @Inject class members.
diff --git a/changelog.d/6926.misc b/changelog.d/6926.misc
new file mode 100644
index 0000000000..dc1330d9fc
--- /dev/null
+++ b/changelog.d/6926.misc
@@ -0,0 +1 @@
+Focus input field when editing homeserver address to speed up login and registration.
\ No newline at end of file
diff --git a/dependencies.gradle b/dependencies.gradle
index 93a62a548e..7a9ed3f931 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -22,7 +22,7 @@ def markwon = "4.6.2"
def moshi = "1.13.0"
def lifecycle = "2.5.1"
def flowBinding = "1.2.0"
-def flipper = "0.156.0"
+def flipper = "0.161.0"
def epoxy = "4.6.2"
def mavericks = "2.7.0"
def glide = "4.13.2"
@@ -30,7 +30,7 @@ def bigImageViewer = "1.8.1"
def jjwt = "0.11.5"
def vanniktechEmoji = "0.15.0"
-def fragment = "1.5.1"
+def fragment = "1.5.2"
// Testing
def mockk = "1.12.3" // We need to use 1.12.3 to have mocking in androidTest until a new version is released: https://github.com/mockk/mockk/issues/819
@@ -104,6 +104,7 @@ ext.libs = [
'moshi' : "com.squareup.moshi:moshi:$moshi",
'moshiKt' : "com.squareup.moshi:moshi-kotlin:$moshi",
'moshiKotlin' : "com.squareup.moshi:moshi-kotlin-codegen:$moshi",
+ 'moshiAdapters' : "com.squareup.moshi:moshi-adapters:$moshi",
'retrofit' : "com.squareup.retrofit2:retrofit:$retrofit",
'retrofitMoshi' : "com.squareup.retrofit2:converter-moshi:$retrofit"
],
diff --git a/docs/danger.md b/docs/danger.md
index acf14018e6..afa3555469 100644
--- a/docs/danger.md
+++ b/docs/danger.md
@@ -85,6 +85,8 @@ To let Danger check all the PRs, including PRs form forks, a GitHub account have
- password: Stored on Passbolt
- GitHub token: A token with limited access has been created and added to the repository https://github.com/vector-im/element-android as secret DANGER_GITHUB_API_TOKEN. This token is not saved anywhere else. In case of problem, just delete it and create a new one, then update the secret.
+PRs from forks do not always have access to the secret `secrets.DANGER_GITHUB_API_TOKEN`, so `secrets.GITHUB_TOKEN` is also provided to the job environment. If `secrets.DANGER_GITHUB_API_TOKEN` is available, it will be used, so user `ElementBot` will comment the PR. Else `secrets.GITHUB_TOKEN` will be used, and bot `github-actions` will comment the PR.
+
## Useful links
- https://danger.systems/
diff --git a/docs/hilt_migration.md b/docs/hilt_migration.md
index 50021e9792..0556cf85dc 100644
--- a/docs/hilt_migration.md
+++ b/docs/hilt_migration.md
@@ -7,8 +7,8 @@ Hilt is built on top of Dagger 2 and simplify usage by removing needs to create
When you create a new feature, you should have the following:
Annotate your Activity with @AndroidEntryPoint
+Annotate your Fragment with @AndroidEntryPoint
If you have a BottomSheetFragment => Annotate it with @AndroidEntryPoint
-Otherwise => Add your Fragment to the FragmentModule
Add your ViewModel.Factory to the MavericksViewModelModule
Makes sure your ViewModel as the following code:
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40104300.txt b/fastlane/metadata/android/cs-CZ/changelogs/40104300.txt
new file mode 100644
index 0000000000..e74d892209
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40104300.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Umožňuje vylepšené přihlašování a registraci.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40104310.txt b/fastlane/metadata/android/cs-CZ/changelogs/40104310.txt
new file mode 100644
index 0000000000..e74d892209
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40104310.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Umožňuje vylepšené přihlašování a registraci.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/en-US/changelogs/40104340.txt b/fastlane/metadata/android/en-US/changelogs/40104340.txt
new file mode 100644
index 0000000000..61db61727a
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40104340.txt
@@ -0,0 +1,2 @@
+Main changes in this version: Various bug fixes and stability improvements.
+Full changelog: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/et/changelogs/40104300.txt b/fastlane/metadata/android/et/changelogs/40104300.txt
new file mode 100644
index 0000000000..e01c9b4329
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40104300.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: senisest parem liitumise ja sisselogimise töövoog.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/et/changelogs/40104310.txt b/fastlane/metadata/android/et/changelogs/40104310.txt
new file mode 100644
index 0000000000..e01c9b4329
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40104310.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: senisest parem liitumise ja sisselogimise töövoog.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fa/changelogs/40104300.txt b/fastlane/metadata/android/fa/changelogs/40104300.txt
new file mode 100644
index 0000000000..7a0e87b263
--- /dev/null
+++ b/fastlane/metadata/android/fa/changelogs/40104300.txt
@@ -0,0 +1,2 @@
+تغییرات عمده در این نگارش: به کار انداختن ورود بهبود یافته و سفرهای ورود.
+گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fa/changelogs/40104310.txt b/fastlane/metadata/android/fa/changelogs/40104310.txt
new file mode 100644
index 0000000000..7a0e87b263
--- /dev/null
+++ b/fastlane/metadata/android/fa/changelogs/40104310.txt
@@ -0,0 +1,2 @@
+تغییرات عمده در این نگارش: به کار انداختن ورود بهبود یافته و سفرهای ورود.
+گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fr-FR/changelogs/40104300.txt b/fastlane/metadata/android/fr-FR/changelogs/40104300.txt
new file mode 100644
index 0000000000..328e66aaa0
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/40104300.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Activation de l’authentification et du parcours d’inscription améliorés.
+Intégralité des changements : https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fr-FR/changelogs/40104310.txt b/fastlane/metadata/android/fr-FR/changelogs/40104310.txt
new file mode 100644
index 0000000000..328e66aaa0
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/40104310.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Activation de l’authentification et du parcours d’inscription améliorés.
+Intégralité des changements : https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/gl/changelogs/40104160.txt b/fastlane/metadata/android/gl-ES/changelogs/40104160.txt
similarity index 100%
rename from fastlane/metadata/android/gl/changelogs/40104160.txt
rename to fastlane/metadata/android/gl-ES/changelogs/40104160.txt
diff --git a/fastlane/metadata/android/gl/changelogs/40104180.txt b/fastlane/metadata/android/gl-ES/changelogs/40104180.txt
similarity index 100%
rename from fastlane/metadata/android/gl/changelogs/40104180.txt
rename to fastlane/metadata/android/gl-ES/changelogs/40104180.txt
diff --git a/fastlane/metadata/android/gl/changelogs/40104190.txt b/fastlane/metadata/android/gl-ES/changelogs/40104190.txt
similarity index 100%
rename from fastlane/metadata/android/gl/changelogs/40104190.txt
rename to fastlane/metadata/android/gl-ES/changelogs/40104190.txt
diff --git a/fastlane/metadata/android/gl/changelogs/40104200.txt b/fastlane/metadata/android/gl-ES/changelogs/40104200.txt
similarity index 100%
rename from fastlane/metadata/android/gl/changelogs/40104200.txt
rename to fastlane/metadata/android/gl-ES/changelogs/40104200.txt
diff --git a/fastlane/metadata/android/gl/changelogs/40104220.txt b/fastlane/metadata/android/gl-ES/changelogs/40104220.txt
similarity index 100%
rename from fastlane/metadata/android/gl/changelogs/40104220.txt
rename to fastlane/metadata/android/gl-ES/changelogs/40104220.txt
diff --git a/fastlane/metadata/android/gl/changelogs/40104230.txt b/fastlane/metadata/android/gl-ES/changelogs/40104230.txt
similarity index 100%
rename from fastlane/metadata/android/gl/changelogs/40104230.txt
rename to fastlane/metadata/android/gl-ES/changelogs/40104230.txt
diff --git a/fastlane/metadata/android/gl/changelogs/40104240.txt b/fastlane/metadata/android/gl-ES/changelogs/40104240.txt
similarity index 100%
rename from fastlane/metadata/android/gl/changelogs/40104240.txt
rename to fastlane/metadata/android/gl-ES/changelogs/40104240.txt
diff --git a/fastlane/metadata/android/gl/changelogs/40104250.txt b/fastlane/metadata/android/gl-ES/changelogs/40104250.txt
similarity index 100%
rename from fastlane/metadata/android/gl/changelogs/40104250.txt
rename to fastlane/metadata/android/gl-ES/changelogs/40104250.txt
diff --git a/fastlane/metadata/android/gl/changelogs/40104260.txt b/fastlane/metadata/android/gl-ES/changelogs/40104260.txt
similarity index 100%
rename from fastlane/metadata/android/gl/changelogs/40104260.txt
rename to fastlane/metadata/android/gl-ES/changelogs/40104260.txt
diff --git a/fastlane/metadata/android/gl/changelogs/40104270.txt b/fastlane/metadata/android/gl-ES/changelogs/40104270.txt
similarity index 100%
rename from fastlane/metadata/android/gl/changelogs/40104270.txt
rename to fastlane/metadata/android/gl-ES/changelogs/40104270.txt
diff --git a/fastlane/metadata/android/gl/full_description.txt b/fastlane/metadata/android/gl-ES/full_description.txt
similarity index 100%
rename from fastlane/metadata/android/gl/full_description.txt
rename to fastlane/metadata/android/gl-ES/full_description.txt
diff --git a/fastlane/metadata/android/gl/short_description.txt b/fastlane/metadata/android/gl-ES/short_description.txt
similarity index 100%
rename from fastlane/metadata/android/gl/short_description.txt
rename to fastlane/metadata/android/gl-ES/short_description.txt
diff --git a/fastlane/metadata/android/gl/title.txt b/fastlane/metadata/android/gl-ES/title.txt
similarity index 100%
rename from fastlane/metadata/android/gl/title.txt
rename to fastlane/metadata/android/gl-ES/title.txt
diff --git a/fastlane/metadata/android/id/changelogs/40104300.txt b/fastlane/metadata/android/id/changelogs/40104300.txt
new file mode 100644
index 0000000000..3d8d13e23d
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40104300.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Mengaktifkan perjalanan masuk dan keluar yang diperbaiki.
+Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/id/changelogs/40104310.txt b/fastlane/metadata/android/id/changelogs/40104310.txt
new file mode 100644
index 0000000000..3d8d13e23d
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40104310.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Mengaktifkan perjalanan masuk dan keluar yang diperbaiki.
+Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/id/full_description.txt b/fastlane/metadata/android/id/full_description.txt
index d3bed0bf6b..20d805c582 100644
--- a/fastlane/metadata/android/id/full_description.txt
+++ b/fastlane/metadata/android/id/full_description.txt
@@ -1,42 +1,42 @@
-Element adalah perpesanan yang aman dan aplikasi kolaborasi tim produktivitas yang ideal untuk obrolan grup saat bekerja jarak jauh. Aplikasi perpesanan ini menggunakan enkripsi ujung-ke-ujung untuk memberikan konferensi video, pembagian file, dan panggilan suara yang aman.
+Element adalah perpesanan yang aman dan aplikasi kolaborasi tim produktivitas yang ideal untuk obrolan grup saat bekerja jarak jauh. Aplikasi perpesanan ini menggunakan enkripsi ujung-ke-ujung untuk menyediakan konferensi video, pembagian berkas, dan panggilan suara yang aman.
-Fitur Element termasuk
-- Alat komunikasi online yang canggih
+Fitur Element termasuk:
+- Alat komunikasi daring yang canggih
- Pesan-pesan yang dienkripsi sepenuhnya untuk memungkinkan komunikasi perusahaan yang lebih aman, bahkan untuk pekerja jarak jauh
-- Obrolan terdesentralisasi berdasarkan kerangka Matrix yang sumber terbuka
-- Pembagian file aman dengan data terenkripsi saat mengelola proyek
+- Obrolan terdesentralisasi berdasarkan kerangka kerja Matrix yang sumber terbuka
+- Pembagian berkas aman dengan data terenkripsi saat mengelola proyek
- Obrolan video dengan VoIP dan pembagian layar
-- Integrasi yang mudah dengan alat kolaborasi online favorit Anda, alat manajemen proyek, layanan VoIP dan aplikasi perpesanan tim lainnya
+- Integrasi yang mudah dengan alat kolaborasi daring favorit Anda, alat pengelola proyek, layanan VoIP dan aplikasi perpesanan tim lainnya
-Element benar-benar berbeda dari aplikasi perpesanan dan aplikasi kolaborasi lainnya. Element beroperasi pada Matrix, jaringan terbuka untuk pengiriman pesan yang aman dan komunikasi terdesentralisasi.
+Element benar-benar berbeda dari aplikasi perpesanan dan aplikasi kolaborasi lainnya. Element beroperasi pada Matrix, jaringan terbuka untuk pengiriman pesan yang aman dan komunikasi yang terdesentralisasi.
Perpesanan dengan privasi dan enkripsi
-Element melindungi Anda dari iklan yang tidak diinginkan, penambangan data dan taman berdinding. Element juga mengamankan semua data Anda, komunikasi video dan suara satu-ke-satu dengan enkripsi ujung-ke-ujung dan verifikasi perangkat menggunakan penandatanganan silang.
+Element melindungi Anda dari iklan yang tidak diinginkan, penambangan data, dan taman berdinding. Element juga mengamankan semua data Anda, komunikasi video dan suara satu-ke-satu dengan enkripsi ujung-ke-ujung, dan verifikasi perangkat menggunakan penandatanganan silang.
-Element memberikan Anda kendali atas privasi Anda sambil memungkinkan Anda untuk berkomunikasi dengan siapa saja secara aman di jaringan Matrix, atau alat kolaborasi bisnis lainnya dengan mengintegrasikan aplikasi-aplikasi seperti Slack.
+Element memberikan Anda kendali atas privasi Anda sambil memungkinkan Anda untuk berkomunikasi dengan siapa saja secara aman di jaringan Matrix, atau alat kolaborasi bisnis lainnya dengan mengintegrasikan aplikasi seperti Slack.
-Element dapat dihost sendiri
-Untuk memungkinkan lebih banyak kendali atas data dan pesan-pesan sensitif Anda, Element dapat dihost sendiri atau Anda dapat memilih host berbasis Matrix, standar untuk komunikasi terdesentralisasi sumber terbuka. Element memberi Anda privasi, kepatuhan keamanan, dan fleksibilitas integrasi.
+Element dapat di-host sendiri
+Untuk memungkinkan lebih banyak kendali atas data dan pesan-pesan sensitif Anda, Element dapat dilayani sendiri atau Anda dapat memilih layanan berbasis Matrix, standar untuk komunikasi terdesentralisasi sumber terbuka. Element memberikan Anda privasi, kepatuhan keamanan, dan fleksibilitas integrasi.
Miliki data Anda
Anda memutuskan di mana untuk menyimpan data dan pesan-pesan Anda, tanpa risiko penambangan data atau akses dari pihak ketiga.
Element menempatkan Anda dalam kendali dengan cara yang berbeda:
-1. Dapatkan akun gratis pada server publik matrix.org yang dihost oleh pengembang Matrix, atau memilih dari ribuan server publik yang dihost oleh sukarelawan
-2. Host sendiri akun Anda dengan menjalankan server pada infrastruktur IT Anda sendiri
+1. Dapatkan akun gratis pada server publik matrix.org yang dilayani oleh pengembang Matrix, atau memilih dari ribuan server publik yang dilayani oleh sukarelawan
+2. Layani akun Anda sendiri dengan menjalankan server pada infrastruktur IT Anda sendiri
3. Daftar untuk akun di server khusus dengan berlangganan platform hosting Layanan Matrix Element
Perpesanan dan kolaborasi terbuka
-Anda dapat mengobrol dengan siapa saja di jaringan Matrix, jika mereka menggunakan Element, aplikasi Matrix lain atau bahkan menggunakan aplikasi perpesanan yang berbeda.
+Anda dapat mengobrol dengan siapa saja di jaringan Matrix, jika mereka menggunakan Element, aplikasi Matrix lain, atau bahkan menggunakan aplikasi perpesanan yang berbeda.
Sangat aman
-Enkripsi ujung-ke-ujung yang nyata (hanya mereka yang dalam obrolan dapat mendekripsi pesan), dan verifikasi perangkat menggunakan penandatanganan silang.
+Enkripsi ujung-ke-ujung yang nyata (hanya mereka yang di dalam obrolan dapat mendekripsikan pesan), dan verifikasi perangkat menggunakan penandatanganan silang.
Komunikasi dan integrasi lengkap
-Perpesanan, panggilan suara dan video, pembagian file, pembagian layar dan banyak integrasi bot dan widget. Buat ruangan dan komunitas, tetap terhubung dan selesaikan hal-hal penting.
+Perpesanan, panggilan suara dan video, pembagian berkas, pembagian layar dan banyak integrasi bot dan widget. Buat ruangan dan komunitas, tetap terhubung, dan selesaikan hal-hal penting.
Ambil di mana Anda tinggalkan
-Tetap terhubung di mana Anda berada, dengan riwayat pesan yang disinkronkan di semua perangkat Anda dan web di https://app.element.io
+Tetap terhubung di mana Anda berada, dengan riwayat pesan yang disinkronkan pada semua perangkat Anda dan pada web di https://app.element.io
Sumber terbuka
-Element Android adalah proyek sumber terbuka, dihost oleh GitHub. Silakan laporkan masalah yang Anda temukan, atau membuat kontribusi ke pengembangannya di https://github.com/vector-im/element-android
+Element Android adalah proyek sumber terbuka, dilayani oleh GitHub. Silakan laporkan masalah yang Anda temukan, atau membuat kontribusi ke pengembangannya di https://github.com/vector-im/element-android
diff --git a/fastlane/metadata/android/it-IT/changelogs/40104300.txt b/fastlane/metadata/android/it-IT/changelogs/40104300.txt
new file mode 100644
index 0000000000..40d9618137
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40104300.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: introduce i percorsi migliorati di accesso e registrazione.
+Cronologia completa: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/it-IT/changelogs/40104310.txt b/fastlane/metadata/android/it-IT/changelogs/40104310.txt
new file mode 100644
index 0000000000..40d9618137
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40104310.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: introduce i percorsi migliorati di accesso e registrazione.
+Cronologia completa: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40104300.txt b/fastlane/metadata/android/pt-BR/changelogs/40104300.txt
new file mode 100644
index 0000000000..5f1aaf4b3d
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40104300.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Habilita as jornadas melhoradas de sign in e sign up.
+Changelog completo: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40104310.txt b/fastlane/metadata/android/pt-BR/changelogs/40104310.txt
new file mode 100644
index 0000000000..5f1aaf4b3d
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40104310.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Habilita as jornadas melhoradas de sign in e sign up.
+Changelog completo: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sk/changelogs/40104300.txt b/fastlane/metadata/android/sk/changelogs/40104300.txt
new file mode 100644
index 0000000000..dd0f554532
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40104300.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Umožňuje vylepšené postupy prihlasovania a registrácie.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sk/changelogs/40104310.txt b/fastlane/metadata/android/sk/changelogs/40104310.txt
new file mode 100644
index 0000000000..dd0f554532
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40104310.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Umožňuje vylepšené postupy prihlasovania a registrácie.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/uk/changelogs/40104300.txt b/fastlane/metadata/android/uk/changelogs/40104300.txt
new file mode 100644
index 0000000000..727508a0cc
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40104300.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: Поліпшені вхід і реєстрація.
+Перелік усіх змін: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/uk/changelogs/40104310.txt b/fastlane/metadata/android/uk/changelogs/40104310.txt
new file mode 100644
index 0000000000..727508a0cc
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40104310.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: Поліпшені вхід і реєстрація.
+Перелік усіх змін: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40104300.txt b/fastlane/metadata/android/zh-TW/changelogs/40104300.txt
new file mode 100644
index 0000000000..3055389b2b
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40104300.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:啟用改善的登入與註冊流程。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40104310.txt b/fastlane/metadata/android/zh-TW/changelogs/40104310.txt
new file mode 100644
index 0000000000..3055389b2b
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40104310.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:啟用改善的登入與註冊流程。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases
diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle
index e6b526585b..faa798c9dc 100644
--- a/matrix-sdk-android/build.gradle
+++ b/matrix-sdk-android/build.gradle
@@ -17,7 +17,7 @@ buildscript {
}
}
dependencies {
- classpath "io.realm:realm-gradle-plugin:10.11.0"
+ classpath "io.realm:realm-gradle-plugin:10.11.1"
}
}
@@ -60,7 +60,7 @@ android {
// that the app's state is completely cleared between tests.
testInstrumentationRunnerArguments clearPackageData: 'true'
- buildConfigField "String", "SDK_VERSION", "\"1.4.34\""
+ buildConfigField "String", "SDK_VERSION", "\"1.4.36\""
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\""
@@ -163,6 +163,7 @@ dependencies {
implementation 'com.squareup.okhttp3:logging-interceptor'
implementation libs.squareup.moshi
+ implementation libs.squareup.moshiAdapters
kapt libs.squareup.moshiKotlin
api "com.atlassian.commonmark:commonmark:0.13.0"
@@ -199,7 +200,7 @@ dependencies {
implementation libs.apache.commonsImaging
// Phone number https://github.com/google/libphonenumber
- implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.53'
+ implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.54'
testImplementation libs.tests.junit
// Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/debug/DebugService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/debug/DebugService.kt
index d0cee08831..7f5e4f2ee7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/debug/DebugService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/debug/DebugService.kt
@@ -28,7 +28,7 @@ interface DebugService {
fun getAllRealmConfigurations(): List
/**
- * Prints out info on DB size to logcat.
+ * Get info on DB size.
*/
- fun logDbUsageInfo()
+ fun getDbUsageInfo(): String
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt
index 68b931b33c..5b41ddaaec 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt
@@ -89,10 +89,14 @@ fun Throwable.isInvalidUIAAuth() = this is Failure.ServerError &&
fun Throwable.isHomeserverUnavailable() = this is Failure.NetworkConnection &&
this.ioException is UnknownHostException
+fun Throwable.isHomeserverConnectionError() = this is Failure.NetworkConnection
+
fun Throwable.isMissingEmailVerification() = this is Failure.ServerError &&
error.code == MatrixError.M_UNAUTHORIZED &&
error.message == "Unable to get validated threepid"
+fun Throwable.isUnrecognisedCertificate() = this is Failure.UnrecognizedCertificateFailure
+
/**
* Try to convert to a RegistrationFlowResponse. Return null in the cases it's not possible
*/
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt
index 63c1c25130..13993149f4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt
@@ -323,9 +323,9 @@ interface Session {
fun getUiaSsoFallbackUrl(authenticationSessionId: String): String
/**
- * Debug API, will print out info on DB size to logcat.
+ * Debug API, will return info about the DB.
*/
- fun logDbUsageInfo()
+ fun getDbUsageInfo(): String
/**
* Debug API, return the list of all RealmConfiguration used by this session.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt
index 8fdbba21c5..84c25776e7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt
@@ -70,6 +70,9 @@ object EventType {
const val STATE_ROOM_ENCRYPTION = "m.room.encryption"
const val STATE_ROOM_SERVER_ACL = "m.room.server_acl"
+ // This type is for local purposes, it should never be processed by the server
+ const val LOCAL_STATE_ROOM_THIRD_PARTY_INVITE = "local.room.third_party_invite"
+
// Call Events
const val CALL_INVITE = "m.call.invite"
const val CALL_CANDIDATES = "m.call.candidates"
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/ThreePid.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/ThreePid.kt
index 6bcf576824..24748f88e4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/ThreePid.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/ThreePid.kt
@@ -18,10 +18,14 @@ package org.matrix.android.sdk.api.session.identity
import com.google.i18n.phonenumbers.NumberParseException
import com.google.i18n.phonenumbers.PhoneNumberUtil
+import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.internal.session.profile.ThirdPartyIdentifier
sealed class ThreePid(open val value: String) {
+ @JsonClass(generateAdapter = true)
data class Email(val email: String) : ThreePid(email)
+
+ @JsonClass(generateAdapter = true)
data class Msisdn(val msisdn: String) : ThreePid(msisdn)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt
index b7b0cc890b..d6eb7b30d3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt
@@ -17,13 +17,16 @@
package org.matrix.android.sdk.api.session.room.model.create
import android.net.Uri
+import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.api.session.identity.ThreePid
import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
+import org.matrix.android.sdk.internal.di.MoshiProvider
+@JsonClass(generateAdapter = true)
open class CreateRoomParams {
/**
* A public visibility indicates that the room will be shown in the published room list.
@@ -61,12 +64,12 @@ open class CreateRoomParams {
* A list of user IDs to invite to the room.
* This will tell the server to invite everyone in the list to the newly created room.
*/
- val invitedUserIds = mutableListOf()
+ var invitedUserIds = mutableListOf()
/**
* A list of objects representing third party IDs to invite into the room.
*/
- val invite3pids = mutableListOf()
+ var invite3pids = mutableListOf()
/**
* Initial Guest Access.
@@ -99,14 +102,14 @@ open class CreateRoomParams {
* The server will clobber the following keys: creator.
* Future versions of the specification may allow the server to clobber other keys.
*/
- val creationContent = mutableMapOf()
+ var creationContent = mutableMapOf()
/**
* A list of state events to set in the new room. This allows the user to override the default state events
* set in the new room. The expected format of the state events are an object with type, state_key and content keys set.
* Takes precedence over events set by preset, but gets overridden by name and topic keys.
*/
- val initialStates = mutableListOf()
+ var initialStates = mutableListOf()
/**
* Set to true to disable federation of this room.
@@ -151,7 +154,7 @@ open class CreateRoomParams {
* Supported value: MXCRYPTO_ALGORITHM_MEGOLM.
*/
var algorithm: String? = null
- private set
+ internal set
var historyVisibility: RoomHistoryVisibility? = null
@@ -161,10 +164,18 @@ open class CreateRoomParams {
var roomVersion: String? = null
- var featurePreset: RoomFeaturePreset? = null
+ @Transient var featurePreset: RoomFeaturePreset? = null
companion object {
- private const val CREATION_CONTENT_KEY_M_FEDERATE = "m.federate"
- private const val CREATION_CONTENT_KEY_ROOM_TYPE = "type"
+ internal const val CREATION_CONTENT_KEY_M_FEDERATE = "m.federate"
+ internal const val CREATION_CONTENT_KEY_ROOM_TYPE = "type"
+
+ fun fromJson(json: String?): CreateRoomParams? {
+ return json?.let { MoshiProvider.providesMoshi().adapter(CreateRoomParams::class.java).fromJson(it) }
+ }
}
}
+
+internal fun CreateRoomParams.toJSONString(): String {
+ return MoshiProvider.providesMoshi().adapter(CreateRoomParams::class.java).toJson(this)
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomStateEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomStateEvent.kt
index fcfdc3e333..d89c72c513 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomStateEvent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomStateEvent.kt
@@ -16,8 +16,10 @@
package org.matrix.android.sdk.api.session.room.model.create
+import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.session.events.model.Content
+@JsonClass(generateAdapter = true)
data class CreateRoomStateEvent(
/**
* Required. The type of event to send.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncService.kt
index 71f7ab8494..6640b8a9af 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncService.kt
@@ -53,6 +53,11 @@ interface SyncService {
*/
fun getSyncState(): SyncState
+ /**
+ * This method returns true if the sync thread is alive, i.e. started.
+ */
+ fun isSyncThreadAlive(): Boolean
+
/**
* This method allows to listen the sync state.
* @return a [LiveData] of [SyncState].
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt
index bb14b417dd..405757e3b3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt
@@ -16,10 +16,12 @@
package org.matrix.android.sdk.internal.crypto.tasks
import org.matrix.android.sdk.api.session.events.model.Event
+import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho
import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.session.room.RoomAPI
+import org.matrix.android.sdk.internal.session.room.create.CreateRoomFromLocalRoomTask
import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask
import org.matrix.android.sdk.internal.session.room.send.LocalEchoRepository
import org.matrix.android.sdk.internal.task.Task
@@ -37,12 +39,17 @@ internal class DefaultSendEventTask @Inject constructor(
private val localEchoRepository: LocalEchoRepository,
private val encryptEventTask: EncryptEventTask,
private val loadRoomMembersTask: LoadRoomMembersTask,
+ private val createRoomFromLocalRoomTask: CreateRoomFromLocalRoomTask,
private val roomAPI: RoomAPI,
private val globalErrorReceiver: GlobalErrorReceiver
) : SendEventTask {
override suspend fun execute(params: SendEventTask.Params): String {
try {
+ if (params.event.isLocalRoomEvent) {
+ return createRoomAndSendEvent(params)
+ }
+
// Make sure to load all members in the room before sending the event.
params.event.roomId
?.takeIf { params.encrypt }
@@ -78,6 +85,12 @@ internal class DefaultSendEventTask @Inject constructor(
}
}
+ private suspend fun createRoomAndSendEvent(params: SendEventTask.Params): String {
+ val roomId = createRoomFromLocalRoomTask.execute(CreateRoomFromLocalRoomTask.Params(params.event.roomId.orEmpty()))
+ Timber.d("State event: convert local room (${params.event.roomId}) to existing room ($roomId) before sending the event.")
+ return execute(params.copy(event = params.event.copy(roomId = roomId)))
+ }
+
@Throws
private suspend fun handleEncryption(params: SendEventTask.Params): Event {
if (params.encrypt && !params.event.isEncrypted()) {
@@ -91,4 +104,7 @@ internal class DefaultSendEventTask @Inject constructor(
}
return params.event
}
+
+ private val Event.isLocalRoomEvent
+ get() = RoomLocalEcho.isLocalEchoId(roomId.orEmpty())
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt
index 861a7a3a77..23a75d2bb3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt
@@ -76,12 +76,12 @@ internal class VerificationTransportToDevice(
.configureWith(SendToDeviceTask.Params(MessageType.MSGTYPE_VERIFICATION_REQUEST, contentMap)) {
this.callback = object : MatrixCallback {
override fun onSuccess(data: Unit) {
- Timber.v("## verification [$tx.transactionId] send toDevice request success")
+ Timber.v("## verification [${tx?.transactionId}] send toDevice request success")
callback.invoke(localId, validKeyReq)
}
override fun onFailure(failure: Throwable) {
- Timber.e("## verification [$tx.transactionId] failed to send toDevice request")
+ Timber.e("## verification [${tx?.transactionId}] failed to send toDevice request")
}
}
}
@@ -103,12 +103,12 @@ internal class VerificationTransportToDevice(
.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_READY, contentMap)) {
this.callback = object : MatrixCallback {
override fun onSuccess(data: Unit) {
- Timber.v("## verification [$tx.transactionId] send toDevice request success")
+ Timber.v("## verification [${tx?.transactionId}] send toDevice request success")
callback?.invoke()
}
override fun onFailure(failure: Throwable) {
- Timber.e("## verification [$tx.transactionId] failed to send toDevice request")
+ Timber.e("## verification [${tx?.transactionId}] failed to send toDevice request")
}
}
}
@@ -136,7 +136,7 @@ internal class VerificationTransportToDevice(
.configureWith(SendToDeviceTask.Params(type, contentMap)) {
this.callback = object : MatrixCallback {
override fun onSuccess(data: Unit) {
- Timber.v("## SAS verification [$tx.transactionId] toDevice type '$type' success.")
+ Timber.v("## SAS verification [${tx.transactionId}] toDevice type '$type' success.")
if (onDone != null) {
onDone()
} else {
@@ -149,7 +149,7 @@ internal class VerificationTransportToDevice(
}
override fun onFailure(failure: Throwable) {
- Timber.e("## SAS verification [$tx.transactionId] failed to send toDevice in state : $tx.state")
+ Timber.e("## SAS verification [${tx.transactionId}] failed to send toDevice in state : ${tx.state}")
tx.cancel(onErrorReason)
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmCompactOnLaunch.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmCompactOnLaunch.kt
new file mode 100644
index 0000000000..1efb2541a7
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmCompactOnLaunch.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.database
+
+import io.realm.DefaultCompactOnLaunchCallback
+
+class RealmCompactOnLaunch : DefaultCompactOnLaunchCallback() {
+ /**
+ * Forces all RealmCompactOnLaunch instances to be equal.
+ * Avoids Realm throwing when multiple instances of this class are used.
+ */
+ override fun equals(other: Any?) = other is RealmCompactOnLaunch
+ override fun hashCode() = 0x1000
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmLiveEntityObserver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmLiveEntityObserver.kt
index f2f88e216b..020b42b3b8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmLiveEntityObserver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmLiveEntityObserver.kt
@@ -38,7 +38,7 @@ internal abstract class RealmLiveEntityObserver(protected val r
LiveEntityObserver, RealmChangeListener> {
private companion object {
- val BACKGROUND_HANDLER = createBackgroundHandler("LIVE_ENTITY_BACKGROUND")
+ val BACKGROUND_HANDLER = createBackgroundHandler("Matrix-LIVE_ENTITY_BACKGROUND")
}
protected val observerScope = CoroutineScope(SupervisorJob() + BACKGROUND_HANDLER.asCoroutineDispatcher())
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 b733aa6fc0..0b11863864 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
@@ -52,6 +52,7 @@ import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo032
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo033
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo034
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo035
+import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo036
import org.matrix.android.sdk.internal.util.Normalizer
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
import javax.inject.Inject
@@ -60,7 +61,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
private val normalizer: Normalizer
) : MatrixRealmMigration(
dbName = "Session",
- schemaVersion = 35L,
+ schemaVersion = 36L,
) {
/**
* Forces all RealmSessionStoreMigration instances to be equal.
@@ -105,5 +106,6 @@ internal class RealmSessionStoreMigration @Inject constructor(
if (oldVersion < 33) MigrateSessionTo033(realm).perform()
if (oldVersion < 34) MigrateSessionTo034(realm).perform()
if (oldVersion < 35) MigrateSessionTo035(realm).perform()
+ if (oldVersion < 36) MigrateSessionTo036(realm).perform()
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt
index 949dd5daa1..16a55c22ac 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt
@@ -64,7 +64,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor(
}
val realmConfiguration = RealmConfiguration.Builder()
- .compactOnLaunch()
+ .compactOnLaunch(RealmCompactOnLaunch())
.directory(directory)
.name(REALM_NAME)
.apply {
@@ -93,7 +93,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor(
return
}
- listOf(REALM_NAME, "$REALM_NAME.lock", "$REALM_NAME.note", "$REALM_NAME.management").forEach { file ->
+ listOf(REALM_NAME, "${REALM_NAME}.lock", "${REALM_NAME}.note", "${REALM_NAME}.management").forEach { file ->
try {
File(directory, file).deleteRecursively()
} catch (e: Exception) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo036.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo036.kt
new file mode 100644
index 0000000000..efcb181ecb
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo036.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.database.migration
+
+import io.realm.DynamicRealm
+import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntityFields
+import org.matrix.android.sdk.internal.util.database.RealmMigrator
+
+internal class MigrateSessionTo036(realm: DynamicRealm) : RealmMigrator(realm, 36) {
+
+ override fun doMigrate(realm: DynamicRealm) {
+ realm.schema.create("LocalRoomSummaryEntity")
+ .addField(LocalRoomSummaryEntityFields.ROOM_ID, String::class.java)
+ .addPrimaryKey(LocalRoomSummaryEntityFields.ROOM_ID)
+ .setRequired(LocalRoomSummaryEntityFields.ROOM_ID, true)
+ .addField(LocalRoomSummaryEntityFields.CREATE_ROOM_PARAMS_STR, String::class.java)
+ .addRealmObjectField(LocalRoomSummaryEntityFields.ROOM_SUMMARY_ENTITY.`$`, realm.schema.get("RoomSummaryEntity")!!)
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/LocalRoomSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/LocalRoomSummaryEntity.kt
new file mode 100644
index 0000000000..fd8331e986
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/LocalRoomSummaryEntity.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.database.model
+
+import io.realm.RealmObject
+import io.realm.annotations.PrimaryKey
+import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
+import org.matrix.android.sdk.api.session.room.model.create.toJSONString
+
+internal open class LocalRoomSummaryEntity(
+ @PrimaryKey var roomId: String = "",
+ var roomSummaryEntity: RoomSummaryEntity? = null,
+ private var createRoomParamsStr: String? = null
+) : RealmObject() {
+
+ var createRoomParams: CreateRoomParams?
+ get() {
+ return CreateRoomParams.fromJson(createRoomParamsStr)
+ }
+ set(value) {
+ createRoomParamsStr = value?.toJSONString()
+ }
+
+ companion object
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt
index d131589dd1..b222bcb710 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt
@@ -35,6 +35,7 @@ import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntit
ReadReceiptEntity::class,
RoomEntity::class,
RoomSummaryEntity::class,
+ LocalRoomSummaryEntity::class,
RoomTagEntity::class,
SyncEntity::class,
PendingThreePidEntity::class,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LocalRoomSummaryEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LocalRoomSummaryEntityQueries.kt
new file mode 100644
index 0000000000..527350bedc
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LocalRoomSummaryEntityQueries.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.database.query
+
+import io.realm.Realm
+import io.realm.RealmQuery
+import io.realm.kotlin.where
+import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntity
+import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntityFields
+
+internal fun LocalRoomSummaryEntity.Companion.where(realm: Realm, roomId: String? = null): RealmQuery {
+ val query = realm.where()
+ if (roomId != null) {
+ query.equalTo(LocalRoomSummaryEntityFields.ROOM_ID, roomId)
+ }
+ return query
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt
index dc20549eb3..2e9c3303d4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt
@@ -19,16 +19,15 @@ package org.matrix.android.sdk.internal.database.tools
import io.realm.Realm
import io.realm.RealmConfiguration
import org.matrix.android.sdk.BuildConfig
-import timber.log.Timber
internal class RealmDebugTools(
private val realmConfiguration: RealmConfiguration
) {
/**
- * Log info about the DB.
+ * Get info about the DB.
*/
- fun logInfo(baseName: String) {
- buildString {
+ fun getInfo(baseName: String): String {
+ return buildString {
append("\n$baseName Realm located at : ${realmConfiguration.realmDirectory}/${realmConfiguration.realmFileName}")
if (BuildConfig.LOG_PRIVATE_DATA) {
@@ -54,7 +53,6 @@ internal class RealmDebugTools(
separator()
}
}
- .let { Timber.i(it) }
}
private fun StringBuilder.separator() = append("\n==============================================")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/debug/DefaultDebugService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/debug/DefaultDebugService.kt
index 3f2e6fafc8..46479c3db6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/debug/DefaultDebugService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/debug/DefaultDebugService.kt
@@ -36,9 +36,9 @@ internal class DefaultDebugService @Inject constructor(
realmConfigurationGlobal
}
- override fun logDbUsageInfo() {
- RealmDebugTools(realmConfigurationAuth).logInfo("Auth")
- RealmDebugTools(realmConfigurationGlobal).logInfo("Global")
- sessionManager.getLastSession()?.logDbUsageInfo()
+ override fun getDbUsageInfo() = buildString {
+ append(RealmDebugTools(realmConfigurationAuth).getInfo("Auth"))
+ append(RealmDebugTools(realmConfigurationGlobal).getInfo("Global"))
+ append(sessionManager.getLastSession()?.getDbUsageInfo())
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixModule.kt
index 49713a1d7f..f2f8a5dc04 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixModule.kt
@@ -40,7 +40,7 @@ internal object MatrixModule {
io = Dispatchers.IO,
computation = Dispatchers.Default,
main = Dispatchers.Main,
- crypto = createBackgroundHandler("Crypto_Thread").asCoroutineDispatcher(),
+ crypto = createBackgroundHandler("Matrix-Crypto_Thread").asCoroutineDispatcher(),
dmVerif = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MoshiProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MoshiProvider.kt
index 8f007f227c..0a737d5e64 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MoshiProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MoshiProvider.kt
@@ -17,6 +17,8 @@
package org.matrix.android.sdk.internal.di
import com.squareup.moshi.Moshi
+import com.squareup.moshi.adapters.PolymorphicJsonAdapterFactory
+import org.matrix.android.sdk.api.session.identity.ThreePid
import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.room.model.message.MessageDefaultContent
@@ -60,6 +62,12 @@ internal object MoshiProvider {
.registerSubtype(MessagePollResponseContent::class.java, MessageType.MSGTYPE_POLL_RESPONSE)
)
.add(SerializeNulls.JSON_ADAPTER_FACTORY)
+ .add(
+ PolymorphicJsonAdapterFactory.of(ThreePid::class.java, "type")
+ .withSubtype(ThreePid.Email::class.java, "email")
+ .withSubtype(ThreePid.Msisdn::class.java, "msisdn")
+ .withDefaultValue(null)
+ )
.build()
fun providesMoshi(): Moshi {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt
index 57db187bdc..679c5085ef 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt
@@ -263,11 +263,11 @@ internal class DefaultSession @Inject constructor(
}
}
- override fun logDbUsageInfo() {
- RealmDebugTools(realmConfiguration).logInfo("Session")
- RealmDebugTools(realmConfigurationCrypto).logInfo("Crypto")
- RealmDebugTools(realmConfigurationIdentity).logInfo("Identity")
- RealmDebugTools(realmConfigurationContentScanner).logInfo("ContentScanner")
+ override fun getDbUsageInfo() = buildString {
+ append(RealmDebugTools(realmConfiguration).getInfo("Session"))
+ append(RealmDebugTools(realmConfigurationCrypto).getInfo("Crypto"))
+ append(RealmDebugTools(realmConfigurationIdentity).getInfo("Identity"))
+ append(RealmDebugTools(realmConfigurationContentScanner).getInfo("ContentScanner"))
}
override fun getRealmConfigurations(): List {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt
index d01324a35f..1475b67276 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt
@@ -43,9 +43,13 @@ import org.matrix.android.sdk.internal.session.room.alias.DefaultGetRoomLocalAli
import org.matrix.android.sdk.internal.session.room.alias.DeleteRoomAliasTask
import org.matrix.android.sdk.internal.session.room.alias.GetRoomIdByAliasTask
import org.matrix.android.sdk.internal.session.room.alias.GetRoomLocalAliasesTask
+import org.matrix.android.sdk.internal.session.room.create.CreateLocalRoomStateEventsTask
import org.matrix.android.sdk.internal.session.room.create.CreateLocalRoomTask
+import org.matrix.android.sdk.internal.session.room.create.CreateRoomFromLocalRoomTask
import org.matrix.android.sdk.internal.session.room.create.CreateRoomTask
+import org.matrix.android.sdk.internal.session.room.create.DefaultCreateLocalRoomStateEventsTask
import org.matrix.android.sdk.internal.session.room.create.DefaultCreateLocalRoomTask
+import org.matrix.android.sdk.internal.session.room.create.DefaultCreateRoomFromLocalRoomTask
import org.matrix.android.sdk.internal.session.room.create.DefaultCreateRoomTask
import org.matrix.android.sdk.internal.session.room.delete.DefaultDeleteLocalRoomTask
import org.matrix.android.sdk.internal.session.room.delete.DeleteLocalRoomTask
@@ -213,6 +217,12 @@ internal abstract class RoomModule {
@Binds
abstract fun bindCreateLocalRoomTask(task: DefaultCreateLocalRoomTask): CreateLocalRoomTask
+ @Binds
+ abstract fun bindCreateLocalRoomStateEventsTask(task: DefaultCreateLocalRoomStateEventsTask): CreateLocalRoomStateEventsTask
+
+ @Binds
+ abstract fun bindCreateRoomFromLocalRoomTask(task: DefaultCreateRoomFromLocalRoomTask): CreateRoomFromLocalRoomTask
+
@Binds
abstract fun bindDeleteLocalRoomTask(task: DefaultDeleteLocalRoomTask): DeleteLocalRoomTask
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomStateEventsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomStateEventsTask.kt
new file mode 100644
index 0000000000..a9ff4970fe
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomStateEventsTask.kt
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.room.create
+
+import org.matrix.android.sdk.api.MatrixPatterns.getServerName
+import org.matrix.android.sdk.api.extensions.orFalse
+import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.session.events.model.Content
+import org.matrix.android.sdk.api.session.events.model.Event
+import org.matrix.android.sdk.api.session.events.model.EventType
+import org.matrix.android.sdk.api.session.events.model.LocalEcho
+import org.matrix.android.sdk.api.session.events.model.toContent
+import org.matrix.android.sdk.api.session.room.model.GuestAccess
+import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
+import org.matrix.android.sdk.api.session.room.model.RoomCanonicalAliasContent
+import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent
+import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
+import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
+import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
+import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
+import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
+import org.matrix.android.sdk.api.session.room.model.RoomNameContent
+import org.matrix.android.sdk.api.session.room.model.RoomThirdPartyInviteContent
+import org.matrix.android.sdk.api.session.room.model.RoomTopicContent
+import org.matrix.android.sdk.api.session.room.model.banOrDefault
+import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
+import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
+import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
+import org.matrix.android.sdk.api.session.room.model.eventsDefaultOrDefault
+import org.matrix.android.sdk.api.session.room.model.inviteOrDefault
+import org.matrix.android.sdk.api.session.room.model.kickOrDefault
+import org.matrix.android.sdk.api.session.room.model.redactOrDefault
+import org.matrix.android.sdk.api.session.room.model.stateDefaultOrDefault
+import org.matrix.android.sdk.api.session.room.model.usersDefaultOrDefault
+import org.matrix.android.sdk.api.session.user.UserService
+import org.matrix.android.sdk.internal.di.UserId
+import org.matrix.android.sdk.internal.session.room.create.CreateLocalRoomStateEventsTask.Params
+import org.matrix.android.sdk.internal.session.room.membership.threepid.toThreePid
+import org.matrix.android.sdk.internal.task.Task
+import org.matrix.android.sdk.internal.util.time.Clock
+import javax.inject.Inject
+
+/**
+ * Generate a list of local state events from the given [CreateRoomBody].
+ * The states events are generated according to the given configuration and following the matrix specification.
+ * This list reflects as much as possible a list of state events related to a real room configured and got from the server.
+ *
+ * Ref: https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3createroom
+ */
+internal interface CreateLocalRoomStateEventsTask : Task> {
+ data class Params(val createRoomBody: CreateRoomBody)
+}
+
+internal class DefaultCreateLocalRoomStateEventsTask @Inject constructor(
+ @UserId private val myUserId: String,
+ private val userService: UserService,
+ private val clock: Clock,
+) : CreateLocalRoomStateEventsTask {
+
+ private lateinit var createRoomBody: CreateRoomBody
+
+ override suspend fun execute(params: Params): List {
+ createRoomBody = params.createRoomBody
+
+ // Build the list of the state events following the priorities from the matrix specification
+ // Changing the order of the events might break the correct display of the room on the client side
+ return buildList {
+ createRoomCreateEvent()
+ createRoomMemberEvents(listOf(myUserId))
+ createRoomPowerLevelsEvent()
+ createRoomAliasEvent()
+ createRoomPresetEvents()
+ createRoomInitialStateEvents()
+ createRoomNameAndTopicStateEvents()
+ createRoomMemberEvents(createRoomBody.invitedUserIds.orEmpty())
+ createRoomThreePidEvents()
+ createRoomDefaultEvents()
+ }
+ }
+
+ /**
+ * Generate the create state event related to this room.
+ */
+ private fun MutableList.createRoomCreateEvent() {
+ val roomCreateEvent = createLocalStateEvent(
+ type = EventType.STATE_ROOM_CREATE,
+ content = RoomCreateContent(
+ creator = myUserId,
+ roomVersion = createRoomBody.roomVersion,
+ type = (createRoomBody.creationContent as? Map<*, *>)?.get(CreateRoomParams.CREATION_CONTENT_KEY_ROOM_TYPE) as? String
+
+ ).toContent(),
+ )
+ add(roomCreateEvent)
+ }
+
+ /**
+ * Generate the create state event related to the power levels using the given overridden values or the default values according to the specification.
+ * Ref: https://spec.matrix.org/latest/client-server-api/#mroompower_levels
+ */
+ private fun MutableList.createRoomPowerLevelsEvent() {
+ val powerLevelsContent = createLocalStateEvent(
+ type = EventType.STATE_ROOM_POWER_LEVELS,
+ content = (createRoomBody.powerLevelContentOverride ?: PowerLevelsContent()).let {
+ it.copy(
+ ban = it.banOrDefault(),
+ eventsDefault = it.eventsDefaultOrDefault(),
+ invite = it.inviteOrDefault(),
+ kick = it.kickOrDefault(),
+ redact = it.redactOrDefault(),
+ stateDefault = it.stateDefaultOrDefault(),
+ usersDefault = it.usersDefaultOrDefault(),
+ )
+ }.toContent(),
+ )
+ add(powerLevelsContent)
+ }
+
+ /**
+ * Generate the local room member state events related to the given user ids, if any.
+ */
+ private suspend fun MutableList.createRoomMemberEvents(userIds: List) {
+ val memberEvents = userIds
+ .mapNotNull { tryOrNull { userService.resolveUser(it) } }
+ .map { user ->
+ createLocalStateEvent(
+ type = EventType.STATE_ROOM_MEMBER,
+ content = RoomMemberContent(
+ isDirect = createRoomBody.isDirect.takeUnless { user.userId == myUserId }.orFalse(),
+ membership = if (user.userId == myUserId) Membership.JOIN else Membership.INVITE,
+ displayName = user.displayName,
+ avatarUrl = user.avatarUrl
+ ).toContent(),
+ stateKey = user.userId
+ )
+ }
+ addAll(memberEvents)
+ }
+
+ /**
+ * Generate the local state events related to the given third party invites, if any.
+ */
+ private fun MutableList.createRoomThreePidEvents() {
+ createRoomBody.invite3pids.orEmpty().forEach { body ->
+ val localThirdPartyInviteEvent = createLocalStateEvent(
+ type = EventType.LOCAL_STATE_ROOM_THIRD_PARTY_INVITE,
+ content = LocalRoomThirdPartyInviteContent(
+ isDirect = createRoomBody.isDirect.orFalse(),
+ membership = Membership.INVITE,
+ displayName = body.address,
+ thirdPartyInvite = body.toThreePid()
+ ).toContent(),
+ )
+ val thirdPartyInviteEvent = createLocalStateEvent(
+ type = EventType.STATE_ROOM_THIRD_PARTY_INVITE,
+ content = RoomThirdPartyInviteContent(
+ displayName = body.address,
+ keyValidityUrl = null,
+ publicKey = null,
+ publicKeys = null
+ ).toContent(),
+ )
+ add(localThirdPartyInviteEvent)
+ add(thirdPartyInviteEvent)
+ }
+ }
+
+ /**
+ * Generate the local state event related to the given alias, if any.
+ */
+ fun MutableList.createRoomAliasEvent() {
+ if (createRoomBody.roomAliasName != null) {
+ val canonicalAliasContent = createLocalStateEvent(
+ type = EventType.STATE_ROOM_CANONICAL_ALIAS,
+ content = RoomCanonicalAliasContent(
+ canonicalAlias = "${createRoomBody.roomAliasName}:${myUserId.getServerName()}"
+ ).toContent(),
+ )
+ add(canonicalAliasContent)
+ }
+ }
+
+ /**
+ * Generate the local state events related to the given [CreateRoomPreset].
+ * Ref: https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3createroom
+ */
+ private fun MutableList.createRoomPresetEvents() {
+ val preset = createRoomBody.preset ?: return
+
+ var joinRules: RoomJoinRules? = null
+ var historyVisibility: RoomHistoryVisibility? = null
+ var guestAccess: GuestAccess? = null
+ when (preset) {
+ CreateRoomPreset.PRESET_PRIVATE_CHAT,
+ CreateRoomPreset.PRESET_TRUSTED_PRIVATE_CHAT -> {
+ joinRules = RoomJoinRules.INVITE
+ historyVisibility = RoomHistoryVisibility.SHARED
+ guestAccess = GuestAccess.CanJoin
+ }
+ CreateRoomPreset.PRESET_PUBLIC_CHAT -> {
+ joinRules = RoomJoinRules.PUBLIC
+ historyVisibility = RoomHistoryVisibility.SHARED
+ guestAccess = GuestAccess.Forbidden
+ }
+ }
+
+ add(createLocalStateEvent(EventType.STATE_ROOM_JOIN_RULES, RoomJoinRulesContent(joinRules.value).toContent()))
+ add(createLocalStateEvent(EventType.STATE_ROOM_HISTORY_VISIBILITY, RoomHistoryVisibilityContent(historyVisibility.value).toContent()))
+ add(createLocalStateEvent(EventType.STATE_ROOM_GUEST_ACCESS, RoomGuestAccessContent(guestAccess.value).toContent()))
+ }
+
+ /**
+ * Generate the local state events related to the given initial states, if any.
+ * The given initial state events override the potential existing ones of the same type.
+ */
+ private fun MutableList.createRoomInitialStateEvents() {
+ val initialStates = createRoomBody.initialStates ?: return
+
+ val initialStateEvents = initialStates.map { createLocalStateEvent(it.type, it.content, it.stateKey) }
+ // Erase existing events of the same type
+ removeAll { event -> event.type in initialStateEvents.map { it.type } }
+ // Add the initial state events to the list
+ addAll(initialStateEvents)
+ }
+
+ /**
+ * Generate the local events related to the given room name and topic, if any.
+ */
+ private fun MutableList.createRoomNameAndTopicStateEvents() {
+ if (createRoomBody.name != null) {
+ add(createLocalStateEvent(EventType.STATE_ROOM_NAME, RoomNameContent(createRoomBody.name).toContent()))
+ }
+ if (createRoomBody.topic != null) {
+ add(createLocalStateEvent(EventType.STATE_ROOM_TOPIC, RoomTopicContent(createRoomBody.topic).toContent()))
+ }
+ }
+
+ /**
+ * Generate the local events which have not been set and are in that case provided by the server with default values.
+ * Default events:
+ * - m.room.history_visibility (https://spec.matrix.org/latest/client-server-api/#server-behaviour-5)
+ * - m.room.guest_access (https://spec.matrix.org/latest/client-server-api/#mroomguest_access)
+ */
+ private fun MutableList.createRoomDefaultEvents() {
+ // HistoryVisibility
+ if (none { it.type == EventType.STATE_ROOM_HISTORY_VISIBILITY }) {
+ add(
+ createLocalStateEvent(
+ type = EventType.STATE_ROOM_HISTORY_VISIBILITY,
+ content = RoomHistoryVisibilityContent(RoomHistoryVisibility.SHARED.value).toContent(),
+ )
+ )
+ }
+ // GuestAccess
+ if (none { it.type == EventType.STATE_ROOM_GUEST_ACCESS }) {
+ add(
+ createLocalStateEvent(
+ type = EventType.STATE_ROOM_GUEST_ACCESS,
+ content = RoomGuestAccessContent(GuestAccess.Forbidden.value).toContent(),
+ )
+ )
+ }
+ }
+
+ /**
+ * Generate a local state event from the given parameters.
+ *
+ * @param type the event type, see [EventType]
+ * @param content the content of the event
+ * @param stateKey the stateKey, if any
+ *
+ * @return a local state event
+ */
+ private fun createLocalStateEvent(type: String?, content: Content?, stateKey: String? = ""): Event {
+ return Event(
+ type = type,
+ senderId = myUserId,
+ stateKey = stateKey,
+ content = content,
+ originServerTs = clock.epochMillis(),
+ eventId = LocalEcho.createLocalEchoId()
+ )
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomTask.kt
index d57491a4c8..03c2b2a47e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomTask.kt
@@ -21,26 +21,15 @@ import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.kotlin.createObject
import kotlinx.coroutines.TimeoutCancellationException
-import org.matrix.android.sdk.api.extensions.orFalse
-import org.matrix.android.sdk.api.extensions.tryOrNull
-import org.matrix.android.sdk.api.session.events.model.Content
-import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.api.session.events.model.LocalEcho
-import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
-import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.Membership
-import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
-import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
-import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho
import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.api.session.sync.model.RoomSyncSummary
-import org.matrix.android.sdk.api.session.user.UserService
-import org.matrix.android.sdk.api.session.user.model.User
+import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
import org.matrix.android.sdk.internal.database.helper.addTimelineEvent
import org.matrix.android.sdk.internal.database.mapper.asDomain
@@ -48,6 +37,7 @@ import org.matrix.android.sdk.internal.database.mapper.toEntity
import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
import org.matrix.android.sdk.internal.database.model.EventInsertType
+import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomEntity
import org.matrix.android.sdk.internal.database.model.RoomMembersLoadStatusType
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
@@ -56,7 +46,6 @@ import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore
import org.matrix.android.sdk.internal.database.query.getOrCreate
import org.matrix.android.sdk.internal.database.query.getOrNull
import org.matrix.android.sdk.internal.di.SessionDatabase
-import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.session.events.getFixedRoomMemberContent
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberEventHandler
import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryUpdater
@@ -70,22 +59,22 @@ import javax.inject.Inject
internal interface CreateLocalRoomTask : Task
internal class DefaultCreateLocalRoomTask @Inject constructor(
- @UserId private val userId: String,
@SessionDatabase private val monarchy: Monarchy,
private val roomMemberEventHandler: RoomMemberEventHandler,
private val roomSummaryUpdater: RoomSummaryUpdater,
@SessionDatabase private val realmConfiguration: RealmConfiguration,
private val createRoomBodyBuilder: CreateRoomBodyBuilder,
- private val userService: UserService,
+ private val cryptoService: DefaultCryptoService,
private val clock: Clock,
+ private val createLocalRoomStateEventsTask: CreateLocalRoomStateEventsTask,
) : CreateLocalRoomTask {
override suspend fun execute(params: CreateRoomParams): String {
- val createRoomBody = createRoomBodyBuilder.build(params.withDefault())
+ val createRoomBody = createRoomBodyBuilder.build(params)
val roomId = RoomLocalEcho.createLocalEchoId()
monarchy.awaitTransaction { realm ->
createLocalRoomEntity(realm, roomId, createRoomBody)
- createLocalRoomSummaryEntity(realm, roomId, createRoomBody)
+ createLocalRoomSummaryEntity(realm, roomId, params, createRoomBody)
}
// Wait for room to be created in DB
@@ -114,14 +103,29 @@ internal class DefaultCreateLocalRoomTask @Inject constructor(
}
}
- private fun createLocalRoomSummaryEntity(realm: Realm, roomId: String, createRoomBody: CreateRoomBody) {
- val otherUserId = createRoomBody.getDirectUserId()
- if (otherUserId != null) {
- RoomSummaryEntity.getOrCreate(realm, roomId).apply {
+ private fun createLocalRoomSummaryEntity(realm: Realm, roomId: String, createRoomParams: CreateRoomParams, createRoomBody: CreateRoomBody) {
+ // Create the room summary entity
+ val roomSummaryEntity = realm.createObject(roomId).apply {
+ val otherUserId = createRoomBody.getDirectUserId()
+ if (otherUserId != null) {
isDirect = true
directUserId = otherUserId
}
}
+
+ // Update the createRoomParams from the potential feature preset before saving
+ createRoomParams.featurePreset?.let { featurePreset ->
+ featurePreset.updateRoomParams(createRoomParams)
+ createRoomParams.initialStates.addAll(featurePreset.setupInitialStates().orEmpty())
+ }
+
+ // Create a LocalRoomSummaryEntity decorated by the related RoomSummaryEntity and the updated CreateRoomParams
+ realm.createObject(roomId).also {
+ it.roomSummaryEntity = roomSummaryEntity
+ it.createRoomParams = createRoomParams
+ }
+
+ // Update the RoomSummaryEntity by simulating a fake sync response
roomSummaryUpdater.update(
realm = realm,
roomId = roomId,
@@ -150,7 +154,7 @@ internal class DefaultCreateLocalRoomTask @Inject constructor(
isLastForward = true
}
- val eventList = createLocalRoomEvents(createRoomBody)
+ val eventList = createLocalRoomStateEventsTask.execute(CreateLocalRoomStateEventsTask.Params(createRoomBody))
val roomMemberContentsByUser = HashMap()
for (event in eventList) {
@@ -169,6 +173,9 @@ internal class DefaultCreateLocalRoomTask @Inject constructor(
roomMemberContentsByUser[event.stateKey] = event.getFixedRoomMemberContent()
roomMemberEventHandler.handle(realm, roomId, event, false)
}
+
+ // Give info to crypto module
+ cryptoService.onStateEvent(roomId, event)
}
roomMemberContentsByUser.getOrPut(event.senderId) {
@@ -187,81 +194,4 @@ internal class DefaultCreateLocalRoomTask @Inject constructor(
return chunkEntity
}
-
- /**
- * Build the list of the events related to the room creation params.
- *
- * @param createRoomBody the room creation params
- *
- * @return the list of events
- */
- private suspend fun createLocalRoomEvents(createRoomBody: CreateRoomBody): List {
- val myUser = userService.getUser(userId) ?: User(userId)
- val invitedUsers = createRoomBody.invitedUserIds.orEmpty()
- .mapNotNull { tryOrNull { userService.resolveUser(it) } }
-
- val createRoomEvent = createLocalEvent(
- type = EventType.STATE_ROOM_CREATE,
- content = RoomCreateContent(
- creator = userId
- ).toContent()
- )
- val myRoomMemberEvent = createLocalEvent(
- type = EventType.STATE_ROOM_MEMBER,
- content = RoomMemberContent(
- membership = Membership.JOIN,
- displayName = myUser.displayName,
- avatarUrl = myUser.avatarUrl
- ).toContent(),
- stateKey = userId
- )
- val roomMemberEvents = invitedUsers.map {
- createLocalEvent(
- type = EventType.STATE_ROOM_MEMBER,
- content = RoomMemberContent(
- isDirect = createRoomBody.isDirect.orFalse(),
- membership = Membership.INVITE,
- displayName = it.displayName,
- avatarUrl = it.avatarUrl
- ).toContent(),
- stateKey = it.userId
- )
- }
-
- return buildList {
- add(createRoomEvent)
- add(myRoomMemberEvent)
- addAll(createRoomBody.initialStates.orEmpty().map { createLocalEvent(it.type, it.content, it.stateKey) })
- addAll(roomMemberEvents)
- }
- }
-
- /**
- * Generate a local event from the given parameters.
- *
- * @param type the event type, see [EventType]
- * @param content the content of the Event
- * @param stateKey the stateKey, if any
- *
- * @return a fake event
- */
- private fun createLocalEvent(type: String?, content: Content?, stateKey: String? = ""): Event {
- return Event(
- type = type,
- senderId = userId,
- stateKey = stateKey,
- content = content,
- originServerTs = clock.epochMillis(),
- eventId = LocalEcho.createLocalEchoId()
- )
- }
-
- /**
- * Setup default values to the CreateRoomParams as the room is created locally (the default values will not be defined by the server).
- */
- private fun CreateRoomParams.withDefault() = this.apply {
- if (visibility == null) visibility = RoomDirectoryVisibility.PRIVATE
- if (historyVisibility == null) historyVisibility = RoomHistoryVisibility.SHARED
- if (guestAccess == null) guestAccess = GuestAccess.Forbidden
- }
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt
index b326c3618c..17e1aba6f6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt
@@ -22,6 +22,7 @@ import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
+import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.session.room.membership.threepid.ThreePidInviteBody
/**
@@ -119,7 +120,13 @@ internal data class CreateRoomBody(
*/
@Json(name = "room_version")
val roomVersion: String?
-)
+) {
+ companion object {
+ fun fromJson(json: String?): CreateRoomBody? {
+ return json?.let { MoshiProvider.providesMoshi().adapter(CreateRoomBody::class.java).fromJson(it) }
+ }
+ }
+}
/**
* Tells if the created room can be a direct chat one.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomFromLocalRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomFromLocalRoomTask.kt
new file mode 100644
index 0000000000..02538a5cc3
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomFromLocalRoomTask.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.room.create
+
+import com.zhuinden.monarchy.Monarchy
+import io.realm.kotlin.where
+import kotlinx.coroutines.TimeoutCancellationException
+import org.matrix.android.sdk.api.extensions.orFalse
+import org.matrix.android.sdk.api.query.QueryStringValue
+import org.matrix.android.sdk.api.session.events.model.Event
+import org.matrix.android.sdk.api.session.events.model.EventType
+import org.matrix.android.sdk.api.session.events.model.toContent
+import org.matrix.android.sdk.api.session.events.model.toModel
+import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
+import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
+import org.matrix.android.sdk.api.session.room.model.tombstone.RoomTombstoneContent
+import org.matrix.android.sdk.api.session.room.send.SendState
+import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
+import org.matrix.android.sdk.internal.database.mapper.toEntity
+import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
+import org.matrix.android.sdk.internal.database.model.EventEntity
+import org.matrix.android.sdk.internal.database.model.EventEntityFields
+import org.matrix.android.sdk.internal.database.model.EventInsertType
+import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntity
+import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntityFields
+import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
+import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
+import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore
+import org.matrix.android.sdk.internal.database.query.getOrCreate
+import org.matrix.android.sdk.internal.database.query.whereRoomId
+import org.matrix.android.sdk.internal.di.SessionDatabase
+import org.matrix.android.sdk.internal.di.UserId
+import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
+import org.matrix.android.sdk.internal.task.Task
+import org.matrix.android.sdk.internal.util.awaitTransaction
+import org.matrix.android.sdk.internal.util.time.Clock
+import java.util.UUID
+import java.util.concurrent.TimeUnit
+import javax.inject.Inject
+
+/**
+ * Create a room on the server from a local room.
+ * The configuration of the local room will be use to configure the new room.
+ * The potential local room members will also be invited to this new room.
+ *
+ * A local tombstone event will be created to indicate that the local room has been replacing by the new one.
+ */
+internal interface CreateRoomFromLocalRoomTask : Task {
+ data class Params(val localRoomId: String)
+}
+
+internal class DefaultCreateRoomFromLocalRoomTask @Inject constructor(
+ @UserId private val userId: String,
+ @SessionDatabase private val monarchy: Monarchy,
+ private val createRoomTask: CreateRoomTask,
+ private val stateEventDataSource: StateEventDataSource,
+ private val clock: Clock,
+) : CreateRoomFromLocalRoomTask {
+
+ private val realmConfiguration
+ get() = monarchy.realmConfiguration
+
+ override suspend fun execute(params: CreateRoomFromLocalRoomTask.Params): String {
+ val replacementRoomId = stateEventDataSource.getStateEvent(params.localRoomId, EventType.STATE_ROOM_TOMBSTONE, QueryStringValue.IsEmpty)
+ ?.content.toModel()
+ ?.replacementRoomId
+
+ if (replacementRoomId != null) {
+ return replacementRoomId
+ }
+
+ var createRoomParams: CreateRoomParams? = null
+ var isEncrypted = false
+ monarchy.doWithRealm { realm ->
+ realm.where()
+ .equalTo(LocalRoomSummaryEntityFields.ROOM_ID, params.localRoomId)
+ .findFirst()
+ ?.let {
+ createRoomParams = it.createRoomParams
+ isEncrypted = it.roomSummaryEntity?.isEncrypted.orFalse()
+ }
+ }
+ val roomId = createRoomTask.execute(createRoomParams!!)
+
+ try {
+ // Wait for all the room events before triggering the replacement room
+ awaitNotEmptyResult(realmConfiguration, TimeUnit.MINUTES.toMillis(1L)) { realm ->
+ realm.where(RoomSummaryEntity::class.java)
+ .equalTo(RoomSummaryEntityFields.ROOM_ID, roomId)
+ .equalTo(RoomSummaryEntityFields.INVITED_MEMBERS_COUNT, createRoomParams?.invitedUserIds?.size ?: 0)
+ }
+ awaitNotEmptyResult(realmConfiguration, TimeUnit.MINUTES.toMillis(1L)) { realm ->
+ EventEntity.whereRoomId(realm, roomId)
+ .equalTo(EventEntityFields.TYPE, EventType.STATE_ROOM_HISTORY_VISIBILITY)
+ }
+ if (isEncrypted) {
+ awaitNotEmptyResult(realmConfiguration, TimeUnit.MINUTES.toMillis(1L)) { realm ->
+ EventEntity.whereRoomId(realm, roomId)
+ .equalTo(EventEntityFields.TYPE, EventType.STATE_ROOM_ENCRYPTION)
+ }
+ }
+ } catch (exception: TimeoutCancellationException) {
+ throw CreateRoomFailure.CreatedWithTimeout(roomId)
+ }
+
+ createTombstoneEvent(params, roomId)
+ return roomId
+ }
+
+ /**
+ * Create a Tombstone event to indicate that the local room has been replaced by a new one.
+ */
+ private suspend fun createTombstoneEvent(params: CreateRoomFromLocalRoomTask.Params, roomId: String) {
+ val now = clock.epochMillis()
+ val event = Event(
+ type = EventType.STATE_ROOM_TOMBSTONE,
+ senderId = userId,
+ originServerTs = now,
+ stateKey = "",
+ eventId = UUID.randomUUID().toString(),
+ content = RoomTombstoneContent(
+ replacementRoomId = roomId
+ ).toContent()
+ )
+ monarchy.awaitTransaction { realm ->
+ val eventEntity = event.toEntity(params.localRoomId, SendState.SYNCED, now).copyToRealmOrIgnore(realm, EventInsertType.INCREMENTAL_SYNC)
+ if (event.stateKey != null && event.type != null && event.eventId != null) {
+ CurrentStateEventEntity.getOrCreate(realm, params.localRoomId, event.stateKey, event.type).apply {
+ eventId = event.eventId
+ root = eventEntity
+ }
+ }
+ }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt
index d76640573f..e558d34ff9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt
@@ -54,8 +54,7 @@ internal class DefaultCreateRoomTask @Inject constructor(
private val directChatsHelper: DirectChatsHelper,
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
private val readMarkersTask: SetReadMarkersTask,
- @SessionDatabase
- private val realmConfiguration: RealmConfiguration,
+ @SessionDatabase private val realmConfiguration: RealmConfiguration,
private val createRoomBodyBuilder: CreateRoomBodyBuilder,
private val globalErrorReceiver: GlobalErrorReceiver,
private val clock: Clock,
@@ -71,7 +70,6 @@ internal class DefaultCreateRoomTask @Inject constructor(
}
val createRoomBody = createRoomBodyBuilder.build(params)
-
val createRoomResponse = try {
executeRequest(globalErrorReceiver) {
roomAPI.createRoom(createRoomBody)
@@ -90,6 +88,7 @@ internal class DefaultCreateRoomTask @Inject constructor(
}
throw throwable
}
+
val roomId = createRoomResponse.roomId
// Wait for room to come back from the sync (but it can maybe be in the DB if the sync response is received before)
try {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/LocalRoomThirdPartyInviteContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/LocalRoomThirdPartyInviteContent.kt
new file mode 100644
index 0000000000..617ed35326
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/LocalRoomThirdPartyInviteContent.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.room.create
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+import org.matrix.android.sdk.api.session.identity.ThreePid
+import org.matrix.android.sdk.api.session.room.model.Membership
+
+/**
+ * Class representing the EventType.LOCAL_STATE_ROOM_THIRD_PARTY_INVITE state event content
+ * This class is only used to store the third party invite data of a local room.
+ */
+@JsonClass(generateAdapter = true)
+internal data class LocalRoomThirdPartyInviteContent(
+ @Json(name = "membership") val membership: Membership,
+ @Json(name = "displayname") val displayName: String? = null,
+ @Json(name = "is_direct") val isDirect: Boolean = false,
+ @Json(name = "third_party_invite") val thirdPartyInvite: ThreePid? = null,
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/delete/DeleteLocalRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/delete/DeleteLocalRoomTask.kt
index 936c94e520..49951d2da0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/delete/DeleteLocalRoomTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/delete/DeleteLocalRoomTask.kt
@@ -21,6 +21,7 @@ import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho
import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
import org.matrix.android.sdk.internal.database.model.EventEntity
+import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
@@ -70,6 +71,9 @@ internal class DefaultDeleteLocalRoomTask @Inject constructor(
RoomEntity.where(realm, roomId = roomId).findAll()
?.also { Timber.i("## DeleteLocalRoomTask - RoomEntity - delete ${it.size} entries") }
?.deleteAllFromRealm()
+ LocalRoomSummaryEntity.where(realm, roomId = roomId).findAll()
+ ?.also { Timber.i("## DeleteLocalRoomTask - LocalRoomSummaryEntity - delete ${it.size} entries") }
+ ?.deleteAllFromRealm()
}
} else {
Timber.i("## DeleteLocalRoomTask - Failed to remove room with id $roomId: not a local room")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/threepid/ThreePidInviteBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/threepid/ThreePidInviteBody.kt
index 3141c052c3..d7b78faea8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/threepid/ThreePidInviteBody.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/threepid/ThreePidInviteBody.kt
@@ -18,6 +18,8 @@ package org.matrix.android.sdk.internal.session.room.membership.threepid
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
+import org.matrix.android.sdk.api.session.identity.ThreePid
+import org.matrix.android.sdk.internal.auth.data.ThreePidMedium
@JsonClass(generateAdapter = true)
internal data class ThreePidInviteBody(
@@ -43,3 +45,9 @@ internal data class ThreePidInviteBody(
@Json(name = "address")
val address: String
)
+
+internal fun ThreePidInviteBody.toThreePid() = when (medium) {
+ ThreePidMedium.EMAIL -> ThreePid.Email(address)
+ ThreePidMedium.MSISDN -> ThreePid.Msisdn(address)
+ else -> null
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt
index 2afca6e554..801ff0ec79 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt
@@ -53,7 +53,7 @@ internal class MultipleEventSendingDispatcherWorker(context: Context, params: Wo
@Inject lateinit var timelineSendEventWorkCommon: TimelineSendEventWorkCommon
@Inject lateinit var localEchoRepository: LocalEchoRepository
- override fun doOnError(params: Params): Result {
+ override fun doOnError(params: Params, failureMessage: String): Result {
params.localEchoIds.forEach { localEchoIds ->
localEchoRepository.updateSendState(
eventId = localEchoIds.eventId,
@@ -63,7 +63,7 @@ internal class MultipleEventSendingDispatcherWorker(context: Context, params: Wo
)
}
- return super.doOnError(params)
+ return super.doOnError(params, failureMessage)
}
override fun injectWith(injector: SessionComponent) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt
index 51107c9655..55363a7251 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt
@@ -55,7 +55,7 @@ internal class EventSenderProcessorThread @Inject constructor(
private val queuedTaskFactory: QueuedTaskFactory,
private val taskExecutor: TaskExecutor,
private val memento: QueueMemento
-) : Thread("SENDER_THREAD_SID_${sessionParams.credentials.sessionId()}"), EventSenderProcessor {
+) : Thread("Matrix-SENDER_THREAD_SID_${sessionParams.credentials.sessionId()}"), EventSenderProcessor {
private fun markAsManaged(task: QueuedTask) {
memento.track(task)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SendStateTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SendStateTask.kt
index 59c9de2932..ecc452edb3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SendStateTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SendStateTask.kt
@@ -16,10 +16,12 @@
package org.matrix.android.sdk.internal.session.room.state
+import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.session.room.RoomAPI
+import org.matrix.android.sdk.internal.session.room.create.CreateRoomFromLocalRoomTask
import org.matrix.android.sdk.internal.task.Task
import timber.log.Timber
import javax.inject.Inject
@@ -35,28 +37,40 @@ internal interface SendStateTask : Task {
internal class DefaultSendStateTask @Inject constructor(
private val roomAPI: RoomAPI,
- private val globalErrorReceiver: GlobalErrorReceiver
+ private val globalErrorReceiver: GlobalErrorReceiver,
+ private val createRoomFromLocalRoomTask: CreateRoomFromLocalRoomTask,
) : SendStateTask {
override suspend fun execute(params: SendStateTask.Params): String {
return executeRequest(globalErrorReceiver) {
- val response = if (params.stateKey.isEmpty()) {
- roomAPI.sendStateEvent(
- roomId = params.roomId,
- stateEventType = params.eventType,
- params = params.body
- )
+ if (RoomLocalEcho.isLocalEchoId(params.roomId)) {
+ // Room is local, so create a real one and send the event to this new room
+ createRoomAndSendEvent(params)
} else {
- roomAPI.sendStateEvent(
- roomId = params.roomId,
- stateEventType = params.eventType,
- stateKey = params.stateKey,
- params = params.body
- )
- }
- response.eventId.also {
- Timber.d("State event: $it just sent in room ${params.roomId}")
+ val response = if (params.stateKey.isEmpty()) {
+ roomAPI.sendStateEvent(
+ roomId = params.roomId,
+ stateEventType = params.eventType,
+ params = params.body
+ )
+ } else {
+ roomAPI.sendStateEvent(
+ roomId = params.roomId,
+ stateEventType = params.eventType,
+ stateKey = params.stateKey,
+ params = params.body
+ )
+ }
+ response.eventId.also {
+ Timber.d("State event: $it just sent in room ${params.roomId}")
+ }
}
}
}
+
+ private suspend fun createRoomAndSendEvent(params: SendStateTask.Params): String {
+ val roomId = createRoomFromLocalRoomTask.execute(CreateRoomFromLocalRoomTask.Params(params.roomId))
+ Timber.d("State event: convert local room (${params.roomId}) to existing room ($roomId) before sending the event.")
+ return execute(params.copy(roomId = roomId))
+ }
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt
index 4eaac67e5a..c380ccf14f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt
@@ -76,7 +76,7 @@ internal class DefaultTimeline(
) : Timeline {
companion object {
- val BACKGROUND_HANDLER = createBackgroundHandler("DefaultTimeline_Thread")
+ val BACKGROUND_HANDLER = createBackgroundHandler("Matrix-DefaultTimeline_Thread")
}
override val timelineID = UUID.randomUUID().toString()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/DefaultSyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/DefaultSyncService.kt
index 691dd7b20d..76c3c38abf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/DefaultSyncService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/DefaultSyncService.kt
@@ -73,6 +73,8 @@ internal class DefaultSyncService @Inject constructor(
override fun getSyncState() = getSyncThread().currentState()
+ override fun isSyncThreadAlive() = getSyncThread().isAlive
+
override fun getSyncRequestStateFlow() = syncRequestStateTracker.syncRequestState
override fun hasAlreadySynced(): Boolean {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt
index 24a60a80da..b47b215655 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt
@@ -62,7 +62,7 @@ internal class SyncThread @Inject constructor(
private val backgroundDetectionObserver: BackgroundDetectionObserver,
private val activeCallHandler: ActiveCallHandler,
private val lightweightSettingsStorage: DefaultLightweightSettingsStorage
-) : Thread("SyncThread"), NetworkConnectivityChecker.Listener, BackgroundDetectionObserver.Listener {
+) : Thread("Matrix-SyncThread"), NetworkConnectivityChecker.Listener, BackgroundDetectionObserver.Listener {
private var state: SyncState = SyncState.Idle
private var liveState = MutableLiveData(state)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt
index 0cc7944d58..a04bc74628 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt
@@ -30,6 +30,7 @@ import org.matrix.android.sdk.internal.session.sync.SyncTask
import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
import org.matrix.android.sdk.internal.worker.SessionWorkerParams
import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
+import org.matrix.android.sdk.internal.worker.startChain
import timber.log.Timber
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@@ -136,6 +137,7 @@ internal class SyncWorker(context: Context, workerParameters: WorkerParameters,
.setConstraints(WorkManagerProvider.workConstraints)
.setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
.setInputData(data)
+ .startChain(true)
.build()
workManagerProvider.workManager
.enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.APPEND_OR_REPLACE, workRequest)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/BackgroundDetectionObserver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/BackgroundDetectionObserver.kt
index 901d0eca8f..dea5f131b9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/BackgroundDetectionObserver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/BackgroundDetectionObserver.kt
@@ -49,13 +49,13 @@ internal class DefaultBackgroundDetectionObserver : BackgroundDetectionObserver
}
override fun onStart(owner: LifecycleOwner) {
- Timber.v("App returning to foreground…")
+ Timber.d("App returning to foreground…")
isInBackground = false
listeners.forEach { it.onMoveToForeground() }
}
override fun onStop(owner: LifecycleOwner) {
- Timber.v("App going to background…")
+ Timber.d("App going to background…")
isInBackground = true
listeners.forEach { it.onMoveToBackground() }
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/SessionSafeCoroutineWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/SessionSafeCoroutineWorker.kt
index 030f51428b..b98b61c9f0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/SessionSafeCoroutineWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/SessionSafeCoroutineWorker.kt
@@ -55,14 +55,16 @@ internal abstract class SessionSafeCoroutineWorker(
// Make sure to inject before handling error as you may need some dependencies to process them.
injectWith(sessionComponent)
- if (params.lastFailureMessage != null) {
- // Forward error to the next workers
- doOnError(params)
- } else {
- doSafeWork(params)
+
+ when (val lastFailureMessage = params.lastFailureMessage) {
+ null -> doSafeWork(params)
+ else -> {
+ // Forward error to the next workers
+ doOnError(params, lastFailureMessage)
+ }
}
} catch (throwable: Throwable) {
- buildErrorResult(params, throwable.localizedMessage ?: "error")
+ buildErrorResult(params, "${throwable::class.java.name}: ${throwable.localizedMessage ?: "N/A error message"}")
}
}
@@ -89,10 +91,10 @@ internal abstract class SessionSafeCoroutineWorker(
* This is called when the input parameters are correct, but contain an error from the previous worker.
*/
@CallSuper
- open fun doOnError(params: PARAM): Result {
+ open fun doOnError(params: PARAM, failureMessage: String): Result {
// Forward the error
return Result.success(inputData)
- .also { Timber.e("Work cancelled due to input error from parent") }
+ .also { Timber.e("Work cancelled due to input error from parent: $failureMessage") }
}
companion object {
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/create/DefaultCreateLocalRoomStateEventsTaskTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/create/DefaultCreateLocalRoomStateEventsTaskTest.kt
new file mode 100644
index 0000000000..1c2cf293b6
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/create/DefaultCreateLocalRoomStateEventsTaskTest.kt
@@ -0,0 +1,462 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.room.create
+
+import io.mockk.coEvery
+import io.mockk.every
+import io.mockk.mockk
+import io.mockk.unmockkAll
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.amshove.kluent.shouldBeEqualTo
+import org.amshove.kluent.shouldNotBeNull
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.matrix.android.sdk.api.MatrixPatterns.getServerName
+import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
+import org.matrix.android.sdk.api.extensions.orFalse
+import org.matrix.android.sdk.api.session.events.model.Event
+import org.matrix.android.sdk.api.session.events.model.EventType
+import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventContent
+import org.matrix.android.sdk.api.session.events.model.toContent
+import org.matrix.android.sdk.api.session.events.model.toModel
+import org.matrix.android.sdk.api.session.identity.ThreePid
+import org.matrix.android.sdk.api.session.room.model.GuestAccess
+import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
+import org.matrix.android.sdk.api.session.room.model.RoomCanonicalAliasContent
+import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent
+import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
+import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
+import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
+import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
+import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
+import org.matrix.android.sdk.api.session.room.model.RoomNameContent
+import org.matrix.android.sdk.api.session.room.model.RoomThirdPartyInviteContent
+import org.matrix.android.sdk.api.session.room.model.RoomTopicContent
+import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
+import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
+import org.matrix.android.sdk.api.session.room.powerlevels.Role
+import org.matrix.android.sdk.api.session.user.UserService
+import org.matrix.android.sdk.api.session.user.model.User
+import org.matrix.android.sdk.internal.session.profile.ThirdPartyIdentifier.Companion.MEDIUM_EMAIL
+import org.matrix.android.sdk.internal.session.profile.ThirdPartyIdentifier.Companion.MEDIUM_MSISDN
+import org.matrix.android.sdk.internal.session.room.membership.threepid.ThreePidInviteBody
+import org.matrix.android.sdk.internal.session.room.membership.threepid.toThreePid
+import org.matrix.android.sdk.internal.util.time.DefaultClock
+
+private const val MY_USER_ID = "my-user-id"
+private const val MY_USER_DISPLAY_NAME = "my-user-display-name"
+private const val MY_USER_AVATAR = "my-user-avatar"
+
+@ExperimentalCoroutinesApi
+internal class DefaultCreateLocalRoomStateEventsTaskTest {
+
+ private val clock = DefaultClock()
+ private val userService = mockk()
+
+ private val defaultCreateLocalRoomStateEventsTask = DefaultCreateLocalRoomStateEventsTask(
+ myUserId = MY_USER_ID,
+ userService = userService,
+ clock = clock
+ )
+
+ lateinit var createRoomBody: CreateRoomBody
+
+ @Before
+ fun setup() {
+ createRoomBody = mockk {
+ every { roomVersion } returns null
+ every { creationContent } returns null
+ every { roomAliasName } returns null
+ every { topic } returns null
+ every { name } returns null
+ every { powerLevelContentOverride } returns null
+ every { initialStates } returns null
+ every { invite3pids } returns null
+ every { preset } returns null
+ every { isDirect } returns null
+ every { invitedUserIds } returns null
+ }
+ coEvery { userService.resolveUser(any()) } answers { User(firstArg()) }
+ }
+
+ @After
+ fun tearDown() {
+ unmockkAll()
+ }
+
+ @Test
+ fun `given a CreateRoomBody when execute then the resulting list of events contains the correct room create state event`() = runTest {
+ // Given
+ val aRoomVersion = "a_room_version"
+
+ every { createRoomBody.roomVersion } returns aRoomVersion
+
+ // When
+ val params = CreateLocalRoomStateEventsTask.Params(createRoomBody)
+ val result = defaultCreateLocalRoomStateEventsTask.execute(params)
+
+ // Then
+ val roomCreateEvent = result.find { it.type == EventType.STATE_ROOM_CREATE }
+ val roomCreateContent = roomCreateEvent?.content.toModel()
+
+ roomCreateContent?.creator shouldBeEqualTo MY_USER_ID
+ roomCreateContent?.roomVersion shouldBeEqualTo aRoomVersion
+ }
+
+ @Test
+ fun `given a CreateRoomBody when execute then the resulting list of events contains the correct name and topic state events`() = runTest {
+ // Given
+ val aRoomName = "a_room_name"
+ val aRoomTopic = "a_room_topic"
+
+ every { createRoomBody.name } returns aRoomName
+ every { createRoomBody.topic } returns aRoomTopic
+
+ // When
+ val params = CreateLocalRoomStateEventsTask.Params(createRoomBody)
+ val result = defaultCreateLocalRoomStateEventsTask.execute(params)
+
+ // Then
+ val roomNameEvent = result.find { it.type == EventType.STATE_ROOM_NAME }
+ val roomTopicEvent = result.find { it.type == EventType.STATE_ROOM_TOPIC }
+
+ roomNameEvent?.content.toModel()?.name shouldBeEqualTo aRoomName
+ roomTopicEvent?.content.toModel()?.topic shouldBeEqualTo aRoomTopic
+ }
+
+ @Test
+ fun `given a CreateRoomBody when execute then the resulting list of events contains the correct room member events`() = runTest {
+ // Given
+ data class RoomMember(val user: User, val membership: Membership)
+
+ val aRoomMemberList: List = listOf(
+ RoomMember(User(MY_USER_ID, MY_USER_DISPLAY_NAME, MY_USER_AVATAR), Membership.JOIN),
+ RoomMember(User("userA_id", "userA_display_name", "userA_avatar"), Membership.INVITE),
+ RoomMember(User("userB_id", "userB_display_name", "userB_avatar"), Membership.INVITE)
+ )
+
+ every { createRoomBody.invitedUserIds } returns aRoomMemberList.filter { it.membership == Membership.INVITE }.map { it.user.userId }
+ coEvery { userService.resolveUser(any()) } answers {
+ aRoomMemberList.map { it.user }.find { it.userId == firstArg() } ?: User(firstArg())
+ }
+
+ // When
+ val params = CreateLocalRoomStateEventsTask.Params(createRoomBody)
+ val result = defaultCreateLocalRoomStateEventsTask.execute(params)
+
+ // Then
+ val roomMemberEvents = result.filter { it.type == EventType.STATE_ROOM_MEMBER }
+
+ roomMemberEvents.map { it.stateKey } shouldBeEqualTo aRoomMemberList.map { it.user.userId }
+ roomMemberEvents.forEach { event ->
+ val roomMemberContent = event.content.toModel()
+ val roomMember = aRoomMemberList.find { it.user.userId == event.stateKey }
+
+ roomMember.shouldNotBeNull()
+ roomMemberContent?.avatarUrl shouldBeEqualTo roomMember.user.avatarUrl
+ roomMemberContent?.displayName shouldBeEqualTo roomMember.user.displayName
+ roomMemberContent?.membership shouldBeEqualTo roomMember.membership
+ }
+ }
+
+ @Test
+ fun `given a CreateRoomBody when execute then the resulting list of events contains the correct power levels event`() = runTest {
+ // Given
+ val aPowerLevelsContent = PowerLevelsContent(
+ ban = 1,
+ kick = 2,
+ invite = 3,
+ redact = 4,
+ eventsDefault = 5,
+ events = null,
+ usersDefault = 6,
+ users = null,
+ stateDefault = 7,
+ notifications = null
+ )
+
+ every { createRoomBody.powerLevelContentOverride } returns aPowerLevelsContent
+
+ // When
+ val params = CreateLocalRoomStateEventsTask.Params(createRoomBody)
+ val result = defaultCreateLocalRoomStateEventsTask.execute(params)
+
+ // Then
+ val roomPowerLevelsEvent = result.find { it.type == EventType.STATE_ROOM_POWER_LEVELS }
+ roomPowerLevelsEvent?.content.toModel() shouldBeEqualTo aPowerLevelsContent
+ }
+
+ @Test
+ fun `given a CreateRoomBody when execute then the resulting list of events contains the correct canonical alias event`() = runTest {
+ // Given
+ val aRoomAlias = "a_room_alias"
+ val expectedCanonicalAlias = "$aRoomAlias:${MY_USER_ID.getServerName()}"
+
+ every { createRoomBody.roomAliasName } returns aRoomAlias
+
+ // When
+ val params = CreateLocalRoomStateEventsTask.Params(createRoomBody)
+ val result = defaultCreateLocalRoomStateEventsTask.execute(params)
+
+ // Then
+ val roomPowerLevelsEvent = result.find { it.type == EventType.STATE_ROOM_CANONICAL_ALIAS }
+ roomPowerLevelsEvent?.content.toModel()?.canonicalAlias shouldBeEqualTo expectedCanonicalAlias
+ }
+
+ @Test
+ fun `given a CreateRoomBody when execute then the resulting list of events contains the correct preset related events`() = runTest {
+ data class ExpectedResult(val joinRules: RoomJoinRules, val historyVisibility: RoomHistoryVisibility, val guestAccess: GuestAccess)
+ data class Case(val preset: CreateRoomPreset, val expectedResult: ExpectedResult)
+
+ CreateRoomPreset.values().forEach { aRoomPreset ->
+ // Given
+ val case = when (aRoomPreset) {
+ CreateRoomPreset.PRESET_PRIVATE_CHAT -> Case(
+ CreateRoomPreset.PRESET_PRIVATE_CHAT,
+ ExpectedResult(RoomJoinRules.INVITE, RoomHistoryVisibility.SHARED, GuestAccess.CanJoin)
+ )
+ CreateRoomPreset.PRESET_TRUSTED_PRIVATE_CHAT -> Case(
+ CreateRoomPreset.PRESET_TRUSTED_PRIVATE_CHAT,
+ ExpectedResult(RoomJoinRules.INVITE, RoomHistoryVisibility.SHARED, GuestAccess.CanJoin)
+ )
+ CreateRoomPreset.PRESET_PUBLIC_CHAT -> Case(
+ CreateRoomPreset.PRESET_PUBLIC_CHAT,
+ ExpectedResult(RoomJoinRules.PUBLIC, RoomHistoryVisibility.SHARED, GuestAccess.Forbidden)
+ )
+ }
+ every { createRoomBody.preset } returns case.preset
+
+ // When
+ val params = CreateLocalRoomStateEventsTask.Params(createRoomBody)
+ val result = defaultCreateLocalRoomStateEventsTask.execute(params)
+
+ // Then
+ result.find { it.type == EventType.STATE_ROOM_JOIN_RULES }
+ ?.content.toModel()
+ ?.joinRules shouldBeEqualTo case.expectedResult.joinRules
+ result.find { it.type == EventType.STATE_ROOM_HISTORY_VISIBILITY }
+ ?.content.toModel()
+ ?.historyVisibility shouldBeEqualTo case.expectedResult.historyVisibility
+ result.find { it.type == EventType.STATE_ROOM_GUEST_ACCESS }
+ ?.content.toModel()
+ ?.guestAccess shouldBeEqualTo case.expectedResult.guestAccess
+ }
+ }
+
+ @Test
+ fun `given a CreateRoomBody when execute then the resulting list of events contains the initial state events`() = runTest {
+ // Given
+ val aListOfInitialStateEvents = listOf(
+ Event(
+ type = EventType.STATE_ROOM_ENCRYPTION,
+ stateKey = "",
+ content = EncryptionEventContent(MXCRYPTO_ALGORITHM_MEGOLM).toContent()
+ ),
+ Event(
+ type = "a_custom_type",
+ content = mapOf("a_custom_map_to_integer" to 42),
+ stateKey = "a_state_key"
+ ),
+ Event(
+ type = "another_custom_type",
+ content = mapOf("a_custom_map_to_boolean" to false),
+ stateKey = "another_state_key"
+ )
+ )
+
+ every { createRoomBody.initialStates } returns aListOfInitialStateEvents
+
+ // When
+ val params = CreateLocalRoomStateEventsTask.Params(createRoomBody)
+ val result = defaultCreateLocalRoomStateEventsTask.execute(params)
+
+ // Then
+ aListOfInitialStateEvents.forEach { expected ->
+ val found = result.find { it.type == expected.type }
+ found.shouldNotBeNull()
+ found.content shouldBeEqualTo expected.content
+ found.stateKey shouldBeEqualTo expected.stateKey
+ }
+ }
+
+ @Test
+ fun `given a CreateRoomBody when execute then the resulting list of events contains the correct third party invite events`() = runTest {
+ // Given
+ val aListOfThreePids = listOf(
+ ThreePid.Email("bob@matrix.org"),
+ ThreePid.Msisdn("+11111111111"),
+ ThreePid.Email("alice@matrix.org"),
+ ThreePid.Msisdn("+22222222222"),
+ )
+ val aListOf3pids = aListOfThreePids.mapIndexed { index, threePid ->
+ ThreePidInviteBody(
+ idServer = "an_id_server_$index",
+ idAccessToken = "an_id_access_token_$index",
+ medium = when (threePid) {
+ is ThreePid.Email -> MEDIUM_EMAIL
+ is ThreePid.Msisdn -> MEDIUM_MSISDN
+ },
+ address = threePid.value
+ )
+ }
+ every { createRoomBody.invite3pids } returns aListOf3pids
+
+ // When
+ val params = CreateLocalRoomStateEventsTask.Params(createRoomBody)
+ val result = defaultCreateLocalRoomStateEventsTask.execute(params)
+
+ // Then
+ val thirdPartyInviteEvents = result.filter { it.type == EventType.STATE_ROOM_THIRD_PARTY_INVITE }
+ val thirdPartyInviteContents = thirdPartyInviteEvents.map { it.content.toModel() }
+ val localThirdPartyInviteEvents = result.filter { it.type == EventType.LOCAL_STATE_ROOM_THIRD_PARTY_INVITE }
+ val localThirdPartyInviteContents = localThirdPartyInviteEvents.map { it.content.toModel() }
+
+ thirdPartyInviteEvents.size shouldBeEqualTo aListOf3pids.size
+ localThirdPartyInviteEvents.size shouldBeEqualTo aListOf3pids.size
+
+ aListOf3pids.forEach { expected ->
+ thirdPartyInviteContents.find { it?.displayName == expected.address }.shouldNotBeNull()
+
+ val localThirdPartyInviteContent = localThirdPartyInviteContents.find { it?.thirdPartyInvite == expected.toThreePid() }
+ localThirdPartyInviteContent.shouldNotBeNull()
+ localThirdPartyInviteContent.membership shouldBeEqualTo Membership.INVITE
+ localThirdPartyInviteContent.isDirect shouldBeEqualTo createRoomBody.isDirect.orFalse()
+ localThirdPartyInviteContent.displayName shouldBeEqualTo expected.address
+ }
+ }
+
+ @Test
+ fun `given a CreateRoomBody with default values when execute then the resulting list of events is correct`() = runTest {
+ // Given
+ // map of expected event types to occurrences
+ val expectedEventTypes = mapOf(
+ EventType.STATE_ROOM_CREATE to 1,
+ EventType.STATE_ROOM_POWER_LEVELS to 1,
+ EventType.STATE_ROOM_MEMBER to 1,
+ EventType.STATE_ROOM_GUEST_ACCESS to 1,
+ EventType.STATE_ROOM_HISTORY_VISIBILITY to 1,
+ )
+ coEvery { userService.resolveUser(any()) } answers {
+ if (firstArg() == MY_USER_ID) User(MY_USER_ID, MY_USER_DISPLAY_NAME, MY_USER_AVATAR) else User(firstArg())
+ }
+
+ // When
+ val params = CreateLocalRoomStateEventsTask.Params(createRoomBody)
+ val result = defaultCreateLocalRoomStateEventsTask.execute(params)
+
+ // Then
+ result.size shouldBeEqualTo expectedEventTypes.values.sum()
+ result.map { it.type }.toSet() shouldBeEqualTo expectedEventTypes.keys
+
+ // Room create
+ result.find { it.type == EventType.STATE_ROOM_CREATE }.shouldNotBeNull()
+ // Room member
+ result.singleOrNull { it.type == EventType.STATE_ROOM_MEMBER }?.stateKey shouldBeEqualTo MY_USER_ID
+ // Power levels
+ val powerLevelsContent = result.find { it.type == EventType.STATE_ROOM_POWER_LEVELS }?.content.toModel()
+ powerLevelsContent.shouldNotBeNull()
+ powerLevelsContent.ban shouldBeEqualTo Role.Moderator.value
+ powerLevelsContent.kick shouldBeEqualTo Role.Moderator.value
+ powerLevelsContent.invite shouldBeEqualTo Role.Moderator.value
+ powerLevelsContent.redact shouldBeEqualTo Role.Moderator.value
+ powerLevelsContent.eventsDefault shouldBeEqualTo Role.Default.value
+ powerLevelsContent.usersDefault shouldBeEqualTo Role.Default.value
+ powerLevelsContent.stateDefault shouldBeEqualTo Role.Moderator.value
+ // Guest access
+ result.find { it.type == EventType.STATE_ROOM_GUEST_ACCESS }
+ ?.content.toModel()?.guestAccess shouldBeEqualTo GuestAccess.Forbidden
+ // History visibility
+ result.find { it.type == EventType.STATE_ROOM_HISTORY_VISIBILITY }
+ ?.content.toModel()?.historyVisibility shouldBeEqualTo RoomHistoryVisibility.SHARED
+ }
+
+ @Test
+ fun `given a CreateRoomBody when execute then the resulting list of events is correctly ordered with the right values`() = runTest {
+ // Given
+ val expectedIsDirect = true
+ val expectedHistoryVisibility = RoomHistoryVisibility.WORLD_READABLE
+
+ every { createRoomBody.roomVersion } returns "a_room_version"
+ every { createRoomBody.roomAliasName } returns "a_room_alias_name"
+ every { createRoomBody.name } returns "a_name"
+ every { createRoomBody.topic } returns "a_topic"
+ every { createRoomBody.powerLevelContentOverride } returns PowerLevelsContent(
+ ban = 1,
+ kick = 2,
+ invite = 3,
+ redact = 4,
+ eventsDefault = 5,
+ events = null,
+ usersDefault = 6,
+ users = null,
+ stateDefault = 7,
+ notifications = null
+ )
+ every { createRoomBody.invite3pids } returns listOf(
+ ThreePidInviteBody(
+ idServer = "an_id_server",
+ idAccessToken = "an_id_access_token",
+ medium = MEDIUM_EMAIL,
+ address = "an_email@example.org"
+ )
+ )
+ every { createRoomBody.preset } returns CreateRoomPreset.PRESET_TRUSTED_PRIVATE_CHAT
+ every { createRoomBody.initialStates } returns listOf(
+ Event(type = "a_custom_type", stateKey = ""),
+ // override the value from the preset
+ Event(
+ type = EventType.STATE_ROOM_HISTORY_VISIBILITY,
+ stateKey = "",
+ content = RoomHistoryVisibilityContent(expectedHistoryVisibility.value).toContent()
+ )
+ )
+ every { createRoomBody.isDirect } returns expectedIsDirect
+ every { createRoomBody.invitedUserIds } returns listOf("a_user_id")
+
+ val orderedExpectedEventType = listOf(
+ EventType.STATE_ROOM_CREATE,
+ EventType.STATE_ROOM_MEMBER,
+ EventType.STATE_ROOM_POWER_LEVELS,
+ EventType.STATE_ROOM_CANONICAL_ALIAS,
+ EventType.STATE_ROOM_JOIN_RULES,
+ EventType.STATE_ROOM_GUEST_ACCESS,
+ "a_custom_type",
+ EventType.STATE_ROOM_HISTORY_VISIBILITY,
+ EventType.STATE_ROOM_NAME,
+ EventType.STATE_ROOM_TOPIC,
+ EventType.STATE_ROOM_MEMBER,
+ EventType.LOCAL_STATE_ROOM_THIRD_PARTY_INVITE,
+ EventType.STATE_ROOM_THIRD_PARTY_INVITE,
+ )
+
+ // When
+ val params = CreateLocalRoomStateEventsTask.Params(createRoomBody)
+ val result = defaultCreateLocalRoomStateEventsTask.execute(params)
+
+ // Then
+ result.map { it.type } shouldBeEqualTo orderedExpectedEventType
+ result.find { it.type == EventType.STATE_ROOM_HISTORY_VISIBILITY }
+ ?.content.toModel()?.historyVisibility shouldBeEqualTo expectedHistoryVisibility
+ result.lastOrNull { it.type == EventType.STATE_ROOM_MEMBER }
+ ?.content.toModel()?.isDirect shouldBeEqualTo expectedIsDirect
+ result.lastOrNull { it.type == EventType.LOCAL_STATE_ROOM_THIRD_PARTY_INVITE }
+ ?.content.toModel()?.isDirect shouldBeEqualTo expectedIsDirect
+ }
+}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/create/DefaultCreateRoomFromLocalRoomTaskTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/create/DefaultCreateRoomFromLocalRoomTaskTest.kt
new file mode 100644
index 0000000000..d3732363b5
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/create/DefaultCreateRoomFromLocalRoomTaskTest.kt
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.room.create
+
+import io.mockk.coEvery
+import io.mockk.coJustRun
+import io.mockk.coVerify
+import io.mockk.every
+import io.mockk.mockk
+import io.mockk.mockkStatic
+import io.mockk.unmockkAll
+import io.realm.kotlin.where
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.amshove.kluent.shouldBeEqualTo
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.matrix.android.sdk.api.query.QueryStringValue
+import org.matrix.android.sdk.api.session.events.model.Event
+import org.matrix.android.sdk.api.session.events.model.EventType
+import org.matrix.android.sdk.api.session.events.model.toContent
+import org.matrix.android.sdk.api.session.events.model.toModel
+import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
+import org.matrix.android.sdk.api.session.room.model.tombstone.RoomTombstoneContent
+import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
+import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
+import org.matrix.android.sdk.internal.database.model.EventEntity
+import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntity
+import org.matrix.android.sdk.internal.database.model.LocalRoomSummaryEntityFields
+import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore
+import org.matrix.android.sdk.internal.database.query.getOrCreate
+import org.matrix.android.sdk.internal.util.time.DefaultClock
+import org.matrix.android.sdk.test.fakes.FakeMonarchy
+import org.matrix.android.sdk.test.fakes.FakeStateEventDataSource
+
+private const val A_LOCAL_ROOM_ID = "local.a-local-room-id"
+private const val AN_EXISTING_ROOM_ID = "an-existing-room-id"
+private const val A_ROOM_ID = "a-room-id"
+private const val MY_USER_ID = "my-user-id"
+
+@ExperimentalCoroutinesApi
+internal class DefaultCreateRoomFromLocalRoomTaskTest {
+
+ private val fakeMonarchy = FakeMonarchy()
+ private val clock = DefaultClock()
+ private val createRoomTask = mockk()
+ private val fakeStateEventDataSource = FakeStateEventDataSource()
+
+ private val defaultCreateRoomFromLocalRoomTask = DefaultCreateRoomFromLocalRoomTask(
+ userId = MY_USER_ID,
+ monarchy = fakeMonarchy.instance,
+ createRoomTask = createRoomTask,
+ stateEventDataSource = fakeStateEventDataSource.instance,
+ clock = clock
+ )
+
+ @Before
+ fun setup() {
+ mockkStatic("org.matrix.android.sdk.internal.database.RealmQueryLatchKt")
+ coJustRun { awaitNotEmptyResult(realmConfiguration = any(), timeoutMillis = any(), builder = any()) }
+
+ mockkStatic("org.matrix.android.sdk.internal.database.query.EventEntityQueriesKt")
+ coEvery { any().copyToRealmOrIgnore(fakeMonarchy.fakeRealm.instance, any()) } answers { firstArg() }
+
+ mockkStatic("org.matrix.android.sdk.internal.database.query.CurrentStateEventEntityQueriesKt")
+ every { CurrentStateEventEntity.getOrCreate(fakeMonarchy.fakeRealm.instance, any(), any(), any()) } answers {
+ CurrentStateEventEntity(roomId = arg(2), stateKey = arg(3), type = arg(4))
+ }
+ }
+
+ @After
+ fun tearDown() {
+ unmockkAll()
+ }
+
+ @Test
+ fun `given a local room id when execute then the existing room id is kept`() = runTest {
+ // Given
+ givenATombstoneEvent(
+ Event(
+ roomId = A_LOCAL_ROOM_ID,
+ type = EventType.STATE_ROOM_TOMBSTONE,
+ stateKey = "",
+ content = RoomTombstoneContent(replacementRoomId = AN_EXISTING_ROOM_ID).toContent()
+ )
+ )
+
+ // When
+ val params = CreateRoomFromLocalRoomTask.Params(A_LOCAL_ROOM_ID)
+ val result = defaultCreateRoomFromLocalRoomTask.execute(params)
+
+ // Then
+ verifyTombstoneEvent(AN_EXISTING_ROOM_ID)
+ result shouldBeEqualTo AN_EXISTING_ROOM_ID
+ }
+
+ @Test
+ fun `given a local room id when execute then it is correctly executed`() = runTest {
+ // Given
+ val aCreateRoomParams = mockk()
+ val aLocalRoomSummaryEntity = mockk {
+ every { roomSummaryEntity } returns mockk(relaxed = true)
+ every { createRoomParams } returns aCreateRoomParams
+ }
+ givenATombstoneEvent(null)
+ givenALocalRoomSummaryEntity(aLocalRoomSummaryEntity)
+
+ coEvery { createRoomTask.execute(any()) } returns A_ROOM_ID
+
+ // When
+ val params = CreateRoomFromLocalRoomTask.Params(A_LOCAL_ROOM_ID)
+ val result = defaultCreateRoomFromLocalRoomTask.execute(params)
+
+ // Then
+ verifyTombstoneEvent(null)
+ // CreateRoomTask has been called with the initial CreateRoomParams
+ coVerify { createRoomTask.execute(aCreateRoomParams) }
+ // The resulting roomId matches the roomId returned by the createRoomTask
+ result shouldBeEqualTo A_ROOM_ID
+ // A tombstone state event has been created
+ coVerify { CurrentStateEventEntity.getOrCreate(realm = any(), roomId = A_LOCAL_ROOM_ID, stateKey = any(), type = EventType.STATE_ROOM_TOMBSTONE) }
+ }
+
+ private fun givenATombstoneEvent(event: Event?) {
+ fakeStateEventDataSource.givenGetStateEventReturns(event)
+ }
+
+ private fun givenALocalRoomSummaryEntity(localRoomSummaryEntity: LocalRoomSummaryEntity) {
+ every {
+ fakeMonarchy.fakeRealm.instance
+ .where()
+ .equalTo(LocalRoomSummaryEntityFields.ROOM_ID, A_LOCAL_ROOM_ID)
+ .findFirst()
+ } returns localRoomSummaryEntity
+ }
+
+ private fun verifyTombstoneEvent(expectedRoomId: String?) {
+ fakeStateEventDataSource.verifyGetStateEvent(A_LOCAL_ROOM_ID, EventType.STATE_ROOM_TOMBSTONE, QueryStringValue.IsEmpty)
+ fakeStateEventDataSource.instance.getStateEvent(A_LOCAL_ROOM_ID, EventType.STATE_ROOM_TOMBSTONE, QueryStringValue.IsEmpty)
+ ?.content.toModel()
+ ?.replacementRoomId shouldBeEqualTo expectedRoomId
+ }
+}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/location/DefaultGetActiveBeaconInfoForUserTaskTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/location/DefaultGetActiveBeaconInfoForUserTaskTest.kt
index 588bfaa979..d51ed77399 100644
--- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/location/DefaultGetActiveBeaconInfoForUserTaskTest.kt
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/location/DefaultGetActiveBeaconInfoForUserTaskTest.kt
@@ -22,6 +22,7 @@ import kotlinx.coroutines.test.runTest
import org.amshove.kluent.shouldBeEqualTo
import org.junit.After
import org.junit.Test
+import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toContent
@@ -69,7 +70,7 @@ class DefaultGetActiveBeaconInfoForUserTaskTest {
fakeStateEventDataSource.verifyGetStateEvent(
roomId = params.roomId,
eventType = EventType.STATE_ROOM_BEACON_INFO.first(),
- stateKey = A_USER_ID
+ stateKey = QueryStringValue.Equals(A_USER_ID)
)
}
}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeMonarchy.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeMonarchy.kt
index d77084fe3b..2d501f12af 100644
--- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeMonarchy.kt
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeMonarchy.kt
@@ -33,7 +33,7 @@ import org.matrix.android.sdk.internal.util.awaitTransaction
internal class FakeMonarchy {
val instance = mockk()
- private val fakeRealm = FakeRealm()
+ val fakeRealm = FakeRealm()
init {
mockkStatic("org.matrix.android.sdk.internal.util.MonarchyKt")
@@ -42,6 +42,12 @@ internal class FakeMonarchy {
} coAnswers {
secondArg Any>().invoke(fakeRealm.instance)
}
+ coEvery {
+ instance.doWithRealm(any())
+ } coAnswers {
+ firstArg().doWithRealm(fakeRealm.instance)
+ }
+ every { instance.realmConfiguration } returns mockk()
}
inline fun givenWhere(): RealmQuery {
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeStateEventDataSource.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeStateEventDataSource.kt
index ca03316fa7..ebb2a1d7a0 100644
--- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeStateEventDataSource.kt
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeStateEventDataSource.kt
@@ -19,7 +19,7 @@ package org.matrix.android.sdk.test.fakes
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
-import org.matrix.android.sdk.api.query.QueryStringValue
+import org.matrix.android.sdk.api.query.QueryStateEventValue
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
@@ -37,12 +37,12 @@ internal class FakeStateEventDataSource {
} returns event
}
- fun verifyGetStateEvent(roomId: String, eventType: String, stateKey: String) {
+ fun verifyGetStateEvent(roomId: String, eventType: String, stateKey: QueryStateEventValue) {
verify {
instance.getStateEvent(
roomId = roomId,
eventType = eventType,
- stateKey = QueryStringValue.Equals(stateKey)
+ stateKey = stateKey
)
}
}
diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt
index b12f15fa5d..b4d7ebae1f 100755
--- a/tools/check/forbidden_strings_in_code.txt
+++ b/tools/check/forbidden_strings_in_code.txt
@@ -185,3 +185,6 @@ System\.currentTimeMillis\(\)===2
onCreateOptionsMenu
onOptionsItemSelected
onPrepareOptionsMenu
+
+### Suspicious String template. Please check that the string template will behave as expected, i.e. the class field and not the whole object will be used. For instance `Timber.d("$event.type")` is not correct, you should write `Timber.d("${event.type}")`. In the former the whole event content will be logged, since it's a data class. If this is expected (i.e. to fix false positive), please add explicit curly braces (`{` and `}`) around the variable, for instance `"elementLogs.${i}.txt"`
+\$[a-zA-Z_]\w*\??\.[a-zA-Z_]
diff --git a/tools/emojis/emoji_picker_datasource_formatted.json b/tools/emojis/emoji_picker_datasource_formatted.json
index a1b944a7eb..41465a442f 100644
--- a/tools/emojis/emoji_picker_datasource_formatted.json
+++ b/tools/emojis/emoji_picker_datasource_formatted.json
@@ -2634,7 +2634,8 @@
"mask",
"sick",
"ill",
- "disease"
+ "disease",
+ "covid"
]
},
"face-with-thermometer": {
@@ -2647,7 +2648,8 @@
"thermometer",
"temperature",
"cold",
- "fever"
+ "fever",
+ "covid"
]
},
"face-with-headbandage": {
@@ -4481,7 +4483,9 @@
"hope",
"wish",
"namaste",
- "highfive"
+ "highfive",
+ "thank you",
+ "appreciate"
]
},
"writing-hand": {
@@ -9581,7 +9585,8 @@
"amoeba",
"bacteria",
"virus",
- "germs"
+ "germs",
+ "covid"
]
},
"bouquet": {
@@ -10260,7 +10265,9 @@
"baguette",
"bread",
"food",
- "french"
+ "french",
+ "france",
+ "bakery"
]
},
"flatbread": {
@@ -10272,7 +10279,8 @@
"naan",
"pita",
"flour",
- "food"
+ "food",
+ "bakery"
]
},
"pretzel": {
@@ -10282,7 +10290,9 @@
"twisted",
"convoluted",
"food",
- "bread"
+ "bread",
+ "germany",
+ "bakery"
]
},
"bagel": {
@@ -10293,7 +10303,8 @@
"breakfast",
"schmear",
"food",
- "bread"
+ "bread",
+ "jewish"
]
},
"pancakes": {
@@ -10306,7 +10317,8 @@
"hotcake",
"pancake",
"flapjacks",
- "hotcakes"
+ "hotcakes",
+ "brunch"
]
},
"waffle": {
@@ -10316,7 +10328,8 @@
"breakfast",
"indecisive",
"iron",
- "food"
+ "food",
+ "brunch"
]
},
"cheese-wedge": {
@@ -10325,7 +10338,8 @@
"j": [
"cheese",
"food",
- "chadder"
+ "chadder",
+ "swiss"
]
},
"meat-on-bone": {
@@ -10376,7 +10390,8 @@
"food",
"meat",
"pork",
- "pig"
+ "pig",
+ "brunch"
]
},
"hamburger": {
@@ -10400,7 +10415,8 @@
"fries",
"chips",
"snack",
- "fast food"
+ "fast food",
+ "potato"
]
},
"pizza": {
@@ -10410,7 +10426,8 @@
"cheese",
"slice",
"food",
- "party"
+ "party",
+ "italy"
]
},
"hot-dog": {
@@ -10420,7 +10437,8 @@
"frankfurter",
"hotdog",
"sausage",
- "food"
+ "food",
+ "america"
]
},
"sandwich": {
@@ -10429,7 +10447,9 @@
"j": [
"bread",
"food",
- "lunch"
+ "lunch",
+ "toast",
+ "bakery"
]
},
"taco": {
@@ -10468,7 +10488,8 @@
"food",
"gyro",
"kebab",
- "stuffed"
+ "stuffed",
+ "mediterranean"
]
},
"falafel": {
@@ -10477,7 +10498,8 @@
"j": [
"chickpea",
"meatball",
- "food"
+ "food",
+ "mediterranean"
]
},
"egg": {
@@ -10498,7 +10520,8 @@
"frying",
"pan",
"food",
- "kitchen"
+ "kitchen",
+ "skillet"
]
},
"shallow-pan-of-food": {
@@ -10510,7 +10533,8 @@
"paella",
"pan",
"shallow",
- "cooking"
+ "cooking",
+ "skillet"
]
},
"pot-of-food": {
@@ -10521,7 +10545,8 @@
"stew",
"food",
"meat",
- "soup"
+ "soup",
+ "hot pot"
]
},
"fondue": {
@@ -10556,7 +10581,8 @@
"green",
"salad",
"healthy",
- "lettuce"
+ "lettuce",
+ "vegetable"
]
},
"popcorn": {
@@ -10566,7 +10592,8 @@
"food",
"movie theater",
"films",
- "snack"
+ "snack",
+ "drama"
]
},
"butter": {
@@ -10592,7 +10619,8 @@
"j": [
"can",
"food",
- "soup"
+ "soup",
+ "tomatoes"
]
},
"bento-box": {
@@ -10602,7 +10630,8 @@
"bento",
"box",
"food",
- "japanese"
+ "japanese",
+ "lunch"
]
},
"rice-cracker": {
@@ -10612,7 +10641,8 @@
"cracker",
"rice",
"food",
- "japanese"
+ "japanese",
+ "snack"
]
},
"rice-ball": {
@@ -10633,7 +10663,6 @@
"cooked",
"rice",
"food",
- "china",
"asian"
]
},
@@ -10680,7 +10709,8 @@
"roasted",
"sweet",
"food",
- "nature"
+ "nature",
+ "plant"
]
},
"oden": {
@@ -10745,7 +10775,8 @@
"autumn",
"festival",
"yuèbǐng",
- "food"
+ "food",
+ "dessert"
]
},
"dango": {
@@ -10772,7 +10803,8 @@
"jiaozi",
"pierogi",
"potsticker",
- "food"
+ "food",
+ "gyoza"
]
},
"fortune-cookie": {
@@ -10780,7 +10812,8 @@
"b": "1F960",
"j": [
"prophecy",
- "food"
+ "food",
+ "dessert"
]
},
"takeout-box": {
@@ -22169,7 +22202,9 @@
"nation",
"country",
"banner",
- "japan"
+ "japan",
+ "jp",
+ "ja"
]
},
"flag-kenya": {
diff --git a/tools/release/pushPlayStoreMetaData.sh b/tools/release/pushPlayStoreMetaData.sh
index 5c2f69cb7b..2d8fd9b36a 100755
--- a/tools/release/pushPlayStoreMetaData.sh
+++ b/tools/release/pushPlayStoreMetaData.sh
@@ -28,7 +28,6 @@ mv ./fastlane/metadata/android/fy ./fastlane_tmp
mv ./fastlane/metadata/android/ga ./fastlane_tmp
mv ./fastlane/metadata/android/kab ./fastlane_tmp
mv ./fastlane/metadata/android/nb ./fastlane_tmp
-mv ./fastlane/metadata/android/gl ./fastlane_tmp
# Fastlane / PlayStore require longDescription and shortDescription file to be set, so copy the default
# one for languages where they are missing
diff --git a/tools/templates/ElementFeature/root/src/app_package/Fragment.kt.ftl b/tools/templates/ElementFeature/root/src/app_package/Fragment.kt.ftl
index 0f01b347c0..133faa6821 100644
--- a/tools/templates/ElementFeature/root/src/app_package/Fragment.kt.ftl
+++ b/tools/templates/ElementFeature/root/src/app_package/Fragment.kt.ftl
@@ -18,10 +18,10 @@ import javax.inject.Inject
data class ${fragmentArgsClass}() : Parcelable
#if>
-//TODO add this fragment into FragmentModule
-class ${fragmentClass} @Inject constructor(
- private val viewModelFactory: ${viewModelClass}.Factory
-) : VectorBaseFragment(), ${viewModelClass}.Factory by viewModelFactory {
+@AndroidEntryPoint
+class ${fragmentClass}() :
+ VectorBaseFragment(),
+ ${viewModelClass}.Factory by viewModelFactory {
<#if createFragmentArgs>
private val fragmentArgs: ${fragmentArgsClass} by args()
diff --git a/vector-config/src/main/java/im/vector/app/config/OnboardingVariant.kt b/vector-config/src/main/java/im/vector/app/config/OnboardingVariant.kt
index ae8cfd1172..8821c8187e 100644
--- a/vector-config/src/main/java/im/vector/app/config/OnboardingVariant.kt
+++ b/vector-config/src/main/java/im/vector/app/config/OnboardingVariant.kt
@@ -18,6 +18,5 @@ package im.vector.app.config
enum class OnboardingVariant {
LEGACY,
- LOGIN_2,
FTUE_AUTH
}
diff --git a/vector/build.gradle b/vector/build.gradle
index 629b7c4135..83d322946b 100644
--- a/vector/build.gradle
+++ b/vector/build.gradle
@@ -37,7 +37,7 @@ ext.versionMinor = 4
// Note: even values are reserved for regular release, odd values for hotfix release.
// When creating a hotfix, you should decrease the value, since the current value
// is the value for the next regular release.
-ext.versionPatch = 34
+ext.versionPatch = 36
static def getGitTimestamp() {
def cmd = 'git show -s --format=%ct'
@@ -391,7 +391,7 @@ dependencies {
implementation libs.androidx.biometric
implementation "org.threeten:threetenbp:1.4.0:no-tzdb"
- implementation "com.gabrielittner.threetenbp:lazythreetenbp:0.10.0"
+ implementation "com.gabrielittner.threetenbp:lazythreetenbp:0.11.0"
implementation libs.squareup.moshi
kapt libs.squareup.moshiKotlin
@@ -413,7 +413,7 @@ dependencies {
implementation 'com.facebook.stetho:stetho:1.6.0'
// Phone number https://github.com/google/libphonenumber
- implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.53'
+ implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.54'
// FlowBinding
implementation libs.github.flowBinding
diff --git a/vector/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt b/vector/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt
index b01c1a895f..068c9fb646 100644
--- a/vector/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt
+++ b/vector/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt
@@ -83,7 +83,7 @@ private fun useMediaStoreScreenshotStorage(
screenshotLocation: String,
bitmap: Bitmap
) {
- contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "$screenshotName.jpeg")
+ contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "${screenshotName}.jpeg")
contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, screenshotLocation)
val uri: Uri? = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
if (uri != null) {
@@ -104,7 +104,7 @@ private fun usePublicExternalScreenshotStorage(
if (!directory.exists()) {
directory.mkdirs()
}
- val file = File(directory, "$screenshotName.jpeg")
+ val file = File(directory, "${screenshotName}.jpeg")
saveScreenshotToStream(bitmap, FileOutputStream(file))
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
}
diff --git a/vector/src/androidTest/java/im/vector/app/features/reactions/data/EmojiDataSourceTest.kt b/vector/src/androidTest/java/im/vector/app/features/reactions/data/EmojiDataSourceTest.kt
index a880b17e0c..3517f806d6 100644
--- a/vector/src/androidTest/java/im/vector/app/features/reactions/data/EmojiDataSourceTest.kt
+++ b/vector/src/androidTest/java/im/vector/app/features/reactions/data/EmojiDataSourceTest.kt
@@ -76,7 +76,7 @@ class EmojiDataSourceTest : InstrumentedTest {
fun searchTestOneResult() {
val emojiDataSource = createEmojiDataSource()
val result = runBlocking {
- emojiDataSource.filterWith("france")
+ emojiDataSource.filterWith("flag-france")
}
assertEquals("Should have 1 result", 1, result.size)
}
diff --git a/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksFragment.kt b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksFragment.kt
index d3e70e26e6..2abf6487e2 100644
--- a/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksFragment.kt
+++ b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksFragment.kt
@@ -28,7 +28,8 @@ import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentDebugMemoryLeaksBinding
@AndroidEntryPoint
-class DebugMemoryLeaksFragment : VectorBaseFragment() {
+class DebugMemoryLeaksFragment :
+ VectorBaseFragment() {
private val viewModel: DebugMemoryLeaksViewModel by fragmentViewModel()
diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml
index beee800b4a..ea62aa1b58 100644
--- a/vector/src/main/AndroidManifest.xml
+++ b/vector/src/main/AndroidManifest.xml
@@ -348,6 +348,8 @@
+
+
diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt
index 4655de7377..46cb6ec79b 100644
--- a/vector/src/main/java/im/vector/app/VectorApplication.kt
+++ b/vector/src/main/java/im/vector/app/VectorApplication.kt
@@ -266,7 +266,7 @@ class VectorApplication :
}
private fun createFontThreadHandler(): Handler {
- val handlerThread = HandlerThread("fonts")
+ val handlerThread = HandlerThread("Vector-fonts")
handlerThread.start()
return Handler(handlerThread.looper)
}
diff --git a/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt b/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt
index 7a1d613ab9..3f0507305a 100644
--- a/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt
+++ b/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt
@@ -20,6 +20,7 @@ import android.content.Context
import arrow.core.Option
import im.vector.app.ActiveSessionDataSource
import im.vector.app.core.extensions.configureAndStart
+import im.vector.app.core.extensions.startSyncing
import im.vector.app.core.pushers.UnifiedPushHelper
import im.vector.app.core.services.GuardServiceStarter
import im.vector.app.features.call.webrtc.WebRtcCallManager
@@ -69,7 +70,7 @@ class ActiveSessionHolder @Inject constructor(
suspend fun clearActiveSession() {
// Do some cleanup first
- getSafeActiveSession()?.let {
+ getSafeActiveSession(startSync = false)?.let {
Timber.w("clearActiveSession of ${it.myUserId}")
it.callSignalingService().removeCallListener(callManager)
it.removeListener(sessionListener)
@@ -90,8 +91,8 @@ class ActiveSessionHolder @Inject constructor(
return activeSessionReference.get() != null || authenticationService.hasAuthenticatedSessions()
}
- fun getSafeActiveSession(): Session? {
- return runBlocking { getOrInitializeSession(startSync = true) }
+ fun getSafeActiveSession(startSync: Boolean = true): Session? {
+ return runBlocking { getOrInitializeSession(startSync = startSync) }
}
fun getActiveSession(): Session {
@@ -100,10 +101,16 @@ class ActiveSessionHolder @Inject constructor(
}
suspend fun getOrInitializeSession(startSync: Boolean): Session? {
- return activeSessionReference.get() ?: sessionInitializer.tryInitialize(readCurrentSession = { activeSessionReference.get() }) { session ->
- setActiveSession(session)
- session.configureAndStart(applicationContext, startSyncing = startSync)
- }
+ return activeSessionReference.get()
+ ?.also {
+ if (startSync && !it.syncService().isSyncThreadAlive()) {
+ it.startSyncing(applicationContext)
+ }
+ }
+ ?: sessionInitializer.tryInitialize(readCurrentSession = { activeSessionReference.get() }) { session ->
+ setActiveSession(session)
+ session.configureAndStart(applicationContext, startSyncing = startSync)
+ }
}
fun isWaitingForSessionInitialization() = activeSessionReference.get() == null && authenticationService.hasAuthenticatedSessions()
diff --git a/vector/src/main/java/im/vector/app/core/di/ActivityEntryPoint.kt b/vector/src/main/java/im/vector/app/core/di/ActivityEntryPoint.kt
index c5f7317ebe..4b8b23489b 100644
--- a/vector/src/main/java/im/vector/app/core/di/ActivityEntryPoint.kt
+++ b/vector/src/main/java/im/vector/app/core/di/ActivityEntryPoint.kt
@@ -16,7 +16,6 @@
package im.vector.app.core.di
-import androidx.fragment.app.FragmentFactory
import androidx.lifecycle.ViewModelProvider
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
@@ -25,6 +24,5 @@ import dagger.hilt.android.components.ActivityComponent
@InstallIn(ActivityComponent::class)
@EntryPoint
interface ActivityEntryPoint {
- fun fragmentFactory(): FragmentFactory
fun viewModelFactory(): ViewModelProvider.Factory
}
diff --git a/vector/src/main/java/im/vector/app/core/di/FragmentKey.kt b/vector/src/main/java/im/vector/app/core/di/FragmentKey.kt
deleted file mode 100644
index bc2dc40a15..0000000000
--- a/vector/src/main/java/im/vector/app/core/di/FragmentKey.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.di
-
-import androidx.fragment.app.Fragment
-import dagger.MapKey
-import kotlin.reflect.KClass
-
-@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
-@Retention(AnnotationRetention.RUNTIME)
-@MapKey
-annotation class FragmentKey(val value: KClass)
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
deleted file mode 100644
index e86b350534..0000000000
--- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt
+++ /dev/null
@@ -1,1056 +0,0 @@
-/*
- * 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.di
-
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentFactory
-import dagger.Binds
-import dagger.Module
-import dagger.hilt.InstallIn
-import dagger.hilt.android.components.ActivityComponent
-import dagger.multibindings.IntoMap
-import im.vector.app.features.analytics.ui.consent.AnalyticsOptInFragment
-import im.vector.app.features.attachments.preview.AttachmentsPreviewFragment
-import im.vector.app.features.contactsbook.ContactsBookFragment
-import im.vector.app.features.crypto.keysbackup.settings.KeysBackupSettingsFragment
-import im.vector.app.features.crypto.quads.SharedSecuredStorageKeyFragment
-import im.vector.app.features.crypto.quads.SharedSecuredStoragePassphraseFragment
-import im.vector.app.features.crypto.quads.SharedSecuredStorageResetAllFragment
-import im.vector.app.features.crypto.recover.BootstrapConclusionFragment
-import im.vector.app.features.crypto.recover.BootstrapConfirmPassphraseFragment
-import im.vector.app.features.crypto.recover.BootstrapEnterPassphraseFragment
-import im.vector.app.features.crypto.recover.BootstrapMigrateBackupFragment
-import im.vector.app.features.crypto.recover.BootstrapReAuthFragment
-import im.vector.app.features.crypto.recover.BootstrapSaveRecoveryKeyFragment
-import im.vector.app.features.crypto.recover.BootstrapSetupRecoveryKeyFragment
-import im.vector.app.features.crypto.recover.BootstrapWaitingFragment
-import im.vector.app.features.crypto.verification.QuadSLoadingFragment
-import im.vector.app.features.crypto.verification.cancel.VerificationCancelFragment
-import im.vector.app.features.crypto.verification.cancel.VerificationNotMeFragment
-import im.vector.app.features.crypto.verification.choose.VerificationChooseMethodFragment
-import im.vector.app.features.crypto.verification.conclusion.VerificationConclusionFragment
-import im.vector.app.features.crypto.verification.emoji.VerificationEmojiCodeFragment
-import im.vector.app.features.crypto.verification.qrconfirmation.VerificationQRWaitingFragment
-import im.vector.app.features.crypto.verification.qrconfirmation.VerificationQrScannedByOtherFragment
-import im.vector.app.features.crypto.verification.request.VerificationRequestFragment
-import im.vector.app.features.devtools.RoomDevToolEditFragment
-import im.vector.app.features.devtools.RoomDevToolFragment
-import im.vector.app.features.devtools.RoomDevToolSendFormFragment
-import im.vector.app.features.devtools.RoomDevToolStateEventListFragment
-import im.vector.app.features.discovery.DiscoverySettingsFragment
-import im.vector.app.features.discovery.change.SetIdentityServerFragment
-import im.vector.app.features.home.HomeDetailFragment
-import im.vector.app.features.home.HomeDrawerFragment
-import im.vector.app.features.home.LoadingFragment
-import im.vector.app.features.home.NewHomeDetailFragment
-import im.vector.app.features.home.room.breadcrumbs.BreadcrumbsFragment
-import im.vector.app.features.home.room.detail.TimelineFragment
-import im.vector.app.features.home.room.detail.search.SearchFragment
-import im.vector.app.features.home.room.list.RoomListFragment
-import im.vector.app.features.home.room.list.home.HomeRoomListFragment
-import im.vector.app.features.home.room.threads.list.views.ThreadListFragment
-import im.vector.app.features.location.LocationSharingFragment
-import im.vector.app.features.location.preview.LocationPreviewFragment
-import im.vector.app.features.login.LoginCaptchaFragment
-import im.vector.app.features.login.LoginFragment
-import im.vector.app.features.login.LoginGenericTextInputFormFragment
-import im.vector.app.features.login.LoginResetPasswordFragment
-import im.vector.app.features.login.LoginResetPasswordMailConfirmationFragment
-import im.vector.app.features.login.LoginResetPasswordSuccessFragment
-import im.vector.app.features.login.LoginServerSelectionFragment
-import im.vector.app.features.login.LoginServerUrlFormFragment
-import im.vector.app.features.login.LoginSignUpSignInSelectionFragment
-import im.vector.app.features.login.LoginSplashFragment
-import im.vector.app.features.login.LoginWaitForEmailFragment
-import im.vector.app.features.login.LoginWebFragment
-import im.vector.app.features.login.terms.LoginTermsFragment
-import im.vector.app.features.login2.LoginCaptchaFragment2
-import im.vector.app.features.login2.LoginFragmentSigninPassword2
-import im.vector.app.features.login2.LoginFragmentSigninUsername2
-import im.vector.app.features.login2.LoginFragmentSignupPassword2
-import im.vector.app.features.login2.LoginFragmentSignupUsername2
-import im.vector.app.features.login2.LoginFragmentToAny2
-import im.vector.app.features.login2.LoginGenericTextInputFormFragment2
-import im.vector.app.features.login2.LoginResetPasswordFragment2
-import im.vector.app.features.login2.LoginResetPasswordMailConfirmationFragment2
-import im.vector.app.features.login2.LoginResetPasswordSuccessFragment2
-import im.vector.app.features.login2.LoginServerSelectionFragment2
-import im.vector.app.features.login2.LoginServerUrlFormFragment2
-import im.vector.app.features.login2.LoginSplashSignUpSignInSelectionFragment2
-import im.vector.app.features.login2.LoginSsoOnlyFragment2
-import im.vector.app.features.login2.LoginWaitForEmailFragment2
-import im.vector.app.features.login2.LoginWebFragment2
-import im.vector.app.features.login2.created.AccountCreatedFragment
-import im.vector.app.features.login2.terms.LoginTermsFragment2
-import im.vector.app.features.matrixto.MatrixToRoomSpaceFragment
-import im.vector.app.features.matrixto.MatrixToUserFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthAccountCreatedFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthCaptchaFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthChooseDisplayNameFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthChooseProfilePictureFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthCombinedLoginFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthCombinedRegisterFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthCombinedServerSelectionFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthEmailEntryFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthGenericTextInputFormFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthLegacyStyleCaptchaFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthLegacyWaitForEmailFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthLoginFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthPersonalizationCompleteFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthPhoneConfirmationFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthPhoneEntryFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthResetPasswordFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthResetPasswordMailConfirmationFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthResetPasswordSuccessFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthServerSelectionFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthSignUpSignInSelectionFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthSplashCarouselFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthSplashFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthUseCaseFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthWaitForEmailFragment
-import im.vector.app.features.onboarding.ftueauth.FtueAuthWebFragment
-import im.vector.app.features.onboarding.ftueauth.terms.FtueAuthLegacyStyleTermsFragment
-import im.vector.app.features.onboarding.ftueauth.terms.FtueAuthTermsFragment
-import im.vector.app.features.pin.PinFragment
-import im.vector.app.features.poll.create.CreatePollFragment
-import im.vector.app.features.qrcode.QrCodeScannerFragment
-import im.vector.app.features.reactions.EmojiChooserFragment
-import im.vector.app.features.reactions.EmojiSearchResultFragment
-import im.vector.app.features.roomdirectory.PublicRoomsFragment
-import im.vector.app.features.roomdirectory.createroom.CreateRoomFragment
-import im.vector.app.features.roomdirectory.picker.RoomDirectoryPickerFragment
-import im.vector.app.features.roomdirectory.roompreview.RoomPreviewNoPreviewFragment
-import im.vector.app.features.roommemberprofile.RoomMemberProfileFragment
-import im.vector.app.features.roommemberprofile.devices.DeviceListFragment
-import im.vector.app.features.roommemberprofile.devices.DeviceTrustInfoActionFragment
-import im.vector.app.features.roomprofile.RoomProfileFragment
-import im.vector.app.features.roomprofile.alias.RoomAliasFragment
-import im.vector.app.features.roomprofile.banned.RoomBannedMemberListFragment
-import im.vector.app.features.roomprofile.members.RoomMemberListFragment
-import im.vector.app.features.roomprofile.notifications.RoomNotificationSettingsFragment
-import im.vector.app.features.roomprofile.permissions.RoomPermissionsFragment
-import im.vector.app.features.roomprofile.settings.RoomSettingsFragment
-import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleFragment
-import im.vector.app.features.roomprofile.settings.joinrule.advanced.RoomJoinRuleChooseRestrictedFragment
-import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment
-import im.vector.app.features.roomprofile.uploads.files.RoomUploadsFilesFragment
-import im.vector.app.features.roomprofile.uploads.media.RoomUploadsMediaFragment
-import im.vector.app.features.settings.VectorSettingsGeneralFragment
-import im.vector.app.features.settings.VectorSettingsHelpAboutFragment
-import im.vector.app.features.settings.VectorSettingsLabsFragment
-import im.vector.app.features.settings.VectorSettingsPinFragment
-import im.vector.app.features.settings.VectorSettingsPreferencesFragment
-import im.vector.app.features.settings.VectorSettingsSecurityPrivacyFragment
-import im.vector.app.features.settings.account.deactivation.DeactivateAccountFragment
-import im.vector.app.features.settings.crosssigning.CrossSigningSettingsFragment
-import im.vector.app.features.settings.devices.VectorSettingsDevicesFragment
-import im.vector.app.features.settings.devtools.AccountDataFragment
-import im.vector.app.features.settings.devtools.GossipingEventsPaperTrailFragment
-import im.vector.app.features.settings.devtools.IncomingKeyRequestListFragment
-import im.vector.app.features.settings.devtools.KeyRequestsFragment
-import im.vector.app.features.settings.devtools.OutgoingKeyRequestListFragment
-import im.vector.app.features.settings.font.FontScaleSettingFragment
-import im.vector.app.features.settings.homeserver.HomeserverSettingsFragment
-import im.vector.app.features.settings.ignored.VectorSettingsIgnoredUsersFragment
-import im.vector.app.features.settings.legals.LegalsFragment
-import im.vector.app.features.settings.locale.LocalePickerFragment
-import im.vector.app.features.settings.notifications.VectorSettingsAdvancedNotificationPreferenceFragment
-import im.vector.app.features.settings.notifications.VectorSettingsNotificationPreferenceFragment
-import im.vector.app.features.settings.notifications.VectorSettingsNotificationsTroubleshootFragment
-import im.vector.app.features.settings.push.PushGatewaysFragment
-import im.vector.app.features.settings.push.PushRulesFragment
-import im.vector.app.features.settings.threepids.ThreePidsSettingsFragment
-import im.vector.app.features.share.IncomingShareFragment
-import im.vector.app.features.signout.soft.SoftLogoutFragment
-import im.vector.app.features.spaces.SpaceListFragment
-import im.vector.app.features.spaces.create.ChoosePrivateSpaceTypeFragment
-import im.vector.app.features.spaces.create.ChooseSpaceTypeFragment
-import im.vector.app.features.spaces.create.CreateSpaceAdd3pidInvitesFragment
-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.leave.SpaceLeaveAdvancedFragment
-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
-import im.vector.app.features.usercode.ShowUserCodeFragment
-import im.vector.app.features.userdirectory.UserListFragment
-import im.vector.app.features.widgets.WidgetFragment
-
-@InstallIn(ActivityComponent::class)
-@Module
-interface FragmentModule {
- /**
- * Fragments with @IntoMap will be injected by this factory.
- */
- @Binds
- fun bindFragmentFactory(factory: VectorFragmentFactory): FragmentFactory
-
- @Binds
- @IntoMap
- @FragmentKey(RoomListFragment::class)
- fun bindRoomListFragment(fragment: RoomListFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LocalePickerFragment::class)
- fun bindLocalePickerFragment(fragment: LocalePickerFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(SpaceListFragment::class)
- fun bindSpaceListFragment(fragment: SpaceListFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(TimelineFragment::class)
- fun bindTimelineFragment(fragment: TimelineFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomDirectoryPickerFragment::class)
- fun bindRoomDirectoryPickerFragment(fragment: RoomDirectoryPickerFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(CreateRoomFragment::class)
- fun bindCreateRoomFragment(fragment: CreateRoomFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomPreviewNoPreviewFragment::class)
- fun bindRoomPreviewNoPreviewFragment(fragment: RoomPreviewNoPreviewFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(KeysBackupSettingsFragment::class)
- fun bindKeysBackupSettingsFragment(fragment: KeysBackupSettingsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoadingFragment::class)
- fun bindLoadingFragment(fragment: LoadingFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(HomeDrawerFragment::class)
- fun bindHomeDrawerFragment(fragment: HomeDrawerFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(HomeDetailFragment::class)
- fun bindHomeDetailFragment(fragment: HomeDetailFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(NewHomeDetailFragment::class)
- fun bindNewHomeDetailFragment(fragment: NewHomeDetailFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(EmojiSearchResultFragment::class)
- fun bindEmojiSearchResultFragment(fragment: EmojiSearchResultFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginFragment::class)
- fun bindLoginFragment(fragment: LoginFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginCaptchaFragment::class)
- fun bindLoginCaptchaFragment(fragment: LoginCaptchaFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginTermsFragment::class)
- fun bindLoginTermsFragment(fragment: LoginTermsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginServerUrlFormFragment::class)
- fun bindLoginServerUrlFormFragment(fragment: LoginServerUrlFormFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginResetPasswordMailConfirmationFragment::class)
- fun bindLoginResetPasswordMailConfirmationFragment(fragment: LoginResetPasswordMailConfirmationFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginResetPasswordFragment::class)
- fun bindLoginResetPasswordFragment(fragment: LoginResetPasswordFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginResetPasswordSuccessFragment::class)
- fun bindLoginResetPasswordSuccessFragment(fragment: LoginResetPasswordSuccessFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginServerSelectionFragment::class)
- fun bindLoginServerSelectionFragment(fragment: LoginServerSelectionFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginSignUpSignInSelectionFragment::class)
- fun bindLoginSignUpSignInSelectionFragment(fragment: LoginSignUpSignInSelectionFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginSplashFragment::class)
- fun bindLoginSplashFragment(fragment: LoginSplashFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginWebFragment::class)
- fun bindLoginWebFragment(fragment: LoginWebFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginGenericTextInputFormFragment::class)
- fun bindLoginGenericTextInputFormFragment(fragment: LoginGenericTextInputFormFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginWaitForEmailFragment::class)
- fun bindLoginWaitForEmailFragment(fragment: LoginWaitForEmailFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginFragmentSigninUsername2::class)
- fun bindLoginFragmentSigninUsername2(fragment: LoginFragmentSigninUsername2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(AccountCreatedFragment::class)
- fun bindAccountCreatedFragment(fragment: AccountCreatedFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginFragmentSignupUsername2::class)
- fun bindLoginFragmentSignupUsername2(fragment: LoginFragmentSignupUsername2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginFragmentSigninPassword2::class)
- fun bindLoginFragmentSigninPassword2(fragment: LoginFragmentSigninPassword2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginFragmentSignupPassword2::class)
- fun bindLoginFragmentSignupPassword2(fragment: LoginFragmentSignupPassword2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginCaptchaFragment2::class)
- fun bindLoginCaptchaFragment2(fragment: LoginCaptchaFragment2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginFragmentToAny2::class)
- fun bindLoginFragmentToAny2(fragment: LoginFragmentToAny2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginTermsFragment2::class)
- fun bindLoginTermsFragment2(fragment: LoginTermsFragment2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginServerUrlFormFragment2::class)
- fun bindLoginServerUrlFormFragment2(fragment: LoginServerUrlFormFragment2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginResetPasswordMailConfirmationFragment2::class)
- fun bindLoginResetPasswordMailConfirmationFragment2(fragment: LoginResetPasswordMailConfirmationFragment2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginResetPasswordFragment2::class)
- fun bindLoginResetPasswordFragment2(fragment: LoginResetPasswordFragment2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginResetPasswordSuccessFragment2::class)
- fun bindLoginResetPasswordSuccessFragment2(fragment: LoginResetPasswordSuccessFragment2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginServerSelectionFragment2::class)
- fun bindLoginServerSelectionFragment2(fragment: LoginServerSelectionFragment2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginSsoOnlyFragment2::class)
- fun bindLoginSsoOnlyFragment2(fragment: LoginSsoOnlyFragment2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginSplashSignUpSignInSelectionFragment2::class)
- fun bindLoginSplashSignUpSignInSelectionFragment2(fragment: LoginSplashSignUpSignInSelectionFragment2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginWebFragment2::class)
- fun bindLoginWebFragment2(fragment: LoginWebFragment2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginGenericTextInputFormFragment2::class)
- fun bindLoginGenericTextInputFormFragment2(fragment: LoginGenericTextInputFormFragment2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LoginWaitForEmailFragment2::class)
- fun bindLoginWaitForEmailFragment2(fragment: LoginWaitForEmailFragment2): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthLegacyStyleCaptchaFragment::class)
- fun bindFtueAuthLegacyStyleCaptchaFragment(fragment: FtueAuthLegacyStyleCaptchaFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthCaptchaFragment::class)
- fun bindFtueAuthCaptchaFragment(fragment: FtueAuthCaptchaFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthGenericTextInputFormFragment::class)
- fun bindFtueAuthGenericTextInputFormFragment(fragment: FtueAuthGenericTextInputFormFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthLoginFragment::class)
- fun bindFtueAuthLoginFragment(fragment: FtueAuthLoginFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthResetPasswordFragment::class)
- fun bindFtueAuthResetPasswordFragment(fragment: FtueAuthResetPasswordFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthResetPasswordMailConfirmationFragment::class)
- fun bindFtueAuthResetPasswordMailConfirmationFragment(fragment: FtueAuthResetPasswordMailConfirmationFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthResetPasswordSuccessFragment::class)
- fun bindFtueAuthResetPasswordSuccessFragment(fragment: FtueAuthResetPasswordSuccessFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthServerSelectionFragment::class)
- fun bindFtueAuthServerSelectionFragment(fragment: FtueAuthServerSelectionFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthSignUpSignInSelectionFragment::class)
- fun bindFtueAuthSignUpSignInSelectionFragment(fragment: FtueAuthSignUpSignInSelectionFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthSplashFragment::class)
- fun bindFtueAuthSplashFragment(fragment: FtueAuthSplashFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthSplashCarouselFragment::class)
- fun bindFtueAuthSplashCarouselFragment(fragment: FtueAuthSplashCarouselFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthUseCaseFragment::class)
- fun bindFtueAuthUseCaseFragment(fragment: FtueAuthUseCaseFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthWaitForEmailFragment::class)
- fun bindFtueAuthWaitForEmailFragment(fragment: FtueAuthWaitForEmailFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthLegacyWaitForEmailFragment::class)
- fun bindFtueAuthLegacyWaitForEmailFragment(fragment: FtueAuthLegacyWaitForEmailFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthWebFragment::class)
- fun bindFtueAuthWebFragment(fragment: FtueAuthWebFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthLegacyStyleTermsFragment::class)
- fun bindFtueAuthLegacyStyleTermsFragment(fragment: FtueAuthLegacyStyleTermsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthTermsFragment::class)
- fun bindFtueAuthTermsFragment(fragment: FtueAuthTermsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthAccountCreatedFragment::class)
- fun bindFtueAuthAccountCreatedFragment(fragment: FtueAuthAccountCreatedFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthEmailEntryFragment::class)
- fun bindFtueAuthEmailEntryFragment(fragment: FtueAuthEmailEntryFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthPhoneEntryFragment::class)
- fun bindFtueAuthPhoneEntryFragment(fragment: FtueAuthPhoneEntryFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthPhoneConfirmationFragment::class)
- fun bindFtueAuthPhoneConfirmationFragment(fragment: FtueAuthPhoneConfirmationFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthChooseDisplayNameFragment::class)
- fun bindFtueAuthChooseDisplayNameFragment(fragment: FtueAuthChooseDisplayNameFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthChooseProfilePictureFragment::class)
- fun bindFtueAuthChooseProfilePictureFragment(fragment: FtueAuthChooseProfilePictureFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthPersonalizationCompleteFragment::class)
- fun bindFtueAuthPersonalizationCompleteFragment(fragment: FtueAuthPersonalizationCompleteFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthCombinedLoginFragment::class)
- fun bindFtueAuthCombinedLoginFragment(fragment: FtueAuthCombinedLoginFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthCombinedRegisterFragment::class)
- fun bindFtueAuthCombinedRegisterFragment(fragment: FtueAuthCombinedRegisterFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FtueAuthCombinedServerSelectionFragment::class)
- fun bindFtueAuthCombinedServerSelectionFragment(fragment: FtueAuthCombinedServerSelectionFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(UserListFragment::class)
- fun bindUserListFragment(fragment: UserListFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(PushGatewaysFragment::class)
- fun bindPushGatewaysFragment(fragment: PushGatewaysFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VectorSettingsNotificationsTroubleshootFragment::class)
- fun bindVectorSettingsNotificationsTroubleshootFragment(fragment: VectorSettingsNotificationsTroubleshootFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VectorSettingsAdvancedNotificationPreferenceFragment::class)
- fun bindVectorSettingsAdvancedNotificationPreferenceFragment(fragment: VectorSettingsAdvancedNotificationPreferenceFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VectorSettingsNotificationPreferenceFragment::class)
- fun bindVectorSettingsNotificationPreferenceFragment(fragment: VectorSettingsNotificationPreferenceFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VectorSettingsLabsFragment::class)
- fun bindVectorSettingsLabsFragment(fragment: VectorSettingsLabsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(HomeserverSettingsFragment::class)
- fun bindHomeserverSettingsFragment(fragment: HomeserverSettingsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(FontScaleSettingFragment::class)
- fun bindFontScaleSettingFragment(fragment: FontScaleSettingFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VectorSettingsPinFragment::class)
- fun bindVectorSettingsPinFragment(fragment: VectorSettingsPinFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VectorSettingsGeneralFragment::class)
- fun bindVectorSettingsGeneralFragment(fragment: VectorSettingsGeneralFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(PushRulesFragment::class)
- fun bindPushRulesFragment(fragment: PushRulesFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VectorSettingsPreferencesFragment::class)
- fun bindVectorSettingsPreferencesFragment(fragment: VectorSettingsPreferencesFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VectorSettingsSecurityPrivacyFragment::class)
- fun bindVectorSettingsSecurityPrivacyFragment(fragment: VectorSettingsSecurityPrivacyFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VectorSettingsHelpAboutFragment::class)
- fun bindVectorSettingsHelpAboutFragment(fragment: VectorSettingsHelpAboutFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VectorSettingsIgnoredUsersFragment::class)
- fun bindVectorSettingsIgnoredUsersFragment(fragment: VectorSettingsIgnoredUsersFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VectorSettingsDevicesFragment::class)
- fun bindVectorSettingsDevicesFragment(fragment: VectorSettingsDevicesFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(ThreePidsSettingsFragment::class)
- fun bindThreePidsSettingsFragment(fragment: ThreePidsSettingsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(PublicRoomsFragment::class)
- fun bindPublicRoomsFragment(fragment: PublicRoomsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomProfileFragment::class)
- fun bindRoomProfileFragment(fragment: RoomProfileFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomMemberListFragment::class)
- fun bindRoomMemberListFragment(fragment: RoomMemberListFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomUploadsFragment::class)
- fun bindRoomUploadsFragment(fragment: RoomUploadsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomUploadsMediaFragment::class)
- fun bindRoomUploadsMediaFragment(fragment: RoomUploadsMediaFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomUploadsFilesFragment::class)
- fun bindRoomUploadsFilesFragment(fragment: RoomUploadsFilesFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomSettingsFragment::class)
- fun bindRoomSettingsFragment(fragment: RoomSettingsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomAliasFragment::class)
- fun bindRoomAliasFragment(fragment: RoomAliasFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomPermissionsFragment::class)
- fun bindRoomPermissionsFragment(fragment: RoomPermissionsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomMemberProfileFragment::class)
- fun bindRoomMemberProfileFragment(fragment: RoomMemberProfileFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(BreadcrumbsFragment::class)
- fun bindBreadcrumbsFragment(fragment: BreadcrumbsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(AnalyticsOptInFragment::class)
- fun bindAnalyticsOptInFragment(fragment: AnalyticsOptInFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(EmojiChooserFragment::class)
- fun bindEmojiChooserFragment(fragment: EmojiChooserFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(SoftLogoutFragment::class)
- fun bindSoftLogoutFragment(fragment: SoftLogoutFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VerificationRequestFragment::class)
- fun bindVerificationRequestFragment(fragment: VerificationRequestFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VerificationChooseMethodFragment::class)
- fun bindVerificationChooseMethodFragment(fragment: VerificationChooseMethodFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VerificationEmojiCodeFragment::class)
- fun bindVerificationEmojiCodeFragment(fragment: VerificationEmojiCodeFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VerificationQrScannedByOtherFragment::class)
- fun bindVerificationQrScannedByOtherFragment(fragment: VerificationQrScannedByOtherFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VerificationQRWaitingFragment::class)
- fun bindVerificationQRWaitingFragment(fragment: VerificationQRWaitingFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VerificationConclusionFragment::class)
- fun bindVerificationConclusionFragment(fragment: VerificationConclusionFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VerificationCancelFragment::class)
- fun bindVerificationCancelFragment(fragment: VerificationCancelFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(QuadSLoadingFragment::class)
- fun bindQuadSLoadingFragment(fragment: QuadSLoadingFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(VerificationNotMeFragment::class)
- fun bindVerificationNotMeFragment(fragment: VerificationNotMeFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(QrCodeScannerFragment::class)
- fun bindQrCodeScannerFragment(fragment: QrCodeScannerFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(DeviceListFragment::class)
- fun bindDeviceListFragment(fragment: DeviceListFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(DeviceTrustInfoActionFragment::class)
- fun bindDeviceTrustInfoActionFragment(fragment: DeviceTrustInfoActionFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(CrossSigningSettingsFragment::class)
- fun bindCrossSigningSettingsFragment(fragment: CrossSigningSettingsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(AttachmentsPreviewFragment::class)
- fun bindAttachmentsPreviewFragment(fragment: AttachmentsPreviewFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(IncomingShareFragment::class)
- fun bindIncomingShareFragment(fragment: IncomingShareFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(AccountDataFragment::class)
- fun bindAccountDataFragment(fragment: AccountDataFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(OutgoingKeyRequestListFragment::class)
- fun bindOutgoingKeyRequestListFragment(fragment: OutgoingKeyRequestListFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(IncomingKeyRequestListFragment::class)
- fun bindIncomingKeyRequestListFragment(fragment: IncomingKeyRequestListFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(KeyRequestsFragment::class)
- fun bindKeyRequestsFragment(fragment: KeyRequestsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(GossipingEventsPaperTrailFragment::class)
- fun bindGossipingEventsPaperTrailFragment(fragment: GossipingEventsPaperTrailFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(BootstrapEnterPassphraseFragment::class)
- fun bindBootstrapEnterPassphraseFragment(fragment: BootstrapEnterPassphraseFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(BootstrapConfirmPassphraseFragment::class)
- fun bindBootstrapConfirmPassphraseFragment(fragment: BootstrapConfirmPassphraseFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(BootstrapWaitingFragment::class)
- fun bindBootstrapWaitingFragment(fragment: BootstrapWaitingFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(BootstrapSetupRecoveryKeyFragment::class)
- fun bindBootstrapSetupRecoveryKeyFragment(fragment: BootstrapSetupRecoveryKeyFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(BootstrapSaveRecoveryKeyFragment::class)
- fun bindBootstrapSaveRecoveryKeyFragment(fragment: BootstrapSaveRecoveryKeyFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(BootstrapConclusionFragment::class)
- fun bindBootstrapConclusionFragment(fragment: BootstrapConclusionFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(BootstrapReAuthFragment::class)
- fun bindBootstrapReAuthFragment(fragment: BootstrapReAuthFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(BootstrapMigrateBackupFragment::class)
- fun bindBootstrapMigrateBackupFragment(fragment: BootstrapMigrateBackupFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(DeactivateAccountFragment::class)
- fun bindDeactivateAccountFragment(fragment: DeactivateAccountFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(SharedSecuredStoragePassphraseFragment::class)
- fun bindSharedSecuredStoragePassphraseFragment(fragment: SharedSecuredStoragePassphraseFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(SharedSecuredStorageKeyFragment::class)
- fun bindSharedSecuredStorageKeyFragment(fragment: SharedSecuredStorageKeyFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(SharedSecuredStorageResetAllFragment::class)
- fun bindSharedSecuredStorageResetAllFragment(fragment: SharedSecuredStorageResetAllFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(SetIdentityServerFragment::class)
- fun bindSetIdentityServerFragment(fragment: SetIdentityServerFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(DiscoverySettingsFragment::class)
- fun bindDiscoverySettingsFragment(fragment: DiscoverySettingsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LegalsFragment::class)
- fun bindLegalsFragment(fragment: LegalsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(ReviewTermsFragment::class)
- fun bindReviewTermsFragment(fragment: ReviewTermsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(WidgetFragment::class)
- fun bindWidgetFragment(fragment: WidgetFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(ContactsBookFragment::class)
- fun bindPhoneBookFragment(fragment: ContactsBookFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(PinFragment::class)
- fun bindPinFragment(fragment: PinFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomBannedMemberListFragment::class)
- fun bindRoomBannedMemberListFragment(fragment: RoomBannedMemberListFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomNotificationSettingsFragment::class)
- fun bindRoomNotificationSettingsFragment(fragment: RoomNotificationSettingsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(SearchFragment::class)
- fun bindSearchFragment(fragment: SearchFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(ShowUserCodeFragment::class)
- fun bindShowUserCodeFragment(fragment: ShowUserCodeFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomDevToolFragment::class)
- fun bindRoomDevToolFragment(fragment: RoomDevToolFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomDevToolStateEventListFragment::class)
- fun bindRoomDevToolStateEventListFragment(fragment: RoomDevToolStateEventListFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomDevToolEditFragment::class)
- fun bindRoomDevToolEditFragment(fragment: RoomDevToolEditFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomDevToolSendFormFragment::class)
- fun bindRoomDevToolSendFormFragment(fragment: RoomDevToolSendFormFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(SpacePreviewFragment::class)
- fun bindSpacePreviewFragment(fragment: SpacePreviewFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(ChooseSpaceTypeFragment::class)
- fun bindChooseSpaceTypeFragment(fragment: ChooseSpaceTypeFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(CreateSpaceDetailsFragment::class)
- fun bindCreateSpaceDetailsFragment(fragment: CreateSpaceDetailsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(CreateSpaceDefaultRoomsFragment::class)
- fun bindCreateSpaceDefaultRoomsFragment(fragment: CreateSpaceDefaultRoomsFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(MatrixToUserFragment::class)
- fun bindMatrixToUserFragment(fragment: MatrixToUserFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(MatrixToRoomSpaceFragment::class)
- fun bindMatrixToRoomSpaceFragment(fragment: MatrixToRoomSpaceFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(SpaceDirectoryFragment::class)
- fun bindSpaceDirectoryFragment(fragment: SpaceDirectoryFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(ChoosePrivateSpaceTypeFragment::class)
- fun bindChoosePrivateSpaceTypeFragment(fragment: ChoosePrivateSpaceTypeFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(CreateSpaceAdd3pidInvitesFragment::class)
- fun bindCreateSpaceAdd3pidInvitesFragment(fragment: CreateSpaceAdd3pidInvitesFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(SpaceAddRoomFragment::class)
- fun bindSpaceAddRoomFragment(fragment: SpaceAddRoomFragment): Fragment
-
- @Binds
- @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
-
- @Binds
- @IntoMap
- @FragmentKey(RoomJoinRuleFragment::class)
- fun bindRoomJoinRuleFragment(fragment: RoomJoinRuleFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(RoomJoinRuleChooseRestrictedFragment::class)
- fun bindRoomJoinRuleChooseRestrictedFragment(fragment: RoomJoinRuleChooseRestrictedFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(SpaceLeaveAdvancedFragment::class)
- fun bindSpaceLeaveAdvancedFragment(fragment: SpaceLeaveAdvancedFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(ThreadListFragment::class)
- fun bindThreadListFragment(fragment: ThreadListFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(CreatePollFragment::class)
- fun bindCreatePollFragment(fragment: CreatePollFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LocationSharingFragment::class)
- fun bindLocationSharingFragment(fragment: LocationSharingFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(LocationPreviewFragment::class)
- fun bindLocationPreviewFragment(fragment: LocationPreviewFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(HomeRoomListFragment::class)
- fun binHomeRoomListFragment(fragment: HomeRoomListFragment): Fragment
-}
diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
index 331b4afa18..b21b4778e3 100644
--- a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
+++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
@@ -52,14 +52,13 @@ import im.vector.app.features.home.room.detail.timeline.reactions.ViewReactionsV
import im.vector.app.features.home.room.detail.upgrade.MigrateRoomViewModel
import im.vector.app.features.home.room.list.RoomListViewModel
import im.vector.app.features.home.room.list.home.HomeRoomListViewModel
+import im.vector.app.features.home.room.list.home.invites.InvitesViewModel
import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel
import im.vector.app.features.invite.InviteUsersToRoomViewModel
import im.vector.app.features.location.LocationSharingViewModel
import im.vector.app.features.location.live.map.LiveLocationMapViewModel
import im.vector.app.features.location.preview.LocationPreviewViewModel
import im.vector.app.features.login.LoginViewModel
-import im.vector.app.features.login2.LoginViewModel2
-import im.vector.app.features.login2.created.AccountCreatedViewModel
import im.vector.app.features.matrixto.MatrixToBottomSheetViewModel
import im.vector.app.features.media.VectorAttachmentViewerViewModel
import im.vector.app.features.onboarding.OnboardingViewModel
@@ -456,21 +455,11 @@ interface MavericksViewModelModule {
@MavericksViewModelKey(MatrixToBottomSheetViewModel::class)
fun matrixToBottomSheetViewModelFactory(factory: MatrixToBottomSheetViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
- @Binds
- @IntoMap
- @MavericksViewModelKey(AccountCreatedViewModel::class)
- fun accountCreatedViewModelFactory(factory: AccountCreatedViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
-
@Binds
@IntoMap
@MavericksViewModelKey(OnboardingViewModel::class)
fun onboardingViewModelFactory(factory: OnboardingViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
- @Binds
- @IntoMap
- @MavericksViewModelKey(LoginViewModel2::class)
- fun loginViewModel2Factory(factory: LoginViewModel2.Factory): MavericksAssistedViewModelFactory<*, *>
-
@Binds
@IntoMap
@MavericksViewModelKey(LoginViewModel::class)
@@ -630,4 +619,9 @@ interface MavericksViewModelModule {
@IntoMap
@MavericksViewModelKey(HomeRoomListViewModel::class)
fun homeRoomListViewModel(factory: HomeRoomListViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+ @Binds
+ @IntoMap
+ @MavericksViewModelKey(InvitesViewModel::class)
+ fun invitesViewModel(factory: InvitesViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
}
diff --git a/vector/src/main/java/im/vector/app/core/di/VectorFragmentFactory.kt b/vector/src/main/java/im/vector/app/core/di/VectorFragmentFactory.kt
deleted file mode 100644
index f761d99114..0000000000
--- a/vector/src/main/java/im/vector/app/core/di/VectorFragmentFactory.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.di
-
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentFactory
-import timber.log.Timber
-import javax.inject.Inject
-import javax.inject.Provider
-
-/**
- * FragmentFactory which uses Dagger to create the instances.
- */
-class VectorFragmentFactory @Inject constructor(
- private val creators: @JvmSuppressWildcards Map, Provider>
-) : FragmentFactory() {
-
- override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
- val fragmentClass = loadFragmentClass(classLoader, className)
- val creator: Provider? = creators[fragmentClass]
- return if (creator == null) {
- Timber.v("Unknown model class: $className, fallback to default instance")
- super.instantiate(classLoader, className)
- } else {
- creator.get()
- }
- }
-}
diff --git a/vector/src/main/java/im/vector/app/core/di/ViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/ViewModelModule.kt
index d90e934d0a..c08f939524 100644
--- a/vector/src/main/java/im/vector/app/core/di/ViewModelModule.kt
+++ b/vector/src/main/java/im/vector/app/core/di/ViewModelModule.kt
@@ -34,6 +34,7 @@ import im.vector.app.features.home.HomeSharedActionViewModel
import im.vector.app.features.home.room.detail.RoomDetailSharedActionViewModel
import im.vector.app.features.home.room.detail.timeline.action.MessageSharedActionViewModel
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
+import im.vector.app.features.home.room.list.actions.RoomListSharedActionViewModel
import im.vector.app.features.reactions.EmojiChooserViewModel
import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel
import im.vector.app.features.roomprofile.RoomProfileSharedActionViewModel
@@ -157,4 +158,9 @@ interface ViewModelModule {
@IntoMap
@ViewModelKey(SpacePeopleSharedActionViewModel::class)
fun bindSpacePeopleSharedActionViewModel(viewModel: SpacePeopleSharedActionViewModel): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(RoomListSharedActionViewModel::class)
+ fun bindRoomListSharedActionViewModel(viewModel: RoomListSharedActionViewModel): ViewModel
}
diff --git a/vector/src/main/java/im/vector/app/core/dialogs/GalleryOrCameraDialogHelperFactory.kt b/vector/src/main/java/im/vector/app/core/dialogs/GalleryOrCameraDialogHelperFactory.kt
new file mode 100644
index 0000000000..0e8dc1d0d1
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/dialogs/GalleryOrCameraDialogHelperFactory.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.core.dialogs
+
+import androidx.fragment.app.Fragment
+import im.vector.app.core.resources.ColorProvider
+import im.vector.app.core.time.Clock
+import javax.inject.Inject
+
+/**
+ * Factory for [GalleryOrCameraDialogHelper].
+ */
+class GalleryOrCameraDialogHelperFactory @Inject constructor(
+ private val colorProvider: ColorProvider,
+ private val clock: Clock,
+) {
+ fun create(fragment: Fragment): GalleryOrCameraDialogHelper {
+ return GalleryOrCameraDialogHelper(fragment, colorProvider, clock)
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt b/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt
index 61c4fe2174..f3aef54062 100644
--- a/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt
+++ b/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt
@@ -175,7 +175,7 @@ fun Fragment.queryExportKeys(userId: String, activityResultLauncher: ActivityRes
selectTxtFileToWrite(
activity = requireActivity(),
activityResultLauncher = activityResultLauncher,
- defaultFileName = "$appName-megolm-export-$userId-$timestamp.txt",
+ defaultFileName = "$appName-megolm-export-$userId-${timestamp}.txt",
chooserHint = getString(R.string.keys_backup_setup_step1_manual_export)
)
}
@@ -187,7 +187,7 @@ fun Activity.queryExportKeys(userId: String, activityResultLauncher: ActivityRes
selectTxtFileToWrite(
activity = this,
activityResultLauncher = activityResultLauncher,
- defaultFileName = "$appName-megolm-export-$userId-$timestamp.txt",
+ defaultFileName = "$appName-megolm-export-$userId-${timestamp}.txt",
chooserHint = getString(R.string.keys_backup_setup_step1_manual_export)
)
}
diff --git a/vector/src/main/java/im/vector/app/core/extensions/Session.kt b/vector/src/main/java/im/vector/app/core/extensions/Session.kt
index caed413e2b..cb1d46efce 100644
--- a/vector/src/main/java/im/vector/app/core/extensions/Session.kt
+++ b/vector/src/main/java/im/vector/app/core/extensions/Session.kt
@@ -28,7 +28,7 @@ import org.matrix.android.sdk.api.session.sync.FilterService
import timber.log.Timber
fun Session.configureAndStart(context: Context, startSyncing: Boolean = true) {
- Timber.i("Configure and start session for $myUserId")
+ Timber.i("Configure and start session for $myUserId. startSyncing: $startSyncing")
open()
filterService().setFilter(FilterService.FilterPreset.ElementFilter)
if (startSyncing) {
diff --git a/vector/src/main/java/im/vector/app/core/extensions/Throwable.kt b/vector/src/main/java/im/vector/app/core/extensions/Throwable.kt
new file mode 100644
index 0000000000..0aa9039dcb
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/extensions/Throwable.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.core.extensions
+
+/**
+ * Recursive through the throwable and its causes for the given predicate.
+ *
+ * @return true when the predicate finds a match.
+ */
+tailrec fun Throwable?.crawlCausesFor(predicate: (Throwable) -> Boolean): Boolean {
+ return when {
+ this == null -> false
+ else -> {
+ when (predicate(this)) {
+ true -> true
+ else -> this.cause.crawlCausesFor(predicate)
+ }
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt
index 24a65e1071..4e7b174772 100644
--- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt
+++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt
@@ -21,7 +21,6 @@ import android.app.Activity
import android.content.Context
import android.os.Build
import android.os.Bundle
-import android.os.Parcelable
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
@@ -39,8 +38,6 @@ import androidx.core.content.ContextCompat
import androidx.core.util.Consumer
import androidx.core.view.MenuProvider
import androidx.core.view.isVisible
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentFactory
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
@@ -67,7 +64,6 @@ import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.extensions.restart
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.core.extensions.singletonEntryPoint
-import im.vector.app.core.extensions.toMvRxBundle
import im.vector.app.core.resources.BuildMeta
import im.vector.app.core.utils.AndroidSystemSettingsProvider
import im.vector.app.core.utils.ToolbarConfig
@@ -169,7 +165,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver
lateinit var navigator: Navigator
private set
- private lateinit var fragmentFactory: FragmentFactory
private lateinit var activeSessionHolder: ActiveSessionHolder
private lateinit var vectorPreferences: VectorPreferences
@@ -210,8 +205,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver
val singletonEntryPoint = singletonEntryPoint()
val activityEntryPoint = EntryPointAccessors.fromActivity(this, ActivityEntryPoint::class.java)
ThemeUtils.setActivityTheme(this, getOtherThemes())
- fragmentFactory = activityEntryPoint.fragmentFactory()
- supportFragmentManager.fragmentFactory = fragmentFactory
viewModelFactory = activityEntryPoint.viewModelFactory()
super.onCreate(savedInstanceState)
addOnMultiWindowModeChangedListener(onMultiWindowModeChangedListener)
@@ -464,12 +457,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver
bugReporter.inMultiWindowMode = it.isInMultiWindowMode
}
- protected fun createFragment(fragmentClass: Class, argsParcelable: Parcelable? = null): Fragment {
- return fragmentFactory.instantiate(classLoader, fragmentClass.name).apply {
- arguments = argsParcelable?.toMvRxBundle()
- }
- }
-
/* ==========================================================================================
* PRIVATE METHODS
* ========================================================================================== */
diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt
index 340c906a6d..8fe2d33f6a 100644
--- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt
+++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt
@@ -123,7 +123,6 @@ abstract class VectorBaseFragment : Fragment(), MavericksView
analyticsTracker = singletonEntryPoint.analyticsTracker()
unrecognizedCertificateDialog = singletonEntryPoint.unrecognizedCertificateDialog()
viewModelFactory = activityEntryPoint.viewModelFactory()
- childFragmentManager.fragmentFactory = activityEntryPoint.fragmentFactory()
super.onAttach(context)
}
diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt
index 1f44ab3686..0993485471 100644
--- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt
+++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt
@@ -92,8 +92,6 @@ class UnifiedPushHelper @Inject constructor(
return@launch
}
- // By default, use internal solution (fcm/background sync)
- UnifiedPush.saveDistributor(context, context.packageName)
val distributors = UnifiedPush.getDistributors(context)
if (distributors.size == 1 && !force) {
@@ -101,7 +99,14 @@ class UnifiedPushHelper @Inject constructor(
UnifiedPush.registerApp(context)
onDoneRunnable?.run()
} else {
- openDistributorDialogInternal(activity, pushersManager, onDoneRunnable, distributors, !force, !force)
+ openDistributorDialogInternal(
+ activity = activity,
+ pushersManager = pushersManager,
+ onDoneRunnable = onDoneRunnable,
+ distributors = distributors,
+ unregisterFirst = force,
+ cancellable = !force
+ )
}
}
}
@@ -165,6 +170,12 @@ class UnifiedPushHelper @Inject constructor(
onDoneRunnable?.run()
}
}
+ .setOnCancelListener {
+ // By default, use internal solution (fcm/background sync)
+ UnifiedPush.saveDistributor(context, context.packageName)
+ UnifiedPush.registerApp(context)
+ onDoneRunnable?.run()
+ }
.setCancelable(cancellable)
.show()
}
diff --git a/vector/src/main/java/im/vector/app/features/MainActivity.kt b/vector/src/main/java/im/vector/app/features/MainActivity.kt
index 14fae80325..e1e7764f19 100644
--- a/vector/src/main/java/im/vector/app/features/MainActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/MainActivity.kt
@@ -38,6 +38,7 @@ import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.utils.deleteAllFiles
import im.vector.app.databinding.ActivityMainBinding
import im.vector.app.features.analytics.VectorAnalytics
+import im.vector.app.features.analytics.plan.ViewRoom
import im.vector.app.features.home.HomeActivity
import im.vector.app.features.home.ShortcutsHandler
import im.vector.app.features.notifications.NotificationDrawerManager
@@ -186,8 +187,7 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity
} else if (intent.action == ACTION_ROOM_DETAILS_FROM_SHORTCUT) {
val roomId = intent.getStringExtra(EXTRA_ROOM_ID)
if (roomId?.isNotEmpty() == true) {
- // TODO Add a trigger Shortcut to the analytics.
- navigator.openRoom(this, roomId)
+ navigator.openRoom(this, roomId, trigger = ViewRoom.Trigger.Shortcut)
}
finish()
} else {
diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt
index deb9088259..6336faa74c 100644
--- a/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt
+++ b/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt
@@ -117,6 +117,12 @@ data class Interaction(
*/
WebLeftPanelExploreRoomsButton,
+ /**
+ * User clicked on the avatar uploader in the profile settings of
+ * Element Web/Desktop.
+ */
+ WebProfileSettingsAvatarUploadButton,
+
/**
* User interacted with pin to sidebar checkboxes in the quick settings
* menu of Element Web/Desktop.
@@ -279,6 +285,18 @@ data class Interaction(
*/
WebRoomListRoomsSublistPlusMenuExploreRoomsItem,
+ /**
+ * User clicked on the button to return to the user onboarding list in
+ * the room list in Element Web/Desktop.
+ */
+ WebRoomListUserOnboardingButton,
+
+ /**
+ * User clicked on the button to close the user onboarding button in the
+ * room list in Element Web/Desktop.
+ */
+ WebRoomListUserOnboardingIgnoreButton,
+
/**
* User interacted with leave action in the general tab of the room
* settings dialog in Element Web/Desktop.
@@ -349,6 +367,36 @@ data class Interaction(
* Web/Desktop.
*/
WebUserMenuThemeToggleButton,
+
+ /**
+ * User clicked on the send DM CTA in the header of the new user
+ * onboarding page in Element Web/Desktop.
+ */
+ WebUserOnboardingHeaderSendDm,
+
+ /**
+ * User clicked on the action of the download apps task on the new user
+ * onboarding page in Element Web/Desktop.
+ */
+ WebUserOnboardingTaskDownloadApps,
+
+ /**
+ * User clicked on the action of the enable notifications task on the
+ * new user onboarding page in Element Web/Desktop.
+ */
+ WebUserOnboardingTaskEnableNotifications,
+
+ /**
+ * User clicked on the action of the find people task on the new user
+ * onboarding page in Element Web/Desktop.
+ */
+ WebUserOnboardingTaskSendDm,
+
+ /**
+ * User clicked on the action of the your profile task on the new user
+ * onboarding page in Element Web/Desktop.
+ */
+ WebUserOnboardingTaskSetupProfile,
}
enum class InteractionType {
diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/PermissionChanged.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/PermissionChanged.kt
new file mode 100644
index 0000000000..9f463a4107
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/analytics/plan/PermissionChanged.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.features.analytics.plan
+
+import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
+
+// GENERATED FILE, DO NOT EDIT. FOR MORE INFORMATION VISIT
+// https://github.com/matrix-org/matrix-analytics-events/
+
+/**
+ * Triggered when the user changes a permission status.
+ */
+data class PermissionChanged(
+ /**
+ * Whether the permission has been granted by the user.
+ */
+ val granted: Boolean,
+ /**
+ * The name of the permission.
+ */
+ val permission: Permission,
+) : VectorAnalyticsEvent {
+
+ enum class Permission {
+ /**
+ * Permissions related to sending notifications have changed.
+ */
+ Notification,
+ }
+
+ override fun getName() = "PermissionChanged"
+
+ override fun getProperties(): Map? {
+ return mutableMapOf().apply {
+ put("granted", granted)
+ put("permission", permission.name)
+ }.takeIf { it.isNotEmpty() }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/ViewRoom.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/ViewRoom.kt
index d2f30eec9b..f6a724304b 100644
--- a/vector/src/main/java/im/vector/app/features/analytics/plan/ViewRoom.kt
+++ b/vector/src/main/java/im/vector/app/features/analytics/plan/ViewRoom.kt
@@ -152,6 +152,11 @@ data class ViewRoom(
*/
RoomList,
+ /**
+ * Room accessed via a shortcut.
+ */
+ Shortcut,
+
/**
* Room accessed via a slash command in Element Web/Desktop like /goto.
*/
diff --git a/vector/src/main/java/im/vector/app/features/analytics/ui/consent/AnalyticsOptInFragment.kt b/vector/src/main/java/im/vector/app/features/analytics/ui/consent/AnalyticsOptInFragment.kt
index a5bafa2ee6..fbeeab9ec3 100644
--- a/vector/src/main/java/im/vector/app/features/analytics/ui/consent/AnalyticsOptInFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/analytics/ui/consent/AnalyticsOptInFragment.kt
@@ -21,6 +21,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.activityViewModel
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.setTextWithColoredPart
import im.vector.app.core.platform.OnBackPressed
@@ -30,9 +31,12 @@ import im.vector.app.databinding.FragmentAnalyticsOptinBinding
import im.vector.app.features.analytics.AnalyticsConfig
import javax.inject.Inject
-class AnalyticsOptInFragment @Inject constructor(
- private val analyticsConfig: AnalyticsConfig,
-) : VectorBaseFragment(), OnBackPressed {
+@AndroidEntryPoint
+class AnalyticsOptInFragment :
+ VectorBaseFragment(),
+ OnBackPressed {
+
+ @Inject lateinit var analyticsConfig: AnalyticsConfig
// Share the view model with the Activity so that the Activity
// can decide what to do when the data has been saved
diff --git a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt
index c3a4ae7df2..47b19a435e 100644
--- a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt
@@ -39,6 +39,7 @@ import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import com.yalantis.ucrop.UCrop
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.insertBeforeLast
@@ -63,15 +64,17 @@ data class AttachmentsPreviewArgs(
val attachments: List
) : Parcelable
-class AttachmentsPreviewFragment @Inject constructor(
- private val attachmentMiniaturePreviewController: AttachmentMiniaturePreviewController,
- private val attachmentBigPreviewController: AttachmentBigPreviewController,
- private val colorProvider: ColorProvider,
- private val clock: Clock,
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class AttachmentsPreviewFragment :
+ VectorBaseFragment(),
AttachmentMiniaturePreviewController.Callback,
VectorMenuProvider {
+ @Inject lateinit var attachmentMiniaturePreviewController: AttachmentMiniaturePreviewController
+ @Inject lateinit var attachmentBigPreviewController: AttachmentBigPreviewController
+ @Inject lateinit var colorProvider: ColorProvider
+ @Inject lateinit var clock: Clock
+
private val fragmentArgs: AttachmentsPreviewArgs by args()
private val viewModel: AttachmentsPreviewViewModel by fragmentViewModel()
diff --git a/vector/src/main/java/im/vector/app/features/call/dialpad/PstnDialActivity.kt b/vector/src/main/java/im/vector/app/features/call/dialpad/PstnDialActivity.kt
new file mode 100644
index 0000000000..a0d6e29849
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/call/dialpad/PstnDialActivity.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.call.dialpad
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatDialog
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.lifecycleScope
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.R
+import im.vector.app.core.error.ErrorFormatter
+import im.vector.app.core.extensions.addFragment
+import im.vector.app.core.platform.SimpleFragmentActivity
+import im.vector.app.features.call.webrtc.WebRtcCallManager
+import im.vector.app.features.createdirect.DirectRoomHelper
+import im.vector.app.features.settings.VectorLocale
+import im.vector.lib.ui.styles.dialogs.MaterialProgressDialog
+import kotlinx.coroutines.launch
+import org.matrix.android.sdk.api.session.Session
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class PstnDialActivity : SimpleFragmentActivity() {
+
+ @Inject lateinit var callManager: WebRtcCallManager
+ @Inject lateinit var directRoomHelper: DirectRoomHelper
+ @Inject lateinit var session: Session
+ @Inject lateinit var errorFormatter: ErrorFormatter
+
+ private var progress: AppCompatDialog? = null
+
+ override fun getTitleRes(): Int = R.string.call
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (isFirstCreation()) {
+ addFragment(
+ views.container,
+ createDialPadFragment()
+ )
+ }
+ }
+
+ private fun handleStartCallWithPhoneNumber(rawNumber: String) {
+ lifecycleScope.launch {
+ try {
+ showLoadingDialog()
+ val result = DialPadLookup(session, callManager, directRoomHelper).lookupPhoneNumber(rawNumber)
+ callManager.startOutgoingCall(result.roomId, result.userId, isVideoCall = false)
+ dismissLoadingDialog()
+ finish()
+ } catch (failure: Throwable) {
+ dismissLoadingDialog()
+ displayErrorDialog(failure)
+ }
+ }
+ }
+
+ private fun createDialPadFragment(): Fragment {
+ val fragment = supportFragmentManager.fragmentFactory.instantiate(classLoader, DialPadFragment::class.java.name)
+ return (fragment as DialPadFragment).apply {
+ arguments = Bundle().apply {
+ putBoolean(DialPadFragment.EXTRA_ENABLE_DELETE, true)
+ putBoolean(DialPadFragment.EXTRA_ENABLE_OK, true)
+ putString(DialPadFragment.EXTRA_REGION_CODE, VectorLocale.applicationLocale.country)
+ }
+ callback = object : DialPadFragment.Callback {
+ override fun onOkClicked(formatted: String?, raw: String?) {
+ if (raw.isNullOrEmpty()) return
+ handleStartCallWithPhoneNumber(raw)
+ }
+ }
+ }
+ }
+
+ private fun showLoadingDialog() {
+ progress?.dismiss()
+ progress = MaterialProgressDialog(this)
+ .show(getString(R.string.please_wait))
+ }
+
+ private fun dismissLoadingDialog() {
+ progress?.dismiss()
+ }
+
+ private fun displayErrorDialog(throwable: Throwable) {
+ MaterialAlertDialogBuilder(this)
+ .setTitle(R.string.dialog_title_error)
+ .setMessage(errorFormatter.toHumanReadable(throwable))
+ .setPositiveButton(R.string.ok, null)
+ .show()
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookFragment.kt b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookFragment.kt
index 8cd7f2de45..4677dce7d6 100644
--- a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookFragment.kt
@@ -24,6 +24,7 @@ import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.extensions.hideKeyboard
@@ -44,9 +45,12 @@ import reactivecircus.flowbinding.android.widget.checkedChanges
import reactivecircus.flowbinding.android.widget.textChanges
import javax.inject.Inject
-class ContactsBookFragment @Inject constructor(
- private val contactsBookController: ContactsBookController
-) : VectorBaseFragment(), ContactsBookController.Callback {
+@AndroidEntryPoint
+class ContactsBookFragment :
+ VectorBaseFragment(),
+ ContactsBookController.Callback {
+
+ @Inject lateinit var contactsBookController: ContactsBookController
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentContactsBookBinding {
return FragmentContactsBookBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt
index b306cb6e03..36ee47ca06 100644
--- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt
@@ -132,10 +132,10 @@ class CreateDirectRoomViewModel @AssistedInject constructor(
if (vectorFeatures.shouldStartDmOnFirstMessage()) {
session.roomService().createLocalRoom(roomParams)
} else {
+ analyticsTracker.capture(CreatedRoom(isDM = roomParams.isDirect.orFalse()))
session.roomService().createRoom(roomParams)
}
}
- analyticsTracker.capture(CreatedRoom(isDM = roomParams.isDirect.orFalse()))
setState {
copy(
diff --git a/vector/src/main/java/im/vector/app/features/createdirect/DirectRoomHelper.kt b/vector/src/main/java/im/vector/app/features/createdirect/DirectRoomHelper.kt
index de2027f2a5..c2cc13920f 100644
--- a/vector/src/main/java/im/vector/app/features/createdirect/DirectRoomHelper.kt
+++ b/vector/src/main/java/im/vector/app/features/createdirect/DirectRoomHelper.kt
@@ -16,6 +16,7 @@
package im.vector.app.features.createdirect
+import im.vector.app.features.VectorFeatures
import im.vector.app.features.analytics.AnalyticsTracker
import im.vector.app.features.analytics.plan.CreatedRoom
import im.vector.app.features.raw.wellknown.getElementWellknown
@@ -30,7 +31,8 @@ import javax.inject.Inject
class DirectRoomHelper @Inject constructor(
private val rawService: RawService,
private val session: Session,
- private val analyticsTracker: AnalyticsTracker
+ private val analyticsTracker: AnalyticsTracker,
+ private val vectorFeatures: VectorFeatures,
) {
suspend fun ensureDMExists(userId: String): String {
@@ -48,8 +50,12 @@ class DirectRoomHelper @Inject constructor(
setDirectMessage()
enableEncryptionIfInvitedUsersSupportIt = adminE2EByDefault
}
- roomId = session.roomService().createRoom(roomParams)
- analyticsTracker.capture(CreatedRoom(isDM = roomParams.isDirect.orFalse()))
+ roomId = if (vectorFeatures.shouldStartDmOnFirstMessage()) {
+ session.roomService().createLocalRoom(roomParams)
+ } else {
+ analyticsTracker.capture(CreatedRoom(isDM = roomParams.isDirect.orFalse()))
+ session.roomService().createRoom(roomParams)
+ }
}
return roomId
}
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt
index 42605a850b..9a3d37eed7 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt
@@ -22,15 +22,16 @@ import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import androidx.core.widget.doOnTextChanged
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.startImportTextFromFileIntent
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import org.matrix.android.sdk.api.extensions.tryOrNull
-import javax.inject.Inject
-class KeysBackupRestoreFromKeyFragment @Inject constructor() :
+@AndroidEntryPoint
+class KeysBackupRestoreFromKeyFragment :
VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupRestoreFromKeyBinding {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt
index 631bc9ff4f..cf98bc7e4d 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt
@@ -24,12 +24,14 @@ import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import androidx.core.text.set
import androidx.core.widget.doOnTextChanged
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentKeysBackupRestoreFromPassphraseBinding
-import javax.inject.Inject
-class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBaseFragment() {
+@AndroidEntryPoint
+class KeysBackupRestoreFromPassphraseFragment :
+ VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupRestoreFromPassphraseBinding {
return FragmentKeysBackupRestoreFromPassphraseBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt
index d26c1e2134..4a1bc49e27 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt
@@ -20,13 +20,15 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.LiveEvent
import im.vector.app.databinding.FragmentKeysBackupRestoreSuccessBinding
-import javax.inject.Inject
-class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragment() {
+@AndroidEntryPoint
+class KeysBackupRestoreSuccessFragment :
+ VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupRestoreSuccessBinding {
return FragmentKeysBackupRestoreSuccessBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt
index edc44fa796..c0001501d5 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt
@@ -22,6 +22,7 @@ import android.view.ViewGroup
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
@@ -30,10 +31,13 @@ import im.vector.app.databinding.FragmentKeysBackupSettingsBinding
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity
import javax.inject.Inject
-class KeysBackupSettingsFragment @Inject constructor(private val keysBackupSettingsRecyclerViewController: KeysBackupSettingsRecyclerViewController) :
+@AndroidEntryPoint
+class KeysBackupSettingsFragment :
VectorBaseFragment(),
KeysBackupSettingsRecyclerViewController.Listener {
+ @Inject lateinit var keysBackupSettingsRecyclerViewController: KeysBackupSettingsRecyclerViewController
+
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSettingsBinding {
return FragmentKeysBackupSettingsBinding.inflate(inflater, container, false)
}
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt
index 7d8feba942..9b8386c741 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt
@@ -20,12 +20,14 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.LiveEvent
import im.vector.app.databinding.FragmentKeysBackupSetupStep1Binding
-import javax.inject.Inject
-class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment() {
+@AndroidEntryPoint
+class KeysBackupSetupStep1Fragment :
+ VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSetupStep1Binding {
return FragmentKeysBackupSetupStep1Binding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt
index 706076dae0..cf92afcc2e 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt
@@ -24,6 +24,7 @@ import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.viewModelScope
import androidx.transition.TransitionManager
import com.nulabinc.zxcvbn.Zxcvbn
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.hidePassword
import im.vector.app.core.platform.VectorBaseFragment
@@ -31,9 +32,10 @@ import im.vector.app.databinding.FragmentKeysBackupSetupStep2Binding
import im.vector.app.features.settings.VectorLocale
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import javax.inject.Inject
-class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment() {
+@AndroidEntryPoint
+class KeysBackupSetupStep2Fragment :
+ VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSetupStep2Binding {
return FragmentKeysBackupSetupStep2Binding.inflate(inflater, container, false)
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 b8b84ea322..7e0fb7e417 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
@@ -28,6 +28,7 @@ import androidx.lifecycle.lifecycleScope
import arrow.core.Try
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.extensions.safeOpenOutputStream
@@ -44,9 +45,10 @@ import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
-import javax.inject.Inject
-class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() {
+@AndroidEntryPoint
+class KeysBackupSetupStep3Fragment :
+ VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSetupStep3Binding {
return FragmentKeysBackupSetupStep3Binding.inflate(inflater, container, false)
@@ -134,7 +136,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() {
+@AndroidEntryPoint
+class SharedSecuredStorageKeyFragment :
+ VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSsssAccessFromKeyBinding {
return FragmentSsssAccessFromKeyBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt
index 5af5480573..877e4aa164 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt
@@ -24,20 +24,19 @@ import android.view.inputmethod.EditorInfo
import androidx.core.text.toSpannable
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.activityViewModel
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseFragment
-import im.vector.app.core.resources.ColorProvider
import im.vector.app.databinding.FragmentSsssAccessFromPassphraseBinding
import im.vector.lib.core.utils.flow.throttleFirst
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.widget.editorActionEvents
import reactivecircus.flowbinding.android.widget.textChanges
-import javax.inject.Inject
-class SharedSecuredStoragePassphraseFragment @Inject constructor(
- private val colorProvider: ColorProvider
-) : VectorBaseFragment() {
+@AndroidEntryPoint
+class SharedSecuredStoragePassphraseFragment :
+ VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSsssAccessFromPassphraseBinding {
return FragmentSsssAccessFromPassphraseBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageResetAllFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageResetAllFragment.kt
index c0d0aa8e76..66344107a4 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageResetAllFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageResetAllFragment.kt
@@ -22,14 +22,15 @@ import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentSsssResetAllBinding
import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet
-import javax.inject.Inject
-class SharedSecuredStorageResetAllFragment @Inject constructor() :
+@AndroidEntryPoint
+class SharedSecuredStorageResetAllFragment :
VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSsssResetAllBinding {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConclusionFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConclusionFragment.kt
index 555f2d7c1c..22ecd3dafd 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConclusionFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConclusionFragment.kt
@@ -23,6 +23,7 @@ import android.view.ViewGroup
import androidx.core.text.toSpannable
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.resources.ColorProvider
@@ -30,9 +31,11 @@ import im.vector.app.core.utils.colorizeMatchingText
import im.vector.app.databinding.FragmentBootstrapConclusionBinding
import javax.inject.Inject
-class BootstrapConclusionFragment @Inject constructor(
- private val colorProvider: ColorProvider
-) : VectorBaseFragment() {
+@AndroidEntryPoint
+class BootstrapConclusionFragment :
+ VectorBaseFragment() {
+
+ @Inject lateinit var colorProvider: ColorProvider
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapConclusionBinding {
return FragmentBootstrapConclusionBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt
index 3c8137d087..285721ee75 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt
@@ -25,6 +25,7 @@ import androidx.core.view.isGone
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.platform.VectorBaseFragment
@@ -34,9 +35,9 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.widget.editorActionEvents
import reactivecircus.flowbinding.android.widget.textChanges
-import javax.inject.Inject
-class BootstrapConfirmPassphraseFragment @Inject constructor() :
+@AndroidEntryPoint
+class BootstrapConfirmPassphraseFragment :
VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapEnterPassphraseBinding {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapEnterPassphraseFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapEnterPassphraseFragment.kt
index ff6d109b3c..43cc25f195 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapEnterPassphraseFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapEnterPassphraseFragment.kt
@@ -24,6 +24,7 @@ import android.view.inputmethod.EditorInfo
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentBootstrapEnterPassphraseBinding
@@ -33,9 +34,9 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.widget.editorActionEvents
import reactivecircus.flowbinding.android.widget.textChanges
-import javax.inject.Inject
-class BootstrapEnterPassphraseFragment @Inject constructor() :
+@AndroidEntryPoint
+class BootstrapEnterPassphraseFragment :
VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapEnterPassphraseBinding {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapMigrateBackupFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapMigrateBackupFragment.kt
index 2c0ccec9fb..2802c872ee 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapMigrateBackupFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapMigrateBackupFragment.kt
@@ -30,6 +30,7 @@ import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.extensions.registerStartForActivityResult
@@ -47,9 +48,11 @@ import reactivecircus.flowbinding.android.widget.editorActionEvents
import reactivecircus.flowbinding.android.widget.textChanges
import javax.inject.Inject
-class BootstrapMigrateBackupFragment @Inject constructor(
- private val colorProvider: ColorProvider
-) : VectorBaseFragment() {
+@AndroidEntryPoint
+class BootstrapMigrateBackupFragment :
+ VectorBaseFragment() {
+
+ @Inject lateinit var colorProvider: ColorProvider
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapMigrateBackupBinding {
return FragmentBootstrapMigrateBackupBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapReAuthFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapReAuthFragment.kt
index c46ccbf08e..d5e60631a5 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapReAuthFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapReAuthFragment.kt
@@ -23,15 +23,14 @@ import android.view.ViewGroup
import androidx.core.view.isVisible
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.core.platform.VectorBaseFragment
-import im.vector.app.core.resources.ColorProvider
import im.vector.app.databinding.FragmentBootstrapReauthBinding
-import javax.inject.Inject
-class BootstrapReAuthFragment @Inject constructor(
- private val colorProvider: ColorProvider
-) : VectorBaseFragment() {
+@AndroidEntryPoint
+class BootstrapReAuthFragment :
+ VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapReauthBinding {
return FragmentBootstrapReauthBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSaveRecoveryKeyFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSaveRecoveryKeyFragment.kt
index db24807c1b..21d68dfe99 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSaveRecoveryKeyFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSaveRecoveryKeyFragment.kt
@@ -27,21 +27,20 @@ import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.extensions.safeOpenOutputStream
import im.vector.app.core.platform.VectorBaseFragment
-import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.utils.startSharePlainTextIntent
import im.vector.app.core.utils.toast
import im.vector.app.databinding.FragmentBootstrapSaveKeyBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import javax.inject.Inject
-class BootstrapSaveRecoveryKeyFragment @Inject constructor(
- private val colorProvider: ColorProvider
-) : VectorBaseFragment() {
+@AndroidEntryPoint
+class BootstrapSaveRecoveryKeyFragment :
+ VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapSaveKeyBinding {
return FragmentBootstrapSaveKeyBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSetupRecoveryKeyFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSetupRecoveryKeyFragment.kt
index 3d078a82ed..b03cbe87a8 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSetupRecoveryKeyFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSetupRecoveryKeyFragment.kt
@@ -23,13 +23,14 @@ import android.view.ViewGroup
import androidx.core.view.isVisible
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentBootstrapSetupRecoveryBinding
import im.vector.app.features.raw.wellknown.SecureBackupMethod
-import javax.inject.Inject
-class BootstrapSetupRecoveryKeyFragment @Inject constructor() :
+@AndroidEntryPoint
+class BootstrapSetupRecoveryKeyFragment :
VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapSetupRecoveryBinding {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapWaitingFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapWaitingFragment.kt
index e0965e69f9..310bb5ac37 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapWaitingFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapWaitingFragment.kt
@@ -21,11 +21,12 @@ import android.view.ViewGroup
import androidx.core.view.isVisible
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentBootstrapWaitingBinding
-import javax.inject.Inject
-class BootstrapWaitingFragment @Inject constructor() :
+@AndroidEntryPoint
+class BootstrapWaitingFragment :
VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapWaitingBinding {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/QuadSLoadingFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/QuadSLoadingFragment.kt
index 366348120b..5b6902df98 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/QuadSLoadingFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/QuadSLoadingFragment.kt
@@ -18,11 +18,13 @@ package im.vector.app.features.crypto.verification
import android.view.LayoutInflater
import android.view.ViewGroup
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentProgressBinding
-import javax.inject.Inject
-class QuadSLoadingFragment @Inject constructor() : VectorBaseFragment() {
+@AndroidEntryPoint
+class QuadSLoadingFragment :
+ VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentProgressBinding {
return FragmentProgressBinding.inflate(inflater, container, false)
}
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/cancel/VerificationCancelFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/cancel/VerificationCancelFragment.kt
index 62bab05e42..c972f7834d 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/cancel/VerificationCancelFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/cancel/VerificationCancelFragment.kt
@@ -22,6 +22,7 @@ import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
@@ -29,11 +30,13 @@ import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
import javax.inject.Inject
-class VerificationCancelFragment @Inject constructor(
- val controller: VerificationCancelController
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class VerificationCancelFragment :
+ VectorBaseFragment(),
VerificationCancelController.Listener {
+ @Inject lateinit var controller: VerificationCancelController
+
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/cancel/VerificationNotMeFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/cancel/VerificationNotMeFragment.kt
index 635a56a6c1..05632bdfc3 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/cancel/VerificationNotMeFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/cancel/VerificationNotMeFragment.kt
@@ -22,6 +22,7 @@ import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
@@ -29,11 +30,13 @@ import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
import javax.inject.Inject
-class VerificationNotMeFragment @Inject constructor(
- val controller: VerificationNotMeController
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class VerificationNotMeFragment :
+ VectorBaseFragment(),
VerificationNotMeController.Listener {
+ @Inject lateinit var controller: VerificationNotMeController
+
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodFragment.kt
index 3d3766f430..45f7908446 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodFragment.kt
@@ -23,6 +23,7 @@ import android.view.ViewGroup
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
@@ -39,11 +40,12 @@ import im.vector.app.features.qrcode.QrCodeScannerActivity
import timber.log.Timber
import javax.inject.Inject
-class VerificationChooseMethodFragment @Inject constructor(
- val controller: VerificationChooseMethodController
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class VerificationChooseMethodFragment :
+ VectorBaseFragment(),
VerificationChooseMethodController.Listener {
+ @Inject lateinit var controller: VerificationChooseMethodController
private val viewModel by fragmentViewModel(VerificationChooseMethodViewModel::class)
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/conclusion/VerificationConclusionFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/conclusion/VerificationConclusionFragment.kt
index 85b90e6004..dd559e8a1b 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/conclusion/VerificationConclusionFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/conclusion/VerificationConclusionFragment.kt
@@ -23,6 +23,7 @@ import android.view.ViewGroup
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
@@ -32,11 +33,13 @@ import im.vector.app.features.crypto.verification.VerificationBottomSheetViewMod
import kotlinx.parcelize.Parcelize
import javax.inject.Inject
-class VerificationConclusionFragment @Inject constructor(
- val controller: VerificationConclusionController
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class VerificationConclusionFragment :
+ VectorBaseFragment(),
VerificationConclusionController.Listener {
+ @Inject lateinit var controller: VerificationConclusionController
+
@Parcelize
data class Args(
val isSuccessFull: Boolean,
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeFragment.kt
index 3f4eaf8ac9..1e1a8d0710 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeFragment.kt
@@ -22,6 +22,7 @@ import android.view.ViewGroup
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
@@ -30,11 +31,13 @@ import im.vector.app.features.crypto.verification.VerificationAction
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
import javax.inject.Inject
-class VerificationEmojiCodeFragment @Inject constructor(
- val controller: VerificationEmojiCodeController
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class VerificationEmojiCodeFragment :
+ VectorBaseFragment(),
VerificationEmojiCodeController.Listener {
+ @Inject lateinit var controller: VerificationEmojiCodeController
+
private val viewModel by fragmentViewModel(VerificationEmojiCodeViewModel::class)
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQRWaitingFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQRWaitingFragment.kt
index 441885dd10..e5402424d0 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQRWaitingFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQRWaitingFragment.kt
@@ -22,6 +22,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.Mavericks
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
@@ -29,9 +30,11 @@ import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
import kotlinx.parcelize.Parcelize
import javax.inject.Inject
-class VerificationQRWaitingFragment @Inject constructor(
- val controller: VerificationQRWaitingController
-) : VectorBaseFragment() {
+@AndroidEntryPoint
+class VerificationQRWaitingFragment :
+ VectorBaseFragment() {
+
+ @Inject lateinit var controller: VerificationQRWaitingController
@Parcelize
data class Args(
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQrScannedByOtherFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQrScannedByOtherFragment.kt
index 9e77506e3b..0fdbd03174 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQrScannedByOtherFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQrScannedByOtherFragment.kt
@@ -21,6 +21,7 @@ import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
@@ -29,11 +30,13 @@ import im.vector.app.features.crypto.verification.VerificationAction
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
import javax.inject.Inject
-class VerificationQrScannedByOtherFragment @Inject constructor(
- val controller: VerificationQrScannedByOtherController
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class VerificationQrScannedByOtherFragment :
+ VectorBaseFragment(),
VerificationQrScannedByOtherController.Listener {
+ @Inject lateinit var controller: VerificationQrScannedByOtherController
+
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/request/VerificationRequestFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/request/VerificationRequestFragment.kt
index 238249683f..6887451a76 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/request/VerificationRequestFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/request/VerificationRequestFragment.kt
@@ -21,6 +21,7 @@ import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
@@ -29,11 +30,13 @@ import im.vector.app.features.crypto.verification.VerificationAction
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
import javax.inject.Inject
-class VerificationRequestFragment @Inject constructor(
- val controller: VerificationRequestController
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class VerificationRequestFragment :
+ VectorBaseFragment(),
VerificationRequestController.Listener {
+ @Inject lateinit var controller: VerificationRequestController
+
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
diff --git a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolActivity.kt b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolActivity.kt
index 774460eb1f..011deb612f 100644
--- a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolActivity.kt
@@ -109,15 +109,15 @@ class RoomDevToolActivity :
}
RoomDevToolViewState.Mode.StateEventList,
RoomDevToolViewState.Mode.StateEventListByType -> {
- val frag = createFragment(RoomDevToolStateEventListFragment::class.java)
+ val frag = RoomDevToolStateEventListFragment()
navigateTo(frag)
}
RoomDevToolViewState.Mode.EditEventContent -> {
- val frag = createFragment(RoomDevToolEditFragment::class.java)
+ val frag = RoomDevToolEditFragment()
navigateTo(frag)
}
is RoomDevToolViewState.Mode.SendEventForm -> {
- val frag = createFragment(RoomDevToolSendFormFragment::class.java)
+ val frag = RoomDevToolSendFormFragment()
navigateTo(frag)
}
}
diff --git a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolEditFragment.kt b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolEditFragment.kt
index 1b6fbb7359..3bbb43013d 100644
--- a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolEditFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolEditFragment.kt
@@ -23,15 +23,16 @@ import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentDevtoolsEditorBinding
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.widget.textChanges
-import javax.inject.Inject
-class RoomDevToolEditFragment @Inject constructor() :
+@AndroidEntryPoint
+class RoomDevToolEditFragment :
VectorBaseFragment() {
private val sharedViewModel: RoomDevToolViewModel by activityViewModel()
diff --git a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolFragment.kt b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolFragment.kt
index 0e1a2418b8..0ebbf7d8bf 100644
--- a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolFragment.kt
@@ -21,6 +21,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.activityViewModel
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
@@ -28,11 +29,13 @@ import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentGenericRecyclerBinding
import javax.inject.Inject
-class RoomDevToolFragment @Inject constructor(
- private val epoxyController: RoomDevToolRootController
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class RoomDevToolFragment :
+ VectorBaseFragment(),
DevToolsInteractionListener {
+ @Inject lateinit var epoxyController: RoomDevToolRootController
+
private val sharedViewModel: RoomDevToolViewModel by activityViewModel()
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding {
diff --git a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolSendFormFragment.kt b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolSendFormFragment.kt
index 6b7dea7d53..3ec49e25f6 100644
--- a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolSendFormFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolSendFormFragment.kt
@@ -22,15 +22,19 @@ import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentGenericRecyclerBinding
import javax.inject.Inject
-class RoomDevToolSendFormFragment @Inject constructor(
- private val epoxyController: RoomDevToolSendFormController
-) : VectorBaseFragment(), DevToolsInteractionListener {
+@AndroidEntryPoint
+class RoomDevToolSendFormFragment :
+ VectorBaseFragment(),
+ DevToolsInteractionListener {
+
+ @Inject lateinit var epoxyController: RoomDevToolSendFormController
val sharedViewModel: RoomDevToolViewModel by activityViewModel()
diff --git a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolStateEventListFragment.kt b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolStateEventListFragment.kt
index 728fb62d66..dfc74e7e74 100644
--- a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolStateEventListFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolStateEventListFragment.kt
@@ -22,6 +22,7 @@ import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
@@ -29,9 +30,12 @@ import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentGenericRecyclerBinding
import javax.inject.Inject
-class RoomDevToolStateEventListFragment @Inject constructor(
- private val epoxyController: RoomStateListController
-) : VectorBaseFragment(), DevToolsInteractionListener {
+@AndroidEntryPoint
+class RoomDevToolStateEventListFragment :
+ VectorBaseFragment(),
+ DevToolsInteractionListener {
+
+ @Inject lateinit var epoxyController: RoomStateListController
val sharedViewModel: RoomDevToolViewModel by activityViewModel()
diff --git a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt
index 285d0f728f..8c801bdf89 100644
--- a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt
@@ -25,6 +25,7 @@ import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
@@ -43,11 +44,13 @@ import org.matrix.android.sdk.api.session.identity.ThreePid
import org.matrix.android.sdk.api.session.terms.TermsService
import javax.inject.Inject
-class DiscoverySettingsFragment @Inject constructor(
- private val controller: DiscoverySettingsController
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class DiscoverySettingsFragment :
+ VectorBaseFragment(),
DiscoverySettingsController.Listener {
+ @Inject lateinit var controller: DiscoverySettingsController
+
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding {
return FragmentGenericRecyclerBinding.inflate(inflater, container, false)
}
diff --git a/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerFragment.kt b/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerFragment.kt
index ee36345418..f8499219aa 100644
--- a/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerFragment.kt
@@ -28,6 +28,7 @@ import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.extensions.toReducedUrl
@@ -42,9 +43,11 @@ import org.matrix.android.sdk.api.session.terms.TermsService
import reactivecircus.flowbinding.android.widget.textChanges
import javax.inject.Inject
-class SetIdentityServerFragment @Inject constructor(
- val colorProvider: ColorProvider
-) : VectorBaseFragment() {
+@AndroidEntryPoint
+class SetIdentityServerFragment :
+ VectorBaseFragment() {
+
+ @Inject lateinit var colorProvider: ColorProvider
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSetIdentityServerBinding {
return FragmentSetIdentityServerBinding.inflate(inflater, container, false)
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 816b9acb24..8ca217636a 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
@@ -37,6 +37,7 @@ import im.vector.app.features.themes.ThemeUtils
@EpoxyModelClass
abstract class HomeSpaceSummaryItem : VectorEpoxyModel(R.layout.item_space) {
+ @EpoxyAttribute var text: String = ""
@EpoxyAttribute var selected: Boolean = false
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null
@EpoxyAttribute var countState: UnreadCounterBadgeView.State = UnreadCounterBadgeView.State(0, false)
diff --git a/vector/src/main/java/im/vector/app/features/grouplist/NewHomeSpaceSummaryItem.kt b/vector/src/main/java/im/vector/app/features/grouplist/NewHomeSpaceSummaryItem.kt
new file mode 100644
index 0000000000..1f967db7ad
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/grouplist/NewHomeSpaceSummaryItem.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.features.grouplist
+
+import android.content.res.ColorStateList
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.core.content.ContextCompat
+import androidx.core.graphics.ColorUtils
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.app.R
+import im.vector.app.core.epoxy.ClickListener
+import im.vector.app.core.epoxy.VectorEpoxyHolder
+import im.vector.app.core.epoxy.VectorEpoxyModel
+import im.vector.app.core.epoxy.onClick
+import im.vector.app.core.platform.CheckableConstraintLayout
+import im.vector.app.features.home.room.list.UnreadCounterBadgeView
+import im.vector.app.features.themes.ThemeUtils
+
+@EpoxyModelClass
+abstract class NewHomeSpaceSummaryItem : VectorEpoxyModel(R.layout.item_new_space) {
+
+ @EpoxyAttribute var text: String = ""
+ @EpoxyAttribute var selected: Boolean = false
+ @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null
+ @EpoxyAttribute var countState: UnreadCounterBadgeView.State = UnreadCounterBadgeView.State(0, false)
+ @EpoxyAttribute var showSeparator: Boolean = false
+
+ override fun getViewType() = R.id.space_item_home
+
+ override fun bind(holder: Holder) {
+ super.bind(holder)
+ holder.root.onClick(listener)
+ holder.name.text = holder.view.context.getString(R.string.all_chats)
+ holder.root.isChecked = selected
+ holder.root.context.resources
+ holder.avatar.background = ContextCompat.getDrawable(holder.view.context, R.drawable.new_space_home_background)
+ holder.avatar.backgroundTintList = ColorStateList.valueOf(
+ ColorUtils.setAlphaComponent(ThemeUtils.getColor(holder.view.context, R.attr.vctr_content_tertiary), (255 * 0.3).toInt()))
+ holder.avatar.setImageResource(R.drawable.ic_space_home)
+ holder.avatar.imageTintList = ColorStateList.valueOf(ThemeUtils.getColor(holder.view.context, R.attr.vctr_content_primary))
+ holder.avatar.scaleType = ImageView.ScaleType.CENTER_INSIDE
+
+ holder.unreadCounter.render(countState)
+ }
+
+ class Holder : VectorEpoxyHolder() {
+ val root by bind(R.id.root)
+ val avatar by bind(R.id.avatar)
+ val name by bind(R.id.name)
+ val unreadCounter by bind(R.id.unread_counter)
+ }
+}
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 fe57b9f735..553b45ad81 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
@@ -56,6 +56,7 @@ import im.vector.app.features.analytics.plan.MobileScreen
import im.vector.app.features.analytics.plan.ViewRoom
import im.vector.app.features.crypto.recover.SetupMode
import im.vector.app.features.disclaimer.showDisclaimerDialog
+import im.vector.app.features.home.room.list.home.layout.HomeLayoutSettingBottomDialogFragment
import im.vector.app.features.matrixto.MatrixToBottomSheet
import im.vector.app.features.matrixto.OriginOfMatrixTo
import im.vector.app.features.navigation.Navigator
@@ -283,6 +284,11 @@ class HomeActivity :
.show(supportFragmentManager, "SPACE_SETTINGS")
}
+ private fun showLayoutSettings() {
+ HomeLayoutSettingBottomDialogFragment()
+ .show(supportFragmentManager, "LAYOUT_SETTINGS")
+ }
+
private fun openSpaceInvite(spaceId: String) {
SpaceInviteBottomSheet.newInstance(spaceId)
.show(supportFragmentManager, "SPACE_INVITE")
@@ -596,6 +602,10 @@ class HomeActivity :
navigator.openSettings(this)
true
}
+ R.id.menu_home_layout_settings -> {
+ showLayoutSettings()
+ true
+ }
R.id.menu_home_invite_friends -> {
launchInviteFriends()
true
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt
index d4c89c1bca..cdc16f1f33 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt
@@ -28,6 +28,7 @@ import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import com.google.android.material.badge.BadgeDrawable
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.SpaceStateHandler
import im.vector.app.core.extensions.commitTransaction
@@ -60,19 +61,21 @@ import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import javax.inject.Inject
-class HomeDetailFragment @Inject constructor(
- private val avatarRenderer: AvatarRenderer,
- private val colorProvider: ColorProvider,
- private val alertManager: PopupAlertManager,
- private val callManager: WebRtcCallManager,
- private val vectorPreferences: VectorPreferences,
- private val spaceStateHandler: SpaceStateHandler,
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class HomeDetailFragment :
+ VectorBaseFragment(),
KeysBackupBanner.Delegate,
CurrentCallsView.Callback,
OnBackPressed,
VectorMenuProvider {
+ @Inject lateinit var avatarRenderer: AvatarRenderer
+ @Inject lateinit var colorProvider: ColorProvider
+ @Inject lateinit var alertManager: PopupAlertManager
+ @Inject lateinit var callManager: WebRtcCallManager
+ @Inject lateinit var vectorPreferences: VectorPreferences
+ @Inject lateinit var spaceStateHandler: SpaceStateHandler
+
private val viewModel: HomeDetailViewModel by fragmentViewModel()
private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel()
private val unreadMessagesSharedViewModel: UnreadMessagesSharedViewModel by activityViewModel()
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt
index 535f38e68e..011a7c4537 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt
@@ -23,6 +23,7 @@ import android.view.ViewGroup
import androidx.core.app.ActivityOptionsCompat
import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.observeK
import im.vector.app.core.extensions.replaceChildFragment
@@ -40,12 +41,14 @@ import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.util.toMatrixItem
import javax.inject.Inject
-class HomeDrawerFragment @Inject constructor(
- private val session: Session,
- private val vectorPreferences: VectorPreferences,
- private val avatarRenderer: AvatarRenderer,
- private val buildMeta: BuildMeta,
-) : VectorBaseFragment() {
+@AndroidEntryPoint
+class HomeDrawerFragment :
+ VectorBaseFragment() {
+
+ @Inject lateinit var session: Session
+ @Inject lateinit var vectorPreferences: VectorPreferences
+ @Inject lateinit var avatarRenderer: AvatarRenderer
+ @Inject lateinit var buildMeta: BuildMeta
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
diff --git a/vector/src/main/java/im/vector/app/features/home/LoadingFragment.kt b/vector/src/main/java/im/vector/app/features/home/LoadingFragment.kt
index 47cfd1c28f..c5e33abf34 100644
--- a/vector/src/main/java/im/vector/app/features/home/LoadingFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/LoadingFragment.kt
@@ -21,11 +21,12 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentLoadingBinding
-import javax.inject.Inject
-class LoadingFragment @Inject constructor() : VectorBaseFragment() {
+@AndroidEntryPoint
+class LoadingFragment : VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoadingBinding {
return FragmentLoadingBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt
index 2e36748069..4b14fecae9 100644
--- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt
@@ -16,18 +16,18 @@
package im.vector.app.features.home
+import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
-import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
-import com.google.android.material.badge.BadgeDrawable
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.SpaceStateHandler
import im.vector.app.core.extensions.commitTransaction
@@ -42,15 +42,13 @@ import im.vector.app.core.ui.views.KeysBackupBanner
import im.vector.app.databinding.FragmentNewHomeDetailBinding
import im.vector.app.features.call.SharedKnownCallsViewModel
import im.vector.app.features.call.VectorCallActivity
-import im.vector.app.features.call.dialpad.DialPadFragment
+import im.vector.app.features.call.dialpad.PstnDialActivity
import im.vector.app.features.call.webrtc.WebRtcCallManager
import im.vector.app.features.home.room.list.home.HomeRoomListFragment
import im.vector.app.features.popup.PopupAlertManager
import im.vector.app.features.popup.VerificationVectorAlert
-import im.vector.app.features.settings.VectorLocale
import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.settings.VectorSettingsActivity.Companion.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY_MANAGE_SESSIONS
-import im.vector.app.features.themes.ThemeUtils
import im.vector.app.features.workers.signout.BannerState
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
import kotlinx.coroutines.Dispatchers
@@ -61,23 +59,24 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.util.toMatrixItem
import javax.inject.Inject
-class NewHomeDetailFragment @Inject constructor(
- private val avatarRenderer: AvatarRenderer,
- private val colorProvider: ColorProvider,
- private val alertManager: PopupAlertManager,
- private val callManager: WebRtcCallManager,
- private val vectorPreferences: VectorPreferences,
- private val appStateHandler: SpaceStateHandler,
- private val session: Session,
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class NewHomeDetailFragment :
+ VectorBaseFragment(),
KeysBackupBanner.Delegate,
CurrentCallsView.Callback,
OnBackPressed,
VectorMenuProvider {
+ @Inject lateinit var avatarRenderer: AvatarRenderer
+ @Inject lateinit var colorProvider: ColorProvider
+ @Inject lateinit var alertManager: PopupAlertManager
+ @Inject lateinit var callManager: WebRtcCallManager
+ @Inject lateinit var vectorPreferences: VectorPreferences
+ @Inject lateinit var spaceStateHandler: SpaceStateHandler
+ @Inject lateinit var session: Session
+
private val viewModel: HomeDetailViewModel by fragmentViewModel()
private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel()
- private val unreadMessagesSharedViewModel: UnreadMessagesSharedViewModel by activityViewModel()
private val serverBackupStatusViewModel: ServerBackupStatusViewModel by activityViewModel()
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
@@ -99,6 +98,10 @@ class NewHomeDetailFragment @Inject constructor(
viewModel.handle(HomeDetailAction.MarkAllRoomsRead)
true
}
+ R.id.menu_home_dialpad -> {
+ startActivity(Intent(requireContext(), PstnDialActivity::class.java))
+ true
+ }
else -> false
}
}
@@ -107,6 +110,7 @@ class NewHomeDetailFragment @Inject constructor(
withState(viewModel) { state ->
val isRoomList = state.currentTab is HomeTab.RoomList
menu.findItem(R.id.menu_home_mark_all_as_read).isVisible = isRoomList && hasUnreadRooms
+ menu.findItem(R.id.menu_home_dialpad).isVisible = state.showDialPadTab
}
}
@@ -120,32 +124,22 @@ class NewHomeDetailFragment @Inject constructor(
super.onViewCreated(view, savedInstanceState)
sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java)
sharedCallActionViewModel = activityViewModelProvider.get(SharedKnownCallsViewModel::class.java)
- setupBottomNavigationView()
setupToolbar()
setupKeysBackupBanner()
setupActiveCallView()
- withState(viewModel) {
- // Update the navigation view if needed (for when we restore the tabs)
- views.bottomNavigationView.selectedItemId = it.currentTab.toMenuId()
+ childFragmentManager.commitTransaction {
+ add(R.id.roomListContainer, HomeRoomListFragment::class.java, null, HOME_ROOM_LIST_FRAGMENT_TAG)
}
viewModel.onEach(HomeDetailViewState::selectedSpace) { selectedSpace ->
onSpaceChange(selectedSpace)
}
- viewModel.onEach(HomeDetailViewState::currentTab) { currentTab ->
- updateUIForTab(currentTab)
- }
-
- viewModel.onEach(HomeDetailViewState::showDialPadTab) { showDialPadTab ->
- updateTabVisibilitySafely(R.id.bottom_action_dial_pad, showDialPadTab)
- }
-
viewModel.observeViewEvents { viewEvent ->
when (viewEvent) {
- HomeDetailViewEvents.CallStarted -> handleCallStarted()
- is HomeDetailViewEvents.FailToCall -> showFailure(viewEvent.failure)
+ HomeDetailViewEvents.CallStarted -> Unit
+ is HomeDetailViewEvents.FailToCall -> Unit
HomeDetailViewEvents.Loading -> showLoadingDialog()
}
}
@@ -176,22 +170,16 @@ class NewHomeDetailFragment @Inject constructor(
}
private fun navigateBack() {
- val previousSpaceId = appStateHandler.getSpaceBackstack().removeLastOrNull()
- val parentSpaceId = appStateHandler.getCurrentSpace()?.flattenParentIds?.lastOrNull()
+ val previousSpaceId = spaceStateHandler.getSpaceBackstack().removeLastOrNull()
+ val parentSpaceId = spaceStateHandler.getCurrentSpace()?.flattenParentIds?.lastOrNull()
setCurrentSpace(previousSpaceId ?: parentSpaceId)
}
private fun setCurrentSpace(spaceId: String?) {
- appStateHandler.setCurrentSpace(spaceId, isForwardNavigation = false)
+ spaceStateHandler.setCurrentSpace(spaceId, isForwardNavigation = false)
sharedActionViewModel.post(HomeActivitySharedAction.OnCloseSpace)
}
- private fun handleCallStarted() {
- dismissLoadingDialog()
- val fragmentTag = HomeTab.DialPad.toFragmentTag()
- (childFragmentManager.findFragmentByTag(fragmentTag) as? DialPadFragment)?.clear()
- }
-
override fun onDestroyView() {
currentCallsViewPresenter.unBind()
super.onDestroyView()
@@ -199,13 +187,12 @@ class NewHomeDetailFragment @Inject constructor(
override fun onResume() {
super.onResume()
- updateTabVisibilitySafely(R.id.bottom_action_notification, vectorPreferences.labAddNotificationTab())
callManager.checkForProtocolsSupportIfNeeded()
refreshSpaceState()
}
private fun refreshSpaceState() {
- appStateHandler.getCurrentSpace()?.let {
+ spaceStateHandler.getCurrentSpace()?.let {
onSpaceChange(it)
}
}
@@ -268,8 +255,7 @@ class NewHomeDetailFragment @Inject constructor(
}
private fun onSpaceChange(spaceSummary: RoomSummary?) {
- // Reimplement in next PR
- println(spaceSummary)
+ views.collapsingToolbar.title = (spaceSummary?.displayName ?: getString(R.string.all_chats))
}
private fun setupKeysBackupBanner() {
@@ -298,82 +284,17 @@ class NewHomeDetailFragment @Inject constructor(
}
}
+ views.collapsingToolbar.debouncedClicks(::openSpaceSettings)
+ views.toolbar.debouncedClicks(::openSpaceSettings)
+
views.avatar.debouncedClicks {
navigator.openSettings(requireContext())
}
}
- private fun setupBottomNavigationView() {
- views.bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab()
- views.bottomNavigationView.setOnItemSelectedListener {
- val tab = when (it.itemId) {
- R.id.bottom_action_people -> HomeTab.RoomList(RoomListDisplayMode.PEOPLE)
- R.id.bottom_action_rooms -> HomeTab.RoomList(RoomListDisplayMode.ROOMS)
- R.id.bottom_action_notification -> HomeTab.RoomList(RoomListDisplayMode.NOTIFICATIONS)
- else -> HomeTab.DialPad
- }
- viewModel.handle(HomeDetailAction.SwitchTab(tab))
- true
- }
- }
-
- private fun updateUIForTab(tab: HomeTab) {
- views.bottomNavigationView.menu.findItem(tab.toMenuId()).isChecked = true
- updateSelectedFragment(tab)
- invalidateOptionsMenu()
- }
-
- private fun HomeTab.toFragmentTag() = "FRAGMENT_TAG_$this"
-
- private fun updateSelectedFragment(tab: HomeTab) {
- val fragmentTag = tab.toFragmentTag()
- val fragmentToShow = childFragmentManager.findFragmentByTag(fragmentTag)
- childFragmentManager.commitTransaction {
- childFragmentManager.fragments
- .filter { it != fragmentToShow }
- .forEach {
- detach(it)
- }
- if (fragmentToShow == null) {
- when (tab) {
- is HomeTab.RoomList -> {
- add(R.id.roomListContainer, HomeRoomListFragment::class.java, null, fragmentTag)
- }
- is HomeTab.DialPad -> {
- add(R.id.roomListContainer, createDialPadFragment(), fragmentTag)
- }
- }
- } else {
- if (tab is HomeTab.DialPad) {
- (fragmentToShow as? DialPadFragment)?.applyCallback()
- }
- attach(fragmentToShow)
- }
- }
- }
-
- private fun createDialPadFragment(): Fragment {
- val fragment = childFragmentManager.fragmentFactory.instantiate(vectorBaseActivity.classLoader, DialPadFragment::class.java.name)
- return (fragment as DialPadFragment).apply {
- arguments = Bundle().apply {
- putBoolean(DialPadFragment.EXTRA_ENABLE_DELETE, true)
- putBoolean(DialPadFragment.EXTRA_ENABLE_OK, true)
- putString(DialPadFragment.EXTRA_REGION_CODE, VectorLocale.applicationLocale.country)
- }
- applyCallback()
- }
- }
-
- private fun updateTabVisibilitySafely(tabId: Int, isVisible: Boolean) {
- val wasVisible = views.bottomNavigationView.menu.findItem(tabId).isVisible
- views.bottomNavigationView.menu.findItem(tabId).isVisible = isVisible
- if (wasVisible && !isVisible) {
- // As we hide it check if it's not the current item!
- withState(viewModel) {
- if (it.currentTab.toMenuId() == tabId) {
- viewModel.handle(HomeDetailAction.SwitchTab(HomeTab.RoomList(RoomListDisplayMode.PEOPLE)))
- }
- }
+ private fun openSpaceSettings() = withState(viewModel) { viewState ->
+ viewState.selectedSpace?.let {
+ sharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(it.roomId))
}
}
@@ -390,9 +311,6 @@ class NewHomeDetailFragment @Inject constructor(
}
override fun invalidate() = withState(viewModel) {
- views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_people).render(it.notificationCountPeople, it.notificationHighlightPeople)
- views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_rooms).render(it.notificationCountRooms, it.notificationHighlightRooms)
- views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_notification).render(it.notificationCountCatchup, it.notificationHighlightCatchup)
views.syncStateView.render(
it.syncState,
it.incrementalSyncRequestState,
@@ -403,27 +321,6 @@ class NewHomeDetailFragment @Inject constructor(
hasUnreadRooms = it.hasUnreadMessages
}
- private fun BadgeDrawable.render(count: Int, highlight: Boolean) {
- isVisible = count > 0
- number = count
- maxCharacterCount = 3
- badgeTextColor = ThemeUtils.getColor(requireContext(), R.attr.colorOnPrimary)
- backgroundColor = if (highlight) {
- ThemeUtils.getColor(requireContext(), R.attr.colorError)
- } else {
- ThemeUtils.getColor(requireContext(), R.attr.vctr_unread_background)
- }
- }
-
- private fun HomeTab.toMenuId() = when (this) {
- is HomeTab.DialPad -> R.id.bottom_action_dial_pad
- is HomeTab.RoomList -> when (displayMode) {
- RoomListDisplayMode.PEOPLE -> R.id.bottom_action_people
- RoomListDisplayMode.ROOMS -> R.id.bottom_action_rooms
- else -> R.id.bottom_action_notification
- }
- }
-
override fun onTapToReturnToCall() {
callManager.getCurrentCall()?.let { call ->
VectorCallActivity.newIntent(
@@ -440,20 +337,14 @@ class NewHomeDetailFragment @Inject constructor(
}
}
- private fun DialPadFragment.applyCallback(): DialPadFragment {
- callback = object : DialPadFragment.Callback {
- override fun onOkClicked(formatted: String?, raw: String?) {
- if (raw.isNullOrEmpty()) return
- viewModel.handle(HomeDetailAction.StartCallWithPhoneNumber(raw))
- }
- }
- return this
- }
-
- override fun onBackPressed(toolbarButton: Boolean) = if (appStateHandler.getCurrentSpace() != null) {
+ override fun onBackPressed(toolbarButton: Boolean) = if (spaceStateHandler.getCurrentSpace() != null) {
navigateBack()
true
} else {
false
}
+
+ companion object {
+ private const val HOME_ROOM_LIST_FRAGMENT_TAG = "TAG_HOME_ROOM_LIST"
+ }
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsFragment.kt
index 4d44ff775a..c5d7d76322 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsFragment.kt
@@ -22,6 +22,7 @@ import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
@@ -30,11 +31,13 @@ import im.vector.app.features.home.room.detail.RoomDetailSharedAction
import im.vector.app.features.home.room.detail.RoomDetailSharedActionViewModel
import javax.inject.Inject
-class BreadcrumbsFragment @Inject constructor(
- private val breadcrumbsController: BreadcrumbsController
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class BreadcrumbsFragment :
+ VectorBaseFragment(),
BreadcrumbsController.Listener {
+ @Inject lateinit var breadcrumbsController: BreadcrumbsController
+
private lateinit var sharedActionViewModel: RoomDetailSharedActionViewModel
private val breadcrumbsViewModel: BreadcrumbsViewModel by fragmentViewModel()
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
index f164183914..b5eb0608d4 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
@@ -67,10 +67,12 @@ import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.vanniktech.emoji.EmojiPopup
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.animations.play
import im.vector.app.core.dialogs.ConfirmationDialogBuilder
import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper
+import im.vector.app.core.dialogs.GalleryOrCameraDialogHelperFactory
import im.vector.app.core.epoxy.LayoutManagerStateRestorer
import im.vector.app.core.error.fatalError
import im.vector.app.core.extensions.cleanup
@@ -255,31 +257,8 @@ import java.net.URL
import java.util.UUID
import javax.inject.Inject
-class TimelineFragment @Inject constructor(
- private val session: Session,
- private val avatarRenderer: AvatarRenderer,
- private val timelineEventController: TimelineEventController,
- autoCompleterFactory: AutoCompleter.Factory,
- private val permalinkHandler: PermalinkHandler,
- private val notificationDrawerManager: NotificationDrawerManager,
- private val eventHtmlRenderer: EventHtmlRenderer,
- private val vectorPreferences: VectorPreferences,
- private val threadsManager: ThreadsManager,
- private val colorProvider: ColorProvider,
- private val dimensionConverter: DimensionConverter,
- private val userPreferencesProvider: UserPreferencesProvider,
- private val notificationUtils: NotificationUtils,
- private val matrixItemColorProvider: MatrixItemColorProvider,
- private val imageContentRenderer: ImageContentRenderer,
- private val roomDetailPendingActionStore: RoomDetailPendingActionStore,
- private val pillsPostProcessorFactory: PillsPostProcessor.Factory,
- private val callManager: WebRtcCallManager,
- private val audioMessagePlaybackTracker: AudioMessagePlaybackTracker,
- private val shareIntentHandler: ShareIntentHandler,
- private val clock: Clock,
- private val vectorFeatures: VectorFeatures,
- private val buildMeta: BuildMeta,
-) :
+@AndroidEntryPoint
+class TimelineFragment :
VectorBaseFragment(),
TimelineEventController.Callback,
VectorInviteView.Callback,
@@ -289,6 +268,31 @@ class TimelineFragment @Inject constructor(
CurrentCallsView.Callback,
VectorMenuProvider {
+ @Inject lateinit var session: Session
+ @Inject lateinit var avatarRenderer: AvatarRenderer
+ @Inject lateinit var timelineEventController: TimelineEventController
+ @Inject lateinit var autoCompleterFactory: AutoCompleter.Factory
+ @Inject lateinit var permalinkHandler: PermalinkHandler
+ @Inject lateinit var notificationDrawerManager: NotificationDrawerManager
+ @Inject lateinit var eventHtmlRenderer: EventHtmlRenderer
+ @Inject lateinit var vectorPreferences: VectorPreferences
+ @Inject lateinit var threadsManager: ThreadsManager
+ @Inject lateinit var colorProvider: ColorProvider
+ @Inject lateinit var dimensionConverter: DimensionConverter
+ @Inject lateinit var userPreferencesProvider: UserPreferencesProvider
+ @Inject lateinit var notificationUtils: NotificationUtils
+ @Inject lateinit var matrixItemColorProvider: MatrixItemColorProvider
+ @Inject lateinit var imageContentRenderer: ImageContentRenderer
+ @Inject lateinit var roomDetailPendingActionStore: RoomDetailPendingActionStore
+ @Inject lateinit var pillsPostProcessorFactory: PillsPostProcessor.Factory
+ @Inject lateinit var callManager: WebRtcCallManager
+ @Inject lateinit var audioMessagePlaybackTracker: AudioMessagePlaybackTracker
+ @Inject lateinit var shareIntentHandler: ShareIntentHandler
+ @Inject lateinit var clock: Clock
+ @Inject lateinit var vectorFeatures: VectorFeatures
+ @Inject lateinit var buildMeta: BuildMeta
+ @Inject lateinit var galleryOrCameraDialogHelperFactory: GalleryOrCameraDialogHelperFactory
+
companion object {
/**
@@ -309,7 +313,7 @@ class TimelineFragment @Inject constructor(
private const val ircPattern = " (IRC)"
}
- private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock)
+ private lateinit var galleryOrCameraDialogHelper: GalleryOrCameraDialogHelper
private val timelineArgs: TimelineArgs by args()
private val glideRequests by lazy {
@@ -362,6 +366,7 @@ class TimelineFragment @Inject constructor(
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
analyticsScreenName = MobileScreen.ScreenName.Room
+ galleryOrCameraDialogHelper = galleryOrCameraDialogHelperFactory.create(this)
setFragmentResultListener(MigrateRoomBottomSheet.REQUEST_KEY) { _, bundle ->
bundle.getString(MigrateRoomBottomSheet.BUNDLE_KEY_REPLACEMENT_ROOM)?.let { replacementRoomId ->
timelineViewModel.handle(RoomDetailAction.RoomUpgradeSuccess(replacementRoomId))
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt
index c0f90aba7a..cea845a490 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt
@@ -82,6 +82,7 @@ import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
+import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.LocalEcho
import org.matrix.android.sdk.api.session.events.model.RelationType
@@ -1269,11 +1270,26 @@ class TimelineViewModel @AssistedInject constructor(
}
}
room.getStateEvent(EventType.STATE_ROOM_TOMBSTONE, QueryStringValue.IsEmpty)?.also {
- setState { copy(tombstoneEvent = it) }
+ onRoomTombstoneUpdated(it)
}
}
}
+ private var roomTombstoneHandled = false
+ private fun onRoomTombstoneUpdated(tombstoneEvent: Event) = withState { state ->
+ if (roomTombstoneHandled) return@withState
+ if (state.isLocalRoom()) {
+ // Local room has been replaced, so navigate to the new room
+ val roomId = tombstoneEvent.getClearContent()?.toModel()
+ ?.replacementRoomId
+ ?: return@withState
+ _viewEvents.post(RoomDetailViewEvents.OpenRoom(roomId, closeCurrentRoom = true))
+ roomTombstoneHandled = true
+ } else {
+ setState { copy(tombstoneEvent = tombstoneEvent) }
+ }
+ }
+
/**
* Navigates to the appropriate event (by paginating the thread timeline until the event is found
* in the snapshot. The main reason for this function is to support the /relations api
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt
index de51adf05a..713ca80089 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt
@@ -29,6 +29,7 @@ import com.airbnb.mvrx.Success
import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
@@ -51,12 +52,13 @@ data class SearchArgs(
val roomAvatarUrl: String?
) : Parcelable
-class SearchFragment @Inject constructor(
- private val controller: SearchResultController
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class SearchFragment :
+ VectorBaseFragment(),
StateView.EventCallback,
SearchResultController.Listener {
+ @Inject lateinit var controller: SearchResultController
private val fragmentArgs: SearchArgs by args()
private val searchViewModel: SearchViewModel by fragmentViewModel()
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineAsyncHelper.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineAsyncHelper.kt
index 655d46194d..87c6a1efda 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineAsyncHelper.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineAsyncHelper.kt
@@ -19,7 +19,7 @@ package im.vector.app.features.home.room.detail.timeline.helper
import android.os.Handler
import android.os.HandlerThread
-private const val THREAD_NAME = "Timeline_Building_Thread"
+private const val THREAD_NAME = "Vector-Timeline_Building_Thread"
object TimelineAsyncHelper {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineEventVisibilityHelper.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineEventVisibilityHelper.kt
index e6765bf35a..d22b649b36 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineEventVisibilityHelper.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineEventVisibilityHelper.kt
@@ -229,8 +229,9 @@ class TimelineEventVisibilityHelper @Inject constructor(
// Hide fake events for local rooms
if (RoomLocalEcho.isLocalEchoId(roomId) &&
- root.getClearType() == EventType.STATE_ROOM_MEMBER ||
- root.getClearType() == EventType.STATE_ROOM_HISTORY_VISIBILITY) {
+ (root.getClearType() == EventType.STATE_ROOM_MEMBER ||
+ root.getClearType() == EventType.STATE_ROOM_HISTORY_VISIBILITY ||
+ root.getClearType() == EventType.STATE_ROOM_THIRD_PARTY_INVITE)) {
return true
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt
index c25fe546c3..de51101804 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt
@@ -35,6 +35,7 @@ import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.epoxy.LayoutManagerStateRestorer
import im.vector.app.core.extensions.cleanup
@@ -70,17 +71,19 @@ data class RoomListParams(
val displayMode: RoomListDisplayMode
) : Parcelable
-class RoomListFragment @Inject constructor(
- private val pagedControllerFactory: RoomSummaryPagedControllerFactory,
- private val notificationDrawerManager: NotificationDrawerManager,
- private val footerController: RoomListFooterController,
- private val userPreferencesProvider: UserPreferencesProvider
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class RoomListFragment :
+ VectorBaseFragment(),
RoomListListener,
OnBackPressed,
FilteredRoomFooterItem.Listener,
NotifsFabMenuView.Listener {
+ @Inject lateinit var pagedControllerFactory: RoomSummaryPagedControllerFactory
+ @Inject lateinit var notificationDrawerManager: NotificationDrawerManager
+ @Inject lateinit var footerController: RoomListFooterController
+ @Inject lateinit var userPreferencesProvider: UserPreferencesProvider
+
private var modelBuildListener: OnModelBuildFinishedListener? = null
private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel
private val roomListParams: RoomListParams by args()
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 4b76daf502..2e0a6ae347 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
@@ -146,17 +146,17 @@ class RoomListViewModel @AssistedInject constructor(
companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory()
private val roomListSectionBuilder = RoomListSectionBuilder(
- session,
- stringProvider,
- spaceStateHandler,
- viewModelScope,
- autoAcceptInvites,
- {
- updatableQuery = it
- },
- suggestedRoomJoiningState,
- !vectorPreferences.prefSpacesShowAllRoomInHome()
- )
+ session,
+ stringProvider,
+ spaceStateHandler,
+ viewModelScope,
+ autoAcceptInvites,
+ {
+ updatableQuery = it
+ },
+ suggestedRoomJoiningState,
+ !vectorPreferences.prefSpacesShowAllRoomInHome()
+ )
val sections: List by lazy {
roomListSectionBuilder.buildSections(initialState.displayMode)
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsSharedAction.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsSharedAction.kt
index 0423a8fffc..8c84aa55e1 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsSharedAction.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsSharedAction.kt
@@ -25,8 +25,7 @@ sealed class RoomListQuickActionsSharedAction(
@StringRes val titleRes: Int,
@DrawableRes val iconResId: Int?,
val destructive: Boolean = false
-) :
- VectorSharedAction {
+) : VectorSharedAction {
data class NotificationsAllNoisy(val roomId: String) : RoomListQuickActionsSharedAction(
R.string.room_list_quick_actions_notifications_all_noisy,
diff --git a/vector/src/main/java/im/vector/app/features/login2/SignMode2.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListSharedAction.kt
similarity index 69%
rename from vector/src/main/java/im/vector/app/features/login2/SignMode2.kt
rename to vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListSharedAction.kt
index f3d59837e7..766bc6eea1 100644
--- a/vector/src/main/java/im/vector/app/features/login2/SignMode2.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListSharedAction.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 New Vector Ltd
+ * Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,11 @@
* limitations under the License.
*/
-package im.vector.app.features.login2
+package im.vector.app.features.home.room.list.actions
-enum class SignMode2 {
- Unknown,
+import im.vector.app.core.platform.VectorSharedAction
- // Account creation
- SignUp,
+sealed class RoomListSharedAction : VectorSharedAction {
- // Login
- SignIn
+ object CloseBottomSheet : RoomListSharedAction()
}
diff --git a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListSharedActionViewModel.kt
similarity index 58%
rename from vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedViewEvents.kt
rename to vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListSharedActionViewModel.kt
index 6a23409f5c..e2545accc8 100644
--- a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedViewEvents.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListSharedActionViewModel.kt
@@ -1,27 +1,22 @@
/*
- * Copyright 2021 New Vector Ltd
+ * Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
*/
-package im.vector.app.features.login2.created
+package im.vector.app.features.home.room.list.actions
-import im.vector.app.core.platform.VectorViewEvents
+import im.vector.app.core.platform.VectorSharedActionViewModel
+import javax.inject.Inject
-/**
- * Transient events for Account Created.
- */
-sealed class AccountCreatedViewEvents : VectorViewEvents {
- data class Failure(val throwable: Throwable) : AccountCreatedViewEvents()
-}
+class RoomListSharedActionViewModel @Inject constructor() : VectorSharedActionViewModel()
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeLayoutPreferencesStore.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeLayoutPreferencesStore.kt
new file mode 100644
index 0000000000..11cd892406
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeLayoutPreferencesStore.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.home.room.list.home
+
+import android.content.Context
+import androidx.datastore.core.DataStore
+import androidx.datastore.preferences.core.Preferences
+import androidx.datastore.preferences.core.booleanPreferencesKey
+import androidx.datastore.preferences.core.edit
+import androidx.datastore.preferences.preferencesDataStore
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+import org.matrix.android.sdk.api.extensions.orFalse
+import javax.inject.Inject
+
+private val Context.dataStore: DataStore by preferencesDataStore(name = "layout_preferences")
+
+class HomeLayoutPreferencesStore @Inject constructor(
+ private val context: Context
+) {
+
+ private val areRecentsEnbabled = booleanPreferencesKey("SETTINGS_PREFERENCES_HOME_RECENTS")
+ private val areFiltersEnabled = booleanPreferencesKey("SETTINGS_PREFERENCES_HOME_FILTERS")
+ private val isAZOrderingEnabled = booleanPreferencesKey("SETTINGS_PREFERENCES_USE_AZ_ORDER")
+
+ val areRecentsEnabledFlow: Flow = context.dataStore.data
+ .map { preferences -> preferences[areRecentsEnbabled].orFalse() }
+ .distinctUntilChanged()
+
+ val areFiltersEnabledFlow: Flow = context.dataStore.data
+ .map { preferences -> preferences[areFiltersEnabled].orFalse() }
+ .distinctUntilChanged()
+
+ val isAZOrderingEnabledFlow: Flow = context.dataStore.data
+ .map { preferences -> preferences[isAZOrderingEnabled].orFalse() }
+ .distinctUntilChanged()
+
+ suspend fun setRecentsEnabled(isEnabled: Boolean) {
+ context.dataStore.edit { settings ->
+ settings[areRecentsEnbabled] = isEnabled
+ }
+ }
+
+ suspend fun setFiltersEnabled(isEnabled: Boolean) {
+ context.dataStore.edit { settings ->
+ settings[areFiltersEnabled] = isEnabled
+ }
+ }
+
+ suspend fun setAZOrderingEnabled(isEnabled: Boolean) {
+ context.dataStore.edit { settings ->
+ settings[isAZOrderingEnabled] = isEnabled
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt
index c98d22a34f..3e8c2b5dcd 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt
@@ -16,6 +16,7 @@
package im.vector.app.features.home.room.list.home
+import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -29,6 +30,7 @@ import com.airbnb.epoxy.OnModelBuildFinishedListener
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.epoxy.LayoutManagerStateRestorer
import im.vector.app.core.extensions.cleanup
@@ -43,9 +45,14 @@ import im.vector.app.features.home.room.list.RoomSummaryItemFactory
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
+import im.vector.app.features.home.room.list.actions.RoomListSharedAction
+import im.vector.app.features.home.room.list.actions.RoomListSharedActionViewModel
import im.vector.app.features.home.room.list.home.filter.HomeFilteredRoomsController
import im.vector.app.features.home.room.list.home.filter.HomeRoomFilter
+import im.vector.app.features.home.room.list.home.invites.InvitesActivity
+import im.vector.app.features.home.room.list.home.invites.InvitesCounterController
import im.vector.app.features.home.room.list.home.recent.RecentRoomCarouselController
+import im.vector.app.features.spaces.SpaceListBottomSheet
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.session.room.model.RoomSummary
@@ -54,35 +61,53 @@ import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
import javax.inject.Inject
-class HomeRoomListFragment @Inject constructor(
- private val roomSummaryItemFactory: RoomSummaryItemFactory,
- private val userPreferencesProvider: UserPreferencesProvider,
- private val recentRoomCarouselController: RecentRoomCarouselController
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class HomeRoomListFragment :
+ VectorBaseFragment(),
RoomListListener {
+ @Inject lateinit var roomSummaryItemFactory: RoomSummaryItemFactory
+ @Inject lateinit var userPreferencesProvider: UserPreferencesProvider
+ @Inject lateinit var recentRoomCarouselController: RecentRoomCarouselController
+ @Inject lateinit var invitesCounterController: InvitesCounterController
+
private val roomListViewModel: HomeRoomListViewModel by fragmentViewModel()
- private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel
+ private lateinit var sharedQuickActionsViewModel: RoomListQuickActionsSharedActionViewModel
+ private lateinit var sharedActionViewModel: RoomListSharedActionViewModel
private var concatAdapter = ConcatAdapter()
private var modelBuildListener: OnModelBuildFinishedListener? = null
+ private val spaceListBottomSheet = SpaceListBottomSheet()
+
private lateinit var stateRestorer: LayoutManagerStateRestorer
+ private val newChatBottomSheet = NewChatBottomSheet()
+
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomListBinding {
return FragmentRoomListBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
-
- sharedActionViewModel = activityViewModelProvider[RoomListQuickActionsSharedActionViewModel::class.java]
- sharedActionViewModel
- .stream()
- .onEach { handleQuickActions(it) }
- .launchIn(viewLifecycleOwner.lifecycleScope)
-
views.stateView.contentView = views.roomListView
views.stateView.state = StateView.State.Loading
+ setupObservers()
+ setupRecyclerView()
+ setupFabs()
+ }
+
+ private fun setupObservers() {
+ sharedQuickActionsViewModel = activityViewModelProvider[RoomListQuickActionsSharedActionViewModel::class.java]
+ sharedActionViewModel = activityViewModelProvider[RoomListSharedActionViewModel::class.java]
+
+ sharedActionViewModel
+ .stream()
+ .onEach(::handleSharedAction)
+ .launchIn(viewLifecycleOwner.lifecycleScope)
+ sharedQuickActionsViewModel
+ .stream()
+ .onEach(::handleQuickActions)
+ .launchIn(viewLifecycleOwner.lifecycleScope)
roomListViewModel.observeViewEvents {
when (it) {
@@ -92,69 +117,11 @@ class HomeRoomListFragment @Inject constructor(
is HomeRoomListViewEvents.Done -> Unit
}
}
-
- setupRecyclerView()
- setupFabs()
}
- private fun setupRecyclerView() {
- val layoutManager = LinearLayoutManager(context)
- stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
- views.roomListView.layoutManager = layoutManager
- views.roomListView.itemAnimator = RoomListAnimator()
- layoutManager.recycleChildrenOnDetach = true
-
- modelBuildListener = OnModelBuildFinishedListener { it.dispatchTo(stateRestorer) }
-
- roomListViewModel.sections.onEach { sections ->
- setUpAdapters(sections)
- }.launchIn(lifecycleScope)
-
- views.roomListView.adapter = concatAdapter
- }
-
- private fun setupFabs() {
- showFABs()
-
- views.newLayoutCreateChatButton.setOnClickListener {
- // Click action for create chat modal goes here (Issue #6717)
- }
-
- views.newLayoutOpenSpacesButton.setOnClickListener {
- // Click action for open spaces modal goes here (Issue #6499)
- }
-
- // Hide FABs when list is scrolling
- views.roomListView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
- override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
- views.createChatFabMenu.handler.removeCallbacksAndMessages(null)
-
- when (newState) {
- RecyclerView.SCROLL_STATE_IDLE -> views.createChatFabMenu.postDelayed(::showFABs, 250)
- RecyclerView.SCROLL_STATE_DRAGGING,
- RecyclerView.SCROLL_STATE_SETTLING -> hideFABs()
- }
- }
- })
- }
-
- private fun showFABs() {
- views.newLayoutCreateChatButton.show()
- views.newLayoutOpenSpacesButton.show()
- }
-
- private fun hideFABs() {
- views.newLayoutCreateChatButton.hide()
- views.newLayoutOpenSpacesButton.hide()
- }
-
- override fun invalidate() = withState(roomListViewModel) { state ->
- views.stateView.state = state.state
- }
-
- private fun setUpAdapters(sections: Set) {
- sections.forEach {
- concatAdapter.addAdapter(getAdapterForData(it))
+ private fun handleSharedAction(action: RoomListSharedAction) {
+ when (action) {
+ RoomListSharedAction.CloseBottomSheet -> spaceListBottomSheet.dismiss()
}
}
@@ -188,6 +155,80 @@ class HomeRoomListFragment @Inject constructor(
}
}
+ private fun setupRecyclerView() {
+ val layoutManager = LinearLayoutManager(context)
+ stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
+ views.roomListView.layoutManager = layoutManager
+ views.roomListView.itemAnimator = RoomListAnimator()
+ layoutManager.recycleChildrenOnDetach = true
+
+ modelBuildListener = OnModelBuildFinishedListener { it.dispatchTo(stateRestorer) }
+
+ roomListViewModel.sections.onEach { sections ->
+ setUpAdapters(sections)
+ }.launchIn(lifecycleScope)
+
+ views.roomListView.adapter = concatAdapter
+
+ // we need to force scroll when recents/filter tabs are added to make them visible
+ concatAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
+ override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
+ if (positionStart == 0) {
+ layoutManager.scrollToPosition(0)
+ }
+ }
+ })
+ }
+
+ private fun setupFabs() {
+ showFABs()
+
+ views.newLayoutCreateChatButton.setOnClickListener {
+ newChatBottomSheet.show(requireActivity().supportFragmentManager, NewChatBottomSheet.TAG)
+ }
+
+ views.newLayoutOpenSpacesButton.setOnClickListener {
+ // Click action for open spaces modal goes here
+ spaceListBottomSheet.show(requireActivity().supportFragmentManager, SpaceListBottomSheet.TAG)
+ }
+
+ // Hide FABs when list is scrolling
+ views.roomListView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+ override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
+ views.createChatFabMenu.handler.removeCallbacksAndMessages(null)
+
+ when (newState) {
+ RecyclerView.SCROLL_STATE_IDLE -> views.createChatFabMenu.postDelayed(::showFABs, 250)
+ RecyclerView.SCROLL_STATE_DRAGGING,
+ RecyclerView.SCROLL_STATE_SETTLING -> hideFABs()
+ }
+ }
+ })
+ }
+
+ private fun showFABs() {
+ views.newLayoutCreateChatButton.show()
+ views.newLayoutOpenSpacesButton.show()
+ }
+
+ private fun hideFABs() {
+ views.newLayoutCreateChatButton.hide()
+ views.newLayoutOpenSpacesButton.hide()
+ }
+
+ override fun invalidate() = withState(roomListViewModel) { state ->
+ views.stateView.state = state.state
+ }
+
+ private fun setUpAdapters(sections: Set) {
+ concatAdapter.adapters.forEach {
+ concatAdapter.removeAdapter(it)
+ }
+ sections.forEach {
+ concatAdapter.addAdapter(getAdapterForData(it))
+ }
+ }
+
private fun promptLeaveRoom(roomId: String) {
val isPublicRoom = roomListViewModel.isPublicRoom(roomId)
val message = buildString {
@@ -212,12 +253,11 @@ class HomeRoomListFragment @Inject constructor(
is HomeRoomSection.RoomSummaryData -> {
HomeFilteredRoomsController(
roomSummaryItemFactory,
- showFilters = section.showFilters,
).also { controller ->
controller.listener = this
controller.onFilterChanged = ::onRoomFilterChanged
section.filtersData.onEach {
- controller.submitFiltersData(it)
+ controller.submitFiltersData(it.getOrNull())
}.launchIn(lifecycleScope)
section.list.observe(viewLifecycleOwner) { list ->
controller.submitList(list)
@@ -230,9 +270,19 @@ class HomeRoomListFragment @Inject constructor(
controller.submitList(list)
}
}.adapter
+ is HomeRoomSection.InvitesCountData -> invitesCounterController.also { controller ->
+ controller.clickListener = ::onInvitesCounterClicked
+ section.count.observe(viewLifecycleOwner) { count ->
+ controller.submitData(count)
+ }
+ }.adapter
}
}
+ private fun onInvitesCounterClicked() {
+ startActivity(Intent(activity, InvitesActivity::class.java))
+ }
+
private fun onRoomFilterChanged(filter: HomeRoomFilter) {
roomListViewModel.handle(HomeRoomListAction.ChangeRoomFilter(filter))
}
@@ -249,6 +299,7 @@ class HomeRoomListFragment @Inject constructor(
override fun onDestroyView() {
views.roomListView.cleanup()
recentRoomCarouselController.listener = null
+ invitesCounterController.clickListener = null
super.onDestroyView()
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt
index 1fed9eba86..5ecf9d6d96 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt
@@ -16,6 +16,7 @@
package im.vector.app.features.home.room.list.home
+import androidx.lifecycle.map
import androidx.paging.PagedList
import arrow.core.toOption
import com.airbnb.mvrx.MavericksViewModelFactory
@@ -34,6 +35,7 @@ import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -53,12 +55,14 @@ import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.state.isPublic
+import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.flow.flow
class HomeRoomListViewModel @AssistedInject constructor(
@Assisted initialState: HomeRoomListViewState,
private val session: Session,
private val spaceStateHandler: SpaceStateHandler,
+ private val preferencesStore: HomeLayoutPreferencesStore,
) : VectorViewModel(initialState) {
@AssistedFactory
@@ -82,17 +86,30 @@ class HomeRoomListViewModel @AssistedInject constructor(
init {
configureSections()
+ observePreferences()
}
- private fun configureSections() {
- val newSections = mutableSetOf()
+ private fun observePreferences() {
+ preferencesStore.areRecentsEnabledFlow.onEach {
+ configureSections()
+ }.launchIn(viewModelScope)
- newSections.add(getRecentRoomsSection())
+ preferencesStore.isAZOrderingEnabledFlow.onEach {
+ configureSections()
+ }.launchIn(viewModelScope)
+ }
+
+ private fun configureSections() = viewModelScope.launch {
+ val newSections = mutableSetOf()
+ newSections.add(getInvitesCountSection())
+
+ val areSettingsEnabled = preferencesStore.areRecentsEnabledFlow.first()
+ if (areSettingsEnabled) {
+ newSections.add(getRecentRoomsSection())
+ }
newSections.add(getFilteredRoomsSection())
- viewModelScope.launch {
- _sections.emit(newSections)
- }
+ _sections.emit(newSections)
setState {
copy(state = StateView.State.Content)
@@ -111,13 +128,30 @@ class HomeRoomListViewModel @AssistedInject constructor(
)
}
- private fun getFilteredRoomsSection(): HomeRoomSection.RoomSummaryData {
+ private fun getInvitesCountSection(): HomeRoomSection.InvitesCountData {
+ val builder = RoomSummaryQueryParams.Builder().also {
+ it.memberships = listOf(Membership.INVITE)
+ }
+
+ val liveCount = session.roomService().getRoomSummariesLive(
+ builder.build(),
+ RoomSortOrder.ACTIVITY
+ ).map { it.count() }
+
+ return HomeRoomSection.InvitesCountData(liveCount)
+ }
+
+ private suspend fun getFilteredRoomsSection(): HomeRoomSection.RoomSummaryData {
val builder = RoomSummaryQueryParams.Builder().also {
it.memberships = listOf(Membership.JOIN)
}
val params = getFilteredQueryParams(HomeRoomFilter.ALL, builder.build())
- val sortOrder = RoomSortOrder.ACTIVITY // #6506
+ val sortOrder = if (preferencesStore.isAZOrderingEnabledFlow.first()) {
+ RoomSortOrder.NAME
+ } else {
+ RoomSortOrder.ACTIVITY
+ }
val liveResults = session.roomService().getFilteredPagedRoomSummariesLive(
params,
@@ -135,19 +169,18 @@ class HomeRoomListViewModel @AssistedInject constructor(
.onEach { selectedSpaceOption ->
val selectedSpace = selectedSpaceOption.orNull()
liveResults.queryParams = liveResults.queryParams.copy(
- spaceFilter = selectedSpace?.roomId.toActiveSpaceOrNoFilter()
+ spaceFilter = selectedSpace?.roomId.toActiveSpaceOrNoFilter()
)
}.launchIn(viewModelScope)
return HomeRoomSection.RoomSummaryData(
list = liveResults.livePagedList,
- showFilters = true, // #6506
filtersData = getFiltersDataFlow()
)
}
- private fun getFiltersDataFlow(): SharedFlow> {
- val flow = MutableSharedFlow>(replay = 1)
+ private fun getFiltersDataFlow(): SharedFlow>> {
+ val flow = MutableSharedFlow>>(replay = 1)
val favouritesFlow = session.flow()
.liveRoomSummaries(
@@ -168,25 +201,28 @@ class HomeRoomListViewModel @AssistedInject constructor(
.map { it.isNotEmpty() }
.distinctUntilChanged()
- favouritesFlow.combine(dmsFLow) { hasFavourite, hasDm ->
- hasFavourite to hasDm
- }.onEach { (hasFavourite, hasDm) ->
- val filtersData = mutableListOf(
- HomeRoomFilter.ALL,
- HomeRoomFilter.UNREADS
- )
- if (hasFavourite) {
- filtersData.add(
- HomeRoomFilter.FAVOURITES
+ combine(favouritesFlow, dmsFLow, preferencesStore.areFiltersEnabledFlow) { hasFavourite, hasDm, areFiltersEnabled ->
+ Triple(hasFavourite, hasDm, areFiltersEnabled)
+ }.onEach { (hasFavourite, hasDm, areFiltersEnabled) ->
+ if (areFiltersEnabled) {
+ val filtersData = mutableListOf(
+ HomeRoomFilter.ALL,
+ HomeRoomFilter.UNREADS
)
+ if (hasFavourite) {
+ filtersData.add(
+ HomeRoomFilter.FAVOURITES
+ )
+ }
+ if (hasDm) {
+ filtersData.add(
+ HomeRoomFilter.PEOPlE
+ )
+ }
+ flow.emit(Optional.from(filtersData))
+ } else {
+ flow.emit(Optional.empty())
}
- if (hasDm) {
- filtersData.add(
- HomeRoomFilter.PEOPlE
- )
- }
-
- flow.emit(filtersData)
}.launchIn(viewModelScope)
return flow
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomSection.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomSection.kt
index f51b479d37..29df594d06 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomSection.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomSection.kt
@@ -21,15 +21,19 @@ import androidx.paging.PagedList
import im.vector.app.features.home.room.list.home.filter.HomeRoomFilter
import kotlinx.coroutines.flow.SharedFlow
import org.matrix.android.sdk.api.session.room.model.RoomSummary
+import org.matrix.android.sdk.api.util.Optional
sealed class HomeRoomSection {
data class RoomSummaryData(
val list: LiveData>,
- val showFilters: Boolean,
- val filtersData: SharedFlow>
+ val filtersData: SharedFlow>>,
) : HomeRoomSection()
data class RecentRoomsData(
val list: LiveData>
) : HomeRoomSection()
+
+ data class InvitesCountData(
+ val count: LiveData
+ ) : HomeRoomSection()
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/NewChatBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/NewChatBottomSheet.kt
new file mode 100644
index 0000000000..05b86f7393
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/NewChatBottomSheet.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.home.room.list.home
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.databinding.FragmentNewChatBottomSheetBinding
+import im.vector.app.features.navigation.Navigator
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class NewChatBottomSheet @Inject constructor() : BottomSheetDialogFragment() {
+
+ @Inject lateinit var navigator: Navigator
+
+ private lateinit var binding: FragmentNewChatBottomSheetBinding
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+ binding = FragmentNewChatBottomSheetBinding.inflate(inflater, container, false)
+ initFABs()
+ return binding.root
+ }
+
+ private fun initFABs() {
+ binding.startChat.setOnClickListener {
+ navigator.openCreateDirectRoom(requireActivity())
+ }
+
+ binding.createRoom.setOnClickListener {
+ navigator.openCreateRoom(requireActivity())
+ }
+
+ binding.exploreRooms.setOnClickListener {
+ navigator.openRoomDirectory(requireContext())
+ }
+ }
+
+ companion object {
+ const val TAG = "NewChatBottomSheet"
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/filter/HomeFilteredRoomsController.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/filter/HomeFilteredRoomsController.kt
index 7c1f154d52..2d673bc089 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/filter/HomeFilteredRoomsController.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/filter/HomeFilteredRoomsController.kt
@@ -28,7 +28,6 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary
class HomeFilteredRoomsController(
private val roomSummaryItemFactory: RoomSummaryItemFactory,
- private val showFilters: Boolean,
) : PagedListEpoxyController(
// Important it must match the PageList builder notify Looper
modelBuildingHandler = createUIHandler()
@@ -48,7 +47,7 @@ class HomeFilteredRoomsController(
override fun addModels(models: List>) {
val host = this
- if (showFilters) {
+ if (host.filtersData != null) {
roomFilterHeaderItem {
id("filter_header")
filtersData(host.filtersData)
@@ -58,7 +57,7 @@ class HomeFilteredRoomsController(
super.addModels(models)
}
- fun submitFiltersData(data: List) {
+ fun submitFiltersData(data: List?) {
this.filtersData = data
requestForcedModelBuild()
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InviteCounterItem.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InviteCounterItem.kt
new file mode 100644
index 0000000000..4bc292be27
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InviteCounterItem.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.home.room.list.home.invites
+
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.app.R
+import im.vector.app.core.epoxy.ClickListener
+import im.vector.app.core.epoxy.VectorEpoxyHolder
+import im.vector.app.core.epoxy.VectorEpoxyModel
+import im.vector.app.features.home.room.list.UnreadCounterBadgeView
+
+@EpoxyModelClass
+abstract class InviteCounterItem : VectorEpoxyModel(R.layout.item_invites_count) {
+
+ @EpoxyAttribute var invitesCount: Int = 0
+ @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null
+
+ override fun bind(holder: Holder) {
+ super.bind(holder)
+ holder.view.setOnClickListener(listener)
+ holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(invitesCount, true))
+ }
+
+ class Holder : VectorEpoxyHolder() {
+ val unreadCounterBadgeView by bind(R.id.invites_count_badge)
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedAction.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesAction.kt
similarity index 57%
rename from vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedAction.kt
rename to vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesAction.kt
index f108bfa886..ed6ed23c9d 100644
--- a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedAction.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesAction.kt
@@ -1,11 +1,11 @@
/*
- * Copyright (c) 2021 New Vector Ltd
+ * Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package im.vector.app.features.login2.created
+package im.vector.app.features.home.room.list.home.invites
-import android.net.Uri
import im.vector.app.core.platform.VectorViewModelAction
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
-sealed class AccountCreatedAction : VectorViewModelAction {
- data class SetDisplayName(val displayName: String) : AccountCreatedAction()
- data class SetAvatar(val avatarUri: Uri, val filename: String) : AccountCreatedAction()
+sealed class InvitesAction : VectorViewModelAction {
+ data class AcceptInvitation(val roomSummary: RoomSummary) : InvitesAction()
+ data class RejectInvitation(val roomSummary: RoomSummary) : InvitesAction()
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesActivity.kt
new file mode 100644
index 0000000000..b590caab42
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesActivity.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.home.room.list.home.invites
+
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.core.extensions.addFragment
+import im.vector.app.core.platform.VectorBaseActivity
+import im.vector.app.databinding.ActivitySimpleBinding
+
+@AndroidEntryPoint
+class InvitesActivity : VectorBaseActivity() {
+
+ override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater)
+
+ override fun initUiAndData() {
+ if (isFirstCreation()) {
+ addFragment(views.simpleFragmentContainer, InvitesFragment::class.java)
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesController.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesController.kt
new file mode 100644
index 0000000000..1511b97c3c
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesController.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.home.room.list.home.invites
+
+import com.airbnb.epoxy.EpoxyModel
+import com.airbnb.epoxy.paging.PagedListEpoxyController
+import im.vector.app.core.utils.createUIHandler
+import im.vector.app.features.home.RoomListDisplayMode
+import im.vector.app.features.home.room.list.RoomListListener
+import im.vector.app.features.home.room.list.RoomSummaryItemFactory
+import im.vector.app.features.home.room.list.RoomSummaryItemPlaceHolder_
+import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
+import javax.inject.Inject
+
+class InvitesController @Inject constructor(
+ private val roomSummaryItemFactory: RoomSummaryItemFactory,
+) : PagedListEpoxyController(
+ // Important it must match the PageList builder notify Looper
+ modelBuildingHandler = createUIHandler()
+) {
+
+ var roomChangeMembershipStates: Map? = null
+ set(value) {
+ field = value
+ requestForcedModelBuild()
+ }
+
+ var listener: RoomListListener? = null
+
+ override fun buildItemModel(currentPosition: Int, item: RoomSummary?): EpoxyModel<*> {
+ item ?: return RoomSummaryItemPlaceHolder_().apply { id(currentPosition) }
+ return roomSummaryItemFactory.create(item, roomChangeMembershipStates.orEmpty(), emptySet(), RoomListDisplayMode.ROOMS, listener)
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesCounterController.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesCounterController.kt
new file mode 100644
index 0000000000..82a31d30a9
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesCounterController.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.home.room.list.home.invites
+
+import com.airbnb.epoxy.EpoxyController
+import im.vector.app.core.resources.StringProvider
+import javax.inject.Inject
+
+class InvitesCounterController @Inject constructor(
+ val stringProvider: StringProvider
+) : EpoxyController() {
+
+ private var count = 0
+ var clickListener: (() -> Unit)? = null
+
+ override fun buildModels() {
+ val host = this
+ if (count != 0) {
+ inviteCounterItem {
+ id("invites_counter")
+ invitesCount(host.count)
+ listener { host.clickListener?.invoke() }
+ }
+ }
+ }
+
+ fun submitData(count: Int?) {
+ this.count = count ?: 0
+ requestModelBuild()
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesFragment.kt
new file mode 100644
index 0000000000..74b46cec33
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesFragment.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.home.room.list.home.invites
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.airbnb.mvrx.fragmentViewModel
+import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.core.extensions.configureWith
+import im.vector.app.core.platform.VectorBaseFragment
+import im.vector.app.databinding.FragmentInvitesBinding
+import im.vector.app.features.analytics.plan.ViewRoom
+import im.vector.app.features.home.room.list.RoomListListener
+import im.vector.app.features.notifications.NotificationDrawerManager
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
+import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class InvitesFragment : VectorBaseFragment(), RoomListListener {
+
+ @Inject lateinit var controller: InvitesController
+ @Inject lateinit var notificationDrawerManager: NotificationDrawerManager
+
+ private val viewModel by fragmentViewModel(InvitesViewModel::class)
+
+ override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentInvitesBinding {
+ return FragmentInvitesBinding.inflate(inflater, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ setupToolbar(views.invitesToolbar)
+ .allowBack()
+
+ views.invitesRecycler.configureWith(controller)
+ controller.listener = this
+
+ viewModel.onEach(InvitesViewState::roomMembershipChanges) {
+ controller.roomChangeMembershipStates = it
+ }
+
+ viewModel.observeViewEvents {
+ when (it) {
+ is InvitesViewEvents.Failure -> showFailure(it.throwable)
+ is InvitesViewEvents.OpenRoom -> handleOpenRoom(it.roomSummary, it.shouldCloseInviteView)
+ InvitesViewEvents.Close -> handleClose()
+ }
+ }
+ }
+
+ private fun handleClose() {
+ requireActivity().finish()
+ }
+
+ private fun handleOpenRoom(roomSummary: RoomSummary, shouldCloseInviteView: Boolean) {
+ navigator.openRoom(
+ context = requireActivity(),
+ roomId = roomSummary.roomId,
+ isInviteAlreadyAccepted = true,
+ trigger = ViewRoom.Trigger.RoomList // #6508
+ )
+ if (shouldCloseInviteView) {
+ requireActivity().finish()
+ }
+ }
+
+ override fun invalidate(): Unit = withState(viewModel) { state ->
+ super.invalidate()
+
+ state.pagedList?.observe(viewLifecycleOwner) { list ->
+ controller.submitList(list)
+ }
+ }
+
+ override fun onRejectRoomInvitation(room: RoomSummary) {
+ notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(room.roomId) }
+ viewModel.handle(InvitesAction.RejectInvitation(room))
+ }
+
+ override fun onAcceptRoomInvitation(room: RoomSummary) {
+ notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(room.roomId) }
+ viewModel.handle(InvitesAction.AcceptInvitation(room))
+ }
+
+ override fun onJoinSuggestedRoom(room: SpaceChildInfo) = Unit
+
+ override fun onSuggestedRoomClicked(room: SpaceChildInfo) = Unit
+
+ override fun onRoomClicked(room: RoomSummary) = Unit
+
+ override fun onRoomLongClicked(room: RoomSummary): Boolean = false
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewEvents.kt
new file mode 100644
index 0000000000..d68577cf95
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewEvents.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.home.room.list.home.invites
+
+import im.vector.app.core.platform.VectorViewEvents
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
+
+sealed class InvitesViewEvents : VectorViewEvents {
+ data class Failure(val throwable: Throwable) : InvitesViewEvents()
+ data class OpenRoom(val roomSummary: RoomSummary, val shouldCloseInviteView: Boolean) : InvitesViewEvents()
+ object Close : InvitesViewEvents()
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewModel.kt
new file mode 100644
index 0000000000..b0d854be66
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewModel.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.home.room.list.home.invites
+
+import androidx.paging.PagedList
+import com.airbnb.mvrx.MavericksViewModelFactory
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
+import im.vector.app.core.platform.VectorViewModel
+import kotlinx.coroutines.launch
+import org.matrix.android.sdk.api.extensions.orFalse
+import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.room.RoomSortOrder
+import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
+import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
+import org.matrix.android.sdk.api.session.room.model.Membership
+import timber.log.Timber
+
+class InvitesViewModel @AssistedInject constructor(
+ @Assisted val initialState: InvitesViewState,
+ private val session: Session,
+) : VectorViewModel(initialState) {
+
+ private val pagedListConfig = PagedList.Config.Builder()
+ .setPageSize(10)
+ .setInitialLoadSizeHint(20)
+ .setEnablePlaceholders(true)
+ .setPrefetchDistance(10)
+ .build()
+
+ @AssistedFactory
+ interface Factory : MavericksAssistedViewModelFactory {
+ override fun create(initialState: InvitesViewState): InvitesViewModel
+ }
+
+ companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory()
+
+ init {
+ observeInvites()
+ }
+
+ override fun handle(action: InvitesAction) {
+ when (action) {
+ is InvitesAction.AcceptInvitation -> handleAcceptInvitation(action)
+ is InvitesAction.RejectInvitation -> handleRejectInvitation(action)
+ }
+ }
+
+ private fun handleRejectInvitation(action: InvitesAction.RejectInvitation) = withState { state ->
+ val roomId = action.roomSummary.roomId
+ val roomMembershipChange = state.roomMembershipChanges[roomId]
+ if (roomMembershipChange?.isInProgress().orFalse()) {
+ // Request already sent, should not happen
+ Timber.w("Try to left an already leaving or joining room. Should not happen")
+ return@withState
+ }
+
+ val shouldCloseInviteView = state.pagedList?.value?.size == 1
+
+ viewModelScope.launch {
+ try {
+ session.roomService().leaveRoom(roomId)
+ // We do not update the rejectingRoomsIds here, because, the room is not rejected yet regarding the sync data.
+ // Instead, we wait for the room to be rejected
+ // Known bug: if the user is invited again (after rejecting the first invitation), the loading will be displayed instead of the buttons.
+ // If we update the state, the button will be displayed again, so it's not ideal...
+ if (shouldCloseInviteView) {
+ _viewEvents.post(InvitesViewEvents.Close)
+ }
+ } catch (failure: Throwable) {
+ // Notify the user
+ _viewEvents.post(InvitesViewEvents.Failure(failure))
+ }
+ }
+ }
+
+ private fun handleAcceptInvitation(action: InvitesAction.AcceptInvitation) = withState { state ->
+ val roomId = action.roomSummary.roomId
+ val roomMembershipChange = state.roomMembershipChanges[roomId]
+ if (roomMembershipChange?.isInProgress().orFalse()) {
+ // Request already sent, should not happen
+ Timber.w("Try to join an already joining room. Should not happen")
+ return@withState
+ }
+ // close invites view when navigate to a room from the last one invite
+
+ val shouldCloseInviteView = state.pagedList?.value?.size == 1
+
+ _viewEvents.post(InvitesViewEvents.OpenRoom(action.roomSummary, shouldCloseInviteView))
+
+ // quick echo
+ setState {
+ copy(
+ roomMembershipChanges = roomMembershipChanges.mapValues {
+ if (it.key == roomId) {
+ ChangeMembershipState.Joining
+ } else {
+ it.value
+ }
+ }
+ )
+ }
+ }
+
+ private fun observeInvites() {
+ val builder = RoomSummaryQueryParams.Builder().also {
+ it.memberships = listOf(Membership.INVITE)
+ }
+ val pagedList = session.roomService().getPagedRoomSummariesLive(
+ queryParams = builder.build(),
+ pagedListConfig = pagedListConfig,
+ sortOrder = RoomSortOrder.ACTIVITY
+ )
+
+ setState {
+ copy(pagedList = pagedList)
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewState.kt
new file mode 100644
index 0000000000..708db29604
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewState.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.home.room.list.home.invites
+
+import androidx.lifecycle.LiveData
+import androidx.paging.PagedList
+import com.airbnb.mvrx.MavericksState
+import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
+
+data class InvitesViewState(
+ val pagedList: LiveData>? = null,
+ val roomMembershipChanges: Map = emptyMap(),
+) : MavericksState
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/layout/HomeLayoutSettingBottomDialogFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/layout/HomeLayoutSettingBottomDialogFragment.kt
new file mode 100644
index 0000000000..0c4d64a1cc
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/layout/HomeLayoutSettingBottomDialogFragment.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.home.room.list.home.layout
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.lifecycle.lifecycleScope
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.R
+import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
+import im.vector.app.databinding.BottomSheetHomeLayoutSettingsBinding
+import im.vector.app.features.home.room.list.home.HomeLayoutPreferencesStore
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class HomeLayoutSettingBottomDialogFragment : VectorBaseBottomSheetDialogFragment() {
+
+ @Inject lateinit var preferencesStore: HomeLayoutPreferencesStore
+
+ override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetHomeLayoutSettingsBinding {
+ return BottomSheetHomeLayoutSettingsBinding.inflate(inflater, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ viewLifecycleOwner.lifecycleScope.launch {
+ views.homeLayoutSettingsRecents.isChecked = preferencesStore.areRecentsEnabledFlow.first()
+ views.homeLayoutSettingsFilters.isChecked = preferencesStore.areFiltersEnabledFlow.first()
+
+ if (preferencesStore.isAZOrderingEnabledFlow.first()) {
+ views.homeLayoutSettingsSortName.isChecked = true
+ } else {
+ views.homeLayoutSettingsSortActivity.isChecked = true
+ }
+ }
+
+ views.homeLayoutSettingsRecents.setOnCheckedChangeListener { _, isChecked ->
+ setRecentsEnabled(isChecked)
+ }
+ views.homeLayoutSettingsFilters.setOnCheckedChangeListener { _, isChecked ->
+ setFiltersEnabled(isChecked)
+ }
+ views.homeLayoutSettingsSortGroup.setOnCheckedChangeListener { _, checkedId ->
+ setAzOrderingEnabled(checkedId == R.id.home_layout_settings_sort_name)
+ }
+ }
+
+ private fun setRecentsEnabled(isEnabled: Boolean) = lifecycleScope.launch {
+ preferencesStore.setRecentsEnabled(isEnabled)
+ }
+
+ private fun setFiltersEnabled(isEnabled: Boolean) = lifecycleScope.launch {
+ preferencesStore.setFiltersEnabled(isEnabled)
+ }
+
+ private fun setAzOrderingEnabled(isEnabled: Boolean) = lifecycleScope.launch {
+ preferencesStore.setAZOrderingEnabled(isEnabled)
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/recent/RecentRoomCarouselController.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/recent/RecentRoomCarouselController.kt
index 53832bbc74..ebec912779 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/recent/RecentRoomCarouselController.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/recent/RecentRoomCarouselController.kt
@@ -59,7 +59,13 @@ class RecentRoomCarouselController @Inject constructor(
data?.let { data ->
carousel {
id("recents_carousel")
- padding(Carousel.Padding(host.hPadding, host.itemSpacing))
+ padding(Carousel.Padding(
+ host.hPadding,
+ 0,
+ host.hPadding,
+ 0,
+ host.itemSpacing)
+ )
withModelsFrom(data) { roomSummary ->
val onClick = host.listener?.let { it::onRoomClicked }
val onLongClick = host.listener?.let { it::onRoomLongClicked }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/threads/list/views/ThreadListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/threads/list/views/ThreadListFragment.kt
index aaa9846c39..ef07067bac 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/threads/list/views/ThreadListFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/threads/list/views/ThreadListFragment.kt
@@ -26,6 +26,7 @@ import androidx.core.view.isVisible
import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
@@ -48,15 +49,17 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.api.util.MatrixItem
import javax.inject.Inject
-class ThreadListFragment @Inject constructor(
- private val avatarRenderer: AvatarRenderer,
- private val bugReporter: BugReporter,
- private val threadListController: ThreadListController,
- val threadListViewModelFactory: ThreadListViewModel.Factory
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class ThreadListFragment :
+ VectorBaseFragment(),
ThreadListController.Listener,
VectorMenuProvider {
+ @Inject lateinit var avatarRenderer: AvatarRenderer
+ @Inject lateinit var bugReporter: BugReporter
+ @Inject lateinit var threadListController: ThreadListController
+ @Inject lateinit var threadListViewModelFactory: ThreadListViewModel.Factory
+
private val threadListViewModel: ThreadListViewModel by fragmentViewModel()
private val threadListArgs: ThreadListArgs by args()
diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingFragment.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingFragment.kt
index d96410010e..779818b3d6 100644
--- a/vector/src/main/java/im/vector/app/features/location/LocationSharingFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingFragment.kt
@@ -31,6 +31,7 @@ import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.mapbox.mapboxsdk.maps.MapView
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.app.core.platform.VectorBaseFragment
@@ -53,15 +54,17 @@ import javax.inject.Inject
/**
* We should consider using SupportMapFragment for a out of the box lifecycle handling.
*/
-class LocationSharingFragment @Inject constructor(
- private val urlMapProvider: UrlMapProvider,
- private val avatarRenderer: AvatarRenderer,
- private val matrixItemColorProvider: MatrixItemColorProvider,
- private val vectorPreferences: VectorPreferences,
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class LocationSharingFragment :
+ VectorBaseFragment(),
LocationTargetChangeListener,
VectorBaseBottomSheetDialogFragment.ResultListener {
+ @Inject lateinit var urlMapProvider: UrlMapProvider
+ @Inject lateinit var avatarRenderer: AvatarRenderer
+ @Inject lateinit var matrixItemColorProvider: MatrixItemColorProvider
+ @Inject lateinit var vectorPreferences: VectorPreferences
+
private val viewModel: LocationSharingViewModel by fragmentViewModel()
private val locationSharingNavigator: LocationSharingNavigator by lazy { DefaultLocationSharingNavigator(activity) }
diff --git a/vector/src/main/java/im/vector/app/features/location/live/map/LiveLocationMapViewFragment.kt b/vector/src/main/java/im/vector/app/features/location/live/map/LiveLocationMapViewFragment.kt
index 85095e7c9f..942021dd64 100644
--- a/vector/src/main/java/im/vector/app/features/location/live/map/LiveLocationMapViewFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/location/live/map/LiveLocationMapViewFragment.kt
@@ -62,7 +62,8 @@ import javax.inject.Inject
* Screen showing a map with all the current users sharing their live location in a room.
*/
@AndroidEntryPoint
-class LiveLocationMapViewFragment @Inject constructor() : VectorBaseFragment() {
+class LiveLocationMapViewFragment :
+ VectorBaseFragment() {
@Inject lateinit var urlMapProvider: UrlMapProvider
@Inject lateinit var bottomSheetController: LiveLocationBottomSheetController
diff --git a/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewFragment.kt b/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewFragment.kt
index 8285d0156b..082cee02f0 100644
--- a/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewFragment.kt
@@ -27,6 +27,7 @@ import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import com.mapbox.mapboxsdk.maps.MapView
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.platform.VectorMenuProvider
@@ -43,12 +44,14 @@ import javax.inject.Inject
/*
* TODO Move locationPinProvider to a ViewModel
*/
-class LocationPreviewFragment @Inject constructor(
- private val urlMapProvider: UrlMapProvider,
- private val locationPinProvider: LocationPinProvider
-) : VectorBaseFragment(),
+@AndroidEntryPoint
+class LocationPreviewFragment :
+ VectorBaseFragment(),
VectorMenuProvider {
+ @Inject lateinit var urlMapProvider: UrlMapProvider
+ @Inject lateinit var locationPinProvider: LocationPinProvider
+
private val args: LocationSharingArgs by args()
private val viewModel: LocationPreviewViewModel by fragmentViewModel()
diff --git a/vector/src/main/java/im/vector/app/features/login/AbstractSSOLoginFragment.kt b/vector/src/main/java/im/vector/app/features/login/AbstractSSOLoginFragment.kt
index b18df6c9cf..ddab65d981 100644
--- a/vector/src/main/java/im/vector/app/features/login/AbstractSSOLoginFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/AbstractSSOLoginFragment.kt
@@ -85,7 +85,7 @@ abstract class AbstractSSOLoginFragment : AbstractLoginFragmen
private fun prefetchIfNeeded() {
withState(loginViewModel) { state ->
- if (state.loginMode.hasSso() && state.loginMode.ssoIdentityProviders().isNullOrEmpty()) {
+ if (state.loginMode.hasSso() && state.loginMode.ssoState().isFallback()) {
// in this case we can prefetch (not other cases for privacy concerns)
loginViewModel.getSsoUrl(
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
diff --git a/vector/src/main/java/im/vector/app/features/login/HomeServerConnectionConfigFactory.kt b/vector/src/main/java/im/vector/app/features/login/HomeServerConnectionConfigFactory.kt
index 955c3f7290..253c514e5a 100644
--- a/vector/src/main/java/im/vector/app/features/login/HomeServerConnectionConfigFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/login/HomeServerConnectionConfigFactory.kt
@@ -17,12 +17,13 @@
package im.vector.app.features.login
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
+import org.matrix.android.sdk.api.network.ssl.Fingerprint
import timber.log.Timber
import javax.inject.Inject
class HomeServerConnectionConfigFactory @Inject constructor() {
- fun create(url: String?): HomeServerConnectionConfig? {
+ fun create(url: String?, fingerprint: Fingerprint? = null): HomeServerConnectionConfig? {
if (url == null) {
return null
}
@@ -30,6 +31,13 @@ class HomeServerConnectionConfigFactory @Inject constructor() {
return try {
HomeServerConnectionConfig.Builder()
.withHomeServerUri(url)
+ .run {
+ if (fingerprint == null) {
+ this
+ } else {
+ withAllowedFingerPrints(listOf(fingerprint))
+ }
+ }
.build()
} catch (t: Throwable) {
Timber.e(t)
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginCaptchaFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginCaptchaFragment.kt
index 1b49f9bfa1..25403b06f3 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginCaptchaFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginCaptchaFragment.kt
@@ -33,6 +33,7 @@ import android.webkit.WebViewClient
import androidx.core.view.isVisible
import com.airbnb.mvrx.args
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.utils.AssetReader
import im.vector.app.databinding.FragmentLoginCaptchaBinding
@@ -51,9 +52,11 @@ data class LoginCaptchaFragmentArgument(
/**
* In this screen, the user is asked to confirm he is not a robot.
*/
-class LoginCaptchaFragment @Inject constructor(
- private val assetReader: AssetReader
-) : AbstractLoginFragment() {
+@AndroidEntryPoint
+class LoginCaptchaFragment :
+ AbstractLoginFragment() {
+
+ @Inject lateinit var assetReader: AssetReader
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginCaptchaBinding {
return FragmentLoginCaptchaBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt
index 9c598c400b..d61044d101 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt
@@ -28,6 +28,7 @@ import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.extensions.hidePassword
@@ -37,12 +38,10 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
-import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.failure.MatrixError
import org.matrix.android.sdk.api.failure.isInvalidPassword
import reactivecircus.flowbinding.android.widget.textChanges
-import javax.inject.Inject
/**
* In this screen:
@@ -52,7 +51,9 @@ import javax.inject.Inject
* In signup mode:
* - the user is asked for login and password
*/
-class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() {
+@AndroidEntryPoint
+class LoginFragment :
+ AbstractSSOLoginFragment() {
private var isSignupMode = false
@@ -100,13 +101,11 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment error("developer error")
- SignMode.SignUp -> SocialLoginButtonsView.Mode.MODE_SIGN_UP
- SignMode.SignIn,
- SignMode.SignInWithMatrixId -> SocialLoginButtonsView.Mode.MODE_SIGN_IN
- }
+ private fun ssoMode(state: LoginViewState) = when (state.signMode) {
+ SignMode.Unknown -> error("developer error")
+ SignMode.SignUp -> SocialLoginButtonsView.Mode.MODE_SIGN_UP
+ SignMode.SignIn,
+ SignMode.SignInWithMatrixId -> SocialLoginButtonsView.Mode.MODE_SIGN_IN
}
private fun submit() {
@@ -201,16 +200,13 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment
+ loginViewModel.getSsoUrl(
+ redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
+ deviceId = state.deviceId,
+ providerId = provider?.id
+ )
+ ?.let { openInCustomTab(it) }
}
} else {
views.loginSocialLoginContainer.isVisible = false
@@ -272,7 +268,6 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() {
+@AndroidEntryPoint
+class LoginGenericTextInputFormFragment :
+ AbstractLoginFragment() {
private val params: LoginGenericTextInputFormFragmentArgument by args()
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginMode.kt b/vector/src/main/java/im/vector/app/features/login/LoginMode.kt
index dd479c89c5..944b159441 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginMode.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginMode.kt
@@ -18,22 +18,21 @@ package im.vector.app.features.login
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
-import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
sealed class LoginMode : Parcelable { // Parcelable because persist state
@Parcelize object Unknown : LoginMode()
@Parcelize object Password : LoginMode()
- @Parcelize data class Sso(val ssoIdentityProviders: List?) : LoginMode()
- @Parcelize data class SsoAndPassword(val ssoIdentityProviders: List?) : LoginMode()
+ @Parcelize data class Sso(val ssoState: SsoState) : LoginMode()
+ @Parcelize data class SsoAndPassword(val ssoState: SsoState) : LoginMode()
@Parcelize object Unsupported : LoginMode()
}
-fun LoginMode.ssoIdentityProviders(): List? {
+fun LoginMode.ssoState(): SsoState {
return when (this) {
- is LoginMode.Sso -> ssoIdentityProviders
- is LoginMode.SsoAndPassword -> ssoIdentityProviders
- else -> null
+ is LoginMode.Sso -> ssoState
+ is LoginMode.SsoAndPassword -> ssoState
+ else -> SsoState.Fallback
}
}
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt
index 1ca0774f54..87df2d9483 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt
@@ -24,6 +24,7 @@ import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.extensions.hidePassword
@@ -36,12 +37,13 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.widget.textChanges
-import javax.inject.Inject
/**
* In this screen, the user is asked for email and new password to reset his password.
*/
-class LoginResetPasswordFragment @Inject constructor() : AbstractLoginFragment() {
+@AndroidEntryPoint
+class LoginResetPasswordFragment :
+ AbstractLoginFragment() {
// Show warning only once
private var showWarning = true
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordMailConfirmationFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordMailConfirmationFragment.kt
index 689e8ef6b7..c95a778860 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordMailConfirmationFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordMailConfirmationFragment.kt
@@ -22,15 +22,17 @@ import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.Fail
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.databinding.FragmentLoginResetPasswordMailConfirmationBinding
import org.matrix.android.sdk.api.failure.is401
-import javax.inject.Inject
/**
* In this screen, the user is asked to check their email and to click on a button once it's done.
*/
-class LoginResetPasswordMailConfirmationFragment @Inject constructor() : AbstractLoginFragment() {
+@AndroidEntryPoint
+class LoginResetPasswordMailConfirmationFragment :
+ AbstractLoginFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginResetPasswordMailConfirmationBinding {
return FragmentLoginResetPasswordMailConfirmationBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordSuccessFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordSuccessFragment.kt
index d2f1f620bd..e601f0512d 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordSuccessFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordSuccessFragment.kt
@@ -20,13 +20,15 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.databinding.FragmentLoginResetPasswordSuccessBinding
-import javax.inject.Inject
/**
* In this screen, we confirm to the user that his password has been reset.
*/
-class LoginResetPasswordSuccessFragment @Inject constructor() : AbstractLoginFragment() {
+@AndroidEntryPoint
+class LoginResetPasswordSuccessFragment :
+ AbstractLoginFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginResetPasswordSuccessBinding {
return FragmentLoginResetPasswordSuccessBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginServerSelectionFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginServerSelectionFragment.kt
index 6c49bafbba..0813957e99 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginServerSelectionFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginServerSelectionFragment.kt
@@ -20,16 +20,18 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.utils.openUrlInChromeCustomTab
import im.vector.app.databinding.FragmentLoginServerSelectionBinding
import me.gujun.android.span.span
-import javax.inject.Inject
/**
* In this screen, the user will choose between matrix.org, modular or other type of homeserver.
*/
-class LoginServerSelectionFragment @Inject constructor() : AbstractLoginFragment() {
+@AndroidEntryPoint
+class LoginServerSelectionFragment :
+ AbstractLoginFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginServerSelectionBinding {
return FragmentLoginServerSelectionBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginServerUrlFormFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginServerUrlFormFragment.kt
index 937e1bdf55..aabe0c2f2f 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginServerUrlFormFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginServerUrlFormFragment.kt
@@ -27,6 +27,7 @@ import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.google.android.material.textfield.TextInputLayout
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.resources.BuildMeta
@@ -43,9 +44,11 @@ import javax.inject.Inject
/**
* In this screen, the user is prompted to enter a homeserver url.
*/
-class LoginServerUrlFormFragment @Inject constructor(
- private val buildMeta: BuildMeta,
-) : AbstractLoginFragment() {
+@AndroidEntryPoint
+class LoginServerUrlFormFragment :
+ AbstractLoginFragment() {
+
+ @Inject lateinit var buildMeta: BuildMeta
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginServerUrlFormBinding {
return FragmentLoginServerUrlFormBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginSignUpSignInSelectionFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginSignUpSignInSelectionFragment.kt
index 1325ea37af..dbcf674847 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginSignUpSignInSelectionFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginSignUpSignInSelectionFragment.kt
@@ -22,16 +22,18 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.toReducedUrl
import im.vector.app.databinding.FragmentLoginSignupSigninSelectionBinding
-import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
-import javax.inject.Inject
+import im.vector.app.features.login.SocialLoginButtonsView.Mode
/**
* In this screen, the user is asked to sign up or to sign in to the homeserver.
*/
-class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractSSOLoginFragment() {
+@AndroidEntryPoint
+class LoginSignUpSignInSelectionFragment :
+ AbstractSSOLoginFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginSignupSigninSelectionBinding {
return FragmentLoginSignupSigninSelectionBinding.inflate(inflater, container, false)
@@ -73,16 +75,13 @@ class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractSSOLogi
when (state.loginMode) {
is LoginMode.SsoAndPassword -> {
views.loginSignupSigninSignInSocialLoginContainer.isVisible = true
- views.loginSignupSigninSocialLoginButtons.ssoIdentityProviders = state.loginMode.ssoIdentityProviders()?.sorted()
- views.loginSignupSigninSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
- override fun onProviderSelected(provider: SsoIdentityProvider?) {
- loginViewModel.getSsoUrl(
- redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
- deviceId = state.deviceId,
- providerId = provider?.id
- )
- ?.let { openInCustomTab(it) }
- }
+ views.loginSignupSigninSocialLoginButtons.render(state.loginMode.ssoState(), Mode.MODE_CONTINUE) { provider ->
+ loginViewModel.getSsoUrl(
+ redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
+ deviceId = state.deviceId,
+ providerId = provider?.id
+ )
+ ?.let { openInCustomTab(it) }
}
}
else -> {
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginSplashFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginSplashFragment.kt
index 7f5e87967b..6a8de819fd 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginSplashFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginSplashFragment.kt
@@ -23,6 +23,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.resources.BuildMeta
import im.vector.app.databinding.FragmentLoginSplashBinding
@@ -35,10 +36,12 @@ import javax.inject.Inject
/**
* In this screen, the user is viewing an introduction to what he can do with this application.
*/
-class LoginSplashFragment @Inject constructor(
- private val vectorPreferences: VectorPreferences,
- private val buildMeta: BuildMeta,
-) : AbstractLoginFragment() {
+@AndroidEntryPoint
+class LoginSplashFragment :
+ AbstractLoginFragment() {
+
+ @Inject lateinit var vectorPreferences: VectorPreferences
+ @Inject lateinit var buildMeta: BuildMeta
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginSplashBinding {
return FragmentLoginSplashBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt
index 40f72ccc99..79d06a0864 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt
@@ -223,7 +223,7 @@ class LoginViewModel @AssistedInject constructor(
setState {
copy(
signMode = SignMode.SignIn,
- loginMode = LoginMode.Sso(action.ssoIdentityProviders),
+ loginMode = LoginMode.Sso(action.ssoIdentityProviders.toSsoState()),
homeServerUrlFromUser = action.homeServerUrl,
homeServerUrl = action.homeServerUrl,
deviceId = action.deviceId
@@ -816,8 +816,8 @@ class LoginViewModel @AssistedInject constructor(
val loginMode = when {
// SSO login is taken first
data.supportedLoginTypes.contains(LoginFlowTypes.SSO) &&
- data.supportedLoginTypes.contains(LoginFlowTypes.PASSWORD) -> LoginMode.SsoAndPassword(data.ssoIdentityProviders)
- data.supportedLoginTypes.contains(LoginFlowTypes.SSO) -> LoginMode.Sso(data.ssoIdentityProviders)
+ data.supportedLoginTypes.contains(LoginFlowTypes.PASSWORD) -> LoginMode.SsoAndPassword(data.ssoIdentityProviders.toSsoState())
+ data.supportedLoginTypes.contains(LoginFlowTypes.SSO) -> LoginMode.Sso(data.ssoIdentityProviders.toSsoState())
data.supportedLoginTypes.contains(LoginFlowTypes.PASSWORD) -> LoginMode.Password
else -> LoginMode.Unsupported
}
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginWaitForEmailFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginWaitForEmailFragment.kt
index 07251f52a2..c13769e9e9 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginWaitForEmailFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginWaitForEmailFragment.kt
@@ -22,11 +22,11 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.args
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.databinding.FragmentLoginWaitForEmailBinding
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.failure.is401
-import javax.inject.Inject
@Parcelize
data class LoginWaitForEmailFragmentArgument(
@@ -36,7 +36,9 @@ data class LoginWaitForEmailFragmentArgument(
/**
* In this screen, the user is asked to check their emails.
*/
-class LoginWaitForEmailFragment @Inject constructor() : AbstractLoginFragment() {
+@AndroidEntryPoint
+class LoginWaitForEmailFragment :
+ AbstractLoginFragment() {
private val params: LoginWaitForEmailFragmentArgument by args()
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginWebFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginWebFragment.kt
index 0940eb50ee..b89018ccff 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginWebFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginWebFragment.kt
@@ -32,6 +32,7 @@ import android.webkit.WebView
import android.webkit.WebViewClient
import com.airbnb.mvrx.activityViewModel
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.utils.AssetReader
import im.vector.app.databinding.FragmentLoginWebBinding
@@ -47,9 +48,11 @@ import javax.inject.Inject
* This screen is displayed when the application does not support login flow or registration flow
* of the homeserver, as a fallback to login or to create an account.
*/
-class LoginWebFragment @Inject constructor(
- private val assetReader: AssetReader
-) : AbstractLoginFragment() {
+@AndroidEntryPoint
+class LoginWebFragment :
+ AbstractLoginFragment() {
+
+ @Inject lateinit var assetReader: AssetReader
private val softLogoutViewModel: SoftLogoutViewModel by activityViewModel()
diff --git a/vector/src/main/java/im/vector/app/features/login/SocialLoginButtonsView.kt b/vector/src/main/java/im/vector/app/features/login/SocialLoginButtonsView.kt
index 4f3b1237f2..816050420e 100644
--- a/vector/src/main/java/im/vector/app/features/login/SocialLoginButtonsView.kt
+++ b/vector/src/main/java/im/vector/app/features/login/SocialLoginButtonsView.kt
@@ -160,8 +160,11 @@ class SocialLoginButtonsView @JvmOverloads constructor(context: Context, attrs:
}
}
-fun SocialLoginButtonsView.render(ssoProviders: List?, mode: SocialLoginButtonsView.Mode, listener: (SsoIdentityProvider?) -> Unit) {
+fun SocialLoginButtonsView.render(state: SsoState, mode: SocialLoginButtonsView.Mode, listener: (SsoIdentityProvider?) -> Unit) {
this.mode = mode
- this.ssoIdentityProviders = ssoProviders?.sorted()
+ this.ssoIdentityProviders = when (state) {
+ SsoState.Fallback -> null
+ is SsoState.IdentityProviders -> state.providers.sorted()
+ }
this.listener = SocialLoginButtonsView.InteractionListener { listener(it) }
}
diff --git a/vector/src/main/java/im/vector/app/features/login/SsoState.kt b/vector/src/main/java/im/vector/app/features/login/SsoState.kt
new file mode 100644
index 0000000000..5f57780bd7
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/login/SsoState.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.login
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
+
+sealed interface SsoState : Parcelable {
+ @Parcelize
+ data class IdentityProviders(val providers: List) : SsoState
+
+ @Parcelize
+ object Fallback : SsoState
+
+ fun isFallback() = this == Fallback
+
+ fun providersOrNull() = when (this) {
+ Fallback -> null
+ is IdentityProviders -> providers.takeIf { it.isNotEmpty() }
+ }
+}
+
+fun List?.toSsoState() = this
+ ?.takeIf { it.isNotEmpty() }
+ ?.let { SsoState.IdentityProviders(it) }
+ ?: SsoState.Fallback
diff --git a/vector/src/main/java/im/vector/app/features/login/terms/LoginTermsFragment.kt b/vector/src/main/java/im/vector/app/features/login/terms/LoginTermsFragment.kt
index ce499f290b..a7a4274876 100755
--- a/vector/src/main/java/im/vector/app/features/login/terms/LoginTermsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/terms/LoginTermsFragment.kt
@@ -42,11 +42,12 @@ data class LoginTermsFragmentArgument(
/**
* LoginTermsFragment displays the list of policies the user has to accept.
*/
-class LoginTermsFragment @Inject constructor(
- private val policyController: PolicyController
-) : AbstractLoginFragment(),
+class LoginTermsFragment :
+ AbstractLoginFragment(),
PolicyController.PolicyControllerListener {
+ @Inject lateinit var policyController: PolicyController
+
private val params: LoginTermsFragmentArgument by args()
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginTermsBinding {
diff --git a/vector/src/main/java/im/vector/app/features/login2/AbstractLoginFragment2.kt b/vector/src/main/java/im/vector/app/features/login2/AbstractLoginFragment2.kt
deleted file mode 100644
index aae51fa959..0000000000
--- a/vector/src/main/java/im/vector/app/features/login2/AbstractLoginFragment2.kt
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * 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.features.login2
-
-import android.os.Bundle
-import android.view.View
-import androidx.annotation.CallSuper
-import androidx.transition.TransitionInflater
-import androidx.viewbinding.ViewBinding
-import com.airbnb.mvrx.activityViewModel
-import com.airbnb.mvrx.withState
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import im.vector.app.R
-import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
-import im.vector.app.core.platform.OnBackPressed
-import im.vector.app.core.platform.VectorBaseFragment
-import kotlinx.coroutines.CancellationException
-import org.matrix.android.sdk.api.failure.Failure
-
-/**
- * Parent Fragment for all the login/registration screens.
- */
-abstract class AbstractLoginFragment2 : VectorBaseFragment