Browse Source

Merge branch 'develop' into feature/fga/improve_node_architecture

misc/jme/add-logging-to-state-machine
ganfra 2 years ago
parent
commit
ec1c84e058
  1. 9
      .github/renovate.json
  2. 4
      .github/workflows/build.yml
  3. 8
      .github/workflows/quality.yml
  4. 4
      .github/workflows/tests.yml
  5. 8
      .maestro/tests/account/login.yaml
  6. 5
      README.md
  7. 2
      app/build.gradle.kts
  8. 1
      changelog.d/132.bugfix
  9. 1
      changelog.d/133.bugfix
  10. 1
      changelog.d/182.bugfix
  11. 146
      docs/_developer_onboarding.md
  12. 21
      docs/screenshot_testing.md
  13. 6
      features/login/impl/build.gradle.kts
  14. 15
      features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt
  15. 40
      features/login/impl/src/main/kotlin/io/element/android/features/login/impl/error/ErrorFormatter.kt
  16. 27
      features/login/impl/src/main/kotlin/io/element/android/features/login/impl/root/LoginRootScreen.kt
  17. 98
      features/login/impl/src/test/kotlin/io/element/android/features/login/impl/error/ErrorFormatterTests.kt
  18. 37
      gradle/libs.versions.toml
  19. 8
      libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ConfirmationDialog.kt
  20. 14
      libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ErrorDialog.kt
  21. 2
      libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorsLight.kt
  22. 3
      libraries/matrix/api/build.gradle.kts
  23. 34
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/AuthErrorCode.kt
  24. 49
      libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/auth/AuthErrorCodeTests.kt
  25. 36
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt
  26. 1
      libraries/ui-strings/src/main/res/values-hu/strings.xml
  27. 1
      libraries/ui-strings/src/main/res/values-it/strings.xml
  28. 1850
      libraries/ui-strings/src/main/res/values-zh-rTW/strings.xml
  29. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Color_Material Design_DarkGrey,NEXUS_5,1.0,en].png
  30. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Color_Material Design_LightGrey,NEXUS_5,1.0,en].png
  31. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_Body Large,NEXUS_5,1.0,en].png
  32. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_Body1,NEXUS_5,1.0,en].png
  33. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_BodySmall,NEXUS_5,1.0,en].png
  34. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_H1,NEXUS_5,1.0,en].png
  35. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_Headline Large,NEXUS_5,1.0,en].png
  36. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_Headline Medium,NEXUS_5,1.0,en].png
  37. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_Headline Small,NEXUS_5,1.0,en].png
  38. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_bodyMedium,NEXUS_5,1.0,en].png
  39. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_titleMedium,NEXUS_5,1.0,en].png
  40. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_titleSmall,NEXUS_5,1.0,en].png
  41. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png
  42. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png
  43. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_2,NEXUS_5,1.0,en].png
  44. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_3,NEXUS_5,1.0,en].png
  45. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_4,NEXUS_5,1.0,en].png
  46. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_0,NEXUS_5,1,en].png
  47. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_0,NEXUS_5,1.0,en].png
  48. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_1,NEXUS_5,1,en].png
  49. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_1,NEXUS_5,1.0,en].png
  50. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_2,NEXUS_5,1,en].png
  51. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_2,NEXUS_5,1.0,en].png
  52. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_3,NEXUS_5,1,en].png
  53. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_3,NEXUS_5,1.0,en].png
  54. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_4,NEXUS_5,1,en].png
  55. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_4,NEXUS_5,1.0,en].png
  56. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_0,NEXUS_5,1.0,en].png
  57. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_1,NEXUS_5,1.0,en].png
  58. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_2,NEXUS_5,1.0,en].png
  59. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_3,NEXUS_5,1.0,en].png
  60. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_4,NEXUS_5,1.0,en].png
  61. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_5,NEXUS_5,1,en].png
  62. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_5,NEXUS_5,1.0,en].png
  63. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_0,NEXUS_5,1,en].png
  64. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_0,NEXUS_5,1.0,en].png
  65. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_1,NEXUS_5,1,en].png
  66. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_1,NEXUS_5,1.0,en].png
  67. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_2,NEXUS_5,1,en].png
  68. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_2,NEXUS_5,1.0,en].png
  69. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_3,NEXUS_5,1,en].png
  70. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_3,NEXUS_5,1.0,en].png
  71. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_4,NEXUS_5,1,en].png
  72. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_4,NEXUS_5,1.0,en].png
  73. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_5,NEXUS_5,1,en].png
  74. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_5,NEXUS_5,1.0,en].png
  75. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.logout_null_DefaultGroup_LogoutPreferenceViewDarkPreview_0_null,NEXUS_5,1.0,en].png
  76. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.logout_null_DefaultGroup_LogoutPreferenceViewLightPreview_0_null,NEXUS_5,1.0,en].png
  77. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_0,NEXUS_5,1.0,en].png
  78. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_1,NEXUS_5,1.0,en].png
  79. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_2,NEXUS_5,1.0,en].png
  80. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_0,NEXUS_5,1.0,en].png
  81. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_1,NEXUS_5,1.0,en].png
  82. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_2,NEXUS_5,1.0,en].png
  83. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.textcomposer_null_DefaultGroup_MessageComposerViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png
  84. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.textcomposer_null_DefaultGroup_MessageComposerViewLightPreview_0_null_0,NEXUS_5,1.0,en].png
  85. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemEncryptedViewDarkPreview_0_null,NEXUS_5,1.0,en].png
  86. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemEncryptedViewLightPreview_0_null,NEXUS_5,1.0,en].png
  87. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png
  88. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png
  89. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewDarkPreview_0_null_2,NEXUS_5,1.0,en].png
  90. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewLightPreview_0_null_0,NEXUS_5,1.0,en].png
  91. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewLightPreview_0_null_1,NEXUS_5,1.0,en].png
  92. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewLightPreview_0_null_2,NEXUS_5,1.0,en].png
  93. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemInformativeViewDarkPreview_0_null,NEXUS_5,1.0,en].png
  94. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemInformativeViewLightPreview_0_null,NEXUS_5,1.0,en].png
  95. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemRedactedViewDarkPreview_0_null,NEXUS_5,1.0,en].png
  96. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemRedactedViewLightPreview_0_null,NEXUS_5,1.0,en].png
  97. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemTextViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png
  98. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemTextViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png
  99. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemTextViewDarkPreview_0_null_2,NEXUS_5,1.0,en].png
  100. 0
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemTextViewDarkPreview_0_null_3,NEXUS_5,1.0,en].png
  101. Some files were not shown because too many files have changed in this diff Show More

9
.github/renovate.json

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base"
],
"labels": ["dependencies"],
"reviewers": ["team:element-x-android-reviewers"],
"ignoreDeps": ["string:app_name"]
}

4
.github/workflows/build.yml

@ -28,6 +28,10 @@ jobs: @@ -28,6 +28,10 @@ jobs:
# Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Configure gradle
uses: gradle/gradle-build-action@v2
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Assemble debug APK
run: ./gradlew assembleDebug $CI_GRADLE_ARG_PROPERTIES
- name: Upload debug APKs

8
.github/workflows/quality.yml

@ -21,6 +21,10 @@ jobs: @@ -21,6 +21,10 @@ jobs:
cancel-in-progress: true
steps:
- uses: actions/checkout@v3
- name: Configure gradle
uses: gradle/gradle-build-action@v2
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Run code quality check suite
run: ./gradlew runQualityChecks $CI_GRADLE_ARG_PROPERTIES
- name: Upload reports
@ -56,6 +60,10 @@ jobs: @@ -56,6 +60,10 @@ jobs:
cancel-in-progress: true
steps:
- uses: actions/checkout@v3
- name: Configure gradle
uses: gradle/gradle-build-action@v2
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Dependency analysis
run: ./gradlew dependencyCheckAnalyze $CI_GRADLE_ARG_PROPERTIES
- name: Upload dependency analysis

4
.github/workflows/tests.yml

@ -25,6 +25,10 @@ jobs: @@ -25,6 +25,10 @@ jobs:
uses: actions/checkout@v3
with:
lfs: 'true'
- name: Configure gradle
uses: gradle/gradle-build-action@v2
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Run unit & screenshot tests, generate kover report
run: ./gradlew koverMergedReport $CI_GRADLE_ARG_PROPERTIES -Pci-build=true

8
.maestro/tests/account/login.yaml

@ -9,9 +9,15 @@ appId: ${APP_ID} @@ -9,9 +9,15 @@ appId: ${APP_ID}
id: "login-email_username"
- inputText: ${USERNAME}
- pressKey: Enter
- tapOn: "Password"
- tapOn:
id: "login-password"
- inputText: "wrong-password"
- pressKey: Enter
- tapOn: "Continue"
- tapOn: "OK"
- tapOn:
id: "login-password"
- eraseText: 20
- inputText: ${PASSWORD}
- pressKey: Enter
- tapOn: "Continue"

5
README.md

@ -16,6 +16,7 @@ The application is a total rewrite of [Element-Android](https://github.com/vecto @@ -16,6 +16,7 @@ The application is a total rewrite of [Element-Android](https://github.com/vecto
* [Screenshots](#screenshots)
* [Rust SDK](#rust-sdk)
* [Status](#status)
* [Contributing](#contributing)
* [Build instructions](#build-instructions)
* [Support](#support)
@ -36,6 +37,10 @@ ElementX leverages the [Matrix Rust SDK](https://github.com/matrix-org/matrix-ru @@ -36,6 +37,10 @@ ElementX leverages the [Matrix Rust SDK](https://github.com/matrix-org/matrix-ru
We're doing this as a way to share code between platforms and while we've seen promising results it's still in the experimental stage and bound to change.
## Status
This project is in work in progress. The app does not cover yet all functionalities we expect.
## Contributing
Please see our [contribution guide](CONTRIBUTING.md).

2
app/build.gradle.kts

@ -29,7 +29,7 @@ plugins { @@ -29,7 +29,7 @@ plugins {
alias(libs.plugins.anvil)
alias(libs.plugins.ksp)
alias(libs.plugins.kapt)
id("com.google.firebase.appdistribution") version "3.0.2"
id("com.google.firebase.appdistribution") version "4.0.0"
id("org.jetbrains.kotlinx.knit") version "0.4.0"
id("kotlin-parcelize")
}

1
changelog.d/132.bugfix

@ -0,0 +1 @@ @@ -0,0 +1 @@
Use user friendly error messages in login following iOS logic, fix dialog colors.

1
changelog.d/133.bugfix

@ -0,0 +1 @@ @@ -0,0 +1 @@
Clear focus on TextFields when submitting forms to prevent issues with the IME keyboard.

1
changelog.d/182.bugfix

@ -0,0 +1 @@ @@ -0,0 +1 @@
Fix the case when a valid homeserver url can't be extracted from the MXID

146
docs/_developer_onboarding.md

@ -8,6 +8,9 @@ @@ -8,6 +8,9 @@
* [Room](#room)
* [Event](#event)
* [Sync](#sync)
* [Rust SDK](#rust-sdk)
* [Matrix Rust Component Kotlin](#matrix-rust-component-kotlin)
* [Build the SDK locally](#build-the-sdk-locally)
* [The Android project](#the-android-project)
* [Application](#application)
* [Jetpack Compose](#jetpack-compose)
@ -32,6 +35,7 @@ This doc is a quick introduction about the project and its architecture. @@ -32,6 +35,7 @@ This doc is a quick introduction about the project and its architecture.
It's aim is to help new developers to understand the overall project and where to start developing.
Other useful documentation:
- all the docs in this folder!
- the [contributing doc](../CONTRIBUTING.md), that you should also read carefully.
@ -39,11 +43,14 @@ Other useful documentation: @@ -39,11 +43,14 @@ Other useful documentation:
Matrix website: [matrix.org](https://matrix.org), [discover page](https://matrix.org/discover).
*Note*: Matrix.org is also hosting a homeserver ([.well-known file](https://matrix.org/.well-known/matrix/client)).
The reference homeserver (this is how Matrix servers are called) implementation is [Synapse](https://github.com/matrix-org/synapse/). But other implementations exist. The Matrix specification is here to ensure that any Matrix client, such as Element Android and its SDK can talk to any Matrix server.
The reference homeserver (this is how Matrix servers are called) implementation is [Synapse](https://github.com/matrix-org/synapse/). But other implementations
exist. The Matrix specification is here to ensure that any Matrix client, such as Element Android and its SDK can talk to any Matrix server.
Have a quick look to the client-server API documentation: [Client-server documentation](https://spec.matrix.org/v1.3/client-server-api/). Other network API exist, the list is here: (https://spec.matrix.org/latest/)
Have a quick look to the client-server API documentation: [Client-server documentation](https://spec.matrix.org/v1.3/client-server-api/). Other network API
exist, the list is here: (https://spec.matrix.org/latest/)
Matrix is an open source protocol. Change are possible and are tracked using [this GitHub repository](https://github.com/matrix-org/matrix-doc/). Changes to the protocol are called MSC: Matrix Spec Change. These are PullRequest to this project.
Matrix is an open source protocol. Change are possible and are tracked using [this GitHub repository](https://github.com/matrix-org/matrix-doc/). Changes to the
protocol are called MSC: Matrix Spec Change. These are PullRequest to this project.
Matrix object are Json data. Unstable prefixes must be used for Json keys when the MSC is not merged (i.e. accepted).
@ -53,7 +60,8 @@ There are many object and data in the Matrix worlds. Let's focus on the most imp @@ -53,7 +60,8 @@ There are many object and data in the Matrix worlds. Let's focus on the most imp
##### Room
`Room` is a place which contains ordered `Event`s. They are identified with their `room_id`. Nearly all the data are stored in rooms, and shared using homeserver to all the Room Member.
`Room` is a place which contains ordered `Event`s. They are identified with their `room_id`. Nearly all the data are stored in rooms, and shared using
homeserver to all the Room Member.
*Note*: Spaces are also Rooms with a different `type`.
@ -63,12 +71,14 @@ There are many object and data in the Matrix worlds. Let's focus on the most imp @@ -63,12 +71,14 @@ There are many object and data in the Matrix worlds. Let's focus on the most imp
There are 2 types of Room Event:
- Regular Events: contain useful content for the user (message, image, etc.), but are not necessarily displayed as this in the timeline (reaction, message edition, call signaling).
- Regular Events: contain useful content for the user (message, image, etc.), but are not necessarily displayed as this in the timeline (reaction, message
edition, call signaling).
- State Events: contain the state of the Room (name, topic, etc.). They have a non null value for the key `state_key`.
Also all the Room Member details are in State Events: one State Event per member. In this case, the `state_key` is the matrixId (= userId).
Important Fields of an Event:
- `event_id`: unique across the Matrix universe;
- `room_id`: the room the Event belongs to;
- `type`: describe what the Event contain, especially in the `content` section, and how the SDK should handle this Event;
@ -80,6 +90,77 @@ So we have a triple `event_id`, `type`, `state_key` which uniquely defines an Ev @@ -80,6 +90,77 @@ So we have a triple `event_id`, `type`, `state_key` which uniquely defines an Ev
This is managed by the Rust SDK.
### Rust SDK
The Rust SDK is hosted here: https://github.com/matrix-org/matrix-rust-sdk.
This repository contains an implementation of a Matrix client-server library written in Rust.
With some bindings we can embed this sdk inside other environments, like Swift or Kotlin, with the help of [Uniffi](https://github.com/mozilla/uniffi-rs).
From these kotlin bindings we can generate native libs (.so files) and kotlin classes/interfaces.
#### Matrix Rust Component Kotlin
To use these bindings in an android project, we need to wrap this up into an android library (as the form of an .aar file).
This is the goal of https://github.com/matrix-org/matrix-rust-components-kotlin.
This repository is used for distributing kotlin releases of the Matrix Rust SDK.
It'll provide the corresponding aar and also publish them on maven.
Most of the time you want to use the releases made on maven with gradle:
```groovy
implementation("org.matrix.rustcomponents:sdk-android:latest-version")
```
You can also have access to the aars through the [release](https://github.com/matrix-org/matrix-rust-components-kotlin/releases) page.
#### Build the SDK locally
If you need to locally build the sdk-android you can use
the [build](https://github.com/matrix-org/matrix-rust-components-kotlin/blob/main/scripts/build.sh) script.
For this, you first need to ensure to setup :
- rust environment (check https://rust-lang.github.io/rustup/ if needed)
- cargo-ndk < 2.12.0
```shell
cargo install cargo-ndk --version 2.11.0
```
- android targets
```shell
rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android i686-linux-android
```
- checkout both [matrix-rust-sdk](https://github.com/matrix-org/matrix-rust-sdk) and [matrix-rust-components-kotlin](https://github.com/matrix-org/matrix-rust-components-kotlin) repositories
```shell
git clone git@github.com:matrix-org/matrix-rust-sdk.git
git clone git@github.com:matrix-org/matrix-rust-components-kotlin.git
```
Then you can launch the build script with the following params:
- `-p` Local path to the rust-sdk repository
- `-o` Optional output path with the expected name of the aar file. By default the aar will be located in the corresponding build/outputs/aar directory.
- `-r` Flag to build in release mode
- `-m` Option to select the gradle module to build. Default is sdk.
- `-t` Option to to select an android target to build against. Default will build for all targets.
So for example to build the sdk against aarch64-linux-android target and copy the generated aar to ElementX project:
```shell
./scripts/build.sh -p [YOUR MATRIX RUST SDK PATH] -t aarch64-linux-android -o [YOUR element-x-android PATH]/libraries/rustsdk/matrix-rust-sdk.aar
```
Finally let the `matrix/impl` module use this aar by switching those lines in the gradle file :
```groovy
dependencies {
api(projects.libraries.rustsdk) // <- comment this line
// api(libs.matrix.sdk) // <- uncomment this line
}
```
You are good to test your local rust development now!
### The Android project
The project should compile out of the box.
@ -87,7 +168,7 @@ The project should compile out of the box. @@ -87,7 +168,7 @@ The project should compile out of the box.
This Android project is a multi modules project.
- `app` module is the Android application module. Other modules are libraries;
- `features` modules contain some UI and can be seen as screen or flow of screens of the application;
- `features` modules contain some UI and can be seen as screen or flow of screens of the application;
- `libraries` modules contain classes that can be useful for other modules to work.
A few details about some modules:
@ -107,7 +188,8 @@ Here is the current module dependency graph: @@ -107,7 +188,8 @@ Here is the current module dependency graph:
### Application
This Android project mainly handle the application layer of the whole software. The communication with the Matrix server, as well as the local storage, the cryptography (encryption and decryption of Event, key management, etc.) is managed by the Rust SDK.
This Android project mainly handle the application layer of the whole software. The communication with the Matrix server, as well as the local storage, the
cryptography (encryption and decryption of Event, key management, etc.) is managed by the Rust SDK.
The application is responsible to store the session credentials though.
@ -131,7 +213,8 @@ About Preview @@ -131,7 +213,8 @@ About Preview
Main libraries and frameworks used in this application:
- Navigation state with [Appyx](https://bumble-tech.github.io/appyx/). Please watch [this video](https://www.droidcon.com/2022/11/15/model-driven-navigation-with-appyx-from-zero-to-hero/) to learn more about Appyx!
- Navigation state with [Appyx](https://bumble-tech.github.io/appyx/). Please
watch [this video](https://www.droidcon.com/2022/11/15/model-driven-navigation-with-appyx-from-zero-to-hero/) to learn more about Appyx!
- DI: [Dagger](https://dagger.dev/) and [Anvil](https://github.com/square/anvil)
- Reactive State management with Compose runtime and [Molecule](https://github.com/cashapp/molecule)
@ -141,20 +224,22 @@ Here are the main points: @@ -141,20 +224,22 @@ Here are the main points:
1. `Presenter` and `View` does not communicate with each other directly, but through `State` and `Event`
2. Views are compose first
3. Presenters are also compose first, and have a single `present(): State` method. It's using the power of compose-runtime/compiler.
3. Presenters are also compose first, and have a single `present(): State` method. It's using the power of compose-runtime/compiler.
4. The point of connection between a `View` and a `Presenter` is a `Node`.
5. A `Node` is also responsible for managing Dagger components if any.
6. A `ParentNode` has some children `Node` and only know about them.
6. A `ParentNode` has some children `Node` and only know about them.
7. This is a single activity full compose application. The `MainActivity` is responsible for holding and configuring the `RootNode`.
8. There is no more needs for Android Architecture Component ViewModel as configuration change should be handled by Composable if needed.
#### Template and naming
There is a template module to easily start a new feature. When creating a new module, you can just copy paste the template. It is located [here](../features/template).
There is a template module to easily start a new feature. When creating a new module, you can just copy paste the template. It is
located [here](../features/template).
For the naming rules, please follow what is being currently used in the template module.
Note that naming of files and classes is important, since those names are used to set up code coverage rules. For instance, presenters MUST have a suffix `Presenter`,states MUST have a suffix `State`, etc. Also we want to have a common naming along all the modules.
Note that naming of files and classes is important, since those names are used to set up code coverage rules. For instance, presenters MUST have a
suffix `Presenter`,states MUST have a suffix `State`, etc. Also we want to have a common naming along all the modules.
### Push
@ -183,14 +268,21 @@ Some dependency, mainly because they are not shared can be declared in `build.gr @@ -183,14 +268,21 @@ Some dependency, mainly because they are not shared can be declared in `build.gr
We have 3 tests frameworks in place, and this should be sufficient to guarantee a good code coverage and limit regressions hopefully:
- Maestro to test the global usage of the application. See the related [documentation](../.maestro/README.md).
- Combination of [Showkase](https://github.com/airbnb/Showkase) and [Paparazzi](https://github.com/cashapp/paparazzi), to test UI pixel perfect. To add test, just add `@Preview` for the composable you are adding. See the related [documentation](screenshot_testing.md) and see in the template the file [TemplateView.kt](../features/template/src/main/kotlin/io/element/android/features/template/TemplateView.kt). We create PreviewProvider to provide different states. See for instance the file [TemplateStateProvider.kt](../features/template/src/main/kotlin/io/element/android/features/template/TemplateStateProvider.kt)
- Tests on presenter with [Molecule](https://github.com/cashapp/molecule) and [Turbine](https://github.com/cashapp/turbine). See in the template the class [TemplatePresenterTests](../features/template/src/test/kotlin/io/element/android/features/template/TemplatePresenterTests.kt).
- Combination of [Showkase](https://github.com/airbnb/Showkase) and [Paparazzi](https://github.com/cashapp/paparazzi), to test UI pixel perfect. To add test,
just add `@Preview` for the composable you are adding. See the related [documentation](screenshot_testing.md) and see in the template the
file [TemplateView.kt](../features/template/src/main/kotlin/io/element/android/features/template/TemplateView.kt). We create PreviewProvider to provide
different states. See for instance the
file [TemplateStateProvider.kt](../features/template/src/main/kotlin/io/element/android/features/template/TemplateStateProvider.kt)
- Tests on presenter with [Molecule](https://github.com/cashapp/molecule) and [Turbine](https://github.com/cashapp/turbine). See in the template the
class [TemplatePresenterTests](../features/template/src/test/kotlin/io/element/android/features/template/TemplatePresenterTests.kt).
**Note** For now we want to avoid using class mocking (with library such as *mockk*), because this should be not necessary. We prefer to create Fake implementation of our interfaces. Mocking can be used to mock Android framework classes though, such as `Bitmap` for instance.
**Note** For now we want to avoid using class mocking (with library such as *mockk*), because this should be not necessary. We prefer to create Fake
implementation of our interfaces. Mocking can be used to mock Android framework classes though, such as `Bitmap` for instance.
### Code coverage
[kover](https://github.com/Kotlin/kotlinx-kover) is used to compute code coverage. Only have unit tests can produce code coverage result. Running Maestro does not participate to the code coverage results.
[kover](https://github.com/Kotlin/kotlinx-kover) is used to compute code coverage. Only have unit tests can produce code coverage result. Running Maestro does
not participate to the code coverage results.
Kover configuration is defined in the main [build.gradle.kts](../build.gradle.kts) file.
@ -200,9 +292,9 @@ To compute the code coverage, run: @@ -200,9 +292,9 @@ To compute the code coverage, run:
./gradlew koverMergedReport
```
and open the Html report: [../build/reports/kover/merged/html/index.html](../build/reports/kover/merged/html/index.html)
and open the Html report: [../build/reports/kover/merged/html/index.html](../build/reports/kover/merged/html/index.html)
To ensure that the code coverage threshold are OK, you can run
To ensure that the code coverage threshold are OK, you can run
```bash
./gradlew koverMergedVerify
@ -210,13 +302,15 @@ To ensure that the code coverage threshold are OK, you can run @@ -210,13 +302,15 @@ To ensure that the code coverage threshold are OK, you can run
Note that the CI performs this check on every pull requests.
Also, if the rule `Global minimum code coverage.` is in error because code coverage is `> maxValue`, `minValue` and `maxValue` can be updated for this rule in the file [build.gradle.kts](../build.gradle.kts) (you will see further instructions there).
Also, if the rule `Global minimum code coverage.` is in error because code coverage is `> maxValue`, `minValue` and `maxValue` can be updated for this rule in
the file [build.gradle.kts](../build.gradle.kts) (you will see further instructions there).
### Other points
#### Logging
**Important warning: ** NEVER log private user data, or use the flag `LOG_PRIVATE_DATA`. Be very careful when logging `data class`, all the content will be output!
**Important warning: ** NEVER log private user data, or use the flag `LOG_PRIVATE_DATA`. Be very careful when logging `data class`, all the content will be
output!
[Timber](https://github.com/JakeWharton/timber) is used to log data to logcat. We do not use directly the `Log` class. If possible please use a tag, as per
@ -247,12 +341,16 @@ Rageshake can be very useful to get logs from a release version of the applicati @@ -247,12 +341,16 @@ Rageshake can be very useful to get logs from a release version of the applicati
### Tips
- Element Android has a `developer mode` in the `Settings/Advanced settings`. Other useful options are available here; (TODO Not supported yet!)
- Show hidden Events can also help to debug feature. When developer mode is enabled, it is possible to view the source (= the Json content) of any Events; (TODO Not supported yet!)
- Show hidden Events can also help to debug feature. When developer mode is enabled, it is possible to view the source (= the Json content) of any Events; (TODO
Not supported yet!)
- Type `/devtools` in a Room composer to access a developer menu. There are some other entry points. Developer mode has to be enabled; (TODO Not supported yet!)
- Hidden debug menu: when developer mode is enabled and on debug build, there are some extra screens that can be accessible using the green wheel. In those screens, it will be possible to toggle some feature flags; (TODO Not supported yet!)
- Using logcat, filtering with `Compositions` can help you to understand what screen are currently displayed on your device. Searching for string displayed on the screen can also help to find the running code in the codebase.
- Hidden debug menu: when developer mode is enabled and on debug build, there are some extra screens that can be accessible using the green wheel. In those
screens, it will be possible to toggle some feature flags; (TODO Not supported yet!)
- Using logcat, filtering with `Compositions` can help you to understand what screen are currently displayed on your device. Searching for string displayed on
the screen can also help to find the running code in the codebase.
- When this is possible, prefer using `sealed interface` instead of `sealed class`;
- When writing temporary code, using the string "DO NOT COMMIT" in a comment can help to avoid committing things by mistake. If committed and pushed, the CI will detect this String and will warn the user about it. (TODO Not supported yet!)
- When writing temporary code, using the string "DO NOT COMMIT" in a comment can help to avoid committing things by mistake. If committed and pushed, the CI
will detect this String and will warn the user about it. (TODO Not supported yet!)
## Happy coding!

21
docs/screenshot_testing.md

@ -21,22 +21,31 @@ @@ -21,22 +21,31 @@
- Install Git LFS through your package manager of choice (`brew install git-lfs` | `yay -S git-lfs`).
- Install the Git LFS hooks into the project.
```bash
```shell
# with element-android as the current working directory
git lfs install --local
```
- If installed correctly, `git push` and `git pull` will now include LFS content.
If installed correctly, `git push` and `git pull` will now include LFS content.
## Recording
- `./gradlew recordPaparazziDebug`
- Paparazzi will generate images in `:tests:uitests/src/test/snapshots`, which will need to be committed to the repository using Git LFS.
It's recommended to delete the content of the folder `/snapshots` before recording.
```shell
rm -rf ./tests/uitests/src/test/snapshots
./gradlew recordPaparazziDebug
```
Paparazzi will generate images in `:tests:uitests/src/test/snapshots`, which will need to be committed to the repository using Git LFS.
## Verifying
- `./gradlew verifyPaparazziDebug`
- In the case of failure, Paparazzi will generate images in `:tests:uitests/out/failure`. The images will show the expected and actual screenshots along with a delta of the two images.
```shell
./gradlew verifyPaparazziDebug
```
In the case of failure, Paparazzi will generate images in `:tests:uitests/out/failure`. The images will show the expected and actual screenshots along with a delta of the two images.
## Contributing

6
features/login/impl/build.gradle.kts

@ -25,6 +25,12 @@ plugins { @@ -25,6 +25,12 @@ plugins {
android {
namespace = "io.element.android.features.login.impl"
testOptions {
unitTests {
isIncludeAndroidResources = true
}
}
}
anvil {

15
features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt

@ -51,6 +51,7 @@ import androidx.compose.ui.tooling.preview.Preview @@ -51,6 +51,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.features.login.impl.R
import io.element.android.features.login.impl.error.changeServerError
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.designsystem.ElementTextStyles
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
@ -91,6 +92,14 @@ fun ChangeServerView( @@ -91,6 +92,14 @@ fun ChangeServerView(
}
}
val focusManager = LocalFocusManager.current
fun submit() {
// Clear focus to prevent keyboard issues with textfields
focusManager.clearFocus(force = true)
eventSink(ChangeServerEvents.Submit)
}
Scaffold(
topBar = {
TopAppBar(
@ -174,7 +183,7 @@ fun ChangeServerView( @@ -174,7 +183,7 @@ fun ChangeServerView(
imeAction = ImeAction.Done,
),
keyboardActions = KeyboardActions(
onDone = { eventSink(ChangeServerEvents.Submit) }
onDone = { submit() }
),
singleLine = true,
maxLines = 1,
@ -215,7 +224,7 @@ fun ChangeServerView( @@ -215,7 +224,7 @@ fun ChangeServerView(
)
Spacer(Modifier.height(32.dp))
Button(
onClick = { eventSink(ChangeServerEvents.Submit) },
onClick = ::submit,
enabled = interactionEnabled && state.submitEnabled,
modifier = Modifier
.fillMaxWidth()
@ -239,7 +248,7 @@ fun ChangeServerView( @@ -239,7 +248,7 @@ fun ChangeServerView(
@Composable
internal fun ChangeServerErrorDialog(error: Throwable, onDismiss: () -> Unit) {
ErrorDialog(
content = error.localizedMessage ?: stringResource(id = StringR.string.unknown_error),
content = stringResource(changeServerError(error)),
onDismiss = onDismiss
)
}

40
features/login/impl/src/main/kotlin/io/element/android/features/login/impl/error/ErrorFormatter.kt

@ -16,34 +16,28 @@ @@ -16,34 +16,28 @@
package io.element.android.features.login.impl.error
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import io.element.android.features.login.impl.root.LoginFormState
import io.element.android.libraries.core.uri.isValidUrl
import io.element.android.libraries.ui.strings.R as StringR
import io.element.android.libraries.matrix.api.auth.AuthErrorCode
import io.element.android.libraries.matrix.api.auth.errorCode
import org.matrix.rustcomponents.sdk.AuthenticationException
import io.element.android.libraries.ui.strings.R.string as StringR
@Composable
fun loginError(
data: LoginFormState,
throwable: Throwable?
): String {
return when {
data.login.isEmpty() -> "Please enter a login"
data.password.isEmpty() -> "Please enter a password"
throwable != null -> stringResource(id = StringR.string.auth_invalid_login_param)
else -> "No error provided"
throwable: Throwable
): Int {
val authException = throwable as? AuthenticationException ?: return StringR.unknown_error
return when (authException.errorCode) {
AuthErrorCode.FORBIDDEN -> StringR.auth_invalid_login_param
AuthErrorCode.USER_DEACTIVATED -> StringR.auth_invalid_login_deactivated_account
AuthErrorCode.UNKNOWN -> StringR.unknown_error
}
}
@Composable
fun changeServerError(
data: String,
throwable: Throwable?
): String {
return when {
data.isEmpty() -> "Please enter a server URL"
!data.isValidUrl() -> stringResource(id = StringR.string.login_error_invalid_home_server)
throwable != null -> "That server doesn’t seem right. Please check the address."
else -> "No error provided"
throwable: Throwable
): Int {
val authException = throwable as? AuthenticationException ?: return StringR.unknown_error
return when (authException) {
is AuthenticationException.InvalidServerName -> StringR.login_error_homeserver_not_found
else -> StringR.unknown_error
}
}

27
features/login/impl/src/main/kotlin/io/element/android/features/login/impl/root/LoginRootScreen.kt

@ -62,6 +62,7 @@ import androidx.compose.ui.text.style.TextAlign @@ -62,6 +62,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.features.login.error.loginError
import io.element.android.libraries.designsystem.ElementTextStyles
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
import io.element.android.libraries.designsystem.components.form.textFieldState
@ -153,6 +154,12 @@ fun LoginRootScreen( @@ -153,6 +154,12 @@ fun LoginRootScreen(
}
}
}
if (state.loggedInState is LoggedInState.ErrorLoggingIn) {
LoginErrorDialog(error = state.loggedInState.failure, onDismiss = {
state.eventSink(LoginRootEvents.ClearError)
})
}
}
@Composable
@ -216,6 +223,14 @@ internal fun LoginForm( @@ -216,6 +223,14 @@ internal fun LoginForm(
val focusManager = LocalFocusManager.current
val eventSink = state.eventSink
fun submit() {
// Clear focus to prevent keyboard issues with textfields
focusManager.clearFocus(force = true)
eventSink(LoginRootEvents.Submit)
}
Column(modifier) {
Text(
text = stringResource(StringR.string.login_form_title),
@ -294,22 +309,16 @@ internal fun LoginForm( @@ -294,22 +309,16 @@ internal fun LoginForm(
imeAction = ImeAction.Done,
),
keyboardActions = KeyboardActions(
onDone = { eventSink(LoginRootEvents.Submit) }
onDone = { submit() }
),
singleLine = true,
maxLines = 1,
)
if (state.loggedInState is LoggedInState.ErrorLoggingIn) {
LoginErrorDialog(error = state.loggedInState.failure, onDismiss = {
eventSink(LoginRootEvents.ClearError)
})
}
Spacer(Modifier.height(28.dp))
// Submit
Button(
onClick = { eventSink(LoginRootEvents.Submit) },
onClick = ::submit,
enabled = interactionEnabled && state.submitEnabled,
modifier = Modifier
.fillMaxWidth()
@ -323,7 +332,7 @@ internal fun LoginForm( @@ -323,7 +332,7 @@ internal fun LoginForm(
@Composable
internal fun LoginErrorDialog(error: Throwable, onDismiss: () -> Unit) {
ErrorDialog(
content = error.localizedMessage ?: stringResource(id = StringR.string.unknown_error),
content = stringResource(loginError(error)),
onDismiss = onDismiss
)
}

98
features/login/impl/src/test/kotlin/io/element/android/features/login/impl/error/ErrorFormatterTests.kt

@ -0,0 +1,98 @@ @@ -0,0 +1,98 @@
/*
* Copyright (c) 2023 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 io.element.android.features.login.impl.error
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.ui.strings.R
import org.junit.Test
import org.matrix.rustcomponents.sdk.AuthenticationException
class ErrorFormatterTests {
// region loginError
@Test
fun `loginError - invalid unknown error returns unknown error message`() {
val error = Throwable("Some unknown error")
assertThat(loginError(error)).isEqualTo(R.string.unknown_error)
}
@Test
fun `loginError - invalid auth error returns unknown error message`() {
val error = AuthenticationException.SlidingSyncNotAvailable("Some message. Also contains M_FORBIDDEN, but won't be parsed")
assertThat(loginError(error)).isEqualTo(R.string.unknown_error)
}
@Test
fun `loginError - unknown error returns unknown error message`() {
val error = AuthenticationException.Generic("M_UNKNOWN")
assertThat(loginError(error)).isEqualTo(R.string.unknown_error)
}
@Test
fun `loginError - forbidden error returns incorrect credentials message`() {
val error = AuthenticationException.Generic("M_FORBIDDEN")
assertThat(loginError(error)).isEqualTo(R.string.auth_invalid_login_param)
}
@Test
fun `loginError - user_deactivated error returns deactivated account message`() {
val error = AuthenticationException.Generic("M_USER_DEACTIVATED")
assertThat(loginError(error)).isEqualTo(R.string.auth_invalid_login_deactivated_account)
}
// endregion loginError
// region changeServerError
@Test
fun `changeServerError - invalid unknown error returns unknown error message`() {
val error = Throwable("Some unknown error")
assertThat(changeServerError(error)).isEqualTo(R.string.unknown_error)
}
@Test
fun `changeServerError - invalid auth error returns unknown error message`() {
val error = AuthenticationException.SlidingSyncNotAvailable("Some message. Also contains M_FORBIDDEN, but won't be parsed")
assertThat(changeServerError(error)).isEqualTo(R.string.unknown_error)
}
@Test
fun `changeServerError - unknown error returns unknown error message`() {
val error = AuthenticationException.Generic("M_UNKNOWN")
assertThat(changeServerError(error)).isEqualTo(R.string.unknown_error)
}
@Test
fun `changeServerError - forbidden error returns unknown error message`() {
val error = AuthenticationException.Generic("M_FORBIDDEN")
assertThat(changeServerError(error)).isEqualTo(R.string.unknown_error)
}
@Test
fun `changeServerError - user_deactivated error returns unknown error message`() {
val error = AuthenticationException.Generic("M_USER_DEACTIVATED")
assertThat(changeServerError(error)).isEqualTo(R.string.unknown_error)
}
@Test
fun `changeServerError - invalid server name error returns invalid server name error message`() {
val error = AuthenticationException.InvalidServerName("Server is not valid")
assertThat(changeServerError(error)).isEqualTo(R.string.login_error_homeserver_not_found)
}
// endregion changeServerError
}

37
gradle/libs.versions.toml

@ -3,11 +3,11 @@ @@ -3,11 +3,11 @@
[versions]
# Project
android_gradle_plugin = "7.4.1"
android_gradle_plugin = "7.4.2"
firebase_gradle_plugin = "3.2.0"
kotlin = "1.8.10"
ksp = "1.8.10-1.0.9"
molecule = "0.7.0"
molecule = "0.7.1"
# AndroidX
material = "1.8.0"
@ -27,30 +27,30 @@ composecompiler = "1.4.2" @@ -27,30 +27,30 @@ composecompiler = "1.4.2"
coroutines = "1.6.4"
# Accompanist
accompanist = "0.27.0"
accompanist = "0.28.0"
# Test
test_core = "1.4.0"
test_core = "1.5.0"
#other
coil = "2.2.2"
datetime = "0.4.0"
serialization_json = "1.4.1"
serialization_json = "1.5.0"
# Warning, also hard-coded in composeDependencies()
showkase = "1.0.0-beta17"
jsoup = "1.15.3"
appyx = "1.0.3"
dependencycheck = "7.4.4"
stem = "2.2.3"
jsoup = "1.15.4"
appyx = "1.0.5"
dependencycheck = "8.1.2"
stem = "2.3.0"
sqldelight = "1.5.5"
# DI
dagger = "2.44.2"
dagger = "2.45"
anvil = "2.4.4"
# quality
detekt = "1.22.0"
ktlint = "11.0.0"
ktlint = "11.3.1"
dependencygraph = "0.10"
[libraries]
@ -67,7 +67,6 @@ androidx_datastore_datastore = { module = "androidx.datastore:datastore", versio @@ -67,7 +67,6 @@ androidx_datastore_datastore = { module = "androidx.datastore:datastore", versio
androidx_constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "constraintlayout" }
androidx_recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "recyclerview" }
androidx_lifecycle_runtime = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle" }
androidx_lifecycle_compose = { module = "androidx.lifecycle:compose", version.ref = "lifecycle" }
androidx_lifecycle_process = { module = "androidx.lifecycle:lifecycle-process", version.ref = "lifecycle" }
androidx_splash = "androidx.core:core-splashscreen:1.0.0"
androidx_security_crypto = "androidx.security:security-crypto:1.0.0"
@ -98,16 +97,16 @@ squareup_seismic = "com.squareup:seismic:1.0.3" @@ -98,16 +97,16 @@ squareup_seismic = "com.squareup:seismic:1.0.3"
test_core = { module = "androidx.test:core", version.ref = "test_core" }
test_corektx = { module = "androidx.test:core-ktx", version.ref = "test_core" }
test_junit = "junit:junit:4.13.2"
test_runner = "androidx.test:runner:1.4.0"
test_runner = "androidx.test:runner:1.5.2"
test_uiautomator = "androidx.test.uiautomator:uiautomator:2.2.0"
test_junitext = "androidx.test.ext:junit:1.1.3"
test_junitext = "androidx.test.ext:junit:1.1.5"
test_mockk = "io.mockk:mockk:1.13.4"
test_barista = "com.adevinta.android:barista:4.2.0"
test_barista = "com.adevinta.android:barista:4.3.0"
test_hamcrest = "org.hamcrest:hamcrest:2.2"
test_orchestrator = "androidx.test:orchestrator:1.4.1"
test_orchestrator = "androidx.test:orchestrator:1.4.2"
test_turbine = "app.cash.turbine:turbine:0.12.1"
test_truth = "com.google.truth:truth:1.1.3"
test_parameter_injector = "com.google.testparameterinjector:test-parameter-injector:1.8"
test_parameter_injector = "com.google.testparameterinjector:test-parameter-injector:1.10"
# Others
coil = { module = "io.coil-kt:coil", version.ref = "coil" }
@ -135,7 +134,7 @@ anvil_compiler_api = { module = "com.squareup.anvil:compiler-api", version.ref = @@ -135,7 +134,7 @@ anvil_compiler_api = { module = "com.squareup.anvil:compiler-api", version.ref =
anvil_compiler_utils = { module = "com.squareup.anvil:compiler-utils", version.ref = "anvil" }
# Composer
wysiwyg = "io.element.android:wysiwyg:0.7.0.1"
wysiwyg = "io.element.android:wysiwyg:1.1.1"
[bundles]
@ -154,6 +153,6 @@ dependencycheck = { id = "org.owasp.dependencycheck", version.ref = "dependencyc @@ -154,6 +153,6 @@ dependencycheck = { id = "org.owasp.dependencycheck", version.ref = "dependencyc
stem = { id = "com.likethesalad.stem", version.ref = "stem" }
stemlibrary = { id = "com.likethesalad.stem-library", version.ref = "stem" }
paparazzi = "app.cash.paparazzi:1.2.0"
sonarqube = "org.sonarqube:3.5.0.2730"
sonarqube = "org.sonarqube:4.0.0.2929"
kover = "org.jetbrains.kotlinx.kover:0.6.1"
sqldelight = { id = "com.squareup.sqldelight", version.ref = "sqldelight" }

8
libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ConfirmationDialog.kt

@ -48,10 +48,10 @@ fun ConfirmationDialog( @@ -48,10 +48,10 @@ fun ConfirmationDialog(
onThirdButtonClicked: () -> Unit = {},
onDismiss: () -> Unit = {},
shape: Shape = AlertDialogDefaults.shape,
containerColor: Color = MaterialTheme.colorScheme.surfaceVariant,
iconContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
titleContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
textContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
containerColor: Color = AlertDialogDefaults.containerColor,
iconContentColor: Color = AlertDialogDefaults.iconContentColor,
titleContentColor: Color = AlertDialogDefaults.titleContentColor,
textContentColor: Color = AlertDialogDefaults.textContentColor,
tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
) {
AlertDialog(

14
libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ErrorDialog.kt

@ -16,10 +16,6 @@ @@ -16,10 +16,6 @@
package io.element.android.libraries.designsystem.components.dialogs
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.AlertDialogDefaults
import androidx.compose.material3.MaterialTheme
@ -31,10 +27,8 @@ import androidx.compose.ui.graphics.Shape @@ -31,10 +27,8 @@ import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.ui.strings.R as StringR
@ -46,10 +40,10 @@ fun ErrorDialog( @@ -46,10 +40,10 @@ fun ErrorDialog(
submitText: String = stringResource(id = StringR.string.ok),
onDismiss: () -> Unit = {},
shape: Shape = AlertDialogDefaults.shape,
containerColor: Color = MaterialTheme.colorScheme.surfaceVariant,
iconContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
titleContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
textContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
containerColor: Color = AlertDialogDefaults.containerColor,
iconContentColor: Color = AlertDialogDefaults.iconContentColor,
titleContentColor: Color = AlertDialogDefaults.titleContentColor,
textContentColor: Color = AlertDialogDefaults.textContentColor,
tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
) {
AlertDialog(

2
libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorsLight.kt

@ -60,7 +60,7 @@ val materialColorSchemeLight = lightColorScheme( @@ -60,7 +60,7 @@ val materialColorSchemeLight = lightColorScheme(
surface = Color.White,
onSurface = Color.Black,
surfaceVariant = Gray_25,
onSurfaceVariant = Gray_150,
onSurfaceVariant = Gray_200,
// TODO surfaceTint = primary,
// TODO inverseSurface = ColorLightTokens.InverseSurface,
// TODO inverseOnSurface = ColorLightTokens.InverseOnSurface,

3
libraries/matrix/api/build.gradle.kts

@ -41,4 +41,7 @@ dependencies { @@ -41,4 +41,7 @@ dependencies {
implementation(libs.serialization.json)
api(projects.libraries.sessionStorage.api)
implementation(libs.coroutines.core)
testImplementation(libs.test.junit)
testImplementation(libs.test.truth)
}

34
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/AuthErrorCode.kt

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
/*
* Copyright (c) 2023 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 io.element.android.libraries.matrix.api.auth
import org.matrix.rustcomponents.sdk.AuthenticationException
enum class AuthErrorCode(val value: String) {
UNKNOWN("M_UNKNOWN"),
USER_DEACTIVATED("M_USER_DEACTIVATED"),
FORBIDDEN("M_FORBIDDEN")
}
// This is taken from the iOS version. It seems like currently there's no better way to extract error codes
val AuthenticationException.errorCode: AuthErrorCode
get() {
val message = (this as? AuthenticationException.Generic)?.message ?: return AuthErrorCode.UNKNOWN
return enumValues<AuthErrorCode>()
.firstOrNull { message.contains(it.value) }
?: AuthErrorCode.UNKNOWN
}

49
libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/auth/AuthErrorCodeTests.kt

@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
/*
* Copyright (c) 2023 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 io.element.android.libraries.matrix.api.auth
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.matrix.rustcomponents.sdk.AuthenticationException
class AuthErrorCodeTests {
@Test
fun `errorCode finds UNKNOWN code`() {
val error = AuthenticationException.Generic("M_UNKNOWN")
assertThat(error.errorCode).isEqualTo(AuthErrorCode.UNKNOWN)
}
@Test
fun `errorCode finds USER_DEACTIVATED code`() {
val error = AuthenticationException.Generic("M_USER_DEACTIVATED")
assertThat(error.errorCode).isEqualTo(AuthErrorCode.USER_DEACTIVATED)
}
@Test
fun `errorCode finds FORBIDDEN code`() {
val error = AuthenticationException.Generic("M_FORBIDDEN")
assertThat(error.errorCode).isEqualTo(AuthErrorCode.FORBIDDEN)
}
@Test
fun `errorCode cannot find code so it returns UNKNOWN`() {
val error = AuthenticationException.Generic("Some other error")
assertThat(error.errorCode).isEqualTo(AuthErrorCode.UNKNOWN)
}
}

36
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt

@ -38,6 +38,7 @@ import org.matrix.rustcomponents.sdk.AuthenticationService @@ -38,6 +38,7 @@ import org.matrix.rustcomponents.sdk.AuthenticationService
import org.matrix.rustcomponents.sdk.Client
import org.matrix.rustcomponents.sdk.ClientBuilder
import org.matrix.rustcomponents.sdk.Session
import org.matrix.rustcomponents.sdk.use
import timber.log.Timber
import java.io.File
import javax.inject.Inject
@ -63,22 +64,21 @@ class RustMatrixAuthenticationService @Inject constructor( @@ -63,22 +64,21 @@ class RustMatrixAuthenticationService @Inject constructor(
}
override suspend fun restoreSession(sessionId: SessionId) = withContext(coroutineDispatchers.io) {
sessionStore.getSession(sessionId.value)
?.let { sessionData ->
try {
ClientBuilder()
.basePath(baseDirectory.absolutePath)
.username(sessionData.userId)
.build().apply {
restoreSession(sessionData.toSession())
}
} catch (throwable: Throwable) {
logError(throwable)
null
}
}?.let {
createMatrixClient(it)
val sessionData = sessionStore.getSession(sessionId.value)
if (sessionData != null) {
try {
val client = ClientBuilder()
.basePath(baseDirectory.absolutePath)
.homeserverUrl(sessionData.homeserverUrl)
.username(sessionData.userId)
.use { it.build() }
client.restoreSession(sessionData.toSession())
createMatrixClient(client)
} catch (throwable: Throwable) {
logError(throwable)
null
}
} else null
}
override fun getHomeserverDetails(): StateFlow<MatrixHomeServerDetails?> = currentHomeserver
@ -101,9 +101,9 @@ class RustMatrixAuthenticationService @Inject constructor( @@ -101,9 +101,9 @@ class RustMatrixAuthenticationService @Inject constructor(
Timber.e(failure, "Fail login")
throw failure
}
val session = client.session()
sessionStore.storeData(session.toSessionData())
SessionId(session.userId)
val sessionData = client.use { it.session().toSessionData() }
sessionStore.storeData(sessionData)
SessionId(sessionData.userId)
}
private fun createMatrixClient(client: Client): MatrixClient {

1
libraries/ui-strings/src/main/res/values-hu/strings.xml

@ -2928,4 +2928,5 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze @@ -2928,4 +2928,5 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze
<string name="error_voice_broadcast_unable_to_decrypt">A hang közvetítés nem fejthető vissza.</string>
<string name="settings_external_account_management">A fiókadatok külön vannak kezelve itt: %1$s.</string>
<string name="settings_external_account_management_title">Fiók</string>
<string name="settings_notification_error_on_update">Hiba történt az értesítések beállításának frissítésekor. Próbáld újra.</string>
</resources>

1
libraries/ui-strings/src/main/res/values-it/strings.xml

@ -2919,4 +2919,5 @@ @@ -2919,4 +2919,5 @@
<string name="error_voice_broadcast_unable_to_decrypt">Impossibile decifrare questa trasmissione vocale.</string>
<string name="settings_external_account_management">I dettagli del tuo account sono gestiti separatamente su %1$s.</string>
<string name="settings_external_account_management_title">Account</string>
<string name="settings_notification_error_on_update">Si è verificato un errore aggiornando le tue preferenze di notifica. Riprova.</string>
</resources>

1850
libraries/ui-strings/src/main/res/values-zh-rTW/strings.xml

File diff suppressed because it is too large Load Diff

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Color_Material Design_DarkGrey,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Color_Material Design_DarkGrey,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Color_Material Design_LightGrey,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Color_Material Design_LightGrey,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_Body Large,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_Body Large,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_Body1,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_Body1,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_BodySmall,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_BodySmall,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_H1,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_H1,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_Headline Large,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_Headline Large,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_Headline Medium,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_Headline Medium,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_Headline Small,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_Headline Small,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_bodyMedium,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_bodyMedium,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_titleMedium,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_titleMedium,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_titleSmall,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[Typo_Element_titleSmall,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_0,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_1,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_2,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_2,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_3,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_3,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_4,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_4,NEXUS_5,1.0,en].png

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_0,NEXUS_5,1,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_0,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_1,NEXUS_5,1,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_1,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_2,NEXUS_5,1,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_2,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_3,NEXUS_5,1,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_3,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_4,NEXUS_5,1,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_4,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_0,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_0,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_1,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_1,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_2,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_2,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_3,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_3,NEXUS_5,1.0,en].png

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_4,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_5,NEXUS_5,1,en].png (Stored with Git LFS)

Binary file not shown.

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_4,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_5,NEXUS_5,1.0,en].png

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_0,NEXUS_5,1,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_0,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_1,NEXUS_5,1,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_1,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_2,NEXUS_5,1,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_2,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_3,NEXUS_5,1,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_3,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_4,NEXUS_5,1,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_4,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_5,NEXUS_5,1,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_5,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.logout_null_DefaultGroup_LogoutPreferenceViewDarkPreview_0_null,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.logout_null_DefaultGroup_LogoutPreferenceViewDarkPreview_0_null,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.logout_null_DefaultGroup_LogoutPreferenceViewLightPreview_0_null,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.logout_null_DefaultGroup_LogoutPreferenceViewLightPreview_0_null,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_0,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_0,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_1,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_1,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_2,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_2,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_0,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_0,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_1,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_1,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_2,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_2,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.textcomposer_null_DefaultGroup_MessageComposerViewDarkPreview_0_null_0,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.textcomposer_null_DefaultGroup_MessageComposerViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.textcomposer_null_DefaultGroup_MessageComposerViewLightPreview_0_null_0,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.textcomposer_null_DefaultGroup_MessageComposerViewLightPreview_0_null_0,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemEncryptedViewDarkPreview_0_null,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemEncryptedViewDarkPreview_0_null,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemEncryptedViewLightPreview_0_null,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemEncryptedViewLightPreview_0_null,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewDarkPreview_0_null_0,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewDarkPreview_0_null_1,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewDarkPreview_0_null_2,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewDarkPreview_0_null_2,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewLightPreview_0_null_0,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewLightPreview_0_null_0,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewLightPreview_0_null_1,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewLightPreview_0_null_1,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewLightPreview_0_null_2,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemImageViewLightPreview_0_null_2,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemInformativeViewDarkPreview_0_null,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemInformativeViewDarkPreview_0_null,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemInformativeViewLightPreview_0_null,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemInformativeViewLightPreview_0_null,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemRedactedViewDarkPreview_0_null,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemRedactedViewDarkPreview_0_null,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemRedactedViewLightPreview_0_null,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemRedactedViewLightPreview_0_null,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemTextViewDarkPreview_0_null_0,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemTextViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemTextViewDarkPreview_0_null_1,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemTextViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemTextViewDarkPreview_0_null_2,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemTextViewDarkPreview_0_null_2,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemTextViewDarkPreview_0_null_3,NEXUS_5,1,en].png → tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.timeline.components.event_null_DefaultGroup_TimelineItemTextViewDarkPreview_0_null_3,NEXUS_5,1.0,en].png

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save