diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 933c442501..be175c0436 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -40,7 +40,7 @@ jobs:
with:
name: vector-${{ matrix.target }}-debug
path: |
- vector/build/outputs/apk/*/debug/*.apk
+ vector-app/build/outputs/apk/*/debug/*.apk
release:
name: Build unsigned GPlay APKs
@@ -65,7 +65,7 @@ jobs:
with:
name: vector-gplay-release-unsigned
path: |
- vector/build/outputs/apk/*/release/*.apk
+ vector-app/build/outputs/apk/*/release/*.apk
exodus:
runs-on: ubuntu-latest
diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml
index d36f2d0765..8a892b9b15 100644
--- a/.github/workflows/danger.yml
+++ b/.github/workflows/danger.yml
@@ -11,7 +11,7 @@ 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:
diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml
index 544d9081f8..da70d13a86 100644
--- a/.github/workflows/quality.yml
+++ b/.github/workflows/quality.yml
@@ -7,7 +7,7 @@ on:
# Enrich gradle.properties for CI/CD
env:
- GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
+ GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -XX:MaxPermSize=512m -Dkotlin.daemon.jvm.options="-Xmx2g" -Dkotlin.incremental=false
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon
jobs:
@@ -27,7 +27,7 @@ jobs:
- uses: actions/checkout@v3
- name: Run knit
run: |
- ./gradlew knitCheck
+ ./gradlew knitCheck $CI_GRADLE_ARG_PROPERTIES
# Check the project: ktlint, detekt, lint
lint:
@@ -41,7 +41,7 @@ jobs:
- uses: actions/checkout@v3
- name: Run ktlint
run: |
- ./gradlew ktlintCheck --continue
+ ./gradlew ktlintCheck $CI_GRADLE_ARG_PROPERTIES --continue
- name: Run detekt
if: always()
run: |
@@ -49,8 +49,8 @@ jobs:
- name: Run lint
# Not always, if ktlint or detekt fail, avoid running the long lint check.
run: |
- ./gradlew lintGplayRelease $CI_GRADLE_ARG_PROPERTIES
- ./gradlew lintFdroidRelease $CI_GRADLE_ARG_PROPERTIES
+ ./gradlew vector-app:lintGplayRelease $CI_GRADLE_ARG_PROPERTIES
+ ./gradlew vector-app:lintFdroidRelease $CI_GRADLE_ARG_PROPERTIES
- name: Upload reports
if: always()
uses: actions/upload-artifact@v3
@@ -66,7 +66,7 @@ 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:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 2a89ed3040..cd7e26f3cf 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -1,9 +1,9 @@
name: Test
on:
- pull_request: {}
+ pull_request: { }
push:
- branches: [main, develop]
+ branches: [ main, develop ]
# Enrich gradle.properties for CI/CD
env:
@@ -48,11 +48,12 @@ jobs:
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
emulator-build: 7425822
- script: |
+ script: |
+ ./gradlew gatherGplayDebugStringTemplates $CI_GRADLE_ARG_PROPERTIES
./gradlew unitTestsWithCoverage $CI_GRADLE_ARG_PROPERTIES
./gradlew instrumentationTestsWithCoverage $CI_GRADLE_ARG_PROPERTIES
./gradlew generateCoverageReport $CI_GRADLE_ARG_PROPERTIES
-# NB: continue-on-error marks steps.tests.conclusion = 'success' but leaves stes.tests.outcome = 'failure'
+ # NB: continue-on-error marks steps.tests.conclusion = 'success' but leaves stes.tests.outcome = 'failure'
- name: Run all the codecoverage tests at once (retry if emulator failed)
uses: reactivecircus/android-emulator-runner@v2
if: always() && steps.tests.outcome == 'failure' # don't run if previous step succeeded.
@@ -65,15 +66,19 @@ jobs:
disable-animations: true
emulator-build: 7425822
script: |
+ ./gradlew gatherGplayDebugStringTemplates $CI_GRADLE_ARG_PROPERTIES
./gradlew unitTestsWithCoverage $CI_GRADLE_ARG_PROPERTIES
./gradlew instrumentationTestsWithCoverage $CI_GRADLE_ARG_PROPERTIES
./gradlew generateCoverageReport $CI_GRADLE_ARG_PROPERTIES
- - run: ./gradlew sonarqube $CI_GRADLE_ARG_PROPERTIES
- if: always() # we may have failed a previous step and retried, that's OK
+
+ # we may have failed a previous step and retried, that's OK
+ - name: Publish results to Sonar
env:
GITHUB_TOKEN: ${{ secrets.SONARQUBE_GITHUB_API_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
ORG_GRADLE_PROJECT_SONAR_LOGIN: ${{ secrets.SONAR_TOKEN }}
+ if: ${{ always() && env.GITHUB_TOKEN != '' && env.SONAR_TOKEN != '' && env.ORG_GRADLE_PROJECT_SONAR_LOGIN != '' }}
+ run: ./gradlew sonarqube $CI_GRADLE_ARG_PROPERTIES
- name: Format unit test results
if: always()
diff --git a/.github/workflows/triage-labelled.yml b/.github/workflows/triage-labelled.yml
index f478d2bd7b..174e3c54c0 100644
--- a/.github/workflows/triage-labelled.yml
+++ b/.github/workflows/triage-labelled.yml
@@ -142,32 +142,6 @@ jobs:
env:
PROJECT_ID: "PN_kwDOAM0swc2KCw"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
-
- move_threads_issues:
- name: A-Threads to Thread board
- runs-on: ubuntu-latest
- # Skip in forks
- if: >
- github.repository == 'vector-im/element-android' &&
- contains(github.event.issue.labels.*.name, 'A-Threads')
- steps:
- - uses: octokit/graphql-action@v2.x
- with:
- headers: '{"GraphQL-Features": "projects_next_graphql"}'
- query: |
- mutation add_to_project($projectid:ID!,$contentid:ID!) {
- addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
- projectNextItem {
- id
- }
- }
- }
- projectid: ${{ env.PROJECT_ID }}
- contentid: ${{ github.event.issue.node_id }}
- env:
- PROJECT_ID: "PN_kwDOAM0swc0rRA"
- GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
-
move_message_bubbles_issues:
name: A-Message-Bubbles to Message bubbles board
runs-on: ubuntu-latest
diff --git a/.github/workflows/triage-priority-bugs.yml b/.github/workflows/triage-priority-bugs.yml
index 6cde154370..e762102226 100644
--- a/.github/workflows/triage-priority-bugs.yml
+++ b/.github/workflows/triage-priority-bugs.yml
@@ -27,7 +27,7 @@ jobs:
- uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
with:
project: Android App Team
- column: P1
+ column: Important Issues & Topics (P1)
repo-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
P1_issues_to_crypto_team_workboard:
diff --git a/CHANGES.md b/CHANGES.md
index 4615ec8ff0..518bbd8b67 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,69 @@
+Changes in Element v1.4.36 (2022-09-10)
+=======================================
+
+New App Layout can be enabled in the Labs settings. Please give it a try!
+
+Features ✨
+----------
+ - Adds New App Layout into Labs ([#7038](https://github.com/vector-im/element-android/issues/7038))
+ - Try to detect devices that lack Opus encoder support, use bundled libopus library for those. ([#7010](https://github.com/vector-im/element-android/issues/7010))
+ - Suggest @room when @channel, @everyone, or @here is typed in composer ([#6529](https://github.com/vector-im/element-android/issues/6529))
+
+Bugfixes 🐛
+----------
+ - Fix long incremental sync. ([#6917](https://github.com/vector-im/element-android/issues/6917))
+ - Fix push with FCM ([#7068](https://github.com/vector-im/element-android/issues/7068))
+ - FTUE - Fixes optional email registration step always being mandatory ([#6969](https://github.com/vector-im/element-android/issues/6969))
+ - Fixes /addToSpace and /joinSpace commands showing invalid syntax warnings ([#6844](https://github.com/vector-im/element-android/issues/6844))
+ - Fix low occurrence crashes. ([#6967](https://github.com/vector-im/element-android/issues/6967))
+ - Fix crash when opening an unknown room ([#6978](https://github.com/vector-im/element-android/issues/6978))
+ - Fix crash on PIN code settings screen. ([#6979](https://github.com/vector-im/element-android/issues/6979))
+ - Fix autoplayed animated stickers ([#6982](https://github.com/vector-im/element-android/issues/6982))
+ - Catch race condition crash in voice recording ([#6989](https://github.com/vector-im/element-android/issues/6989))
+ - Fix invite to room when in a space buttons not working. ([#7054](https://github.com/vector-im/element-android/issues/7054))
+
+In development 🚧
+----------------
+ - Create DM room only on first message - Create the DM and navigate to the new room after sending an event ([#5525](https://github.com/vector-im/element-android/issues/5525))
+ - [App Layout] New empty states for home screen ([#6835](https://github.com/vector-im/element-android/issues/6835))
+ - [App Layout] Bottom navigation tabs are removed for new home screen ([#6565](https://github.com/vector-im/element-android/issues/6565))
+ - [App Layout] fixed space switching dialog measured with wrong height sometimes ([#6750](https://github.com/vector-im/element-android/issues/6750))
+ - [App Layout] Fabs doesn't go off screen anymore ([#6765](https://github.com/vector-im/element-android/issues/6765))
+ - [New Layout] Adds back navigation through spaces ([#6877](https://github.com/vector-im/element-android/issues/6877))
+ - [App Layout] new room invites screen ([#6889](https://github.com/vector-im/element-android/issues/6889))
+ - [App Layout] - Invites now show empty screen after you reject last invite ([#6876](https://github.com/vector-im/element-android/issues/6876))
+ - [App Layout] - space switcher now has empty state ([#6754](https://github.com/vector-im/element-android/issues/6754))
+ - [App Layout] - Improves Developer Mode Debug Button UX and adds it to New App Layout ([#6871](https://github.com/vector-im/element-android/issues/6871))
+ - [New Layout] Changes space sheet to accordion-style with expandable subspaces ([#6907](https://github.com/vector-im/element-android/issues/6907))
+ - [New Layout] Adds space invites ([#6924](https://github.com/vector-im/element-android/issues/6924))
+ - [App Layout] fixed invites count badge bottom margin on a home screen ([#6947](https://github.com/vector-im/element-android/issues/6947))
+ - [New Layout] Improves talkback accessibility ([#7016](https://github.com/vector-im/element-android/issues/7016))
+ - [New Layout] Changes space icon in fab and in release notes screen ([#7039](https://github.com/vector-im/element-android/issues/7039))
+ - [New Layout] Adds header to spaces bottom sheet ([#7040](https://github.com/vector-im/element-android/issues/7040))
+ - [App Layout] New App Layout is enabled by default (Edit: has to be enabled in Labs) ([#6958](https://github.com/vector-im/element-android/issues/6958))
+ - [App Layout] Obsolete settings are not shown when App Layout flag is enabled ([#6646](https://github.com/vector-im/element-android/issues/6646))
+ - [Devices Management] Session overview screen ([#6961](https://github.com/vector-im/element-android/issues/6961))
+ - [Devices Management] Refactor some code to improve testability ([#7043](https://github.com/vector-im/element-android/issues/7043))
+ - [Device Manager] Current Session Section ([#6902](https://github.com/vector-im/element-android/issues/6902))
+ - [Device Manager] Other Sessions Section ([#6945](https://github.com/vector-im/element-android/issues/6945))
+ - [Device Manager] Render Security Recommendations ([#6964](https://github.com/vector-im/element-android/issues/6964))
+
+Improved Documentation 📚
+------------------------
+ - Clarify that setting up a FCM Rewrite Proxy is not necessary for use of the UnifiedPush FCM distributor. ([#6727](https://github.com/vector-im/element-android/issues/6727))
+
+Other changes
+-------------
+ - Increase sticker size ([#6982](https://github.com/vector-im/element-android/issues/6982))
+ - Focus input field when editing homeserver address to speed up login and registration. ([#6926](https://github.com/vector-im/element-android/issues/6926))
+ - Log basic Http information in production. ([#6925](https://github.com/vector-im/element-android/issues/6925))
+ - Converts the vector module to a library with a parent vector-app application module ([#6407](https://github.com/vector-im/element-android/issues/6407))
+ - Creates a dedicated strings module ([#3955](https://github.com/vector-im/element-android/issues/3955))
+ - Remove FragmentModule and the Fragment factory. No need to Inject the constructor on your Fragment, just add @AndroidEntryPoint annotation and @Inject class members. ([#6894](https://github.com/vector-im/element-android/issues/6894))
+ - Small refactor of UnifiedPushHelper ([#6936](https://github.com/vector-im/element-android/issues/6936))
+ - CI: only run sonarqube task when token is known ([#7057](https://github.com/vector-im/element-android/issues/7057))
+
+
Changes in Element v1.4.34 (2022-08-23)
=======================================
diff --git a/FEATURES.md b/FEATURES.md
index f46b1248ec..f7786b5855 100644
--- a/FEATURES.md
+++ b/FEATURES.md
@@ -23,7 +23,6 @@ Here you can find some extra features and changes compared to Element Android (w
- Option to open a room without marking anything as read automatically
- Remember across app restarts which categories in the chat overview are expanded or collapsed
- Message count passed to the notification badge (visible next to the launcher icon on recent Android versions)
-- Bigger stickers
- Don't always repeat sender name for multiple stickers by the same sender
- Chat options menu: add entry for member list (to skip the step of clicking on the room name, to enter room settings), and hide the less frequently used invite option (which is still available from the member list)
- Smaller compose area (as before Element 1.0.12)
diff --git a/build.gradle b/build.gradle
index 38cbc3af0f..a40790d441 100644
--- a/build.gradle
+++ b/build.gradle
@@ -28,10 +28,11 @@ buildscript {
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 "com.likethesalad.android:stem-plugin:2.2.2"
+ 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"
+ classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
@@ -39,12 +40,12 @@ buildscript {
plugins {
// ktlint Plugin
- id "org.jlleitschuh.gradle.ktlint" version "10.3.0"
+ id "org.jlleitschuh.gradle.ktlint" version "11.0.0"
// Detekt
id "io.gitlab.arturbosch.detekt" version "1.21.0"
// Dependency Analysis
- id 'com.autonomousapps.dependency-analysis' version "1.12.0"
+ id 'com.autonomousapps.dependency-analysis' version "1.13.1"
}
// https://github.com/jeremylong/DependencyCheck
diff --git a/coverage.gradle b/coverage.gradle
index f335ed8063..716f9b7cc7 100644
--- a/coverage.gradle
+++ b/coverage.gradle
@@ -28,8 +28,8 @@ def initializeReport(report, projects, classExcludes) {
report.executionData {
fileTree(rootProject.rootDir.absolutePath).include(
- "**/build/**/*.exec",
- "**/build/outputs/code_coverage/**/coverage.ec",
+ "**/build/**/*.exec",
+ "**/build/outputs/code_coverage/**/coverage.ec",
)
}
report.reports {
@@ -74,18 +74,18 @@ def collectProjects(predicate) {
task generateCoverageReport(type: JacocoReport) {
outputs.upToDateWhen { false }
rootProject.apply plugin: 'jacoco'
- def projects = collectProjects { ['vector', 'matrix-sdk-android'].contains(it.name) }
+ def projects = collectProjects { ['vector-app', 'vector', 'matrix-sdk-android'].contains(it.name) }
initializeReport(it, projects, excludes)
}
task unitTestsWithCoverage(type: GradleBuild) {
// the 7.1.3 android gradle plugin has a bug where enableTestCoverage generates invalid coverage
- startParameter.projectProperties.coverage = [enableTestCoverage: false]
+ startParameter.projectProperties.coverage = [enableTestCoverage: false]
tasks = [':vector:testGplayDebugUnitTest', ':matrix-sdk-android:testDebugUnitTest']
}
task instrumentationTestsWithCoverage(type: GradleBuild) {
- startParameter.projectProperties.coverage = [enableTestCoverage: true]
+ startParameter.projectProperties.coverage = [enableTestCoverage: true]
startParameter.projectProperties['android.testInstrumentationRunnerArguments.notPackage'] = 'im.vector.app.ui'
- tasks = [':vector:connectedGplayDebugAndroidTest', 'matrix-sdk-android:connectedDebugAndroidTest']
+ tasks = [':vector-app:connectedGplayDebugAndroidTest', ':vector:connectedGplayDebugAndroidTest', 'matrix-sdk-android:connectedDebugAndroidTest']
}
diff --git a/dependencies.gradle b/dependencies.gradle
index 8a7260294b..77c601d7b6 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.157.0"
+def flipper = "0.163.0"
def epoxy = "4.6.2"
def mavericks = "2.7.0"
def glide = "4.13.2"
@@ -86,6 +86,8 @@ ext.libs = [
'material' : "com.google.android.material:material:1.6.1",
'appdistributionApi' : "com.google.firebase:firebase-appdistribution-api-ktx:$appDistribution",
'appdistribution' : "com.google.firebase:firebase-appdistribution:$appDistribution",
+ // Phone number https://github.com/google/libphonenumber
+ 'phonenumber' : "com.googlecode.libphonenumber:libphonenumber:8.12.54"
],
dagger : [
'dagger' : "com.google.dagger:dagger:$dagger",
@@ -105,6 +107,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/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/docs/nightly_build.md b/docs/nightly_build.md
index 7750e0466a..77cc676c7f 100644
--- a/docs/nightly_build.md
+++ b/docs/nightly_build.md
@@ -47,7 +47,7 @@ git checkout develop
mv towncrier.toml towncrier.toml.bak
sed 's/CHANGES\.md/CHANGES_NIGHTLY\.md/' towncrier.toml.bak > towncrier.toml
rm towncrier.toml.bak
-yes n | towncrier --version nightly
+yes n | towncrier build --version nightly
./gradlew assembleGplayNightly appDistributionUploadGplayNightly $CI_GRADLE_ARG_PROPERTIES
```
diff --git a/docs/unifiedpush.md b/docs/unifiedpush.md
index 2851644e66..9f44c6b2f9 100644
--- a/docs/unifiedpush.md
+++ b/docs/unifiedpush.md
@@ -18,7 +18,7 @@ The recently started UnifiedPush project is an Android protocol and library for
The *F-Droid* and *Gplay* flavors of Element Android support UnifiedPush, so the user can use any distributor installed on their devices. This would make it possible to have push notifications without depending on Google services or libraries. Currently, the main distributors are [ntfy](https://ntfy.sh) which does not require any setup (like manual registration) to use the public server and [NextPush](https://github.com/UP-NextPush/android), available as a nextcloud application.
-The *Gplay* variant uses a UnifiedPush library which basically embed a FCM distributor built into the application (so a user doesn't need to do anything other than install the app to get FCM notifications). This variant uses Google Services to receive notifications if the user has not installed any distributor.
+The *Gplay* variant uses a UnifiedPush library which basically embed a FCM distributor built into the application (so a user doesn't need to do anything other than install the app to get FCM notifications). This variant uses Google Services to receive notifications if the user has not installed any distributor. A [FCM Rewrite Proxy](https://unifiedpush.org/developers/embedded_fcm/#fcm-rewrite-proxy) is not required for Element Android's implementation of the FCM distributor - it will work with an existing Matrix push provider, such as [Sygnal](https://github.com/matrix-org/sygnal).
The *F-Droid* variant does not use this library to avoid any proprietary blob. It will use a polling service if the user has not installed any distributor.
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40104320.txt b/fastlane/metadata/android/cs-CZ/changelogs/40104320.txt
new file mode 100644
index 0000000000..578549ce6c
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40104320.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Opravy různých chyb a vylepšení stability.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40104340.txt b/fastlane/metadata/android/cs-CZ/changelogs/40104340.txt
new file mode 100644
index 0000000000..578549ce6c
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40104340.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Opravy různých chyb a vylepšení stability.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/de-DE/changelogs/40104260.txt b/fastlane/metadata/android/de-DE/changelogs/40104260.txt
new file mode 100644
index 0000000000..0298255dad
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+Die wichtigsten Änderungen in dieser Version: UnifiedPush wird unterstützt; Dies ermöglicht Push-Benachrichtigungen ohne FCM.
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/de-DE/changelogs/40104270.txt b/fastlane/metadata/android/de-DE/changelogs/40104270.txt
new file mode 100644
index 0000000000..50b5647608
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+Die wichtigsten Änderungen in dieser Version: Verschiedene Fehlerbehebungen und Stabilitätsverbesserungen.
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/de-DE/changelogs/40104280.txt b/fastlane/metadata/android/de-DE/changelogs/40104280.txt
new file mode 100644
index 0000000000..50b5647608
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40104280.txt
@@ -0,0 +1,2 @@
+Die wichtigsten Änderungen in dieser Version: Verschiedene Fehlerbehebungen und Stabilitätsverbesserungen.
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/de-DE/changelogs/40104300.txt b/fastlane/metadata/android/de-DE/changelogs/40104300.txt
new file mode 100644
index 0000000000..c906fedd54
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40104300.txt
@@ -0,0 +1,2 @@
+Die wichtigsten Änderungen in dieser Version: Verbessertes Anmelde- und Registrierungserlebnis.
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/de-DE/changelogs/40104310.txt b/fastlane/metadata/android/de-DE/changelogs/40104310.txt
new file mode 100644
index 0000000000..c906fedd54
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40104310.txt
@@ -0,0 +1,2 @@
+Die wichtigsten Änderungen in dieser Version: Verbessertes Anmelde- und Registrierungserlebnis.
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/de-DE/changelogs/40104320.txt b/fastlane/metadata/android/de-DE/changelogs/40104320.txt
new file mode 100644
index 0000000000..50b5647608
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40104320.txt
@@ -0,0 +1,2 @@
+Die wichtigsten Änderungen in dieser Version: Verschiedene Fehlerbehebungen und Stabilitätsverbesserungen.
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/de-DE/changelogs/40104340.txt b/fastlane/metadata/android/de-DE/changelogs/40104340.txt
new file mode 100644
index 0000000000..50b5647608
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40104340.txt
@@ -0,0 +1,2 @@
+Die wichtigsten Änderungen in dieser Version: Verschiedene Fehlerbehebungen und Stabilitätsverbesserungen.
+Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/en-US/changelogs/40104360.txt b/fastlane/metadata/android/en-US/changelogs/40104360.txt
new file mode 100644
index 0000000000..da03f28760
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40104360.txt
@@ -0,0 +1,3 @@
+New App Layout can be enabled in the Labs settings. Please give it a try!
+Fix issues about missing notification, and long incremental sync.
+Full changelog: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/et/changelogs/40104320.txt b/fastlane/metadata/android/et/changelogs/40104320.txt
new file mode 100644
index 0000000000..1df5ac4176
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40104320.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: erinevate vigade parandused ja stabiilsust edendavad kohendused.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/et/changelogs/40104340.txt b/fastlane/metadata/android/et/changelogs/40104340.txt
new file mode 100644
index 0000000000..1df5ac4176
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40104340.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: erinevate vigade parandused ja stabiilsust edendavad kohendused.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fa/changelogs/40104320.txt b/fastlane/metadata/android/fa/changelogs/40104320.txt
new file mode 100644
index 0000000000..29efb95925
--- /dev/null
+++ b/fastlane/metadata/android/fa/changelogs/40104320.txt
@@ -0,0 +1,2 @@
+تغییرات عمده در این نگارش: رفع اشکالهای مختلف و بهبودهای پایداری.
+گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fa/changelogs/40104340.txt b/fastlane/metadata/android/fa/changelogs/40104340.txt
new file mode 100644
index 0000000000..29efb95925
--- /dev/null
+++ b/fastlane/metadata/android/fa/changelogs/40104340.txt
@@ -0,0 +1,2 @@
+تغییرات عمده در این نگارش: رفع اشکالهای مختلف و بهبودهای پایداری.
+گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fr-FR/changelogs/40104320.txt b/fastlane/metadata/android/fr-FR/changelogs/40104320.txt
new file mode 100644
index 0000000000..fe61fd021c
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/40104320.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Plusieurs corrections de bogues et d’améliorations de stabilité.
+Intégralité des changements : https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/fr-FR/changelogs/40104340.txt b/fastlane/metadata/android/fr-FR/changelogs/40104340.txt
new file mode 100644
index 0000000000..fe61fd021c
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/40104340.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : Plusieurs corrections de bogues et d’améliorations de stabilité.
+Intégralité des changements : https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104100.txt b/fastlane/metadata/android/hu-HU/changelogs/40104100.txt
new file mode 100644
index 0000000000..97746bdcc6
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104100.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Görgetés a hangüzenetben. Különböző hibajavítások és stabilitásjavítások.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104110.txt b/fastlane/metadata/android/hu-HU/changelogs/40104110.txt
new file mode 100644
index 0000000000..25772a8ea1
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104110.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104120.txt b/fastlane/metadata/android/hu-HU/changelogs/40104120.txt
new file mode 100644
index 0000000000..79df59cf5e
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104120.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Lehetővé teszi a felhasználók számára, hogy offline jelenjenek meg, és audio lejátszót ad hozzá a hangmellékletekhez.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104130.txt b/fastlane/metadata/android/hu-HU/changelogs/40104130.txt
new file mode 100644
index 0000000000..79df59cf5e
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104130.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Lehetővé teszi a felhasználók számára, hogy offline jelenjenek meg, és audio lejátszót ad hozzá a hangmellékletekhez.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104140.txt b/fastlane/metadata/android/hu-HU/changelogs/40104140.txt
new file mode 100644
index 0000000000..2ea8acda97
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104140.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: A figyelmen kívül hagyott felhasználók kezelésének javítása. Különböző hibajavítások és stabilitásjavítások.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104160.txt b/fastlane/metadata/android/hu-HU/changelogs/40104160.txt
new file mode 100644
index 0000000000..d92018adb0
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104160.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: A titkosított üzenetek jobb kezelése. Különböző hibajavítások és stabilitásjavítások.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104180.txt b/fastlane/metadata/android/hu-HU/changelogs/40104180.txt
new file mode 100644
index 0000000000..25772a8ea1
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104180.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104190.txt b/fastlane/metadata/android/hu-HU/changelogs/40104190.txt
new file mode 100644
index 0000000000..25772a8ea1
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104190.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104200.txt b/fastlane/metadata/android/hu-HU/changelogs/40104200.txt
new file mode 100644
index 0000000000..25772a8ea1
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104200.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104220.txt b/fastlane/metadata/android/hu-HU/changelogs/40104220.txt
new file mode 100644
index 0000000000..25772a8ea1
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104220.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104230.txt b/fastlane/metadata/android/hu-HU/changelogs/40104230.txt
new file mode 100644
index 0000000000..25772a8ea1
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104230.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104240.txt b/fastlane/metadata/android/hu-HU/changelogs/40104240.txt
new file mode 100644
index 0000000000..25772a8ea1
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104240.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104250.txt b/fastlane/metadata/android/hu-HU/changelogs/40104250.txt
new file mode 100644
index 0000000000..25772a8ea1
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104250.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104260.txt b/fastlane/metadata/android/hu-HU/changelogs/40104260.txt
new file mode 100644
index 0000000000..54d881323f
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104260.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: UnifiedPush használata, és lehetővé teszi a felhasználó számára, hogy FCM nélkül tolja.
+Teljes változásnapló: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104270.txt b/fastlane/metadata/android/hu-HU/changelogs/40104270.txt
new file mode 100644
index 0000000000..25772a8ea1
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104270.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104280.txt b/fastlane/metadata/android/hu-HU/changelogs/40104280.txt
new file mode 100644
index 0000000000..25772a8ea1
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104280.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104300.txt b/fastlane/metadata/android/hu-HU/changelogs/40104300.txt
new file mode 100644
index 0000000000..9882e09368
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104300.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Lehetővé teszi a továbbfejlesztett bejelentkezési és regisztrációs utakat.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104310.txt b/fastlane/metadata/android/hu-HU/changelogs/40104310.txt
new file mode 100644
index 0000000000..9882e09368
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104310.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Lehetővé teszi a továbbfejlesztett bejelentkezési és regisztrációs utakat.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104320.txt b/fastlane/metadata/android/hu-HU/changelogs/40104320.txt
new file mode 100644
index 0000000000..25772a8ea1
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104320.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104340.txt b/fastlane/metadata/android/hu-HU/changelogs/40104340.txt
new file mode 100644
index 0000000000..25772a8ea1
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40104340.txt
@@ -0,0 +1,2 @@
+Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások.
+Teljes változásjegyzék: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/id/changelogs/40104320.txt b/fastlane/metadata/android/id/changelogs/40104320.txt
new file mode 100644
index 0000000000..1017951d47
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40104320.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Banyak perbaikan kutu dan perbaikan stabilitas.
+Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/id/changelogs/40104340.txt b/fastlane/metadata/android/id/changelogs/40104340.txt
new file mode 100644
index 0000000000..1017951d47
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40104340.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Banyak perbaikan kutu dan perbaikan stabilitas.
+Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/it-IT/changelogs/40104320.txt b/fastlane/metadata/android/it-IT/changelogs/40104320.txt
new file mode 100644
index 0000000000..556a6fc7ea
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40104320.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: varie correzioni di errori e miglioramenti della stabilità.
+Cronologia completa: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/it-IT/changelogs/40104340.txt b/fastlane/metadata/android/it-IT/changelogs/40104340.txt
new file mode 100644
index 0000000000..556a6fc7ea
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40104340.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: varie correzioni di errori e miglioramenti della stabilità.
+Cronologia completa: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40100100.txt b/fastlane/metadata/android/pl-PL/changelogs/40100100.txt
new file mode 100644
index 0000000000..7960e8a961
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40100100.txt
@@ -0,0 +1,2 @@
+Ta nowa wersja zawiera głównie poprawki błędów i ulepszenia. Wysyłanie wiadomości jest teraz znacznie szybsze.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.0.10
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40100110.txt b/fastlane/metadata/android/pl-PL/changelogs/40100110.txt
new file mode 100644
index 0000000000..ce95f4ab46
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40100110.txt
@@ -0,0 +1,2 @@
+Ta nowa wersja zawiera głównie ulepszenia interfejsu i doświadczenia użytkownika. Teraz możesz zapraszać znajomych i bardzo szybko tworzyć bezpośrednie rozmowy, skanując kody QR.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.0.11
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40100120.txt b/fastlane/metadata/android/pl-PL/changelogs/40100120.txt
new file mode 100644
index 0000000000..5b79301d97
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40100120.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Podgląd URL, nowa klawiatura Emoji, nowe możliwości ustawień pokoju i śnieg na Boże Narodzenie!
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.0.12
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40100130.txt b/fastlane/metadata/android/pl-PL/changelogs/40100130.txt
new file mode 100644
index 0000000000..6a8f3ac662
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40100130.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Podgląd URL, nowa klawiatura Emoji, nowe możliwości ustawień pokoju i śnieg na Boże Narodzenie!
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.0.13
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40100140.txt b/fastlane/metadata/android/pl-PL/changelogs/40100140.txt
new file mode 100644
index 0000000000..084f75dbf7
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40100140.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Edytuj uprawnienia do pokoju, automatyczny jasny/ciemny motyw i kilka poprawek błędów.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.0.14
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40100150.txt b/fastlane/metadata/android/pl-PL/changelogs/40100150.txt
new file mode 100644
index 0000000000..f2cb216b06
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40100150.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Obsługa logowania społecznościowego.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.0.15
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40100160.txt b/fastlane/metadata/android/pl-PL/changelogs/40100160.txt
new file mode 100644
index 0000000000..354d794070
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40100160.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Obsługa logowania społecznościowego.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases/tag/v1.0.15 i https://github.com/vector-im/element-android/releases/tag/v1.0.16
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40104300.txt b/fastlane/metadata/android/pl-PL/changelogs/40104300.txt
new file mode 100644
index 0000000000..d50c5a3f0e
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40104300.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Włącza ulepszone podróże w logowaniu i przy rejestracji.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40104310.txt b/fastlane/metadata/android/pl-PL/changelogs/40104310.txt
new file mode 100644
index 0000000000..d50c5a3f0e
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40104310.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Włącza ulepszone podróże w logowaniu i przy rejestracji.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40104320.txt b/fastlane/metadata/android/pl-PL/changelogs/40104320.txt
new file mode 100644
index 0000000000..005f2d2b71
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40104320.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Różne poprawki błędów i ulepszenia stabilności.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pl-PL/changelogs/40104340.txt b/fastlane/metadata/android/pl-PL/changelogs/40104340.txt
new file mode 100644
index 0000000000..e175a61725
--- /dev/null
+++ b/fastlane/metadata/android/pl-PL/changelogs/40104340.txt
@@ -0,0 +1,2 @@
+Główne zmiany w tej wersji: Rozmaite poprawki błędów i usprawnienia stabilności.
+Pełna lista zmian: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40104320.txt b/fastlane/metadata/android/pt-BR/changelogs/40104320.txt
new file mode 100644
index 0000000000..6e11e92579
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40104320.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Vários consertos de bugs e melhorias de estabilidade.
+Changelog completo: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40104340.txt b/fastlane/metadata/android/pt-BR/changelogs/40104340.txt
new file mode 100644
index 0000000000..6e11e92579
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40104340.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Vários consertos de bugs e melhorias de estabilidade.
+Changelog completo: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sk/changelogs/40104320.txt b/fastlane/metadata/android/sk/changelogs/40104320.txt
new file mode 100644
index 0000000000..50670f18c2
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40104320.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Rôzne opravy chýb a vylepšenia stability.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/sk/changelogs/40104340.txt b/fastlane/metadata/android/sk/changelogs/40104340.txt
new file mode 100644
index 0000000000..50670f18c2
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40104340.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Rôzne opravy chýb a vylepšenia stability.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/uk/changelogs/40104320.txt b/fastlane/metadata/android/uk/changelogs/40104320.txt
new file mode 100644
index 0000000000..9664c615c1
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40104320.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: Усунуто різні вади й поліпшено стабільність.
+Перелік усіх змін: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/uk/changelogs/40104340.txt b/fastlane/metadata/android/uk/changelogs/40104340.txt
new file mode 100644
index 0000000000..9664c615c1
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40104340.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: Усунуто різні вади й поліпшено стабільність.
+Перелік усіх змін: https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104080.txt b/fastlane/metadata/android/zh-CN/changelogs/40104080.txt
index 44d178cfce..09b5bf2cd3 100644
--- a/fastlane/metadata/android/zh-CN/changelogs/40104080.txt
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104080.txt
@@ -1,2 +1,2 @@
-此版本的主要变化:Thread timeline are now live and faster. 多个bug修复及稳定性改进。
+此版本的主要变化:消息列时间线 are now live and faster. 多个bug修复及稳定性改进。
完整更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104300.txt b/fastlane/metadata/android/zh-CN/changelogs/40104300.txt
new file mode 100644
index 0000000000..f6e5f8ddfc
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104300.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:启用改善的登录与注册流程。
+完整更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104310.txt b/fastlane/metadata/android/zh-CN/changelogs/40104310.txt
new file mode 100644
index 0000000000..f6e5f8ddfc
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104310.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:启用改善的登录与注册流程。
+完整更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-CN/changelogs/40104320.txt b/fastlane/metadata/android/zh-CN/changelogs/40104320.txt
new file mode 100644
index 0000000000..be6a485fb4
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/40104320.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:多个bug修复与稳定性改善。
+完整更改日志:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40104320.txt b/fastlane/metadata/android/zh-TW/changelogs/40104320.txt
new file mode 100644
index 0000000000..4bcca9a0b8
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40104320.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:多個臭蟲修復與穩定性改善。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40104340.txt b/fastlane/metadata/android/zh-TW/changelogs/40104340.txt
new file mode 100644
index 0000000000..4bcca9a0b8
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40104340.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:多個臭蟲修復與穩定性改善。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases
diff --git a/increment_version.sh b/increment_version.sh
index 49dbbb4f78..c7e9d7fbaf 100755
--- a/increment_version.sh
+++ b/increment_version.sh
@@ -43,7 +43,7 @@ fi
last_tag=`downstream_latest_tag`
-build_gradle="vector/build.gradle"
+build_gradle="vector-app/build.gradle"
get_prop() {
local prop="$1"
diff --git a/library/ui-strings/build.gradle b/library/ui-strings/build.gradle
new file mode 100644
index 0000000000..860fc3c980
--- /dev/null
+++ b/library/ui-strings/build.gradle
@@ -0,0 +1,22 @@
+plugins {
+ id 'com.android.library'
+ id 'kotlin-android'
+ id 'com.likethesalad.stem-library'
+}
+
+android {
+ compileSdk versions.compileSdk
+ defaultConfig {
+ minSdk versions.minSdk
+ targetSdk versions.targetSdk
+ }
+
+ compileOptions {
+ sourceCompatibility versions.sourceCompat
+ targetCompatibility versions.targetCompat
+ }
+
+ kotlinOptions {
+ jvmTarget = "11"
+ }
+}
diff --git a/library/ui-strings/src/main/AndroidManifest.xml b/library/ui-strings/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..deff03ee0a
--- /dev/null
+++ b/library/ui-strings/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/vector/src/main/res/values-ab/strings.xml b/library/ui-strings/src/main/res/values-ab/strings.xml
similarity index 100%
rename from vector/src/main/res/values-ab/strings.xml
rename to library/ui-strings/src/main/res/values-ab/strings.xml
diff --git a/vector/src/main/res/values-ang/strings.xml b/library/ui-strings/src/main/res/values-ang/strings.xml
similarity index 100%
rename from vector/src/main/res/values-ang/strings.xml
rename to library/ui-strings/src/main/res/values-ang/strings.xml
diff --git a/vector/src/main/res/values-ar/strings.xml b/library/ui-strings/src/main/res/values-ar/strings.xml
similarity index 100%
rename from vector/src/main/res/values-ar/strings.xml
rename to library/ui-strings/src/main/res/values-ar/strings.xml
diff --git a/vector/src/main/res/values-ar/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-ar/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-ar/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-ar/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-az/strings.xml b/library/ui-strings/src/main/res/values-az/strings.xml
similarity index 100%
rename from vector/src/main/res/values-az/strings.xml
rename to library/ui-strings/src/main/res/values-az/strings.xml
diff --git a/vector/src/main/res/values-az/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-az/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-az/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-az/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-b+sr+Latn/strings.xml b/library/ui-strings/src/main/res/values-b+sr+Latn/strings.xml
similarity index 100%
rename from vector/src/main/res/values-b+sr+Latn/strings.xml
rename to library/ui-strings/src/main/res/values-b+sr+Latn/strings.xml
diff --git a/vector/src/main/res/values-b+sr+Latn/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-b+sr+Latn/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-b+sr+Latn/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-b+sr+Latn/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-bg/strings.xml b/library/ui-strings/src/main/res/values-bg/strings.xml
similarity index 100%
rename from vector/src/main/res/values-bg/strings.xml
rename to library/ui-strings/src/main/res/values-bg/strings.xml
diff --git a/vector/src/main/res/values-bg/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-bg/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-bg/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-bg/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-bg/strings_sc.xml b/library/ui-strings/src/main/res/values-bg/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-bg/strings_sc.xml
rename to library/ui-strings/src/main/res/values-bg/strings_sc.xml
diff --git a/vector/src/main/res/values-bn-rBD/strings.xml b/library/ui-strings/src/main/res/values-bn-rBD/strings.xml
similarity index 100%
rename from vector/src/main/res/values-bn-rBD/strings.xml
rename to library/ui-strings/src/main/res/values-bn-rBD/strings.xml
diff --git a/vector/src/main/res/values-bn-rBD/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-bn-rBD/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-bn-rBD/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-bn-rBD/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-bn-rIN/strings.xml b/library/ui-strings/src/main/res/values-bn-rIN/strings.xml
similarity index 100%
rename from vector/src/main/res/values-bn-rIN/strings.xml
rename to library/ui-strings/src/main/res/values-bn-rIN/strings.xml
diff --git a/vector/src/main/res/values-bn-rIN/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-bn-rIN/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-bn-rIN/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-bn-rIN/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-bn/strings.xml b/library/ui-strings/src/main/res/values-bn/strings.xml
similarity index 100%
rename from vector/src/main/res/values-bn/strings.xml
rename to library/ui-strings/src/main/res/values-bn/strings.xml
diff --git a/vector/src/main/res/values-bs/strings.xml b/library/ui-strings/src/main/res/values-bs/strings.xml
similarity index 100%
rename from vector/src/main/res/values-bs/strings.xml
rename to library/ui-strings/src/main/res/values-bs/strings.xml
diff --git a/vector/src/main/res/values-bs/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-bs/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-bs/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-bs/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-ca/strings.xml b/library/ui-strings/src/main/res/values-ca/strings.xml
similarity index 98%
rename from vector/src/main/res/values-ca/strings.xml
rename to library/ui-strings/src/main/res/values-ca/strings.xml
index c98333ffdb..13a5b6c119 100644
--- a/vector/src/main/res/values-ca/strings.xml
+++ b/library/ui-strings/src/main/res/values-ca/strings.xml
@@ -2600,4 +2600,40 @@
\nPotser el servidor utilitzat no està configurat per mostrar mapes.
Obre configuració
Tots els xats
+ Preferències de disseny
+ Explora sales
+ Per estar més segur, verifica les teves sessions i tanca qualsevol sessió que no reconeguis o ja no utilitzis.
+ Altres sessions
+ Sessions
+ Obre la llista d\'espais
+ Crea un nou xat o sala
+ Gent
+ Preferits
+ No llegits
+ Tot
+ A - Z
+ Activitat
+ Ordena per
+ Mostra recents
+ Mostra filtres
+ Mostra totes les sessions (V2, WIP)
+ Crea sala
+ Inicia xat
+ Verifica la teva sessió actual per a missatges segurs millorats.
+ Verificada · Última activitat %1$s
+ No verificada · Última activitat %1$s
+ Veure-ho tot (%1$d)
+ Sessió actual
+ Veure detalls
+ Verifica sessió
+ La sessió actual està llesta per la missatgeria segura.
+ Sessió no verificada
+ Sessió verificada
+ Tipus de dispositiu desconegut
+ Ordinador
+ Web
+ Mòbil
+ Aquesta sala no s\'ha trobat.
+\nTorna-ho a provar més tard.%s
+ Invitacions
diff --git a/vector/src/main/res/values-ca/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-ca/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-ca/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-ca/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-cs/strings.xml b/library/ui-strings/src/main/res/values-cs/strings.xml
similarity index 98%
rename from vector/src/main/res/values-cs/strings.xml
rename to library/ui-strings/src/main/res/values-cs/strings.xml
index 960c5e0a40..b7bfeac444 100644
--- a/vector/src/main/res/values-cs/strings.xml
+++ b/library/ui-strings/src/main/res/values-cs/strings.xml
@@ -2650,4 +2650,40 @@
\nTento domovský server nemusí být nakonfigurován pro zobrazování map.
Otevřít nastavení
Všechny konverzace
+ Zobrazit všechny relace (V2, WIP)
+ V zájmu co nejlepšího zabezpečení ověřujte své relace a odhlašujte se ze všech relací, které již nepoznáváte nebo nepoužíváte.
+ Ostatní relace
+ Relace
+ Seznam otevřených prostorů
+ Vytvořit novou konverzaci nebo místnost
+ Lidé
+ Oblíbené
+ Nepřečtené
+ Všechny
+ A - Z
+ Aktivita
+ Seřadit podle
+ Zobrazit nedávné
+ Zobrazit filtry
+ Předvolby uspořádání
+ Prozkoumat místnosti
+ Vytvořit místnost
+ Zahájit konverzaci
+ Neověřeno · Poslední aktivita %1$s
+ Ověřeno · Poslední aktivita %1$s
+ Zobrazit všechny (%1$d)
+ Aktuální relace
+ Zobrazit podrobnosti
+ Ověřit relaci
+ Ověřte svou aktuální relaci pro vylepšené zabezpečené zasílání zpráv.
+ Vaše aktuální relace je připravena pro bezpečné zasílání zpráv.
+ Neověřená relace
+ Ověřená relace
+ Neznámý typ zařízení
+ Desktop
+ Web
+ Mobil
+ Je nám líto, tato místnost nebyla nalezena.
+\nZkuste to prosím později.%s
+ Pozvánky
diff --git a/vector/src/main/res/values-cs/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-cs/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-cs/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-cs/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-cs/strings_sc.xml b/library/ui-strings/src/main/res/values-cs/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-cs/strings_sc.xml
rename to library/ui-strings/src/main/res/values-cs/strings_sc.xml
diff --git a/vector/src/main/res/values-cy/strings.xml b/library/ui-strings/src/main/res/values-cy/strings.xml
similarity index 100%
rename from vector/src/main/res/values-cy/strings.xml
rename to library/ui-strings/src/main/res/values-cy/strings.xml
diff --git a/vector/src/main/res/values-cy/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-cy/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-cy/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-cy/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-da/strings.xml b/library/ui-strings/src/main/res/values-da/strings.xml
similarity index 100%
rename from vector/src/main/res/values-da/strings.xml
rename to library/ui-strings/src/main/res/values-da/strings.xml
diff --git a/vector/src/main/res/values-da/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-da/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-da/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-da/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-de/strings.xml b/library/ui-strings/src/main/res/values-de/strings.xml
similarity index 97%
rename from vector/src/main/res/values-de/strings.xml
rename to library/ui-strings/src/main/res/values-de/strings.xml
index 40473e9e27..8e502a6392 100644
--- a/vector/src/main/res/values-de/strings.xml
+++ b/library/ui-strings/src/main/res/values-de/strings.xml
@@ -320,7 +320,7 @@
Zu ungelesenen Nachrichten springen
Raum verlassen
Raum wirklich verlassen\?
- DIREKT-CHATS
+ Direktnachrichten
Einladen
Verbannen
Verbannung aufheben
@@ -543,21 +543,21 @@
Du hast aktuell keine Stickerpakete aktiviert.
\n
\nMöchtest du welche hinzufügen\?
- Account deaktivieren
- Meinen Account deaktivieren
+ Konto deaktivieren
+ Mein Konto deaktivieren
Sende Analysedaten
${app_name} sammelt anonyme Analysedaten um uns zu helfen, die App zu verbessern.
Ein benötigter Parameter fehlt.
Um %1$s weiter zu verwenden, musst die Geschäftsbedingungen begutachten und ihnen zustimmen.
Jetzt prüfen
- Account deaktivieren
+ Konto deaktivieren
Dies wird dein Konto permanent unbenutzbar machen. Du wirst dich nicht anmelden können und keiner wird denselben Nutzernamen erneut registrieren können. Du verlässt automatisch alle Räume, in denen du bist, und deine Kontoangaben werden vom Identitätsserver gelöscht. Diese Aktion ist unumkehrbar.
\n
\nDie Deaktivierung deines Konto wird standardmäßig keine deiner gesendeten Nachrichten löschen. Wenn du möchtest, dass auch deine Nachrichten gelöscht werden, wähle zusätzlich die Option unten.
\n
\nDie Sichtbarkeit deiner Nachrichten ist ähnlich wie bei E-Mails: Wenn deine Nachrichten gelöscht werden, bedeutet dies, dass von dir verschickte Nachrichten nicht mit neuen oder unregistrierten Nutzer geteilt werden. Aber registrierte Nutzer, die bereits Zugang zu diesen Nachrichten haben, behalten weiterhin Zugriff auf ihre Kopie.
Bitte alle Nachrichten, die ich gesendet habe, löschen, wenn mein Konto deaktiviert wird (Warnung: Unterhaltungen werden für zukünftige Nutzer unvollständig erscheinen)
- Account deaktivieren
+ Konto deaktivieren
Download
Schlüssel von deinen anderen Sitzungen erneut anfordern.
Bitte öffne ${app_name} auf einem anderen Gerät, das die Nachricht entschlüsseln kann, damit es die Schlüssel an diese Sitzung senden kann.
@@ -604,7 +604,7 @@
zusammenklappen
%1$s: %2$s
+%d
- Entfernen
+ Aus Unterhaltung entfernen
Linkvorschau im Chat aktivieren, falls dein Homeserver diese Funktion unterstützt.
Schreibbenachrichtigungen senden
Lasse andere Benutzer wissen, dass du tippst.
@@ -834,9 +834,9 @@
\nSitzungsname: %1$s
\nZuletzt gesehen: %2$s
\nWenn du nicht mit einer anderen Sitzung angemeldet bist, ignoriere diese Anfrage.
- Eine unverifizierte Sitzung fordert Verschlüsselungs-Schlüssel an.
-\nSitzungsname: %1$s
-\nZuletzt gesehen: %2$s
+ Eine nicht verifizierte Sitzung fordert Verschlüsselungs-Schlüssel an.
+\nSitzungsname: %1$s
+\nZuletzt gesehen: %2$s
\nWenn du nicht eine andere Sitzung angemeldet hast, ignoriere diese Anfrage.
Teilen
Ignorieren
@@ -1426,7 +1426,7 @@
Wähle deinen Wiederherstellungsschlüssel, gib ihn ein oder füge ihn aus der Zwischenablage ein
Konnte nicht auf gesicherten Speicher zugreifen
Unverschlüsselt
- Verschlüsselt von einem unbekannten Gerät
+ Verschlüsselt von einem nicht verifiziertem Gerät
Überprüfe, wo du angemeldet bist
Verifiziere alle deine Sitzungen, um sicherzustellen, dass dein Konto und deine Nachrichten sicher sind
Bestätige neue Anmeldung zu deinem Konto: %1$s
@@ -2572,4 +2572,54 @@
Wie lautet die Adresse deines Servers\?
Muss 8 oder mehr Zeichen umfassen
Wähle deinen Server
-
+
+ - %1$s und %2$d anderer
+ - %1$s und %2$d andere
+
+ A - Z
+ Aktivität
+ Sortierung
+ Filter anzeigen
+ Layouteinstellungen
+ Räume erkunden
+ Raum erstellen
+ Ungelesene
+ Personen
+ Schreibe deine erste Nachricht, um %s zur Konversation einzuladen
+ Alle Sitzungen anzeigen (V2, in Arbeit)
+ Für bestmögliche Sicherheit verifiziere deine Sitzungen und melde dich von allen ab, die du nicht erkennst oder nutzt.
+ Andere Sitzungen
+ Sitzungen
+ Space-Liste öffnen
+ Beginne ein Gespräch oder erstelle einen Raum
+ Favoriten
+ Alle
+ Karte laden nicht möglich
+\nDieser Heimserver könnte für die Kartendarstellung nicht konfiguriert sein.
+ Einstellungen öffnen
+ Dieser QR-Code ist fehlerhaft. Bitte versuche es mit einer anderen Methode.
+ Du wirst deinen verschlüsselten Nachrichtenverlauf nicht abrufen können. Um neu zu beginnen, setze deine Sicherung und Verifizierungsschlüssel zurück.
+ Verifizierung dieses Gerätes nicht möglich
+ Aktualisiere deine Daten …
+ Standort teilen
+ Du musst die Berechtigung erhalten, um deinen Live-Standort mit diesem Raum zu teilen.
+ Dir fehlt die Berechtigung, deinen Live-Standort teilen zu dürfen
+ Passwort zurückgesetzt
+ Code erneut schicken
+ Ein Code wurde an %s gesendet
+ Bestätigungscode
+ %s muss dein Konto verifizieren
+ Gib deine Telefonnummer ein
+ %s muss dein Konto verifizieren
+ Kontakt aufnehmen
+ Element Matrix Services (EMS) ist ein robuster und zuverlässiger Hosting-Dienst für schnelle und sichere Echtzeitkommunikation. Erfahre mehr unter element.io/ems
+ Willst du deinen eigenen Server betreiben\?
+ Web
+ Mobil
+ Entschuldigung, dieser Raum wurde nicht gefunden.
+\nBitte versuche es später erneut.%s
+ Einladungen
+ Nicht verifiziert · Letzte Aktivität %1$s
+ Verifiziere deine aktuelle Sitzung für besonders sichere Nachrichtenübertragung.
+ Nicht verifizierte Sitzung
+
\ No newline at end of file
diff --git a/vector/src/main/res/values-de/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-de/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-de/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-de/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-de/strings_sc.xml b/library/ui-strings/src/main/res/values-de/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-de/strings_sc.xml
rename to library/ui-strings/src/main/res/values-de/strings_sc.xml
diff --git a/vector/src/main/res/values-de/strings_sc_donottranslate.xml b/library/ui-strings/src/main/res/values-de/strings_sc_donottranslate.xml
similarity index 100%
rename from vector/src/main/res/values-de/strings_sc_donottranslate.xml
rename to library/ui-strings/src/main/res/values-de/strings_sc_donottranslate.xml
diff --git a/vector/src/main/res/values-el/strings.xml b/library/ui-strings/src/main/res/values-el/strings.xml
similarity index 100%
rename from vector/src/main/res/values-el/strings.xml
rename to library/ui-strings/src/main/res/values-el/strings.xml
diff --git a/vector/src/main/res/values-el/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-el/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-el/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-el/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-en-rGB/strings.xml b/library/ui-strings/src/main/res/values-en-rGB/strings.xml
similarity index 100%
rename from vector/src/main/res/values-en-rGB/strings.xml
rename to library/ui-strings/src/main/res/values-en-rGB/strings.xml
diff --git a/vector/src/main/res/values-en-rGB/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-en-rGB/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-en-rGB/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-en-rGB/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-eo/strings.xml b/library/ui-strings/src/main/res/values-eo/strings.xml
similarity index 100%
rename from vector/src/main/res/values-eo/strings.xml
rename to library/ui-strings/src/main/res/values-eo/strings.xml
diff --git a/vector/src/main/res/values-eo/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-eo/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-eo/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-eo/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-es-rMX/strings.xml b/library/ui-strings/src/main/res/values-es-rMX/strings.xml
similarity index 100%
rename from vector/src/main/res/values-es-rMX/strings.xml
rename to library/ui-strings/src/main/res/values-es-rMX/strings.xml
diff --git a/vector/src/main/res/values-es-rMX/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-es-rMX/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-es-rMX/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-es-rMX/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-es/strings.xml b/library/ui-strings/src/main/res/values-es/strings.xml
similarity index 100%
rename from vector/src/main/res/values-es/strings.xml
rename to library/ui-strings/src/main/res/values-es/strings.xml
diff --git a/vector/src/main/res/values-es/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-es/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-es/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-es/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-es/strings_sc.xml b/library/ui-strings/src/main/res/values-es/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-es/strings_sc.xml
rename to library/ui-strings/src/main/res/values-es/strings_sc.xml
diff --git a/vector/src/main/res/values-et/strings.xml b/library/ui-strings/src/main/res/values-et/strings.xml
similarity index 98%
rename from vector/src/main/res/values-et/strings.xml
rename to library/ui-strings/src/main/res/values-et/strings.xml
index 89460d921c..55fb9dfef0 100644
--- a/vector/src/main/res/values-et/strings.xml
+++ b/library/ui-strings/src/main/res/values-et/strings.xml
@@ -2591,4 +2591,40 @@
\nSee koduserver ei pruugi olla seadistatud kuvama kaarte.
Ava seadistused
Kõik vestlused
+ Näita kõiki sessioone (V2, WIP)
+ Parima turvalisuse nimel verifitseeri kõik oma sessioonid ning logi välja neist, mida sa enam ei kasuta.
+ Muud sessioonid
+ Sessionid
+ Ava kogukondade loend
+ Alusta uut vestlust või loo uus jututuba
+ Inimesed
+ Lemmikud
+ Lugemata
+ Kõik
+ A - Z
+ Aktiivsuse alusel
+ Järjestamisviis
+ Näita hiljutisi sõnumeid
+ Näita otsinguvalikuid
+ Paigutuse seadistused
+ Tutvu jututubadega
+ Loo jututuba
+ Alusta vestlust
+ Verifitseerimata · Viimati kasutusel %1$s
+ Verifitseeritud · Viimati kasutusel %1$s
+ Näita kõiki (%1$d)
+ Praegune sessioon
+ Vaata lisateavet
+ Verifitseeri sessioon
+ Turvalise sõnumivahetuse nimel palun verifitseeri oma praegune sessioon.
+ Sinu praegune sessioon on valmis turvaliseks sõnumivahetuseks.
+ Verifitseerimata sessioon
+ Verifitseeritud sessioon
+ Tundmatu seadme tüüp
+ Töölauarakendus
+ Veebiliides
+ Mobiiltelefon
+ Vabandust, aga seda jututuba ei õnnestu leida.
+\nPalun proovi hiljem uuesti.%s
+ Kutsed
diff --git a/vector/src/main/res/values-et/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-et/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-et/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-et/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-et/strings_sc.xml b/library/ui-strings/src/main/res/values-et/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-et/strings_sc.xml
rename to library/ui-strings/src/main/res/values-et/strings_sc.xml
diff --git a/vector/src/main/res/values-eu/strings.xml b/library/ui-strings/src/main/res/values-eu/strings.xml
similarity index 100%
rename from vector/src/main/res/values-eu/strings.xml
rename to library/ui-strings/src/main/res/values-eu/strings.xml
diff --git a/vector/src/main/res/values-eu/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-eu/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-eu/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-eu/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-eu/strings_sc.xml b/library/ui-strings/src/main/res/values-eu/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-eu/strings_sc.xml
rename to library/ui-strings/src/main/res/values-eu/strings_sc.xml
diff --git a/vector/src/main/res/values-fa/strings.xml b/library/ui-strings/src/main/res/values-fa/strings.xml
similarity index 98%
rename from vector/src/main/res/values-fa/strings.xml
rename to library/ui-strings/src/main/res/values-fa/strings.xml
index c534356e92..e104225389 100644
--- a/vector/src/main/res/values-fa/strings.xml
+++ b/library/ui-strings/src/main/res/values-fa/strings.xml
@@ -2600,4 +2600,40 @@
\nشاید این کارساز خانگی برای نمایش نقشهها پیکربندی نشده باشد.
گشودن تنظیمات
تمامی گپها
+ نمایش تمامی نشستها (ن۲، دحت)
+ برای امنیت بیشتر، نشستهایتان را تأیید و از هر نشستی که تشخیصش نمیدهید یا دیگر استفاده نمیکنید خارج شوید.
+ دیگر نشستها
+ نشستها
+ گشودن سیاههٔ فضاها
+ ایجاد اتاق یا گفتوگویی جدید
+ افراد
+ محبوبها
+ نخواندهها
+ همه
+ آ - ی
+ فعّالیت
+ چینش بر اساس
+ نمایش تازگیها
+ نمایش پالایهها
+ ترجیحات چینش
+ کاوش اتاقها
+ ایجاد اتاق
+ آغاز گپ
+ تأیید نشده · آخرین فعّالیت %1$s
+ تأیید شده · آخرین فعّالیت %1$s
+ دیدن همه (%1$d)
+ نشست کنونی
+ دیدن جزییات
+ تأیید نشست
+ نشست کنونیتان را برای پیامرسانی امن بهبود یافته تأیید کنید.
+ نشست کنونیتان برای پیامرسانی امن آماده است.
+ نشست تأیید نشده
+ نشست تأیید شده
+ گونهٔ افزاره ناشناخته
+ میزکار
+ وب
+ تلفن همراه
+ متأسفانه این اتاق پیدا نشد.
+\nلطفاً بعداً دوباره تلاش کنید.%s
+ دعوتها
diff --git a/vector/src/main/res/values-fa/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-fa/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-fa/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-fa/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-fa/strings_sc.xml b/library/ui-strings/src/main/res/values-fa/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-fa/strings_sc.xml
rename to library/ui-strings/src/main/res/values-fa/strings_sc.xml
diff --git a/vector/src/main/res/values-fi/strings.xml b/library/ui-strings/src/main/res/values-fi/strings.xml
similarity index 100%
rename from vector/src/main/res/values-fi/strings.xml
rename to library/ui-strings/src/main/res/values-fi/strings.xml
diff --git a/vector/src/main/res/values-fi/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-fi/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-fi/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-fi/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-fr-rCA/strings.xml b/library/ui-strings/src/main/res/values-fr-rCA/strings.xml
similarity index 100%
rename from vector/src/main/res/values-fr-rCA/strings.xml
rename to library/ui-strings/src/main/res/values-fr-rCA/strings.xml
diff --git a/vector/src/main/res/values-fr-rCA/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-fr-rCA/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-fr-rCA/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-fr-rCA/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-fr/strings.xml b/library/ui-strings/src/main/res/values-fr/strings.xml
similarity index 98%
rename from vector/src/main/res/values-fr/strings.xml
rename to library/ui-strings/src/main/res/values-fr/strings.xml
index c5a7a7b2b7..55b5f88134 100644
--- a/vector/src/main/res/values-fr/strings.xml
+++ b/library/ui-strings/src/main/res/values-fr/strings.xml
@@ -2600,4 +2600,40 @@
\nCe serveur d’accueil n’a peut-être pas été configuré pour afficher les cartes.
Ouvrir les paramètres
Toutes les conversations
+ Afficher toutes les sessions (V2, en cours)
+ Pour une meilleure sécurité, vérifiez vos sessions et déconnectez toutes les sessions que vous ne connaissez pas ou que vous n’utilisez plus.
+ Autres sessions
+ Sessions
+ Ouvrir la liste des espaces
+ Créer une nouvelle conversation ou salon
+ Personnes
+ Favoris
+ Non lus
+ Tous
+ A - Z
+ Activité
+ Trier par
+ Afficher les récents
+ Afficher les filtres
+ Préférences de présentation
+ Parcourir les salons
+ Créer un salon
+ Commencer une discussion
+ Non vérifiée · Dernière activité %1$s
+ Vérifié · Dernière activité %1$s
+ Tout voir (%1$d)
+ Cette session
+ Voir les détails
+ Vérifier la session
+ Vérifiez votre session pour une sécurité renforcée de votre messagerie.
+ Votre session est prête pour l’envoi de messages sécurisés.
+ Session non vérifiée
+ Session vérifiée
+ Type de périphérique inconnu
+ Ordinateur
+ Web
+ Portable
+ Désolé, impossible de trouver ce salon.
+\nVeuillez réessayer plus tard.%s
+ Invitations
diff --git a/vector/src/main/res/values-fr/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-fr/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-fr/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-fr/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-fr/strings_sc.xml b/library/ui-strings/src/main/res/values-fr/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-fr/strings_sc.xml
rename to library/ui-strings/src/main/res/values-fr/strings_sc.xml
diff --git a/vector/src/main/res/values-fy/strings.xml b/library/ui-strings/src/main/res/values-fy/strings.xml
similarity index 100%
rename from vector/src/main/res/values-fy/strings.xml
rename to library/ui-strings/src/main/res/values-fy/strings.xml
diff --git a/vector/src/main/res/values-fy/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-fy/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-fy/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-fy/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-ga/strings.xml b/library/ui-strings/src/main/res/values-ga/strings.xml
similarity index 100%
rename from vector/src/main/res/values-ga/strings.xml
rename to library/ui-strings/src/main/res/values-ga/strings.xml
diff --git a/vector/src/main/res/values-ga/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-ga/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-ga/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-ga/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-gl/strings.xml b/library/ui-strings/src/main/res/values-gl/strings.xml
similarity index 100%
rename from vector/src/main/res/values-gl/strings.xml
rename to library/ui-strings/src/main/res/values-gl/strings.xml
diff --git a/vector/src/main/res/values-gl/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-gl/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-gl/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-gl/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-hr/strings.xml b/library/ui-strings/src/main/res/values-hr/strings.xml
similarity index 100%
rename from vector/src/main/res/values-hr/strings.xml
rename to library/ui-strings/src/main/res/values-hr/strings.xml
diff --git a/vector/src/main/res/values-hr/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-hr/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-hr/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-hr/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-hu/strings.xml b/library/ui-strings/src/main/res/values-hu/strings.xml
similarity index 98%
rename from vector/src/main/res/values-hu/strings.xml
rename to library/ui-strings/src/main/res/values-hu/strings.xml
index a35595fb36..af8bf26b2e 100644
--- a/vector/src/main/res/values-hu/strings.xml
+++ b/library/ui-strings/src/main/res/values-hu/strings.xml
@@ -157,7 +157,7 @@
%s megváltoztatta a szerver ACL-eket ehhez a szobához.
• IP címet hosztnévként használó szerverek tiltva vannak.
• IP címet hosztnévként használó szerverek engedélyezve vannak.
- • Engedélyezve vannak azok a szerverek, amik illeszkednek erre: %s
+ • Engedélyezve vannak azok a szerverek, amik illeszkednek erre: %s.
• Tiltva vannak azok a szerverek, amik illeszkednek erre: %s
Beállítottad a szerver ACL-eket ehhez a szobához.
%s beállította a szerver ACL-eket ehhez a szobához.
@@ -2600,4 +2600,40 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze
%1$s és %2$s
Minden beszélgetés
+ Nem ellenőrzött - Utolsó aktivitás %1$s
+ Ellenőrzött - Utolsó tevékenység %1$s
+ Összes megtekintése (%1$d)
+ Jelenlegi munkamenet
+ Részletek megtekintése
+ Munkamenet hitelesítése
+ Az aktuális munkamenet készen áll a biztonságos üzenetküldésre.
+ Az aktuális munkamenet készen áll a biztonságos üzenetküldésre.
+ Ellenőrizetlen munkamenet
+ Ellenőrzött munkamenet
+ Ismeretlen eszköztípus
+ Asztali
+ Web
+ Mobil
+ Minden munkamenet megjelenítése (V2, WIP)
+ A legjobb biztonság érdekében ellenőrizd a munkameneteket, és jelentkezz ki minden olyan munkamenetből, melyet már nem ismersz fel vagy nem használsz.
+ Más munkamenetek
+ Munkamenetek
+ Nyitott területek listája
+ Új beszélgetés vagy szoba létrehozása
+ Résztvevők
+ Kedvencek
+ Olvasatlan
+ Mind
+ Sajnáljuk, ez a szoba nem található.
+\nKérjük, próbáld meg később újra.%s
+ Meghívók
+ A - Z
+ Aktivitás
+ Rendezés
+ Legfrissebbek megjelenítése
+ Szűrők megjelenítése
+ Elrendezési beállítások
+ Szobák felfedezése
+ Szoba létrehozása
+ Chat indítása
diff --git a/vector/src/main/res/values-hu/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-hu/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-hu/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-hu/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-hu/strings_sc.xml b/library/ui-strings/src/main/res/values-hu/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-hu/strings_sc.xml
rename to library/ui-strings/src/main/res/values-hu/strings_sc.xml
diff --git a/vector/src/main/res/values-in/strings.xml b/library/ui-strings/src/main/res/values-in/strings.xml
similarity index 96%
rename from vector/src/main/res/values-in/strings.xml
rename to library/ui-strings/src/main/res/values-in/strings.xml
index 4dea8c3f92..d1e68b4529 100644
--- a/vector/src/main/res/values-in/strings.xml
+++ b/library/ui-strings/src/main/res/values-in/strings.xml
@@ -47,8 +47,8 @@
Hanya kontak Matrix
Ruangan
Laporan kutu
- Aplikasi gagal saat terakhir digunakan. Apakah Anda ingin membuka halaman laporan kegagalan\?
- Gabung di Ruangan
+ Aplikasi mogok saat terakhir digunakan. Apakah Anda ingin membuka halaman laporan kemogokan\?
+ Bergabung ke Ruangan
Mulai Panggilan Suara
Masuk
Mulai Panggilan Video
@@ -69,7 +69,7 @@
TIDAK
Lanjut
Hapus
- Gabung
+ Bergabung
Tolak
Nanti
Kirim catatan gangguan
@@ -88,7 +88,7 @@
Kirim tampilan layar
Mohon uraikan kutu tersebut. Apa yang Anda lakukan\? Apa yang Anda harapkan terjadi\? Apa yang sebenarnya terjadi\?
Catatan dari klien akan dikirim bersama laporan gangguan ini untuk mendalami kendala yang Anda temukan. Laporan gangguan ini, termasuk catatan dan tangkapan layar, tidak akan terlihat secara umum. Jika Anda hanya ingin mengirimkan tulisan di atas, silakan hapus centang:
- Sepertinya Anda mengguncang ponsel akibat frustrasi. Apakah Anda ingin membuka halaman laporan kutu\?
+ Sepertinya Anda mengguncang ponsel akibat emosi. Apakah Anda ingin membuka halaman laporan kutu\?
Pengiriman laporan kutu gagal (%s)
Kemajuan (%s%%)
Nama Pengguna
@@ -122,9 +122,9 @@
Kirim Sticker
Ambil foto
Ambil video
- Saat ini Anda belum memiliki pak stiker.
+ Saat ini Anda belum memiliki paket stiker apa pun.
\n
-\nMau tambah sekarang\?
+\nIngin tambah sekarang\?
Maaf, tidak ada aplikasi eksternal yang mendukung apa yang ingin dilakukan.
Meminta ulang kunci enkripsi dari perangkat Anda yang lain.
Jalankan ${app_name} di perangkat yang dapat mendekripsi pesan tersebut agar kunci dapat dikirim ke perangkat ini.
@@ -146,8 +146,8 @@
Sembunyikan semua pesan dari pengguna ini
Tunjukkan semua pesan dari pengguna ini
Sebut
- Anda tidak akan dapat mengembalikan perubahan ini setelah Anda mengangkat pengguna ini agar memiliki kuasa yang setara dengan Anda.
-\nApakah anda yakin untuk melanjutkan\?
+ Anda tidak akan dapat mengembalikan perubahan ini setelah Anda mengangkat pengguna ini agar memiliki daya yang setara dengan Anda.
+\nApakah Anda yakin untuk melanjutkan\?
Melakukan pencekalan pengguna akan mengeluarkannya dari ruangan ini dan mencegahnya untuk kembali masuk.
Gagal terjawab oleh pihak lain.
%s sedang mengetik…
@@ -210,7 +210,7 @@
Tidak dapat membuat widget.
Gagal mengirim permohonan.
Tingkat energi harus bilangan positif.
- Anda tidak tergabung dengan ruangan ini.
+ Anda tidak di ruangan ini.
Anda tidak memiliki permisi untuk melakukan itu di ruangan ini.
Tidak ada room_id dalam permohonan.
Tidak ada user_id dalam permohonan.
@@ -228,7 +228,7 @@
Menghapus cekalan pengguna dengan id berikut
Tentukan tingkat kuasa seorang pengguna
Undang pengguna dengan id berikut bergabung ke ruangan ini
- Gabung ke ruangan dengan alamat berikut
+ Bergabung ke ruangan dengan alamat berikut
Tinggalkan ruang
Tentukan topik ruang
Keluarkan pengguna dengan id berikut
@@ -251,10 +251,10 @@
Nonaktifkan Akun
Ini akan mengakibatkan akun Anda tidak dapat digunakan secara permanen. Anda tidak akan dapat masuk dan orang lain tidak dapat mendaftar ulang dengan ID pengguna yang sama. Ini akan mengakibatkan akun Anda keluar dari semua ruangan tempat Anda berpartisipasi serta menghapus semua detail akun dari server identitas Anda. Tindakan ini tidak dapat diubah.
\n
-\nMenonaktifkan akun Anda tidak membuat kami melupakan pesan-pesan yang Anda kirim secara default. Jika Anda ingin kami melupakan pesan-pesan Anda, mohon centang kotak berikut.
+\nMenonaktifkan akun Anda tidak membuat kami melupakan pesan-pesan yang Anda kirim secara bawaan. Jika Anda ingin kami melupakan pesan-pesan Anda, mohon centang kotak berikut.
\n
\nKeterbacaan pesan di Matrix serupa dengan email. Dengan kami melupakan pesan-pesan Anda berarti pesan-pesan yang Anda kirim tidak akan dibagikan kepada pengguna baru ataupun yang belum terdaftar, tetapi pengguna yang terdaftar yang mempunyai mengakses pesan-pesan tersebut masih dapat mengakses salinan mereka.
- Mohon lupakan semua pesan yang telah saya kirim ketika akun saya dideaktivasi (Peringatan: ini akan mengakibatkan pengguna di masa depan melihat percakapan yang tidak lengkap)
+ Mohon lupakan semua pesan yang telah saya kirim ketika akun saya dinonaktifkan (Peringatan: ini akan mengakibatkan pengguna di masa depan melihat percakapan yang tidak lengkap)
Nonaktifkan Akun
Mohon masukkan kata sandi Anda.
Ruangan ini telah berubah dan tidak lagi aktif.
@@ -276,7 +276,7 @@
Jangan kirim pesan terenkripsi ke perangkat yang tidak terverifikasi dari perangkat ini.
TIDAK terverifikasi
Verifikasi
- Untuk memastikan perangkat dapat dipercaya, mohon kontak pengguna dengan medium lain (misalnya tatap muka atau panggilan telepon) dan tanya apakah kunci yang mereka lihat di Pengaturan Pengguna untuk perangkat ini cocok dengan kunci berikut:
+ Konfirmasi dengan membandingkan berikut ini dengan Pengaturan Pengguna di sesi Anda yang lain:
Apabila cocok, tekan tombol verifikasi berikut.
Apabila tidak, seseorang sedang menyadap perangkat ini dan mungkin perlu diblokir.
Di masa mendatang proses verifikasi ini akan dimutakhirkan.
@@ -290,7 +290,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Siapa pun
Hanya anggota (dimulai sejak opsi ini dipilih)
Hanya anggota (dimulai sejak mereka diundang)
- Hanya anggota (dimulai sejak mereka bergabung)
+ Hanya anggota (sejak mereka bergabung)
Pengguna yang dicekal
Lanjutan
ID internal ruangan ini
@@ -378,11 +378,11 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Keluarkan
Periksa Keadaan Pemberitahuan
Hasil diagnosa pemeriksaan keadaan
- Lansungkan Ujicoba
+ Jalankan Pengujian
Berlangsung… (%1$d of %2$d)
Diagnosa dasar berlangsung lancar. Apabila Anda masih belum dapat menerima pemberitahuan, mohon kirim laporan kutu untuk kami selidiki.
- Satu atau beberapa ujicoba gagal, coba sugesti yang kami tawarkan.
- Satu atau beberapa ujicoba gagal, mohon kirim laporan kutu untuk kami selidiki.
+ Satu atau beberapa ujian gagal, coba saran yang kami tawarkan.
+ Satu atau beberapa ujian gagal, mohon kirim laporan kutu untuk kami selidiki.
Pengaturan Sistem.
Pemberitahuan diperbolehkan dalam pengaturan sistem.
Notifikasi dinonaktifkan dalam pengaturan sistem.
@@ -400,7 +400,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Perbolehkan
Pemeriksaan Layanan Google Play
APK Layanan Google Play ditemukan dan telah diperbaharui.
- ${app_name} menggunakan Layanan Google Play untuk mendorong pesan tapi tampaknya tidak diatur sebagaimana harusnya.
+ ${app_name} menggunakan Layanan Google Play untuk mendorong pesan tapi tampaknya tidak diatur sebagaimana harusnya:
\n%1$s
Perbaiki Layanan Google Play
Token Firebase
@@ -417,7 +417,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Layanan tidak akan mulai ketika perangkat dinyalakan kembali, Anda tidak akan menerima pemberitahuan hingga Anda membuka ${app_name}.
Perbolehkan memulai ketika perangkat dinyalakan
Periksa halangan di balik layar
- Larangan background dinonaktifkan untuk ${app_name}. Percobaan ini sebaiknya dijalankan menggunakan jaringan mobile data (bukan WIFI).
+ Larangan latar belakang dinonaktifkan untuk ${app_name}. Percobaan ini sebaiknya dijalankan menggunakan jaringan data ponsel (bukan WiFi).
\n%1$s
Larangan background dinonaktifkan untuk ${app_name}.
\nAktivitas yang dilakukan aplikasi ini akan terhalang ketika beroperasi di balik layar, dan ini dapat mempengaruhi pemunculan notifikasi.
@@ -446,7 +446,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
[%1$s]
\nError ini di luar kendali ${app_name} dan menurut Google, error ini muncul ketika terlalu banyak aplikasi terdaftar dengan FCM pada perangkat tersebut. Error ini tidak seharusnya mempengaruhi pengguna biasa.
[%1$s]
-\nError ini di luar kendali ${app_name}, dan dapat muncul karena berbagai alasan. Coba lagi nanti, atau Anda juga dapat memeriksa apabila penggunaan jaringan data Layanan Google Play tidak terhalang oleh sistem, atau waktu pada perangkat sudah benar, atau ini dapat terjadi pada ROM tidak resmi.
+\nKesalahan ini di luar kendali ${app_name}, dan dapat muncul karena berbagai alasan. Coba lagi nanti, atau Anda juga dapat memeriksa apabila penggunaan jaringan data Layanan Google Play tidak terhalang oleh sistem, atau waktu pada perangkat sudah benar, atau ini dapat terjadi pada ROM tidak resmi.
[%1$s]
\nError ini di luar kendali ${app_name}. Tidak terdapat akun Google pada perangkat. Mohon buka pengelola akun dan tambahkan akun Google.
Tambah Akun
@@ -493,7 +493,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
%s melakukan panggilan suara.
Anda melakukan panggilan video.
%s melakukan panggilan video.
- Anda mengubah nama kamar menjadi: %1$s
+ Anda mengubah nama ruangan menjadi: %1$s
%1$s mengubah nama ruangan menjadi: %2$s
Anda mengubah avatar ruangan ini
%1$s mengubah avatar ruangan ini
@@ -546,7 +546,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Aplikasi ini sedang menunggu push
Aplikasi ini menerima push
Gagal menerima push. Solusinya adalah untuk menginstal ulang aplikasi.
- Percobaan Push
+ Percobaan Dorongan
Pastikan Anda mengeklik tautan di email yang telah kami kirimkan kepada Anda.
Hapus %s\?
Tidak ada nomor telepon yang ditambahkan ke akun Anda
@@ -578,7 +578,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Batalkan pencekalan pengguna
Alasan untuk mencekal
Cekal pengguna
- Pengguna yang dikeluarkan akan menghilangkannya dari ruangan ini.
+ Pengguna akan dikeluarkan dari ruangan ini.
\n
\nUntuk mencegah mereka bergabung lagi, Anda seharusnya mencekalnya.
Alasan untuk mengeluarkan
@@ -657,7 +657,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Gagal menambahkan widget
Anda tidak dapat melakukan panggilan dengan diri sendiri, tunggu untuk peserta untuk menerima undangan
Anda tidak dapat melakukan panggilan dengan diri sendiri
- Pertemuan menggunakan kebijakan keamanan dan izin Jitsi. Semua orang saat ini berada di ruangan akan melihat undangan untuk bergabung saat pertemuan Anda sedang berlangsung.
+ Pertemuan menggunakan kebijakan keamanan dan perizinan Jitsi. Semua orang saat ini berada di ruangan akan melihat undangan untuk bergabung saat pertemuan Anda sedang berlangsung.
Mulai rapat video
Mulai rapat audio
Anda tidak memiliki izin untuk memulai panggilan
@@ -675,19 +675,19 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Putuskan
Batalkan
Tidak Ada
- Standar Sistem
+ Bawaan Sistem
Anda mengaktifkan enkripsi ujung-ke-ujung. (algoritma tidak dikenali %1$s).
%1$s mengaktifkan enkripsi ujung-ke-ujung. (algoritma tidak dikenali %2$s).
Anda mengaktifkan enkripsi ujung-ke-ujung.
%1$s mengaktifkan enkripsi ujung-ke-ujung.
- Anda telah mencegah para tamu untuk bergabung ruangan.
- %1$s telah mencegah para tamu untuk bergabung ruangan.
- Anda telah mencegah para tamu untuk bergabung ruangan.
- %1$s telah mencegah para tamu untuk bergabung ruangan.
- %1$s telah mengizinkan para tamu untuk bergabung ruangan.
- Anda telah mengizinkan para tamu untuk bergabung ruangan.
- Anda telah mengizinkan para tamu untuk bergabung disini.
- %1$s telah mengizinkan para tamu untuk bergabung disini.
+ Anda telah mencegah para tamu untuk bergabung ke ruangan.
+ %1$s telah mencegah para tamu untuk bergabung ke ruangan.
+ Anda telah mencegah para tamu untuk bergabung ke ruangan.
+ %1$s telah mencegah para tamu untuk bergabung ke ruangan.
+ %1$s telah mengizinkan para tamu untuk bergabung ke ruangan.
+ Anda telah mengizinkan para tamu untuk bergabung ke ruangan.
+ Anda telah mengizinkan para tamu untuk bergabung di sini.
+ %1$s telah mengizinkan para tamu untuk bergabung di sini.
Anda mengubah alamat untuk ruangan ini.
%1$s mengubah alamat untuk ruangan ini.
Anda mengubah alamat utama dan alamat alternatif untuk ruangan ini.
@@ -740,12 +740,12 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
%1$s meninggalkan ruangan. Alasan: %2$s
Anda meninggalkan ruangan. Alasan: %1$s
%1$s meninggalkan ruangan. Alasan: %2$s
- Anda bergabung. Alasan %1$s
- %1$s bergabung. Alasan %2$s
- %1$s bergabung ruangan. Alasan: %2$s
+ Anda bergabung. Alasan: %1$s
+ %1$s bergabung. Alasan: %2$s
+ %1$s bergabung ke ruangan. Alasan: %2$s
%1$s mengundang Anda. Alasan: %2$s
Anda mengundang %1$s. Alasan: %2$s
- Anda bergabung ruangan. Alasan %1$s
+ Anda bergabung ke ruangan. Alasan: %1$s
%1$s mengundang %2$s. Alasan: %3$s
Undangan Anda. Alasan: %1$s
Undangan %1$s. Alasan: %2$s
@@ -800,12 +800,12 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
%1$s menerima undangan untuk %2$s
Anda membatalkan undangan untuk %1$s
%1$s membatalkan undangan untuk %2$s
- Anda membatalkan undangan untuk %1$s untuk bergabung ruangan
- %1$s membatalkan undangan untuk %2$s untuk bergabung ruangan
+ Anda membatalkan undangan untuk %1$s untuk bergabung ke ruangan
+ %1$s membatalkan undangan untuk %2$s untuk bergabung ke ruangan
Anda mengundang %1$s
%1$s mengundang %2$s
- Anda mengirimkan undangan ke %1$s untuk bergabung ruangan
- %1$s mengirimkan undangan ke %2$s untuk bergabung ruangan
+ Anda mengirimkan undangan ke %1$s untuk bergabung ke ruangan
+ %1$s mengirimkan undangan ke %2$s untuk bergabung ke ruangan
Anda menghapus avatar ruangan
%1$s menghapus avatar ruangan
Anda menghapus topik ruangan
@@ -833,8 +833,8 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Maaf, terjadi kesalahan
Mohon masukkan nama pengguna.
Diam
- Penurunan harga telah dinonaktifkan.
- Penurunan harga telah diaktifkan.
+ Markdown telah dinonaktifkan.
+ Markdown telah diaktifkan.
Perintah \"%s\" membutuhkan parameter tambahan, atau beberapa parameter salah.
Abaikan
Permintaan Pembagian Kunci
@@ -965,9 +965,9 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Beritahu saya untuk
Putar suara rana
Pilih
- Sumber media default
+ Sumber media bawaan
Pilih
- Kompresi default
+ Kompresi bawaan
Media
Kelola email dan nomor telepon yang ditautkan ke akun Matrix Anda
Email dan nomor telepon
@@ -992,7 +992,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Gunakan perintah /confetti atau kirim pesan yang berisi ❄️ atau 🎉
Tampilkan efek chat
Gunakan pengelola integrasi untuk mengelola bot, jembatan, widget, dan paket stiker.
-\nPengelola integrasi menerima data konfigurasi, dan dapat memodifikasi widget, mengirim undangan ruang, dan mengatur tingkat daya dengan sepengetahuan Anda.
+\nPengelola integrasi menerima data konfigurasi, dan dapat memodifikasi widget, mengirim undangan ruang, dan mengatur tingkat daya dengan pengetahuan Anda.
Integrasi
- %d detik
@@ -1047,11 +1047,11 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Email ini tidak terkait dengan akun apa pun.
Aplikasi tidak dapat membuat akun di homeserver ini.
\n
-\nApakah Anda ingin mendaftar menggunakan client web\?
+\nApakah Anda ingin mendaftar menggunakan klien web\?
Maaf, server ini tidak menerima akun baru.
Aplikasi tidak dapat masuk ke homeserver ini. Homeserver mendukung jenis masuk berikut: %1$s.
\n
-\nApakah Anda ingin masuk menggunakan client web\?
+\nApakah Anda ingin masuk menggunakan klien web\?
Ada kesalahan terjadi saat memuat halaman: %1$s (%2$d)
Masukkan alamat server yang ingin Anda gunakan
Masukkan alamat Modular Element atau Server yang ingin Anda gunakan
@@ -1076,7 +1076,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Lainnya
Pelajari lebih lanjut
Hosting premium untuk organisasi
- Bergabunglah dengan jutaan orang secara gratis di server publik terbesar
+ Bergabung dengan jutaan orang secara gratis di server publik terbesar
Sama seperti email, akun memiliki satu tempat, tetapi Anda dapat berkomunikasi dengan siapa saja
Pilih server
Mulai
@@ -1374,7 +1374,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
BUAT
Pesan Langsung
Ruangan
- Ruangan ini tidak dapat ditampilkan. Apakah Anda masih mau bergabung\?
+ Ruangan ini tidak dapat ditampilkan. Apakah Anda masih ingin bergabung\?
Ruangan ini tidak dapat di akses di waktu ini.
\nCoba lagi nanti, atau tanya admin ruangan untuk memeriksa jika Anda punya akses.
Ruangan ini tidak dapat di tampilkan
@@ -1424,7 +1424,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Tidak ada informasi cryptographic
unstable
stable
- Versi Default
+ Versi Bawaan
Versi Ruangan 👓
Batas tidak diketahui.
Homeserver Anda menerima lampiran (file, media, dsb.) dengan ukuran hingga %s.
@@ -1435,7 +1435,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Kelola Sesi
Tampilkan Semua Sesi
Sesi Aktif
- Admin server Anda telah menonaktifkan enkripsi ujung-ke-ujung secara default di kamar pribadi & pesan langsung.
+ Admin server Anda telah menonaktifkan enkripsi ujung-ke-ujung secara bawaan di ruangan & Pesan Langsung privat.
Tanda Tangan Silang dinonaktifkan
Tanda Tangan Silang diaktifkan.
\nKunci dipercaya.
@@ -1710,7 +1710,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Tambahkan ruangan dan space yang sudah ada
Anda adalah admin satu-satunya di space ini. Meninggalkannya berarti siapa saja tidak akan mempunyai kontrol atas space-nya.
Anda tidak akan dapat bergabung lagi kecuali jika Anda diundang lagi.
- Anda orang satu-satunya di sini. Jika Anda tinggalkan, siapa saja tidak dapat bergabung di masa depan, termasuk Anda.
+ Anda adalah orang satu-satunya di sini. Jika Anda tinggalkan, siapa saja tidak dapat bergabung di masa depan, termasuk Anda.
Apakah Anda yakin untuk meninggalkan %s\?
Tinggalkan
Tambahkan ruangan
@@ -2015,7 +2015,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Gagal mengimpor kunci
Menunggu untuk %s…
Hampir selesai! Menunggu untuk konfirmasi…
- Hampir selesai! Apakah perangkat yang lain menunjukkan centang yang sama\?
+ Hampir selesai! Apakah perangkat yang lain menunjukkan sebuah centang\?
"Topik: "
Tambahkan topik
%s untuk memberi tahu orang-orang tentang ruangan ini.
@@ -2043,7 +2043,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Mengsinkronisasikan Kunci Penandatanganan Diri
Mengsinkronisasikan Kunci Pengguna
Mengsinkronisasikan Kunci Utama
- Mendefinisikan Kunci SSSS default
+ Mendefinisikan Kunci SSSS bawaan
Membuat kunci aman dari frasa sandi
Mempublikasikan kunci identitas yang telah dibuat
Selesai
@@ -2071,7 +2071,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Jika Anda batalkan, Anda tidak dapat membaca pesan terenkripsi di perangkat ini dan pengguna lain tidak akan mempercayainya
Akun Anda mungkin dikompromikan
Ini bukan saya
- Login baru. Apakah itu Anda\?
+ Pemasukan baru. Apakah itu Anda\?
Segarkan
Akses riwayat pesan terenkripsi
Ekspor Audit
@@ -2091,13 +2091,13 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
- Kirim gambar dengan ukuran asli
- Apakah Anda mau mengirim lampiran ini ke %1$s\?
+ Apakah Anda ingin mengirim lampiran ini ke %1$s\?
Hapus…
Tidak dapat menemukan rahasia di penyimpanan
Jika Anda tidak dapat mengakses sesi yang sudah ada
Peringatan tingkat kepercayaan
Level kepercayaan peringatan
- Level kepercayaan default
+ Level kepercayaan bawaan
Dipilih
Video
mempunyai draf yang belum dikirim
@@ -2109,7 +2109,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Buka widget
Tangkap layar
Gagal mengotentikasi
- ${app_name} meminta Anda untuk memasukkan kredential untuk melakukan aksi ini.
+ ${app_name} meminta Anda untuk memasukkan kredensial untuk melakukan tindakan ini.
Otentikasi Ulang Dibutuhkan
Geser untuk mengakhirkan panggilan
Orang tak dikenal
@@ -2155,7 +2155,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Koneksi ke server telah hilang
Tidak
Ya
- Hampir selesai! Apakah %s menampilkan centang yang sama\?
+ Hampir selesai! Apakah %s menampilkan sebuah centang\?
Kode QR
Atur Ulang Kunci
Memulai Tanda Tangan Silang
@@ -2186,9 +2186,9 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Izin space
Menghapus cekalan akan mengizinkan pengguna untuk bergabung ke space lagi.
Mencekal pengguna akan mengeluarkan pengguna dari space ini dan mencegah pengguna untuk bergabung lagi.
- mengeluarkan pengguna akan mengeluarkannya dari space ini.
+ Pengguna akan dikeluarkan dari space ini.
\n
-\nUntuk mencegah pengguna untuk bergabung lagi, Anda seharusnya cekal pengguna itu saja.
+\nUntuk mencegah mereka untuk bergabung lagi, Anda seharusnya mencekalnya.
Berhenti Merekam
Menambahkan ( ͡° ͜ʖ ͡°) ke pesan teks biasa
Tidak ada kebijakan yang disediakan oleh server identitasnya
@@ -2552,4 +2552,40 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
%1$s dan %2$s
Email belum diverifikasi, periksa kotak masuk Anda
Semua Obrolan
+ Tampilkan Semua Sesi (V2, Dalam Pengembangan)
+ Untuk keamanan terbaik, verifikasi sesi Anda dan keluarkan sesi apa pun yang Anda tidak kenal atau Anda tidak gunakan lagi.
+ Sesi lainnya
+ Sesi
+ Buka daftar space
+ Buat percakapan atau ruangan baru
+ Orang
+ Favorit
+ Belum dibaca
+ Semua
+ A - Z
+ Aktivitas
+ Urutkan berdasarkan
+ Tampilkan terkini
+ Tampilkan saringan
+ Preferensi tata letak
+ Jelajahi Ruangan
+ Buat Ruangan
+ Mulai Obrolan
+ Maaf, ruangan ini tidak ditemukan.
+\nMohon coba lagi nanti.%s
+ Belum diverifikasi · Aktivitas terakhir %1$s
+ Terverifikasi · Aktivitas terakhir %1$s
+ Tampilkan Semua (%1$d)
+ Sesi Saat Ini
+ Tampilkan Detail
+ Verifikasi Sesi
+ Verifikasi sesi Anda saat ini untuk perpesanan yang aman.
+ Sesi Anda saat ini siap untuk perpesanan yang aman.
+ Sesi belum diverifikasi
+ Sesi terverifikasi
+ Tipe perangkat tidak diketahui
+ Desktop
+ Web
+ Ponsel
+ Undangan
diff --git a/vector/src/main/res/values-in/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-in/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-in/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-in/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-is/strings.xml b/library/ui-strings/src/main/res/values-is/strings.xml
similarity index 100%
rename from vector/src/main/res/values-is/strings.xml
rename to library/ui-strings/src/main/res/values-is/strings.xml
diff --git a/vector/src/main/res/values-is/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-is/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-is/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-is/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-it/strings.xml b/library/ui-strings/src/main/res/values-it/strings.xml
similarity index 98%
rename from vector/src/main/res/values-it/strings.xml
rename to library/ui-strings/src/main/res/values-it/strings.xml
index b14b9d8fbd..ecb29d1586 100644
--- a/vector/src/main/res/values-it/strings.xml
+++ b/library/ui-strings/src/main/res/values-it/strings.xml
@@ -2591,4 +2591,40 @@
\nQuesto homeserver potrebbe non essere configurato per mostrare mappe.
Apri le impostazioni
Tutte le chat
+ Mostra tutte le sessioni (V2, WIP)
+ Per una maggiore sicurezza, verifica le tue sessioni e disconnetti quelle che non riconosci o che non usi più.
+ Altre sessioni
+ Sessioni
+ Apri elenco spazi
+ Crea una nuova conversazione o stanza
+ Persone
+ Preferiti
+ Non lette
+ Tutte
+ A - Z
+ Attività
+ Ordina per
+ Mostra recenti
+ Mostra filtri
+ Preferenze disposizione
+ Esplora le stanze
+ Crea una stanza
+ Inizia una chat
+ Non verificata · Ultima attività %1$s
+ Verificata · Ultima attività %1$s
+ Vedi tutte (%1$d)
+ Sessione attuale
+ Vedi dettagli
+ Verifica la sessione
+ Verifica la tua sessione attuale per messaggi più sicuri.
+ La tua sessione attuale è pronta per i messaggi sicuri.
+ Sessione non verificata
+ Sessione verificata
+ Tipo di dispositivo sconosciuto
+ Desktop
+ Web
+ Mobile
+ Spiacenti, questa stanza non è stata trovata.
+\nRiprova più tardi.%s
+ Inviti
diff --git a/vector/src/main/res/values-it/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-it/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-it/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-it/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-it/strings_sc.xml b/library/ui-strings/src/main/res/values-it/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-it/strings_sc.xml
rename to library/ui-strings/src/main/res/values-it/strings_sc.xml
diff --git a/vector/src/main/res/values-iw/strings.xml b/library/ui-strings/src/main/res/values-iw/strings.xml
similarity index 100%
rename from vector/src/main/res/values-iw/strings.xml
rename to library/ui-strings/src/main/res/values-iw/strings.xml
diff --git a/vector/src/main/res/values-iw/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-iw/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-iw/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-iw/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-ja/strings.xml b/library/ui-strings/src/main/res/values-ja/strings.xml
similarity index 100%
rename from vector/src/main/res/values-ja/strings.xml
rename to library/ui-strings/src/main/res/values-ja/strings.xml
diff --git a/vector/src/main/res/values-ja/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-ja/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-ja/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-ja/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-kaa/strings.xml b/library/ui-strings/src/main/res/values-kaa/strings.xml
similarity index 100%
rename from vector/src/main/res/values-kaa/strings.xml
rename to library/ui-strings/src/main/res/values-kaa/strings.xml
diff --git a/vector/src/main/res/values-kab/strings.xml b/library/ui-strings/src/main/res/values-kab/strings.xml
similarity index 100%
rename from vector/src/main/res/values-kab/strings.xml
rename to library/ui-strings/src/main/res/values-kab/strings.xml
diff --git a/vector/src/main/res/values-kab/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-kab/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-kab/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-kab/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-ko/strings.xml b/library/ui-strings/src/main/res/values-ko/strings.xml
similarity index 100%
rename from vector/src/main/res/values-ko/strings.xml
rename to library/ui-strings/src/main/res/values-ko/strings.xml
diff --git a/vector/src/main/res/values-ko/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-ko/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-ko/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-ko/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-ku/strings.xml b/library/ui-strings/src/main/res/values-ku/strings.xml
similarity index 100%
rename from vector/src/main/res/values-ku/strings.xml
rename to library/ui-strings/src/main/res/values-ku/strings.xml
diff --git a/vector/src/main/res/values-ku/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-ku/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-ku/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-ku/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-lo/strings.xml b/library/ui-strings/src/main/res/values-lo/strings.xml
similarity index 100%
rename from vector/src/main/res/values-lo/strings.xml
rename to library/ui-strings/src/main/res/values-lo/strings.xml
diff --git a/vector/src/main/res/values-lo/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-lo/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-lo/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-lo/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-lt/strings.xml b/library/ui-strings/src/main/res/values-lt/strings.xml
similarity index 66%
rename from vector/src/main/res/values-lt/strings.xml
rename to library/ui-strings/src/main/res/values-lt/strings.xml
index 454bf8a4db..c33f8257c6 100644
--- a/vector/src/main/res/values-lt/strings.xml
+++ b/library/ui-strings/src/main/res/values-lt/strings.xml
@@ -447,4 +447,238 @@
- %d praleistų balso skambučių
Skambutis baigtas
-
+ ${app_name} reikia leidimo prieiti prie jūsų mikrofono, kad galėtumėte atlikti garso skambučius.
+ Baigiamas skambutis…
+ Nuotolinio ryšio pusėje nepavyko prisijungti.
+ Jokio atsakymo
+ Naudotojas, kuriam skambinote, yra užimtas.
+ Naudotojas užimtas
+ Sulaikėte skambutį
+ %s sulaikė skambutį
+ Sulaikyti
+ Tęsti
+ Balso skambutis su %s
+ Vaizdo skambutis su %s
+ Vaizdo skambutis vyksta…
+ Skambutis vyksta…
+ Įeinantis balso skambutis
+ Įeinantis vaizdo skambutis
+
+ - Praleistas vaizdo skambutis
+ - %d praleisti vaizdo skambučiai
+ - %d praleistų vaizdo skambučių
+
+ Skambutis skamba…
+ Jungiamasi prie skambučio…
+ Pasirinkite skambučių melodiją:
+ Įeinančio skambučio melodija
+ Įeinantiems skambučiams naudoti numatytąją ${app_name} melodiją
+ Prieš pradedant skambutį prašyti patvirtinimo
+ Užkirsti kelią atsitiktiniam skambučiui
+ Mažas
+ Vidutinis
+ Didelis
+ Originalas
+
+ - %d narystės pokytis
+ - %d narystės pokyčiai
+ - %d narystės pokyčių
+
+ Prašome paleisti ${app_name} kitame įrenginyje, kuris gali iššifruoti žinutę, kad galėtų išsiųsti raktus į šią sesiją.
+ Pakartotinai paprašykite šifravimo raktų iš kitų seansų.
+ Išsiųsta per daug užklausų
+ Nebuvo tinkamo JSON
+ Klaidingas JSON
+ Neautorizuotas, trūksta galiojančių tapatumo duomenų
+ SSL klaida.
+ SSL klaida: bendrakeleivio tapatybė nepatvirtinta.
+ Pasirinkti namų serverį
+ Nepavyko pasiekti namų serverio URL adresu %s. Patikrinkite nuorodą arba pasirinkite namų serverį rankiniu būdu.
+ Nepavyko pasiekti namų serverio šiuo URL adresu, prašome jį patikrinti
+ Tai nėra galiojantis \"Matrix\" serverio adresas
+ Prašome įvesti tinkamą URL adresą
+ Peržiūrėkite ir sutikite su šio namų serverio taisyklėmis:
+ %1$s išėjo iš kambario. Priežastis: %2$s
+ Prisijungėte. Priežastis: %1$s
+ %1$s prisijungė. Priežastis: %2$s
+ Prisijungėte prie kambario. Priežastis: %1$s
+ %1$s prisijungė prie kambario. Priežastis: %2$s
+ Siunčiama žinutė…
+ Žinutė išsiųsta
+ - Kai kurie naudotojai nebeignoruojami
+ ${app_name} turi išvalyti talpyklą, kad ji būtų atnaujinta dėl šios priežasties:
+\n%s
+\n
+\nAtkreipkite dėmesį, kad atlikus šį veiksmą programa bus paleista iš naujo ir tai gali šiek tiek užtrukti.
+ Pradinio sinchronizavimo užklausa
+ Pradinė sinchronizacija:
+\nImportuojame paskyros duomenis
+ Pradinė sinchronizacija:
+\nImportuojame išeitus kambarius
+ Pradinė sinchronizacija:
+\nImportuojame kambarių kvietimus
+ Pradinė sinchronizacija:
+\nĮkeliame jūsų pokalbius
+\nJei prisijungėte prie daugybės kambarių, tai gali užtrukti
+ Pradinė sinchronizacija:
+\nImportuojame kambarius
+ Pradinė sinchronizacija:
+\nImportuojame kriptografija
+ Pradinė sinchronizacija:
+\nImportuojame paskyrą…
+ Pradinė sinchronizacija:
+\nLaukiame serverio atsakymo…
+ Pradinė sinchronizacija:
+\nAtsisiunčiame duomenis…
+ Tuščias kambarys (buvo %s)
+ Tuščias kambarys
+
+ - %1$s, %2$s, %3$s ir %4$d kitas
+ - %1$s, %2$s, %3$s ir %4$d kiti
+ - %1$s, %2$s, %3$s ir %4$d kitų
+
+ %1$s, %2$s, %3$s ir %4$s
+ %1$s, %2$s ir %3$s
+ %1$s ir %2$s
+ Kvietimas į kambarį
+ Telefono numeris
+ El. pašto adresas
+ Jums neleidžiama prisijungti prie šio kambario
+ Sukurti kambarį
+ Naršyti kambarius
+ Jūs atnaujinote čia.
+ El. paštas nepatvirtintas, patikrinkite savo pašto dėžutę
+ Nepavyko patvirtinti el. pašto adreso: įsitikinkite, kad paspaudėte el. laiške esančią nuorodą
+ Šis namų serveris norėtų įsitikinti, kad nesate robotas
+ Pamiršote slaptažodį\?
+ Šis telefono numeris jau yra įrašytas.
+ Šis el. pašto adresas jau yra įrašytas.
+ Tai neatrodo kaip tinkamas el. pašto adresas
+ Neteisingas naudotojo vardas ir (arba) slaptažodis
+ Pateikti
+ Prisijungimas vienkartiniu prisijungimu
+ Prisijungti
+ Atsiprašome, nerastos jokios išorinės programos šiam veiksmui atlikti.
+ Šiuo metu nėra įjungti jokie lipdukų paketai.
+\n
+\nAr norite pridėti keletą dabar\?
+ Naudoti kaip numatytąjį ir daugiau neklausti
+ Filmuoti
+ Fotografuoti
+ Fotografuoti arba filmuoti
+ Siųsti lipduką
+ Siųsti failus
+ Sustabdyti ekrano bendrinimą
+ Bendrinti ekraną
+ Įjungti HD
+ Išjungti HD
+ Atgalinė
+ Priekinė
+ Perjungti kamerą
+ Pasirinkite garso įrenginį
+ Kvietimai
+ A - Z
+ Veikla
+ Rikiuoti pagal
+ Rodyti naujausius
+ Rodyti filtrus
+ Išdėstymo parinktys
+ Kitas
+ min
+ val
+ %1$s pakeitė alternatyvius šio kambario adresus.
+
+ - Pašalinote alternatyvų šio kambario adresą %1$s.
+ - Pašalinote alternatyvius šio kambario adresus %1$s.
+ - Pašalinote alternatyvius šio kambario adresus %1$s.
+
+
+ - %1$s pašalino alternatyvų šio kambario adresą %2$s.
+ - %1$s pašalino alternatyvius šio kambario adresus %2$s.
+ - %1$s pašalino alternatyvius šio kambario adresus %2$s.
+
+
+ - Pridėjote alternatyvų šio kambario adresą %1$s.
+ - Pridėjote alternatyvius šio kambario adresus %1$s.
+ - Pridėjote alternatyvius šio kambario adresus %1$s.
+
+
+ - %1$s pridėjo alternatyvų šio kambario adresą %2$s.
+ - %1$s pridėjo alternatyvius šio kambario adresus %2$s.
+ - %1$s pridėjo alternatyvius šio kambario adresus %2$s.
+
+ Pašalinote pagrindinį šio kambario adresą.
+ %1$s pašalino pagrindinį šio kambario adresą.
+ Nustatėte pagrindinį šio kambario adresą į %1$s.
+ %1$s nustatė pagrindinį šio kambario adresą į %2$s.
+ Pridėjote %1$s ir pašalinote %2$s kaip šio kambario adresus.
+ %1$s pridėjo %2$s ir pašalino %3$s kaip šio kambario adresus.
+
+ - Pašalinote %1$s kaip šio kambario adresą.
+ - Pašalinote %1$s iš šio kambario adresų.
+ - Pašalinote %1$s iš šio kambario adresų.
+
+
+ - %1$s pašalino %2$s kaip šio kambario adresą.
+ - %1$s pašalino %2$s iš šio kambario adresų.
+ - %1$s pašalino %2$s iš šio kambario adresų.
+
+
+ - Pridėjote %1$s kaip šio kambario adresą.
+ - Pridėjote %1$s kaip šio kambario adresus.
+ - Pridėjote %1$s kaip šio kambario adresus.
+
+
+ - %1$s pridėjo %2$s kaip šio kambario adresą.
+ - %1$s pridėjo %2$s kaip šio kambario adresus.
+ - %1$s pridėjo %2$s kaip šio kambario adresus.
+
+ Atšaukėte %1$s kvietimą. Priežastis: %2$s
+ %1$s atšaukė %2$s kvietimą. Priežastis: %3$s
+ Priėmėte %1$s kvietimą. Priežastis: %2$s
+ %1$s priėmė %2$s kvietimą. Priežastis: %3$s
+ Jūs užblokavote %1$s. Priežastis: %2$s
+ %1$s užblokavo %2$s. Priežastis: %3$s
+ Atblokavote %1$s. Priežastis: %2$s
+ %1$s atblokavo %2$s. Priežastis: %3$s
+ Pašalinote %1$s. Priežastis: %2$s
+ %1$s pašalino %2$s. Priežastis: %3$s
+ Kvietimą atmetėte. Priežastis: %1$s
+ %1$s atmetė kvietimą. Priežastis: %2$s
+ Išėjote. Priežastis: %1$s
+ %1$s išėjo. Priežastis: %2$s
+ Išėjote iš kambario. Priežastis: %1$s
+ Visi pokalbiai
+ Matricos klaida
+ Nepavyksta išsiųsti žinutės
+ Siuntėjo įrenginys neatsiuntė mums šios žinutės raktų.
+ ** Nepavyksta iššifruoti: %s **
+ %1$s nuo %2$s iki %3$s
+ %1$s pakeitė %2$s galios lygį.
+ Pakeitėte %1$s galios lygį.
+ Pasirinktinis
+ Pasirinktinis (%1$d)
+ Standartinis
+ Moderatorius
+ Adminas
+ Pakeitėte %1$s valdiklį
+ %1$s pakeitė %2$s valdiklį
+ Pašalinote %1$s valdiklį
+ %1$s pašalino %2$s valdiklį
+ Pridėjote %1$s valdiklį
+ %1$s pridėjo %2$s valdiklį
+ %1$s išsiuntė kvietimą %2$s prisijungti prie kambario
+ %1$s atšaukė %2$s kvietimą prisijungti prie kambario
+ Priėmėte kvietimą į %1$s
+ %1$s priėmė kvietimą į %2$s
+ Atšaukėte kvietimą %1$s
+ %1$s atšaukė %2$s kvietimą
+ Atšaukėte %1$s kvietimą prisijungti prie kambario
+ Pakeitimų nėra.
+ • Serveriai atitinkantys %s buvo pašalinti iš leidžiamų sąrašo.
+ • Serveriai atitinkantys %s dabar yra leidžiami.
+ • Serveriai atitinkantys %s buvo pašalinti iš draudimų sąrašo.
+ • Serveriai atitinkantys %s dabar yra uždrausti.
+ • Serveriai atitinkantys %s yra leidžiami.
+ • Serveriai atitinkantys %s yra uždrausti.
+
\ No newline at end of file
diff --git a/vector/src/main/res/values-lt/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-lt/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-lt/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-lt/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-lv/strings.xml b/library/ui-strings/src/main/res/values-lv/strings.xml
similarity index 100%
rename from vector/src/main/res/values-lv/strings.xml
rename to library/ui-strings/src/main/res/values-lv/strings.xml
diff --git a/vector/src/main/res/values-lv/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-lv/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-lv/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-lv/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-mk/strings.xml b/library/ui-strings/src/main/res/values-mk/strings.xml
similarity index 100%
rename from vector/src/main/res/values-mk/strings.xml
rename to library/ui-strings/src/main/res/values-mk/strings.xml
diff --git a/vector/src/main/res/values-ml/strings.xml b/library/ui-strings/src/main/res/values-ml/strings.xml
similarity index 100%
rename from vector/src/main/res/values-ml/strings.xml
rename to library/ui-strings/src/main/res/values-ml/strings.xml
diff --git a/vector/src/main/res/values-ml/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-ml/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-ml/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-ml/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-nb-rNO/strings.xml b/library/ui-strings/src/main/res/values-nb-rNO/strings.xml
similarity index 100%
rename from vector/src/main/res/values-nb-rNO/strings.xml
rename to library/ui-strings/src/main/res/values-nb-rNO/strings.xml
diff --git a/vector/src/main/res/values-nb-rNO/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-nb-rNO/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-nb-rNO/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-nb-rNO/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-nb-rNO/strings_sc.xml b/library/ui-strings/src/main/res/values-nb-rNO/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-nb-rNO/strings_sc.xml
rename to library/ui-strings/src/main/res/values-nb-rNO/strings_sc.xml
diff --git a/vector/src/main/res/values-nl/strings.xml b/library/ui-strings/src/main/res/values-nl/strings.xml
similarity index 99%
rename from vector/src/main/res/values-nl/strings.xml
rename to library/ui-strings/src/main/res/values-nl/strings.xml
index 513fb42fa1..b1d239963e 100644
--- a/vector/src/main/res/values-nl/strings.xml
+++ b/library/ui-strings/src/main/res/values-nl/strings.xml
@@ -2596,4 +2596,27 @@
%1$s en %2$s
E-mailadres niet geverifieerd, controleer je inbox
+ Toon alle sessies (V2, WIP)
+ Kan kaart niet laden
+\nDeze server is mogelijk niet geconfigureerd om kaarten weer te geven.
+ Open instellingen
+ Voor de beste beveiliging verifieert u uw sessies en meldt u zich af bij elke sessie die u niet meer herkent of gebruikt.
+ Andere sessies
+ Sessies
+ Lijst met publieke spaces
+ Maak een nieuw gesprek of een nieuwe kamer
+ Personen
+ Favorieten
+ Ongelezen
+ Alles
+ A - Z
+ Activiteit
+ Sorteer op
+ Recente tonen
+ Toon filters
+ Lay-outvoorkeuren
+ Ontdek kamers
+ Kamer creëren
+ Start gesprek
+ Alle gesprekken
diff --git a/vector/src/main/res/values-nl/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-nl/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-nl/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-nl/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-nl/strings_sc.xml b/library/ui-strings/src/main/res/values-nl/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-nl/strings_sc.xml
rename to library/ui-strings/src/main/res/values-nl/strings_sc.xml
diff --git a/vector/src/main/res/values-nn/strings.xml b/library/ui-strings/src/main/res/values-nn/strings.xml
similarity index 100%
rename from vector/src/main/res/values-nn/strings.xml
rename to library/ui-strings/src/main/res/values-nn/strings.xml
diff --git a/vector/src/main/res/values-nn/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-nn/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-nn/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-nn/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-pa/strings.xml b/library/ui-strings/src/main/res/values-pa/strings.xml
similarity index 100%
rename from vector/src/main/res/values-pa/strings.xml
rename to library/ui-strings/src/main/res/values-pa/strings.xml
diff --git a/vector/src/main/res/values-pa/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-pa/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-pa/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-pa/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-pl/strings.xml b/library/ui-strings/src/main/res/values-pl/strings.xml
similarity index 97%
rename from vector/src/main/res/values-pl/strings.xml
rename to library/ui-strings/src/main/res/values-pl/strings.xml
index ecc9316084..18b0de078c 100644
--- a/vector/src/main/res/values-pl/strings.xml
+++ b/library/ui-strings/src/main/res/values-pl/strings.xml
@@ -735,7 +735,7 @@
Ustal jak inni mogą odnaleść twoje konto.
Media
Domyślne źródło mediów
- Odzyskiwanie zaszyforwanych wiadomości
+ Odzyskiwanie zaszyfrowanych wiadomości
- %1$s: %2$d wiadomość
- %1$s: %2$d wiadomości
@@ -1058,12 +1058,12 @@
Zaakceptowałeś(-łaś)
Żądanie weryfikacji wysłane
Żądanie weryfikacji
- Zweryfikuj tą sesję
+ Zweryfikuj tę sesję
Zeskanuj kod z urządzenia innego użytkownika aby bezpiecznie zweryfikować siebie nawzajem
Zeskanuj ich kod
Nie można zeskanować
Jeżeli nie jesteś z tą osobą, zamiast tego porównaj emoji
- Zweryfikuj porównując emoji
+ Zweryfikuj porównując emotikony
Zweryfikuj %s
Zweryfikowano %s
Oczekiwanie na %s…
@@ -1099,7 +1099,7 @@
Aktywować szyfrowanie\?
Raz włączone szyfrowanie w pokoju nie może zostać wyłączone. Wiadomości wysłane w zaszyfrowanym pokoju nie są widziane przez serwer, a jedynie przez uczestników w pokoju. Aktywowanie szyfrowania może uniemożliwić wielu botom i mostkom prawidłowe działanie.
Aktywuj szyfrowanie
- Aby być bezpiecznym, zweryfikuj %s poprzez sprawdzenie jednorazowego kodu.
+ Aby zachować bezpieczeństwo, zweryfikuj %s poprzez sprawdzenie jednorazowego kodu.
Aby być bezpiecznym, zrób to osobiście lub użyj innej metody komunikacji.
Porównaj unikalny ciąg emoji, upewniając się, że pojawiają się w identycznym porządku.
Porównaj kod wyświetlany na ekranie innego użytkownika.
@@ -1120,7 +1120,7 @@
Wyloguj z tej sesji
Brak dostępnej informacji o kryptografii
Ta sesja jest zaufana dla bezpiecznej wymiany wiadomości, ponieważ ją zweryfikowałeś(-łaś):
- Zweryfikuj tą sesję aby oznaczyć ją jako zaufaną i przyznać jej dostęp do zaszyfrowanych wiadomości. Jeżeli nie logowałeś(-łaś) się do tej sesji, twoje konto mogło zostać naruszone:
+ Zweryfikuj tę sesję aby oznaczyć ją jako zaufaną i przyznać jej dostęp do zaszyfrowanych wiadomości. Jeżeli nie logowałeś(-łaś) się do tej sesji, twoje konto mogło zostać zaatakowane:
- %d aktywna sesja
- %d aktywne sesje
@@ -1330,12 +1330,12 @@
Hasło odzyskiwania
Weryfikacja anulowana
Weryfikacja anulowana. Możesz rozpocząć jej proces ponownie.
- Jedno z poniższych mogło zostać skompromitowane:
+ Jedno z poniższych może być zagrożone:
\n
-\n-Twoje hasło
-\n-Twój serwer domowy
-\n-To urządzenie albo inne urządzenie
-\n-Połączenie internetowe używane przez urządzenie
+\n- Twoje hasło
+\n- Twój serwer domowy
+\n- To lub drugie urządzenie
+\n- Połączenie internetowe używane przez dowolne z urządzeń
\n
\nZalecamy natychmiastową zmianę Twojego hasła oraz klucza odzyskiwania w Ustawieniach.
Jeżeli anulujesz, nie będziesz w stanie czytać zaszyfrowanych wiadomości na nowym urządzeniu, a inni użytkownicy nie będą mu ufali
@@ -1388,7 +1388,7 @@
Zablokuj wszystkich nie będących członkami %s przed dołączeniem do tego pokoju
Ukryj zaawansowane
Pokaż zaawansowane
- Nie można znaleźć właściwego serwera domowego. Zweryfikuj swój identyfikator
+ Nie można znaleźć właściwego serwera domowego. Sprawdź swój identyfikator
To nie jest prawidłowy identyfikator użytkownika. Oczekiwany format: \"@user:homeserver.org\"
Jeżeli nie pamiętasz hasła, cofnij się aby je zresetować.
Matrix ID
@@ -1492,7 +1492,7 @@
Włącz \"Zezwalaj na integracje\" w Ustawieniach żeby to zrobić.
Integracje są zablokowane
To zastąpi obecny Klucz bądź Hasło.
- Wygeneruj nowy Klucz Bezpieczeństwa albo Hasło dla istniejącej kopii zapasowej.
+ Wygeneruj nowy klucz bezpieczeństwa albo hasło dla istniejącej kopii zapasowej.
Zabezpiecza przeciwko utracie dostępu do zaszyfrowanych wiadomości oraz danych poprzez zapisanie zaszyfrowanych kluczy na Twoim serwerze.
Powiadomienie zostało kliknięte!
Proszę kliknąć na powiadomieniu, Jeżeli nie widzisz powiadomienia, sprawdź ustawienia systemowe.
@@ -1649,7 +1649,7 @@
Mój kod
Udostępnij mój kod
Zeskanuj kod QR
- Nie możemy zaprosić użytkowników. Zweryfikuj osoby, które chcesz zaprosić i spróbuj ponownie.
+ Nie udało się zaprosić użytkowników. Sprawdź osoby, które chcesz zaprosić i spróbuj ponownie.
- Zaproszenia wysłane do %1$s i jeszcze jednej osoby
- Zaproszenia wysłane do %1$s i %2$d innych osób
@@ -1985,7 +1985,7 @@
Udostępnij link
Zaproś przez nazwę użytkownika lub email
Zaproś przez email
- Aktualnie jesteś tylko Ty. %s będzie jeszcze lepsza kiedy dołączą inni.
+ Aktualnie jesteś tu tylko ty. %s będzie jeszcze lepszą przestrzenią, gdy dołączą do niej inni.
Zaproś do %s
Zaproś osoby
Zaproś osoby do Twojej przestrzeni
@@ -2127,7 +2127,7 @@
Limit wielkości pliku na serwerze
Wersja serwera
Nazwa serwera
- Zweryfikuj zgodność wyświetlonych emotikon
+ Zamiast tego, zweryfikuj porównując emotikony
Zeskanuj za pomocą tego urządzenia
Zeskanuj kod Twoim drugim urządzeniem lub przełącz się i zeskanuj za pomocą tego urządzenia
Głos
@@ -2311,8 +2311,8 @@
Zastąp kolor wyświetlanej nazwy
Posiadam już konto
- Połącz się z każdym.
- Ty jesteś w kontroli.
+ Bezpieczna komunikacja.
+ Masz wszystko pod kontrolą.
Przejmij swoje konwersacje.
By odkryć istniejące kontakty, musisz najpierw przesłać swoje dane kontaktowe (adresy e-mail i numer telefonu) do serwera tożsamości. Przed wysłaniem Twoje dane zostaną zaszyfrowane w celu zachowania prywatności.
Uzyskaj pomoc w korzystaniu z ${app_name}
@@ -2392,12 +2392,12 @@
Społeczności
Zespoły
Przyjaciele i rodzina
- Pomożemy Ci się połączyć
+ Pomożemy Ci nawiązać kontakt
Z kim będziesz najczęściej rozmawiać\?
- Szyfrowane od-końca-do-końca i nie wymaga numeru telefonu. Brak reklam i dataminingu.
+ Szyfrowane od-końca-do-końca, bez konieczności podawania numeru telefonu. Zero reklam i dataminingu.
Wybierz, gdzie prowadzone są Twoje rozmowy, dając Ci kontrolę i niezależność. Połączenie przez sieć Matrix.
Bezpieczna i niezależna komunikacja, która zapewnia ten sam poziom prywatności, co rozmowa twarzą w twarz we własnym domu.
- Wiadomości dla Twojego zespołu.
+ Komunikacja dla Twojego zespołu.
Położenie
Zagadnienia prawne
Już przeglądasz ten wątek!
@@ -2521,7 +2521,7 @@
Każdy w przestrzeni nadrzędnej będzie mógł znaleźć ten pokój i dołączyć do niego — nie ma potrzeby ręcznego zapraszania wszystkich. W każdej chwili możesz to zmienić w ustawieniach pokoju.
Automatycznie aktualizuj nadrzędną przestrzeń
Twój system automatycznie wyśle dzienniki, gdy wystąpi błąd niemożności odszyfrowania
- Błędy automatycznego deszyfrowania raportów.
+ Automatycznie zgłaszaj błędy deszyfrowania.
Opuść pokój o podanym identyfikatorze (lub aktualny pokój, jeśli null)
Udostępnili swoją lokalizację
Powiadom cały pokój
@@ -2686,4 +2686,52 @@
%1$s i %2$s
Email nie został zweryfikowany, sprawdź swoją skrzynkę
-
+ Nie udało się zarejestrować tokena punktu końcowego na serwerze domowym:
+\n%1$s
+ Wyświetl wszystkie sesje (V2, WIP)
+ Bieżąca brama: %s
+ Wejście
+ Nie można znaleźć punktu końcowego.
+ Bieżący punkt końcowy: %s
+ Punkt końcowy
+ Nie można wczytać mapy.
+\nTen serwer macierzysty może nie być skonfigurowany do wyświetlania map.
+ Otwórz ustawienia
+ Aby zapewnić najlepsze bezpieczeństwo, zweryfikuj swoje sesje i wyloguj się z każdej sesji, której już nie rozpoznajesz lub której już nie używasz.
+ Inne sesje
+ Sesje
+ Lista otwartych przestrzeni
+ Utwórz nową rozmowę lub pokój
+ Ludzie
+ Ulubione
+ Nieprzeczytane
+ Wszystkie
+ Punkt końcowy został pomyślnie zarejestrowany na serwerze domowym.
+ Rejestracja punktu końcowego
+ A - Z
+ Aktywności
+ Sortuj według
+ Wyświetl ostatnie
+ Wyświetl filtry
+ Preferencje interfejsu
+ Przeglądaj pokoje
+ Utwórz pokój
+ Zacznij rozmawiać
+ Wszystkie rozmowy
+ Nie zweryfikowano · Ostatnia aktywność %1$s
+ Zweryfikowano · Ostatnia aktywność %1$s
+ Pokaż wszystkie (%1$d)
+ Obecna sesja
+ Pokaż szczegóły
+ Zweryfikuj sesję
+ Twoja obecna sesja jest przygotowana do bezpiecznej komunikacji.
+ Niezweryfikowana sesja
+ Zweryfikowana sesja
+ Nieznany typ urządzenia
+ Komputer
+ Przeglądarka
+ Urządzenie przenośne
+ Niestety, ten pokój nie został znaleziony.
+\nSpróbuj ponownie później.%s
+ Zaproszenia
+
\ No newline at end of file
diff --git a/vector/src/main/res/values-pl/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-pl/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-pl/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-pl/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-pl/strings_sc.xml b/library/ui-strings/src/main/res/values-pl/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-pl/strings_sc.xml
rename to library/ui-strings/src/main/res/values-pl/strings_sc.xml
diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/library/ui-strings/src/main/res/values-pt-rBR/strings.xml
similarity index 98%
rename from vector/src/main/res/values-pt-rBR/strings.xml
rename to library/ui-strings/src/main/res/values-pt-rBR/strings.xml
index a148ea90cb..08c41db365 100644
--- a/vector/src/main/res/values-pt-rBR/strings.xml
+++ b/library/ui-strings/src/main/res/values-pt-rBR/strings.xml
@@ -2600,4 +2600,40 @@
\nEste servidor casa pode não estar configurado para exibir mapas.
Abrir configurações
Todos os Chats
+ Mostrar Todas Sessões (V2, WIP)
+ Para a melhor segurança, verifique suas sessões e faça signout de qualquer sessão que você não reconhece ou usa mais.
+ Outras sessões
+ Sessões
+ Abrir lista de espaços
+ Criar uma nova conversa ou sala
+ Todas
+ Pessoas
+ Favoritas
+ Não-lidas
+ A - Z
+ Atividade
+ Ordenar por
+ Mostrar recentes
+ Mostrar filtros
+ Preferências de layout
+ Explorar Salas
+ Criar Sala
+ Começar Chat
+ Não-verificada · Última atividade %1$s
+ Verificada · Última atividade %1$s
+ Ver Todas (%1$d)
+ Sessão Atual
+ Visualizar Detalhes
+ Verificar Sessão
+ Verifique sua sessão atual para mensageria segura melhorada.
+ Sua sessão atual está pronta para mensageria segura.
+ Sessão não-verificada
+ Sessão verificada
+ Tipo de dispositivo desconhecido
+ Desktop
+ Mobile
+ Web
+ Desculpe, esta sala não tem sido encontrada.
+\nPor favor retente mais tarde.%s
+ Convites
diff --git a/vector/src/main/res/values-pt-rBR/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-pt-rBR/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-pt-rBR/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-pt-rBR/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-pt-rBR/strings_sc.xml b/library/ui-strings/src/main/res/values-pt-rBR/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-pt-rBR/strings_sc.xml
rename to library/ui-strings/src/main/res/values-pt-rBR/strings_sc.xml
diff --git a/vector/src/main/res/values-pt/strings.xml b/library/ui-strings/src/main/res/values-pt/strings.xml
similarity index 100%
rename from vector/src/main/res/values-pt/strings.xml
rename to library/ui-strings/src/main/res/values-pt/strings.xml
diff --git a/vector/src/main/res/values-pt/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-pt/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-pt/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-pt/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-ro/strings.xml b/library/ui-strings/src/main/res/values-ro/strings.xml
similarity index 100%
rename from vector/src/main/res/values-ro/strings.xml
rename to library/ui-strings/src/main/res/values-ro/strings.xml
diff --git a/vector/src/main/res/values-ro/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-ro/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-ro/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-ro/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-ro/strings_sc.xml b/library/ui-strings/src/main/res/values-ro/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-ro/strings_sc.xml
rename to library/ui-strings/src/main/res/values-ro/strings_sc.xml
diff --git a/vector/src/main/res/values-ru/strings.xml b/library/ui-strings/src/main/res/values-ru/strings.xml
similarity index 99%
rename from vector/src/main/res/values-ru/strings.xml
rename to library/ui-strings/src/main/res/values-ru/strings.xml
index 01ce2f1bf6..4852be1f82 100644
--- a/vector/src/main/res/values-ru/strings.xml
+++ b/library/ui-strings/src/main/res/values-ru/strings.xml
@@ -2659,5 +2659,23 @@
Открыть настройки
Не удалось загрузить карту
\nВозможно, этот домашний сервер не настроен для отображения карт.
- Все Беседы
-
+ Все беседы
+ Для лучшей безопасности заверьте свои сессии и выйдите из тех, которые более не признаёте или не используете.
+ Другие сессии
+ Сессии
+ Создать беседу или комнату
+ Показать все сессии (V2, в разработке)
+ Люди
+ Настройки макета
+ Фильтры
+ Недавние
+ Избранные
+ Непрочитанные
+ Все
+ А - Я
+ Активности
+ Сортировать по
+ Обзор комнат
+ Начать беседу
+ Создать комнату
+
\ No newline at end of file
diff --git a/vector/src/main/res/values-ru/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-ru/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-ru/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-ru/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-ru/strings_sc.xml b/library/ui-strings/src/main/res/values-ru/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-ru/strings_sc.xml
rename to library/ui-strings/src/main/res/values-ru/strings_sc.xml
diff --git a/vector/src/main/res/values-rue/strings.xml b/library/ui-strings/src/main/res/values-rue/strings.xml
similarity index 100%
rename from vector/src/main/res/values-rue/strings.xml
rename to library/ui-strings/src/main/res/values-rue/strings.xml
diff --git a/vector/src/main/res/values-si/strings.xml b/library/ui-strings/src/main/res/values-si/strings.xml
similarity index 100%
rename from vector/src/main/res/values-si/strings.xml
rename to library/ui-strings/src/main/res/values-si/strings.xml
diff --git a/vector/src/main/res/values-si/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-si/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-si/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-si/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-sk/strings.xml b/library/ui-strings/src/main/res/values-sk/strings.xml
similarity index 98%
rename from vector/src/main/res/values-sk/strings.xml
rename to library/ui-strings/src/main/res/values-sk/strings.xml
index cb2d371ccc..2cc2d0280e 100644
--- a/vector/src/main/res/values-sk/strings.xml
+++ b/library/ui-strings/src/main/res/values-sk/strings.xml
@@ -2650,4 +2650,40 @@
\nTento domovský server nemusí byť nakonfigurovaný na zobrazovanie máp.
Otvoriť nastavenia
Všetky konverzácie
+ Zobraziť všetky relácie (V2, WIP)
+ V záujme čo najlepšieho zabezpečenia overte svoje relácie a odhláste sa z každej relácie, ktorú už nepoznáte alebo nepoužívate.
+ Iné relácie
+ Relácie
+ Otvoriť zoznam priestorov
+ Vytvoriť novú konverzáciu alebo miestnosť
+ Ľudia
+ Obľúbené
+ Neprečítané
+ Všetky
+ A - Z
+ Aktivity
+ Zoradiť podľa
+ Zobraziť posledné
+ Zobraziť filtre
+ Predvoľby rozmiestnenia
+ Preskúmať miestnosti
+ Vytvoriť miestnosť
+ Začať konverzáciu
+ Neoverené - Posledná aktivita %1$s
+ Overené - Posledná aktivita %1$s
+ Zobraziť všetky (%1$d)
+ Aktuálna relácia
+ Zobraziť podrobnosti
+ Overiť reláciu
+ Overte svoju aktuálnu reláciu pre vylepšené bezpečné zasielanie správ.
+ Vaša aktuálna relácia je pripravená na bezpečné zasielanie správ.
+ Neoverená relácia
+ Overená relácia
+ Neznámy typ zariadenia
+ Stolný počítač
+ Web
+ Mobil
+ Je nám ľúto, táto miestnosť nebola nájdená.
+\nProsím, skúste to neskôr.%s
+ Pozvánky
diff --git a/vector/src/main/res/values-sk/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-sk/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-sk/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-sk/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-sk/strings_sc.xml b/library/ui-strings/src/main/res/values-sk/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-sk/strings_sc.xml
rename to library/ui-strings/src/main/res/values-sk/strings_sc.xml
diff --git a/vector/src/main/res/values-sl/strings.xml b/library/ui-strings/src/main/res/values-sl/strings.xml
similarity index 100%
rename from vector/src/main/res/values-sl/strings.xml
rename to library/ui-strings/src/main/res/values-sl/strings.xml
diff --git a/vector/src/main/res/values-sl/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-sl/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-sl/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-sl/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-sq/strings.xml b/library/ui-strings/src/main/res/values-sq/strings.xml
similarity index 100%
rename from vector/src/main/res/values-sq/strings.xml
rename to library/ui-strings/src/main/res/values-sq/strings.xml
diff --git a/vector/src/main/res/values-sq/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-sq/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-sq/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-sq/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-sr/strings.xml b/library/ui-strings/src/main/res/values-sr/strings.xml
similarity index 100%
rename from vector/src/main/res/values-sr/strings.xml
rename to library/ui-strings/src/main/res/values-sr/strings.xml
diff --git a/vector/src/main/res/values-sr/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-sr/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-sr/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-sr/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-sv/strings.xml b/library/ui-strings/src/main/res/values-sv/strings.xml
similarity index 100%
rename from vector/src/main/res/values-sv/strings.xml
rename to library/ui-strings/src/main/res/values-sv/strings.xml
diff --git a/vector/src/main/res/values-sv/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-sv/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-sv/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-sv/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-sv/strings_sc.xml b/library/ui-strings/src/main/res/values-sv/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-sv/strings_sc.xml
rename to library/ui-strings/src/main/res/values-sv/strings_sc.xml
diff --git a/vector/src/main/res/values-szl/strings.xml b/library/ui-strings/src/main/res/values-szl/strings.xml
similarity index 100%
rename from vector/src/main/res/values-szl/strings.xml
rename to library/ui-strings/src/main/res/values-szl/strings.xml
diff --git a/vector/src/main/res/values-szl/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-szl/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-szl/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-szl/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-ta/strings.xml b/library/ui-strings/src/main/res/values-ta/strings.xml
similarity index 100%
rename from vector/src/main/res/values-ta/strings.xml
rename to library/ui-strings/src/main/res/values-ta/strings.xml
diff --git a/vector/src/main/res/values-te/strings.xml b/library/ui-strings/src/main/res/values-te/strings.xml
similarity index 100%
rename from vector/src/main/res/values-te/strings.xml
rename to library/ui-strings/src/main/res/values-te/strings.xml
diff --git a/vector/src/main/res/values-te/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-te/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-te/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-te/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-th/strings.xml b/library/ui-strings/src/main/res/values-th/strings.xml
similarity index 100%
rename from vector/src/main/res/values-th/strings.xml
rename to library/ui-strings/src/main/res/values-th/strings.xml
diff --git a/vector/src/main/res/values-th/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-th/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-th/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-th/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-tlh/strings.xml b/library/ui-strings/src/main/res/values-tlh/strings.xml
similarity index 100%
rename from vector/src/main/res/values-tlh/strings.xml
rename to library/ui-strings/src/main/res/values-tlh/strings.xml
diff --git a/vector/src/main/res/values-tlh/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-tlh/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-tlh/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-tlh/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-tr/strings.xml b/library/ui-strings/src/main/res/values-tr/strings.xml
similarity index 100%
rename from vector/src/main/res/values-tr/strings.xml
rename to library/ui-strings/src/main/res/values-tr/strings.xml
diff --git a/vector/src/main/res/values-tr/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-tr/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-tr/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-tr/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-tr/strings_sc.xml b/library/ui-strings/src/main/res/values-tr/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-tr/strings_sc.xml
rename to library/ui-strings/src/main/res/values-tr/strings_sc.xml
diff --git a/vector/src/main/res/values-tzm/strings.xml b/library/ui-strings/src/main/res/values-tzm/strings.xml
similarity index 100%
rename from vector/src/main/res/values-tzm/strings.xml
rename to library/ui-strings/src/main/res/values-tzm/strings.xml
diff --git a/vector/src/main/res/values-tzm/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-tzm/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-tzm/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-tzm/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-uk/strings.xml b/library/ui-strings/src/main/res/values-uk/strings.xml
similarity index 98%
rename from vector/src/main/res/values-uk/strings.xml
rename to library/ui-strings/src/main/res/values-uk/strings.xml
index bf786be0c4..1c809fff3e 100644
--- a/vector/src/main/res/values-uk/strings.xml
+++ b/library/ui-strings/src/main/res/values-uk/strings.xml
@@ -2700,4 +2700,40 @@
\nМожливо, цей домашній сервер не налаштовано для показу карт.
Відкрити налаштування
Усі бесіди
+ Показати всі сеанси (V2, WIP)
+ Для найкращої безпеки перевірте свої сеанси та вийдіть з усіх сеансів, які ви більше не розпізнаєте або не використовуєте.
+ Інші сеанси
+ Сеанси
+ Відкрити список кімнат
+ Створити нову розмову або кімнату
+ Люди
+ Обрані
+ Непрочитані
+ Усі
+ А - Я
+ Діяльністю
+ Упорядкувати за
+ Показувати останні
+ Показати фільтри
+ Налаштування макета
+ Знайти кімнати
+ Створити кімнату
+ Розпочати бесіду
+ Не звірений · Остання активність %1$s
+ Звірений · Остання активність %1$s
+ Переглянути всі (%1$d)
+ Поточний сеанс
+ Переглянути подробиці
+ Звірити сеанс
+ Звірте свій поточний сеанс для безпечнішого обміну повідомленнями.
+ Ваш поточний сеанс готовий для безпечного обміну повідомленнями.
+ Не звірений сеанс
+ Звірений сеанс
+ Невідомий тип пристрою
+ Комп\'ютер
+ Браузер
+ Мобільний
+ Перепрошуємо, цю кімнату не знайдено.
+\nСпробуйте пізніше.%s
+ Запрошення
diff --git a/vector/src/main/res/values-uk/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-uk/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-uk/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-uk/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-ur/strings.xml b/library/ui-strings/src/main/res/values-ur/strings.xml
similarity index 100%
rename from vector/src/main/res/values-ur/strings.xml
rename to library/ui-strings/src/main/res/values-ur/strings.xml
diff --git a/vector/src/main/res/values-uz/strings.xml b/library/ui-strings/src/main/res/values-uz/strings.xml
similarity index 100%
rename from vector/src/main/res/values-uz/strings.xml
rename to library/ui-strings/src/main/res/values-uz/strings.xml
diff --git a/vector/src/main/res/values-uz/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-uz/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-uz/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-uz/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-vi/strings.xml b/library/ui-strings/src/main/res/values-vi/strings.xml
similarity index 100%
rename from vector/src/main/res/values-vi/strings.xml
rename to library/ui-strings/src/main/res/values-vi/strings.xml
diff --git a/vector/src/main/res/values-vi/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-vi/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-vi/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-vi/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-vi/strings_sc.xml b/library/ui-strings/src/main/res/values-vi/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-vi/strings_sc.xml
rename to library/ui-strings/src/main/res/values-vi/strings_sc.xml
diff --git a/vector/src/main/res/values-vls/strings.xml b/library/ui-strings/src/main/res/values-vls/strings.xml
similarity index 100%
rename from vector/src/main/res/values-vls/strings.xml
rename to library/ui-strings/src/main/res/values-vls/strings.xml
diff --git a/vector/src/main/res/values-vls/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-vls/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-vls/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-vls/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-zh-rCN/strings.xml b/library/ui-strings/src/main/res/values-zh-rCN/strings.xml
similarity index 98%
rename from vector/src/main/res/values-zh-rCN/strings.xml
rename to library/ui-strings/src/main/res/values-zh-rCN/strings.xml
index 3083978734..4e1c8e61c8 100644
--- a/vector/src/main/res/values-zh-rCN/strings.xml
+++ b/library/ui-strings/src/main/res/values-zh-rCN/strings.xml
@@ -1309,7 +1309,7 @@
管理会话
登出此会话
加密信息不可用
- 此会话对安全消息可信因为你已验证它:
+ 因为你已验证此会话,所以其在安全地收发消息上可受信任:
验证此会话以将其标记为可信,并授予其访问加密消息的权限。如果你未登录此会话,则你的账户可能已被盗:
- %d 个活动会话
@@ -1323,7 +1323,7 @@
会话
可信任
未信任
- 此会话可信任,可以用于收发加密消息,因为 %1$s(%2$s)已验证了它:
+ 可信任此会话用于安全地收发消息,因为%1$s(%2$s)已验证了它:
%1$s (%2$s) 使用新会话登录:
在此用户信任此会话之前,发送到该会话和从该会话发送的消息均标有警告。或者,你可以手动进行验证。
初始化交叉签名
@@ -1682,7 +1682,7 @@
"话题: "
添加一个话题
%s让人们知道此房间是关于什么的。
- 这是你和 %s 的私聊消息历史记录的开始。
+ 这是你和%s的私聊消息历史的开始。
这是此对话的开始。
这是 %s 的开始。
导出审计
@@ -2550,4 +2550,37 @@
\n此主服务器可能没有设置好显示地图。
打开设置
全部聊天
-
+ 显示全部会话(V2, WIP)
+ 为获得最佳安全性,请验证你的会话,并从任何你不认识或不再使用的会话登出。
+ 其他会话
+ 会话
+ 打开空间列表
+ 创建新对话或房间
+ 人
+ 收藏
+ 未读
+ 全部
+ A—Z
+ 活动
+ 排序方式
+ 显示最近的
+ 显示过滤条件
+ 布局偏好
+ 探索房间
+ 创建房间
+ 开始聊天
+ 抱歉,未发现此房间。
+\n请晚些重试。%s
+ 未验证 · 上次活跃 %1$s
+ 已验证 · 上次活跃 %1$s
+ 查看全部(%1$d)
+ 当前会话
+ 查看详情
+ 验证会话
+ 为了获得增强的安全的消息传送,请验证你当前的会话。
+ 你的当前会话已准备好安全地收发消息。
+ 未验证的会话
+ 已验证的会话
+ 未知的设备类型
+ 邀请
+
\ No newline at end of file
diff --git a/vector/src/main/res/values-zh-rCN/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-zh-rCN/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-zh-rCN/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-zh-rCN/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-zh-rCN/strings_sc.xml b/library/ui-strings/src/main/res/values-zh-rCN/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-zh-rCN/strings_sc.xml
rename to library/ui-strings/src/main/res/values-zh-rCN/strings_sc.xml
diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/library/ui-strings/src/main/res/values-zh-rTW/strings.xml
similarity index 98%
rename from vector/src/main/res/values-zh-rTW/strings.xml
rename to library/ui-strings/src/main/res/values-zh-rTW/strings.xml
index 91388ed561..0f5208bcde 100644
--- a/vector/src/main/res/values-zh-rTW/strings.xml
+++ b/library/ui-strings/src/main/res/values-zh-rTW/strings.xml
@@ -2550,4 +2550,40 @@
\n此家伺服器可能未設定好顯示地圖。
開啟設定
所有聊天
+ 顯示所有工作階段 (V2, WIP)
+ 為了取得最佳安全性,請驗證您的工作階段並登出任何您無法識別或不再使用的工作階段。
+ 其他工作階段
+ 工作階段
+ 開啟空間清單
+ 建立新的對話或聊天室
+ 聯絡人
+ 最愛
+ 未讀
+ 全部
+ A - Z
+ 排序由
+ 活動
+ 顯示最近的
+ 顯示過濾條件
+ 佈局偏好設定
+ 探索聊天室
+ 建立聊天室
+ 開始聊天
+ 未驗證 · 最後活動 %1$s
+ 已驗證 · 最後活動 %1$s
+ 檢視全部 (%1$d)
+ 目前工作階段
+ 檢視詳細資訊
+ 驗證工作階段
+ 驗證您目前的工作階段以強化安全通訊。
+ 您目前的工作階段已準備好進行安全通訊。
+ 未驗證的工作階段
+ 已驗證的工作階段
+ 未知的裝置類型
+ 桌面
+ 網頁
+ 行動裝置
+ 抱歉,找不到此聊天室。
+\n請稍後再試。%s
+ 邀請
diff --git a/vector/src/main/res/values-zh-rTW/strings_no_weblate.xml b/library/ui-strings/src/main/res/values-zh-rTW/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values-zh-rTW/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values-zh-rTW/strings_no_weblate.xml
diff --git a/vector/src/main/res/values-zh-rTW/strings_sc.xml b/library/ui-strings/src/main/res/values-zh-rTW/strings_sc.xml
similarity index 100%
rename from vector/src/main/res/values-zh-rTW/strings_sc.xml
rename to library/ui-strings/src/main/res/values-zh-rTW/strings_sc.xml
diff --git a/vector/src/main/res/values/array.xml b/library/ui-strings/src/main/res/values/array.xml
similarity index 100%
rename from vector/src/main/res/values/array.xml
rename to library/ui-strings/src/main/res/values/array.xml
diff --git a/vector/src/main/res/values/donottranslate.xml b/library/ui-strings/src/main/res/values/donottranslate.xml
similarity index 100%
rename from vector/src/main/res/values/donottranslate.xml
rename to library/ui-strings/src/main/res/values/donottranslate.xml
diff --git a/vector/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml
similarity index 96%
rename from vector/src/main/res/values/strings.xml
rename to library/ui-strings/src/main/res/values/strings.xml
index 980524dee8..6a87ce82f4 100644
--- a/vector/src/main/res/values/strings.xml
+++ b/library/ui-strings/src/main/res/values/strings.xml
@@ -141,6 +141,10 @@
Create Room
Change Space
Explore Rooms
+
+ Expand %s children
+
+ Collapse %s children
@@ -435,12 +439,25 @@
Activity
A - Z
+ Enable new layout
+ A simplified Element with optional tabs
+
Invites
Low priority
"System Alerts"
Suggested Rooms
+
+ No spaces yet.
+ Spaces are a new way to group rooms and people. Create a space to get started.
+
+
+ Invites
+
+ Nothing new.
+ This is where your new requests and invites will be.
+
Conversations
Matrix contacts only
@@ -1345,6 +1362,9 @@
Start the system camera instead of the custom camera screen.
To continue you need to accept the Terms of this service.
+
+ Sorry, this room has not been found.\nPlease retry later.%s
+
You added a new session \'%s\', which is requesting encryption keys.
A new session is requesting encryption keys.\nSession name: %1$s\nLast seen: %2$s\nIf you didn’t log in on another session, ignore this request.
@@ -3204,4 +3224,67 @@
Show All Sessions (V2, WIP)
+ Mobile
+ Web
+ Desktop
+ Unknown device type
+ Verified session
+ Unverified session
+
+ Your current session is ready for secure messaging.
+
+ Verify your current session for enhanced secure messaging.
+ Your current session is ready for secure messaging.
+ This session is ready for secure messaging.
+ Verify your current session for enhanced secure messaging.
+ Verify or sign out from this session for best security and reliability.
+ Verify Session
+ View Details
+
+ Current Session
+ View All (%1$d)
+
+ Verified · Last activity %1$s
+
+ Unverified · Last activity %1$s
+
+
+ - Inactive for %1$d+ day (%2$s)
+ - Inactive for %1$d+ days (%2$s)
+
+ Security recommendations
+ Improve your account security by following these recommendations.
+ Unverified sessions
+ Verify or sign out from unverified sessions.
+ Inactive sessions
+
+ - Consider signing out from old sessions (%1$d day or more) that you don’t use anymore.
+ - Consider signing out from old sessions (%1$d days or more) that you don’t use anymore.
+
+ Current Session
+ Session
+
+ Last activity %1$s
+
+
+ %s\nis looking a little empty.
+
+ Spaces are a new way to group rooms and people. Add an existing room, or create a new one, using the bottom-right button.
+
+ Welcome to ${app_name},\n%s.
+ The all-in-one secure chat app for teams, friends and organisations. Create a chat, or join an existing room, to get started.
+ Nothing to report.
+ This is where your unread messages will show up, when you have some.
+
+ Welcome to a new view!
+
+ To simplify your ${app_name}, tabs are now optional. Manage them using the top-right menu.
+ Access Spaces
+
+ Access your Spaces (bottom-right) faster and easier than ever before.
+ Give Feedback
+
+ Tap top right to see the option to feedback.
+ Try it out
+
diff --git a/vector/src/main/res/values/strings_no_weblate.xml b/library/ui-strings/src/main/res/values/strings_no_weblate.xml
similarity index 100%
rename from vector/src/main/res/values/strings_no_weblate.xml
rename to library/ui-strings/src/main/res/values/strings_no_weblate.xml
diff --git a/library/ui-styles/src/debug/AndroidManifest.xml b/library/ui-styles/src/debug/AndroidManifest.xml
index e32676136d..4692043110 100644
--- a/library/ui-styles/src/debug/AndroidManifest.xml
+++ b/library/ui-styles/src/debug/AndroidManifest.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/library/ui-styles/src/main/res/values-h720dp/dimens.xml b/library/ui-styles/src/main/res/values-h720dp/dimens.xml
index 1a7791720d..2a7b12cf2f 100644
--- a/library/ui-styles/src/main/res/values-h720dp/dimens.xml
+++ b/library/ui-styles/src/main/res/values-h720dp/dimens.xml
@@ -2,4 +2,8 @@
- 0.05
- 0.40
-
\ No newline at end of file
+
+ 16dp
+ 40dp
+ 46dp
+
diff --git a/library/ui-styles/src/main/res/values/colors.xml b/library/ui-styles/src/main/res/values/colors.xml
index 8660ef0c98..7333618df6 100644
--- a/library/ui-styles/src/main/res/values/colors.xml
+++ b/library/ui-styles/src/main/res/values/colors.xml
@@ -147,6 +147,7 @@
#8BC34A
#212121
#FF4B55
+ #0FFF4B55
diff --git a/library/ui-styles/src/main/res/values/dimens.xml b/library/ui-styles/src/main/res/values/dimens.xml
index f310e17f97..71d96c7e5c 100644
--- a/library/ui-styles/src/main/res/values/dimens.xml
+++ b/library/ui-styles/src/main/res/values/dimens.xml
@@ -78,4 +78,9 @@
112dp
+
+
+ 8dp
+ 16dp
+ 28dp
diff --git a/library/ui-styles/src/main/res/values/stylable_devices_list_header_view.xml b/library/ui-styles/src/main/res/values/stylable_devices_list_header_view.xml
index f0807f89c6..97e0290815 100644
--- a/library/ui-styles/src/main/res/values/stylable_devices_list_header_view.xml
+++ b/library/ui-styles/src/main/res/values/stylable_devices_list_header_view.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/library/ui-styles/src/main/res/values/stylable_security_recommendation_view.xml b/library/ui-styles/src/main/res/values/stylable_security_recommendation_view.xml
new file mode 100644
index 0000000000..4283c8da8a
--- /dev/null
+++ b/library/ui-styles/src/main/res/values/stylable_security_recommendation_view.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/library/ui-styles/src/main/res/values/styles_devices_management.xml b/library/ui-styles/src/main/res/values/styles_devices_management.xml
index 2a63c2ed36..6fb236d3e6 100644
--- a/library/ui-styles/src/main/res/values/styles_devices_management.xml
+++ b/library/ui-styles/src/main/res/values/styles_devices_management.xml
@@ -7,6 +7,7 @@
diff --git a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt
index f22cfa369a..80ed311901 100644
--- a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt
+++ b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt
@@ -72,7 +72,7 @@ class FlowSession(private val session: Session) {
}
fun liveMyDevicesInfo(): Flow> {
- return session.cryptoService().getLiveMyDevicesInfo().asFlow()
+ return session.cryptoService().getMyDevicesInfoLive().asFlow()
.startWith(session.coroutineDispatchers.io) {
session.cryptoService().getMyDevicesInfo()
}
diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle
index aa8731da2a..7b06edb530 100644
--- a/matrix-sdk-android/build.gradle
+++ b/matrix-sdk-android/build.gradle
@@ -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"
@@ -198,8 +199,7 @@ dependencies {
// Exif data handling
implementation libs.apache.commonsImaging
- // Phone number https://github.com/google/libphonenumber
- implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.54'
+ implementation libs.google.phonenumber
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/androidTest/java/org/matrix/android/sdk/internal/crypto/CryptoStoreHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/CryptoStoreHelper.kt
index ba1afd4758..48cfbebe5b 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/CryptoStoreHelper.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/CryptoStoreHelper.kt
@@ -21,6 +21,7 @@ import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStore
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreModule
import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper
+import org.matrix.android.sdk.internal.crypto.store.db.mapper.MyDeviceLastSeenInfoEntityMapper
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.util.time.DefaultClock
import kotlin.random.Random
@@ -37,6 +38,7 @@ internal class CryptoStoreHelper {
userId = "userId_" + Random.nextInt(),
deviceId = "deviceId_sample",
clock = DefaultClock(),
+ myDeviceLastSeenInfoEntityMapper = MyDeviceLastSeenInfoEntityMapper()
)
}
}
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt
index 251c13ccbf..f883295495 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt
@@ -676,8 +676,8 @@ class E2eeSanityTests : InstrumentedTest {
assertEquals("Decimal code should have matched", oldCode, newCode)
// Assert that devices are verified
- val newDeviceFromOldPov: CryptoDeviceInfo? = aliceSession.cryptoService().getDeviceInfo(aliceSession.myUserId, aliceNewSession.sessionParams.deviceId)
- val oldDeviceFromNewPov: CryptoDeviceInfo? = aliceSession.cryptoService().getDeviceInfo(aliceSession.myUserId, aliceSession.sessionParams.deviceId)
+ val newDeviceFromOldPov: CryptoDeviceInfo? = aliceSession.cryptoService().getCryptoDeviceInfo(aliceSession.myUserId, aliceNewSession.sessionParams.deviceId)
+ val oldDeviceFromNewPov: CryptoDeviceInfo? = aliceSession.cryptoService().getCryptoDeviceInfo(aliceSession.myUserId, aliceSession.sessionParams.deviceId)
Assert.assertTrue("new device should be verified from old point of view", newDeviceFromOldPov!!.isVerified)
Assert.assertTrue("old device should be verified from new point of view", oldDeviceFromNewPov!!.isVerified)
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt
index 8cb38ddc87..ef3fdfeeda 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt
@@ -193,7 +193,7 @@ class XSigningTest : InstrumentedTest {
fail("Bob should see the new device")
}
- val bobSecondDevicePOVFirstDevice = bobSession.cryptoService().getDeviceInfo(bobUserId, bobSecondDeviceId)
+ val bobSecondDevicePOVFirstDevice = bobSession.cryptoService().getCryptoDeviceInfo(bobUserId, bobSecondDeviceId)
assertNotNull("Bob Second device should be known and persisted from first", bobSecondDevicePOVFirstDevice)
// Manually mark it as trusted from first session
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt
index c2e74abc59..1bffbeeeaa 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt
@@ -521,9 +521,9 @@ class SASTest : InstrumentedTest {
testHelper.await(bobSASLatch)
// Assert that devices are verified
- val bobDeviceInfoFromAlicePOV: CryptoDeviceInfo? = aliceSession.cryptoService().getDeviceInfo(bobUserId, bobDeviceId)
+ val bobDeviceInfoFromAlicePOV: CryptoDeviceInfo? = aliceSession.cryptoService().getCryptoDeviceInfo(bobUserId, bobDeviceId)
val aliceDeviceInfoFromBobPOV: CryptoDeviceInfo? =
- bobSession.cryptoService().getDeviceInfo(aliceSession.myUserId, aliceSession.cryptoService().getMyDevice().deviceId)
+ bobSession.cryptoService().getCryptoDeviceInfo(aliceSession.myUserId, aliceSession.cryptoService().getMyDevice().deviceId)
assertTrue("alice device should be verified from bob point of view", aliceDeviceInfoFromBobPOV!!.isVerified)
assertTrue("bob device should be verified from alice point of view", bobDeviceInfoFromAlicePOV!!.isVerified)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt
index a5e05f69e0..e0e662c789 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt
@@ -40,6 +40,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationServic
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.content.RoomKeyWithHeldContent
+import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.crypto.model.SessionInfo
interface CryptoService {
@@ -113,7 +114,19 @@ interface CryptoService {
fun setRoomBlacklistUnverifiedDevices(roomId: String)
- fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo?
+ fun getCryptoDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo?
+
+ fun getCryptoDeviceInfo(deviceId: String, callback: MatrixCallback)
+
+ fun getCryptoDeviceInfo(userId: String): List
+
+ fun getLiveCryptoDeviceInfo(): LiveData>
+
+ fun getLiveCryptoDeviceInfoWithId(deviceId: String): LiveData>
+
+ fun getLiveCryptoDeviceInfo(userId: String): LiveData>
+
+ fun getLiveCryptoDeviceInfo(userIds: List): LiveData>
fun requestRoomKeyForEvent(event: Event)
@@ -127,9 +140,9 @@ interface CryptoService {
fun getMyDevicesInfo(): List
- fun getLiveMyDevicesInfo(): LiveData>
+ fun getMyDevicesInfoLive(): LiveData>
- fun getDeviceInfo(deviceId: String, callback: MatrixCallback)
+ fun getMyDevicesInfoLive(deviceId: String): LiveData>
fun inboundGroupSessionsCount(onlyBackedUp: Boolean): Int
@@ -156,14 +169,6 @@ interface CryptoService {
fun downloadKeys(userIds: List, forceDownload: Boolean, callback: MatrixCallback>)
- fun getCryptoDeviceInfo(userId: String): List
-
- fun getLiveCryptoDeviceInfo(): LiveData>
-
- fun getLiveCryptoDeviceInfo(userId: String): LiveData>
-
- fun getLiveCryptoDeviceInfo(userIds: List): LiveData>
-
fun addNewSessionListener(newSessionListener: NewSessionListener)
fun removeSessionListener(listener: NewSessionListener)
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 25c068388d..5d011bbe29 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/room/timeline/Timeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/Timeline.kt
index b5136933be..8a98ef798f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/Timeline.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/Timeline.kt
@@ -74,7 +74,7 @@ interface Timeline {
/**
* Set the offset for the target event, e.g. if we want to load the event just below said id
*/
- fun getTargetEventOffset(offset: Int)
+ fun setTargetEventOffset(offset: Int)
/**
* Check if the timeline can be enriched by paginating.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
index 35c066dea8..8dd7c309c6 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
@@ -73,6 +73,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityConten
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.session.room.model.shouldShareHistory
import org.matrix.android.sdk.api.session.sync.model.SyncResponse
+import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.crypto.actions.MegolmSessionDataImporter
import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
import org.matrix.android.sdk.internal.crypto.algorithms.IMXEncrypting
@@ -273,23 +274,18 @@ internal class DefaultCryptoService @Inject constructor(
.executeBy(taskExecutor)
}
- override fun getLiveMyDevicesInfo(): LiveData> {
+ override fun getMyDevicesInfoLive(): LiveData> {
return cryptoStore.getLiveMyDevicesInfo()
}
+ override fun getMyDevicesInfoLive(deviceId: String): LiveData> {
+ return cryptoStore.getLiveMyDevicesInfo(deviceId)
+ }
+
override fun getMyDevicesInfo(): List {
return cryptoStore.getMyDevicesInfo()
}
- override fun getDeviceInfo(deviceId: String, callback: MatrixCallback) {
- getDeviceInfoTask
- .configureWith(GetDeviceInfoTask.Params(deviceId)) {
- this.executionThread = TaskThread.CRYPTO
- this.callback = callback
- }
- .executeBy(taskExecutor)
- }
-
override fun inboundGroupSessionsCount(onlyBackedUp: Boolean): Int {
return cryptoStore.inboundGroupSessionsCount(onlyBackedUp)
}
@@ -513,7 +509,7 @@ internal class DefaultCryptoService @Inject constructor(
* @param userId the user id
* @param deviceId the device id
*/
- override fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? {
+ override fun getCryptoDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? {
return if (userId.isNotEmpty() && !deviceId.isNullOrEmpty()) {
cryptoStore.getUserDevice(userId, deviceId)
} else {
@@ -521,6 +517,15 @@ internal class DefaultCryptoService @Inject constructor(
}
}
+ override fun getCryptoDeviceInfo(deviceId: String, callback: MatrixCallback) {
+ getDeviceInfoTask
+ .configureWith(GetDeviceInfoTask.Params(deviceId)) {
+ this.executionThread = TaskThread.CRYPTO
+ this.callback = callback
+ }
+ .executeBy(taskExecutor)
+ }
+
override fun getCryptoDeviceInfo(userId: String): List {
return cryptoStore.getUserDeviceList(userId).orEmpty()
}
@@ -529,6 +534,10 @@ internal class DefaultCryptoService @Inject constructor(
return cryptoStore.getLiveDeviceList()
}
+ override fun getLiveCryptoDeviceInfoWithId(deviceId: String): LiveData> {
+ return cryptoStore.getLiveDeviceWithId(deviceId)
+ }
+
override fun getLiveCryptoDeviceInfo(userId: String): LiveData> {
return cryptoStore.getLiveDeviceList(userId)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt
index e466def1a1..d405bdce27 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt
@@ -779,6 +779,11 @@ internal class DefaultCrossSigningService @Inject constructor(
override fun onUsersDeviceUpdate(userIds: List) {
Timber.d("## CrossSigning - onUsersDeviceUpdate for users: ${userIds.logLimit()}")
+ checkTrustAndAffectedRoomShields(userIds)
+ }
+
+ fun checkTrustAndAffectedRoomShields(userIds: List) {
+ Timber.d("## CrossSigning - checkTrustAndAffectedRoomShields for users: ${userIds.logLimit()}")
val workerParams = UpdateTrustWorker.Params(
sessionId = sessionId,
filename = updateTrustWorkerDataRepository.createParam(userIds)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt
index f1dc060e10..6d845ec59e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt
@@ -207,6 +207,7 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
private suspend fun updateTrustStep2(userList: List, myCrossSigningInfo: MXCrossSigningInfo?) {
Timber.d("## CrossSigning - Updating shields for impacted rooms...")
awaitTransaction(sessionRealmConfiguration) { sessionRealm ->
+ Timber.d("## CrossSigning - Updating shields for impacted rooms - in transaction")
Realm.getInstance(cryptoRealmConfiguration).use { cryptoRealm ->
sessionRealm.where(RoomMemberSummaryEntity::class.java)
.`in`(RoomMemberSummaryEntityFields.USER_ID, userList.toTypedArray())
@@ -239,6 +240,7 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
}
}
}
+ Timber.d("## CrossSigning - Updating shields for impacted rooms - END")
}
private fun getCrossSigningInfo(cryptoRealm: Realm, userId: String): MXCrossSigningInfo? {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt
index 0413fc730c..56eba25249 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt
@@ -238,10 +238,14 @@ internal interface IMXCryptoStore {
// TODO temp
fun getLiveDeviceList(): LiveData>
+ fun getLiveDeviceWithId(deviceId: String): LiveData>
+
fun getMyDevicesInfo(): List
fun getLiveMyDevicesInfo(): LiveData>
+ fun getLiveMyDevicesInfo(deviceId: String): LiveData>
+
fun saveMyDevicesInfo(info: List)
/**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt
index 31a82eb58a..56430566c0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt
@@ -55,6 +55,7 @@ import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
import org.matrix.android.sdk.internal.crypto.model.OutboundGroupSessionWrapper
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper
+import org.matrix.android.sdk.internal.crypto.store.db.mapper.MyDeviceLastSeenInfoEntityMapper
import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailMapper
@@ -68,6 +69,7 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity
+import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntity
@@ -112,6 +114,7 @@ internal class RealmCryptoStore @Inject constructor(
@UserId private val userId: String,
@DeviceId private val deviceId: String?,
private val clock: Clock,
+ private val myDeviceLastSeenInfoEntityMapper: MyDeviceLastSeenInfoEntityMapper,
) : IMXCryptoStore {
/* ==========================================================================================
@@ -580,6 +583,12 @@ internal class RealmCryptoStore @Inject constructor(
}
}
+ override fun getLiveDeviceWithId(deviceId: String): LiveData> {
+ return Transformations.map(getLiveDeviceList()) { devices ->
+ devices.firstOrNull { it.deviceId == deviceId }.toOptional()
+ }
+ }
+
override fun getMyDevicesInfo(): List {
return monarchy.fetchAllCopiedSync {
it.where()
@@ -598,17 +607,24 @@ internal class RealmCryptoStore @Inject constructor(
{ realm: Realm ->
realm.where()
},
- { entity ->
- DeviceInfo(
- deviceId = entity.deviceId,
- lastSeenIp = entity.lastSeenIp,
- lastSeenTs = entity.lastSeenTs,
- displayName = entity.displayName
- )
- }
+ { entity -> myDeviceLastSeenInfoEntityMapper.map(entity) }
)
}
+ override fun getLiveMyDevicesInfo(deviceId: String): LiveData> {
+ val liveData = monarchy.findAllMappedWithChanges(
+ { realm: Realm ->
+ realm.where()
+ .equalTo(MyDeviceLastSeenInfoEntityFields.DEVICE_ID, deviceId)
+ },
+ { entity -> myDeviceLastSeenInfoEntityMapper.map(entity) }
+ )
+
+ return Transformations.map(liveData) {
+ it.firstOrNull().toOptional()
+ }
+ }
+
override fun saveMyDevicesInfo(info: List) {
val entities = info.map {
MyDeviceLastSeenInfoEntity(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapper.kt
new file mode 100644
index 0000000000..38a7569aab
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapper.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.crypto.store.db.mapper
+
+import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
+import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity
+import javax.inject.Inject
+
+internal class MyDeviceLastSeenInfoEntityMapper @Inject constructor() {
+
+ fun map(entity: MyDeviceLastSeenInfoEntity): DeviceInfo {
+ return DeviceInfo(
+ deviceId = entity.deviceId,
+ lastSeenIp = entity.lastSeenIp,
+ lastSeenTs = entity.lastSeenTs,
+ displayName = entity.displayName
+ )
+ }
+}
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/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt
index 5f49688ebe..7234c22613 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
@@ -58,6 +58,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 timber.log.Timber
@@ -81,7 +82,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
private val scSchemaVersion = 6L
private val scSchemaVersionOffset = (1L shl 12)
- val schemaVersion = 35L +
+ val schemaVersion = 36L +
scSchemaVersion * scSchemaVersionOffset
}
@@ -133,6 +134,7 @@ 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()
if (oldScVersion <= 0) MigrateScSessionTo001(realm).perform()
if (oldScVersion <= 1) MigrateScSessionTo002(realm).perform()
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/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/di/NetworkModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/NetworkModule.kt
index 113e780e5c..cb2088a145 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/NetworkModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/NetworkModule.kt
@@ -42,7 +42,7 @@ internal object NetworkModule {
@Provides
@JvmStatic
fun providesHttpLoggingInterceptor(): HttpLoggingInterceptor {
- val logger = FormattedJsonHttpLogger()
+ val logger = FormattedJsonHttpLogger(BuildConfig.OKHTTP_LOGGING_LEVEL)
val interceptor = HttpLoggingInterceptor(logger)
interceptor.level = BuildConfig.OKHTTP_LOGGING_LEVEL
return interceptor
diff --git a/matrix-sdk-android/src/debug/java/org/matrix/android/sdk/internal/network/interceptors/FormattedJsonHttpLogger.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/interceptors/FormattedJsonHttpLogger.kt
similarity index 84%
rename from matrix-sdk-android/src/debug/java/org/matrix/android/sdk/internal/network/interceptors/FormattedJsonHttpLogger.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/interceptors/FormattedJsonHttpLogger.kt
index 2661bd1f70..4e0525536c 100644
--- a/matrix-sdk-android/src/debug/java/org/matrix/android/sdk/internal/network/interceptors/FormattedJsonHttpLogger.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/interceptors/FormattedJsonHttpLogger.kt
@@ -23,15 +23,17 @@ import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
-internal class FormattedJsonHttpLogger : HttpLoggingInterceptor.Logger {
+internal class FormattedJsonHttpLogger(
+ private val level: HttpLoggingInterceptor.Level
+) : HttpLoggingInterceptor.Logger {
companion object {
private const val INDENT_SPACE = 2
}
/**
- * Log the message and try to log it again as a JSON formatted string
- * Note: it can consume a lot of memory but it is only in DEBUG mode
+ * Log the message and try to log it again as a JSON formatted string.
+ * Note: it can consume a lot of memory but it is only in DEBUG mode.
*
* @param message
*/
@@ -39,6 +41,10 @@ internal class FormattedJsonHttpLogger : HttpLoggingInterceptor.Logger {
override fun log(@NonNull message: String) {
Timber.v(message)
+ // Try to log formatted Json only if there is a chance that [message] contains Json.
+ // It can be only the case if we log the bodies of Http requests.
+ if (level != HttpLoggingInterceptor.Level.BODY) return
+
if (message.startsWith("{")) {
// JSON Detected
try {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt
index a79f35bcb6..a7572035df 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt
@@ -55,6 +55,7 @@ import org.matrix.android.sdk.internal.session.space.SpaceModule
import org.matrix.android.sdk.internal.session.sync.SyncModule
import org.matrix.android.sdk.internal.session.sync.SyncTask
import org.matrix.android.sdk.internal.session.sync.SyncTokenStore
+import org.matrix.android.sdk.internal.session.sync.handler.UpdateUserWorker
import org.matrix.android.sdk.internal.session.sync.job.SyncWorker
import org.matrix.android.sdk.internal.session.terms.TermsModule
import org.matrix.android.sdk.internal.session.thirdparty.ThirdPartyModule
@@ -128,6 +129,8 @@ internal interface SessionComponent {
fun inject(worker: UpdateTrustWorker)
+ fun inject(worker: UpdateUserWorker)
+
fun inject(worker: DeactivateLiveLocationShareWorker)
@Component.Factory
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 af0cc9919b..7fddb5e7ce 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
@@ -215,6 +219,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/RoomMemberEventHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt
index fd6552525e..cb7bbf07fc 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt
@@ -140,7 +140,8 @@ internal class RoomMemberEventHandler @Inject constructor(
val previousDisplayName = prevContent?.get("displayname") as? String
val previousAvatar = prevContent?.get("avatar_url") as? String
- if (previousDisplayName != roomMember.displayName || previousAvatar != roomMember.avatarUrl) {
+ if ((previousDisplayName != null && previousDisplayName != roomMember.displayName) ||
+ (previousAvatar != null && previousAvatar != roomMember.avatarUrl)) {
aggregator.userIdsToFetch.add(eventUserId)
}
}
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/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/summary/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt
index cdeca06015..e2c9795cb3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt
@@ -68,6 +68,7 @@ import org.matrix.android.sdk.internal.session.room.accountdata.RoomAccountDataD
import org.matrix.android.sdk.internal.session.room.membership.RoomDisplayNameResolver
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
import org.matrix.android.sdk.internal.session.room.relationship.RoomChildRelationInfo
+import org.matrix.android.sdk.internal.session.sync.SyncResponsePostTreatmentAggregator
import timber.log.Timber
import javax.inject.Inject
import kotlin.math.min
@@ -137,7 +138,8 @@ internal class RoomSummaryUpdater @Inject constructor(
unreadCount: Int? = null,
updateMembers: Boolean = false,
inviterId: String? = null,
- updateCounts: Boolean = true
+ updateCounts: Boolean = true,
+ aggregator: SyncResponsePostTreatmentAggregator? = null
) {
val roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, roomId)
if (roomSummary != null) {
@@ -246,8 +248,14 @@ internal class RoomSummaryUpdater @Inject constructor(
roomSummaryEntity.otherMemberIds.clear()
roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers)
if (roomSummaryEntity.isEncrypted && otherRoomMembers.isNotEmpty()) {
- // mmm maybe we could only refresh shield instead of checking trust also?
- crossSigningService.onUsersDeviceUpdate(otherRoomMembers)
+ if (aggregator == null) {
+ // Do it now
+ // mmm maybe we could only refresh shield instead of checking trust also?
+ crossSigningService.checkTrustAndAffectedRoomShields(otherRoomMembers)
+ } else {
+ // Schedule it
+ aggregator.userIdsForCheckingTrustAndAffectedRoomShields.addAll(otherRoomMembers)
+ }
}
}
}
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 7551af8492..d473d8af3e 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
@@ -484,7 +484,7 @@ internal class DefaultTimeline(
return targetEventOffset
}
- override fun getTargetEventOffset(offset: Int) {
+ override fun setTargetEventOffset(offset: Int) {
targetEventOffset = offset
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt
index f4dede547e..b67a628c0a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt
@@ -127,29 +127,25 @@ internal class SyncResponseHandler @Inject constructor(
// Everything else we need to do outside the transaction
measureTimeMillis {
- Timber.v("Handle Aggregator")
- aggregatorHandler.handle(aggregator)
+ aggregatorHandler.handle(aggregator)
}.also {
- Timber.i("Finish handling Aggregator in $it ms")
+ Timber.i("Aggregator management took $it ms")
}
measureTimeMillis {
- Timber.v("Handle Push rules")
- syncResponse.rooms?.let {
- checkPushRules(it, isInitialSync)
- userAccountDataSyncHandler.synchronizeWithServerIfNeeded(it.invite)
- dispatchInvitedRoom(it)
- }
+ syncResponse.rooms?.let {
+ checkPushRules(it, isInitialSync)
+ userAccountDataSyncHandler.synchronizeWithServerIfNeeded(it.invite)
+ dispatchInvitedRoom(it)
+ }
}.also {
- Timber.i("Finish handling Push rules in $it ms")
+ Timber.i("SyncResponse.rooms post treatment took $it ms")
}
- Timber.v("On sync completed")
measureTimeMillis {
- Timber.v("Handle onSyncCompleted")
- cryptoSyncHandler.onSyncCompleted(syncResponse)
+ cryptoSyncHandler.onSyncCompleted(syncResponse)
}.also {
- Timber.i("Finish handling onSyncCompleted in $it ms")
+ Timber.i("cryptoSyncHandler.onSyncCompleted took $it ms")
}
// post sync stuffs
@@ -159,9 +155,10 @@ internal class SyncResponseHandler @Inject constructor(
roomSyncHandler.postSyncSpaceHierarchyHandle(it)
}
}.also {
- Timber.i("Finish handling postSyncSpaceHierarchy in $it ms")
+ Timber.i("postSyncSpaceHierarchy took $it ms")
}
+ Timber.v("On sync completed")
}
private fun dispatchInvitedRoom(roomsSyncResponse: RoomsSyncResponse) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt
index e9452c59fc..2b7f936fa8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt
@@ -23,6 +23,9 @@ internal class SyncResponsePostTreatmentAggregator {
// Map of roomId to directUserId
val directChatsToCheck = mutableMapOf()
- // List of userIds to fetch and update at the end of incremental syncs
- val userIdsToFetch = mutableListOf()
+ // Set of userIds to fetch and update at the end of incremental syncs
+ val userIdsToFetch = mutableSetOf()
+
+ // Set of users to call `crossSigningService.checkTrustAndAffectedRoomShields` once per sync
+ val userIdsForCheckingTrustAndAffectedRoomShields = mutableSetOf()
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/SyncResponsePostTreatmentAggregatorHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/SyncResponsePostTreatmentAggregatorHandler.kt
index c638ed4f80..c749f77fff 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/SyncResponsePostTreatmentAggregatorHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/SyncResponsePostTreatmentAggregatorHandler.kt
@@ -16,32 +16,39 @@
package org.matrix.android.sdk.internal.session.sync.handler
-import com.zhuinden.monarchy.Monarchy
+import androidx.work.BackoffPolicy
+import androidx.work.ExistingWorkPolicy
import org.matrix.android.sdk.api.MatrixPatterns
-import org.matrix.android.sdk.api.extensions.tryOrNull
-import org.matrix.android.sdk.api.session.user.model.User
-import org.matrix.android.sdk.internal.di.SessionDatabase
-import org.matrix.android.sdk.internal.session.profile.GetProfileInfoTask
+import org.matrix.android.sdk.internal.crypto.crosssigning.DefaultCrossSigningService
+import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorker
+import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorkerDataRepository
+import org.matrix.android.sdk.internal.di.SessionId
+import org.matrix.android.sdk.internal.di.WorkManagerProvider
import org.matrix.android.sdk.internal.session.sync.RoomSyncEphemeralTemporaryStore
import org.matrix.android.sdk.internal.session.sync.SyncResponsePostTreatmentAggregator
import org.matrix.android.sdk.internal.session.sync.model.accountdata.toMutable
-import org.matrix.android.sdk.internal.session.user.UserEntityFactory
import org.matrix.android.sdk.internal.session.user.accountdata.DirectChatsHelper
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask
-import org.matrix.android.sdk.internal.util.awaitTransaction
+import org.matrix.android.sdk.internal.util.logLimit
+import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
+import timber.log.Timber
+import java.util.concurrent.TimeUnit
import javax.inject.Inject
internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor(
private val directChatsHelper: DirectChatsHelper,
private val ephemeralTemporaryStore: RoomSyncEphemeralTemporaryStore,
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
- private val getProfileInfoTask: GetProfileInfoTask,
- @SessionDatabase private val monarchy: Monarchy,
+ private val crossSigningService: DefaultCrossSigningService,
+ private val updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository,
+ private val workManagerProvider: WorkManagerProvider,
+ @SessionId private val sessionId: String,
) {
suspend fun handle(aggregator: SyncResponsePostTreatmentAggregator) {
cleanupEphemeralFiles(aggregator.ephemeralFilesToDelete)
updateDirectUserIds(aggregator.directChatsToCheck)
fetchAndUpdateUsers(aggregator.userIdsToFetch)
+ handleUserIdsForCheckingTrustAndAffectedRoomShields(aggregator.userIdsForCheckingTrustAndAffectedRoomShields)
}
private fun cleanupEphemeralFiles(ephemeralFilesToDelete: List) {
@@ -79,23 +86,26 @@ internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor(
}
}
- private suspend fun fetchAndUpdateUsers(userIdsToFetch: List) {
- fetchUsers(userIdsToFetch)
- .takeIf { it.isNotEmpty() }
- ?.saveLocally()
+ private fun fetchAndUpdateUsers(userIdsToFetch: Collection) {
+ if (userIdsToFetch.isEmpty()) return
+ Timber.d("## Configure Worker to update users: ${userIdsToFetch.logLimit()}")
+ val workerParams = UpdateTrustWorker.Params(
+ sessionId = sessionId,
+ filename = updateTrustWorkerDataRepository.createParam(userIdsToFetch.toList())
+ )
+ val workerData = WorkerParamsFactory.toData(workerParams)
+
+ val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder()
+ .setInputData(workerData)
+ .setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
+ .build()
+
+ workManagerProvider.workManager
+ .beginUniqueWork("USER_UPDATE_QUEUE", ExistingWorkPolicy.APPEND_OR_REPLACE, workRequest)
+ .enqueue()
}
- private suspend fun fetchUsers(userIdsToFetch: List) = userIdsToFetch.mapNotNull {
- tryOrNull {
- val profileJson = getProfileInfoTask.execute(GetProfileInfoTask.Params(it))
- User.fromJson(it, profileJson)
- }
- }
-
- private suspend fun List.saveLocally() {
- val userEntities = map { user -> UserEntityFactory.create(user) }
- monarchy.awaitTransaction {
- it.insertOrUpdate(userEntities)
- }
+ private fun handleUserIdsForCheckingTrustAndAffectedRoomShields(userIdsWithDeviceUpdate: Iterable) {
+ crossSigningService.checkTrustAndAffectedRoomShields(userIdsWithDeviceUpdate.toList())
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UpdateUserWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UpdateUserWorker.kt
new file mode 100644
index 0000000000..1f840a82d5
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UpdateUserWorker.kt
@@ -0,0 +1,99 @@
+/*
+ * 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.sync.handler
+
+import android.content.Context
+import androidx.work.WorkerParameters
+import com.zhuinden.monarchy.Monarchy
+import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.session.user.model.User
+import org.matrix.android.sdk.internal.SessionManager
+import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorker
+import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorkerDataRepository
+import org.matrix.android.sdk.internal.di.SessionDatabase
+import org.matrix.android.sdk.internal.session.SessionComponent
+import org.matrix.android.sdk.internal.session.profile.GetProfileInfoTask
+import org.matrix.android.sdk.internal.session.user.UserEntityFactory
+import org.matrix.android.sdk.internal.util.awaitTransaction
+import org.matrix.android.sdk.internal.util.logLimit
+import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
+import timber.log.Timber
+import javax.inject.Inject
+
+/**
+ * Note: We reuse the same type [UpdateTrustWorker.Params], since the input data are the same.
+ */
+internal class UpdateUserWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
+ SessionSafeCoroutineWorker(context, params, sessionManager, UpdateTrustWorker.Params::class.java) {
+
+ @SessionDatabase
+ @Inject lateinit var monarchy: Monarchy
+ @Inject lateinit var updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository
+ @Inject lateinit var getProfileInfoTask: GetProfileInfoTask
+
+ override fun injectWith(injector: SessionComponent) {
+ injector.inject(this)
+ }
+
+ override suspend fun doSafeWork(params: UpdateTrustWorker.Params): Result {
+ val userList = params.filename
+ ?.let { updateTrustWorkerDataRepository.getParam(it) }
+ ?.userIds
+ ?: params.updatedUserIds.orEmpty()
+
+ // List should not be empty, but let's avoid go further in case of empty list
+ if (userList.isNotEmpty()) {
+ Timber.v("## UpdateUserWorker - updating users: ${userList.logLimit()}")
+ fetchAndUpdateUsers(userList)
+ }
+
+ cleanup(params)
+ return Result.success()
+ }
+
+ private suspend fun fetchAndUpdateUsers(userIdsToFetch: Collection) {
+ fetchUsers(userIdsToFetch)
+ .takeIf { it.isNotEmpty() }
+ ?.saveLocally()
+ }
+
+ private suspend fun fetchUsers(userIdsToFetch: Collection) = userIdsToFetch.mapNotNull {
+ tryOrNull {
+ val profileJson = getProfileInfoTask.execute(GetProfileInfoTask.Params(it))
+ User.fromJson(it, profileJson)
+ }
+ }
+
+ private suspend fun List.saveLocally() {
+ val userEntities = map { user -> UserEntityFactory.create(user) }
+ Timber.d("## saveLocally()")
+ monarchy.awaitTransaction {
+ Timber.d("## saveLocally() - in transaction")
+ it.insertOrUpdate(userEntities)
+ }
+ Timber.d("## saveLocally() - END")
+ }
+
+ private fun cleanup(params: UpdateTrustWorker.Params) {
+ params.filename
+ ?.let { updateTrustWorkerDataRepository.delete(it) }
+ }
+
+ override fun buildErrorParams(params: UpdateTrustWorker.Params, message: String): UpdateTrustWorker.Params {
+ return params.copy(lastFailureMessage = params.lastFailureMessage ?: message)
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt
index 28f9b4c881..618aa216bd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt
@@ -154,12 +154,12 @@ internal class RoomSyncHandler @Inject constructor(
}
is HandlingStrategy.INVITED ->
handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountInvitedRooms, 0.1f) {
- handleInvitedRoom(realm, it.key, it.value, insertType, syncLocalTimeStampMillis)
+ handleInvitedRoom(realm, it.key, it.value, insertType, syncLocalTimeStampMillis, aggregator)
}
is HandlingStrategy.LEFT -> {
handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountLeftRooms, 0.3f) {
- handleLeftRoom(realm, it.key, it.value, insertType, syncLocalTimeStampMillis)
+ handleLeftRoom(realm, it.key, it.value, insertType, syncLocalTimeStampMillis, aggregator)
}
}
}
@@ -286,7 +286,8 @@ internal class RoomSyncHandler @Inject constructor(
roomSync.summary,
roomSync.unreadNotifications,
roomSync.unreadCount,
- updateMembers = hasRoomMember
+ updateMembers = hasRoomMember,
+ aggregator = aggregator
)
return roomEntity
}
@@ -296,7 +297,8 @@ internal class RoomSyncHandler @Inject constructor(
roomId: String,
roomSync: InvitedRoomSync,
insertType: EventInsertType,
- syncLocalTimestampMillis: Long
+ syncLocalTimestampMillis: Long,
+ aggregator: SyncResponsePostTreatmentAggregator
): RoomEntity {
Timber.v("Handle invited sync for room $roomId")
val isInitialSync = insertType == EventInsertType.INITIAL_SYNC
@@ -320,7 +322,7 @@ internal class RoomSyncHandler @Inject constructor(
it.type == EventType.STATE_ROOM_MEMBER
}
roomChangeMembershipStateDataSource.setMembershipFromSync(roomId, Membership.INVITE)
- roomSummaryUpdater.update(realm, roomId, Membership.INVITE, updateMembers = true, inviterId = inviterEvent?.senderId)
+ roomSummaryUpdater.update(realm, roomId, Membership.INVITE, updateMembers = true, inviterId = inviterEvent?.senderId, aggregator = aggregator)
return roomEntity
}
@@ -329,7 +331,8 @@ internal class RoomSyncHandler @Inject constructor(
roomId: String,
roomSync: RoomSync,
insertType: EventInsertType,
- syncLocalTimestampMillis: Long
+ syncLocalTimestampMillis: Long,
+ aggregator: SyncResponsePostTreatmentAggregator
): RoomEntity {
val isInitialSync = insertType == EventInsertType.INITIAL_SYNC
val roomEntity = RoomEntity.getOrCreate(realm, roomId)
@@ -367,7 +370,7 @@ internal class RoomSyncHandler @Inject constructor(
roomEntity.chunks.clearWith { it.deleteOnCascade(deleteStateEvents = true, canDeleteRoot = true) }
roomTypingUsersHandler.handle(realm, roomId, null)
roomChangeMembershipStateDataSource.setMembershipFromSync(roomId, Membership.LEAVE)
- roomSummaryUpdater.update(realm, roomId, membership, roomSync.summary, roomSync.unreadNotifications)
+ roomSummaryUpdater.update(realm, roomId, membership, roomSync.summary, roomSync.unreadNotifications, aggregator = aggregator)
return roomEntity
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt
index 83f9532870..80bbbb7938 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt
@@ -30,6 +30,7 @@ import org.matrix.android.sdk.internal.session.room.aggregation.livelocation.Dea
import org.matrix.android.sdk.internal.session.room.send.MultipleEventSendingDispatcherWorker
import org.matrix.android.sdk.internal.session.room.send.RedactEventWorker
import org.matrix.android.sdk.internal.session.room.send.SendEventWorker
+import org.matrix.android.sdk.internal.session.sync.handler.UpdateUserWorker
import org.matrix.android.sdk.internal.session.sync.job.SyncWorker
import timber.log.Timber
import javax.inject.Inject
@@ -62,6 +63,8 @@ internal class MatrixWorkerFactory @Inject constructor(private val sessionManage
SyncWorker(appContext, workerParameters, sessionManager)
UpdateTrustWorker::class.java.name ->
UpdateTrustWorker(appContext, workerParameters, sessionManager)
+ UpdateUserWorker::class.java.name ->
+ UpdateUserWorker(appContext, workerParameters, sessionManager)
UploadContentWorker::class.java.name ->
UploadContentWorker(appContext, workerParameters, sessionManager)
DeactivateLiveLocationShareWorker::class.java.name ->
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapperTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapperTest.kt
new file mode 100644
index 0000000000..a27f430edc
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapperTest.kt
@@ -0,0 +1,52 @@
+/*
+ * 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.crypto.store.db.mapper
+
+import org.amshove.kluent.shouldBeEqualTo
+import org.junit.Test
+import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
+import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity
+
+private const val A_DEVICE_ID = "device-id"
+private const val AN_IP_ADDRESS = "ip-address"
+private const val A_TIMESTAMP = 123L
+private const val A_DISPLAY_NAME = "display-name"
+
+class MyDeviceLastSeenInfoEntityMapperTest {
+
+ private val myDeviceLastSeenInfoEntityMapper = MyDeviceLastSeenInfoEntityMapper()
+
+ @Test
+ fun `given an entity when mapping to model then all fields are correctly mapped`() {
+ val entity = MyDeviceLastSeenInfoEntity(
+ deviceId = A_DEVICE_ID,
+ lastSeenIp = AN_IP_ADDRESS,
+ lastSeenTs = A_TIMESTAMP,
+ displayName = A_DISPLAY_NAME
+ )
+ val expectedDeviceInfo = DeviceInfo(
+ deviceId = A_DEVICE_ID,
+ lastSeenIp = AN_IP_ADDRESS,
+ lastSeenTs = A_TIMESTAMP,
+ displayName = A_DISPLAY_NAME
+ )
+
+ val deviceInfo = myDeviceLastSeenInfoEntityMapper.map(entity)
+
+ deviceInfo shouldBeEqualTo expectedDeviceInfo
+ }
+}
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/settings.gradle b/settings.gradle
index 782d2caf4a..e5b5511b94 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,7 +1,9 @@
+include ':vector-app'
include ':vector'
include ':vector-config'
include ':matrix-sdk-android'
include ':library:core-utils'
+include ':library:ui-strings'
include ':library:ui-styles'
include ':library:jsonviewer'
include ':library:attachment-viewer'
diff --git a/tools/check/check_code_quality.sh b/tools/check/check_code_quality.sh
index 910616176c..fc46fca758 100755
--- a/tools/check/check_code_quality.sh
+++ b/tools/check/check_code_quality.sh
@@ -74,7 +74,9 @@ ${searchForbiddenStringsScript} ./tools/check/forbidden_strings_in_code.txt \
./vector/src/debug/java \
./vector/src/release/java \
./vector/src/fdroid/java \
- ./vector/src/gplay/java
+ ./vector/src/gplay/java \
+ ./vector-app/src/gplay/java \
+ ./vector-app/src/main/java
resultForbiddenStringInCode=$?
@@ -95,7 +97,9 @@ ${searchForbiddenStringsScript} ./tools/check/forbidden_strings_in_code_app.txt
./vector/src/debug/java \
./vector/src/release/java \
./vector/src/fdroid/java \
- ./vector/src/gplay/java
+ ./vector/src/gplay/java \
+ ./vector-app/src/gplay/java \
+ ./vector-app/src/main/java
resultForbiddenStringInCodeApp=$?
@@ -107,7 +111,8 @@ ${searchForbiddenStringsScript} ./tools/check/forbidden_strings_in_resources.txt
./vector/src/main/res/color \
./vector/src/main/res/layout \
./vector/src/main/res/values \
- ./vector/src/main/res/xml
+ ./vector/src/main/res/xml \
+ ./vector-app/src/main/res/values
resultForbiddenStringInResource=$?
@@ -115,7 +120,8 @@ echo
echo "Search for forbidden patterns in layouts..."
${searchForbiddenStringsScript} ./tools/check/forbidden_strings_in_layout.txt \
- ./vector/src/main/res/layout
+ ./vector/src/main/res/layout \
+ ./vector-app/src/main/res/layout
resultForbiddenStringInLayout=$?
@@ -155,7 +161,11 @@ ${checkLongFilesScript} ${maxLines} \
./vector/src/main/java \
./vector/src/release/java \
./vector/src/sharedTest/java \
- ./vector/src/test/java
+ ./vector/src/test/java \
+ ./vector/src/androidTest/java \
+ ./vector/src/gplay/java \
+ ./vector/src/main/java
+
resultLongFiles=$?
diff --git a/vector/lint.xml b/tools/lint/lint.xml
similarity index 100%
rename from vector/lint.xml
rename to tools/lint/lint.xml
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-app/build.gradle b/vector-app/build.gradle
new file mode 100644
index 0000000000..1c2782118d
--- /dev/null
+++ b/vector-app/build.gradle
@@ -0,0 +1,378 @@
+import com.android.build.OutputFile
+
+apply plugin: 'com.android.application'
+apply plugin: 'com.google.firebase.appdistribution'
+apply plugin: 'com.google.android.gms.oss-licenses-plugin'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-parcelize'
+apply plugin: 'kotlin-kapt'
+apply plugin: 'dagger.hilt.android.plugin'
+apply plugin: 'kotlinx-knit'
+apply plugin: 'com.likethesalad.stem'
+
+if (project.hasProperty("coverage")) {
+ apply plugin: 'jacoco'
+}
+
+kapt {
+ correctErrorTypes = true
+}
+
+knit {
+ files = fileTree(project.rootDir) {
+ include '**/*.md'
+ include '**/*.kt'
+ include '**/*.kts'
+ exclude '**/build/**'
+ exclude '**/.gradle/**'
+ exclude '**/towncrier/template.md'
+ exclude '**/CHANGES.md'
+ }
+}
+
+// Note: 2 digits max for each value
+ext.versionMajor = 1
+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 = 36
+
+ext.scVersion = 58
+
+static def getGitTimestamp() {
+ def cmd = 'git show -s --format=%ct'
+ return cmd.execute().text.trim() as Long
+}
+
+static def generateVersionCodeFromTimestamp() {
+ // It's unix timestamp, minus timestamp of October 3rd 2018 (first commit date) divided by 100: It's incremented by one every 100 seconds.
+ // plus 20_000_000 for compatibility reason with the previous way the Version Code was computed
+ // Note that the result will be multiplied by 10 when adding the digit for the arch
+ return ((getGitTimestamp() - 1_538_524_800) / 100).toInteger() + 20_000_000
+}
+
+def generateVersionCodeFromVersionName() {
+ // plus 4_000_000 for compatibility reason with the previous way the Version Code was computed
+ // Note that the result will be multiplied by 10 when adding the digit for the arch
+ return (versionMajor * 1_00_00 + versionMinor * 1_00 + versionPatch + scVersion) + 4_000_000
+}
+
+def getVersionCode() {
+ if (gitBranchName() == "develop") {
+ return generateVersionCodeFromTimestamp()
+ } else {
+ return generateVersionCodeFromVersionName()
+ }
+}
+
+static def gitRevision() {
+ def cmd = "git rev-parse --short=8 HEAD"
+ return cmd.execute().text.trim()
+}
+
+static def gitRevisionDate() {
+ def cmd = "git show -s --format=%ci HEAD^{commit}"
+ return cmd.execute().text.trim()
+}
+
+static def gitBranchName() {
+ def fromEnv = System.env.BUILDKITE_BRANCH as String ?: ""
+
+ if (!fromEnv.isEmpty()) {
+ return fromEnv
+ } else {
+ // Note: this command return "HEAD" on Buildkite, so use the system env 'BUILDKITE_BRANCH' content first
+ def cmd = "git rev-parse --abbrev-ref HEAD"
+ return cmd.execute().text.trim()
+ }
+}
+
+// For Google Play build, build on any other branch than main will have a "-dev" suffix
+static def getGplayVersionSuffix() {
+ if (gitBranchName() == "main" || true) {
+ return ""
+ } else {
+ return "-dev"
+ }
+}
+
+static def gitTag() {
+ def cmd = "git describe --exact-match --tags"
+ return cmd.execute().text.trim()
+}
+
+// For F-Droid build, build on a not tagged commit will have a "-dev" suffix
+static def getFdroidVersionSuffix() {
+ if (gitTag() == "") {
+ return "-dev"
+ } else {
+ return ""
+ }
+}
+
+project.android.buildTypes.all { buildType ->
+ buildType.javaCompileOptions.annotationProcessorOptions.arguments =
+ [
+ validateEpoxyModelUsage: String.valueOf(buildType.name == 'debug')
+ ]
+}
+
+// map for the version codes last digit
+// x86 must have greater values than arm
+// 64 bits have greater value than 32 bits
+ext.abiVersionCodes = ["armeabi-v7a": 1, "arm64-v8a": 2, "x86": 3, "x86_64": 4].withDefault { 0 }
+
+def buildNumber = System.env.BUILDKITE_BUILD_NUMBER as Integer ?: 0
+
+android {
+ // Due to a bug introduced in Android gradle plugin 3.6.0, we have to specify the ndk version to use
+ // Ref: https://issuetracker.google.com/issues/144111441
+ ndkVersion "21.3.6528147"
+
+ compileSdk versions.compileSdk
+
+ defaultConfig {
+ applicationId "de.spiritcroc.riotx"
+ // Set to API 21: see #405
+ minSdk versions.minSdk
+ targetSdk versions.targetSdk
+ multiDexEnabled true
+
+ renderscriptTargetApi 24
+ renderscriptSupportModeEnabled true
+
+ versionCode 40100910
+ versionName "1.4.34.sc58"
+
+ // Generate a random app task affinity
+ manifestPlaceholders = [appTaskAffinitySuffix: "H_${gitRevision()}"]
+
+ buildConfigField "String", "GIT_REVISION", "\"${gitRevision()}\""
+ buildConfigField "String", "GIT_REVISION_DATE", "\"${gitRevisionDate()}\""
+ buildConfigField "String", "GIT_BRANCH_NAME", "\"${gitBranchName()}\""
+ buildConfigField "String", "BUILD_NUMBER", "\"${buildNumber}\""
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+
+ // Keep abiFilter for the universalApk
+ ndk {
+ abiFilters "armeabi-v7a", "x86", 'arm64-v8a', 'x86_64'
+ }
+
+ // Ref: https://developer.android.com/studio/build/configure-apk-splits.html
+ splits {
+ // Configures multiple APKs based on ABI.
+ abi {
+ // Enables building multiple APKs per ABI.
+ enable true
+
+ // By default all ABIs are included, so use reset() and include to specify that we only
+ // want APKs for armeabi-v7a, x86, arm64-v8a and x86_64.
+
+ // Resets the list of ABIs that Gradle should create APKs for to none.
+ reset()
+
+ // Specifies a list of ABIs that Gradle should create APKs for.
+ include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
+
+ // Generate a universal APK that includes all ABIs, so user who install from CI tool can use this one by default.
+ universalApk true
+ }
+ }
+
+ /*
+ applicationVariants.all { variant ->
+ // assign different version code for each output
+ def baseVariantVersion = variant.versionCode * 10
+ variant.outputs.each { output ->
+ def baseAbiVersionCode = project.ext.abiVersionCodes.get(output.getFilter(OutputFile.ABI))
+ // Known limitation: it does not modify the value in the BuildConfig.java generated file
+ // See https://issuetracker.google.com/issues/171133218
+ output.versionCodeOverride = baseVariantVersion + baseAbiVersionCode
+ print "ABI " + output.getFilter(OutputFile.ABI) + " \t-> VersionCode = " + output.versionCodeOverride + "\n"
+ output.outputFileName = output.outputFileName.replace("vector-app", "vector")
+ }
+ }
+ */
+
+ // The following argument makes the Android Test Orchestrator run its
+ // "pm clear" command after each test invocation. This command ensures
+ // that the app's state is completely cleared between tests.
+ testInstrumentationRunnerArguments clearPackageData: 'true'
+ }
+
+ testOptions {
+ // Disables animations during instrumented tests you run from the command line…
+ // This property does not affect tests that you run using Android Studio.”
+ animationsDisabled = true
+
+ // Comment to run on Android 12
+// execution 'ANDROIDX_TEST_ORCHESTRATOR'
+ }
+
+ signingConfigs {
+ debug {
+ keyAlias 'androiddebugkey'
+ keyPassword 'android'
+ storeFile file('./signature/debug.keystore')
+ storePassword 'android'
+ }
+ nightly {
+ keyAlias System.env.ELEMENT_ANDROID_NIGHTLY_KEYID ?: project.property("signing.element.nightly.keyId")
+ keyPassword System.env.ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD ?: project.property("signing.element.nightly.keyPassword")
+ storeFile file('./signature/nightly.keystore')
+ storePassword System.env.ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD ?: project.property("signing.element.nightly.storePassword")
+ }
+ release {
+ keyAlias project.property("signing.element.keyId")
+ keyPassword project.property("signing.element.keyPassword")
+ storeFile file(project.property("signing.element.storePath"))
+ storePassword project.property("signing.element.storePassword")
+ }
+ }
+
+ buildTypes {
+ debug {
+ applicationIdSuffix ".debug"
+ signingConfig signingConfigs.debug
+ resValue "string", "app_name", "SchildiChat dbg"
+ resValue "color", "launcher_background", "#0DBD8B"
+
+ if (project.hasProperty("coverage")) {
+ testCoverageEnabled = coverage.enableTestCoverage
+ }
+ }
+
+ release {
+ resValue "string", "app_name", "SchildiChat"
+ resValue "color", "launcher_background", "#0DBD8B"
+ postprocessing {
+ removeUnusedCode true
+ removeUnusedResources true
+ // We do not activate obfuscation as it makes it hard then to read crash reports, and it's a bit useless on an open source project :)
+ obfuscate false
+ optimizeCode true
+ proguardFiles 'proguard-rules.pro'
+ }
+ // signingConfig signingConfigs.release
+ }
+
+ nightly {
+ initWith release
+ applicationIdSuffix ".nightly"
+ versionNameSuffix "-nightly"
+ // Just override the background color of the launcher icon for the nightly build.
+ resValue "color", "launcher_background", "#07007E"
+ // We need to copy paste this block, this is not done automatically by `initWith release`
+ postprocessing {
+ removeUnusedCode true
+ removeUnusedResources true
+ // We do not activate obfuscation as it makes it hard then to read crash reports, and it's a bit useless on an open source project :)
+ obfuscate false
+ optimizeCode true
+ proguardFiles 'proguard-rules.pro'
+ }
+ matchingFallbacks = ['release']
+ signingConfig signingConfigs.nightly
+ firebaseAppDistribution {
+ artifactType = "APK"
+ // We upload the universal APK to fix this error:
+ // "App Distribution found more than 1 output file for this variant.
+ // Please contact firebase-support@google.com for help using APK splits with App Distribution."
+ artifactPath = "$rootDir/vector-app/build/outputs/apk/gplay/nightly/vector-gplay-universal-nightly.apk"
+ // This file will be generated by the GitHub action
+ releaseNotesFile = "CHANGES_NIGHTLY.md"
+ groups = "external-testers"
+ // This should not be required, but if I do not add the appId, I get this error:
+ // "App Distribution halted because it had a problem uploading the APK: [404] Requested entity was not found."
+ appId = "1:912726360885:android:efd8545af52a9f9300427c"
+ }
+ }
+ }
+
+ flavorDimensions "store"
+
+ productFlavors {
+ gplay {
+ apply plugin: 'com.google.gms.google-services'
+ afterEvaluate {
+ tasks.matching { it.name.contains("GoogleServices") && !it.name.contains("Gplay") }*.enabled = false
+ }
+
+ dimension "store"
+ isDefault = true
+ versionName "1.4.34.sc58"
+ buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"G\""
+ buildConfigField "String", "FLAVOR_DESCRIPTION", "\"GooglePlay\""
+ }
+
+ fdroid {
+ dimension "store"
+ versionName "1.4.34.sc58"
+ buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"F\""
+ buildConfigField "String", "FLAVOR_DESCRIPTION", "\"FDroid\""
+ }
+ }
+
+ lintOptions {
+ lintConfig file("../tools/lint/lint.xml")
+
+ checkDependencies true
+ abortOnError true
+ }
+
+ compileOptions {
+ sourceCompatibility versions.sourceCompat
+ targetCompatibility versions.targetCompat
+ }
+
+ kotlinOptions {
+ jvmTarget = "11"
+ freeCompilerArgs += [
+ "-opt-in=kotlin.RequiresOptIn",
+ // Fixes false positive "This is an internal Mavericks API. It is not intended for external use."
+ // of MvRx `by viewModel()` calls. Maybe due to the inlining of code... This is a temporary fix...
+ "-opt-in=com.airbnb.mvrx.InternalMavericksApi",
+ // Opt in for kotlinx.coroutines.FlowPreview too
+ "-opt-in=kotlinx.coroutines.FlowPreview",
+ // Opt in for kotlinx.coroutines.ExperimentalCoroutinesApi too
+ "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
+ ]
+ }
+}
+
+dependencies {
+ implementation project(':vector')
+ implementation project(':vector-config')
+ implementation libs.dagger.hilt
+ implementation 'androidx.multidex:multidex:2.0.1'
+ implementation "androidx.sharetarget:sharetarget:1.1.0"
+
+ kapt libs.dagger.hiltCompiler
+
+ androidTestImplementation libs.androidx.testCore
+ androidTestImplementation libs.androidx.testRunner
+ androidTestImplementation libs.androidx.testRules
+ androidTestImplementation libs.androidx.junit
+ androidTestImplementation libs.androidx.espressoCore
+ androidTestImplementation libs.androidx.espressoContrib
+ androidTestImplementation libs.androidx.espressoIntents
+ androidTestImplementation libs.tests.kluent
+ androidTestImplementation libs.androidx.coreTesting
+ androidTestImplementation(libs.jetbrains.coroutinesTest) {
+ exclude group: "org.jetbrains.kotlinx", module: "kotlinx-coroutines-debug"
+ }
+ // Plant Timber tree for test
+ androidTestImplementation libs.tests.timberJunitRule
+ // "The one who serves a great Espresso"
+ androidTestImplementation('com.adevinta.android:barista:4.2.0') {
+ exclude group: 'org.jetbrains.kotlin'
+ }
+ androidTestImplementation libs.mockk.mockkAndroid
+ androidTestUtil libs.androidx.orchestrator
+ androidTestImplementation libs.androidx.fragmentTesting
+ androidTestImplementation "org.jetbrains.kotlin:kotlin-reflect:1.7.10"
+ debugImplementation libs.androidx.fragmentTesting
+}
+
diff --git a/vector/proguard-rules.pro b/vector-app/proguard-rules.pro
similarity index 100%
rename from vector/proguard-rules.pro
rename to vector-app/proguard-rules.pro
diff --git a/vector/signature/README.md b/vector-app/signature/README.md
similarity index 100%
rename from vector/signature/README.md
rename to vector-app/signature/README.md
diff --git a/vector/signature/debug.keystore b/vector-app/signature/debug.keystore
similarity index 100%
rename from vector/signature/debug.keystore
rename to vector-app/signature/debug.keystore
diff --git a/vector/signature/nightly.keystore b/vector-app/signature/nightly.keystore
similarity index 100%
rename from vector/signature/nightly.keystore
rename to vector-app/signature/nightly.keystore
diff --git a/vector/src/androidTest/java/im/vector/app/CantVerifyTest.kt b/vector-app/src/androidTest/java/im/vector/app/CantVerifyTest.kt
similarity index 96%
rename from vector/src/androidTest/java/im/vector/app/CantVerifyTest.kt
rename to vector-app/src/androidTest/java/im/vector/app/CantVerifyTest.kt
index e6b17c1e9e..6f9d6cdde9 100644
--- a/vector/src/androidTest/java/im/vector/app/CantVerifyTest.kt
+++ b/vector-app/src/androidTest/java/im/vector/app/CantVerifyTest.kt
@@ -23,6 +23,7 @@ import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
+import com.adevinta.android.barista.internal.viewaction.SleepViewAction
import im.vector.app.features.MainActivity
import im.vector.app.ui.robot.ElementRobot
import org.junit.Rule
@@ -33,7 +34,7 @@ import java.util.UUID
@RunWith(AndroidJUnit4::class)
@LargeTest
-class CantVerifyTest : VerificationTestBase() {
+class CantVerifyTest {
@get:Rule
val testRule = RuleChain
diff --git a/vector/src/androidTest/java/im/vector/app/ClearCurrentSessionRule.kt b/vector-app/src/androidTest/java/im/vector/app/ClearCurrentSessionRule.kt
similarity index 83%
rename from vector/src/androidTest/java/im/vector/app/ClearCurrentSessionRule.kt
rename to vector-app/src/androidTest/java/im/vector/app/ClearCurrentSessionRule.kt
index 735e96c1e0..f09e522932 100644
--- a/vector/src/androidTest/java/im/vector/app/ClearCurrentSessionRule.kt
+++ b/vector-app/src/androidTest/java/im/vector/app/ClearCurrentSessionRule.kt
@@ -21,6 +21,8 @@ import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.test.platform.app.InstrumentationRegistry
+import dagger.hilt.EntryPoints
+import im.vector.app.core.di.SingletonEntryPoint
import im.vector.app.features.analytics.store.AnalyticsStore
import kotlinx.coroutines.runBlocking
import org.junit.rules.TestWatcher
@@ -39,10 +41,11 @@ class ClearCurrentSessionRule : TestWatcher() {
runBlocking {
reflectAnalyticDatastore(context).edit { it.clear() }
runCatching {
- val holder = (context.applicationContext as VectorApplication).activeSessionHolder
- holder.getSafeActiveSession()?.signOutService()?.signOut(true)
- (context.applicationContext as VectorApplication).vectorPreferences.clearPreferences()
- holder.clearActiveSession()
+ val entryPoint = EntryPoints.get(context.applicationContext, SingletonEntryPoint::class.java)
+ val sessionHolder = entryPoint.activeSessionHolder()
+ sessionHolder.getSafeActiveSession()?.signOutService()?.signOut(true)
+ entryPoint.vectorPreferences().clearPreferences()
+ sessionHolder.clearActiveSession()
}
}
return super.apply(base, description)
diff --git a/vector/src/androidTest/java/im/vector/app/EspressoExt.kt b/vector-app/src/androidTest/java/im/vector/app/EspressoExt.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/EspressoExt.kt
rename to vector-app/src/androidTest/java/im/vector/app/EspressoExt.kt
diff --git a/vector/src/androidTest/java/im/vector/app/RegistrationTest.kt b/vector-app/src/androidTest/java/im/vector/app/RegistrationTest.kt
similarity index 99%
rename from vector/src/androidTest/java/im/vector/app/RegistrationTest.kt
rename to vector-app/src/androidTest/java/im/vector/app/RegistrationTest.kt
index 7920e8e0d8..68a4d27deb 100644
--- a/vector/src/androidTest/java/im/vector/app/RegistrationTest.kt
+++ b/vector-app/src/androidTest/java/im/vector/app/RegistrationTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 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.
diff --git a/vector/src/androidTest/java/im/vector/app/SecurityBootstrapTest.kt b/vector-app/src/androidTest/java/im/vector/app/SecurityBootstrapTest.kt
similarity index 99%
rename from vector/src/androidTest/java/im/vector/app/SecurityBootstrapTest.kt
rename to vector-app/src/androidTest/java/im/vector/app/SecurityBootstrapTest.kt
index 7dc20178f2..1243758b2f 100644
--- a/vector/src/androidTest/java/im/vector/app/SecurityBootstrapTest.kt
+++ b/vector-app/src/androidTest/java/im/vector/app/SecurityBootstrapTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 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.
diff --git a/vector/src/androidTest/java/im/vector/app/TestMatrixCallback.kt b/vector-app/src/androidTest/java/im/vector/app/TestMatrixCallback.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/TestMatrixCallback.kt
rename to vector-app/src/androidTest/java/im/vector/app/TestMatrixCallback.kt
diff --git a/vector/src/androidTest/java/im/vector/app/VerificationTestBase.kt b/vector-app/src/androidTest/java/im/vector/app/VerificationTestBase.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/VerificationTestBase.kt
rename to vector-app/src/androidTest/java/im/vector/app/VerificationTestBase.kt
diff --git a/vector/src/androidTest/java/im/vector/app/VerifySessionInteractiveTest.kt b/vector-app/src/androidTest/java/im/vector/app/VerifySessionInteractiveTest.kt
similarity index 99%
rename from vector/src/androidTest/java/im/vector/app/VerifySessionInteractiveTest.kt
rename to vector-app/src/androidTest/java/im/vector/app/VerifySessionInteractiveTest.kt
index 8c9faee336..da13e49e84 100644
--- a/vector/src/androidTest/java/im/vector/app/VerifySessionInteractiveTest.kt
+++ b/vector-app/src/androidTest/java/im/vector/app/VerifySessionInteractiveTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 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.
@@ -33,6 +33,7 @@ import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
+import com.adevinta.android.barista.internal.viewaction.SleepViewAction
import im.vector.app.core.utils.getMatrixInstance
import im.vector.app.features.MainActivity
import im.vector.app.features.home.HomeActivity
diff --git a/vector/src/androidTest/java/im/vector/app/VerifySessionPassphraseTest.kt b/vector-app/src/androidTest/java/im/vector/app/VerifySessionPassphraseTest.kt
similarity index 98%
rename from vector/src/androidTest/java/im/vector/app/VerifySessionPassphraseTest.kt
rename to vector-app/src/androidTest/java/im/vector/app/VerifySessionPassphraseTest.kt
index 23a662dcc8..53e088118b 100644
--- a/vector/src/androidTest/java/im/vector/app/VerifySessionPassphraseTest.kt
+++ b/vector-app/src/androidTest/java/im/vector/app/VerifySessionPassphraseTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 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.
@@ -33,6 +33,7 @@ import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.platform.app.InstrumentationRegistry
+import com.adevinta.android.barista.internal.viewaction.SleepViewAction
import im.vector.app.core.resources.StringProvider
import im.vector.app.core.utils.getMatrixInstance
import im.vector.app.features.MainActivity
diff --git a/vector/src/androidTest/java/im/vector/app/core/utils/TestMatrixHelper.kt b/vector-app/src/androidTest/java/im/vector/app/core/utils/TestMatrixHelper.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/core/utils/TestMatrixHelper.kt
rename to vector-app/src/androidTest/java/im/vector/app/core/utils/TestMatrixHelper.kt
diff --git a/vector/src/androidTest/java/im/vector/app/espresso/tools/EspressoPreference.kt b/vector-app/src/androidTest/java/im/vector/app/espresso/tools/EspressoPreference.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/espresso/tools/EspressoPreference.kt
rename to vector-app/src/androidTest/java/im/vector/app/espresso/tools/EspressoPreference.kt
diff --git a/vector/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt b/vector-app/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt
rename to vector-app/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt
diff --git a/vector/src/androidTest/java/im/vector/app/espresso/tools/WaitActivity.kt b/vector-app/src/androidTest/java/im/vector/app/espresso/tools/WaitActivity.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/espresso/tools/WaitActivity.kt
rename to vector-app/src/androidTest/java/im/vector/app/espresso/tools/WaitActivity.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt b/vector-app/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt
similarity index 91%
rename from vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt
index 9434006060..d4878b8dcc 100644
--- a/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt
+++ b/vector-app/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt
@@ -21,6 +21,7 @@ import androidx.test.espresso.IdlingPolicies
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
+import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule
import im.vector.app.R
import im.vector.app.espresso.tools.ScreenshotFailureRule
@@ -28,6 +29,7 @@ import im.vector.app.features.MainActivity
import im.vector.app.getString
import im.vector.app.ui.robot.ElementRobot
import im.vector.app.ui.robot.settings.labs.LabFeature
+import im.vector.app.ui.robot.settings.labs.LabFeaturesPreferences
import im.vector.app.ui.robot.withDeveloperMode
import org.junit.Rule
import org.junit.Test
@@ -49,7 +51,14 @@ class UiAllScreensSanityTest {
.around(GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE))
.around(ScreenshotFailureRule())
- private val elementRobot = ElementRobot()
+ private val elementRobot = ElementRobot(
+ LabFeaturesPreferences(
+ InstrumentationRegistry.getInstrumentation()
+ .targetContext
+ .resources
+ .getBoolean(R.bool.settings_labs_new_app_layout_default)
+ )
+ )
// Last passing:
// 2020-11-09
@@ -101,11 +110,11 @@ class UiAllScreensSanityTest {
val spaceName = UUID.randomUUID().toString()
elementRobot.space {
- createSpace {
+ createSpace(true) {
createAndCrawl(spaceName)
}
val publicSpaceName = UUID.randomUUID().toString()
- createSpace {
+ createSpace(false) {
createPublicSpace(publicSpaceName)
}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/AnalyticsRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/AnalyticsRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/AnalyticsRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/AnalyticsRobot.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/CreateNewRoomRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/CreateNewRoomRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/CreateNewRoomRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/CreateNewRoomRobot.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/DialogRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/DialogRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/DialogRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/DialogRobot.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/ElementRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/ElementRobot.kt
similarity index 76%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/ElementRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/ElementRobot.kt
index b6fbfc23ab..b70fcfec25 100644
--- a/vector/src/androidTest/java/im/vector/app/ui/robot/ElementRobot.kt
+++ b/vector-app/src/androidTest/java/im/vector/app/ui/robot/ElementRobot.kt
@@ -33,21 +33,25 @@ import com.adevinta.android.barista.interaction.BaristaDialogInteractions.clickD
import com.adevinta.android.barista.interaction.BaristaDrawerInteractions.openDrawer
import im.vector.app.EspressoHelper
import im.vector.app.R
+import im.vector.app.espresso.tools.clickOnPreference
import im.vector.app.espresso.tools.waitUntilActivityVisible
import im.vector.app.espresso.tools.waitUntilDialogVisible
import im.vector.app.espresso.tools.waitUntilViewVisible
import im.vector.app.features.createdirect.CreateDirectRoomActivity
import im.vector.app.features.home.HomeActivity
import im.vector.app.features.onboarding.OnboardingActivity
+import im.vector.app.features.settings.VectorSettingsActivity
import im.vector.app.initialSyncIdlingResource
import im.vector.app.ui.robot.settings.SettingsRobot
import im.vector.app.ui.robot.settings.labs.LabFeature
+import im.vector.app.ui.robot.settings.labs.LabFeaturesPreferences
import im.vector.app.ui.robot.space.SpaceRobot
import im.vector.app.withIdlingResource
import timber.log.Timber
-class ElementRobot {
-
+class ElementRobot(
+ private val labsPreferences: LabFeaturesPreferences = LabFeaturesPreferences(false)
+) {
fun onboarding(block: OnboardingRobot.() -> Unit) {
block(OnboardingRobot())
}
@@ -73,40 +77,63 @@ class ElementRobot {
val activity = EspressoHelper.getCurrentActivity()!!
val uiSession = (activity as HomeActivity).activeSessionHolder.getActiveSession()
withIdlingResource(initialSyncIdlingResource(uiSession)) {
- waitUntilViewVisible(withId(R.id.bottomNavigationView))
+ waitUntilViewVisible(withId(R.id.roomListContainer))
}
}
fun settings(shouldGoBack: Boolean = true, block: SettingsRobot.() -> Unit) {
- openDrawer()
- clickOn(R.id.homeDrawerHeaderSettingsView)
+ if (labsPreferences.isNewAppLayoutEnabled) {
+ onView(withId((R.id.avatar))).perform(click())
+ } else {
+ openDrawer()
+ clickOn(R.id.homeDrawerHeaderSettingsView)
+ }
+
block(SettingsRobot())
if (shouldGoBack) pressBack()
- waitUntilViewVisible(withId(R.id.bottomNavigationView))
+ waitUntilViewVisible(withId(R.id.roomListContainer))
}
fun newDirectMessage(block: NewDirectMessageRobot.() -> Unit) {
- clickOn(R.id.bottom_action_people)
- clickOn(R.id.createChatRoomButton)
+ if (labsPreferences.isNewAppLayoutEnabled) {
+ clickOn(R.id.newLayoutCreateChatButton)
+ waitUntilDialogVisible(withId(R.id.start_chat))
+ clickOn(R.id.start_chat)
+ } else {
+ clickOn(R.id.bottom_action_people)
+ clickOn(R.id.createChatRoomButton)
+ }
+
waitUntilActivityVisible {
waitUntilViewVisible(withId(R.id.userListSearch))
}
closeSoftKeyboard()
block(NewDirectMessageRobot())
pressBack()
- waitUntilViewVisible(withId(R.id.bottomNavigationView))
+ if (labsPreferences.isNewAppLayoutEnabled) {
+ pressBack() // close create dialog
+ }
+ waitUntilViewVisible(withId(R.id.roomListContainer))
}
fun newRoom(block: NewRoomRobot.() -> Unit) {
- clickOn(R.id.bottom_action_rooms)
- RoomListRobot().newRoom { block() }
- waitUntilViewVisible(withId(R.id.bottomNavigationView))
+ if (!labsPreferences.isNewAppLayoutEnabled) {
+ clickOn(R.id.bottom_action_rooms)
+ }
+ RoomListRobot(labsPreferences).newRoom { block() }
+ if (labsPreferences.isNewAppLayoutEnabled) {
+ pressBack() // close create dialog
+ }
+ waitUntilViewVisible(withId(R.id.roomListContainer))
}
fun roomList(block: RoomListRobot.() -> Unit) {
- clickOn(R.id.bottom_action_rooms)
- block(RoomListRobot())
- waitUntilViewVisible(withId(R.id.bottomNavigationView))
+ if (!labsPreferences.isNewAppLayoutEnabled) {
+ clickOn(R.id.bottom_action_rooms)
+ }
+
+ block(RoomListRobot(labsPreferences))
+ waitUntilViewVisible(withId(R.id.roomListContainer))
}
fun toggleLabFeature(labFeature: LabFeature) {
@@ -146,8 +173,17 @@ class ElementRobot {
}
fun signout(expectSignOutWarning: Boolean) {
- clickOn(R.id.groupToolbarAvatarImageView)
- clickOn(R.id.homeDrawerHeaderSignoutView)
+ if (labsPreferences.isNewAppLayoutEnabled) {
+ onView(withId((R.id.avatar)))
+ .perform(click())
+ waitUntilActivityVisible {
+ clickOn(R.string.settings_general_title)
+ }
+ clickOnPreference(R.string.action_sign_out)
+ } else {
+ clickOn(R.id.groupToolbarAvatarImageView)
+ clickOn(R.id.homeDrawerHeaderSignoutView)
+ }
val isShowingSignOutWarning = kotlin.runCatching {
waitUntilViewVisible(withId(R.id.exitAnywayButton))
@@ -187,7 +223,7 @@ class ElementRobot {
}
fun space(block: SpaceRobot.() -> Unit) {
- block(SpaceRobot())
+ block(SpaceRobot(labsPreferences))
}
}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/MessageMenuRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/MessageMenuRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/MessageMenuRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/MessageMenuRobot.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/NewDirectMessageRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/NewDirectMessageRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/NewDirectMessageRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/NewDirectMessageRobot.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/NewRoomRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/NewRoomRobot.kt
similarity index 79%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/NewRoomRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/NewRoomRobot.kt
index 09ff1162c0..0cea26d5cc 100644
--- a/vector/src/androidTest/java/im/vector/app/ui/robot/NewRoomRobot.kt
+++ b/vector-app/src/androidTest/java/im/vector/app/ui/robot/NewRoomRobot.kt
@@ -21,10 +21,15 @@ import androidx.test.espresso.matcher.ViewMatchers.withId
import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
import im.vector.app.R
import im.vector.app.espresso.tools.waitUntilViewVisible
+import im.vector.app.features.DefaultVectorFeatures
+import im.vector.app.features.VectorFeatures
+import im.vector.app.ui.robot.settings.labs.LabFeaturesPreferences
class NewRoomRobot(
- var createdRoom: Boolean = false
+ var createdRoom: Boolean = false,
+ private val labsPreferences: LabFeaturesPreferences
) {
+ private val features: VectorFeatures = DefaultVectorFeatures()
fun createNewRoom(block: CreateNewRoomRobot.() -> Unit) {
clickOn(R.string.create_new_room)
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/OnboardingRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/OnboardingRobot.kt
similarity index 99%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/OnboardingRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/OnboardingRobot.kt
index e72535c116..1f1a799db3 100644
--- a/vector/src/androidTest/java/im/vector/app/ui/robot/OnboardingRobot.kt
+++ b/vector-app/src/androidTest/java/im/vector/app/ui/robot/OnboardingRobot.kt
@@ -33,7 +33,6 @@ import im.vector.app.features.DefaultVectorFeatures
import im.vector.app.waitForView
class OnboardingRobot {
-
private val defaultVectorFeatures = DefaultVectorFeatures()
fun crawl() {
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/OnboardingServersRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/OnboardingServersRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/OnboardingServersRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/OnboardingServersRobot.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/RoomDetailRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/RoomDetailRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/RoomDetailRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/RoomDetailRobot.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/RoomListRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/RoomListRobot.kt
similarity index 74%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/RoomListRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/RoomListRobot.kt
index dc07f06202..e4984aeed0 100644
--- a/vector/src/androidTest/java/im/vector/app/ui/robot/RoomListRobot.kt
+++ b/vector-app/src/androidTest/java/im/vector/app/ui/robot/RoomListRobot.kt
@@ -27,9 +27,11 @@ import com.adevinta.android.barista.assertion.BaristaVisibilityAssertions
import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
import im.vector.app.R
import im.vector.app.espresso.tools.waitUntilActivityVisible
+import im.vector.app.espresso.tools.waitUntilDialogVisible
import im.vector.app.features.roomdirectory.RoomDirectoryActivity
+import im.vector.app.ui.robot.settings.labs.LabFeaturesPreferences
-class RoomListRobot {
+class RoomListRobot(private val labsPreferences: LabFeaturesPreferences) {
fun openRoom(roomName: String, block: RoomDetailRobot.() -> Unit) {
clickOn(roomName)
@@ -49,11 +51,17 @@ class RoomListRobot {
}
fun newRoom(block: NewRoomRobot.() -> Unit) {
- clickOn(R.id.createGroupRoomButton)
- waitUntilActivityVisible {
- BaristaVisibilityAssertions.assertDisplayed(R.id.publicRoomsList)
+ if (labsPreferences.isNewAppLayoutEnabled) {
+ clickOn(R.id.newLayoutCreateChatButton)
+ waitUntilDialogVisible(ViewMatchers.withId(R.id.create_room))
+ clickOn(R.id.create_room)
+ } else {
+ clickOn(R.id.createGroupRoomButton)
+ waitUntilActivityVisible {
+ BaristaVisibilityAssertions.assertDisplayed(R.id.publicRoomsList)
+ }
}
- val newRoomRobot = NewRoomRobot()
+ val newRoomRobot = NewRoomRobot(false, labsPreferences)
block(newRoomRobot)
if (!newRoomRobot.createdRoom) {
pressBack()
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/RoomSettingsRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/RoomSettingsRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/RoomSettingsRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/RoomSettingsRobot.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsAdvancedRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsAdvancedRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsAdvancedRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsAdvancedRobot.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsGeneralRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsGeneralRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsGeneralRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsGeneralRobot.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsHelpRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsHelpRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsHelpRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsHelpRobot.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsLegalsRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsLegalsRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsLegalsRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsLegalsRobot.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsPreferencesRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsPreferencesRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsPreferencesRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsPreferencesRobot.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsRobot.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsSecurityRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsSecurityRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsSecurityRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsSecurityRobot.kt
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/labs/LabFeature.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/labs/LabFeature.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/settings/labs/LabFeature.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/labs/LabFeature.kt
diff --git a/vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/labs/LabFeaturesPreferences.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/labs/LabFeaturesPreferences.kt
new file mode 100644
index 0000000000..8f36e7ae23
--- /dev/null
+++ b/vector-app/src/androidTest/java/im/vector/app/ui/robot/settings/labs/LabFeaturesPreferences.kt
@@ -0,0 +1,19 @@
+/*
+ * 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.ui.robot.settings.labs
+
+data class LabFeaturesPreferences(val isNewAppLayoutEnabled: Boolean)
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/space/SpaceCreateRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/space/SpaceCreateRobot.kt
similarity index 94%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/space/SpaceCreateRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/space/SpaceCreateRobot.kt
index 018f3097ba..e5147c2085 100644
--- a/vector/src/androidTest/java/im/vector/app/ui/robot/space/SpaceCreateRobot.kt
+++ b/vector-app/src/androidTest/java/im/vector/app/ui/robot/space/SpaceCreateRobot.kt
@@ -31,6 +31,7 @@ import im.vector.app.espresso.tools.waitUntilActivityVisible
import im.vector.app.espresso.tools.waitUntilDialogVisible
import im.vector.app.espresso.tools.waitUntilViewVisible
import im.vector.app.features.home.HomeActivity
+import im.vector.app.features.home.room.detail.RoomDetailActivity
import im.vector.app.features.spaces.manage.SpaceManageActivity
class SpaceCreateRobot {
@@ -85,7 +86,9 @@ class SpaceCreateRobot {
clickOn(R.id.nextButton)
waitUntilViewVisible(withId(R.id.recyclerView))
clickOn(R.id.nextButton)
- waitUntilDialogVisible(withId(R.id.inviteByMxidButton))
+ waitUntilActivityVisible {
+ waitUntilDialogVisible(withId(R.id.inviteByMxidButton))
+ }
// close invite dialog
pressBack()
waitUntilViewVisible(withId(R.id.timelineRecyclerView))
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/space/SpaceMenuRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/space/SpaceMenuRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/space/SpaceMenuRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/space/SpaceMenuRobot.kt
diff --git a/vector-app/src/androidTest/java/im/vector/app/ui/robot/space/SpaceRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/space/SpaceRobot.kt
new file mode 100644
index 0000000000..e8ff58ba6a
--- /dev/null
+++ b/vector-app/src/androidTest/java/im/vector/app/ui/robot/space/SpaceRobot.kt
@@ -0,0 +1,105 @@
+/*
+ * 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.ui.robot.space
+
+import androidx.recyclerview.widget.RecyclerView
+import androidx.test.espresso.Espresso
+import androidx.test.espresso.action.ViewActions.click
+import androidx.test.espresso.action.ViewActions.longClick
+import androidx.test.espresso.contrib.RecyclerViewActions
+import androidx.test.espresso.matcher.ViewMatchers
+import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
+import com.adevinta.android.barista.interaction.BaristaDrawerInteractions.openDrawer
+import com.adevinta.android.barista.internal.viewaction.ClickChildAction
+import im.vector.app.R
+import im.vector.app.espresso.tools.waitUntilDialogVisible
+import im.vector.app.espresso.tools.waitUntilViewVisible
+import im.vector.app.features.DefaultVectorFeatures
+import im.vector.app.features.VectorFeatures
+import im.vector.app.ui.robot.settings.labs.LabFeaturesPreferences
+import org.hamcrest.Matchers
+
+class SpaceRobot(private val labsPreferences: LabFeaturesPreferences) {
+ private val features: VectorFeatures = DefaultVectorFeatures()
+
+ fun createSpace(isFirstSpace: Boolean, block: SpaceCreateRobot.() -> Unit) {
+ if (labsPreferences.isNewAppLayoutEnabled) {
+ clickOn(R.id.newLayoutOpenSpacesButton)
+ if (isFirstSpace) {
+ waitUntilDialogVisible(ViewMatchers.withId(R.id.spaces_empty_group))
+ clickOn(R.id.spaces_empty_button)
+ } else {
+ waitUntilDialogVisible(ViewMatchers.withId(R.id.groupListView))
+ Espresso.onView(ViewMatchers.withId(R.id.groupListView))
+ .perform(
+ RecyclerViewActions.actionOnItem(
+ ViewMatchers.hasDescendant(ViewMatchers.withId(R.id.plus)),
+ click()
+ ).atPosition(0)
+ )
+ }
+ } else {
+ openDrawer()
+ clickOn(R.string.create_space)
+ }
+ block(SpaceCreateRobot())
+ }
+
+ fun spaceMenu(spaceName: String, block: SpaceMenuRobot.() -> Unit) {
+ if (labsPreferences.isNewAppLayoutEnabled) {
+ clickOn(R.id.newLayoutOpenSpacesButton)
+ waitUntilDialogVisible(ViewMatchers.withId(R.id.groupListView))
+ } else {
+ openDrawer()
+ }
+ with(SpaceMenuRobot()) {
+ openMenu(spaceName)
+ block()
+ }
+ }
+
+ fun openMenu(spaceName: String) {
+ waitUntilViewVisible(ViewMatchers.withId(R.id.groupListView))
+ if (labsPreferences.isNewAppLayoutEnabled) {
+ Espresso.onView(ViewMatchers.withId(R.id.groupListView))
+ .perform(
+ RecyclerViewActions.actionOnItem(
+ ViewMatchers.hasDescendant(Matchers.allOf(ViewMatchers.withId(R.id.name), ViewMatchers.withText(spaceName))),
+ longClick()
+ ).atPosition(0)
+ )
+ } else {
+ Espresso.onView(ViewMatchers.withId(R.id.groupListView))
+ .perform(
+ RecyclerViewActions.actionOnItem(
+ ViewMatchers.hasDescendant(Matchers.allOf(ViewMatchers.withId(R.id.groupNameView), ViewMatchers.withText(spaceName))),
+ ClickChildAction.clickChildWithId(R.id.groupTmpLeave)
+ ).atPosition(0)
+ )
+ }
+
+ waitUntilDialogVisible(ViewMatchers.withId(R.id.spaceNameView))
+ }
+
+ fun selectSpace(spaceName: String) {
+ if (!labsPreferences.isNewAppLayoutEnabled) {
+ openDrawer()
+ waitUntilViewVisible(ViewMatchers.withId(R.id.groupListView))
+ }
+ clickOn(spaceName)
+ }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/space/SpaceSettingsRobot.kt b/vector-app/src/androidTest/java/im/vector/app/ui/robot/space/SpaceSettingsRobot.kt
similarity index 100%
rename from vector/src/androidTest/java/im/vector/app/ui/robot/space/SpaceSettingsRobot.kt
rename to vector-app/src/androidTest/java/im/vector/app/ui/robot/space/SpaceSettingsRobot.kt
diff --git a/vector-app/src/gplay/AndroidManifest.xml b/vector-app/src/gplay/AndroidManifest.xml
new file mode 100755
index 0000000000..0ac14f9cd3
--- /dev/null
+++ b/vector-app/src/gplay/AndroidManifest.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vector/src/gplay/debug/google-services.json b/vector-app/src/gplay/debug/google-services.json
similarity index 100%
rename from vector/src/gplay/debug/google-services.json
rename to vector-app/src/gplay/debug/google-services.json
diff --git a/vector/src/gplay/nightly/google-services.json b/vector-app/src/gplay/nightly/google-services.json
similarity index 100%
rename from vector/src/gplay/nightly/google-services.json
rename to vector-app/src/gplay/nightly/google-services.json
diff --git a/vector/src/gplay/release/google-services.json b/vector-app/src/gplay/release/google-services.json
similarity index 100%
rename from vector/src/gplay/release/google-services.json
rename to vector-app/src/gplay/release/google-services.json
diff --git a/vector-app/src/main/AndroidManifest.xml b/vector-app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..ad29118417
--- /dev/null
+++ b/vector-app/src/main/AndroidManifest.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector-app/src/main/java/im/vector/app/VectorApplication.kt
similarity index 98%
rename from vector/src/main/java/im/vector/app/VectorApplication.kt
rename to vector-app/src/main/java/im/vector/app/VectorApplication.kt
index ddfe0a9da0..d532e0cd50 100644
--- a/vector/src/main/java/im/vector/app/VectorApplication.kt
+++ b/vector-app/src/main/java/im/vector/app/VectorApplication.kt
@@ -1,11 +1,11 @@
/*
- * 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.
* 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,
@@ -68,6 +68,7 @@ import im.vector.app.features.settings.VectorLocale
import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.themes.ThemeUtils
import im.vector.app.features.version.VersionProvider
+import im.vector.application.R
import org.jitsi.meet.sdk.log.JitsiMeetDefaultLogHandler
import org.matrix.android.sdk.api.Matrix
import org.matrix.android.sdk.api.auth.AuthenticationService
diff --git a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt b/vector-app/src/main/java/im/vector/app/core/di/SingletonModule.kt
similarity index 98%
rename from vector/src/main/java/im/vector/app/core/di/SingletonModule.kt
rename to vector-app/src/main/java/im/vector/app/core/di/SingletonModule.kt
index a060ebe731..384c584e0c 100644
--- a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt
+++ b/vector-app/src/main/java/im/vector/app/core/di/SingletonModule.kt
@@ -1,11 +1,11 @@
/*
- * 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.
* 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,
@@ -28,7 +28,6 @@ import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
-import im.vector.app.BuildConfig
import im.vector.app.EmojiCompatWrapper
import im.vector.app.EmojiSpanify
import im.vector.app.SpaceStateHandler
@@ -58,6 +57,7 @@ import im.vector.app.features.settings.FontScalePreferencesImpl
import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.ui.SharedPreferencesUiStateRepository
import im.vector.app.features.ui.UiStateRepository
+import im.vector.application.BuildConfig
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
diff --git a/vector/src/main/res/drawable-anydpi-v26/ic_launcher_foreground.xml b/vector-app/src/main/res/drawable-anydpi-v26/ic_launcher_foreground.xml
similarity index 100%
rename from vector/src/main/res/drawable-anydpi-v26/ic_launcher_foreground.xml
rename to vector-app/src/main/res/drawable-anydpi-v26/ic_launcher_foreground.xml
diff --git a/vector/src/main/res/drawable/ic_launcher_background.xml b/vector-app/src/main/res/drawable/ic_launcher_background.xml
similarity index 100%
rename from vector/src/main/res/drawable/ic_launcher_background.xml
rename to vector-app/src/main/res/drawable/ic_launcher_background.xml
diff --git a/vector/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/vector-app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
similarity index 100%
rename from vector/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
rename to vector-app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
diff --git a/vector/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/vector-app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
similarity index 100%
rename from vector/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
rename to vector-app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
diff --git a/vector/src/main/res/mipmap-anydpi-v26/ic_launcher_sc.xml b/vector-app/src/main/res/mipmap-anydpi-v26/ic_launcher_sc.xml
similarity index 100%
rename from vector/src/main/res/mipmap-anydpi-v26/ic_launcher_sc.xml
rename to vector-app/src/main/res/mipmap-anydpi-v26/ic_launcher_sc.xml
diff --git a/vector/src/main/res/mipmap-hdpi/ic_launcher.png b/vector-app/src/main/res/mipmap-hdpi/ic_launcher.png
similarity index 100%
rename from vector/src/main/res/mipmap-hdpi/ic_launcher.png
rename to vector-app/src/main/res/mipmap-hdpi/ic_launcher.png
diff --git a/vector/src/main/res/mipmap-hdpi/ic_launcher_foreground_sc.png b/vector-app/src/main/res/mipmap-hdpi/ic_launcher_foreground_sc.png
similarity index 100%
rename from vector/src/main/res/mipmap-hdpi/ic_launcher_foreground_sc.png
rename to vector-app/src/main/res/mipmap-hdpi/ic_launcher_foreground_sc.png
diff --git a/vector/src/main/res/mipmap-hdpi/ic_launcher_round.png b/vector-app/src/main/res/mipmap-hdpi/ic_launcher_round.png
similarity index 100%
rename from vector/src/main/res/mipmap-hdpi/ic_launcher_round.png
rename to vector-app/src/main/res/mipmap-hdpi/ic_launcher_round.png
diff --git a/vector/src/main/res/mipmap-hdpi/ic_launcher_sc.png b/vector-app/src/main/res/mipmap-hdpi/ic_launcher_sc.png
similarity index 100%
rename from vector/src/main/res/mipmap-hdpi/ic_launcher_sc.png
rename to vector-app/src/main/res/mipmap-hdpi/ic_launcher_sc.png
diff --git a/vector/src/main/res/mipmap-mdpi/ic_launcher.png b/vector-app/src/main/res/mipmap-mdpi/ic_launcher.png
similarity index 100%
rename from vector/src/main/res/mipmap-mdpi/ic_launcher.png
rename to vector-app/src/main/res/mipmap-mdpi/ic_launcher.png
diff --git a/vector/src/main/res/mipmap-mdpi/ic_launcher_foreground_sc.png b/vector-app/src/main/res/mipmap-mdpi/ic_launcher_foreground_sc.png
similarity index 100%
rename from vector/src/main/res/mipmap-mdpi/ic_launcher_foreground_sc.png
rename to vector-app/src/main/res/mipmap-mdpi/ic_launcher_foreground_sc.png
diff --git a/vector/src/main/res/mipmap-mdpi/ic_launcher_round.png b/vector-app/src/main/res/mipmap-mdpi/ic_launcher_round.png
similarity index 100%
rename from vector/src/main/res/mipmap-mdpi/ic_launcher_round.png
rename to vector-app/src/main/res/mipmap-mdpi/ic_launcher_round.png
diff --git a/vector/src/main/res/mipmap-mdpi/ic_launcher_sc.png b/vector-app/src/main/res/mipmap-mdpi/ic_launcher_sc.png
similarity index 100%
rename from vector/src/main/res/mipmap-mdpi/ic_launcher_sc.png
rename to vector-app/src/main/res/mipmap-mdpi/ic_launcher_sc.png
diff --git a/vector/src/main/res/mipmap-xhdpi/ic_launcher.png b/vector-app/src/main/res/mipmap-xhdpi/ic_launcher.png
similarity index 100%
rename from vector/src/main/res/mipmap-xhdpi/ic_launcher.png
rename to vector-app/src/main/res/mipmap-xhdpi/ic_launcher.png
diff --git a/vector/src/main/res/mipmap-xhdpi/ic_launcher_foreground_sc.png b/vector-app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_sc.png
similarity index 100%
rename from vector/src/main/res/mipmap-xhdpi/ic_launcher_foreground_sc.png
rename to vector-app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_sc.png
diff --git a/vector/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/vector-app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
similarity index 100%
rename from vector/src/main/res/mipmap-xhdpi/ic_launcher_round.png
rename to vector-app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
diff --git a/vector/src/main/res/mipmap-xhdpi/ic_launcher_sc.png b/vector-app/src/main/res/mipmap-xhdpi/ic_launcher_sc.png
similarity index 100%
rename from vector/src/main/res/mipmap-xhdpi/ic_launcher_sc.png
rename to vector-app/src/main/res/mipmap-xhdpi/ic_launcher_sc.png
diff --git a/vector/src/main/res/mipmap-xxhdpi/ic_launcher.png b/vector-app/src/main/res/mipmap-xxhdpi/ic_launcher.png
similarity index 100%
rename from vector/src/main/res/mipmap-xxhdpi/ic_launcher.png
rename to vector-app/src/main/res/mipmap-xxhdpi/ic_launcher.png
diff --git a/vector/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_sc.png b/vector-app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_sc.png
similarity index 100%
rename from vector/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_sc.png
rename to vector-app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_sc.png
diff --git a/vector/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/vector-app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
similarity index 100%
rename from vector/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
rename to vector-app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
diff --git a/vector/src/main/res/mipmap-xxhdpi/ic_launcher_sc.png b/vector-app/src/main/res/mipmap-xxhdpi/ic_launcher_sc.png
similarity index 100%
rename from vector/src/main/res/mipmap-xxhdpi/ic_launcher_sc.png
rename to vector-app/src/main/res/mipmap-xxhdpi/ic_launcher_sc.png
diff --git a/vector/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/vector-app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
similarity index 100%
rename from vector/src/main/res/mipmap-xxxhdpi/ic_launcher.png
rename to vector-app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
diff --git a/vector/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_sc.png b/vector-app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_sc.png
similarity index 100%
rename from vector/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_sc.png
rename to vector-app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_sc.png
diff --git a/vector/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/vector-app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
similarity index 100%
rename from vector/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
rename to vector-app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
diff --git a/vector/src/main/res/mipmap-xxxhdpi/ic_launcher_sc.png b/vector-app/src/main/res/mipmap-xxxhdpi/ic_launcher_sc.png
similarity index 100%
rename from vector/src/main/res/mipmap-xxxhdpi/ic_launcher_sc.png
rename to vector-app/src/main/res/mipmap-xxxhdpi/ic_launcher_sc.png
diff --git a/vector/src/main/res/values/font_certs.xml b/vector-app/src/main/res/values/font_certs.xml
similarity index 100%
rename from vector/src/main/res/values/font_certs.xml
rename to vector-app/src/main/res/values/font_certs.xml
diff --git a/vector-app/src/main/res/values/strings.xml b/vector-app/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..84dde58d40
--- /dev/null
+++ b/vector-app/src/main/res/values/strings.xml
@@ -0,0 +1,5 @@
+
+
+
+ ignored
+
diff --git a/vector-config/src/main/res/values/config-settings.xml b/vector-config/src/main/res/values/config-settings.xml
index b2cd21c3de..1701fd45b0 100755
--- a/vector-config/src/main/res/values/config-settings.xml
+++ b/vector-config/src/main/res/values/config-settings.xml
@@ -38,6 +38,7 @@
false
+ false
true
false
diff --git a/vector/build.gradle b/vector/build.gradle
index 4d5ebbbd22..313d2b1520 100644
--- a/vector/build.gradle
+++ b/vector/build.gradle
@@ -1,14 +1,8 @@
-import com.android.build.OutputFile
-
-apply plugin: 'com.android.application'
-apply plugin: 'com.google.firebase.appdistribution'
-apply plugin: 'com.google.android.gms.oss-licenses-plugin'
+apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt'
-apply plugin: 'com.likethesalad.stem'
apply plugin: 'dagger.hilt.android.plugin'
-apply plugin: 'kotlinx-knit'
if (project.hasProperty("coverage")) {
apply plugin: 'jacoco'
@@ -18,100 +12,11 @@ kapt {
correctErrorTypes = true
}
-knit {
- files = fileTree(project.rootDir) {
- include '**/*.md'
- include '**/*.kt'
- include '**/*.kts'
- exclude '**/build/**'
- exclude '**/.gradle/**'
- exclude '**/towncrier/template.md'
- exclude '**/CHANGES.md'
- exclude '/node_modules'
- }
-}
-
-// Note: 2 digits max for each value
-ext.versionMajor = 1
-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.scVersion = 58
-
-static def getGitTimestamp() {
- def cmd = 'git show -s --format=%ct'
- return cmd.execute().text.trim() as Long
-}
-
-static def generateVersionCodeFromTimestamp() {
- // It's unix timestamp, minus timestamp of October 3rd 2018 (first commit date) divided by 100: It's incremented by one every 100 seconds.
- // plus 20_000_000 for compatibility reason with the previous way the Version Code was computed
- // Note that the result will be multiplied by 10 when adding the digit for the arch
- return ((getGitTimestamp() - 1_538_524_800) / 100).toInteger() + 20_000_000
-}
-
-def generateVersionCodeFromVersionName() {
- // plus 4_000_000 for compatibility reason with the previous way the Version Code was computed
- // Note that the result will be multiplied by 10 when adding the digit for the arch
- return (versionMajor * 1_00_00 + versionMinor * 1_00 + versionPatch + scVersion) + 4_000_000
-}
-
-def getVersionCode() {
- if (gitBranchName() == "develop") {
- return generateVersionCodeFromTimestamp()
- } else {
- return generateVersionCodeFromVersionName()
- }
-}
-
static def gitRevision() {
def cmd = "git rev-parse --short=8 HEAD"
return cmd.execute().text.trim()
}
-static def gitRevisionDate() {
- def cmd = "git show -s --format=%ci HEAD^{commit}"
- return cmd.execute().text.trim()
-}
-
-static def gitBranchName() {
- def fromEnv = System.env.BUILDKITE_BRANCH as String ?: ""
-
- if (!fromEnv.isEmpty()) {
- return fromEnv
- } else {
- // Note: this command return "HEAD" on Buildkite, so use the system env 'BUILDKITE_BRANCH' content first
- def cmd = "git rev-parse --abbrev-ref HEAD"
- return cmd.execute().text.trim()
- }
-}
-
-// For Google Play build, build on any other branch than main will have a "-dev" suffix
-static def getGplayVersionSuffix() {
- if (gitBranchName() == "main" || true) {
- return ""
- } else {
- return "-dev"
- }
-}
-
-static def gitTag() {
- def cmd = "git describe --exact-match --tags"
- return cmd.execute().text.trim()
-}
-
-// For F-Droid build, build on a not tagged commit will have a "-dev" suffix
-static def getFdroidVersionSuffix() {
- if (gitTag() == "") {
- return "-dev"
- } else {
- return ""
- }
-}
-
project.android.buildTypes.all { buildType ->
buildType.javaCompileOptions.annotationProcessorOptions.arguments =
[
@@ -119,13 +24,6 @@ project.android.buildTypes.all { buildType ->
]
}
-// map for the version codes last digit
-// x86 must have greater values than arm
-// 64 bits have greater value than 32 bits
-ext.abiVersionCodes = ["armeabi-v7a": 1, "arm64-v8a": 2, "x86": 3, "x86_64": 4].withDefault { 0 }
-
-def buildNumber = System.env.BUILDKITE_BUILD_NUMBER as Integer ?: 0
-
android {
// Due to a bug introduced in Android gradle plugin 3.6.0, we have to specify the ndk version to use
// Ref: https://issuetracker.google.com/issues/144111441
@@ -134,29 +32,9 @@ android {
compileSdk versions.compileSdk
defaultConfig {
- applicationId "de.spiritcroc.riotx"
// Set to API 21: see #405
minSdk versions.minSdk
targetSdk versions.targetSdk
- multiDexEnabled true
-
- renderscriptTargetApi 24
- renderscriptSupportModeEnabled true
-
- // `develop` branch will have version code from timestamp, to ensure each build from CI has a incremented versionCode.
- // Other branches (main, features, etc.) will have version code based on application version.
- versionCode 40100910
-
- // Required for sonar analysis
- versionName "1.4.34.sc58"
-
- // Generate a random app task affinity
- manifestPlaceholders = [appTaskAffinitySuffix: "H_${gitRevision()}"]
-
- buildConfigField "String", "GIT_REVISION", "\"${gitRevision()}\""
- buildConfigField "String", "GIT_REVISION_DATE", "\"${gitRevisionDate()}\""
- buildConfigField "String", "GIT_BRANCH_NAME", "\"${gitBranchName()}\""
- buildConfigField "String", "BUILD_NUMBER", "\"${buildNumber}\""
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -165,40 +43,8 @@ android {
abiFilters "armeabi-v7a", "x86", 'arm64-v8a', 'x86_64'
}
- // Ref: https://developer.android.com/studio/build/configure-apk-splits.html
- splits {
- // Configures multiple APKs based on ABI.
- abi {
- // Enables building multiple APKs per ABI.
- enable true
-
- // By default all ABIs are included, so use reset() and include to specify that we only
- // want APKs for armeabi-v7a, x86, arm64-v8a and x86_64.
-
- // Resets the list of ABIs that Gradle should create APKs for to none.
- reset()
-
- // Specifies a list of ABIs that Gradle should create APKs for.
- include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
-
- // Generate a universal APK that includes all ABIs, so user who install from CI tool can use this one by default.
- universalApk true
- }
- }
-
- /*
- applicationVariants.all { variant ->
- // assign different version code for each output
- def baseVariantVersion = variant.versionCode * 10
- variant.outputs.each { output ->
- def baseAbiVersionCode = project.ext.abiVersionCodes.get(output.getFilter(OutputFile.ABI))
- // Known limitation: it does not modify the value in the BuildConfig.java generated file
- // See https://issuetracker.google.com/issues/171133218
- output.versionCodeOverride = baseVariantVersion + baseAbiVersionCode
- print "ABI " + output.getFilter(OutputFile.ABI) + " \t-> VersionCode = " + output.versionCodeOverride + "\n"
- }
- }
- */
+ // Generate a random app task affinity
+ manifestPlaceholders = [appTaskAffinitySuffix: "H_${gitRevision()}"]
// The following argument makes the Android Test Orchestrator run its
// "pm clear" command after each test invocation. This command ensures
@@ -214,125 +60,31 @@ android {
// Comment to run on Android 12
// execution 'ANDROIDX_TEST_ORCHESTRATOR'
}
- signingConfigs {
- debug {
- keyAlias 'androiddebugkey'
- keyPassword 'android'
- storeFile file('./signature/debug.keystore')
- storePassword 'android'
- }
- nightly {
- keyAlias System.env.ELEMENT_ANDROID_NIGHTLY_KEYID ?: project.property("signing.element.nightly.keyId")
- keyPassword System.env.ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD ?: project.property("signing.element.nightly.keyPassword")
- storeFile file('./signature/nightly.keystore')
- storePassword System.env.ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD ?: project.property("signing.element.nightly.storePassword")
- }
- release {
- keyAlias project.property("signing.element.keyId")
- keyPassword project.property("signing.element.keyPassword")
- storeFile file(project.property("signing.element.storePath"))
- storePassword project.property("signing.element.storePassword")
- }
- }
-
buildTypes {
debug {
- applicationIdSuffix ".debug"
- resValue "string", "app_name", "SchildiChat dbg"
- resValue "color", "launcher_background", "#0DBD8B"
-
- signingConfig signingConfigs.debug
-
if (project.hasProperty("coverage")) {
testCoverageEnabled = coverage.enableTestCoverage
}
}
-
- release {
- resValue "string", "app_name", "SchildiChat"
- resValue "color", "launcher_background", "#0DBD8B"
-
- postprocessing {
- removeUnusedCode true
- removeUnusedResources true
- // We do not activate obfuscation as it makes it hard then to read crash reports, and it's a bit useless on an open source project :)
- obfuscate false
- optimizeCode true
- proguardFiles 'proguard-rules.pro'
- }
- // signingConfig signingConfigs.release
- }
-
nightly {
initWith release
- applicationIdSuffix ".nightly"
- versionNameSuffix "-nightly"
-
- // Just override the background color of the launcher icon for the nightly build.
- resValue "color", "launcher_background", "#07007E"
-
- // We need to copy paste this block, this is not done automatically by `initWith release`
- postprocessing {
- removeUnusedCode true
- removeUnusedResources true
- // We do not activate obfuscation as it makes it hard then to read crash reports, and it's a bit useless on an open source project :)
- obfuscate false
- optimizeCode true
- proguardFiles 'proguard-rules.pro'
- }
matchingFallbacks = ['release']
- signingConfig signingConfigs.nightly
- firebaseAppDistribution {
- artifactType = "APK"
- // We upload the universal APK to fix this error:
- // "App Distribution found more than 1 output file for this variant.
- // Please contact firebase-support@google.com for help using APK splits with App Distribution."
- artifactPath = "$rootDir/vector/build/outputs/apk/gplay/nightly/vector-gplay-universal-nightly.apk"
- // This file will be generated by the GitHub action
- releaseNotesFile = "CHANGES_NIGHTLY.md"
- groups = "external-testers"
- // This should not be required, but if I do not add the appId, I get this error:
- // "App Distribution halted because it had a problem uploading the APK: [404] Requested entity was not found."
- appId = "1:912726360885:android:efd8545af52a9f9300427c"
- }
}
+ release
}
flavorDimensions "store"
productFlavors {
gplay {
- apply plugin: 'com.google.gms.google-services'
- afterEvaluate {
- tasks.matching { it.name.contains("GoogleServices") && !it.name.contains("Gplay") }*.enabled = false
- }
-
dimension "store"
- isDefault = true
-
- versionName "1.4.34.sc58"
-
- buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"G\""
- buildConfigField "String", "FLAVOR_DESCRIPTION", "\"GooglePlay\""
}
fdroid {
dimension "store"
-
- versionName "1.4.34.sc58"
-
- buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"F\""
- buildConfigField "String", "FLAVOR_DESCRIPTION", "\"FDroid\""
}
}
- lintOptions {
- lintConfig file("lint.xml")
-
- checkDependencies true
- abortOnError true
- }
-
compileOptions {
sourceCompatibility versions.sourceCompat
targetCompatibility versions.targetCompat
@@ -368,23 +120,19 @@ android {
buildFeatures {
viewBinding true
}
-
- packagingOptions {
- exclude 'META-INF/lib_release.kotlin_module'
- }
}
dependencies {
implementation project(":vector-config")
- implementation project(":matrix-sdk-android")
+ api project(":matrix-sdk-android")
implementation project(":matrix-sdk-android-flow")
implementation project(":library:jsonviewer")
+ implementation project(":library:ui-strings")
implementation project(":library:ui-styles")
implementation project(":library:core-utils")
implementation project(":library:attachment-viewer")
implementation project(":library:diff-match-patch")
implementation project(":library:multipicker")
- implementation 'androidx.multidex:multidex:2.0.1'
implementation libs.jetbrains.kotlinReflect
implementation libs.jetbrains.coroutinesCore
@@ -394,14 +142,13 @@ dependencies {
implementation libs.androidx.appCompat
implementation libs.androidx.fragmentKtx
implementation libs.androidx.constraintLayout
- implementation "androidx.sharetarget:sharetarget:1.1.0"
implementation libs.androidx.core
implementation "androidx.media:media:1.6.0"
implementation "androidx.transition:transition:1.4.1"
implementation libs.androidx.biometric
- implementation "org.threeten:threetenbp:1.4.0:no-tzdb"
- implementation "com.gabrielittner.threetenbp:lazythreetenbp:0.11.0"
+ api "org.threeten:threetenbp:1.4.0:no-tzdb"
+ api "com.gabrielittner.threetenbp:lazythreetenbp:0.11.0"
implementation libs.squareup.moshi
implementation libs.squareup.moshiKt
@@ -409,35 +156,34 @@ dependencies {
// Lifecycle
implementation libs.androidx.lifecycleLivedata
- implementation libs.androidx.lifecycleProcess
+ api libs.androidx.lifecycleProcess
implementation libs.androidx.lifecycleRuntimeKtx
- implementation libs.androidx.datastorepreferences
+ api libs.androidx.datastorepreferences
// Opus Encoder
implementation libs.element.opusencoder
// Log
- implementation libs.jakewharton.timber
+ api libs.jakewharton.timber
// Debug
- implementation 'com.facebook.stetho:stetho:1.6.0'
+ api 'com.facebook.stetho:stetho:1.6.0'
- // Phone number https://github.com/google/libphonenumber
- implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.54'
+ api libs.google.phonenumber
// FlowBinding
implementation libs.github.flowBinding
implementation libs.github.flowBindingAppcompat
- implementation libs.airbnb.epoxy
+ api libs.airbnb.epoxy
implementation libs.airbnb.epoxyGlide
kapt libs.airbnb.epoxyProcessor
implementation libs.airbnb.epoxyPaging
- implementation libs.airbnb.mavericks
+ api libs.airbnb.mavericks
// Snap Helper https://github.com/rubensousa/GravitySnapHelper
- implementation 'com.github.rubensousa:gravitysnaphelper:2.2.2'
+ api 'com.github.rubensousa:gravitysnaphelper:2.2.2'
// Nightly
// API-only library
@@ -446,7 +192,7 @@ dependencies {
gplayImplementation libs.google.appdistribution
// Work
- implementation libs.androidx.work
+ api libs.androidx.work
// Paging
implementation libs.androidx.pagingRuntimeKtx
@@ -455,7 +201,7 @@ dependencies {
implementation libs.arrow.core
// Pref
- implementation libs.androidx.preferenceKtx
+ api libs.androidx.preferenceKtx
// UI
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
@@ -514,7 +260,7 @@ dependencies {
// UnifiedPush
implementation 'com.github.UnifiedPush:android-connector:2.0.1'
// UnifiedPush gplay flavor only
- gplayImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:2.1.1') {
+ gplayImplementation('com.google.firebase:firebase-messaging:23.0.8') {
exclude group: 'com.google.firebase', module: 'firebase-core'
exclude group: 'com.google.firebase', module: 'firebase-analytics'
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
@@ -531,7 +277,7 @@ dependencies {
implementation('com.facebook.react:react-native-webrtc:1.94.2-jitsi-10227332@aar')
// Jitsi
- implementation('org.jitsi.react:jitsi-meet-sdk:5.0.2') {
+ api('org.jitsi.react:jitsi-meet-sdk:5.0.2') {
exclude group: 'com.google.firebase'
exclude group: 'com.google.android.gms'
exclude group: 'com.android.installreferrer'
@@ -543,8 +289,8 @@ dependencies {
implementation 'me.dm7.barcodescanner:zxing:1.9.13'
// Emoji Keyboard
- implementation libs.vanniktech.emojiMaterial
- implementation libs.vanniktech.emojiGoogle
+ api libs.vanniktech.emojiMaterial
+ api libs.vanniktech.emojiGoogle
implementation 'im.dlg:android-dialer:1.2.5'
@@ -557,14 +303,14 @@ dependencies {
implementation 'commons-codec:commons-codec:1.15'
// MapTiler
- fdroidImplementation(libs.maplibre.androidSdk) {
+ fdroidApi(libs.maplibre.androidSdk) {
exclude group: 'com.google.android.gms', module: 'play-services-location'
}
- fdroidImplementation(libs.maplibre.pluginAnnotation) {
+ fdroidApi(libs.maplibre.pluginAnnotation) {
exclude group: 'com.google.android.gms', module: 'play-services-location'
}
- gplayImplementation libs.maplibre.androidSdk
- gplayImplementation libs.maplibre.pluginAnnotation
+ gplayApi libs.maplibre.androidSdk
+ gplayApi libs.maplibre.pluginAnnotation
// TESTS
testImplementation libs.tests.junit
diff --git a/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderProviderTests.kt b/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderProviderTests.kt
index 61f745178c..65f81b145b 100644
--- a/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderProviderTests.kt
+++ b/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderProviderTests.kt
@@ -20,6 +20,8 @@ import android.os.Build
import androidx.test.platform.app.InstrumentationRegistry
import im.vector.app.AndroidVersionTestOverrider
import im.vector.app.features.DefaultVectorFeatures
+import io.mockk.every
+import io.mockk.spyk
import org.amshove.kluent.shouldBeInstanceOf
import org.junit.After
import org.junit.Test
@@ -27,7 +29,7 @@ import org.junit.Test
class VoiceRecorderProviderTests {
private val context = InstrumentationRegistry.getInstrumentation().targetContext
- private val provider = VoiceRecorderProvider(context, DefaultVectorFeatures())
+ private val provider = spyk(VoiceRecorderProvider(context, DefaultVectorFeatures()))
@After
fun tearDown() {
@@ -35,11 +37,19 @@ class VoiceRecorderProviderTests {
}
@Test
- fun provideVoiceRecorderOnAndroidQReturnsQRecorder() {
+ fun provideVoiceRecorderOnAndroidQAndCodecReturnsQRecorder() {
AndroidVersionTestOverrider.override(Build.VERSION_CODES.Q)
+ every { provider.hasOpusEncoder() } returns true
provider.provideVoiceRecorder().shouldBeInstanceOf(VoiceRecorderQ::class)
}
+ @Test
+ fun provideVoiceRecorderOnAndroidQButNoCodecReturnsLRecorder() {
+ AndroidVersionTestOverrider.override(Build.VERSION_CODES.Q)
+ every { provider.hasOpusEncoder() } returns false
+ provider.provideVoiceRecorder().shouldBeInstanceOf(VoiceRecorderL::class)
+ }
+
@Test
fun provideVoiceRecorderOnOlderAndroidVersionReturnsLRecorder() {
AndroidVersionTestOverrider.override(Build.VERSION_CODES.LOLLIPOP)
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/space/SpaceRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/space/SpaceRobot.kt
deleted file mode 100644
index b8a2f4313b..0000000000
--- a/vector/src/androidTest/java/im/vector/app/ui/robot/space/SpaceRobot.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.ui.robot.space
-
-import androidx.recyclerview.widget.RecyclerView
-import androidx.test.espresso.Espresso
-import androidx.test.espresso.contrib.RecyclerViewActions
-import androidx.test.espresso.matcher.ViewMatchers
-import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
-import com.adevinta.android.barista.interaction.BaristaDrawerInteractions.openDrawer
-import com.adevinta.android.barista.internal.viewaction.ClickChildAction
-import im.vector.app.R
-import im.vector.app.espresso.tools.waitUntilDialogVisible
-import im.vector.app.espresso.tools.waitUntilViewVisible
-import org.hamcrest.Matchers
-
-class SpaceRobot {
-
- fun createSpace(block: SpaceCreateRobot.() -> Unit) {
- openDrawer()
- clickOn(R.string.create_space)
- block(SpaceCreateRobot())
- }
-
- fun spaceMenu(spaceName: String, block: SpaceMenuRobot.() -> Unit) {
- openDrawer()
- with(SpaceMenuRobot()) {
- openMenu(spaceName)
- block()
- }
- }
-
- fun openMenu(spaceName: String) {
- waitUntilViewVisible(ViewMatchers.withId(R.id.groupListView))
- Espresso.onView(ViewMatchers.withId(R.id.groupListView))
- .perform(
- RecyclerViewActions.actionOnItem(
- ViewMatchers.hasDescendant(Matchers.allOf(ViewMatchers.withId(R.id.groupNameView), ViewMatchers.withText(spaceName))),
- ClickChildAction.clickChildWithId(R.id.groupTmpLeave)
- ).atPosition(0)
- )
- waitUntilDialogVisible(ViewMatchers.withId(R.id.spaceNameView))
- }
-
- fun selectSpace(spaceName: String) {
- openDrawer()
- waitUntilViewVisible(ViewMatchers.withId(R.id.groupListView))
- clickOn(spaceName)
- }
-}
diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt b/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt
index c127e3aed6..9b2711a8c3 100644
--- a/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt
+++ b/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt
@@ -88,7 +88,7 @@ class DebugFeaturesStateFactory @Inject constructor(
createBooleanFeature(
label = "Enable New App Layout",
key = DebugFeatureKeys.newAppLayoutEnabled,
- factory = VectorFeatures::isNewAppLayoutEnabled
+ factory = VectorFeatures::isNewAppLayoutFeatureEnabled
),
createBooleanFeature(
label = "Enable New Device Management",
diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt b/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt
index 003b9b8084..bb4cae3201 100644
--- a/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt
+++ b/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt
@@ -76,8 +76,8 @@ class DebugVectorFeatures(
override fun shouldStartDmOnFirstMessage(): Boolean = read(DebugFeatureKeys.startDmOnFirstMsg)
?: vectorFeatures.shouldStartDmOnFirstMessage()
- override fun isNewAppLayoutEnabled(): Boolean = read(DebugFeatureKeys.newAppLayoutEnabled)
- ?: vectorFeatures.isNewAppLayoutEnabled()
+ override fun isNewAppLayoutFeatureEnabled(): Boolean = read(DebugFeatureKeys.newAppLayoutEnabled)
+ ?: vectorFeatures.isNewAppLayoutFeatureEnabled()
override fun isNewDeviceManagementEnabled(): Boolean = read(DebugFeatureKeys.newDeviceManagementEnabled)
?: vectorFeatures.isNewDeviceManagementEnabled()
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/debug/java/im/vector/app/features/debug/settings/DebugPrivateSettingsFragment.kt b/vector/src/debug/java/im/vector/app/features/debug/settings/DebugPrivateSettingsFragment.kt
index 38253fe7c2..be3d41e0e1 100644
--- a/vector/src/debug/java/im/vector/app/features/debug/settings/DebugPrivateSettingsFragment.kt
+++ b/vector/src/debug/java/im/vector/app/features/debug/settings/DebugPrivateSettingsFragment.kt
@@ -16,6 +16,8 @@
package im.vector.app.features.debug.settings
+import android.annotation.SuppressLint
+import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -24,6 +26,7 @@ import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentDebugPrivateSettingsBinding
+import im.vector.app.features.home.room.list.home.release.ReleaseNotesActivity
class DebugPrivateSettingsFragment : VectorBaseFragment() {
@@ -35,7 +38,6 @@ class DebugPrivateSettingsFragment : VectorBaseFragment
viewModel.handle(DebugPrivateSettingsViewActions.SetForceLoginFallbackEnabled(isChecked))
}
+ views.releaseNotesActivityHasBeenDisplayedReset.setOnClickListener {
+ viewModel.handle(DebugPrivateSettingsViewActions.ResetReleaseNotesActivityHasBeenDisplayed)
+ }
+ views.showReleaseNotesActivity.setOnClickListener {
+ startActivity(Intent(requireActivity(), ReleaseNotesActivity::class.java))
+ }
}
override fun invalidate() = withState(viewModel) {
@@ -57,5 +65,7 @@ class DebugPrivateSettingsFragment : VectorBaseFragment(initialState) {
@AssistedFactory
@@ -43,6 +45,15 @@ class DebugPrivateSettingsViewModel @AssistedInject constructor(
init {
observeVectorOverrides()
+ observeReleaseNotesPreferencesStore()
+ }
+
+ private fun observeReleaseNotesPreferencesStore() {
+ releaseNotesPreferencesStore.appLayoutOnboardingShown.setOnEach {
+ copy(
+ releaseNotesActivityHasBeenDisplayed = it
+ )
+ }
}
private fun observeVectorOverrides() {
@@ -72,6 +83,13 @@ class DebugPrivateSettingsViewModel @AssistedInject constructor(
is DebugPrivateSettingsViewActions.SetForceLoginFallbackEnabled -> handleSetForceLoginFallbackEnabled(action)
is SetDisplayNameCapabilityOverride -> handleSetDisplayNameCapabilityOverride(action)
is SetAvatarCapabilityOverride -> handleSetAvatarCapabilityOverride(action)
+ DebugPrivateSettingsViewActions.ResetReleaseNotesActivityHasBeenDisplayed -> handleResetReleaseNotesActivityHasBeenDisplayed()
+ }
+ }
+
+ private fun handleResetReleaseNotesActivityHasBeenDisplayed() {
+ viewModelScope.launch {
+ releaseNotesPreferencesStore.setAppLayoutOnboardingShown(false)
}
}
diff --git a/vector/src/debug/java/im/vector/app/features/debug/settings/DebugPrivateSettingsViewState.kt b/vector/src/debug/java/im/vector/app/features/debug/settings/DebugPrivateSettingsViewState.kt
index 749b11a744..a390c94942 100644
--- a/vector/src/debug/java/im/vector/app/features/debug/settings/DebugPrivateSettingsViewState.kt
+++ b/vector/src/debug/java/im/vector/app/features/debug/settings/DebugPrivateSettingsViewState.kt
@@ -22,7 +22,8 @@ import im.vector.app.features.debug.settings.OverrideDropdownView.OverrideDropdo
data class DebugPrivateSettingsViewState(
val dialPadVisible: Boolean = false,
val forceLoginFallback: Boolean = false,
- val homeserverCapabilityOverrides: HomeserverCapabilityOverrides = HomeserverCapabilityOverrides()
+ val homeserverCapabilityOverrides: HomeserverCapabilityOverrides = HomeserverCapabilityOverrides(),
+ val releaseNotesActivityHasBeenDisplayed: Boolean = false,
) : MavericksState
data class HomeserverCapabilityOverrides(
diff --git a/vector/src/debug/res/layout/fragment_debug_private_settings.xml b/vector/src/debug/res/layout/fragment_debug_private_settings.xml
index c42ad68dce..55824930bc 100644
--- a/vector/src/debug/res/layout/fragment_debug_private_settings.xml
+++ b/vector/src/debug/res/layout/fragment_debug_private_settings.xml
@@ -49,6 +49,27 @@
android:layout_marginEnd="16dp"
android:layout_marginBottom="4dp" />
+
+
+
+
+
+
diff --git a/vector/src/fdroid/AndroidManifest.xml b/vector/src/fdroid/AndroidManifest.xml
index 29dac6533e..15db89ca13 100644
--- a/vector/src/fdroid/AndroidManifest.xml
+++ b/vector/src/fdroid/AndroidManifest.xml
@@ -28,20 +28,6 @@
android:enabled="true"
android:exported="false" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/vector/src/gplay/java/im/vector/app/nightly/FirebaseNightlyProxy.kt b/vector/src/gplay/java/im/vector/app/nightly/FirebaseNightlyProxy.kt
index 59a1e3eb17..94a36036b6 100644
--- a/vector/src/gplay/java/im/vector/app/nightly/FirebaseNightlyProxy.kt
+++ b/vector/src/gplay/java/im/vector/app/nightly/FirebaseNightlyProxy.kt
@@ -20,8 +20,8 @@ import android.content.SharedPreferences
import androidx.core.content.edit
import com.google.firebase.appdistribution.FirebaseAppDistribution
import com.google.firebase.appdistribution.FirebaseAppDistributionException
-import im.vector.app.BuildConfig
import im.vector.app.core.di.DefaultPreferences
+import im.vector.app.core.resources.BuildMeta
import im.vector.app.core.time.Clock
import im.vector.app.features.home.NightlyProxy
import timber.log.Timber
@@ -31,6 +31,7 @@ class FirebaseNightlyProxy @Inject constructor(
private val clock: Clock,
@DefaultPreferences
private val sharedPreferences: SharedPreferences,
+ private val buildMeta: BuildMeta,
) : NightlyProxy {
override fun onHomeResumed() {
@@ -58,7 +59,7 @@ class FirebaseNightlyProxy @Inject constructor(
}
private fun canDisplayPopup(): Boolean {
- if (BuildConfig.APPLICATION_ID != "im.vector.app.nightly") return false
+ if (buildMeta.applicationId != "im.vector.app.nightly") return false
val today = clock.epochMillis() / A_DAY_IN_MILLIS
val lastDisplayPopupDay = sharedPreferences.getLong(SHARED_PREF_KEY, 0)
return (today > lastDisplayPopupDay)
diff --git a/vector/src/gplay/java/im/vector/app/push/fcm/VectorFirebaseMessagingService.kt b/vector/src/gplay/java/im/vector/app/push/fcm/VectorFirebaseMessagingService.kt
new file mode 100644
index 0000000000..7fd55bd165
--- /dev/null
+++ b/vector/src/gplay/java/im/vector/app/push/fcm/VectorFirebaseMessagingService.kt
@@ -0,0 +1,64 @@
+/*
+ * 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.push.fcm
+
+import com.google.firebase.messaging.FirebaseMessagingService
+import com.google.firebase.messaging.RemoteMessage
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.R
+import im.vector.app.core.di.ActiveSessionHolder
+import im.vector.app.core.pushers.FcmHelper
+import im.vector.app.core.pushers.PushParser
+import im.vector.app.core.pushers.PushersManager
+import im.vector.app.core.pushers.UnifiedPushHelper
+import im.vector.app.core.pushers.VectorPushHandler
+import im.vector.app.features.settings.VectorPreferences
+import org.matrix.android.sdk.api.logger.LoggerTag
+import timber.log.Timber
+import javax.inject.Inject
+
+private val loggerTag = LoggerTag("Push", LoggerTag.SYNC)
+
+@AndroidEntryPoint
+class VectorFirebaseMessagingService : FirebaseMessagingService() {
+ @Inject lateinit var fcmHelper: FcmHelper
+ @Inject lateinit var vectorPreferences: VectorPreferences
+ @Inject lateinit var activeSessionHolder: ActiveSessionHolder
+ @Inject lateinit var pushersManager: PushersManager
+ @Inject lateinit var pushParser: PushParser
+ @Inject lateinit var vectorPushHandler: VectorPushHandler
+ @Inject lateinit var unifiedPushHelper: UnifiedPushHelper
+
+ override fun onNewToken(token: String) {
+ Timber.tag(loggerTag.value).d("New Firebase token")
+ fcmHelper.storeFcmToken(token)
+ if (
+ vectorPreferences.areNotificationEnabledForDevice() &&
+ activeSessionHolder.hasActiveSession() &&
+ unifiedPushHelper.isEmbeddedDistributor()
+ ) {
+ pushersManager.enqueueRegisterPusher(token, getString(R.string.pusher_http_url))
+ }
+ }
+
+ override fun onMessageReceived(message: RemoteMessage) {
+ Timber.tag(loggerTag.value).d("New Firebase message")
+ pushParser.parsePushDataFcm(message.data).let {
+ vectorPushHandler.handle(it)
+ }
+ }
+}
diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml
index 4a96c958bb..d52a163265 100644
--- a/vector/src/main/AndroidManifest.xml
+++ b/vector/src/main/AndroidManifest.xml
@@ -15,6 +15,7 @@
+
@@ -74,19 +75,7 @@
-
+
+
+
+
@@ -426,7 +418,7 @@
@@ -438,41 +430,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/vector/src/main/java/im/vector/app/SpaceStateHandler.kt b/vector/src/main/java/im/vector/app/SpaceStateHandler.kt
index 818f96874a..7e51f789da 100644
--- a/vector/src/main/java/im/vector/app/SpaceStateHandler.kt
+++ b/vector/src/main/java/im/vector/app/SpaceStateHandler.kt
@@ -52,11 +52,13 @@ interface SpaceStateHandler : DefaultLifecycleObserver {
)
/**
- * Gets the current backstack of spaces (via their id).
+ * Gets the Space ID of the space on top of the backstack.
*
- * null may be an entry in the ArrayDeque to indicate the root space (All Chats)
+ * May return null to indicate the All Chats space.
*/
- fun getSpaceBackstack(): ArrayDeque
+ fun popSpaceBackstack(): String?
+
+ fun getSpaceBackstack(): List
/**
* Gets a flow of the selected space for clients to react immediately to space changes.
diff --git a/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt
index 992781c2e7..32b23f8e59 100644
--- a/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt
+++ b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt
@@ -25,6 +25,7 @@ import im.vector.app.core.utils.BehaviorDataSource
import im.vector.app.features.analytics.AnalyticsTracker
import im.vector.app.features.analytics.plan.UserProperties
import im.vector.app.features.session.coroutineScope
+import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.ui.UiStateRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -67,7 +68,8 @@ class SpaceStateHandlerImpl @Inject constructor(
private val sessionDataSource: ActiveSessionDataSource,
private val uiStateRepository: UiStateRepository,
private val activeSessionHolder: ActiveSessionHolder,
- private val analyticsTracker: AnalyticsTracker
+ private val analyticsTracker: AnalyticsTracker,
+ private val vectorPreferences: VectorPreferences,
) : SpaceStateHandler {
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
@@ -81,8 +83,6 @@ class SpaceStateHandlerImpl @Inject constructor(
private val selectedSpaceFlowIgnoreSwipe = selectedSpaceDataSourceSc.stream()
.filter { it.getOrElse{ null }?.second != SelectSpaceFrom.SWIPE }
- private val spaceBackstack = ArrayDeque()
-
override fun getCurrentSpace(): RoomSummary? {
return selectedSpaceDataSourceSc.currentValue?.orNull()?.first?.let { spaceSummary ->
activeSessionHolder.getSafeActiveSession()?.roomService()?.getRoomSummary(spaceSummary.roomId)
@@ -97,9 +97,9 @@ class SpaceStateHandlerImpl @Inject constructor(
from: SelectSpaceFrom,
) {
val activeSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return
- val currentSpace = selectedSpaceDataSourceSc.currentValue?.orNull()?.first
- val spaceSummary = spaceId?.let { activeSession.getRoomSummary(spaceId) }
- val sameSpaceSelected = currentSpace != null && spaceId == currentSpace.roomId
+ val spaceToLeave = selectedSpaceDataSourceSc.currentValue?.orNull()?.first
+ val spaceToSet = spaceId?.let { activeSession.getRoomSummary(spaceId) }
+ val sameSpaceSelected = spaceId == spaceToLeave?.roomId
if (sameSpaceSelected) {
return
@@ -111,18 +111,18 @@ class SpaceStateHandlerImpl @Inject constructor(
}
if (isForwardNavigation && from in listOf(SelectSpaceFrom.SELECT, SelectSpaceFrom.INIT)) {
- spaceBackstack.addLast(currentSpace?.roomId)
+ addToBackstack(spaceToLeave, spaceToSet)
}
if (persistNow) {
- uiStateRepository.storeSelectedSpace(spaceSummary?.roomId, activeSession.sessionId)
+ uiStateRepository.storeSelectedSpace(spaceToSet?.roomId, activeSession.sessionId)
}
- if (spaceSummary == null) {
+ if (spaceToSet == null) {
//selectedSpaceDataSourceSc.post(Option.empty())
selectedSpaceDataSourceSc.post(Option.just(Pair(null, from)))
} else {
- selectedSpaceDataSourceSc.post(Option.just(Pair(spaceSummary, from)))
+ selectedSpaceDataSourceSc.post(Option.just(Pair(spaceToSet, from)))
}
if (spaceId != null) {
@@ -134,6 +134,17 @@ class SpaceStateHandlerImpl @Inject constructor(
}
}
+ private fun addToBackstack(spaceToLeave: RoomSummary?, spaceToSet: RoomSummary?) {
+ // Only add to the backstack if the space to set is not All Chats, else clear the backstack
+ if (spaceToSet != null) {
+ val currentPersistedBackstack = vectorPreferences.getSpaceBackstack().toMutableList()
+ currentPersistedBackstack.add(spaceToLeave?.roomId)
+ vectorPreferences.setSpaceBackstack(currentPersistedBackstack)
+ } else {
+ vectorPreferences.setSpaceBackstack(emptyList())
+ }
+ }
+
private fun observeActiveSession() {
sessionDataSource.stream()
.distinctUntilChanged()
@@ -159,7 +170,15 @@ class SpaceStateHandlerImpl @Inject constructor(
}
*/
- override fun getSpaceBackstack() = spaceBackstack
+ override fun popSpaceBackstack(): String? {
+ vectorPreferences.getSpaceBackstack().toMutableList().apply {
+ val poppedSpaceId = removeLast()
+ vectorPreferences.setSpaceBackstack(this)
+ return poppedSpaceId
+ }
+ }
+
+ override fun getSpaceBackstack() = vectorPreferences.getSpaceBackstack()
override fun getSelectedSpaceFlow() = selectedSpaceFlow
diff --git a/vector/src/main/java/im/vector/app/core/date/DateFormatKind.kt b/vector/src/main/java/im/vector/app/core/date/DateFormatKind.kt
index b08a1dc725..a66066ac8b 100644
--- a/vector/src/main/java/im/vector/app/core/date/DateFormatKind.kt
+++ b/vector/src/main/java/im/vector/app/core/date/DateFormatKind.kt
@@ -27,7 +27,7 @@ enum class DateFormatKind {
// Will show hour or date relative (9:30am or yesterday or Sep 7 or 09/07/2020)
ROOM_LIST,
- // Will show full date (Sep 7 2020)
+ // Will show full date (Sep 7, 2020)
TIMELINE_DAY_DIVIDER,
// Will show full date and time (Mon, Sep 7 2020, 9:30am)
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 851d4df7a1..0000000000
--- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt
+++ /dev/null
@@ -1,966 +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.list.home.NewChatBottomSheet
-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.PromptSimplifiedModeFragment
-import im.vector.app.features.login.terms.LoginTermsFragment
-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.VectorSettingsAdvancedSettingsFragment
-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(NewChatBottomSheet::class)
- fun bindNewChatBottomSheetFragment(fragment: NewChatBottomSheet): 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(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(VectorSettingsAdvancedSettingsFragment::class)
- fun bindVectorSettingsAdvancedSettingsFragment(fragment: VectorSettingsAdvancedSettingsFragment): 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(PromptSimplifiedModeFragment::class)
- fun bindPromptSimplifiedModeFragment(fragment: PromptSimplifiedModeFragment): 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 6da47c4f7d..8bcfd4e422 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,6 +52,8 @@ 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.home.room.list.home.release.ReleaseNotesViewModel
import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel
import im.vector.app.features.invite.InviteUsersToRoomViewModel
import im.vector.app.features.location.LocationSharingViewModel
@@ -86,6 +88,7 @@ import im.vector.app.features.settings.account.deactivation.DeactivateAccountVie
import im.vector.app.features.settings.crosssigning.CrossSigningSettingsViewModel
import im.vector.app.features.settings.devices.DeviceVerificationInfoBottomSheetViewModel
import im.vector.app.features.settings.devices.DevicesViewModel
+import im.vector.app.features.settings.devices.v2.overview.SessionOverviewViewModel
import im.vector.app.features.settings.devtools.AccountDataViewModel
import im.vector.app.features.settings.devtools.GossipingEventsPaperTrailViewModel
import im.vector.app.features.settings.devtools.KeyRequestListViewModel
@@ -349,6 +352,11 @@ interface MavericksViewModelModule {
@MavericksViewModelKey(DevicesViewModel::class)
fun devicesViewModelFactory(factory: DevicesViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+ @Binds
+ @IntoMap
+ @MavericksViewModelKey(im.vector.app.features.settings.devices.v2.DevicesViewModel::class)
+ fun devicesViewModelV2Factory(factory: im.vector.app.features.settings.devices.v2.DevicesViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
@Binds
@IntoMap
@MavericksViewModelKey(KeyRequestListViewModel::class)
@@ -618,4 +626,19 @@ interface MavericksViewModelModule {
@IntoMap
@MavericksViewModelKey(HomeRoomListViewModel::class)
fun homeRoomListViewModel(factory: HomeRoomListViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+ @Binds
+ @IntoMap
+ @MavericksViewModelKey(InvitesViewModel::class)
+ fun invitesViewModel(factory: InvitesViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+ @Binds
+ @IntoMap
+ @MavericksViewModelKey(ReleaseNotesViewModel::class)
+ fun releaseNotesViewModel(factory: ReleaseNotesViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+ @Binds
+ @IntoMap
+ @MavericksViewModelKey(SessionOverviewViewModel::class)
+ fun sessionOverviewViewModelFactory(factory: SessionOverviewViewModel.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/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/error/ErrorFormatter.kt b/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt
index d9a08bd81a..a09f852958 100644
--- a/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt
+++ b/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt
@@ -16,6 +16,7 @@
package im.vector.app.core.error
+import android.content.ActivityNotFoundException
import im.vector.app.R
import im.vector.app.core.resources.StringProvider
import im.vector.app.features.call.dialpad.DialPadLookup
@@ -134,6 +135,8 @@ class DefaultErrorFormatter @Inject constructor(
is MatrixIdFailure.InvalidMatrixId ->
stringProvider.getString(R.string.login_signin_matrix_id_error_invalid_matrix_id)
is VoiceFailure -> voiceMessageError(throwable)
+ is ActivityNotFoundException ->
+ stringProvider.getString(R.string.error_no_external_application_found)
else -> throwable.localizedMessage
}
?: stringProvider.getString(R.string.unknown_error)
diff --git a/vector/src/main/java/im/vector/app/core/platform/StateView.kt b/vector/src/main/java/im/vector/app/core/platform/StateView.kt
index 6f36787d0c..2fb99c705a 100755
--- a/vector/src/main/java/im/vector/app/core/platform/StateView.kt
+++ b/vector/src/main/java/im/vector/app/core/platform/StateView.kt
@@ -21,6 +21,7 @@ import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
+import android.widget.ImageView
import androidx.core.view.isVisible
import im.vector.app.R
import im.vector.app.core.extensions.updateConstraintSet
@@ -36,7 +37,8 @@ class StateView @JvmOverloads constructor(context: Context, attrs: AttributeSet?
val title: CharSequence? = null,
val image: Drawable? = null,
val isBigImage: Boolean = false,
- val message: CharSequence? = null
+ val message: CharSequence? = null,
+ val imageScaleType: ImageView.ScaleType? = ImageView.ScaleType.FIT_CENTER,
) : State()
data class Error(val message: CharSequence? = null) : State()
@@ -79,6 +81,7 @@ class StateView @JvmOverloads constructor(context: Context, attrs: AttributeSet?
is State.Content -> Unit
is State.Loading -> Unit
is State.Empty -> {
+ views.emptyImageView.scaleType = newState.imageScaleType
views.emptyImageView.setImageDrawable(newState.image)
views.emptyView.updateConstraintSet {
it.constrainPercentHeight(R.id.emptyImageView, if (newState.isBigImage) 0.5f else 0.1f)
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..c2c66ae69e 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)
@@ -256,7 +249,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver
initUiAndData()
- if (vectorFeatures.isNewAppLayoutEnabled()) {
+ if (vectorPreferences.isNewAppLayoutEnabled()) {
tryOrNull { // Add to XML theme when feature flag is removed
val toolbarBackground = MaterialColors.getColor(views.root, R.attr.vctr_toolbar_background)
window.statusBarColor = toolbarBackground
@@ -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/receiver/KeepInternalDistributor.kt b/vector/src/main/java/im/vector/app/core/pushers/KeepInternalDistributor.kt
similarity index 96%
rename from vector/src/main/java/im/vector/app/core/receiver/KeepInternalDistributor.kt
rename to vector/src/main/java/im/vector/app/core/pushers/KeepInternalDistributor.kt
index 3feee8c63b..63725f01a3 100644
--- a/vector/src/main/java/im/vector/app/core/receiver/KeepInternalDistributor.kt
+++ b/vector/src/main/java/im/vector/app/core/pushers/KeepInternalDistributor.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package im.vector.app.fdroid.receiver
+package im.vector.app.core.pushers
import android.content.BroadcastReceiver
import android.content.Context
diff --git a/vector/src/main/java/im/vector/app/core/pushers/PushParser.kt b/vector/src/main/java/im/vector/app/core/pushers/PushParser.kt
index 6f141e3736..8c18295c45 100644
--- a/vector/src/main/java/im/vector/app/core/pushers/PushParser.kt
+++ b/vector/src/main/java/im/vector/app/core/pushers/PushParser.kt
@@ -24,28 +24,34 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.util.MatrixJsonParser
import javax.inject.Inject
+/**
+ * Parse the received data from Push. Json format are different depending on the source.
+ *
+ * Notifications received by FCM are formatted by the matrix gateway [1]. The data send to FCM is the content
+ * of the "notification" attribute of the json sent to the gateway [2][3].
+ * On the other side, with UnifiedPush, the content of the message received is the content posted to the push
+ * gateway endpoint [3].
+ *
+ * *Note*: If we want to get the same content with FCM and unifiedpush, we can do a new sygnal pusher [4].
+ *
+ * [1] https://github.com/matrix-org/sygnal/blob/main/sygnal/gcmpushkin.py
+ * [2] https://github.com/matrix-org/sygnal/blob/main/sygnal/gcmpushkin.py#L366
+ * [3] https://spec.matrix.org/latest/push-gateway-api/
+ * [4] https://github.com/p1gp1g/sygnal/blob/unifiedpush/sygnal/upfcmpushkin.py (Not tested for a while)
+ */
class PushParser @Inject constructor() {
- /**
- * Parse the received data from Push. Json format are different depending on the source.
- *
- * Notifications received by FCM are formatted by the matrix gateway [1]. The data send to FCM is the content
- * of the "notification" attribute of the json sent to the gateway [2][3].
- * On the other side, with UnifiedPush, the content of the message received is the content posted to the push
- * gateway endpoint [3].
- *
- * *Note*: If we want to get the same content with FCM and unifiedpush, we can do a new sygnal pusher [4].
- *
- * [1] https://github.com/matrix-org/sygnal/blob/main/sygnal/gcmpushkin.py
- * [2] https://github.com/matrix-org/sygnal/blob/main/sygnal/gcmpushkin.py#L366
- * [3] https://spec.matrix.org/latest/push-gateway-api/
- * [4] https://github.com/p1gp1g/sygnal/blob/unifiedpush/sygnal/upfcmpushkin.py (Not tested for a while)
- */
- fun parseData(message: String, firebaseFormat: Boolean): PushData? {
- val moshi = MatrixJsonParser.getMoshi()
- return if (firebaseFormat) {
- tryOrNull { moshi.adapter(PushDataFcm::class.java).fromJson(message) }?.toPushData()
- } else {
- tryOrNull { moshi.adapter(PushDataUnifiedPush::class.java).fromJson(message) }?.toPushData()
+ fun parsePushDataUnifiedPush(message: ByteArray): PushData? {
+ return MatrixJsonParser.getMoshi().let {
+ tryOrNull { it.adapter(PushDataUnifiedPush::class.java).fromJson(String(message)) }?.toPushData()
}
}
+
+ fun parsePushDataFcm(message: Map): PushData {
+ val pushDataFcm = PushDataFcm(
+ eventId = message["event_id"],
+ roomId = message["room_id"],
+ unread = message["unread"]?.let { tryOrNull { Integer.parseInt(it) } },
+ )
+ return pushDataFcm.toPushData()
+ }
}
diff --git a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt
index 91ab58207d..c77f454ab0 100644
--- a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt
+++ b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt
@@ -29,7 +29,7 @@ import kotlin.math.abs
private const val DEFAULT_PUSHER_FILE_TAG = "mobile"
class PushersManager @Inject constructor(
- private val unifiedPushStore: UnifiedPushStore,
+ private val unifiedPushHelper: UnifiedPushHelper,
private val activeSessionHolder: ActiveSessionHolder,
private val localeProvider: LocaleProvider,
private val stringProvider: StringProvider,
@@ -39,9 +39,9 @@ class PushersManager @Inject constructor(
val currentSession = activeSessionHolder.getActiveSession()
currentSession.pushersService().testPush(
- unifiedPushStore.getPushGateway()!!,
+ unifiedPushHelper.getPushGateway() ?: return,
stringProvider.getString(R.string.pusher_app_id),
- unifiedPushStore.getEndpointOrToken().orEmpty(),
+ unifiedPushHelper.getEndpointOrToken().orEmpty(),
TEST_EVENT_ID
)
}
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 e1dc4ce93b..6050016025 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
@@ -46,6 +46,9 @@ class UnifiedPushHelper @Inject constructor(
private val vectorFeatures: VectorFeatures,
private val fcmHelper: FcmHelper,
) {
+
+ // Called when the home activity starts
+ // or when notifications are enabled
fun register(
activity: FragmentActivity,
onDoneRunnable: Runnable? = null,
@@ -56,7 +59,14 @@ class UnifiedPushHelper @Inject constructor(
)
}
- fun reRegister(
+ // If registration is forced:
+ // * the current distributor (if any) is removed
+ // * The dialog is opened
+ //
+ // The registration is forced in 2 cases :
+ // * in the settings
+ // * in the troubleshoot list (doFix)
+ fun forceRegister(
activity: FragmentActivity,
pushersManager: PushersManager,
onDoneRunnable: Runnable? = null
@@ -86,7 +96,8 @@ class UnifiedPushHelper @Inject constructor(
// Un-register first
unregister(pushersManager)
}
- if (UnifiedPush.getDistributor(context).isNotEmpty()) {
+ // the !force should not be needed
+ if (!force && UnifiedPush.getDistributor(context).isNotEmpty()) {
UnifiedPush.registerApp(context)
onDoneRunnable?.run()
return@launch
@@ -94,45 +105,26 @@ class UnifiedPushHelper @Inject constructor(
val distributors = UnifiedPush.getDistributors(context)
- if (distributors.size == 1 && !force) {
+ if (!force && distributors.size == 1) {
UnifiedPush.saveDistributor(context, distributors.first())
UnifiedPush.registerApp(context)
onDoneRunnable?.run()
} else {
openDistributorDialogInternal(
activity = activity,
- pushersManager = pushersManager,
onDoneRunnable = onDoneRunnable,
- distributors = distributors,
- unregisterFirst = force,
- cancellable = !force
+ distributors = distributors
)
}
}
}
- fun openDistributorDialog(
- activity: FragmentActivity,
- pushersManager: PushersManager,
- onDoneRunnable: Runnable,
- ) {
- val distributors = UnifiedPush.getDistributors(activity)
- openDistributorDialogInternal(
- activity,
- pushersManager,
- onDoneRunnable, distributors,
- unregisterFirst = true,
- cancellable = true,
- )
- }
-
+ // There is no case where this function is called
+ // with a saved distributor and/or a pusher
private fun openDistributorDialogInternal(
activity: FragmentActivity,
- pushersManager: PushersManager?,
onDoneRunnable: Runnable?,
- distributors: List,
- unregisterFirst: Boolean,
- cancellable: Boolean,
+ distributors: List
) {
val internalDistributorName = stringProvider.getString(
if (fcmHelper.isFirebaseAvailable()) {
@@ -154,16 +146,8 @@ class UnifiedPushHelper @Inject constructor(
.setTitle(stringProvider.getString(R.string.unifiedpush_getdistributors_dialog_title))
.setItems(distributorsName.toTypedArray()) { _, which ->
val distributor = distributors[which]
- if (distributor == UnifiedPush.getDistributor(context)) {
- Timber.d("Same distributor selected again, no action")
- return@setItems
- }
activity.lifecycleScope.launch {
- if (unregisterFirst) {
- // Un-register first
- unregister(pushersManager)
- }
UnifiedPush.saveDistributor(context, distributor)
Timber.i("Saving distributor: $distributor")
UnifiedPush.registerApp(context)
@@ -176,7 +160,7 @@ class UnifiedPushHelper @Inject constructor(
UnifiedPush.registerApp(context)
onDoneRunnable?.run()
}
- .setCancelable(cancellable)
+ .setCancelable(true)
.show()
}
@@ -184,7 +168,10 @@ class UnifiedPushHelper @Inject constructor(
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
vectorPreferences.setFdroidSyncBackgroundMode(mode)
try {
- pushersManager?.unregisterPusher(unifiedPushStore.getEndpointOrToken().orEmpty())
+ getEndpointOrToken()?.let {
+ Timber.d("Removing $it")
+ pushersManager?.unregisterPusher(it)
+ }
} catch (e: Exception) {
Timber.d(e, "Probably unregistering a non existing pusher")
}
@@ -253,11 +240,16 @@ class UnifiedPushHelper @Inject constructor(
}
fun isEmbeddedDistributor(): Boolean {
- return UnifiedPush.getDistributor(context) == context.packageName && fcmHelper.isFirebaseAvailable()
+ return isInternalDistributor() && fcmHelper.isFirebaseAvailable()
}
fun isBackgroundSync(): Boolean {
- return UnifiedPush.getDistributor(context) == context.packageName && !fcmHelper.isFirebaseAvailable()
+ return isInternalDistributor() && !fcmHelper.isFirebaseAvailable()
+ }
+
+ private fun isInternalDistributor(): Boolean {
+ return UnifiedPush.getDistributor(context).isEmpty() ||
+ UnifiedPush.getDistributor(context) == context.packageName
}
fun doesBackgroundSync(): Boolean {
@@ -265,7 +257,7 @@ class UnifiedPushHelper @Inject constructor(
}
fun getPrivacyFriendlyUpEndpoint(): String? {
- val endpoint = unifiedPushStore.getEndpointOrToken()
+ val endpoint = getEndpointOrToken()
if (endpoint.isNullOrEmpty()) return null
if (isEmbeddedDistributor()) {
return endpoint
@@ -278,4 +270,14 @@ class UnifiedPushHelper @Inject constructor(
null
}
}
+
+ fun getEndpointOrToken(): String? {
+ return if (isEmbeddedDistributor()) fcmHelper.getFcmToken()
+ else unifiedPushStore.getEndpoint()
+ }
+
+ fun getPushGateway(): String? {
+ return if (isEmbeddedDistributor()) stringProvider.getString(R.string.pusher_http_url)
+ else unifiedPushStore.getPushGateway()
+ }
}
diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushStore.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushStore.kt
index 07d291a723..d9c6bf3159 100644
--- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushStore.kt
+++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushStore.kt
@@ -22,7 +22,8 @@ import im.vector.app.core.di.DefaultSharedPreferences
import javax.inject.Inject
class UnifiedPushStore @Inject constructor(
- context: Context,
+ val context: Context,
+ val fcmHelper: FcmHelper
) {
private val defaultPrefs = DefaultSharedPreferences.getInstance(context)
@@ -31,7 +32,7 @@ class UnifiedPushStore @Inject constructor(
*
* @return the UnifiedPush Endpoint or null if not received
*/
- fun getEndpointOrToken(): String? {
+ fun getEndpoint(): String? {
return defaultPrefs.getString(PREFS_ENDPOINT_OR_TOKEN, null)
}
diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorPushHandler.kt
similarity index 58%
rename from vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt
rename to vector/src/main/java/im/vector/app/core/pushers/VectorPushHandler.kt
index 7996c96af9..b74028d579 100644
--- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt
+++ b/vector/src/main/java/im/vector/app/core/pushers/VectorPushHandler.kt
@@ -20,20 +20,16 @@ import android.content.Context
import android.content.Intent
import android.os.Handler
import android.os.Looper
-import android.widget.Toast
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.localbroadcastmanager.content.LocalBroadcastManager
-import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.network.WifiDetector
import im.vector.app.core.pushers.model.PushData
import im.vector.app.core.resources.BuildMeta
-import im.vector.app.core.services.GuardServiceStarter
import im.vector.app.features.notifications.NotifiableEventResolver
import im.vector.app.features.notifications.NotificationActionIds
import im.vector.app.features.notifications.NotificationDrawerManager
-import im.vector.app.features.settings.BackgroundSyncMode
import im.vector.app.features.settings.VectorDataStore
import im.vector.app.features.settings.VectorPreferences
import kotlinx.coroutines.CoroutineScope
@@ -46,30 +42,22 @@ import org.matrix.android.sdk.api.logger.LoggerTag
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.getTimelineEvent
-import org.unifiedpush.android.connector.MessagingReceiver
import timber.log.Timber
import javax.inject.Inject
private val loggerTag = LoggerTag("Push", LoggerTag.SYNC)
-/**
- * Hilt injection happen at super.onReceive().
- */
-@AndroidEntryPoint
-class VectorMessagingReceiver : MessagingReceiver() {
- @Inject lateinit var notificationDrawerManager: NotificationDrawerManager
- @Inject lateinit var notifiableEventResolver: NotifiableEventResolver
- @Inject lateinit var pushersManager: PushersManager
- @Inject lateinit var activeSessionHolder: ActiveSessionHolder
- @Inject lateinit var vectorPreferences: VectorPreferences
- @Inject lateinit var vectorDataStore: VectorDataStore
- @Inject lateinit var wifiDetector: WifiDetector
- @Inject lateinit var guardServiceStarter: GuardServiceStarter
- @Inject lateinit var unifiedPushHelper: UnifiedPushHelper
- @Inject lateinit var unifiedPushStore: UnifiedPushStore
- @Inject lateinit var pushParser: PushParser
- @Inject lateinit var actionIds: NotificationActionIds
- @Inject lateinit var buildMeta: BuildMeta
+class VectorPushHandler @Inject constructor(
+ private val notificationDrawerManager: NotificationDrawerManager,
+ private val notifiableEventResolver: NotifiableEventResolver,
+ private val activeSessionHolder: ActiveSessionHolder,
+ private val vectorPreferences: VectorPreferences,
+ private val vectorDataStore: VectorDataStore,
+ private val wifiDetector: WifiDetector,
+ private val actionIds: NotificationActionIds,
+ private val context: Context,
+ private val buildMeta: BuildMeta
+) {
private val coroutineScope = CoroutineScope(SupervisorJob())
@@ -81,25 +69,19 @@ class VectorMessagingReceiver : MessagingReceiver() {
/**
* Called when message is received.
*
- * @param context the Android context
- * @param message the message
- * @param instance connection, for multi-account
+ * @param pushData the data received in the push.
*/
- override fun onMessage(context: Context, message: ByteArray, instance: String) {
- Timber.tag(loggerTag.value).d("## onMessage() received")
+ fun handle(pushData: PushData) {
+ Timber.tag(loggerTag.value).d("## handling pushData")
- val sMessage = String(message)
if (buildMeta.lowPrivacyLoggingEnabled) {
- Timber.tag(loggerTag.value).d("## onMessage() $sMessage")
+ Timber.tag(loggerTag.value).d("## pushData: $pushData")
}
runBlocking {
vectorDataStore.incrementPushCounter()
}
- val pushData = pushParser.parseData(sMessage, unifiedPushHelper.isEmbeddedDistributor())
- ?: return Unit.also { Timber.tag(loggerTag.value).w("Invalid received data Json format") }
-
// Diagnostic Push
if (pushData.eventId == PushersManager.TEST_EVENT_ID) {
val intent = Intent(actionIds.push)
@@ -117,53 +99,7 @@ class VectorMessagingReceiver : MessagingReceiver() {
// we are in foreground, let the sync do the things?
Timber.tag(loggerTag.value).d("PUSH received in a foreground state, ignore")
} else {
- coroutineScope.launch(Dispatchers.IO) { onMessageReceivedInternal(pushData) }
- }
- }
- }
-
- override fun onNewEndpoint(context: Context, endpoint: String, instance: String) {
- Timber.tag(loggerTag.value).i("onNewEndpoint: adding $endpoint")
- if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) {
- // If the endpoint has changed
- // or the gateway has changed
- if (unifiedPushStore.getEndpointOrToken() != endpoint) {
- unifiedPushStore.storeUpEndpoint(endpoint)
- coroutineScope.launch {
- unifiedPushHelper.storeCustomOrDefaultGateway(endpoint) {
- unifiedPushStore.getPushGateway()?.let {
- pushersManager.enqueueRegisterPusher(endpoint, it)
- }
- }
- }
- } else {
- Timber.tag(loggerTag.value).i("onNewEndpoint: skipped")
- }
- }
- if (!vectorPreferences.forceAllowBackgroundSync()) {
- val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED
- vectorPreferences.setFdroidSyncBackgroundMode(mode)
- guardServiceStarter.stop()
- }
- }
-
- override fun onRegistrationFailed(context: Context, instance: String) {
- Toast.makeText(context, "Push service registration failed", Toast.LENGTH_SHORT).show()
- val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
- vectorPreferences.setFdroidSyncBackgroundMode(mode)
- guardServiceStarter.start()
- }
-
- override fun onUnregistered(context: Context, instance: String) {
- Timber.tag(loggerTag.value).d("Unifiedpush: Unregistered")
- val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
- vectorPreferences.setFdroidSyncBackgroundMode(mode)
- guardServiceStarter.start()
- runBlocking {
- try {
- pushersManager.unregisterPusher(unifiedPushStore.getEndpointOrToken().orEmpty())
- } catch (e: Exception) {
- Timber.tag(loggerTag.value).d("Probably unregistering a non existing pusher")
+ coroutineScope.launch(Dispatchers.IO) { handleInternal(pushData) }
}
}
}
@@ -173,12 +109,12 @@ class VectorMessagingReceiver : MessagingReceiver() {
*
* @param pushData Object containing message data.
*/
- private suspend fun onMessageReceivedInternal(pushData: PushData) {
+ private suspend fun handleInternal(pushData: PushData) {
try {
if (buildMeta.lowPrivacyLoggingEnabled) {
- Timber.tag(loggerTag.value).d("## onMessageReceivedInternal() : $pushData")
+ Timber.tag(loggerTag.value).d("## handleInternal() : $pushData")
} else {
- Timber.tag(loggerTag.value).d("## onMessageReceivedInternal()")
+ Timber.tag(loggerTag.value).d("## handleInternal()")
}
val session = activeSessionHolder.getOrInitializeSession(startSync = false)
@@ -198,7 +134,7 @@ class VectorMessagingReceiver : MessagingReceiver() {
}
}
} catch (e: Exception) {
- Timber.tag(loggerTag.value).e(e, "## onMessageReceivedInternal() failed")
+ Timber.tag(loggerTag.value).e(e, "## handleInternal() failed")
}
}
diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorUnifiedPushMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorUnifiedPushMessagingReceiver.kt
new file mode 100644
index 0000000000..bd327b52c1
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/pushers/VectorUnifiedPushMessagingReceiver.kt
@@ -0,0 +1,118 @@
+/*
+ * 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.pushers
+
+import android.content.Context
+import android.widget.Toast
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.core.di.ActiveSessionHolder
+import im.vector.app.core.services.GuardServiceStarter
+import im.vector.app.features.settings.BackgroundSyncMode
+import im.vector.app.features.settings.VectorPreferences
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import org.matrix.android.sdk.api.logger.LoggerTag
+import org.unifiedpush.android.connector.MessagingReceiver
+import timber.log.Timber
+import javax.inject.Inject
+
+private val loggerTag = LoggerTag("Push", LoggerTag.SYNC)
+
+/**
+ * Hilt injection happen at super.onReceive().
+ */
+@AndroidEntryPoint
+class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
+ @Inject lateinit var pushersManager: PushersManager
+ @Inject lateinit var pushParser: PushParser
+ @Inject lateinit var activeSessionHolder: ActiveSessionHolder
+ @Inject lateinit var vectorPreferences: VectorPreferences
+ @Inject lateinit var vectorPushHandler: VectorPushHandler
+ @Inject lateinit var guardServiceStarter: GuardServiceStarter
+ @Inject lateinit var unifiedPushStore: UnifiedPushStore
+ @Inject lateinit var unifiedPushHelper: UnifiedPushHelper
+
+ private val coroutineScope = CoroutineScope(SupervisorJob())
+
+ /**
+ * Called when message is received.
+ *
+ * @param context the Android context
+ * @param message the message
+ * @param instance connection, for multi-account
+ */
+ override fun onMessage(context: Context, message: ByteArray, instance: String) {
+ Timber.tag(loggerTag.value).d("New message")
+ pushParser.parsePushDataUnifiedPush(message)?.let {
+ vectorPushHandler.handle(it)
+ } ?: run {
+ Timber.tag(loggerTag.value).w("Invalid received data Json format")
+ }
+ }
+
+ override fun onNewEndpoint(context: Context, endpoint: String, instance: String) {
+ Timber.tag(loggerTag.value).i("onNewEndpoint: adding $endpoint")
+ if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) {
+ // If the endpoint has changed
+ // or the gateway has changed
+ if (unifiedPushHelper.getEndpointOrToken() != endpoint) {
+ unifiedPushStore.storeUpEndpoint(endpoint)
+ coroutineScope.launch {
+ unifiedPushHelper.storeCustomOrDefaultGateway(endpoint) {
+ unifiedPushHelper.getPushGateway()?.let {
+ pushersManager.enqueueRegisterPusher(endpoint, it)
+ }
+ }
+ }
+ } else {
+ Timber.tag(loggerTag.value).i("onNewEndpoint: skipped")
+ }
+ }
+ if (!vectorPreferences.forceAllowBackgroundSync()) {
+ val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED
+ vectorPreferences.setFdroidSyncBackgroundMode(mode)
+ guardServiceStarter.stop()
+ }
+ }
+
+ override fun onRegistrationFailed(context: Context, instance: String) {
+ Toast.makeText(context, "Push service registration failed", Toast.LENGTH_SHORT).show()
+ if (!vectorPreferences.isBackgroundSyncEnabled()) {
+ val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
+ vectorPreferences.setFdroidSyncBackgroundMode(mode)
+ guardServiceStarter.start()
+ }
+ }
+
+ override fun onUnregistered(context: Context, instance: String) {
+ Timber.tag(loggerTag.value).d("Unifiedpush: Unregistered")
+ if (!vectorPreferences.isBackgroundSyncEnabled()) {
+ val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
+ vectorPreferences.setFdroidSyncBackgroundMode(mode)
+ guardServiceStarter.start()
+ }
+ runBlocking {
+ try {
+ pushersManager.unregisterPusher(unifiedPushHelper.getEndpointOrToken().orEmpty())
+ } catch (e: Exception) {
+ Timber.tag(loggerTag.value).d("Probably unregistering a non existing pusher")
+ }
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt
index 1b9c37ae0a..e78cdf5ff8 100644
--- a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt
+++ b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt
@@ -16,8 +16,6 @@
package im.vector.app.core.pushers.model
-import com.squareup.moshi.Json
-import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.MatrixPatterns
/**
@@ -32,11 +30,10 @@ import org.matrix.android.sdk.api.MatrixPatterns
*
* .
*/
-@JsonClass(generateAdapter = true)
data class PushDataFcm(
- @Json(name = "event_id") val eventId: String?,
- @Json(name = "room_id") val roomId: String?,
- @Json(name = "unread") var unread: Int?,
+ val eventId: String?,
+ val roomId: String?,
+ var unread: Int?,
)
fun PushDataFcm.toPushData() = PushData(
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/VectorFeatures.kt b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt
index e60b225689..dbdb0ba1c7 100644
--- a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt
+++ b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt
@@ -18,6 +18,7 @@ package im.vector.app.features
import im.vector.app.config.Config
import im.vector.app.config.OnboardingVariant
+import im.vector.app.features.settings.VectorPreferences
interface VectorFeatures {
@@ -33,7 +34,13 @@ interface VectorFeatures {
fun isLocationSharingEnabled(): Boolean
fun forceUsageOfOpusEncoder(): Boolean
fun shouldStartDmOnFirstMessage(): Boolean
- fun isNewAppLayoutEnabled(): Boolean
+
+ /**
+ * This is only to enable if the labs flag should be visible and effective.
+ * If on the client-side you want functionality that should be enabled with the new layout,
+ * use [VectorPreferences.isNewAppLayoutEnabled] instead.
+ */
+ fun isNewAppLayoutFeatureEnabled(): Boolean
fun isNewDeviceManagementEnabled(): Boolean
}
@@ -50,6 +57,6 @@ class DefaultVectorFeatures : VectorFeatures {
override fun isLocationSharingEnabled() = Config.ENABLE_LOCATION_SHARING
override fun forceUsageOfOpusEncoder(): Boolean = false
override fun shouldStartDmOnFirstMessage(): Boolean = false
- override fun isNewAppLayoutEnabled(): Boolean = false
+ override fun isNewAppLayoutFeatureEnabled(): Boolean = true
override fun isNewDeviceManagementEnabled(): Boolean = false
}
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..1df1b35439 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
@@ -40,6 +40,46 @@ data class Interaction(
) : VectorAnalyticsEvent {
enum class Name {
+ /**
+ * User tapped the All filter in the All Chats filter tab.
+ */
+ MobileAllChatsFilterAll,
+
+ /**
+ * User tapped the Favourites filter in the All Chats filter tab.
+ */
+ MobileAllChatsFilterFavourites,
+
+ /**
+ * User tapped the People filter in the All Chats filter tab.
+ */
+ MobileAllChatsFilterPeople,
+
+ /**
+ * User tapped the Unreads filter in the All Chats filter tab.
+ */
+ MobileAllChatsFilterUnreads,
+
+ /**
+ * User disabled filters from the all chats layout settings.
+ */
+ MobileAllChatsFiltersDisabled,
+
+ /**
+ * User enabled filters from the all chats layout settings.
+ */
+ MobileAllChatsFiltersEnabled,
+
+ /**
+ * User disabled recents from the all chats layout settings.
+ */
+ MobileAllChatsRecentsDisabled,
+
+ /**
+ * User enabled recents from the all chats layout settings.
+ */
+ MobileAllChatsRecentsEnabled,
+
/**
* User tapped on Add to Home button on Room Details screen.
*/
@@ -60,6 +100,11 @@ data class Interaction(
*/
MobileRoomThreadSummaryItem,
+ /**
+ * User validated the creation of a new space.
+ */
+ MobileSpaceCreationValidated,
+
/**
* User tapped on the filter button on ThreadList screen.
*/
@@ -81,6 +126,12 @@ data class Interaction(
*/
SpacePanelSwitchSpace,
+ /**
+ * User tapped an unselected sub space from the space list -> space
+ * switching should occur.
+ */
+ SpacePanelSwitchSubSpace,
+
/**
* User clicked the create room button in the add existing room to space
* dialog in Element Web/Desktop.
@@ -117,6 +168,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 +336,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 +418,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/MobileScreen.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/MobileScreen.kt
index 3ce3dfb578..7ea41e2d78 100644
--- a/vector/src/main/java/im/vector/app/features/analytics/plan/MobileScreen.kt
+++ b/vector/src/main/java/im/vector/app/features/analytics/plan/MobileScreen.kt
@@ -43,6 +43,11 @@ data class MobileScreen(
*/
CreateRoom,
+ /**
+ * The screen shown to create a new space.
+ */
+ CreateSpace,
+
/**
* The confirmation screen shown before deactivating an account.
*/
@@ -78,6 +83,11 @@ data class MobileScreen(
*/
InviteFriends,
+ /**
+ * Room accessed via space bottom sheet list.
+ */
+ Invites,
+
/**
* The screen that displays the login flow (when the user already has an
* account).
@@ -261,6 +271,11 @@ data class MobileScreen(
*/
Sidebar,
+ /**
+ * Room accessed via space bottom sheet list.
+ */
+ SpaceBottomSheet,
+
/**
* Screen that displays the list of rooms and spaces of a space.
*/
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/UserProperties.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/UserProperties.kt
index 77be2456cd..28732c9a42 100644
--- a/vector/src/main/java/im/vector/app/features/analytics/plan/UserProperties.kt
+++ b/vector/src/main/java/im/vector/app/features/analytics/plan/UserProperties.kt
@@ -44,6 +44,10 @@ data class UserProperties(
* Whether the user has the people space enabled.
*/
val webMetaSpacePeopleEnabled: Boolean? = null,
+ /**
+ * The active filter in the All Chats screen.
+ */
+ val allChatsActiveFilter: AllChatsActiveFilter? = null,
/**
* The selected messaging use case during the onboarding flow.
*/
@@ -80,6 +84,29 @@ data class UserProperties(
WorkMessaging,
}
+ enum class AllChatsActiveFilter {
+
+ /**
+ * Filters are activated and All is selected.
+ */
+ All,
+
+ /**
+ * Filters are activated and Favourites is selected.
+ */
+ Favourites,
+
+ /**
+ * Filters are activated and People is selected.
+ */
+ People,
+
+ /**
+ * Filters are activated and Unreads is selected.
+ */
+ Unreads,
+ }
+
fun getProperties(): Map? {
return mutableMapOf().apply {
webMetaSpaceFavouritesEnabled?.let { put("WebMetaSpaceFavouritesEnabled", it) }
@@ -87,6 +114,7 @@ data class UserProperties(
webMetaSpaceHomeEnabled?.let { put("WebMetaSpaceHomeEnabled", it) }
webMetaSpaceOrphansEnabled?.let { put("WebMetaSpaceOrphansEnabled", it) }
webMetaSpacePeopleEnabled?.let { put("WebMetaSpacePeopleEnabled", it) }
+ allChatsActiveFilter?.let { put("allChatsActiveFilter", it.name) }
ftueUseCaseSelection?.let { put("ftueUseCaseSelection", it.name) }
numFavouriteRooms?.let { put("numFavouriteRooms", it) }
numSpaces?.let { put("numSpaces", it) }
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..366979025a 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
@@ -110,6 +110,11 @@ data class ViewRoom(
*/
MobileSearchContactDetail,
+ /**
+ * Room accessed via space bottom sheet list.
+ */
+ MobileSpaceBottomSheet,
+
/**
* Room accessed via interacting with direct chat item in the space
* contact detail screen.
@@ -152,6 +157,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/AttachmentsHelper.kt b/vector/src/main/java/im/vector/app/features/attachments/AttachmentsHelper.kt
index 6cb4e5d78e..97e15d819d 100644
--- a/vector/src/main/java/im/vector/app/features/attachments/AttachmentsHelper.kt
+++ b/vector/src/main/java/im/vector/app/features/attachments/AttachmentsHelper.kt
@@ -47,6 +47,7 @@ class AttachmentsHelper(
interface Callback {
fun onContactAttachmentReady(contactAttachment: ContactAttachment)
fun onContentAttachmentsReady(attachments: List)
+ fun onAttachmentError(throwable: Throwable)
}
// Capture path allows to handle camera image picking. It must be restored if the activity gets killed.
@@ -76,21 +77,21 @@ class AttachmentsHelper(
/**
* Starts the process for handling file picking.
*/
- fun selectFile(activityResultLauncher: ActivityResultLauncher) {
+ fun selectFile(activityResultLauncher: ActivityResultLauncher) = doSafe {
MultiPicker.get(MultiPicker.FILE).startWith(activityResultLauncher)
}
/**
* Starts the process for handling image/video picking.
*/
- fun selectGallery(activityResultLauncher: ActivityResultLauncher) {
+ fun selectGallery(activityResultLauncher: ActivityResultLauncher) = doSafe {
MultiPicker.get(MultiPicker.MEDIA).startWith(activityResultLauncher)
}
/**
* Starts the process for handling audio picking.
*/
- fun selectAudio(activityResultLauncher: ActivityResultLauncher) {
+ fun selectAudio(activityResultLauncher: ActivityResultLauncher) = doSafe {
MultiPicker.get(MultiPicker.AUDIO).startWith(activityResultLauncher)
}
@@ -104,20 +105,12 @@ class AttachmentsHelper(
cameraVideoActivityResultLauncher: ActivityResultLauncher
) {
PhotoOrVideoDialog(activity, vectorPreferences).show(object : PhotoOrVideoDialog.PhotoOrVideoDialogListener {
- override fun takePhoto() {
- try {
- captureUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(context, cameraActivityResultLauncher)
- } catch (e: ActivityNotFoundException) {
- Toast.makeText(activity, R.string.error_no_external_application_found, Toast.LENGTH_LONG).show()
- }
+ override fun takePhoto() = doSafe {
+ captureUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(context, cameraActivityResultLauncher)
}
- override fun takeVideo() {
- try {
- captureUri = MultiPicker.get(MultiPicker.CAMERA_VIDEO).startWithExpectingFile(context, cameraVideoActivityResultLauncher)
- } catch (e: ActivityNotFoundException) {
- Toast.makeText(activity, R.string.error_no_external_application_found, Toast.LENGTH_LONG).show()
- }
+ override fun takeVideo() = doSafe {
+ captureUri = MultiPicker.get(MultiPicker.CAMERA_VIDEO).startWithExpectingFile(context, cameraVideoActivityResultLauncher)
}
})
}
@@ -125,10 +118,18 @@ class AttachmentsHelper(
/**
* Starts the process for handling contact picking.
*/
- fun selectContact(activityResultLauncher: ActivityResultLauncher) {
+ fun selectContact(activityResultLauncher: ActivityResultLauncher) = doSafe {
MultiPicker.get(MultiPicker.CONTACT).startWith(activityResultLauncher)
}
+ private fun doSafe(function: () -> Unit) {
+ try {
+ function()
+ } catch (activityNotFound: ActivityNotFoundException) {
+ callback.onAttachmentError(activityNotFound)
+ }
+ }
+
/**
* This methods aims to handle the result data.
*/
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 e98facd1a0..e21d64c979 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/autocomplete/member/AutocompleteMemberPresenter.kt b/vector/src/main/java/im/vector/app/features/autocomplete/member/AutocompleteMemberPresenter.kt
index a480b1c279..ff04a4db17 100644
--- a/vector/src/main/java/im/vector/app/features/autocomplete/member/AutocompleteMemberPresenter.kt
+++ b/vector/src/main/java/im/vector/app/features/autocomplete/member/AutocompleteMemberPresenter.kt
@@ -145,7 +145,12 @@ class AutocompleteMemberPresenter @AssistedInject constructor(
private fun createEveryoneItem(query: CharSequence?) =
room.roomSummary()
?.takeIf { canNotifyEveryone() }
- ?.takeIf { query.isNullOrBlank() || MatrixItem.NOTIFY_EVERYONE.startsWith("@$query") }
+ ?.takeIf {
+ query.isNullOrBlank() ||
+ SUGGEST_ROOM_KEYWORDS.any {
+ it.startsWith("@$query")
+ }
+ }
?.let {
AutocompleteMemberItem.Everyone(it)
}
@@ -165,6 +170,7 @@ class AutocompleteMemberPresenter @AssistedInject constructor(
companion object {
private const val ID_HEADER_MEMBERS = "ID_HEADER_MEMBERS"
private const val ID_HEADER_EVERYONE = "ID_HEADER_EVERYONE"
+ private val SUGGEST_ROOM_KEYWORDS = setOf(MatrixItem.NOTIFY_EVERYONE, "@channel", "@everyone", "@here")
}
}
diff --git a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt
index 1378321026..be3cabfc18 100644
--- a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt
+++ b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt
@@ -374,15 +374,15 @@ class CommandParser @Inject constructor() {
}
}
Command.ADD_TO_SPACE.matches(slashCommand) -> {
- if (messageParts.size == 1) {
- ParsedCommand.AddToSpace(spaceId = message)
+ if (messageParts.size == 2) {
+ ParsedCommand.AddToSpace(spaceId = messageParts.last())
} else {
ParsedCommand.ErrorSyntax(Command.ADD_TO_SPACE)
}
}
Command.JOIN_SPACE.matches(slashCommand) -> {
- if (messageParts.size == 1) {
- ParsedCommand.JoinSpace(spaceIdOrAlias = message)
+ if (messageParts.size == 2) {
+ ParsedCommand.JoinSpace(spaceIdOrAlias = messageParts.last())
} else {
ParsedCommand.ErrorSyntax(Command.JOIN_SPACE)
}
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/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 41ff8af04b..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)
diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageKeyFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageKeyFragment.kt
index 5a7aba65a5..efb24ebea7 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageKeyFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageKeyFragment.kt
@@ -24,6 +24,7 @@ import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.activityViewModel
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.platform.VectorBaseFragment
@@ -35,9 +36,10 @@ import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.extensions.tryOrNull
import reactivecircus.flowbinding.android.widget.editorActionEvents
import reactivecircus.flowbinding.android.widget.textChanges
-import javax.inject.Inject
-class SharedSecuredStorageKeyFragment @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 5f2ece2c1d..911bd4e80a 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
@@ -40,7 +40,7 @@ abstract class HomeSpaceSummaryItem : VectorEpoxyModel
if (activityResult.resultCode == Activity.RESULT_OK) {
val spaceId = SpaceCreationActivity.getCreatedSpaceId(activityResult.data)
@@ -162,8 +168,9 @@ class HomeActivity :
navigator.switchToSpace(
context = this,
spaceId = spaceId,
- postSwitchOption
+ postSwitchOption,
)
+ roomListSharedActionViewModel.post(RoomListSharedAction.CloseBottomSheet)
}
}
}
@@ -200,26 +207,29 @@ class HomeActivity :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ isNewAppLayoutEnabled = vectorPreferences.isNewAppLayoutEnabled()
analyticsScreenName = MobileScreen.ScreenName.Home
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false)
unifiedPushHelper.register(this) {
if (unifiedPushHelper.isEmbeddedDistributor()) {
fcmHelper.ensureFcmTokenIsRetrieved(
this,
- pushManager,
+ pushersManager,
vectorPreferences.areNotificationEnabledForDevice()
)
}
}
sharedActionViewModel = viewModelProvider[HomeSharedActionViewModel::class.java]
+ roomListSharedActionViewModel = viewModelProvider[RoomListSharedActionViewModel::class.java]
views.drawerLayout.addDrawerListener(drawerListener)
if (isFirstCreation()) {
- if (vectorFeatures.isNewAppLayoutEnabled()) {
+ if (vectorPreferences.isNewAppLayoutEnabled()) {
views.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
replaceFragment(views.homeDetailFragmentContainer, NewHomeDetailFragment::class.java)
} else {
replaceFragment(views.homeDetailFragmentContainer, HomeDetailFragment::class.java)
replaceFragment(views.homeDrawerFragmentContainer, HomeDrawerFragment::class.java)
+ views.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
}
}
@@ -266,6 +276,7 @@ class HomeActivity :
}
is HomeActivityViewEvents.OnCrossSignedInvalidated -> handleCrossSigningInvalidated(it)
HomeActivityViewEvents.ShowAnalyticsOptIn -> handleShowAnalyticsOptIn()
+ HomeActivityViewEvents.ShowReleaseNotes -> handleShowReleaseNotes()
HomeActivityViewEvents.NotifyUserForThreadsMigration -> handleNotifyUserForThreadsMigration()
is HomeActivityViewEvents.MigrateThreads -> migrateThreadsIfNeeded(it.checkSession)
}
@@ -280,6 +291,10 @@ class HomeActivity :
homeActivityViewModel.handle(HomeActivityViewActions.ViewStarted)
}
+ private fun handleShowReleaseNotes() {
+ startActivity(Intent(this, ReleaseNotesActivity::class.java))
+ }
+
private fun showSpaceSettings(spaceId: String) {
// open bottom sheet
SpaceSettingsMenuBottomSheet
@@ -377,7 +392,7 @@ class HomeActivity :
lifecycleScope.launch {
val isHandled = permalinkHandler.launch(
- context = this@HomeActivity,
+ fragmentActivity = this@HomeActivity,
deepLink = resolvedLink,
navigationInterceptor = this@HomeActivity,
buildTask = true
@@ -577,9 +592,17 @@ class HomeActivity :
// Check nightly
nightlyProxy.onHomeResumed()
+
+ checkNewAppLayoutFlagChange()
}
- override fun getMenuRes() = if (vectorFeatures.isNewAppLayoutEnabled()) R.menu.menu_new_home else R.menu.menu_home
+ private fun checkNewAppLayoutFlagChange() {
+ if (vectorPreferences.isNewAppLayoutEnabled() != isNewAppLayoutEnabled) {
+ restart()
+ }
+ }
+
+ override fun getMenuRes() = if (vectorPreferences.isNewAppLayoutEnabled()) R.menu.menu_new_home else R.menu.menu_home
override fun handlePrepareMenu(menu: Menu) {
menu.findItem(R.id.menu_home_init_sync_legacy)?.isVisible = vectorPreferences.developerMode()
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewEvents.kt
index 170550d5b4..e0b9e8ceb5 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewEvents.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewEvents.kt
@@ -31,6 +31,7 @@ sealed interface HomeActivityViewEvents : VectorViewEvents {
data class OnCrossSignedInvalidated(val userItem: MatrixItem.UserItem) : HomeActivityViewEvents
object PromptToEnableSessionPush : HomeActivityViewEvents
object ShowAnalyticsOptIn : HomeActivityViewEvents
+ object ShowReleaseNotes : HomeActivityViewEvents
object NotifyUserForThreadsMigration : HomeActivityViewEvents
data class MigrateThreads(val checkSession: Boolean) : HomeActivityViewEvents
object StartRecoverySetupFlow : HomeActivityViewEvents
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
index cfe76706a5..6aba9eefcf 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
@@ -26,11 +26,13 @@ import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.VectorViewModel
+import im.vector.app.features.VectorFeatures
import im.vector.app.features.analytics.AnalyticsConfig
import im.vector.app.features.analytics.AnalyticsTracker
import im.vector.app.features.analytics.extensions.toAnalyticsType
import im.vector.app.features.analytics.plan.Signup
import im.vector.app.features.analytics.store.AnalyticsStore
+import im.vector.app.features.home.room.list.home.release.ReleaseNotesPreferencesStore
import im.vector.app.features.login.ReAuthHelper
import im.vector.app.features.onboarding.AuthenticationDescription
import im.vector.app.features.raw.wellknown.ElementWellKnown
@@ -82,6 +84,8 @@ class HomeActivityViewModel @AssistedInject constructor(
private val vectorPreferences: VectorPreferences,
private val analyticsTracker: AnalyticsTracker,
private val analyticsConfig: AnalyticsConfig,
+ private val releaseNotesPreferencesStore: ReleaseNotesPreferencesStore,
+ private val vectorFeatures: VectorFeatures,
) : VectorViewModel(initialState) {
@AssistedFactory
@@ -110,9 +114,26 @@ class HomeActivityViewModel @AssistedInject constructor(
checkSessionPushIsOn()
observeCrossSigningReset()
observeAnalytics()
+ observeReleaseNotes()
initThreadsMigration()
}
+ private fun observeReleaseNotes() = withState { state ->
+ // we don't want to show release notes for new users or after relogin
+ if (state.authenticationDescription == null && vectorPreferences.isNewAppLayoutEnabled()) {
+ releaseNotesPreferencesStore.appLayoutOnboardingShown.onEach { isAppLayoutOnboardingShown ->
+ if (!isAppLayoutOnboardingShown) {
+ _viewEvents.post(HomeActivityViewEvents.ShowReleaseNotes)
+ }
+ }.launchIn(viewModelScope)
+ } else {
+ // we assume that users which came from auth flow either have seen updates already (relogin) or don't need them (new user)
+ viewModelScope.launch {
+ releaseNotesPreferencesStore.setAppLayoutOnboardingShown(true)
+ }
+ }
+ }
+
private fun observeAnalytics() {
if (analyticsConfig.isEnabled) {
analyticsStore.didAskUserConsentFlow
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 f39726a7a2..de65eea16f 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
@@ -32,6 +32,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 de.spiritcroc.matrixsdk.util.DbgUtil
import de.spiritcroc.matrixsdk.util.Dimber
import de.spiritcroc.viewpager.reduceDragSensitivity
@@ -73,19 +74,21 @@ import timber.log.Timber
import javax.inject.Inject
import kotlin.math.abs
-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 DEBUG_VIEW_PAGER = DbgUtil.isDbgEnabled(DbgUtil.DBG_VIEW_PAGER)
private val viewPagerDimber = Dimber("Home pager", DbgUtil.DBG_VIEW_PAGER)
@@ -216,7 +219,7 @@ class HomeDetailFragment @Inject constructor(
unreadMessagesSharedViewModel.onEach { state ->
views.drawerUnreadCounterBadgeView.render(
- UnreadCounterBadgeView.State(
+ UnreadCounterBadgeView.State.Count(
count = state.otherSpacesUnread.totalCount,
highlighted = state.otherSpacesUnread.isHighlight,
unread = state.otherSpacesUnread.unreadCount,
@@ -257,7 +260,7 @@ class HomeDetailFragment @Inject constructor(
}
private fun navigateBack() {
- val previousSpaceId = spaceStateHandler.getSpaceBackstack().removeLastOrNull()
+ val previousSpaceId = spaceStateHandler.popSpaceBackstack()
val parentSpaceId = spaceStateHandler.getCurrentSpace()?.flattenParentIds?.lastOrNull()
setCurrentSpace(previousSpaceId ?: parentSpaceId)
}
@@ -381,9 +384,10 @@ class HomeDetailFragment @Inject constructor(
viewBinder = VerificationVectorAlert.ViewBinder(user, avatarRenderer)
colorInt = colorProvider.getColorFromAttribute(R.attr.colorPrimary)
contentAction = Runnable {
- (weakCurrentActivity?.get() as? VectorBaseActivity<*>)
- ?.navigator
- ?.requestSessionVerification(requireContext(), newest.deviceId ?: "")
+ (weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let { vectorBaseActivity ->
+ vectorBaseActivity.navigator
+ .requestSessionVerification(vectorBaseActivity, newest.deviceId ?: "")
+ }
unknownDeviceDetectorSharedViewModel.handle(
UnknownDeviceDetectorSharedViewModel.Action.IgnoreDevice(newest.deviceId?.let { listOf(it) }.orEmpty())
)
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 cc59727386..c21065815f 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
@@ -41,12 +42,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
@@ -114,7 +117,6 @@ class HomeDrawerFragment @Inject constructor(
}
// Debug menu
- views.homeDrawerHeaderDebugView.isVisible = buildMeta.isDebug && vectorPreferences.developerMode()
views.homeDrawerHeaderDebugView.debouncedClicks {
sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer)
navigator.openDebug(requireActivity())
@@ -129,4 +131,9 @@ class HomeDrawerFragment @Inject constructor(
// SC-Easy mode prompt
PromptSimplifiedModeActivity.showIfRequired(requireContext(), vectorPreferences)
}
+
+ override fun onResume() {
+ super.onResume()
+ views.homeDrawerHeaderDebugView.isVisible = buildMeta.isDebug && vectorPreferences.developerMode()
+ }
}
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 0e4f0d90dc..3681ba4c15 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
@@ -23,11 +23,13 @@ import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
+import androidx.core.view.isVisible
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 com.google.android.material.appbar.AppBarLayout
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.SpaceStateHandler
import im.vector.app.core.extensions.commitTransaction
@@ -35,6 +37,7 @@ import im.vector.app.core.platform.OnBackPressed
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.platform.VectorMenuProvider
+import im.vector.app.core.resources.BuildMeta
import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.ui.views.CurrentCallsView
import im.vector.app.core.ui.views.CurrentCallsViewPresenter
@@ -44,44 +47,52 @@ import im.vector.app.features.call.SharedKnownCallsViewModel
import im.vector.app.features.call.VectorCallActivity
import im.vector.app.features.call.dialpad.PstnDialActivity
import im.vector.app.features.call.webrtc.WebRtcCallManager
+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.HomeRoomListFragment
+import im.vector.app.features.home.room.list.home.NewChatBottomSheet
import im.vector.app.features.popup.PopupAlertManager
import im.vector.app.features.popup.VerificationVectorAlert
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.spaces.SpaceListBottomSheet
import im.vector.app.features.workers.signout.BannerState
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
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 spaceStateHandler: 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
+ @Inject lateinit var buildMeta: BuildMeta
+
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
+ private lateinit var sharedRoomListActionViewModel: RoomListSharedActionViewModel
private lateinit var sharedCallActionViewModel: SharedKnownCallsViewModel
+ private val newChatBottomSheet = NewChatBottomSheet()
+ private val spaceListBottomSheet = SpaceListBottomSheet()
+
private var hasUnreadRooms = false
set(value) {
if (value != field) {
@@ -124,24 +135,21 @@ class NewHomeDetailFragment @Inject constructor(
super.onViewCreated(view, savedInstanceState)
sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java)
sharedCallActionViewModel = activityViewModelProvider.get(SharedKnownCallsViewModel::class.java)
- setupBottomNavigationView()
setupToolbar()
setupKeysBackupBanner()
setupActiveCallView()
+ setupDebugButton()
+ setupFabs()
+ setupObservers()
- 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.observeViewEvents { viewEvent ->
when (viewEvent) {
HomeDetailViewEvents.CallStarted -> Unit
@@ -175,10 +183,37 @@ class NewHomeDetailFragment @Inject constructor(
}
}
- private fun navigateBack() {
- val previousSpaceId = spaceStateHandler.getSpaceBackstack().removeLastOrNull()
- val parentSpaceId = spaceStateHandler.getCurrentSpace()?.flattenParentIds?.lastOrNull()
- setCurrentSpace(previousSpaceId ?: parentSpaceId)
+ private fun setupObservers() {
+ sharedRoomListActionViewModel = activityViewModelProvider[RoomListSharedActionViewModel::class.java]
+
+ sharedRoomListActionViewModel
+ .stream()
+ .onEach(::handleSharedAction)
+ .launchIn(viewLifecycleOwner.lifecycleScope)
+ }
+
+ private fun handleSharedAction(action: RoomListSharedAction) {
+ when (action) {
+ RoomListSharedAction.CloseBottomSheet -> spaceListBottomSheet.dismiss()
+ }
+ }
+
+ 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)
+ }
+ }
+
+ private fun showFABs() {
+ views.newLayoutCreateChatButton.show()
+ views.newLayoutOpenSpacesButton.show()
}
private fun setCurrentSpace(spaceId: String?) {
@@ -193,7 +228,6 @@ class NewHomeDetailFragment @Inject constructor(
override fun onResume() {
super.onResume()
- updateTabVisibilitySafely(R.id.bottom_action_notification, vectorPreferences.labAddNotificationTab())
callManager.checkForProtocolsSupportIfNeeded()
refreshSpaceState()
}
@@ -216,9 +250,10 @@ class NewHomeDetailFragment @Inject constructor(
viewBinder = VerificationVectorAlert.ViewBinder(user, avatarRenderer)
colorInt = colorProvider.getColorFromAttribute(R.attr.colorPrimary)
contentAction = Runnable {
- (weakCurrentActivity?.get() as? VectorBaseActivity<*>)
- ?.navigator
- ?.requestSessionVerification(requireContext(), newest.deviceId ?: "")
+ (weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let { vectorBaseActivity ->
+ vectorBaseActivity.navigator
+ .requestSessionVerification(vectorBaseActivity, newest.deviceId ?: "")
+ }
unknownDeviceDetectorSharedViewModel.handle(
UnknownDeviceDetectorSharedViewModel.Action.IgnoreDevice(newest.deviceId?.let { listOf(it) }.orEmpty())
)
@@ -285,12 +320,6 @@ class NewHomeDetailFragment @Inject constructor(
private fun setupToolbar() {
setupToolbar(views.toolbar)
- lifecycleScope.launch(Dispatchers.IO) {
- session.userService().getUser(session.myUserId)?.let { user ->
- avatarRenderer.render(user.toMatrixItem(), views.avatar)
- }
- }
-
views.collapsingToolbar.debouncedClicks(::openSpaceSettings)
views.toolbar.debouncedClicks(::openSpaceSettings)
@@ -305,63 +334,15 @@ class NewHomeDetailFragment @Inject constructor(
}
}
- 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 setupDebugButton() {
+ views.debugButton.debouncedClicks {
+ sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer)
+ navigator.openDebug(requireActivity())
}
- }
- 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 -> {
- throw NotImplementedError("this tab shouldn't exists when app layout is enabled")
- }
- }
- } else {
- attach(fragmentToShow)
- }
- }
- }
-
- 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)))
- }
- }
- }
+ views.appBarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { _, verticalOffset ->
+ views.debugButton.isVisible = verticalOffset == 0 && buildMeta.isDebug && vectorPreferences.developerMode()
+ })
}
/* ==========================================================================================
@@ -377,9 +358,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,
@@ -387,27 +365,13 @@ class NewHomeDetailFragment @Inject constructor(
vectorPreferences.developerShowDebugInfo()
)
+ refreshAvatar()
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
+ private fun refreshAvatar() = withState(viewModel) { state ->
+ state.myMatrixItem?.let { user ->
+ avatarRenderer.render(user, views.avatar)
}
}
@@ -427,10 +391,17 @@ class NewHomeDetailFragment @Inject constructor(
}
}
- override fun onBackPressed(toolbarButton: Boolean) = if (spaceStateHandler.getCurrentSpace() != null) {
- navigateBack()
- true
- } else {
+ override fun onBackPressed(toolbarButton: Boolean) = if (spaceStateHandler.isRoot()) {
false
+ } else {
+ val lastSpace = spaceStateHandler.popSpaceBackstack()
+ spaceStateHandler.setCurrentSpace(lastSpace, isForwardNavigation = false)
+ true
+ }
+
+ private fun SpaceStateHandler.isRoot() = getSpaceBackstack().isEmpty()
+
+ 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/breadcrumbs/BreadcrumbsItem.kt b/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsItem.kt
index f72597f268..02dc22a024 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsItem.kt
@@ -52,7 +52,7 @@ abstract class BreadcrumbsItem : VectorEpoxyModel(R.layo
holder.unreadIndentIndicator.isVisible = hasUnreadMessage
avatarRenderer.render(matrixItem, holder.avatarImageView)
holder.avatarImageView.contentDescription = matrixItem.getBestName()
- holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted, unreadMessages, markedUnread))
+ holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State.Count(unreadNotificationCount, showHighlighted, unreadMessages, markedUnread))
holder.draftIndentIndicator.isVisible = hasDraft
holder.typingIndicator.isVisible = hasTypingUsers
}
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 052f471287..b7c65814aa 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
@@ -65,11 +65,13 @@ import com.airbnb.epoxy.EpoxyViewHolder
import com.airbnb.epoxy.OnModelBuildFinishedListener
import com.airbnb.epoxy.addGlidePreloader
import com.airbnb.epoxy.glidePreloader
+import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.args
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 de.spiritcroc.matrixsdk.util.DbgUtil
import de.spiritcroc.matrixsdk.util.Dimber
import de.spiritcroc.menu.ArrayOptionsMenuHelper
@@ -82,6 +84,7 @@ 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
@@ -171,6 +174,7 @@ import im.vector.app.features.home.room.detail.composer.SendMode
import im.vector.app.features.home.room.detail.composer.boolean
import im.vector.app.features.home.room.detail.composer.voice.VoiceMessageRecorderView
import im.vector.app.features.home.room.detail.composer.voice.VoiceMessageRecorderView.RecordingUiState
+import im.vector.app.features.home.room.detail.error.RoomNotFound
import im.vector.app.features.home.room.detail.readreceipts.DisplayReadReceiptsBottomSheet
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
import im.vector.app.features.home.room.detail.timeline.action.EventSharedAction
@@ -237,6 +241,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.billcarsonfr.jsonviewer.JSonViewerDialog
import org.commonmark.parser.Parser
+import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
@@ -276,34 +281,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 generationVideoDownloadDecider: ThumbnailGenerationVideoDownloadDecider,
- private val bubbleThemeUtils: BubbleThemeUtils,
- 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 typingHelper: TypingHelper,
- 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,
@@ -313,6 +292,34 @@ 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 generationVideoDownloadDecider: ThumbnailGenerationVideoDownloadDecider
+ @Inject lateinit var bubbleThemeUtils: BubbleThemeUtils
+ @Inject lateinit var typingHelper: TypingHelper
+ @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
+
private val rmDimber = Dimber("ReadMarkerDbg", DbgUtil.DBG_READ_MARKER)
companion object {
@@ -338,7 +345,7 @@ class TimelineFragment @Inject constructor(
const val FLOATING_DATE_HIDE_DELAY = 1500L
}
- private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock)
+ private lateinit var galleryOrCameraDialogHelper: GalleryOrCameraDialogHelper
private val timelineArgs: TimelineArgs by args()
private val glideRequests by lazy {
@@ -391,6 +398,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))
@@ -521,7 +529,7 @@ class TimelineFragment @Inject constructor(
RoomDetailViewEvents.HideWaitingView -> vectorBaseActivity.hideWaitingView()
is RoomDetailViewEvents.RequestNativeWidgetPermission -> requestNativeWidgetPermission(it)
is RoomDetailViewEvents.OpenRoom -> handleOpenRoom(it)
- RoomDetailViewEvents.OpenInvitePeople -> navigator.openInviteUsersToRoom(requireContext(), timelineArgs.roomId)
+ RoomDetailViewEvents.OpenInvitePeople -> navigator.openInviteUsersToRoom(requireActivity(), timelineArgs.roomId)
RoomDetailViewEvents.OpenSetRoomAvatarDialog -> galleryOrCameraDialogHelper.show()
RoomDetailViewEvents.OpenRoomSettings -> handleOpenRoomSettings(RoomProfileActivity.EXTRA_DIRECT_ACCESS_ROOM_SETTINGS)
RoomDetailViewEvents.OpenRoomProfile -> handleOpenRoomSettings()
@@ -1042,18 +1050,18 @@ class TimelineFragment @Inject constructor(
}
private fun doJumpToBottom() {
- if (!timelineViewModel.timeline.isLive) {
+ if (timelineViewModel.timeline?.isLive == false) {
scrollOnNewMessageCallback.forceScrollOnNextUpdate()
- timelineViewModel.timeline.restartWithEventId(null)
+ timelineViewModel.timeline?.restartWithEventId(null)
} else {
- timelineViewModel.timeline.setTargetEventId(null)
+ timelineViewModel.timeline?.setTargetEventId(null)
layoutManager.scrollToPositionWithOffset(0, 0)
}
}
private fun reloadTimeline(rebuildTimeline: Boolean = false, invalidateEpoxy: Boolean = true) {
if (rebuildTimeline) {
- timelineViewModel.timeline.restartWithEventId(latestCurrentlyVisibleItem()?.eventId ?: timelineViewModel.timeline.getTargetEventId())
+ timelineViewModel.timeline?.let { it.restartWithEventId(latestCurrentlyVisibleItem()?.eventId ?: it.getTargetEventId()) }
}
if (invalidateEpoxy) {
timelineEventController.invalidateFullTimeline()
@@ -1392,12 +1400,12 @@ class TimelineFragment @Inject constructor(
}
}
- private fun handleSearchAction() {
+ private fun handleSearchAction() = withState(timelineViewModel) { state ->
navigator.openSearch(
context = requireContext(),
roomId = timelineArgs.roomId,
- roomDisplayName = timelineViewModel.getRoomSummary()?.displayName,
- roomAvatarUrl = timelineViewModel.getRoomSummary()?.avatarUrl
+ roomDisplayName = state.asyncRoomSummary()?.displayName,
+ roomAvatarUrl = state.asyncRoomSummary()?.avatarUrl
)
}
@@ -1912,6 +1920,10 @@ class TimelineFragment @Inject constructor(
override fun invalidate() = withState(timelineViewModel, messageComposerViewModel) { mainState, messageComposerState ->
invalidateOptionsMenu()
+ if (mainState.asyncRoomSummary is Fail) {
+ handleRoomSummaryFailure(mainState.asyncRoomSummary)
+ return@withState
+ }
val summary = mainState.asyncRoomSummary()
renderToolbar(summary)
renderTypingMessageNotification(summary, mainState)
@@ -1967,6 +1979,23 @@ class TimelineFragment @Inject constructor(
updateLiveLocationIndicator(mainState.isSharingLiveLocation)
}
+ private fun handleRoomSummaryFailure(asyncRoomSummary: Fail) {
+ views.roomNotFound.isVisible = true
+ views.roomNotFoundText.text = when (asyncRoomSummary.error) {
+ is RoomNotFound -> {
+ getString(
+ R.string.timeline_error_room_not_found,
+ if (vectorPreferences.developerMode()) {
+ "\nDeveloper info: $timelineArgs"
+ } else {
+ ""
+ }
+ )
+ }
+ else -> errorFormatter.toHumanReadable(asyncRoomSummary.error)
+ }
+ }
+
private fun updateLiveLocationIndicator(isSharingLiveLocation: Boolean) {
views.liveLocationStatusIndicator.isVisible = isSharingLiveLocation
}
@@ -2474,7 +2503,7 @@ class TimelineFragment @Inject constructor(
override fun onRoomCreateLinkClicked(url: String) {
viewLifecycleOwner.lifecycleScope.launchWhenResumed {
permalinkHandler
- .launch(requireContext(), url, object : NavigationInterceptor {
+ .launch(requireActivity(), url, object : NavigationInterceptor {
override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?, rootThreadEventId: String?): Boolean {
requireActivity().finish()
return false
@@ -2862,15 +2891,19 @@ class TimelineFragment @Inject constructor(
* Navigate to Threads timeline for the specified rootThreadEventId
* using the ThreadsActivity.
*/
- private fun navigateToThreadTimeline(rootThreadEventId: String, startsThread: Boolean = false, showKeyboard: Boolean = false) {
+ private fun navigateToThreadTimeline(
+ rootThreadEventId: String,
+ startsThread: Boolean = false,
+ showKeyboard: Boolean = false,
+ ) = withState(timelineViewModel) { state ->
analyticsTracker.capture(Interaction.Name.MobileRoomThreadSummaryItem.toAnalyticsInteraction())
context?.let {
val roomThreadDetailArgs = ThreadTimelineArgs(
startsThread = startsThread,
roomId = timelineArgs.roomId,
- displayName = timelineViewModel.getRoomSummary()?.displayName,
- avatarUrl = timelineViewModel.getRoomSummary()?.avatarUrl,
- roomEncryptionTrustLevel = timelineViewModel.getRoomSummary()?.roomEncryptionTrustLevel,
+ displayName = state.asyncRoomSummary()?.displayName,
+ avatarUrl = state.asyncRoomSummary()?.avatarUrl,
+ roomEncryptionTrustLevel = state.asyncRoomSummary()?.roomEncryptionTrustLevel,
rootThreadEventId = rootThreadEventId,
showKeyboard = showKeyboard
)
@@ -2901,14 +2934,14 @@ class TimelineFragment @Inject constructor(
* Navigate to Threads list for the current room
* using the ThreadsActivity.
*/
- private fun navigateToThreadList() {
+ private fun navigateToThreadList() = withState(timelineViewModel) { state ->
analyticsTracker.capture(Interaction.Name.MobileRoomThreadListButton.toAnalyticsInteraction())
context?.let {
val roomThreadDetailArgs = ThreadTimelineArgs(
roomId = timelineArgs.roomId,
- displayName = timelineViewModel.getRoomSummary()?.displayName,
- roomEncryptionTrustLevel = timelineViewModel.getRoomSummary()?.roomEncryptionTrustLevel,
- avatarUrl = timelineViewModel.getRoomSummary()?.avatarUrl
+ displayName = state.asyncRoomSummary()?.displayName,
+ roomEncryptionTrustLevel = state.asyncRoomSummary()?.roomEncryptionTrustLevel,
+ avatarUrl = state.asyncRoomSummary()?.avatarUrl
)
navigator.openThreadList(it, roomThreadDetailArgs)
}
@@ -3000,6 +3033,10 @@ class TimelineFragment @Inject constructor(
messageComposerViewModel.handle(MessageComposerAction.SendMessage(formattedContact, false))
}
+ override fun onAttachmentError(throwable: Throwable) {
+ showFailure(throwable)
+ }
+
private fun onViewWidgetsClicked() {
RoomWidgetsBottomSheet.newInstance()
.show(childFragmentManager, "ROOM_WIDGETS_BOTTOM_SHEET")
@@ -3034,7 +3071,7 @@ class TimelineFragment @Inject constructor(
val shouldStickToBottom = stickToBottom ||
(!enabled &&
!views.timelineRecyclerView.canScrollVertically(1) &&
- !timelineViewModel.timeline.hasMoreToLoad(Timeline.Direction.FORWARDS)
+ !timelineViewModel.timeline?.hasMoreToLoad(Timeline.Direction.FORWARDS).orFalse()
)
scrollOnNewMessageCallback.initialForceScroll = enabled
if (shouldStickToBottom) {
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 dce0c30d0c..59e6f97a3c 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
@@ -50,6 +50,7 @@ import im.vector.app.features.call.webrtc.WebRtcCallManager
import im.vector.app.features.createdirect.DirectRoomHelper
import im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy
import im.vector.app.features.crypto.verification.SupportedVerificationMethodsProvider
+import im.vector.app.features.home.room.detail.error.RoomNotFound
import im.vector.app.features.home.room.detail.location.RedactLiveLocationShareEventUseCase
import im.vector.app.features.home.room.detail.sticker.StickerPickerActionHandler
import im.vector.app.features.home.room.detail.timeline.factory.TimelineFactory
@@ -85,6 +86,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
@@ -95,6 +97,7 @@ 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.file.FileService
import org.matrix.android.sdk.api.session.getRoom
+import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.session.room.getStateEvent
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.api.session.room.location.UpdateLiveLocationShareResult
@@ -145,21 +148,16 @@ class TimelineViewModel @AssistedInject constructor(
private val cryptoConfig: CryptoConfig,
buildMeta: BuildMeta,
timelineFactory: TimelineFactory,
- spaceStateHandler: SpaceStateHandler,
+ private val spaceStateHandler: SpaceStateHandler,
) : VectorViewModel(initialState),
Timeline.Listener, ChatEffectManager.Delegate, CallProtocolsChecker.Listener, LocationSharingServiceConnection.Callback {
- private val room = session.getRoom(initialState.roomId)!!
- private val eventId = initialState.eventId ?: if (loadRoomAtFirstUnread() && initialState.rootThreadEventId == null) room.roomSummary()?.readMarkerId else null
+ private val room = session.getRoom(initialState.roomId)
+ private val eventId = initialState.eventId ?: if (loadRoomAtFirstUnread() && initialState.rootThreadEventId == null) room?.roomSummary()?.readMarkerId else null
private val invisibleEventsSource = BehaviorDataSource()
private val visibleEventsSource = BehaviorDataSource()
private var timelineEvents = MutableSharedFlow>(0)
- val timeline = timelineFactory.createTimeline(viewModelScope, room, eventId, initialState.rootThreadEventId).apply {
- // Target the event just below $eventId in case that it is the readMarkerId
- if (initialState.eventId == null && eventId != null) {
- getTargetEventOffset(-1)
- }
- }
+ val timeline: Timeline?
private val rmDimber = Dimber("ReadMarkerDbg", DbgUtil.DBG_READ_MARKER)
@@ -200,9 +198,25 @@ class TimelineViewModel @AssistedInject constructor(
}
init {
+ // This method will take care of a null room to update the state.
+ observeRoomSummary()
+ if (room == null) {
+ timeline = null
+ } else {
+ // Nominal case, we have retrieved the room.
+ timeline = timelineFactory.createTimeline(viewModelScope, room, eventId, initialState.rootThreadEventId).apply {
+ // Target the event just below $eventId in case that it is the readMarkerId
+ if (initialState.eventId == null && eventId != null) {
+ setTargetEventOffset(-1)
+ }
+ }
+ initSafe(room, timeline)
+ }
+ }
+
+ private fun initSafe(room: Room, timeline: Timeline) {
timeline.start(initialState.rootThreadEventId)
timeline.addListener(this)
- observeRoomSummary()
observeMembershipChanges()
observeSummaryState()
getUnreadState()
@@ -214,7 +228,6 @@ class TimelineViewModel @AssistedInject constructor(
observeActiveRoomWidgets()
observePowerLevel()
setupPreviewUrlObservers()
- room.getRoomSummaryLive()
viewModelScope.launch(Dispatchers.IO) {
if (loadRoomAtFirstUnread()) {
if (vectorPreferences.readReceiptFollowsReadMarker()) {
@@ -293,6 +306,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun prepareForEncryption() {
+ if (room == null) return
// check if there is not already a call made, or if there has been an error
if (prepareToEncrypt.shouldLoad) {
prepareToEncrypt = Loading()
@@ -309,6 +323,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun observePowerLevel() {
+ if (room == null) return
PowerLevelsFlowFactory(room).createFlow()
.onEach {
val powerLevelsHelper = PowerLevelsHelper(it)
@@ -359,6 +374,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun observeMyRoomMember() {
+ if (room == null) return
val queryParams = roomMemberQueryParams {
this.userId = QueryStringValue.Equals(session.myUserId, QueryStringValue.Case.SENSITIVE)
}
@@ -374,6 +390,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun setupPreviewUrlObservers() {
+ if (room == null) return
if (!vectorPreferences.showUrlPreviews()) {
return
}
@@ -402,6 +419,7 @@ class TimelineViewModel @AssistedInject constructor(
* This is a local implementation has nothing to do with APIs.
*/
private fun markThreadTimelineAsReadLocal() {
+ if (room == null) return
if (initialState.openAnonymously) {
return
}
@@ -416,6 +434,7 @@ class TimelineViewModel @AssistedInject constructor(
* Observe local unread threads.
*/
private fun observeLocalThreadNotifications() {
+ if (room == null) return
room.flow()
.liveLocalUnreadThreadList()
.execute {
@@ -433,10 +452,6 @@ class TimelineViewModel @AssistedInject constructor(
}
}
- fun getOtherUserIds() = room.roomSummary()?.otherMemberIds
-
- fun getRoomSummary() = room.roomSummary()
-
override fun handle(action: RoomDetailAction) {
when (action) {
is RoomDetailAction.ComposerFocusChange -> handleComposerFocusChange(action)
@@ -551,6 +566,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleSetNewAvatar(action: RoomDetailAction.SetAvatarAction) {
+ if (room == null) return
viewModelScope.launch(Dispatchers.IO) {
try {
room.stateService().updateAvatar(action.newAvatarUri, action.newAvatarFileName)
@@ -570,11 +586,13 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleJumpToReadReceipt(action: RoomDetailAction.JumpToReadReceipt) {
+ if (room == null) return
room.readService().getUserReadReceipt(action.userId)
?.let { handleNavigateToEvent(RoomDetailAction.NavigateToEvent(it, true)) }
}
private fun handleSendSticker(action: RoomDetailAction.SendSticker) {
+ if (room == null) return
val content = initialState.rootThreadEventId?.let {
action.stickerContent.copy(
relatesTo = RelationDefaultContent(
@@ -589,6 +607,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleStartCall(action: RoomDetailAction.StartCall) {
+ if (room == null) return
viewModelScope.launch {
room.roomSummary()?.otherMemberIds?.firstOrNull()?.let {
callManager.startOutgoingCall(room.roomId, it, action.isVideo)
@@ -634,7 +653,7 @@ class TimelineViewModel @AssistedInject constructor(
_viewEvents.post(RoomDetailViewEvents.ShowWaitingView)
viewModelScope.launch(Dispatchers.IO) {
try {
- val widget = jitsiService.createJitsiWidget(room.roomId, action.withVideo)
+ val widget = jitsiService.createJitsiWidget(initialState.roomId, action.withVideo)
_viewEvents.post(RoomDetailViewEvents.JoinJitsiConference(widget, action.withVideo))
} catch (failure: Throwable) {
_viewEvents.post(RoomDetailViewEvents.ShowMessage(stringProvider.getString(R.string.failed_to_add_widget)))
@@ -653,7 +672,7 @@ class TimelineViewModel @AssistedInject constructor(
} else {
_viewEvents.post(RoomDetailViewEvents.ShowWaitingView)
}
- session.widgetService().destroyRoomWidget(room.roomId, widgetId)
+ session.widgetService().destroyRoomWidget(initialState.roomId, widgetId)
// local echo
setState {
copy(
@@ -708,6 +727,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun stopTrackingUnreadMessages() {
+ if (room == null) return
if (trackUnreadMessages.getAndSet(false)) {
mostRecentDisplayedEvent?.root?.eventId?.also {
session.coroutineScope.launch(NonCancellable) {
@@ -728,10 +748,11 @@ class TimelineViewModel @AssistedInject constructor(
}
fun getMember(userId: String): RoomMemberSummary? {
- return room.membershipService().getRoomMember(userId)
+ return room?.membershipService()?.getRoomMember(userId)
}
private fun handleComposerFocusChange(action: RoomDetailAction.ComposerFocusChange) {
+ if (room == null) return
// Ensure outbound session keys
if (room.roomCryptoService().isEncrypted()) {
rawService.withElementWellKnown(viewModelScope, session.sessionParams) {
@@ -830,11 +851,12 @@ class TimelineViewModel @AssistedInject constructor(
// PRIVATE METHODS *****************************************************************************
private fun handleSendReaction(action: RoomDetailAction.SendReaction) {
+ if (room == null) return
room.relationService().sendReaction(action.targetEventId, action.reaction)
}
private fun handleRedactEvent(action: RoomDetailAction.RedactAction) {
- val event = room.getTimelineEvent(action.targetEventId) ?: return
+ val event = room?.getTimelineEvent(action.targetEventId) ?: return
if (event.isLiveLocation()) {
viewModelScope.launch {
redactLiveLocationShareEventUseCase.execute(event.root, room, action.reason)
@@ -845,6 +867,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleUndoReact(action: RoomDetailAction.UndoReaction) {
+ if (room == null) return
viewModelScope.launch {
tryOrNull {
room.relationService().undoReaction(action.targetEventId, action.reaction)
@@ -853,6 +876,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleUpdateQuickReaction(action: RoomDetailAction.UpdateQuickReactAction) {
+ if (room == null) return
if (action.add) {
room.relationService().sendReaction(action.targetEventId, action.selectedReaction)
} else {
@@ -865,6 +889,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleSendMedia(action: RoomDetailAction.SendMedia) {
+ if (room == null) return
room.sendService().sendMedias(
action.attachments,
action.compressBeforeSending,
@@ -874,6 +899,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleEventVisible(action: RoomDetailAction.TimelineEventTurnsVisible) {
+ if (room == null) return
viewModelScope.launch(Dispatchers.Default) {
if (action.event.root.sendState.isSent()) { // ignore pending/local events
visibleEventsSource.post(action)
@@ -901,6 +927,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleLoadMore(action: RoomDetailAction.LoadMoreTimelineEvents) {
+ if (timeline == null) return
timeline.paginate(action.direction, PAGINATION_COUNT)
}
@@ -908,7 +935,7 @@ class TimelineViewModel @AssistedInject constructor(
notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(initialState.roomId) }
viewModelScope.launch {
try {
- session.roomService().leaveRoom(room.roomId)
+ session.roomService().leaveRoom(initialState.roomId)
} catch (throwable: Throwable) {
_viewEvents.post(RoomDetailViewEvents.Failure(throwable, showInDialog = true))
}
@@ -919,7 +946,7 @@ class TimelineViewModel @AssistedInject constructor(
notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(initialState.roomId) }
viewModelScope.launch {
try {
- session.roomService().joinRoom(room.roomId)
+ session.roomService().joinRoom(initialState.roomId)
trackRoomJoined()
} catch (throwable: Throwable) {
_viewEvents.post(RoomDetailViewEvents.Failure(throwable, showInDialog = true))
@@ -928,6 +955,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun trackRoomJoined() {
+ if (room == null) return
val trigger = if (initialState.isInviteAlreadyAccepted) {
JoinedRoom.Trigger.Invite
} else {
@@ -985,6 +1013,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleNavigateToEvent(action: RoomDetailAction.NavigateToEvent) {
+ if (timeline == null) return
val targetEventId: String = action.eventId
val indexOfEvent = timeline.getIndexOfEvent(targetEventId)
if (indexOfEvent == null) {
@@ -998,6 +1027,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleResendEvent(action: RoomDetailAction.ResendMessage) {
+ if (room == null) return
val targetEventId = action.eventId
room.getTimelineEvent(targetEventId)?.let {
// State must be UNDELIVERED or Failed
@@ -1016,6 +1046,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleRemove(action: RoomDetailAction.RemoveFailedEcho) {
+ if (room == null) return
val targetEventId = action.eventId
room.getTimelineEvent(targetEventId)?.let {
// State must be UNDELIVERED or Failed
@@ -1028,6 +1059,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleCancel(action: RoomDetailAction.CancelSend) {
+ if (room == null) return
if (action.force) {
room.sendService().cancelSend(action.eventId)
return
@@ -1044,14 +1076,17 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleResendAll() {
+ if (room == null) return
room.sendService().resendAllFailedMessages()
}
private fun handleRemoveAllFailedMessages() {
+ if (room == null) return
room.sendService().cancelAllFailedMessages()
}
private fun observeEventDisplayedActions() {
+ if (room == null) return
// We are buffering scroll events for half a second
// and keep the most recent one to set the read receipt on.
@@ -1083,9 +1118,10 @@ class TimelineViewModel @AssistedInject constructor(
* Returns the index of event in the timeline.
* Returns Int.MAX_VALUE if not found
*/
- private fun TimelineEvent.indexOfEvent(): Int = timeline.getIndexOfEvent(eventId) ?: Int.MAX_VALUE
+ private fun TimelineEvent.indexOfEvent(): Int = timeline?.getIndexOfEvent(eventId) ?: Int.MAX_VALUE
private fun handleMarkAllAsRead() {
+ if (room == null) return
setState { copy(unreadState = UnreadState.HasNoUnread) }
viewModelScope.launch {
tryOrNullAnon { room.readService().markAsRead(ReadService.MarkAsReadParams.BOTH) }
@@ -1093,11 +1129,12 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleReportContent(action: RoomDetailAction.ReportContent) {
+ if (room == null) return
viewModelScope.launch {
val event = try {
room.reportingService().reportContent(action.eventId, -100, action.reason)
RoomDetailViewEvents.ActionSuccess(action)
- } catch (failure: Exception) {
+ } catch (failure: Throwable) {
RoomDetailViewEvents.ActionFailure(action, failure)
}
_viewEvents.post(event)
@@ -1121,11 +1158,11 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleAcceptVerification(action: RoomDetailAction.AcceptVerificationRequest) {
- Timber.v("## SAS handleAcceptVerification ${action.otherUserId}, roomId:${room.roomId}, txId:${action.transactionId}")
+ Timber.v("## SAS handleAcceptVerification ${action.otherUserId}, roomId:${initialState.roomId}, txId:${action.transactionId}")
if (session.cryptoService().verificationService().readyPendingVerificationInDMs(
supportedVerificationMethodsProvider.provide(),
action.otherUserId,
- room.roomId,
+ initialState.roomId,
action.transactionId
)) {
_viewEvents.post(RoomDetailViewEvents.ActionSuccess(action))
@@ -1138,7 +1175,7 @@ class TimelineViewModel @AssistedInject constructor(
session.cryptoService().verificationService().declineVerificationRequestInDMs(
action.otherUserId,
action.transactionId,
- room.roomId
+ initialState.roomId
)
}
@@ -1149,7 +1186,7 @@ class TimelineViewModel @AssistedInject constructor(
private fun handleResumeRequestVerification(action: RoomDetailAction.ResumeVerification) {
// Check if this request is still active and handled by me
- session.cryptoService().verificationService().getExistingVerificationRequestInRoom(room.roomId, action.transactionId)?.let {
+ session.cryptoService().verificationService().getExistingVerificationRequestInRoom(initialState.roomId, action.transactionId)?.let {
if (it.handledByOtherSession) return
if (!it.isFinished) {
_viewEvents.post(
@@ -1164,6 +1201,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleReRequestKeys(action: RoomDetailAction.ReRequestKeys) {
+ if (room == null) return
// Check if this request is still active and handled by me
room.getTimelineEvent(action.eventId)?.let {
session.cryptoService().reRequestRoomKeyForEvent(it.root)
@@ -1172,6 +1210,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleTapOnFailedToDecrypt(action: RoomDetailAction.TapOnFailedToDecrypt) {
+ if (room == null) return
room.getTimelineEvent(action.eventId)?.let {
val code = when (it.root.mCryptoError) {
MXCryptoError.ErrorType.KEYS_WITHHELD -> {
@@ -1185,6 +1224,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleVoteToPoll(action: RoomDetailAction.VoteToPoll) {
+ if (room == null) return
// Do not allow to vote unsent local echo of the poll event
if (LocalEcho.isLocalEchoId(action.eventId)) return
// Do not allow to vote the same option twice
@@ -1197,6 +1237,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun handleEndPoll(eventId: String) {
+ if (room == null) return
room.sendService().endPoll(eventId)
}
@@ -1216,7 +1257,7 @@ class TimelineViewModel @AssistedInject constructor(
private fun handleStopLiveLocationSharing() {
viewModelScope.launch {
- val result = stopLiveLocationShareUseCase.execute(room.roomId)
+ val result = stopLiveLocationShareUseCase.execute(initialState.roomId)
if (result is UpdateLiveLocationShareResult.Failure) {
_viewEvents.post(RoomDetailViewEvents.Failure(throwable = result.error, showInDialog = true))
}
@@ -1224,16 +1265,26 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun observeRoomSummary() {
- room.flow().liveRoomSummary()
- .unwrap()
- .execute { async ->
- copy(
- asyncRoomSummary = async
- )
- }
+ if (room == null) {
+ Timber.w("Warning, room with Id ${initialState.roomId} is not found.")
+ setState {
+ copy(
+ asyncRoomSummary = Fail(RoomNotFound())
+ )
+ }
+ } else {
+ room.flow().liveRoomSummary()
+ .unwrap()
+ .execute { async ->
+ copy(
+ asyncRoomSummary = async
+ )
+ }
+ }
}
private fun getUnreadState() {
+ if (room == null) return
combine(
timelineEvents,
room.flow().liveRoomSummary().unwrap()
@@ -1259,6 +1310,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun computeUnreadState(events: List, roomSummary: RoomSummary): UnreadState {
+ if (timeline == null) return UnreadState.Unknown
rmDimber.i{"computeUnreadState, empty = ${events.isEmpty()}, markerId = ${roomSummary.readMarkerId}"}
if (events.isEmpty()) return UnreadState.Unknown
val readMarkerIdSnapshot = roomSummary.readMarkerId ?: return UnreadState.Unknown
@@ -1315,6 +1367,7 @@ class TimelineViewModel @AssistedInject constructor(
}
private fun observeSummaryState() {
+ if (room == null) return
onAsync(RoomDetailViewState::asyncRoomSummary) { summary ->
setState {
val typingMessage = typingHelper.getTypingMessage(summary.typingUsers)
@@ -1332,17 +1385,33 @@ 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
*/
private var threadPermalinkHandled = false
private fun navigateToThreadEventIfNeeded(snapshot: List) {
+ if (timeline == null) return
if (eventId != null && initialState.rootThreadEventId != null) {
// When we have a permalink and we are in a thread timeline
if (snapshot.firstOrNull { it.eventId == eventId } != null && !threadPermalinkHandled) {
@@ -1366,6 +1435,7 @@ class TimelineViewModel @AssistedInject constructor(
}
override fun onTimelineFailure(throwable: Throwable) {
+ if (timeline == null) return
// If we have a critical timeline issue, we get back to live.
timeline.restartWithEventId(null)
_viewEvents.post(RoomDetailViewEvents.Failure(throwable))
@@ -1391,11 +1461,11 @@ class TimelineViewModel @AssistedInject constructor(
}
override fun onCleared() {
- timeline.dispose()
- timeline.removeAllListeners()
- decryptionFailureTracker.onTimeLineDisposed(room.roomId)
+ timeline?.dispose()
+ timeline?.removeAllListeners()
+ decryptionFailureTracker.onTimeLineDisposed(initialState.roomId)
if (vectorPreferences.sendTypingNotifs()) {
- room.typingService().userStopsTyping()
+ room?.typingService()?.userStopsTyping()
}
chatEffectManager.delegate = null
chatEffectManager.dispose()
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/AudioMessageHelper.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/AudioMessageHelper.kt
index 2e150daee6..a5e899c672 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/AudioMessageHelper.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/AudioMessageHelper.kt
@@ -48,7 +48,7 @@ class AudioMessageHelper @Inject constructor(
) {
private var mediaPlayer: MediaPlayer? = null
private var currentPlayingId: String? = null
- private var voiceRecorder: VoiceRecorder = voiceRecorderProvider.provideVoiceRecorder()
+ private val voiceRecorder: VoiceRecorder by lazy { voiceRecorderProvider.provideVoiceRecorder() }
private val amplitudeList = mutableListOf()
@@ -79,18 +79,19 @@ class AudioMessageHelper @Inject constructor(
}
fun stopRecording(): MultiPickerAudioType? {
- tryOrNull("Cannot stop media recording amplitude") {
- stopRecordingAmplitudes()
- }
val voiceMessageFile = tryOrNull("Cannot stop media recorder!") {
voiceRecorder.stopRecord()
voiceRecorder.getVoiceMessageFile()
}
- try {
+ tryOrNull("Cannot stop media recording amplitude") {
+ stopRecordingAmplitudes()
+ }
+
+ return try {
voiceMessageFile?.let {
val outputFileUri = FileProvider.getUriForFile(context, buildMeta.applicationId + ".fileProvider", it, "Voice message.${it.extension}")
- return outputFileUri
+ outputFileUri
.toMultiPickerAudioType(context)
?.apply {
waveform = if (amplitudeList.size < 50) {
@@ -99,10 +100,13 @@ class AudioMessageHelper @Inject constructor(
amplitudeList.chunked(amplitudeList.size / 50) { items -> items.maxOrNull() ?: 0 }
}
}
- } ?: return null
+ }
} catch (e: FileNotFoundException) {
Timber.e(e, "Cannot stop voice recording")
- return null
+ null
+ } catch (e: RuntimeException) {
+ Timber.e(e, "Error while retrieving metadata")
+ null
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt
index 96a65e0922..efe13c3653 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt
@@ -885,7 +885,11 @@ class MessageComposerViewModel @AssistedInject constructor(
}
private fun handlePlayOrPauseRecordingPlayback() {
- audioMessageHelper.startOrPauseRecordingPlayback()
+ try {
+ audioMessageHelper.startOrPauseRecordingPlayback()
+ } catch (failure: Throwable) {
+ _viewEvents.post(MessageComposerViewEvents.VoicePlaybackOrRecordingFailure(failure))
+ }
}
fun endAllVoiceActions(deleteRecord: Boolean = true) {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/error/RoomNotFound.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/error/RoomNotFound.kt
new file mode 100644
index 0000000000..3a8554ae4c
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/error/RoomNotFound.kt
@@ -0,0 +1,19 @@
+/*
+ * 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.detail.error
+
+class RoomNotFound : Throwable()
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/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt
index 55e6fbde62..ca30a0af34 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt
@@ -38,11 +38,13 @@ import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
import org.matrix.android.sdk.api.session.events.model.getMsgType
import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage
+import org.matrix.android.sdk.api.session.events.model.isSticker
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedContent
import org.matrix.android.sdk.api.session.room.model.RoomSummary
+import org.matrix.android.sdk.api.session.room.model.message.MessageType
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
@@ -173,7 +175,7 @@ class MessageInformationDataFactory @Inject constructor(
isLastFromThisSender = isLastFromThisSender,
e2eDecoration = e2eDecoration,
sendStateDecoration = sendStateDecoration,
- messageType = event.root.getMsgType()
+ messageType = if (event.root.isSticker()) { MessageType.MSGTYPE_STICKER_LOCAL } else { event.root.getMsgType() }
)
}
@@ -211,7 +213,7 @@ class MessageInformationDataFactory @Inject constructor(
.toModel()
?.deviceId
?.let { deviceId ->
- session.cryptoService().getDeviceInfo(event.root.senderId ?: "", deviceId)
+ session.cryptoService().getCryptoDeviceInfo(event.root.senderId ?: "", deviceId)
}
when {
sendingDevice == null -> {
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 21a79c4631..17db8b1f3b 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
@@ -230,8 +230,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/detail/timeline/item/CallTileTimelineItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/CallTileTimelineItem.kt
index 58d267fb0e..86aada82ac 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/CallTileTimelineItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/CallTileTimelineItem.kt
@@ -246,7 +246,7 @@ abstract class CallTileTimelineItem : AbsBaseMessageItem(R.layout.item_tim
)
companion object {
- private const val STUB_ID = R.id.messageContentDefaultStub
+ private val STUB_ID = R.id.messageContentDefaultStub
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt
index e1022fd5ed..1fc2156eef 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt
@@ -272,7 +272,7 @@ abstract class MergedRoomCreationItem : BasedMergedItem() {
}
companion object {
- private const val STUB_ID = R.id.messageContentAudioStub
+ private val STUB_ID = R.id.messageContentAudioStub
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageFileItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageFileItem.kt
index f51eaa8fa7..fbc7a778af 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageFileItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageFileItem.kt
@@ -139,6 +139,6 @@ abstract class MessageFileItem : AbsMessageItem() {
}
companion object {
- private const val STUB_ID = R.id.messageContentFileStub
+ private val STUB_ID = R.id.messageContentFileStub
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt
index 6786f8948e..5b2228f2f8 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt
@@ -74,7 +74,7 @@ abstract class MessageImageVideoItem : AbsMessageItem() {
}
companion object {
- private const val STUB_ID = R.id.messageContentTextStub
+ private val STUB_ID = R.id.messageContentTextStub
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageVoiceItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageVoiceItem.kt
index 990a8018e6..acc0a29a66 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageVoiceItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageVoiceItem.kt
@@ -187,6 +187,6 @@ abstract class MessageVoiceItem : AbsMessageItem() {
}
companion object {
- private const val STUB_ID = R.id.messageContentVoiceStub
+ private val STUB_ID = R.id.messageContentVoiceStub
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/NoticeItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/NoticeItem.kt
index fa73fe19b1..6139dd2a79 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/NoticeItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/NoticeItem.kt
@@ -87,6 +87,6 @@ abstract class NoticeItem : BaseEventItem(R.layout.item_timel
)
companion object {
- private const val STUB_ID = R.id.messageContentNoticeStub
+ private val STUB_ID = R.id.messageContentNoticeStub
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/PollItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/PollItem.kt
index 5dd721b007..54be4092ed 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/PollItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/PollItem.kt
@@ -92,6 +92,6 @@ abstract class PollItem : AbsMessageItem() {
}
companion object {
- private const val STUB_ID = R.id.messageContentPollStub
+ private val STUB_ID = R.id.messageContentPollStub
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/RedactedMessageItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/RedactedMessageItem.kt
index 057a9bad0e..f04d681862 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/RedactedMessageItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/RedactedMessageItem.kt
@@ -29,6 +29,6 @@ abstract class RedactedMessageItem : AbsMessageItem(
class Holder : AbsMessageItem.Holder(STUB_ID)
companion object {
- private const val STUB_ID = R.id.messageContentRedactedStub
+ private val STUB_ID = R.id.messageContentRedactedStub
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/StatusTileTimelineItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/StatusTileTimelineItem.kt
index c4dd4bedeb..1e5bb0521d 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/StatusTileTimelineItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/StatusTileTimelineItem.kt
@@ -76,7 +76,7 @@ abstract class StatusTileTimelineItem : AbsBaseMessageItem(R.la
val expandedArrowDrawable = ContextCompat.getDrawable(holder.rootView.context, expandedArrowDrawableRes)?.also {
DrawableCompat.setTint(it, tintColor)
}
- holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted, unreadMessages, markedUnread))
+ holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State.Count(unreadNotificationCount, showHighlighted, unreadMessages, markedUnread))
holder.titleView.text = title
//holder.counterView.text = itemCount.takeIf { it > 0 }?.toString().orEmpty()
//holder.counterView.setCompoundDrawablesWithIntrinsicBounds(null, null, expandedArrowDrawable, null)
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 e6df436dae..ed0d35494d 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
@@ -38,6 +38,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 de.spiritcroc.matrixsdk.util.DbgUtil
import de.spiritcroc.matrixsdk.util.Dimber
import im.vector.app.R
@@ -79,18 +80,20 @@ data class RoomListParams(
val explicitSpaceId: String? = SPACE_ID_FOLLOW_APP
) : Parcelable
-class RoomListFragment @Inject constructor(
- private val pagedControllerFactory: RoomSummaryPagedControllerFactory,
- private val notificationDrawerManager: NotificationDrawerManager,
- private val vectorPreferences: VectorPreferences,
- 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 vectorPreferences: VectorPreferences
+ @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()
@@ -265,7 +268,7 @@ class RoomListFragment @Inject constructor(
}
private fun handleShowMxToLink(link: String) {
- navigator.openMatrixToBottomSheet(requireContext(), link, OriginOfMatrixTo.ROOM_LIST)
+ navigator.openMatrixToBottomSheet(requireActivity(), link, OriginOfMatrixTo.ROOM_LIST)
}
override fun onDestroyView() {
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 2a84f6802f..4804025487 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
@@ -290,7 +290,7 @@ class RoomListViewModel @AssistedInject constructor(
viewModelScope.launch {
try {
room.roomPushRuleService().setRoomNotificationState(action.notificationState)
- } catch (failure: Exception) {
+ } catch (failure: Throwable) {
_viewEvents.post(RoomListViewEvents.Failure(failure))
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItem.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItem.kt
index 6db3da295f..c4c49b8f19 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItem.kt
@@ -119,7 +119,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel(R.layo
itemLongClickListener?.onLongClick(it) ?: false
}
holder.titleView.text = matrixItem.getBestName()
- holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted, unreadCount ?: 0, markedUnread))
+ holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State.Count(unreadNotificationCount, showHighlighted, unreadCount ?: 0, markedUnread))
holder.unreadIndentIndicator.isVisible = hasUnreadMessage
// Mirror unreadCounterBadgeView colors
holder.unreadIndentIndicator.setBackgroundColor(
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/SectionHeaderAdapter.kt b/vector/src/main/java/im/vector/app/features/home/room/list/SectionHeaderAdapter.kt
index c5466eb353..1de5d6bde8 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/SectionHeaderAdapter.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/SectionHeaderAdapter.kt
@@ -102,7 +102,9 @@ class SectionHeaderAdapter constructor(
binding.roomCategoryTitleView.setCompoundDrawablesWithIntrinsicBounds(null, null, collapsableArrowDrawable, null)
//binding.roomCategoryCounterView.setCompoundDrawablesWithIntrinsicBounds(null, null, collapsableArrowDrawable, null)
//binding.roomCategoryCounterView.text = roomsSectionData.itemCount.takeIf { it > 0 }?.toString().orEmpty()
- binding.roomCategoryUnreadCounterBadgeView.render(UnreadCounterBadgeView.State(roomsSectionData.notificationCount, roomsSectionData.isHighlighted, roomsSectionData.unread, roomsSectionData.markedUnread))
+ binding.roomCategoryUnreadCounterBadgeView.render(
+ UnreadCounterBadgeView.State.Count(roomsSectionData.notificationCount, roomsSectionData.isHighlighted, roomsSectionData.unread, roomsSectionData.markedUnread)
+ )
}
companion object {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/UnreadCounterBadgeView.kt b/vector/src/main/java/im/vector/app/features/home/room/list/UnreadCounterBadgeView.kt
index e78dfa0902..6fa052f836 100755
--- a/vector/src/main/java/im/vector/app/features/home/room/list/UnreadCounterBadgeView.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/UnreadCounterBadgeView.kt
@@ -19,8 +19,9 @@ import android.content.Context
import android.util.AttributeSet
import android.view.View
import com.google.android.material.textview.MaterialTextView
+import dagger.hilt.EntryPoints
import im.vector.app.R
-import im.vector.app.VectorApplication
+import im.vector.app.core.di.SingletonEntryPoint
class UnreadCounterBadgeView : MaterialTextView {
@@ -30,37 +31,54 @@ class UnreadCounterBadgeView : MaterialTextView {
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
- private val vectorPreferences = (context.applicationContext as VectorApplication).vectorPreferences
+ private val vectorPreferences = EntryPoints.get(context.applicationContext, SingletonEntryPoint::class.java).vectorPreferences()
fun render(state: State) {
- if (state.count == 0 && !state.markedUnread && (state.unread == 0 || !vectorPreferences.shouldShowUnimportantCounterBadge())) {
- visibility = View.INVISIBLE
- } else {
- visibility = View.VISIBLE
- val bgRes = if (state.count > 0 || state.markedUnread) {
- if (state.highlighted) {
- R.drawable.bg_unread_highlight
- } else {
- R.drawable.bg_unread_notification
- }
- } else {
- R.drawable.bg_unread_unimportant
- }
- setBackgroundResource(bgRes)
- text = if (state.count == 0 && state.markedUnread)
- // Centered star (instead of "*")
- //"\u2217"
- "!"
- else
- RoomSummaryFormatter.formatUnreadMessagesCounter(if (state.count > 0) state.count else state.unread)
+ when (state) {
+ is State.Count -> renderAsCount(state)
+ is State.Text -> renderAsText(state)
}
}
- data class State(
- val count: Int,
- val highlighted: Boolean,
- // SC addition
- val unread: Int,
- val markedUnread: Boolean
- )
+ private fun renderAsCount(state: State.Count) {
+ val view = this
+
+ with(state) {
+ if (count == 0 && !markedUnread && (unread == 0 || !vectorPreferences.shouldShowUnimportantCounterBadge())) {
+ visibility = View.INVISIBLE
+ } else {
+ visibility = View.VISIBLE
+ val bgRes = if (count > 0 || markedUnread) {
+ if (highlighted) {
+ R.drawable.bg_unread_highlight
+ } else {
+ R.drawable.bg_unread_notification
+ }
+ } else {
+ R.drawable.bg_unread_unimportant
+ }
+ setBackgroundResource(bgRes)
+ view.text = if (count == 0 && markedUnread)
+ "!"
+ else
+ RoomSummaryFormatter.formatUnreadMessagesCounter(if (count > 0) count else unread)
+ }
+ }
+ }
+
+ private fun renderAsText(state: State.Text) {
+ val view = this
+
+ with(state) {
+ visibility = View.VISIBLE
+ val bgRes = if (highlighted) R.drawable.bg_unread_highlight else R.drawable.bg_unread_notification
+ setBackgroundResource(bgRes)
+ view.text = text
+ }
+ }
+
+ sealed class State {
+ data class Count(val count: Int, val highlighted: Boolean, val unread: Int, val markedUnread: Boolean) : State()
+ data class Text(val text: String, val highlighted: Boolean) : State()
+ }
}
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 abb7e4eaea..09615a4574 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,12 +45,11 @@ 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
@@ -57,25 +58,23 @@ 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 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)
}
@@ -86,17 +85,10 @@ class HomeRoomListFragment @Inject constructor(
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)
@@ -112,12 +104,6 @@ class HomeRoomListFragment @Inject constructor(
}
}
- private fun handleSharedAction(action: RoomListSharedAction) {
- when (action) {
- RoomListSharedAction.CloseBottomSheet -> spaceListBottomSheet.dismiss()
- }
- }
-
private fun handleQuickActions(quickAction: RoomListQuickActionsSharedAction) {
when (quickAction) {
is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> {
@@ -186,42 +172,6 @@ class HomeRoomListFragment @Inject constructor(
})
}
- 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
}
@@ -262,11 +212,17 @@ class HomeRoomListFragment @Inject constructor(
).also { controller ->
controller.listener = this
controller.onFilterChanged = ::onRoomFilterChanged
+ roomListViewModel.emptyStateFlow.onEach { emptyStateOptional ->
+ controller.submitEmptyStateData(emptyStateOptional.getOrNull())
+ }.launchIn(lifecycleScope)
section.filtersData.onEach {
controller.submitFiltersData(it.getOrNull())
}.launchIn(lifecycleScope)
section.list.observe(viewLifecycleOwner) { list ->
controller.submitList(list)
+ if (list.isEmpty()) {
+ controller.requestForcedModelBuild()
+ }
}
}.adapter
}
@@ -276,9 +232,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))
}
@@ -295,6 +261,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 a4b018bb40..29976e83f0 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,17 +16,22 @@
package im.vector.app.features.home.room.list.home
+import android.widget.ImageView
+import androidx.lifecycle.map
import androidx.paging.PagedList
import arrow.core.toOption
import com.airbnb.mvrx.MavericksViewModelFactory
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import im.vector.app.R
import im.vector.app.SpaceStateHandler
import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.StateView
import im.vector.app.core.platform.VectorViewModel
+import im.vector.app.core.resources.DrawableProvider
+import im.vector.app.core.resources.StringProvider
import im.vector.app.features.home.room.list.home.filter.HomeRoomFilter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -35,6 +40,7 @@ import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -51,6 +57,7 @@ import org.matrix.android.sdk.api.session.room.RoomSortOrder
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
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
@@ -62,6 +69,8 @@ class HomeRoomListViewModel @AssistedInject constructor(
private val session: Session,
private val spaceStateHandler: SpaceStateHandler,
private val preferencesStore: HomeLayoutPreferencesStore,
+ private val stringProvider: StringProvider,
+ private val drawableProvider: DrawableProvider,
) : VectorViewModel(initialState) {
@AssistedFactory
@@ -81,6 +90,10 @@ class HomeRoomListViewModel @AssistedInject constructor(
private val _sections = MutableSharedFlow>(replay = 1)
val sections = _sections.asSharedFlow()
+ private var currentFilter: HomeRoomFilter = HomeRoomFilter.ALL
+ private val _emptyStateFlow = MutableSharedFlow>(replay = 1)
+ val emptyStateFlow = _emptyStateFlow.asSharedFlow()
+
private var filteredPagedRoomSummariesLive: UpdatableLivePageResult? = null
init {
@@ -100,14 +113,15 @@ class HomeRoomListViewModel @AssistedInject constructor(
private fun configureSections() = viewModelScope.launch {
val newSections = mutableSetOf()
+ newSections.add(getInvitesCountSection())
val areSettingsEnabled = preferencesStore.areRecentsEnabledFlow.first()
-
if (areSettingsEnabled) {
newSections.add(getRecentRoomsSection())
}
newSections.add(getFilteredRoomsSection())
+ emitEmptyState()
_sections.emit(newSections)
setState {
@@ -127,6 +141,19 @@ class HomeRoomListViewModel @AssistedInject constructor(
)
}
+ 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)
@@ -157,6 +184,7 @@ class HomeRoomListViewModel @AssistedInject constructor(
liveResults.queryParams = liveResults.queryParams.copy(
spaceFilter = selectedSpace?.roomId.toActiveSpaceOrNoFilter()
)
+ emitEmptyState()
}.launchIn(viewModelScope)
return HomeRoomSection.RoomSummaryData(
@@ -165,27 +193,48 @@ class HomeRoomListViewModel @AssistedInject constructor(
)
}
+ private fun emitEmptyState() {
+ viewModelScope.launch {
+ val emptyState = getEmptyStateData(currentFilter, spaceStateHandler.getCurrentSpace())
+ _emptyStateFlow.emit(Optional.from(emptyState))
+ }
+ }
+
private fun getFiltersDataFlow(): SharedFlow>> {
val flow = MutableSharedFlow>>(replay = 1)
- val favouritesFlow = session.flow()
- .liveRoomSummaries(
- RoomSummaryQueryParams.Builder().also { builder ->
- builder.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
- }.build()
- )
- .map { it.isNotEmpty() }
+ val spaceFLow = spaceStateHandler.getSelectedSpaceFlow()
.distinctUntilChanged()
+ .onStart {
+ emit(spaceStateHandler.getCurrentSpace().toOption())
+ }
- val dmsFLow = session.flow()
- .liveRoomSummaries(
- RoomSummaryQueryParams.Builder().also { builder ->
- builder.memberships = listOf(Membership.JOIN)
- builder.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
- }.build()
- )
- .map { it.isNotEmpty() }
- .distinctUntilChanged()
+ val favouritesFlow =
+ spaceFLow.flatMapLatest { selectedSpace ->
+ session.flow()
+ .liveRoomSummaries(
+ RoomSummaryQueryParams.Builder().also { builder ->
+ builder.spaceFilter = selectedSpace.orNull()?.roomId.toActiveSpaceOrNoFilter()
+ builder.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
+ }.build()
+ )
+ }
+ .map { it.isNotEmpty() }
+ .distinctUntilChanged()
+
+ val dmsFLow =
+ spaceFLow.flatMapLatest { selectedSpace ->
+ session.flow()
+ .liveRoomSummaries(
+ RoomSummaryQueryParams.Builder().also { builder ->
+ builder.spaceFilter = selectedSpace.orNull()?.roomId.toActiveSpaceOrNoFilter()
+ builder.memberships = listOf(Membership.JOIN)
+ builder.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
+ }.build()
+ )
+ }
+ .map { it.isNotEmpty() }
+ .distinctUntilChanged()
combine(favouritesFlow, dmsFLow, preferencesStore.areFiltersEnabledFlow) { hasFavourite, hasDm, areFiltersEnabled ->
Triple(hasFavourite, hasDm, areFiltersEnabled)
@@ -236,6 +285,38 @@ class HomeRoomListViewModel @AssistedInject constructor(
}
}
+ private fun getEmptyStateData(filter: HomeRoomFilter, selectedSpace: RoomSummary?): StateView.State.Empty? {
+ return when (filter) {
+ HomeRoomFilter.ALL ->
+ if (selectedSpace != null) {
+ StateView.State.Empty(
+ title = stringProvider.getString(R.string.home_empty_space_no_rooms_title, selectedSpace.displayName),
+ message = stringProvider.getString(R.string.home_empty_space_no_rooms_message),
+ image = drawableProvider.getDrawable(R.drawable.ill_empty_space),
+ isBigImage = true
+ )
+ } else {
+ val userName = session.userService().getUser(session.myUserId)?.displayName ?: ""
+ StateView.State.Empty(
+ title = stringProvider.getString(R.string.home_empty_no_rooms_title, userName),
+ message = stringProvider.getString(R.string.home_empty_no_rooms_message),
+ image = drawableProvider.getDrawable(R.drawable.ill_empty_all_chats),
+ isBigImage = true
+ )
+ }
+ HomeRoomFilter.UNREADS ->
+ StateView.State.Empty(
+ title = stringProvider.getString(R.string.home_empty_no_unreads_title),
+ message = stringProvider.getString(R.string.home_empty_no_unreads_message),
+ image = drawableProvider.getDrawable(R.drawable.ill_empty_unreads),
+ isBigImage = true,
+ imageScaleType = ImageView.ScaleType.CENTER_INSIDE
+ )
+ else ->
+ null
+ }
+ }
+
override fun handle(action: HomeRoomListAction) {
when (action) {
is HomeRoomListAction.SelectRoom -> handleSelectRoom(action)
@@ -248,9 +329,12 @@ class HomeRoomListViewModel @AssistedInject constructor(
}
private fun handleChangeRoomFilter(action: HomeRoomListAction.ChangeRoomFilter) {
+ currentFilter = action.filter
filteredPagedRoomSummariesLive?.let { liveResults ->
liveResults.queryParams = getFilteredQueryParams(action.filter, liveResults.queryParams)
}
+
+ emitEmptyState()
}
fun isPublicRoom(roomId: String): Boolean {
@@ -289,7 +373,7 @@ class HomeRoomListViewModel @AssistedInject constructor(
viewModelScope.launch {
try {
room.roomPushRuleService().setRoomNotificationState(action.notificationState)
- } catch (failure: Exception) {
+ } catch (failure: Throwable) {
_viewEvents.post(HomeRoomListViewEvents.Failure(failure))
}
}
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 74ec46d6b7..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
@@ -32,4 +32,8 @@ sealed class 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/RoomListEmptyItem.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/RoomListEmptyItem.kt
new file mode 100644
index 0000000000..f7b3262529
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/RoomListEmptyItem.kt
@@ -0,0 +1,40 @@
+/*
+ * 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 com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.app.R
+import im.vector.app.core.epoxy.VectorEpoxyHolder
+import im.vector.app.core.epoxy.VectorEpoxyModel
+import im.vector.app.core.platform.StateView
+
+@EpoxyModelClass
+abstract class RoomListEmptyItem : VectorEpoxyModel(R.layout.item_state_view) {
+
+ @EpoxyAttribute
+ lateinit var emptyData: StateView.State.Empty
+
+ override fun bind(holder: Holder) {
+ super.bind(holder)
+ holder.stateView.state = emptyData
+ }
+
+ class Holder : VectorEpoxyHolder() {
+ val stateView by bind(R.id.stateView)
+ }
+}
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 2d673bc089..789c9e9985 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
@@ -18,11 +18,13 @@ package im.vector.app.features.home.room.list.home.filter
import com.airbnb.epoxy.EpoxyModel
import com.airbnb.epoxy.paging.PagedListEpoxyController
+import im.vector.app.core.platform.StateView
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 im.vector.app.features.home.room.list.home.roomListEmptyItem
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.model.RoomSummary
@@ -44,6 +46,8 @@ class HomeFilteredRoomsController(
var onFilterChanged: ((HomeRoomFilter) -> Unit)? = null
private var filtersData: List? = null
+ private var emptyStateData: StateView.State.Empty? = null
+ private var currentState: StateView.State = StateView.State.Content
override fun addModels(models: List>) {
val host = this
@@ -54,14 +58,29 @@ class HomeFilteredRoomsController(
onFilterChangedListener(host.onFilterChanged)
}
}
- super.addModels(models)
+
+ if (models.isEmpty() && emptyStateData != null) {
+ emptyStateData?.let { emptyState ->
+ roomListEmptyItem {
+ id("state_item")
+ emptyData(emptyState)
+ }
+ currentState = emptyState
+ }
+ } else {
+ currentState = StateView.State.Content
+ super.addModels(models)
+ }
+ }
+
+ fun submitEmptyStateData(state: StateView.State.Empty?) {
+ this.emptyStateData = state
}
fun submitFiltersData(data: List?) {
this.filtersData = data
requestForcedModelBuild()
}
-
override fun buildItemModel(currentPosition: Int, item: RoomSummary?): EpoxyModel<*> {
item ?: return RoomSummaryItemPlaceHolder_().apply { id(currentPosition) }
return roomSummaryItemFactory.create(item, roomChangeMembershipStates.orEmpty(), emptySet(), RoomListDisplayMode.ROOMS, listener)
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..7ef41060f8
--- /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.Count(invitesCount, true, 0, false))
+ }
+
+ class Holder : VectorEpoxyHolder() {
+ val unreadCounterBadgeView by bind(R.id.invites_count_badge)
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesAction.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesAction.kt
new file mode 100644
index 0000000000..d96e0f01de
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesAction.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.VectorViewModelAction
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
+
+sealed class InvitesAction : VectorViewModelAction {
+ data class SelectRoom(val roomSummary: RoomSummary) : InvitesAction()
+ 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..0dbc1b8f34
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesFragment.kt
@@ -0,0 +1,132 @@
+/*
+ * 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 androidx.lifecycle.lifecycleScope
+import com.airbnb.mvrx.fragmentViewModel
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.core.extensions.configureWith
+import im.vector.app.core.platform.StateView
+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 kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+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.invitesStateView.contentView = views.invitesRecycler
+
+ 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, it.isInviteAlreadySelected)
+ }
+ }
+
+ viewModel.invites.onEach {
+ when (it) {
+ is InvitesContentState.Content -> {
+ views.invitesStateView.state = StateView.State.Content
+ controller.submitList(it.content)
+ }
+ is InvitesContentState.Empty -> {
+ views.invitesStateView.state = StateView.State.Empty(
+ title = it.title,
+ image = it.image,
+ message = it.message
+ )
+ }
+ is InvitesContentState.Error -> {
+ when (views.invitesStateView.state) {
+ StateView.State.Content -> showErrorInSnackbar(it.throwable)
+ else -> views.invitesStateView.state = StateView.State.Error(it.throwable.message)
+ }
+ }
+ InvitesContentState.Loading -> views.invitesStateView.state = StateView.State.Loading
+ }
+ }.launchIn(viewLifecycleOwner.lifecycleScope)
+ }
+
+ private fun handleOpenRoom(
+ roomSummary: RoomSummary,
+ shouldCloseInviteView: Boolean,
+ isInviteAlreadyAccepted: Boolean,
+ ) {
+ navigator.openRoom(
+ context = requireActivity(),
+ roomId = roomSummary.roomId,
+ isInviteAlreadyAccepted = isInviteAlreadyAccepted,
+ trigger = ViewRoom.Trigger.RoomList // #6508
+ )
+ if (shouldCloseInviteView) {
+ requireActivity().finish()
+ }
+ }
+
+ 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) {
+ viewModel.handle(InvitesAction.SelectRoom(room))
+ }
+
+ 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..69749b8c48
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewEvents.kt
@@ -0,0 +1,29 @@
+/*
+ * 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,
+ val isInviteAlreadySelected: Boolean,
+ ) : 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..8ef7c2bfef
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewModel.kt
@@ -0,0 +1,176 @@
+/*
+ * 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.asFlow
+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.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
+import im.vector.app.core.platform.VectorViewModel
+import im.vector.app.core.resources.DrawableProvider
+import im.vector.app.core.resources.StringProvider
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.asSharedFlow
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.launch
+import org.matrix.android.sdk.api.extensions.orFalse
+import org.matrix.android.sdk.api.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,
+ private val stringProvider: StringProvider,
+ private val drawableProvider: DrawableProvider
+) : 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()
+
+ private val _invites = MutableSharedFlow(replay = 1)
+ val invites = _invites.asSharedFlow()
+
+ private var invitesCount = -1
+
+ init {
+ observeInvites()
+ }
+
+ override fun handle(action: InvitesAction) {
+ when (action) {
+ is InvitesAction.SelectRoom -> handleSelectRoom(action)
+ is InvitesAction.AcceptInvitation -> handleAcceptInvitation(action)
+ is InvitesAction.RejectInvitation -> handleRejectInvitation(action)
+ }
+ }
+
+ private fun handleSelectRoom(action: InvitesAction.SelectRoom) {
+ _viewEvents.post(InvitesViewEvents.OpenRoom(
+ roomSummary = action.roomSummary,
+ shouldCloseInviteView = false,
+ isInviteAlreadySelected = false,
+ ))
+ }
+
+ 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
+ }
+
+ 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...
+ } 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 = invitesCount == 1
+
+ // quick echo
+ setState {
+ copy(
+ roomMembershipChanges = roomMembershipChanges.mapValues {
+ if (it.key == roomId) {
+ ChangeMembershipState.Joining
+ } else {
+ it.value
+ }
+ }
+ )
+ }
+
+ _viewEvents.post(InvitesViewEvents.OpenRoom(action.roomSummary, shouldCloseInviteView, isInviteAlreadySelected = true))
+ }
+
+ 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
+ )
+
+ pagedList.asFlow()
+ .map {
+ if (it.isEmpty()) {
+ InvitesContentState.Empty(
+ title = stringProvider.getString(R.string.invites_empty_title),
+ image = drawableProvider.getDrawable(R.drawable.ic_invites_empty),
+ message = stringProvider.getString(R.string.invites_empty_message)
+ )
+ } else {
+ invitesCount = it.loadedCount
+ InvitesContentState.Content(it)
+ }
+ }
+ .catch {
+ emit(InvitesContentState.Error(it))
+ }
+ .onStart {
+ emit(InvitesContentState.Loading)
+ }.onEach {
+ _invites.emit(it)
+ }.launchIn(viewModelScope)
+ }
+}
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..2f82c3fe76
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewState.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.graphics.drawable.Drawable
+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 roomMembershipChanges: Map = emptyMap(),
+) : MavericksState
+
+sealed interface InvitesContentState {
+ object Loading : InvitesContentState
+ data class Empty(
+ val title: CharSequence,
+ val image: Drawable?,
+ val message: CharSequence
+ ) : InvitesContentState
+
+ data class Content(val content: PagedList) : InvitesContentState
+ data class Error(val throwable: Throwable) : InvitesContentState
+}
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 b26b610eac..8b9f107ccb 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
@@ -23,6 +23,8 @@ import com.airbnb.epoxy.CarouselModelBuilder
import com.airbnb.epoxy.EpoxyController
import com.airbnb.epoxy.EpoxyModel
import com.airbnb.epoxy.carousel
+import com.google.android.material.color.MaterialColors
+import im.vector.app.R
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.list.RoomListListener
import org.matrix.android.sdk.api.session.room.model.RoomSummary
@@ -39,13 +41,13 @@ class RecentRoomCarouselController @Inject constructor(
private val hPadding = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
- 16f,
+ 4f,
resources.displayMetrics
).toInt()
- private val itemSpacing = TypedValue.applyDimension(
+ private val topPadding = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
- 24f,
+ 12f,
resources.displayMetrics
).toInt()
@@ -61,11 +63,16 @@ class RecentRoomCarouselController @Inject constructor(
id("recents_carousel")
padding(Carousel.Padding(
host.hPadding,
- 0,
+ host.topPadding,
host.hPadding,
0,
- host.itemSpacing)
+ 0,
)
+ )
+ onBind { _, view, _ ->
+ val colorSurface = MaterialColors.getColor(view, R.attr.vctr_toolbar_background)
+ view.setBackgroundColor(colorSurface)
+ }
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/list/home/recent/RecentRoomItem.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/recent/RecentRoomItem.kt
index e0610ee031..e691d0f61f 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/recent/RecentRoomItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/recent/RecentRoomItem.kt
@@ -60,7 +60,7 @@ abstract class RecentRoomItem : VectorEpoxyModel(R.layout
avatarRenderer.render(matrixItem, holder.avatarImageView)
holder.avatarImageView.contentDescription = matrixItem.getBestName()
- holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted, unreadCount, markedUnread))
+ holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State.Count(unreadNotificationCount, showHighlighted, unreadCount, markedUnread))
holder.title.text = matrixItem.getBestName()
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseCarouselData.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseCarouselData.kt
new file mode 100644
index 0000000000..22431b0bf9
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseCarouselData.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.release
+
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+
+class ReleaseCarouselData(
+ val items: List-
+) {
+ data class Item(
+ @StringRes val title: Int,
+ @StringRes val body: Int,
+ @DrawableRes val image: Int,
+ )
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseCarouselItem.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseCarouselItem.kt
new file mode 100644
index 0000000000..49eb0761f7
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseCarouselItem.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.release
+
+import android.widget.ImageView
+import android.widget.TextView
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.app.R
+import im.vector.app.core.epoxy.VectorEpoxyHolder
+import im.vector.app.core.epoxy.VectorEpoxyModel
+
+@EpoxyModelClass
+abstract class ReleaseCarouselItem : VectorEpoxyModel(R.layout.item_release_carousel) {
+
+ @EpoxyAttribute
+ lateinit var item: ReleaseCarouselData.Item
+
+ override fun bind(holder: Holder) {
+ super.bind(holder)
+
+ holder.image.setImageResource(item.image)
+ holder.title.setText(item.title)
+ holder.body.setText(item.body)
+ }
+
+ class Holder : VectorEpoxyHolder() {
+ val image by bind(R.id.carousel_item_image)
+ val title by bind(R.id.carousel_item_title)
+ val body by bind(R.id.carousel_item_body)
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesAction.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesAction.kt
new file mode 100644
index 0000000000..7a66d00589
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesAction.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.release
+
+import im.vector.app.core.platform.VectorViewModelAction
+
+sealed class ReleaseNotesAction : VectorViewModelAction {
+ data class NextPressed(
+ val isLastItemSelected: Boolean = false
+ ) : ReleaseNotesAction()
+ data class PageSelected(
+ val selectedPageIndex: Int = 0
+ ) : ReleaseNotesAction()
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesActivity.kt
new file mode 100644
index 0000000000..4d8cfc9f23
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesActivity.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.release
+
+import androidx.lifecycle.lifecycleScope
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.core.extensions.addFragment
+import im.vector.app.core.platform.ScreenOrientationLocker
+import im.vector.app.core.platform.VectorBaseActivity
+import im.vector.app.databinding.ActivitySimpleBinding
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class ReleaseNotesActivity : VectorBaseActivity() {
+
+ @Inject lateinit var orientationLocker: ScreenOrientationLocker
+ @Inject lateinit var releaseNotesPreferencesStore: ReleaseNotesPreferencesStore
+
+ override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater)
+
+ override fun getCoordinatorLayout() = views.coordinatorLayout
+
+ override fun initUiAndData() {
+ orientationLocker.lockPhonesToPortrait(this)
+ if (isFirstCreation()) {
+ addFragment(views.simpleFragmentContainer, ReleaseNotesFragment::class.java)
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ lifecycleScope.launch {
+ releaseNotesPreferencesStore.setAppLayoutOnboardingShown(true)
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesCarouselController.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesCarouselController.kt
new file mode 100644
index 0000000000..22d2915c47
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesCarouselController.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.home.room.list.home.release
+
+import com.airbnb.epoxy.TypedEpoxyController
+import javax.inject.Inject
+
+class ReleaseNotesCarouselController @Inject constructor() : TypedEpoxyController() {
+ override fun buildModels(data: ReleaseCarouselData) {
+ data.items.forEachIndexed { index, item ->
+ releaseCarouselItem {
+ id(index)
+ item(item)
+ }
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesFragment.kt
new file mode 100644
index 0000000000..6b86897dc8
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesFragment.kt
@@ -0,0 +1,138 @@
+/*
+ * 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.release
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
+import androidx.viewpager2.widget.ViewPager2
+import com.airbnb.mvrx.fragmentViewModel
+import com.google.android.material.tabs.TabLayoutMediator
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.R
+import im.vector.app.core.epoxy.onClick
+import im.vector.app.core.platform.VectorBaseFragment
+import im.vector.app.databinding.BottomSheetReleaseNotesBinding
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class ReleaseNotesFragment : VectorBaseFragment() {
+
+ @Inject lateinit var carouselController: ReleaseNotesCarouselController
+ private var tabLayoutMediator: TabLayoutMediator? = null
+
+ private val viewModel by fragmentViewModel(ReleaseNotesViewModel::class)
+
+ override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetReleaseNotesBinding {
+ return BottomSheetReleaseNotesBinding.inflate(inflater, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val carouselAdapter = carouselController.adapter
+ views.releaseNotesCarousel.adapter = carouselAdapter
+
+ tabLayoutMediator = TabLayoutMediator(views.releaseNotesCarouselIndicator, views.releaseNotesCarousel) { _, _ -> }
+ .also { it.attach() }
+
+ val pageCallback = object : ViewPager2.OnPageChangeCallback() {
+ override fun onPageSelected(position: Int) {
+ viewModel.handle(ReleaseNotesAction.PageSelected(position))
+ updateButtonText(position)
+ }
+ }
+
+ viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
+ override fun onCreate(owner: LifecycleOwner) {
+ views.releaseNotesCarousel.registerOnPageChangeCallback(pageCallback)
+ }
+
+ override fun onDestroy(owner: LifecycleOwner) {
+ views.releaseNotesCarousel.unregisterOnPageChangeCallback(pageCallback)
+ }
+ })
+
+ carouselController.setData(createCarouselData())
+
+ views.releaseNotesBtnClose.onClick { close() }
+ views.releaseNotesButtonNext.onClick {
+ val isLastItemSelected = with(views.releaseNotesCarouselIndicator) {
+ selectedTabPosition == tabCount - 1
+ }
+ viewModel.handle(ReleaseNotesAction.NextPressed(isLastItemSelected))
+ }
+
+ viewModel.observeViewEvents {
+ when (it) {
+ is ReleaseNotesViewEvents.SelectPage -> selectPage(it.index)
+ ReleaseNotesViewEvents.Close -> close()
+ }
+ }
+ }
+
+ private fun createCarouselData(): ReleaseCarouselData {
+ return ReleaseCarouselData(
+ listOf(
+ ReleaseCarouselData.Item(
+ R.string.onboarding_new_app_layout_welcome_title,
+ R.string.onboarding_new_app_layout_welcome_message,
+ R.drawable.ill_app_layout_onboarding_rooms
+ ),
+ ReleaseCarouselData.Item(
+ R.string.onboarding_new_app_layout_spaces_title,
+ R.string.onboarding_new_app_layout_spaces_message,
+ R.drawable.ill_app_layout_onboarding_spaces
+ ),
+ ReleaseCarouselData.Item(
+ R.string.onboarding_new_app_layout_feedback_title,
+ R.string.onboarding_new_app_layout_feedback_message,
+ R.drawable.ill_app_layout_onboarding_rooms
+ ),
+ )
+ )
+ }
+
+ private fun close() {
+ requireActivity().finish()
+ }
+
+ private fun selectPage(index: Int) {
+ views.releaseNotesCarouselIndicator.selectTab(views.releaseNotesCarouselIndicator.getTabAt(index))
+ updateButtonText(index)
+ }
+
+ private fun updateButtonText(selectedIndex: Int) {
+ val isLastItem = selectedIndex == views.releaseNotesCarouselIndicator.tabCount - 1
+ if (isLastItem) {
+ views.releaseNotesButtonNext.setText(R.string.onboarding_new_app_layout_button_try)
+ } else {
+ views.releaseNotesButtonNext.setText(R.string.action_next)
+ }
+ }
+
+ override fun onDestroyView() {
+ tabLayoutMediator?.detach()
+ tabLayoutMediator = null
+
+ views.releaseNotesCarousel.adapter = null
+ super.onDestroyView()
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesPreferencesStore.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesPreferencesStore.kt
new file mode 100644
index 0000000000..cefe107905
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesPreferencesStore.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.release
+
+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 = "release_notes")
+
+class ReleaseNotesPreferencesStore @Inject constructor(
+ private val context: Context
+) {
+
+ private val isAppLayoutOnboardingShown = booleanPreferencesKey("SETTINGS_APP_LAYOUT_ONBOARDING_SHOWN")
+
+ val appLayoutOnboardingShown: Flow = context.dataStore.data
+ .map { preferences -> preferences[isAppLayoutOnboardingShown].orFalse() }
+ .distinctUntilChanged()
+
+ suspend fun setAppLayoutOnboardingShown(isShown: Boolean) {
+ context.dataStore.edit { settings ->
+ settings[isAppLayoutOnboardingShown] = isShown
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesViewEvents.kt
new file mode 100644
index 0000000000..7901a8b28f
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesViewEvents.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.release
+
+import im.vector.app.core.platform.VectorViewEvents
+
+sealed class ReleaseNotesViewEvents : VectorViewEvents {
+ object Close : ReleaseNotesViewEvents()
+ data class SelectPage(val index: Int) : ReleaseNotesViewEvents()
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesViewModel.kt
new file mode 100644
index 0000000000..23e2364d0c
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesViewModel.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.release
+
+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.VectorDummyViewState
+import im.vector.app.core.platform.VectorViewModel
+
+class ReleaseNotesViewModel @AssistedInject constructor(
+ @Assisted initialState: VectorDummyViewState,
+) : VectorViewModel(initialState) {
+
+ @AssistedFactory
+ interface Factory : MavericksAssistedViewModelFactory {
+ override fun create(initialState: VectorDummyViewState): ReleaseNotesViewModel
+ }
+
+ companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory()
+
+ private var selectedPageIndex = 0
+
+ init {
+ _viewEvents.post(ReleaseNotesViewEvents.SelectPage(0))
+ }
+
+ override fun handle(action: ReleaseNotesAction) {
+ when (action) {
+ is ReleaseNotesAction.NextPressed -> handleNextPressed(action)
+ is ReleaseNotesAction.PageSelected -> handlePageSelected(action)
+ }
+ }
+
+ private fun handlePageSelected(action: ReleaseNotesAction.PageSelected) {
+ selectedPageIndex = action.selectedPageIndex
+ }
+
+ private fun handleNextPressed(action: ReleaseNotesAction.NextPressed) {
+ if (action.isLastItemSelected) {
+ _viewEvents.post(ReleaseNotesViewEvents.Close)
+ } else {
+ _viewEvents.post(ReleaseNotesViewEvents.SelectPage(++selectedPageIndex))
+ }
+ }
+}
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/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 4a66da6ec2..2362c8ee75 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
@@ -41,7 +42,6 @@ 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:
@@ -51,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
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginGenericTextInputFormFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginGenericTextInputFormFragment.kt
index 07253d80ec..2bc8419989 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginGenericTextInputFormFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginGenericTextInputFormFragment.kt
@@ -29,6 +29,7 @@ import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.args
import com.google.i18n.phonenumbers.NumberParseException
import com.google.i18n.phonenumbers.PhoneNumberUtil
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.extensions.isEmail
@@ -41,7 +42,6 @@ import org.matrix.android.sdk.api.auth.registration.RegisterThreePid
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.failure.is401
import reactivecircus.flowbinding.android.widget.textChanges
-import javax.inject.Inject
enum class TextInputFormFragmentMode {
SetEmail,
@@ -59,7 +59,9 @@ data class LoginGenericTextInputFormFragmentArgument(
/**
* In this screen, the user is asked for a text input.
*/
-class LoginGenericTextInputFormFragment @Inject constructor() : AbstractLoginFragment() {
+@AndroidEntryPoint
+class LoginGenericTextInputFormFragment :
+ AbstractLoginFragment() {
private val params: LoginGenericTextInputFormFragmentArgument by args()
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 aafd426335..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 im.vector.app.features.login.SocialLoginButtonsView.Mode
-import javax.inject.Inject
/**
* 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)
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 751123cd9e..86c9ac43db 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.core.utils.openUrlInChromeCustomTab
@@ -37,10 +38,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/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/PromptSimplifiedModeFragment.kt b/vector/src/main/java/im/vector/app/features/login/PromptSimplifiedModeFragment.kt
index 09886db52d..50d6691372 100644
--- a/vector/src/main/java/im/vector/app/features/login/PromptSimplifiedModeFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/PromptSimplifiedModeFragment.kt
@@ -20,11 +20,13 @@ 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.FragmentPromptSimplifiedModeBinding
import im.vector.app.features.settings.VectorPreferences
import javax.inject.Inject
+@AndroidEntryPoint
class PromptSimplifiedModeFragment @Inject constructor(private val vectorPreferences: VectorPreferences) : VectorBaseFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentPromptSimplifiedModeBinding {
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/matrixto/MatrixToRoomSpaceFragment.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToRoomSpaceFragment.kt
index 8dd9fd030a..f564802b57 100644
--- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToRoomSpaceFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToRoomSpaceFragment.kt
@@ -28,6 +28,7 @@ import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized
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.setTextOrHide
import im.vector.app.core.platform.ButtonStateView
@@ -38,10 +39,12 @@ import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomType
import javax.inject.Inject
-class MatrixToRoomSpaceFragment @Inject constructor(
- private val avatarRenderer: AvatarRenderer,
- private val spaceCardRenderer: SpaceCardRenderer
-) : VectorBaseFragment() {
+@AndroidEntryPoint
+class MatrixToRoomSpaceFragment :
+ VectorBaseFragment() {
+
+ @Inject lateinit var avatarRenderer: AvatarRenderer
+ @Inject lateinit var spaceCardRenderer: SpaceCardRenderer
private val sharedViewModel: MatrixToBottomSheetViewModel by parentFragmentViewModel()
diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToUserFragment.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToUserFragment.kt
index 3792183bca..c8b18e327b 100644
--- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToUserFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToUserFragment.kt
@@ -28,15 +28,18 @@ import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized
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.databinding.FragmentMatrixToUserCardBinding
import im.vector.app.features.home.AvatarRenderer
import javax.inject.Inject
-class MatrixToUserFragment @Inject constructor(
- private val avatarRenderer: AvatarRenderer
-) : VectorBaseFragment() {
+@AndroidEntryPoint
+class MatrixToUserFragment :
+ VectorBaseFragment() {
+
+ @Inject lateinit var avatarRenderer: AvatarRenderer
private val sharedViewModel: MatrixToBottomSheetViewModel by parentFragmentViewModel()
diff --git a/vector/src/main/java/im/vector/app/features/media/ImageContentRenderer.kt b/vector/src/main/java/im/vector/app/features/media/ImageContentRenderer.kt
index a4536fd689..e8fee17fe1 100644
--- a/vector/src/main/java/im/vector/app/features/media/ImageContentRenderer.kt
+++ b/vector/src/main/java/im/vector/app/features/media/ImageContentRenderer.kt
@@ -339,8 +339,7 @@ class ImageContentRenderer @Inject constructor(
}
Mode.STICKER -> {
// limit on width
- val maxWidthDp = min(dimensionConverter.dpToPx(240), maxImageWidth)
- finalWidth = min(dimensionConverter.dpToPx(width), maxWidthDp)
+ finalWidth = min(dimensionConverter.dpToPx(width), maxImageWidth * 3 / 4)
finalHeight = finalWidth * height / width
}
}
diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
index a9d7d6adcb..83b76cf86e 100644
--- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
+++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
@@ -25,11 +25,11 @@ import android.view.View
import android.view.Window
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
-import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityOptionsCompat
import androidx.core.app.TaskStackBuilder
import androidx.core.util.Pair
import androidx.core.view.ViewCompat
+import androidx.fragment.app.FragmentActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import im.vector.app.R
import im.vector.app.SpaceStateHandler
@@ -178,13 +178,25 @@ class DefaultNavigator @Inject constructor(
startActivity(context, intent, buildTask)
}
- override fun switchToSpace(context: Context, spaceId: String, postSwitchSpaceAction: Navigator.PostSwitchSpaceAction) {
+ override fun switchToSpace(
+ context: Context,
+ spaceId: String,
+ postSwitchSpaceAction: Navigator.PostSwitchSpaceAction,
+ ) {
if (sessionHolder.getSafeActiveSession()?.getRoomSummary(spaceId) == null) {
fatalError("Trying to open an unknown space $spaceId", vectorPreferences.failFast())
return
}
spaceStateHandler.setCurrentSpace(spaceId)
- when (postSwitchSpaceAction) {
+ handlePostSwitchAction(context, spaceId, postSwitchSpaceAction)
+ }
+
+ private fun handlePostSwitchAction(
+ context: Context,
+ spaceId: String,
+ action: Navigator.PostSwitchSpaceAction,
+ ) {
+ when (action) {
Navigator.PostSwitchSpaceAction.None -> {
// go back to home if we are showing room details?
// This is a bit ugly, but the navigator is supposed to know about the activity stack
@@ -200,9 +212,9 @@ class DefaultNavigator @Inject constructor(
}
is Navigator.PostSwitchSpaceAction.OpenDefaultRoom -> {
val args = TimelineArgs(
- postSwitchSpaceAction.roomId,
+ action.roomId,
eventId = null,
- openShareSpaceForId = spaceId.takeIf { postSwitchSpaceAction.showShareSheet }
+ openShareSpaceForId = spaceId.takeIf { action.showShareSheet }
)
val intent = RoomDetailActivity.newIntent(context, args, false)
startActivity(context, intent, false)
@@ -214,75 +226,65 @@ class DefaultNavigator @Inject constructor(
startActivity(context, SpacePreviewActivity.newIntent(context, spaceId), false)
}
- override fun performDeviceVerification(context: Context, otherUserId: String, sasTransactionId: String) {
+ override fun performDeviceVerification(fragmentActivity: FragmentActivity, otherUserId: String, sasTransactionId: String) {
val session = sessionHolder.getSafeActiveSession() ?: return
val tx = session.cryptoService().verificationService().getExistingTransaction(otherUserId, sasTransactionId)
?: return
(tx as? IncomingSasVerificationTransaction)?.performAccept()
- if (context is AppCompatActivity) {
- VerificationBottomSheet.withArgs(
- roomId = null,
- otherUserId = otherUserId,
- transactionId = sasTransactionId
- ).show(context.supportFragmentManager, "REQPOP")
- }
+ VerificationBottomSheet.withArgs(
+ roomId = null,
+ otherUserId = otherUserId,
+ transactionId = sasTransactionId
+ ).show(fragmentActivity.supportFragmentManager, "REQPOP")
}
- override fun requestSessionVerification(context: Context, otherSessionId: String) {
+ override fun requestSessionVerification(fragmentActivity: FragmentActivity, otherSessionId: String) {
val session = sessionHolder.getSafeActiveSession() ?: return
val pr = session.cryptoService().verificationService().requestKeyVerification(
supportedVerificationMethodsProvider.provide(),
session.myUserId,
listOf(otherSessionId)
)
- if (context is AppCompatActivity) {
- VerificationBottomSheet.withArgs(
- roomId = null,
- otherUserId = session.myUserId,
- transactionId = pr.transactionId
- ).show(context.supportFragmentManager, VerificationBottomSheet.WAITING_SELF_VERIF_TAG)
- }
+ VerificationBottomSheet.withArgs(
+ roomId = null,
+ otherUserId = session.myUserId,
+ transactionId = pr.transactionId
+ ).show(fragmentActivity.supportFragmentManager, VerificationBottomSheet.WAITING_SELF_VERIF_TAG)
}
- override fun requestSelfSessionVerification(context: Context) {
+ override fun requestSelfSessionVerification(fragmentActivity: FragmentActivity) {
val session = sessionHolder.getSafeActiveSession() ?: return
val otherSessions = session.cryptoService()
.getCryptoDeviceInfo(session.myUserId)
.filter { it.deviceId != session.sessionParams.deviceId }
.map { it.deviceId }
- if (context is AppCompatActivity) {
- if (otherSessions.isNotEmpty()) {
- val pr = session.cryptoService().verificationService().requestKeyVerification(
- supportedVerificationMethodsProvider.provide(),
- session.myUserId,
- otherSessions
- )
- VerificationBottomSheet.forSelfVerification(session, pr.transactionId ?: pr.localId)
- .show(context.supportFragmentManager, VerificationBottomSheet.WAITING_SELF_VERIF_TAG)
- } else {
- VerificationBottomSheet.forSelfVerification(session)
- .show(context.supportFragmentManager, VerificationBottomSheet.WAITING_SELF_VERIF_TAG)
- }
- }
- }
-
- override fun waitSessionVerification(context: Context) {
- val session = sessionHolder.getSafeActiveSession() ?: return
- if (context is AppCompatActivity) {
- VerificationBottomSheet.forSelfVerification(session)
- .show(context.supportFragmentManager, VerificationBottomSheet.WAITING_SELF_VERIF_TAG)
- }
- }
-
- override fun upgradeSessionSecurity(context: Context, initCrossSigningOnly: Boolean) {
- if (context is AppCompatActivity) {
- BootstrapBottomSheet.show(
- context.supportFragmentManager,
- if (initCrossSigningOnly) SetupMode.CROSS_SIGNING_ONLY else SetupMode.NORMAL
+ if (otherSessions.isNotEmpty()) {
+ val pr = session.cryptoService().verificationService().requestKeyVerification(
+ supportedVerificationMethodsProvider.provide(),
+ session.myUserId,
+ otherSessions
)
+ VerificationBottomSheet.forSelfVerification(session, pr.transactionId ?: pr.localId)
+ .show(fragmentActivity.supportFragmentManager, VerificationBottomSheet.WAITING_SELF_VERIF_TAG)
+ } else {
+ VerificationBottomSheet.forSelfVerification(session)
+ .show(fragmentActivity.supportFragmentManager, VerificationBottomSheet.WAITING_SELF_VERIF_TAG)
}
}
+ override fun waitSessionVerification(fragmentActivity: FragmentActivity) {
+ val session = sessionHolder.getSafeActiveSession() ?: return
+ VerificationBottomSheet.forSelfVerification(session)
+ .show(fragmentActivity.supportFragmentManager, VerificationBottomSheet.WAITING_SELF_VERIF_TAG)
+ }
+
+ override fun upgradeSessionSecurity(fragmentActivity: FragmentActivity, initCrossSigningOnly: Boolean) {
+ BootstrapBottomSheet.show(
+ fragmentActivity.supportFragmentManager,
+ if (initCrossSigningOnly) SetupMode.CROSS_SIGNING_ONLY else SetupMode.NORMAL
+ )
+ }
+
override fun openRoomMemberProfile(userId: String, roomId: String?, context: Context, buildTask: Boolean) {
val args = RoomMemberProfileArgs(userId = userId, roomId = roomId)
val intent = RoomMemberProfileActivity.newIntent(context, args)
@@ -306,16 +308,14 @@ class DefaultNavigator @Inject constructor(
context.startActivity(intent)
}
- override fun openMatrixToBottomSheet(context: Context, link: String, origin: OriginOfMatrixTo) {
- if (context is AppCompatActivity) {
- if (context !is MatrixToBottomSheet.InteractionListener) {
- fatalError("Caller context should implement MatrixToBottomSheet.InteractionListener", vectorPreferences.failFast())
- return
- }
- // TODO check if there is already one??
- MatrixToBottomSheet.withLink(link, origin)
- .show(context.supportFragmentManager, "HA#MatrixToBottomSheet")
+ override fun openMatrixToBottomSheet(fragmentActivity: FragmentActivity, link: String, origin: OriginOfMatrixTo) {
+ if (fragmentActivity !is MatrixToBottomSheet.InteractionListener) {
+ fatalError("Caller context should implement MatrixToBottomSheet.InteractionListener", vectorPreferences.failFast())
+ return
}
+ // TODO check if there is already one??
+ MatrixToBottomSheet.withLink(link, origin)
+ .show(fragmentActivity.supportFragmentManager, "HA#MatrixToBottomSheet")
}
override fun openRoomDirectory(context: Context, initialFilter: String) {
@@ -337,18 +337,16 @@ class DefaultNavigator @Inject constructor(
}.start(context)
}
- override fun openInviteUsersToRoom(context: Context, roomId: String) {
+ override fun openInviteUsersToRoom(fragmentActivity: FragmentActivity, roomId: String) {
when (val currentSpace = spaceStateHandler.getCurrentSpace()) {
- null -> InviteUsersToRoomActivity.getIntent(context, roomId).start(context)
- else -> showInviteToDialog(context, currentSpace, roomId)
+ null -> InviteUsersToRoomActivity.getIntent(fragmentActivity, roomId).start(fragmentActivity)
+ else -> showInviteToDialog(fragmentActivity, currentSpace, roomId)
}
}
- private fun showInviteToDialog(context: Context, currentSpace: RoomSummary, roomId: String) {
- (context as? AppCompatActivity)?.supportFragmentManager?.let { fragmentManager ->
- InviteRoomSpaceChooserBottomSheet.showInstance(fragmentManager, currentSpace.roomId, roomId) { itemId ->
- InviteUsersToRoomActivity.getIntent(context, itemId).start(context)
- }
+ private fun showInviteToDialog(fragmentActivity: FragmentActivity, currentSpace: RoomSummary, roomId: String) {
+ InviteRoomSpaceChooserBottomSheet.showInstance(fragmentActivity.supportFragmentManager, currentSpace.roomId, roomId) { itemId ->
+ InviteUsersToRoomActivity.getIntent(fragmentActivity, itemId).start(fragmentActivity)
}
}
@@ -371,24 +369,20 @@ class DefaultNavigator @Inject constructor(
debugNavigator.openDebugMenu(context)
}
- override fun openKeysBackupSetup(context: Context, showManualExport: Boolean) {
+ override fun openKeysBackupSetup(fragmentActivity: FragmentActivity, showManualExport: Boolean) {
// if cross signing is enabled and trusted or not set up at all we should propose full 4S
sessionHolder.getSafeActiveSession()?.let { session ->
if (session.cryptoService().crossSigningService().getMyCrossSigningKeys() == null ||
session.cryptoService().crossSigningService().canCrossSign()) {
- (context as? AppCompatActivity)?.let {
- BootstrapBottomSheet.show(it.supportFragmentManager, SetupMode.NORMAL)
- }
+ BootstrapBottomSheet.show(fragmentActivity.supportFragmentManager, SetupMode.NORMAL)
} else {
- context.startActivity(KeysBackupSetupActivity.intent(context, showManualExport))
+ fragmentActivity.startActivity(KeysBackupSetupActivity.intent(fragmentActivity, showManualExport))
}
}
}
- override fun open4SSetup(context: Context, setupMode: SetupMode) {
- if (context is AppCompatActivity) {
- BootstrapBottomSheet.show(context.supportFragmentManager, setupMode)
- }
+ override fun open4SSetup(fragmentActivity: FragmentActivity, setupMode: SetupMode) {
+ BootstrapBottomSheet.show(fragmentActivity.supportFragmentManager, setupMode)
}
override fun openKeysBackupManager(context: Context) {
diff --git a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
index 16a6f752f4..a6ea315530 100644
--- a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
+++ b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
@@ -23,6 +23,7 @@ import android.net.Uri
import android.view.View
import androidx.activity.result.ActivityResultLauncher
import androidx.core.util.Pair
+import androidx.fragment.app.FragmentActivity
import im.vector.app.features.analytics.plan.ViewRoom
import im.vector.app.features.crypto.recover.SetupMode
import im.vector.app.features.displayname.getBestName
@@ -70,19 +71,23 @@ interface Navigator {
data class OpenDefaultRoom(val roomId: String, val showShareSheet: Boolean) : PostSwitchSpaceAction()
}
- fun switchToSpace(context: Context, spaceId: String, postSwitchSpaceAction: PostSwitchSpaceAction)
+ fun switchToSpace(
+ context: Context,
+ spaceId: String,
+ postSwitchSpaceAction: PostSwitchSpaceAction,
+ )
fun openSpacePreview(context: Context, spaceId: String)
- fun performDeviceVerification(context: Context, otherUserId: String, sasTransactionId: String)
+ fun performDeviceVerification(fragmentActivity: FragmentActivity, otherUserId: String, sasTransactionId: String)
- fun requestSessionVerification(context: Context, otherSessionId: String)
+ fun requestSessionVerification(fragmentActivity: FragmentActivity, otherSessionId: String)
- fun requestSelfSessionVerification(context: Context)
+ fun requestSelfSessionVerification(fragmentActivity: FragmentActivity)
- fun waitSessionVerification(context: Context)
+ fun waitSessionVerification(fragmentActivity: FragmentActivity)
- fun upgradeSessionSecurity(context: Context, initCrossSigningOnly: Boolean)
+ fun upgradeSessionSecurity(fragmentActivity: FragmentActivity, initCrossSigningOnly: Boolean)
fun openRoomForSharingAndFinish(activity: Activity, roomId: String, sharedData: SharedData)
@@ -90,13 +95,13 @@ interface Navigator {
fun openRoomPreview(context: Context, roomPreviewData: RoomPreviewData, fromEmailInviteLink: PermalinkData.RoomEmailInviteLink? = null)
- fun openMatrixToBottomSheet(context: Context, link: String, origin: OriginOfMatrixTo)
+ fun openMatrixToBottomSheet(fragmentActivity: FragmentActivity, link: String, origin: OriginOfMatrixTo)
fun openCreateRoom(context: Context, initialName: String = "", openAfterCreate: Boolean = true)
fun openCreateDirectRoom(context: Context)
- fun openInviteUsersToRoom(context: Context, roomId: String)
+ fun openInviteUsersToRoom(fragmentActivity: FragmentActivity, roomId: String)
fun openRoomDirectory(context: Context, initialFilter: String = "")
@@ -108,9 +113,9 @@ interface Navigator {
fun openDebug(context: Context)
- fun openKeysBackupSetup(context: Context, showManualExport: Boolean)
+ fun openKeysBackupSetup(fragmentActivity: FragmentActivity, showManualExport: Boolean)
- fun open4SSetup(context: Context, setupMode: SetupMode)
+ fun open4SSetup(fragmentActivity: FragmentActivity, setupMode: SetupMode)
fun openKeysBackupManager(context: Context)
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt
index 9661feb002..4f8a77f25d 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt
@@ -627,7 +627,8 @@ class OnboardingViewModel @AssistedInject constructor(
_viewEvents.post(OnboardingViewEvents.OnAccountCreated)
}
AuthenticationDescription.Login -> {
- setState { copy(isLoading = false) }
+ setState { copy(isLoading = false, selectedAuthenticationState = SelectedAuthenticationState(authenticationDescription)) }
+ awaitState()
_viewEvents.post(OnboardingViewEvents.OnAccountSignedIn)
}
}
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthAccountCreatedFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthAccountCreatedFragment.kt
index 9f2aadef5c..a53ca52e85 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthAccountCreatedFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthAccountCreatedFragment.kt
@@ -23,6 +23,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.text.toSpannable
import androidx.core.view.isVisible
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.animations.play
import im.vector.app.core.di.ActiveSessionHolder
@@ -34,9 +35,11 @@ import im.vector.app.features.onboarding.OnboardingViewEvents
import im.vector.app.features.onboarding.OnboardingViewState
import javax.inject.Inject
-class FtueAuthAccountCreatedFragment @Inject constructor(
- private val activeSessionHolder: ActiveSessionHolder
-) : AbstractFtueAuthFragment() {
+@AndroidEntryPoint
+class FtueAuthAccountCreatedFragment :
+ AbstractFtueAuthFragment() {
+
+ @Inject lateinit var activeSessionHolder: ActiveSessionHolder
private var hasPlayedConfetti = false
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCaptchaFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCaptchaFragment.kt
index 1f44922b3b..f170868307 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCaptchaFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCaptchaFragment.kt
@@ -24,6 +24,7 @@ import android.view.ViewGroup
import android.view.ViewStub
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.extensions.crawlCausesFor
import im.vector.app.databinding.FragmentFtueLoginCaptchaBinding
@@ -43,9 +44,11 @@ data class FtueAuthCaptchaFragmentArgument(
/**
* In this screen, the user is asked to confirm they are not a robot.
*/
-class FtueAuthCaptchaFragment @Inject constructor(
- private val captchaWebview: CaptchaWebview
-) : AbstractFtueAuthFragment() {
+@AndroidEntryPoint
+class FtueAuthCaptchaFragment :
+ AbstractFtueAuthFragment() {
+
+ @Inject lateinit var captchaWebview: CaptchaWebview
private val params: FtueAuthCaptchaFragmentArgument by args()
private var webViewBinding: ViewStubWebviewBinding? = null
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthChooseDisplayNameFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthChooseDisplayNameFragment.kt
index c4b4e807ac..234a5789c1 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthChooseDisplayNameFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthChooseDisplayNameFragment.kt
@@ -22,15 +22,17 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.hasContent
import im.vector.app.core.platform.SimpleTextWatcher
import im.vector.app.databinding.FragmentFtueDisplayNameBinding
import im.vector.app.features.onboarding.OnboardingAction
import im.vector.app.features.onboarding.OnboardingViewEvents
import im.vector.app.features.onboarding.OnboardingViewState
-import javax.inject.Inject
-class FtueAuthChooseDisplayNameFragment @Inject constructor() : AbstractFtueAuthFragment() {
+@AndroidEntryPoint
+class FtueAuthChooseDisplayNameFragment :
+ AbstractFtueAuthFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueDisplayNameBinding {
return FragmentFtueDisplayNameBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthChooseProfilePictureFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthChooseProfilePictureFragment.kt
index 1a673b156a..92d0aa2a0f 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthChooseProfilePictureFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthChooseProfilePictureFragment.kt
@@ -24,12 +24,11 @@ import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.isInvisible
import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper
-import im.vector.app.core.extensions.singletonEntryPoint
-import im.vector.app.core.resources.ColorProvider
-import im.vector.app.core.time.Clock
+import im.vector.app.core.dialogs.GalleryOrCameraDialogHelperFactory
import im.vector.app.databinding.FragmentFtueProfilePictureBinding
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.onboarding.OnboardingAction
@@ -38,19 +37,26 @@ import im.vector.app.features.onboarding.OnboardingViewState
import org.matrix.android.sdk.api.util.MatrixItem
import javax.inject.Inject
-class FtueAuthChooseProfilePictureFragment @Inject constructor(
- private val activeSessionHolder: ActiveSessionHolder,
- colorProvider: ColorProvider,
- clock: Clock,
-) : AbstractFtueAuthFragment(), GalleryOrCameraDialogHelper.Listener {
+@AndroidEntryPoint
+class FtueAuthChooseProfilePictureFragment :
+ AbstractFtueAuthFragment(),
+ GalleryOrCameraDialogHelper.Listener {
- private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock)
- private val avatarRenderer: AvatarRenderer by lazy { requireContext().singletonEntryPoint().avatarRenderer() }
+ @Inject lateinit var activeSessionHolder: ActiveSessionHolder
+ @Inject lateinit var galleryOrCameraDialogHelperFactory: GalleryOrCameraDialogHelperFactory
+ @Inject lateinit var avatarRenderer: AvatarRenderer
+
+ private lateinit var galleryOrCameraDialogHelper: GalleryOrCameraDialogHelper
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueProfilePictureBinding {
return FragmentFtueProfilePictureBinding.inflate(inflater, container, false)
}
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ galleryOrCameraDialogHelper = galleryOrCameraDialogHelperFactory.create(this)
+ }
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupViews()
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedLoginFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedLoginFragment.kt
index b24511b4bc..6877810f0a 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedLoginFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedLoginFragment.kt
@@ -24,6 +24,7 @@ import android.view.ViewGroup
import androidx.autofill.HintConstants
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.clearErrorOnChange
import im.vector.app.core.extensions.content
@@ -48,10 +49,12 @@ import kotlinx.coroutines.flow.launchIn
import reactivecircus.flowbinding.android.widget.textChanges
import javax.inject.Inject
-class FtueAuthCombinedLoginFragment @Inject constructor(
- private val loginFieldsValidation: LoginFieldsValidation,
- private val loginErrorParser: LoginErrorParser
-) : AbstractSSOFtueAuthFragment() {
+@AndroidEntryPoint
+class FtueAuthCombinedLoginFragment :
+ AbstractSSOFtueAuthFragment() {
+
+ @Inject lateinit var loginFieldsValidation: LoginFieldsValidation
+ @Inject lateinit var loginErrorParser: LoginErrorParser
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueCombinedLoginBinding {
return FragmentFtueCombinedLoginBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedRegisterFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedRegisterFragment.kt
index d06d1e8051..66668f5303 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedRegisterFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedRegisterFragment.kt
@@ -27,6 +27,7 @@ import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
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.clearErrorOnChange
import im.vector.app.core.extensions.content
@@ -60,11 +61,12 @@ import org.matrix.android.sdk.api.failure.isRegistrationDisabled
import org.matrix.android.sdk.api.failure.isUsernameInUse
import org.matrix.android.sdk.api.failure.isWeakPassword
import reactivecircus.flowbinding.android.widget.textChanges
-import javax.inject.Inject
private const val MINIMUM_PASSWORD_LENGTH = 8
-class FtueAuthCombinedRegisterFragment @Inject constructor() : AbstractSSOFtueAuthFragment() {
+@AndroidEntryPoint
+class FtueAuthCombinedRegisterFragment :
+ AbstractSSOFtueAuthFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueCombinedRegisterBinding {
return FragmentFtueCombinedRegisterBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedServerSelectionFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedServerSelectionFragment.kt
index 2563c1d777..f39946a1d0 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedServerSelectionFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedServerSelectionFragment.kt
@@ -20,6 +20,7 @@ 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.extensions.associateContentStateWith
import im.vector.app.core.extensions.clearErrorOnChange
@@ -27,6 +28,7 @@ import im.vector.app.core.extensions.content
import im.vector.app.core.extensions.editText
import im.vector.app.core.extensions.realignPercentagesToParent
import im.vector.app.core.extensions.setOnImeDoneListener
+import im.vector.app.core.extensions.showKeyboard
import im.vector.app.core.extensions.toReducedUrl
import im.vector.app.core.utils.ensureProtocol
import im.vector.app.core.utils.ensureTrailingSlash
@@ -37,9 +39,10 @@ import im.vector.app.features.onboarding.OnboardingFlow
import im.vector.app.features.onboarding.OnboardingViewEvents
import im.vector.app.features.onboarding.OnboardingViewState
import org.matrix.android.sdk.api.failure.isHomeserverUnavailable
-import javax.inject.Inject
-class FtueAuthCombinedServerSelectionFragment @Inject constructor() : AbstractFtueAuthFragment() {
+@AndroidEntryPoint
+class FtueAuthCombinedServerSelectionFragment :
+ AbstractFtueAuthFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueServerSelectionCombinedBinding {
return FragmentFtueServerSelectionCombinedBinding.inflate(inflater, container, false)
@@ -89,6 +92,9 @@ class FtueAuthCombinedServerSelectionFragment @Inject constructor() : AbstractFt
val userUrlInput = state.selectedHomeserver.userFacingUrl?.toReducedUrlKeepingSchemaIfInsecure() ?: viewModel.getDefaultHomeserverUrl()
views.chooseServerInput.editText().setText(userUrlInput)
}
+
+ views.chooseServerInput.editText().selectAll()
+ views.chooseServerInput.editText().showKeyboard(true)
}
override fun onError(throwable: Throwable) {
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthEmailEntryFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthEmailEntryFragment.kt
index 5de8fce82f..e315f191c1 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthEmailEntryFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthEmailEntryFragment.kt
@@ -17,9 +17,12 @@
package im.vector.app.features.onboarding.ftueauth
import android.os.Bundle
+import android.os.Parcelable
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.core.extensions.associateContentStateWith
import im.vector.app.core.extensions.autofillEmail
@@ -34,10 +37,18 @@ import im.vector.app.databinding.FragmentFtueEmailInputBinding
import im.vector.app.features.onboarding.OnboardingAction
import im.vector.app.features.onboarding.OnboardingViewState
import im.vector.app.features.onboarding.RegisterAction
+import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.auth.registration.RegisterThreePid
-import javax.inject.Inject
-class FtueAuthEmailEntryFragment @Inject constructor() : AbstractFtueAuthFragment() {
+@Parcelize
+data class FtueAuthEmailEntryFragmentArgument(
+ val mandatory: Boolean,
+) : Parcelable
+
+@AndroidEntryPoint
+class FtueAuthEmailEntryFragment : AbstractFtueAuthFragment() {
+
+ private val params: FtueAuthEmailEntryFragmentArgument by args()
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueEmailInputBinding {
return FragmentFtueEmailInputBinding.inflate(inflater, container, false)
@@ -49,7 +60,11 @@ class FtueAuthEmailEntryFragment @Inject constructor() : AbstractFtueAuthFragmen
}
private fun setupViews() {
- views.emailEntryInput.associateContentStateWith(button = views.emailEntrySubmit, enabledPredicate = { it.isEmail() })
+ views.emailEntryInput.hint = getString(if (params.mandatory) R.string.ftue_auth_email_entry_title else R.string.login_set_email_optional_hint)
+ views.emailEntryInput.associateContentStateWith(
+ button = views.emailEntrySubmit,
+ enabledPredicate = { it.isEmail() || it.isEmptyAndOptional() },
+ )
views.emailEntryInput.setOnImeDoneListener { updateEmail() }
views.emailEntryInput.clearErrorOnChange(viewLifecycleOwner)
views.emailEntrySubmit.debouncedClicks { updateEmail() }
@@ -58,9 +73,14 @@ class FtueAuthEmailEntryFragment @Inject constructor() : AbstractFtueAuthFragmen
private fun updateEmail() {
val email = views.emailEntryInput.content()
- viewModel.handle(OnboardingAction.PostRegisterAction(RegisterAction.AddThreePid(RegisterThreePid.Email(email))))
+ when {
+ email.isEmptyAndOptional() -> viewModel.handle(OnboardingAction.PostRegisterAction(RegisterAction.RegisterDummy))
+ else -> viewModel.handle(OnboardingAction.PostRegisterAction(RegisterAction.AddThreePid(RegisterThreePid.Email(email))))
+ }
}
+ private fun String.isEmptyAndOptional() = isEmpty() && !params.mandatory
+
override fun updateWithState(state: OnboardingViewState) {
views.emailEntryHeaderSubtitle.text = getString(R.string.ftue_auth_email_subtitle, state.selectedHomeserver.userFacingUrl.toReducedUrl())
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthGenericTextInputFormFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthGenericTextInputFormFragment.kt
index edfbcd89b6..02d0c25cfd 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthGenericTextInputFormFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthGenericTextInputFormFragment.kt
@@ -29,6 +29,7 @@ import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.args
import com.google.i18n.phonenumbers.NumberParseException
import com.google.i18n.phonenumbers.PhoneNumberUtil
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.extensions.isEmail
@@ -44,7 +45,6 @@ import org.matrix.android.sdk.api.auth.registration.RegisterThreePid
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.failure.is401
import reactivecircus.flowbinding.android.widget.textChanges
-import javax.inject.Inject
@Parcelize
data class FtueAuthGenericTextInputFormFragmentArgument(
@@ -56,7 +56,9 @@ data class FtueAuthGenericTextInputFormFragmentArgument(
/**
* In this screen, the user is asked for a text input.
*/
-class FtueAuthGenericTextInputFormFragment @Inject constructor() : AbstractFtueAuthFragment() {
+@AndroidEntryPoint
+class FtueAuthGenericTextInputFormFragment :
+ AbstractFtueAuthFragment() {
private val params: FtueAuthGenericTextInputFormFragmentArgument by args()
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthLegacyStyleCaptchaFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthLegacyStyleCaptchaFragment.kt
index b8b30529a6..0efd8390ba 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthLegacyStyleCaptchaFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthLegacyStyleCaptchaFragment.kt
@@ -20,6 +20,7 @@ import android.os.Parcelable
import android.view.LayoutInflater
import android.view.ViewGroup
import com.airbnb.mvrx.args
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.databinding.FragmentLoginCaptchaBinding
import im.vector.app.features.onboarding.OnboardingAction
import im.vector.app.features.onboarding.OnboardingViewState
@@ -35,9 +36,11 @@ data class FtueAuthLegacyStyleCaptchaFragmentArgument(
/**
* In this screen, the user is asked to confirm they are not a robot.
*/
-class FtueAuthLegacyStyleCaptchaFragment @Inject constructor(
- private val captchaWebview: CaptchaWebview
-) : AbstractFtueAuthFragment() {
+@AndroidEntryPoint
+class FtueAuthLegacyStyleCaptchaFragment :
+ AbstractFtueAuthFragment() {
+
+ @Inject lateinit var captchaWebview: CaptchaWebview
private val params: FtueAuthLegacyStyleCaptchaFragmentArgument by args()
private var isWebViewLoaded = false
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthLegacyWaitForEmailFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthLegacyWaitForEmailFragment.kt
index c815f354f0..fb468ddeb2 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthLegacyWaitForEmailFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthLegacyWaitForEmailFragment.kt
@@ -21,16 +21,18 @@ 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 im.vector.app.features.onboarding.OnboardingAction
import im.vector.app.features.onboarding.RegisterAction
-import javax.inject.Inject
/**
* In this screen, the user is asked to check their emails.
*/
-class FtueAuthLegacyWaitForEmailFragment @Inject constructor() : AbstractFtueAuthFragment() {
+@AndroidEntryPoint
+class FtueAuthLegacyWaitForEmailFragment :
+ AbstractFtueAuthFragment() {
private val params: FtueAuthWaitForEmailFragmentArgument by args()
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthLoginFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthLoginFragment.kt
index ad159943b1..3fd8df6bb9 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthLoginFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthLoginFragment.kt
@@ -28,6 +28,7 @@ import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
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.hideKeyboard
import im.vector.app.core.extensions.hidePassword
@@ -53,7 +54,6 @@ import org.matrix.android.sdk.api.failure.isRegistrationDisabled
import org.matrix.android.sdk.api.failure.isUsernameInUse
import org.matrix.android.sdk.api.failure.isWeakPassword
import reactivecircus.flowbinding.android.widget.textChanges
-import javax.inject.Inject
/**
* In this screen:
@@ -63,7 +63,9 @@ import javax.inject.Inject
* In signup mode:
* - the user is asked for login and password
*/
-class FtueAuthLoginFragment @Inject constructor() : AbstractSSOFtueAuthFragment() {
+@AndroidEntryPoint
+class FtueAuthLoginFragment :
+ AbstractSSOFtueAuthFragment() {
private var isSignupMode = false
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthPersonalizationCompleteFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthPersonalizationCompleteFragment.kt
index 8e88a6ed46..96cc1c3b45 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthPersonalizationCompleteFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthPersonalizationCompleteFragment.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.databinding.FragmentFtuePersonalizationCompleteBinding
import im.vector.app.features.onboarding.OnboardingAction
import im.vector.app.features.onboarding.OnboardingViewEvents
-import javax.inject.Inject
-class FtueAuthPersonalizationCompleteFragment @Inject constructor() : AbstractFtueAuthFragment() {
+@AndroidEntryPoint
+class FtueAuthPersonalizationCompleteFragment :
+ AbstractFtueAuthFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtuePersonalizationCompleteBinding {
return FragmentFtuePersonalizationCompleteBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthPhoneConfirmationFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthPhoneConfirmationFragment.kt
index 39577efa19..af6c33c028 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthPhoneConfirmationFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthPhoneConfirmationFragment.kt
@@ -22,6 +22,7 @@ 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.core.extensions.associateContentStateWith
import im.vector.app.core.extensions.clearErrorOnChange
@@ -32,14 +33,15 @@ import im.vector.app.features.onboarding.OnboardingAction
import im.vector.app.features.onboarding.RegisterAction
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.failure.Failure
-import javax.inject.Inject
@Parcelize
data class FtueAuthPhoneConfirmationFragmentArgument(
val msisdn: String
) : Parcelable
-class FtueAuthPhoneConfirmationFragment @Inject constructor() : AbstractFtueAuthFragment() {
+@AndroidEntryPoint
+class FtueAuthPhoneConfirmationFragment :
+ AbstractFtueAuthFragment() {
private val params: FtueAuthPhoneConfirmationFragmentArgument by args()
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthPhoneEntryFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthPhoneEntryFragment.kt
index 32291ecb6e..620dd1293c 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthPhoneEntryFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthPhoneEntryFragment.kt
@@ -21,6 +21,7 @@ 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.extensions.associateContentStateWith
import im.vector.app.core.extensions.autofillPhoneNumber
@@ -38,9 +39,11 @@ import org.matrix.android.sdk.api.auth.registration.RegisterThreePid
import reactivecircus.flowbinding.android.widget.textChanges
import javax.inject.Inject
-class FtueAuthPhoneEntryFragment @Inject constructor(
- private val phoneNumberParser: PhoneNumberParser
-) : AbstractFtueAuthFragment() {
+@AndroidEntryPoint
+class FtueAuthPhoneEntryFragment :
+ AbstractFtueAuthFragment() {
+
+ @Inject lateinit var phoneNumberParser: PhoneNumberParser
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtuePhoneInputBinding {
return FragmentFtuePhoneInputBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordBreakerFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordBreakerFragment.kt
index 721423ecdf..0daf1b3c6f 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordBreakerFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordBreakerFragment.kt
@@ -39,7 +39,8 @@ data class FtueAuthResetPasswordBreakerArgument(
) : Parcelable
@AndroidEntryPoint
-class FtueAuthResetPasswordBreakerFragment : AbstractFtueAuthFragment() {
+class FtueAuthResetPasswordBreakerFragment :
+ AbstractFtueAuthFragment() {
@Inject lateinit var themeProvider: ThemeProvider
private val params: FtueAuthResetPasswordBreakerArgument by args()
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordEmailEntryFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordEmailEntryFragment.kt
index 5fa1a8ed82..51c73a40e3 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordEmailEntryFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordEmailEntryFragment.kt
@@ -33,7 +33,8 @@ import im.vector.app.features.onboarding.OnboardingAction
import im.vector.app.features.onboarding.OnboardingViewState
@AndroidEntryPoint
-class FtueAuthResetPasswordEmailEntryFragment : AbstractFtueAuthFragment() {
+class FtueAuthResetPasswordEmailEntryFragment :
+ AbstractFtueAuthFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueResetPasswordEmailInputBinding {
return FragmentFtueResetPasswordEmailInputBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordEntryFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordEntryFragment.kt
index 61826352bf..0b0e06a0b0 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordEntryFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordEntryFragment.kt
@@ -34,7 +34,8 @@ import im.vector.app.features.onboarding.OnboardingViewState
import org.matrix.android.sdk.api.failure.isMissingEmailVerification
@AndroidEntryPoint
-class FtueAuthResetPasswordEntryFragment : AbstractFtueAuthFragment() {
+class FtueAuthResetPasswordEntryFragment :
+ AbstractFtueAuthFragment() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueResetPasswordInputBinding {
return FragmentFtueResetPasswordInputBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordFragment.kt
index 9bef084750..376218d474 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordFragment.kt
@@ -22,6 +22,7 @@ import android.view.View
import android.view.ViewGroup
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.extensions.hideKeyboard
import im.vector.app.core.extensions.hidePassword
@@ -35,12 +36,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 FtueAuthResetPasswordFragment @Inject constructor() : AbstractFtueAuthFragment() {
+@AndroidEntryPoint
+class FtueAuthResetPasswordFragment :
+ AbstractFtueAuthFragment() {
// Show warning only once
private var showWarning = true
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordMailConfirmationFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordMailConfirmationFragment.kt
index 76fbae6f40..301ed4fd8b 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordMailConfirmationFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordMailConfirmationFragment.kt
@@ -21,17 +21,19 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.databinding.FragmentLoginResetPasswordMailConfirmationBinding
import im.vector.app.features.onboarding.OnboardingAction
import im.vector.app.features.onboarding.OnboardingViewState
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 FtueAuthResetPasswordMailConfirmationFragment @Inject constructor() : AbstractFtueAuthFragment