Merge branch 'release/0.4.3'
This commit is contained in:
commit
488c2361be
1654 changed files with 7418 additions and 4744 deletions
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
|
@ -38,7 +38,7 @@ jobs:
|
|||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '17'
|
||||
- name: Configure gradle
|
||||
uses: gradle/gradle-build-action@v2.12.0
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
with:
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||
- name: Assemble debug APK
|
||||
|
|
|
|||
3
.github/workflows/fork-pr-notice.yml
vendored
3
.github/workflows/fork-pr-notice.yml
vendored
|
|
@ -11,7 +11,8 @@ jobs:
|
|||
welcome:
|
||||
runs-on: ubuntu-latest
|
||||
name: Welcome comment
|
||||
if: github.event.pull_request.fork != null
|
||||
# Only display it if base repo (upstream) is different from HEAD repo (possibly a fork)
|
||||
if: github.event.pull_request.base.repo.full_name != github.event.pull_request.head.repo.full_name
|
||||
steps:
|
||||
- name: Add auto-generated commit warning
|
||||
uses: actions/github-script@v7
|
||||
|
|
|
|||
2
.github/workflows/nightlyReports.yml
vendored
2
.github/workflows/nightlyReports.yml
vendored
|
|
@ -62,7 +62,7 @@ jobs:
|
|||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '17'
|
||||
- name: Configure gradle
|
||||
uses: gradle/gradle-build-action@v2.12.0
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
with:
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||
- name: Dependency analysis
|
||||
|
|
|
|||
2
.github/workflows/quality.yml
vendored
2
.github/workflows/quality.yml
vendored
|
|
@ -40,7 +40,7 @@ jobs:
|
|||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '17'
|
||||
- name: Configure gradle
|
||||
uses: gradle/gradle-build-action@v2.12.0
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
with:
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||
- name: Run code quality check suite
|
||||
|
|
|
|||
2
.github/workflows/recordScreenshots.yml
vendored
2
.github/workflows/recordScreenshots.yml
vendored
|
|
@ -39,7 +39,7 @@ jobs:
|
|||
java-version: '17'
|
||||
# Add gradle cache, this should speed up the process
|
||||
- name: Configure gradle
|
||||
uses: gradle/gradle-build-action@v2.12.0
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
with:
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||
- name: Record screenshots
|
||||
|
|
|
|||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
|
@ -25,7 +25,7 @@ jobs:
|
|||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '17'
|
||||
- name: Configure gradle
|
||||
uses: gradle/gradle-build-action@v2.12.0
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
- name: Create app bundle
|
||||
env:
|
||||
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
||||
|
|
|
|||
2
.github/workflows/sonar.yml
vendored
2
.github/workflows/sonar.yml
vendored
|
|
@ -32,7 +32,7 @@ jobs:
|
|||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '17'
|
||||
- name: Configure gradle
|
||||
uses: gradle/gradle-build-action@v2.12.0
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
with:
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||
- name: 🔊 Publish results to Sonar
|
||||
|
|
|
|||
2
.github/workflows/sync-localazy.yml
vendored
2
.github/workflows/sync-localazy.yml
vendored
|
|
@ -24,7 +24,7 @@ jobs:
|
|||
- name: Run Localazy script
|
||||
run: ./tools/localazy/downloadStrings.sh --all
|
||||
- name: Create Pull Request for Strings
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
token: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
||||
commit-message: Sync Strings from Localazy
|
||||
|
|
|
|||
2
.github/workflows/sync-sas-strings.yml
vendored
2
.github/workflows/sync-sas-strings.yml
vendored
|
|
@ -23,7 +23,7 @@ jobs:
|
|||
- name: Run SAS String script
|
||||
run: ./tools/sas/import_sas_strings.py
|
||||
- name: Create Pull Request for SAS Strings
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
commit-message: Sync SAS Strings
|
||||
title: Sync SAS Strings
|
||||
|
|
|
|||
11
.github/workflows/tests.yml
vendored
11
.github/workflows/tests.yml
vendored
|
|
@ -44,7 +44,7 @@ jobs:
|
|||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '17'
|
||||
- name: Configure gradle
|
||||
uses: gradle/gradle-build-action@v2.12.0
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
with:
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||
|
||||
|
|
@ -81,6 +81,9 @@ jobs:
|
|||
# https://github.com/codecov/codecov-action
|
||||
- name: ☂️ Upload coverage reports to codecov
|
||||
if: always()
|
||||
uses: codecov/codecov-action@v3
|
||||
# with:
|
||||
# files: build/reports/kover/xml/report.xml
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
fail_ci_if_error: true
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
# with:
|
||||
# files: build/reports/kover/xml/report.xml
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ appId: ${APP_ID}
|
|||
# Back from timeline
|
||||
- back
|
||||
- assertVisible: "MyR"
|
||||
- hideKeyboard
|
||||
# Back from search
|
||||
- back
|
||||
- runFlow: ../assertions/assertHomeDisplayed.yaml
|
||||
|
|
|
|||
31
CHANGES.md
31
CHANGES.md
|
|
@ -1,3 +1,34 @@
|
|||
Changes in Element X v0.4.3 (2024-02-14)
|
||||
========================================
|
||||
|
||||
Features ✨
|
||||
----------
|
||||
- Change "Read receipts" advanced setting used to send private Read Receipt to "Share presence" settings. When disabled, private Read Receipts will be sent, and no typing notification will be sent. Also Read Receipts and typing notifications will not be rendered in the timeline. ([#2241](https://github.com/element-hq/element-x-android/issues/2241))
|
||||
- Render typing notifications. ([#2242](https://github.com/element-hq/element-x-android/issues/2242))
|
||||
- Manually mark a room as unread. ([#2261](https://github.com/element-hq/element-x-android/issues/2261))
|
||||
- Add empty state to the room list. ([#2330](https://github.com/element-hq/element-x-android/issues/2330))
|
||||
- Allow joining unencrypted video calls in non encrypted rooms. ([#2333](https://github.com/element-hq/element-x-android/issues/2333))
|
||||
|
||||
Bugfixes 🐛
|
||||
----------
|
||||
- Fix crash after unregistering UnifiedPush distributor ([#2304](https://github.com/element-hq/element-x-android/issues/2304))
|
||||
- Add missing device id to settings screen. ([#2316](https://github.com/element-hq/element-x-android/issues/2316))
|
||||
- Open the keyboard (and keep it opened) when creating a poll. ([#2329](https://github.com/element-hq/element-x-android/issues/2329))
|
||||
- Fix message forwarding after SDK API change related to Timeline intitialization.
|
||||
|
||||
Other changes
|
||||
-------------
|
||||
- Adjusted the login flow buttons so the continue button is always at the same height ([#825](https://github.com/element-hq/element-x-android/issues/825))
|
||||
- Move migration screen to within the room list ([#2310](https://github.com/element-hq/element-x-android/issues/2310))
|
||||
- Render correctly in reply to data when Event cannot be decrypted or has been redacted ([#2318](https://github.com/element-hq/element-x-android/issues/2318))
|
||||
- Remove Compose Foundation version pinning workaround. This was done to avoid a bug introduced in the default foundation version used by the material3 library, but that has already been fixed.
|
||||
- Remove `FilterHiddenStateEventsProcessor`, as this is already handled by the Rust SDK.
|
||||
- Remove session preferences on user log out.
|
||||
|
||||
Breaking changes 🚨
|
||||
-------------------
|
||||
- Update Compound icons in the project. Since the icon prefix changed to `ic_compound_` and the `CompoundIcons` helper now contains the vector icons as composable functions.
|
||||
|
||||
Changes in Element X v0.4.2 (2024-01-31)
|
||||
========================================
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
Please read https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.md
|
||||
|
||||
Element X Android support can be found in this room: [](https://matrix.to/#/#element-android:matrix.org).
|
||||
Element X Android support can be found in this room: [](https://matrix.to/#/#element-x-android:matrix.org).
|
||||
|
||||
The rest of the document contains specific rules for Matrix Android projects
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
[](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android)
|
||||
[](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android)
|
||||
[](https://codecov.io/github/vector-im/element-x-android)
|
||||
[](https://matrix.to/#/#element-x-android:matrix.org)
|
||||
[](https://matrix.to/#/#element-x-android:matrix.org)
|
||||
[](https://localazy.com/p/element)
|
||||
|
||||
# Element X Android
|
||||
|
|
|
|||
|
|
@ -35,10 +35,8 @@ import io.element.android.x.R
|
|||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun IconPreview(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(modifier = modifier) {
|
||||
internal fun IconPreview() {
|
||||
Box {
|
||||
Image(painter = painterResource(id = R.mipmap.ic_launcher_background), contentDescription = null)
|
||||
Image(painter = painterResource(id = R.mipmap.ic_launcher_foreground), contentDescription = null)
|
||||
}
|
||||
|
|
@ -46,10 +44,8 @@ internal fun IconPreview(
|
|||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun RoundIconPreview(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(modifier = modifier.clip(shape = CircleShape)) {
|
||||
internal fun RoundIconPreview() {
|
||||
Box(modifier = Modifier.clip(shape = CircleShape)) {
|
||||
Image(painter = painterResource(id = R.mipmap.ic_launcher_background), contentDescription = null)
|
||||
Image(painter = painterResource(id = R.mipmap.ic_launcher_foreground), contentDescription = null)
|
||||
}
|
||||
|
|
@ -57,11 +53,9 @@ internal fun RoundIconPreview(
|
|||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun MonochromeIconPreview(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
internal fun MonochromeIconPreview() {
|
||||
Box(
|
||||
modifier = modifier
|
||||
modifier = Modifier
|
||||
.size(108.dp)
|
||||
.background(Color(0xFF2F3133))
|
||||
.clip(shape = RoundedCornerShape(32.dp)),
|
||||
|
|
|
|||
|
|
@ -84,10 +84,8 @@ fun LoadingRoomNodeView(
|
|||
@Composable
|
||||
private fun LoadingRoomTopBar(
|
||||
onBackClicked: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
TopAppBar(
|
||||
modifier = modifier,
|
||||
navigationIcon = {
|
||||
BackButton(onClick = onBackClicked)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import io.element.android.features.rageshake.test.crash.FakeCrashDataStore
|
|||
import io.element.android.features.rageshake.test.rageshake.FakeRageShake
|
||||
import io.element.android.features.rageshake.test.rageshake.FakeRageshakeDataStore
|
||||
import io.element.android.features.rageshake.test.screenshot.FakeScreenshotHolder
|
||||
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
||||
import io.element.android.services.apperror.api.AppErrorState
|
||||
import io.element.android.services.apperror.api.AppErrorStateService
|
||||
import io.element.android.services.apperror.impl.DefaultAppErrorStateService
|
||||
|
|
@ -83,6 +84,7 @@ class RootPresenterTest {
|
|||
val rageshake = FakeRageShake()
|
||||
val screenshotHolder = FakeScreenshotHolder()
|
||||
val crashDetectionPresenter = DefaultCrashDetectionPresenter(
|
||||
buildMeta = aBuildMeta(),
|
||||
crashDataStore = crashDataStore
|
||||
)
|
||||
val rageshakeDetectionPresenter = DefaultRageshakeDetectionPresenter(
|
||||
|
|
|
|||
|
|
@ -4,13 +4,43 @@ This document explains how to install Element X Android from a Github Release.
|
|||
|
||||
<!--- TOC -->
|
||||
|
||||
* [Requirements](#requirements)
|
||||
* [Steps](#steps)
|
||||
* [I already have the application on my phone](#i-already-have-the-application-on-my-phone)
|
||||
* [Installing the universal APK](#installing-the-universal-apk)
|
||||
* [Instructions](#instructions)
|
||||
* [Steps](#steps)
|
||||
* [I already have the application on my phone](#i-already-have-the-application-on-my-phone)
|
||||
* [Installing from the App Bundle](#installing-from-the-app-bundle)
|
||||
* [Requirements](#requirements)
|
||||
* [Steps](#steps)
|
||||
* [I already have the application on my phone](#i-already-have-the-application-on-my-phone)
|
||||
|
||||
<!--- END -->
|
||||
|
||||
## Requirements
|
||||
## Installing the universal APK
|
||||
|
||||
### Instructions
|
||||
|
||||
The easiest way to install the application from a GitHub release is to use the universal APK which is attached to the release. This APK is compatible with all Android devices, but it is not optimized for any of them. So it may not be as fast as it could be on your device, and it may not be as small as it could be.
|
||||
|
||||
Alternatively, you can generate an APK that is optimized for your device. This is explained in the next section.
|
||||
|
||||
### Steps
|
||||
|
||||
- Open the GitHub release that you want to install from using the Web browser of your phone.
|
||||
- Download the APK
|
||||
- Open the APK file from the download notification, or from the file manager
|
||||
- Follow the steps to install the application
|
||||
|
||||
### I already have the application on my phone
|
||||
|
||||
If the application was already installed on your phone, there are several cases:
|
||||
|
||||
- it was installed from the PlayStore, you can install the universal APK as long as the version is more recent. The existing data should not be lost.
|
||||
- it was installed from a previous GitHub release, this is like an application upgrade.
|
||||
- it was installed from a more recent GitHub release, or from the PlayStore with a later version, you will have to uninstall it first.
|
||||
|
||||
## Installing from the App Bundle
|
||||
|
||||
### Requirements
|
||||
|
||||
The Github release will contain an Android App Bundle (with `aab` extension) file, unlike in the Element Android project where releases directly provide the APKs. So there are some steps to perform to generate and sign App Bundle APKs. An APK suitable for the targeted device will then be generated.
|
||||
|
||||
|
|
@ -31,7 +61,7 @@ You will also need to install [bundletool](https://developer.android.com/studio/
|
|||
brew install bundletool
|
||||
```
|
||||
|
||||
## Steps
|
||||
### Steps
|
||||
|
||||
1. Open the GitHub release that you want to install from https://github.com/element-hq/element-x-android/releases
|
||||
2. Download the asset `app-release-signed.aab`
|
||||
|
|
@ -55,7 +85,7 @@ bundletool install-apks --apks=./tmp/elementx.apks
|
|||
|
||||
That's it, the application should be installed on your device, you can start it from the launcher icon.
|
||||
|
||||
## I already have the application on my phone
|
||||
### I already have the application on my phone
|
||||
|
||||
If the application was already installed on your phone, there are several cases:
|
||||
|
||||
|
|
|
|||
10
fastlane/metadata/android/en-US/changelogs/40004030.txt
Normal file
10
fastlane/metadata/android/en-US/changelogs/40004030.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
Main changes in this version:
|
||||
- Added share presence toggle.
|
||||
- Render typing notifications.
|
||||
- Manually mark a room as unread.
|
||||
- Add an empty state to the room list.
|
||||
- Allow joining unencrypted video calls in non encrypted rooms.
|
||||
|
||||
And several other bugfixes.
|
||||
|
||||
Full changelog: https://github.com/element-hq/element-x-android/releases
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_analytics_settings_share_data">"Дзяліцеся дадзенымі аналітыкі"</string>
|
||||
<string name="screen_analytics_settings_help_us_improve">"Даваць ананімныя дадзеныя аб выкарыстанні, каб дапамагчы нам выявіць праблемы."</string>
|
||||
<string name="screen_analytics_settings_read_terms">"Вы можаце азнаёміцца з усімі нашымі ўмовамі %1$s."</string>
|
||||
<string name="screen_analytics_settings_read_terms_content_link">"тут"</string>
|
||||
</resources>
|
||||
|
|
@ -57,7 +57,6 @@ import io.element.android.libraries.designsystem.theme.components.ButtonSize
|
|||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.TextButton
|
||||
import io.element.android.libraries.designsystem.theme.temporaryColorBgSpecial
|
||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
|
|
@ -67,7 +66,6 @@ fun AnalyticsOptInView(
|
|||
onClickTerms: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
LogCompositions(tag = "Analytics", msg = "Root")
|
||||
val eventSink = state.eventSink
|
||||
|
||||
fun onTermsAccepted() {
|
||||
|
|
@ -101,10 +99,8 @@ private const val LINK_TAG = "link"
|
|||
private fun AnalyticsOptInHeader(
|
||||
state: AnalyticsOptInState,
|
||||
onClickTerms: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
IconTitleSubtitleMolecule(
|
||||
|
|
@ -141,24 +137,22 @@ private fun AnalyticsOptInHeader(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun CheckIcon(modifier: Modifier = Modifier) {
|
||||
private fun CheckIcon() {
|
||||
Icon(
|
||||
modifier = modifier
|
||||
modifier = Modifier
|
||||
.size(20.dp)
|
||||
.background(color = MaterialTheme.colorScheme.background, shape = CircleShape)
|
||||
.padding(2.dp),
|
||||
imageVector = CompoundIcons.Check,
|
||||
imageVector = CompoundIcons.Check(),
|
||||
contentDescription = null,
|
||||
tint = ElementTheme.colors.textActionAccent,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AnalyticsOptInContent(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
private fun AnalyticsOptInContent() {
|
||||
Box(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = BiasAlignment(
|
||||
horizontalBias = 0f,
|
||||
verticalBias = -0.4f
|
||||
|
|
@ -190,11 +184,8 @@ private fun AnalyticsOptInContent(
|
|||
private fun AnalyticsOptInFooter(
|
||||
onTermsAccepted: () -> Unit,
|
||||
onTermsDeclined: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
ButtonColumnMolecule(
|
||||
modifier = modifier,
|
||||
) {
|
||||
ButtonColumnMolecule {
|
||||
Button(
|
||||
text = stringResource(id = CommonStrings.action_ok),
|
||||
onClick = onTermsAccepted,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_analytics_prompt_data_usage">"Мы не будзем запісваць або прафіляваць любыя асабістыя даныя"</string>
|
||||
<string name="screen_analytics_prompt_help_us_improve">"Даваць ананімныя дадзеныя аб выкарыстанні, каб дапамагчы нам выявіць праблемы."</string>
|
||||
<string name="screen_analytics_prompt_read_terms">"Вы можаце азнаёміцца з усімі нашымі ўмовамі %1$s."</string>
|
||||
<string name="screen_analytics_prompt_read_terms_content_link">"тут"</string>
|
||||
<string name="screen_analytics_prompt_settings">"Вы можаце адключыць гэта ў любы час"</string>
|
||||
<string name="screen_analytics_prompt_third_party_sharing">"Мы не будзем перадаваць вашыя дадзеныя трэцім асобам"</string>
|
||||
<string name="screen_analytics_prompt_title">"Дапамажыце палепшыць %1$s"</string>
|
||||
</resources>
|
||||
|
|
@ -64,7 +64,7 @@ internal fun CallScreenView(
|
|||
title = { Text(stringResource(R.string.element_call)) },
|
||||
navigationIcon = {
|
||||
BackButton(
|
||||
imageVector = CompoundIcons.Close,
|
||||
imageVector = CompoundIcons.Close(),
|
||||
onClick = { state.eventSink(CallScreenEvents.Hangup) }
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class DefaultCallWidgetProvider @Inject constructor(
|
|||
): Result<Pair<MatrixWidgetDriver, String>> = runCatching {
|
||||
val room = matrixClientsProvider.getOrRestore(sessionId).getOrThrow().getRoom(roomId) ?: error("Room not found")
|
||||
val baseUrl = appPreferencesStore.getCustomElementCallBaseUrlFlow().firstOrNull() ?: ElementCallConfig.DEFAULT_BASE_URL
|
||||
val widgetSettings = callWidgetSettingsProvider.provide(baseUrl)
|
||||
val widgetSettings = callWidgetSettingsProvider.provide(baseUrl, encrypted = room.isEncrypted)
|
||||
val callUrl = room.generateWidgetWebViewUrl(widgetSettings, clientId, languageTag, theme).getOrThrow()
|
||||
room.getWidgetDriver(widgetSettings).getOrThrow() to callUrl
|
||||
}
|
||||
|
|
|
|||
6
features/call/src/main/res/values-be/translations.xml
Normal file
6
features/call/src/main/res/values-be/translations.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="call_foreground_service_channel_title_android">"Бягучы выклік"</string>
|
||||
<string name="call_foreground_service_message_android">"Націсніце, каб вярнуцца да выкліка"</string>
|
||||
<string name="call_foreground_service_title_android">"☎️ Выконваецца выклік"</string>
|
||||
</resources>
|
||||
|
|
@ -88,10 +88,8 @@ private fun AddPeopleViewTopBar(
|
|||
hasSelectedUsers: Boolean,
|
||||
onBackPressed: () -> Unit,
|
||||
onNextPressed: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
TopAppBar(
|
||||
modifier = modifier,
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.screen_create_room_add_people_title),
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package io.element.android.features.createroom.impl.configureroom
|
|||
|
||||
import android.net.Uri
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
|
|
@ -38,8 +37,6 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusManager
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
|
|
@ -52,6 +49,7 @@ import io.element.android.libraries.designsystem.components.LabelledTextField
|
|||
import io.element.android.libraries.designsystem.components.async.AsyncActionView
|
||||
import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults
|
||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||
import io.element.android.libraries.designsystem.modifiers.clearFocusOnTap
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
|
||||
|
|
@ -173,10 +171,8 @@ private fun ConfigureRoomToolbar(
|
|||
isNextActionEnabled: Boolean,
|
||||
onBackPressed: () -> Unit,
|
||||
onNextPressed: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
TopAppBar(
|
||||
modifier = modifier,
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(R.string.screen_create_room_title),
|
||||
|
|
@ -259,13 +255,6 @@ private fun RoomPrivacyOptions(
|
|||
}
|
||||
}
|
||||
|
||||
private fun Modifier.clearFocusOnTap(focusManager: FocusManager): Modifier =
|
||||
pointerInput(Unit) {
|
||||
detectTapGestures(onTap = {
|
||||
focusManager.clearFocus()
|
||||
})
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun ConfigureRoomViewPreview(@PreviewParameter(ConfigureRoomStateProvider::class) state: ConfigureRoomState) = ElementPreview {
|
||||
|
|
|
|||
|
|
@ -33,18 +33,18 @@ data class RoomPrivacyItem(
|
|||
|
||||
@Composable
|
||||
fun roomPrivacyItems(): ImmutableList<RoomPrivacyItem> {
|
||||
return RoomPrivacy.values()
|
||||
return RoomPrivacy.entries
|
||||
.map {
|
||||
when (it) {
|
||||
RoomPrivacy.Private -> RoomPrivacyItem(
|
||||
privacy = it,
|
||||
icon = CompoundDrawables.ic_lock,
|
||||
icon = CompoundDrawables.ic_compound_lock_solid,
|
||||
title = stringResource(R.string.screen_create_room_private_option_title),
|
||||
description = stringResource(R.string.screen_create_room_private_option_description),
|
||||
)
|
||||
RoomPrivacy.Public -> RoomPrivacyItem(
|
||||
privacy = it,
|
||||
icon = CompoundDrawables.ic_public,
|
||||
icon = CompoundDrawables.ic_compound_public,
|
||||
title = stringResource(R.string.screen_create_room_public_option_title),
|
||||
description = stringResource(R.string.screen_create_room_public_option_description),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -117,10 +117,8 @@ fun CreateRoomRootView(
|
|||
@Composable
|
||||
private fun CreateRoomRootViewTopBar(
|
||||
onClosePressed: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
TopAppBar(
|
||||
modifier = modifier,
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(id = CommonStrings.action_start_chat),
|
||||
|
|
@ -129,7 +127,7 @@ private fun CreateRoomRootViewTopBar(
|
|||
},
|
||||
navigationIcon = {
|
||||
BackButton(
|
||||
imageVector = CompoundIcons.Close,
|
||||
imageVector = CompoundIcons.Close(),
|
||||
onClick = onClosePressed,
|
||||
)
|
||||
}
|
||||
|
|
@ -141,16 +139,15 @@ private fun CreateRoomActionButtonsList(
|
|||
state: CreateRoomRootState,
|
||||
onNewRoomClicked: () -> Unit,
|
||||
onInvitePeopleClicked: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
Column {
|
||||
CreateRoomActionButton(
|
||||
iconRes = CompoundDrawables.ic_plus,
|
||||
iconRes = CompoundDrawables.ic_compound_plus,
|
||||
text = stringResource(id = R.string.screen_create_room_action_create_room),
|
||||
onClick = onNewRoomClicked,
|
||||
)
|
||||
CreateRoomActionButton(
|
||||
iconRes = CompoundDrawables.ic_share_android,
|
||||
iconRes = CompoundDrawables.ic_compound_share_android,
|
||||
text = stringResource(id = CommonStrings.action_invite_friends_to_app, state.applicationName),
|
||||
onClick = onInvitePeopleClicked,
|
||||
)
|
||||
|
|
@ -162,10 +159,9 @@ private fun CreateRoomActionButton(
|
|||
@DrawableRes iconRes: Int,
|
||||
text: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(56.dp)
|
||||
.clickable { onClick() }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Новы пакой"</string>
|
||||
<string name="screen_create_room_action_invite_people">"Запрасіце сяброў у Element"</string>
|
||||
<string name="screen_create_room_add_people_title">"Запрасіць людзей"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Пры стварэнні пакоя адбылася памылка"</string>
|
||||
<string name="screen_create_room_private_option_description">"Паведамленні ў гэтым пакоі зашыфраваны. Гэта шыфраванне нельга адключыць."</string>
|
||||
<string name="screen_create_room_private_option_title">"Прыватны пакой (толькі па запрашэнні)"</string>
|
||||
<string name="screen_create_room_public_option_description">"Паведамленні не зашыфраваны, і кожны можа іх прачытаць. Вы можаце ўключыць шыфраванне пазней."</string>
|
||||
<string name="screen_create_room_public_option_title">"Адкрыты пакой (для ўсіх)"</string>
|
||||
<string name="screen_create_room_topic_label">"Тэма (неабавязкова)"</string>
|
||||
<string name="screen_start_chat_error_starting_chat">"Пры спробе пачаць чат адбылася памылка"</string>
|
||||
<string name="screen_create_room_room_name_label">"Назва пакоя"</string>
|
||||
<string name="screen_create_room_title">"Стварыце пакой"</string>
|
||||
</resources>
|
||||
|
|
@ -8,8 +8,8 @@
|
|||
<string name="screen_create_room_private_option_title">"Soukromá místnost (jen pro pozvané)"</string>
|
||||
<string name="screen_create_room_public_option_description">"Zprávy nejsou šifrované a může si je přečíst kdokoli. Šifrování můžete povolit později."</string>
|
||||
<string name="screen_create_room_public_option_title">"Veřejná místnost (kdokoli)"</string>
|
||||
<string name="screen_create_room_room_name_label">"Název místnosti"</string>
|
||||
<string name="screen_create_room_topic_label">"Téma (nepovinné)"</string>
|
||||
<string name="screen_start_chat_error_starting_chat">"Při pokusu o zahájení chatu došlo k chybě"</string>
|
||||
<string name="screen_create_room_room_name_label">"Název místnosti"</string>
|
||||
<string name="screen_create_room_title">"Vytvořit místnost"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
<string name="screen_create_room_private_option_title">"Privater Raum (nur auf Einladung)"</string>
|
||||
<string name="screen_create_room_public_option_description">"Die Nachrichten sind nicht verschlüsselt und können von jedem gelesen werden. Die Verschlüsselung kann zu einem späteren Zeitpunkt aktiviert werden."</string>
|
||||
<string name="screen_create_room_public_option_title">"Öffentlicher Raum (für alle)"</string>
|
||||
<string name="screen_create_room_room_name_label">"Raumname"</string>
|
||||
<string name="screen_create_room_topic_label">"Thema (optional)"</string>
|
||||
<string name="screen_start_chat_error_starting_chat">"Beim Versuch, einen Chat zu starten, ist ein Fehler aufgetreten"</string>
|
||||
<string name="screen_create_room_room_name_label">"Raumname"</string>
|
||||
<string name="screen_create_room_title">"Raum erstellen"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
<string name="screen_create_room_private_option_title">"Sala privada (sólo con invitación)"</string>
|
||||
<string name="screen_create_room_public_option_description">"Los mensajes no están cifrados y cualquiera puede leerlos. Puedes activar la encriptación más adelante."</string>
|
||||
<string name="screen_create_room_public_option_title">"Sala pública (cualquiera)"</string>
|
||||
<string name="screen_create_room_room_name_label">"Nombre de la sala"</string>
|
||||
<string name="screen_create_room_topic_label">"Tema (opcional)"</string>
|
||||
<string name="screen_start_chat_error_starting_chat">"Se ha producido un error al intentar iniciar un chat"</string>
|
||||
<string name="screen_create_room_room_name_label">"Nombre de la sala"</string>
|
||||
<string name="screen_create_room_title">"Crear una sala"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
<string name="screen_create_room_private_option_title">"Salon privé (sur invitation seulement)"</string>
|
||||
<string name="screen_create_room_public_option_description">"Les messages ne sont pas chiffrés et n’importe qui peut les lire. Vous pouvez activer le chiffrement ultérieurement."</string>
|
||||
<string name="screen_create_room_public_option_title">"Salon public (tout le monde)"</string>
|
||||
<string name="screen_create_room_room_name_label">"Nom du salon"</string>
|
||||
<string name="screen_create_room_topic_label">"Sujet (facultatif)"</string>
|
||||
<string name="screen_start_chat_error_starting_chat">"Une erreur s’est produite lors de la tentative de création de la discussion"</string>
|
||||
<string name="screen_create_room_room_name_label">"Nom du salon"</string>
|
||||
<string name="screen_create_room_title">"Créer un salon"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
<string name="screen_create_room_private_option_title">"Privát szoba (csak meghívással)"</string>
|
||||
<string name="screen_create_room_public_option_description">"Az üzenetek nincsenek titkosítva, és bárki elolvashatja őket. A titkosítást később is engedélyezheti."</string>
|
||||
<string name="screen_create_room_public_option_title">"Nyilvános szoba (bárki)"</string>
|
||||
<string name="screen_create_room_room_name_label">"Szoba neve"</string>
|
||||
<string name="screen_create_room_topic_label">"Téma (nem kötelező)"</string>
|
||||
<string name="screen_start_chat_error_starting_chat">"Hiba történt a csevegés indításakor"</string>
|
||||
<string name="screen_create_room_room_name_label">"Szoba neve"</string>
|
||||
<string name="screen_create_room_title">"Szoba létrehozása"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
<string name="screen_create_room_private_option_title">"Ruangan pribadi (hanya undangan)"</string>
|
||||
<string name="screen_create_room_public_option_description">"Pesan tidak dienkripsi dan siapa pun dapat membacanya. Anda dapat mengaktifkan enkripsi di kemudian hari."</string>
|
||||
<string name="screen_create_room_public_option_title">"Ruang publik (siapa saja)"</string>
|
||||
<string name="screen_create_room_room_name_label">"Nama ruangan"</string>
|
||||
<string name="screen_create_room_topic_label">"Topik (opsional)"</string>
|
||||
<string name="screen_start_chat_error_starting_chat">"Terjadi kesalahan saat mencoba memulai obrolan"</string>
|
||||
<string name="screen_create_room_room_name_label">"Nama ruangan"</string>
|
||||
<string name="screen_create_room_title">"Buat ruangan"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
<string name="screen_create_room_private_option_title">"Stanza privata (solo su invito)"</string>
|
||||
<string name="screen_create_room_public_option_description">"I messaggi non sono cifrati e chiunque può leggerli. Puoi attivare la crittografia in un secondo momento."</string>
|
||||
<string name="screen_create_room_public_option_title">"Stanza pubblica (chiunque)"</string>
|
||||
<string name="screen_create_room_room_name_label">"Nome stanza"</string>
|
||||
<string name="screen_create_room_topic_label">"Argomento (facoltativo)"</string>
|
||||
<string name="screen_start_chat_error_starting_chat">"Si è verificato un errore durante il tentativo di avviare una chat"</string>
|
||||
<string name="screen_create_room_room_name_label">"Nome stanza"</string>
|
||||
<string name="screen_create_room_title">"Crea una stanza"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
<string name="screen_create_room_private_option_title">"Cameră privată (doar pe bază de invitație)"</string>
|
||||
<string name="screen_create_room_public_option_description">"Mesajele nu sunt criptate și oricine le poate citi. Puteți activa criptarea la o dată ulterioară."</string>
|
||||
<string name="screen_create_room_public_option_title">"Cameră publică (oricine)"</string>
|
||||
<string name="screen_create_room_room_name_label">"Numele camerei"</string>
|
||||
<string name="screen_create_room_topic_label">"Subiect (opțional)"</string>
|
||||
<string name="screen_start_chat_error_starting_chat">"A apărut o eroare la încercarea începerii conversației"</string>
|
||||
<string name="screen_create_room_room_name_label">"Numele camerei"</string>
|
||||
<string name="screen_create_room_title">"Creați o cameră"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
<string name="screen_create_room_private_option_title">"Приватная комната (только по приглашению)"</string>
|
||||
<string name="screen_create_room_public_option_description">"Сообщения не зашифрованы, каждый может их прочитать. Вы можете включить шифрование позже."</string>
|
||||
<string name="screen_create_room_public_option_title">"Публичная комната (любой)"</string>
|
||||
<string name="screen_create_room_room_name_label">"Название комнаты"</string>
|
||||
<string name="screen_create_room_topic_label">"Тема (необязательно)"</string>
|
||||
<string name="screen_start_chat_error_starting_chat">"Произошла ошибка при попытке открытия комнаты"</string>
|
||||
<string name="screen_create_room_room_name_label">"Название комнаты"</string>
|
||||
<string name="screen_create_room_title">"Создать комнату"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
<string name="screen_create_room_private_option_title">"Súkromná miestnosť (len pre pozvaných)"</string>
|
||||
<string name="screen_create_room_public_option_description">"Správy nie sú šifrované a môže si ich prečítať ktokoľvek. Šifrovanie môžete zapnúť neskôr."</string>
|
||||
<string name="screen_create_room_public_option_title">"Verejná miestnosť (ktokoľvek)"</string>
|
||||
<string name="screen_create_room_room_name_label">"Názov miestnosti"</string>
|
||||
<string name="screen_create_room_topic_label">"Téma (voliteľné)"</string>
|
||||
<string name="screen_start_chat_error_starting_chat">"Pri pokuse o spustenie konverzácie sa vyskytla chyba"</string>
|
||||
<string name="screen_create_room_room_name_label">"Názov miestnosti"</string>
|
||||
<string name="screen_create_room_title">"Vytvoriť miestnosť"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<string name="screen_create_room_private_option_title">"私密聊天室(僅限邀請)"</string>
|
||||
<string name="screen_create_room_public_option_description">"訊息未加密,任何人都可以查看。您可以在之後啟用加密功能。"</string>
|
||||
<string name="screen_create_room_public_option_title">"公開聊天室(任何人)"</string>
|
||||
<string name="screen_create_room_room_name_label">"聊天室名稱"</string>
|
||||
<string name="screen_create_room_topic_label">"主題(非必填)"</string>
|
||||
<string name="screen_create_room_room_name_label">"聊天室名稱"</string>
|
||||
<string name="screen_create_room_title">"建立聊天室"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
<string name="screen_create_room_private_option_title">"Private room (invite only)"</string>
|
||||
<string name="screen_create_room_public_option_description">"Messages are not encrypted and anyone can read them. You can enable encryption at a later date."</string>
|
||||
<string name="screen_create_room_public_option_title">"Public room (anyone)"</string>
|
||||
<string name="screen_create_room_room_name_label">"Room name"</string>
|
||||
<string name="screen_create_room_topic_label">"Topic (optional)"</string>
|
||||
<string name="screen_start_chat_error_starting_chat">"An error occurred when trying to start a chat"</string>
|
||||
<string name="screen_create_room_room_name_label">"Room name"</string>
|
||||
<string name="screen_create_room_title">"Create a room"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ import dagger.assisted.AssistedInject
|
|||
import io.element.android.anvilannotations.ContributesNode
|
||||
import io.element.android.features.analytics.api.AnalyticsEntryPoint
|
||||
import io.element.android.features.ftue.api.FtueEntryPoint
|
||||
import io.element.android.features.ftue.impl.migration.MigrationScreenNode
|
||||
import io.element.android.features.ftue.impl.notifications.NotificationsOptInNode
|
||||
import io.element.android.features.ftue.impl.state.DefaultFtueState
|
||||
import io.element.android.features.ftue.impl.state.FtueStep
|
||||
|
|
@ -74,9 +73,6 @@ class FtueFlowNode @AssistedInject constructor(
|
|||
@Parcelize
|
||||
data object Placeholder : NavTarget
|
||||
|
||||
@Parcelize
|
||||
data object MigrationScreen : NavTarget
|
||||
|
||||
@Parcelize
|
||||
data object WelcomeScreen : NavTarget
|
||||
|
||||
|
|
@ -114,14 +110,6 @@ class FtueFlowNode @AssistedInject constructor(
|
|||
NavTarget.Placeholder -> {
|
||||
createNode<PlaceholderNode>(buildContext)
|
||||
}
|
||||
NavTarget.MigrationScreen -> {
|
||||
val callback = object : MigrationScreenNode.Callback {
|
||||
override fun onMigrationFinished() {
|
||||
lifecycleScope.launch { moveToNextStep() }
|
||||
}
|
||||
}
|
||||
createNode<MigrationScreenNode>(buildContext, listOf(callback))
|
||||
}
|
||||
NavTarget.WelcomeScreen -> {
|
||||
val callback = object : WelcomeNode.Callback {
|
||||
override fun onContinueClicked() {
|
||||
|
|
@ -158,9 +146,6 @@ class FtueFlowNode @AssistedInject constructor(
|
|||
|
||||
private fun moveToNextStep() {
|
||||
when (ftueState.getNextStep()) {
|
||||
FtueStep.MigrationScreen -> {
|
||||
backstack.newRoot(NavTarget.MigrationScreen)
|
||||
}
|
||||
FtueStep.WelcomeScreen -> {
|
||||
backstack.newRoot(NavTarget.WelcomeScreen)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* 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.ftue.impl.migration
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
|
||||
@ContributesNode(SessionScope::class)
|
||||
class MigrationScreenNode @AssistedInject constructor(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
private val presenter: MigrationScreenPresenter,
|
||||
) : Node(buildContext, plugins = plugins) {
|
||||
interface Callback : Plugin {
|
||||
fun onMigrationFinished()
|
||||
}
|
||||
|
||||
private fun onMigrationFinished() {
|
||||
plugins.filterIsInstance<Callback>().forEach { it.onMigrationFinished() }
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
val state = presenter.present()
|
||||
MigrationScreenView(
|
||||
state,
|
||||
onMigrationFinished = ::onMigrationFinished,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -67,7 +67,7 @@ fun NotificationsOptInView(
|
|||
header = { NotificationsOptInHeader(modifier = Modifier.padding(top = 60.dp, bottom = 12.dp)) },
|
||||
footer = { NotificationsOptInFooter(state) },
|
||||
) {
|
||||
NotificationsOptInContent(modifier = Modifier.fillMaxWidth())
|
||||
NotificationsOptInContent()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ private fun NotificationsOptInHeader(
|
|||
modifier = modifier,
|
||||
title = stringResource(R.string.screen_notification_optin_title),
|
||||
subTitle = stringResource(R.string.screen_notification_optin_subtitle),
|
||||
iconImageVector = CompoundIcons.NotificationsSolid,
|
||||
iconImageVector = CompoundIcons.NotificationsSolid(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -104,10 +104,8 @@ private fun NotificationsOptInFooter(state: NotificationsOptInState) {
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun NotificationsOptInContent(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
private fun NotificationsOptInContent() {
|
||||
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(
|
||||
16.dp,
|
||||
|
|
@ -144,10 +142,8 @@ private fun NotificationRow(
|
|||
avatarColorsId: String,
|
||||
firstRowPercent: Float,
|
||||
secondRowPercent: Float,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Surface(
|
||||
modifier = modifier,
|
||||
color = ElementTheme.colors.bgCanvasDisabled,
|
||||
shape = RoundedCornerShape(14.dp),
|
||||
shadowElevation = 2.dp,
|
||||
|
|
|
|||
|
|
@ -21,11 +21,9 @@ import android.os.Build
|
|||
import androidx.annotation.VisibleForTesting
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.features.ftue.api.state.FtueState
|
||||
import io.element.android.features.ftue.impl.migration.MigrationScreenStore
|
||||
import io.element.android.features.ftue.impl.welcome.state.WelcomeScreenState
|
||||
import io.element.android.features.lockscreen.api.LockScreenService
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.permissions.api.PermissionStateProvider
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider
|
||||
|
|
@ -43,17 +41,14 @@ class DefaultFtueState @Inject constructor(
|
|||
coroutineScope: CoroutineScope,
|
||||
private val analyticsService: AnalyticsService,
|
||||
private val welcomeScreenState: WelcomeScreenState,
|
||||
private val migrationScreenStore: MigrationScreenStore,
|
||||
private val permissionStateProvider: PermissionStateProvider,
|
||||
private val lockScreenService: LockScreenService,
|
||||
private val matrixClient: MatrixClient,
|
||||
) : FtueState {
|
||||
override val shouldDisplayFlow = MutableStateFlow(isAnyStepIncomplete())
|
||||
|
||||
override suspend fun reset() {
|
||||
welcomeScreenState.reset()
|
||||
analyticsService.reset()
|
||||
migrationScreenStore.reset()
|
||||
if (sdkVersionProvider.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
|
||||
permissionStateProvider.resetPermission(Manifest.permission.POST_NOTIFICATIONS)
|
||||
}
|
||||
|
|
@ -67,12 +62,7 @@ class DefaultFtueState @Inject constructor(
|
|||
|
||||
fun getNextStep(currentStep: FtueStep? = null): FtueStep? =
|
||||
when (currentStep) {
|
||||
null -> if (shouldDisplayMigrationScreen()) {
|
||||
FtueStep.MigrationScreen
|
||||
} else {
|
||||
getNextStep(FtueStep.MigrationScreen)
|
||||
}
|
||||
FtueStep.MigrationScreen -> if (shouldDisplayWelcomeScreen()) {
|
||||
null -> if (shouldDisplayWelcomeScreen()) {
|
||||
FtueStep.WelcomeScreen
|
||||
} else {
|
||||
getNextStep(FtueStep.WelcomeScreen)
|
||||
|
|
@ -97,7 +87,6 @@ class DefaultFtueState @Inject constructor(
|
|||
|
||||
private fun isAnyStepIncomplete(): Boolean {
|
||||
return listOf(
|
||||
{ shouldDisplayMigrationScreen() },
|
||||
{ shouldDisplayWelcomeScreen() },
|
||||
{ shouldAskNotificationPermissions() },
|
||||
{ needsAnalyticsOptIn() },
|
||||
|
|
@ -105,10 +94,6 @@ class DefaultFtueState @Inject constructor(
|
|||
).any { it() }
|
||||
}
|
||||
|
||||
private fun shouldDisplayMigrationScreen(): Boolean {
|
||||
return migrationScreenStore.isMigrationScreenNeeded(matrixClient.sessionId)
|
||||
}
|
||||
|
||||
private fun needsAnalyticsOptIn(): Boolean {
|
||||
// We need this function to not be suspend, so we need to load the value through runBlocking
|
||||
return runBlocking { analyticsService.didAskUserConsent().first().not() }
|
||||
|
|
@ -147,7 +132,6 @@ class DefaultFtueState @Inject constructor(
|
|||
}
|
||||
|
||||
sealed interface FtueStep {
|
||||
data object MigrationScreen : FtueStep
|
||||
data object WelcomeScreen : FtueStep
|
||||
data object NotificationsOptIn : FtueStep
|
||||
data object AnalyticsOptIn : FtueStep
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ import io.element.android.libraries.designsystem.preview.ElementPreview
|
|||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Button
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
||||
import io.element.android.libraries.testtags.TestTags
|
||||
import io.element.android.libraries.testtags.testTag
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
|
@ -102,11 +101,11 @@ fun WelcomeView(
|
|||
private fun listItems() = persistentListOf(
|
||||
InfoListItem(
|
||||
message = stringResource(R.string.screen_welcome_bullet_2),
|
||||
iconId = CommonDrawables.ic_lock_outline,
|
||||
iconVector = CompoundIcons.Lock(),
|
||||
),
|
||||
InfoListItem(
|
||||
message = stringResource(R.string.screen_welcome_bullet_3),
|
||||
iconVector = CompoundIcons.ChatProblem,
|
||||
iconVector = CompoundIcons.ChatProblem(),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
11
features/ftue/impl/src/main/res/values-be/translations.xml
Normal file
11
features/ftue/impl/src/main/res/values-be/translations.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_notification_optin_subtitle">"Вы можаце змяніць налады пазней."</string>
|
||||
<string name="screen_notification_optin_title">"Дазвольце апавяшчэнні і ніколі не прапускайце іх"</string>
|
||||
<string name="screen_welcome_bullet_1">"Званкі, апытанні, пошук і многае іншае будзе дададзена пазней у гэтым годзе."</string>
|
||||
<string name="screen_welcome_bullet_2">"Гісторыя паведамленняў для зашыфраваных пакояў пакуль недаступна."</string>
|
||||
<string name="screen_welcome_bullet_3">"Мы будзем рады пачуць вашае меркаванне, паведаміце нам аб гэтым праз старонку налад."</string>
|
||||
<string name="screen_welcome_button">"Пачнём!"</string>
|
||||
<string name="screen_welcome_subtitle">"Вось што вам трэба ведаць:"</string>
|
||||
<string name="screen_welcome_title">"Вітаем у %1$s!"</string>
|
||||
</resources>
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_migration_message">"Jedná se o jednorázový proces, prosíme o strpení."</string>
|
||||
<string name="screen_migration_title">"Nastavení vašeho účtu"</string>
|
||||
<string name="screen_notification_optin_subtitle">"Nastavení můžete později změnit."</string>
|
||||
<string name="screen_notification_optin_title">"Povolte oznámení a nezmeškejte žádnou zprávu"</string>
|
||||
<string name="screen_welcome_bullet_1">"Hovory, hlasování, vyhledávání a další budou přidány koncem tohoto roku."</string>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_migration_message">"Dies ist ein einmaliger Vorgang, danke fürs Warten."</string>
|
||||
<string name="screen_migration_title">"Dein Konto wird eingerichtet."</string>
|
||||
<string name="screen_notification_optin_subtitle">"Du kannst deine Einstellungen später ändern."</string>
|
||||
<string name="screen_notification_optin_title">"Erlaube Benachrichtigungen und verpasse keine Nachricht"</string>
|
||||
<string name="screen_welcome_bullet_1">"Anrufe, Umfragen, Suchfunktionen und mehr werden im Laufe des Jahres hinzugefügt."</string>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_migration_message">"Este proceso solo se hace una vez, gracias por esperar."</string>
|
||||
<string name="screen_migration_title">"Configura tu cuenta"</string>
|
||||
<string name="screen_notification_optin_subtitle">"Puedes cambiar la configuración más tarde."</string>
|
||||
<string name="screen_notification_optin_title">"Activa las notificaciones y nunca te pierdas un mensaje"</string>
|
||||
<string name="screen_welcome_bullet_1">"Las llamadas, las encuestas, la búsqueda y más se agregarán más adelante este año."</string>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_migration_message">"Il s’agit d’une opération ponctuelle, merci d’attendre quelques instants."</string>
|
||||
<string name="screen_migration_title">"Configuration de votre compte."</string>
|
||||
<string name="screen_notification_optin_subtitle">"Vous pourrez modifier vos paramètres ultérieurement."</string>
|
||||
<string name="screen_notification_optin_title">"Autorisez les notifications et ne manquez aucun message"</string>
|
||||
<string name="screen_welcome_bullet_1">"Les appels, les sondages, les recherches et plus encore seront ajoutés plus tard cette année."</string>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_migration_message">"Ez egy egyszeri folyamat, köszönjük a türelmét."</string>
|
||||
<string name="screen_migration_title">"A fiók beállítása."</string>
|
||||
<string name="screen_notification_optin_subtitle">"A beállításokat később is módosíthatja."</string>
|
||||
<string name="screen_notification_optin_title">"Értesítések engedélyezése, hogy soha ne maradjon le egyetlen üzenetről sem"</string>
|
||||
<string name="screen_welcome_bullet_1">"A hívások, szavazások, keresések és egyebek az év további részében kerülnek hozzáadásra."</string>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_migration_message">"Ini adalah proses satu kali, terima kasih telah menunggu."</string>
|
||||
<string name="screen_migration_title">"Menyiapkan akun Anda."</string>
|
||||
<string name="screen_notification_optin_subtitle">"Anda dapat mengubah pengaturan Anda nanti."</string>
|
||||
<string name="screen_notification_optin_title">"Izinkan pemberitahuan dan jangan pernah melewatkan pesan"</string>
|
||||
<string name="screen_welcome_bullet_1">"Panggilan, pemungutan suara, pencarian, dan lainnya akan ditambahkan di tahun ini."</string>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_migration_message">"Si tratta di una procedura che si effettua una sola volta, grazie per l\'attesa."</string>
|
||||
<string name="screen_migration_title">"Configurazione del tuo account."</string>
|
||||
<string name="screen_notification_optin_subtitle">"Potrai modificare le tue impostazioni in seguito."</string>
|
||||
<string name="screen_notification_optin_title">"Consenti le notifiche e non perdere mai un messaggio"</string>
|
||||
<string name="screen_welcome_bullet_1">"Chiamate, sondaggi, ricerche e altro ancora saranno aggiunti nel corso dell\'anno."</string>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_migration_message">"Acesta este un proces care se desfășoară o singură dată, vă mulțumim pentru așteptare."</string>
|
||||
<string name="screen_migration_title">"Contul dumneavoastră se configurează"</string>
|
||||
<string name="screen_welcome_bullet_1">"Apelurile, sondajele, căutare și multe altele vor fi adăugate în cursul acestui an."</string>
|
||||
<string name="screen_welcome_bullet_2">"Istoricul mesajelor pentru camerele criptate nu va fi disponibil în această actualizare."</string>
|
||||
<string name="screen_welcome_bullet_3">"Ne-ar plăcea să auzim de la dumneavoastră, spuneți-ne ce părere aveți prin intermediul paginii de setări."</string>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_migration_message">"Это одноразовый процесс, спасибо, что подождали."</string>
|
||||
<string name="screen_migration_title">"Настройка учетной записи."</string>
|
||||
<string name="screen_notification_optin_subtitle">"Вы можете изменить настройки позже."</string>
|
||||
<string name="screen_notification_optin_title">"Разрешите уведомления и никогда не пропустите сообщение"</string>
|
||||
<string name="screen_welcome_bullet_1">"Звонки, опросы, поиск и многое другое будут добавлены позже в этом году."</string>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_migration_message">"Ide o jednorazový proces, ďakujeme za trpezlivosť."</string>
|
||||
<string name="screen_migration_title">"Nastavenie vášho účtu."</string>
|
||||
<string name="screen_notification_optin_subtitle">"Svoje nastavenia môžete neskôr zmeniť."</string>
|
||||
<string name="screen_notification_optin_title">"Povoľte oznámenia a nikdy nezmeškajte žiadnu správu"</string>
|
||||
<string name="screen_welcome_bullet_1">"Hovory, ankety, vyhľadávanie a ďalšie funkcie pribudnú neskôr v tomto roku."</string>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_migration_message">"這是一次性的程序,感謝您耐心等候。"</string>
|
||||
<string name="screen_migration_title">"正在設定您的帳號。"</string>
|
||||
<string name="screen_welcome_bullet_1">"通話、投票、搜尋等更多功能將在今年登場。"</string>
|
||||
<string name="screen_welcome_bullet_2">"在這次的更新,您無法查看聊天室內被加密的歷史訊息。"</string>
|
||||
<string name="screen_welcome_bullet_3">"我們很樂意聽取您的意見,請到設定頁面告訴我們您的想法。"</string>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_migration_message">"This is a one time process, thanks for waiting."</string>
|
||||
<string name="screen_migration_title">"Setting up your account."</string>
|
||||
<string name="screen_notification_optin_subtitle">"You can change your settings later."</string>
|
||||
<string name="screen_notification_optin_title">"Allow notifications and never miss a message"</string>
|
||||
<string name="screen_welcome_bullet_1">"Calls, polls, search and more will be added later this year."</string>
|
||||
|
|
|
|||
|
|
@ -18,16 +18,11 @@ package io.element.android.features.ftue.impl
|
|||
|
||||
import android.os.Build
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.ftue.impl.migration.InMemoryMigrationScreenStore
|
||||
import io.element.android.features.ftue.impl.migration.MigrationScreenStore
|
||||
import io.element.android.features.ftue.impl.state.DefaultFtueState
|
||||
import io.element.android.features.ftue.impl.state.FtueStep
|
||||
import io.element.android.features.ftue.impl.welcome.state.FakeWelcomeState
|
||||
import io.element.android.features.lockscreen.api.LockScreenService
|
||||
import io.element.android.features.lockscreen.test.FakeLockScreenService
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.permissions.impl.FakePermissionStateProvider
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||
|
|
@ -54,7 +49,6 @@ class DefaultFtueStateTests {
|
|||
fun `given all checks being true, should display flow is false`() = runTest {
|
||||
val welcomeState = FakeWelcomeState()
|
||||
val analyticsService = FakeAnalyticsService()
|
||||
val migrationScreenStore = InMemoryMigrationScreenStore()
|
||||
val permissionStateProvider = FakePermissionStateProvider(permissionGranted = true)
|
||||
val lockScreenService = FakeLockScreenService()
|
||||
val coroutineScope = CoroutineScope(coroutineContext + SupervisorJob())
|
||||
|
|
@ -63,14 +57,12 @@ class DefaultFtueStateTests {
|
|||
coroutineScope = coroutineScope,
|
||||
welcomeState = welcomeState,
|
||||
analyticsService = analyticsService,
|
||||
migrationScreenStore = migrationScreenStore,
|
||||
permissionStateProvider = permissionStateProvider,
|
||||
lockScreenService = lockScreenService,
|
||||
)
|
||||
|
||||
welcomeState.setWelcomeScreenShown()
|
||||
analyticsService.setDidAskUserConsent()
|
||||
migrationScreenStore.setMigrationScreenShown(A_SESSION_ID)
|
||||
permissionStateProvider.setPermissionGranted()
|
||||
lockScreenService.setIsPinSetup(true)
|
||||
state.updateState()
|
||||
|
|
@ -85,7 +77,6 @@ class DefaultFtueStateTests {
|
|||
fun `traverse flow`() = runTest {
|
||||
val welcomeState = FakeWelcomeState()
|
||||
val analyticsService = FakeAnalyticsService()
|
||||
val migrationScreenStore = InMemoryMigrationScreenStore()
|
||||
val permissionStateProvider = FakePermissionStateProvider(permissionGranted = false)
|
||||
val lockScreenService = FakeLockScreenService()
|
||||
val coroutineScope = CoroutineScope(coroutineContext + SupervisorJob())
|
||||
|
|
@ -94,29 +85,24 @@ class DefaultFtueStateTests {
|
|||
coroutineScope = coroutineScope,
|
||||
welcomeState = welcomeState,
|
||||
analyticsService = analyticsService,
|
||||
migrationScreenStore = migrationScreenStore,
|
||||
permissionStateProvider = permissionStateProvider,
|
||||
lockScreenService = lockScreenService,
|
||||
)
|
||||
val steps = mutableListOf<FtueStep?>()
|
||||
|
||||
// First step, migration screen
|
||||
steps.add(state.getNextStep(steps.lastOrNull()))
|
||||
migrationScreenStore.setMigrationScreenShown(A_SESSION_ID)
|
||||
|
||||
// Second step, welcome screen
|
||||
// First step, welcome screen
|
||||
steps.add(state.getNextStep(steps.lastOrNull()))
|
||||
welcomeState.setWelcomeScreenShown()
|
||||
|
||||
// Third step, notifications opt in
|
||||
// Second step, notifications opt in
|
||||
steps.add(state.getNextStep(steps.lastOrNull()))
|
||||
permissionStateProvider.setPermissionGranted()
|
||||
|
||||
// Fourth step, entering PIN code
|
||||
// Third step, entering PIN code
|
||||
steps.add(state.getNextStep(steps.lastOrNull()))
|
||||
lockScreenService.setIsPinSetup(true)
|
||||
|
||||
// Fifth step, analytics opt in
|
||||
// Fourth step, analytics opt in
|
||||
steps.add(state.getNextStep(steps.lastOrNull()))
|
||||
analyticsService.setDidAskUserConsent()
|
||||
|
||||
|
|
@ -124,7 +110,6 @@ class DefaultFtueStateTests {
|
|||
steps.add(state.getNextStep(steps.lastOrNull()))
|
||||
|
||||
assertThat(steps).containsExactly(
|
||||
FtueStep.MigrationScreen,
|
||||
FtueStep.WelcomeScreen,
|
||||
FtueStep.NotificationsOptIn,
|
||||
FtueStep.LockscreenSetup,
|
||||
|
|
@ -141,19 +126,16 @@ class DefaultFtueStateTests {
|
|||
fun `if a check for a step is true, start from the next one`() = runTest {
|
||||
val coroutineScope = CoroutineScope(coroutineContext + SupervisorJob())
|
||||
val analyticsService = FakeAnalyticsService()
|
||||
val migrationScreenStore = InMemoryMigrationScreenStore()
|
||||
val permissionStateProvider = FakePermissionStateProvider(permissionGranted = false)
|
||||
val lockScreenService = FakeLockScreenService()
|
||||
val state = createState(
|
||||
coroutineScope = coroutineScope,
|
||||
analyticsService = analyticsService,
|
||||
migrationScreenStore = migrationScreenStore,
|
||||
permissionStateProvider = permissionStateProvider,
|
||||
lockScreenService = lockScreenService,
|
||||
)
|
||||
|
||||
// Skip first 4 steps
|
||||
migrationScreenStore.setMigrationScreenShown(A_SESSION_ID)
|
||||
// Skip first 3 steps
|
||||
state.setWelcomeScreenShown()
|
||||
permissionStateProvider.setPermissionGranted()
|
||||
lockScreenService.setIsPinSetup(true)
|
||||
|
|
@ -171,18 +153,15 @@ class DefaultFtueStateTests {
|
|||
fun `if version is older than 13 we don't display the notification opt in screen`() = runTest {
|
||||
val coroutineScope = CoroutineScope(coroutineContext + SupervisorJob())
|
||||
val analyticsService = FakeAnalyticsService()
|
||||
val migrationScreenStore = InMemoryMigrationScreenStore()
|
||||
val lockScreenService = FakeLockScreenService()
|
||||
|
||||
val state = createState(
|
||||
sdkIntVersion = Build.VERSION_CODES.M,
|
||||
coroutineScope = coroutineScope,
|
||||
analyticsService = analyticsService,
|
||||
migrationScreenStore = migrationScreenStore,
|
||||
lockScreenService = lockScreenService,
|
||||
)
|
||||
|
||||
migrationScreenStore.setMigrationScreenShown(A_SESSION_ID)
|
||||
assertThat(state.getNextStep()).isEqualTo(FtueStep.WelcomeScreen)
|
||||
state.setWelcomeScreenShown()
|
||||
lockScreenService.setIsPinSetup(true)
|
||||
|
|
@ -200,9 +179,7 @@ class DefaultFtueStateTests {
|
|||
coroutineScope: CoroutineScope,
|
||||
welcomeState: FakeWelcomeState = FakeWelcomeState(),
|
||||
analyticsService: AnalyticsService = FakeAnalyticsService(),
|
||||
migrationScreenStore: MigrationScreenStore = InMemoryMigrationScreenStore(),
|
||||
permissionStateProvider: FakePermissionStateProvider = FakePermissionStateProvider(permissionGranted = false),
|
||||
matrixClient: MatrixClient = FakeMatrixClient(),
|
||||
lockScreenService: LockScreenService = FakeLockScreenService(),
|
||||
// First version where notification permission is required
|
||||
sdkIntVersion: Int = Build.VERSION_CODES.TIRAMISU,
|
||||
|
|
@ -211,9 +188,7 @@ class DefaultFtueStateTests {
|
|||
coroutineScope = coroutineScope,
|
||||
analyticsService = analyticsService,
|
||||
welcomeScreenState = welcomeState,
|
||||
migrationScreenStore = migrationScreenStore,
|
||||
permissionStateProvider = permissionStateProvider,
|
||||
lockScreenService = lockScreenService,
|
||||
matrixClient = matrixClient,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_invites_decline_chat_message">"Вы ўпэўненыя, што жадаеце адхіліць запрашэнне ў %1$s?"</string>
|
||||
<string name="screen_invites_decline_chat_title">"Адхіліць запрашэнне"</string>
|
||||
<string name="screen_invites_decline_direct_chat_message">"Вы ўпэўненыя, што жадаеце адмовіцца ад прыватных зносін з %1$s?"</string>
|
||||
<string name="screen_invites_decline_direct_chat_title">"Адхіліць чат"</string>
|
||||
<string name="screen_invites_empty_list">"Няма запрашэнняў"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) запрасіў вас"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="leave_room_alert_empty_subtitle">"Вы ўпэўнены, што жадаеце пакінуць гэты пакой? Вы тут адзіны карыстальнік. Калі вы выйдзеце, ніхто не зможа далучыцца ў будучыні, у тым ліку і вы."</string>
|
||||
<string name="leave_room_alert_private_subtitle">"Вы ўпэўнены, што жадаеце пакінуць гэты пакой? Гэты пакой не агульнадаступны, і вы не зможаце далучыцца да яго зноў без запрашэння."</string>
|
||||
<string name="leave_room_alert_subtitle">"Вы ўпэўнены, што жадаеце пакінуць пакой?"</string>
|
||||
</resources>
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="leave_conversation_alert_subtitle">"Bist du sicher, dass du diese Unterhaltung verlassen willst? Diese Unterhaltung ist nicht öffentlich und du kannst ihr ohne Einladung nicht wieder beitreten."</string>
|
||||
<string name="leave_room_alert_empty_subtitle">"Bist du sicher, dass du diesen Raum verlassen möchtest? Du bist die einzige Person hier. Wenn du austritst, kann in Zukunft niemand mehr eintreten, auch du nicht."</string>
|
||||
<string name="leave_room_alert_private_subtitle">"Bist du sicher, dass du diesen Raum verlassen möchtest? Dieser Raum ist nicht öffentlich und du kannst ihm ohne Einladung nicht erneut beitreten."</string>
|
||||
<string name="leave_room_alert_subtitle">"Bist du sicher, dass du den Raum verlassen willst?"</string>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="leave_conversation_alert_subtitle">"Biztos, hogy elhagyja ezt a beszélgetést? Ez a beszélgetés nem nyilvános, és meghívás nélkül nem fog tudni visszacsatlakozni."</string>
|
||||
<string name="leave_room_alert_empty_subtitle">"Biztos, hogy elhagyja ezt a szobát? Ön az egyedüli ember itt. Ha kilép, akkor senki sem fog tudni csatlakozni a jövőben, Önt is beleértve."</string>
|
||||
<string name="leave_room_alert_private_subtitle">"Biztos, hogy elhagyod ezt a szobát? Ez a szoba nem nyilvános, és meghívó nélkül nem fogsz tudni újra belépni."</string>
|
||||
<string name="leave_room_alert_subtitle">"Biztos, hogy elhagyod a szobát?"</string>
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
|||
import androidx.compose.ui.unit.dp
|
||||
import com.mapbox.mapboxsdk.camera.CameraPosition
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.features.location.api.Location
|
||||
import io.element.android.features.location.api.internal.centerBottomEdge
|
||||
import io.element.android.features.location.api.internal.rememberTileStyleUrl
|
||||
|
|
@ -211,8 +212,8 @@ fun SendLocationView(
|
|||
.padding(end = 16.dp, bottom = 72.dp + navBarPadding),
|
||||
) {
|
||||
when (state.mode) {
|
||||
SendLocationState.Mode.PinLocation -> Icon(resourceId = CommonDrawables.ic_location_navigator, contentDescription = null)
|
||||
SendLocationState.Mode.SenderLocation -> Icon(resourceId = CommonDrawables.ic_location_navigator_centered, contentDescription = null)
|
||||
SendLocationState.Mode.PinLocation -> Icon(imageVector = CompoundIcons.LocationNavigator(), contentDescription = null)
|
||||
SendLocationState.Mode.SenderLocation -> Icon(imageVector = CompoundIcons.LocationNavigatorCentred(), contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ fun ShowLocationView(
|
|||
actions = {
|
||||
IconButton(onClick = { state.eventSink(ShowLocationEvents.Share) }) {
|
||||
Icon(
|
||||
imageVector = CompoundIcons.ShareAndroid,
|
||||
imageVector = CompoundIcons.ShareAndroid(),
|
||||
contentDescription = stringResource(CommonStrings.action_share),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,10 +66,8 @@ fun PinEntryTextField(
|
|||
private fun PinEntryRow(
|
||||
pinEntry: PinEntry,
|
||||
isSecured: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
FlowRow(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp, alignment = Alignment.CenterHorizontally),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
|
|
@ -83,7 +81,6 @@ private fun PinEntryRow(
|
|||
private fun PinDigitView(
|
||||
digit: PinDigit,
|
||||
isSecured: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val shape = RoundedCornerShape(8.dp)
|
||||
val appearanceModifier = when (digit) {
|
||||
|
|
@ -95,7 +92,7 @@ private fun PinDigitView(
|
|||
}
|
||||
}
|
||||
Box(
|
||||
modifier = modifier
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.then(appearanceModifier),
|
||||
contentAlignment = Alignment.Center,
|
||||
|
|
|
|||
|
|
@ -57,13 +57,12 @@ fun SetupBiometricView(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun SetupBiometricHeader(modifier: Modifier = Modifier) {
|
||||
private fun SetupBiometricHeader() {
|
||||
val biometricAuth = stringResource(id = R.string.screen_app_lock_biometric_authentication)
|
||||
IconTitleSubtitleMolecule(
|
||||
iconImageVector = Icons.Default.Fingerprint,
|
||||
title = stringResource(id = R.string.screen_app_lock_settings_enable_biometric_unlock),
|
||||
subTitle = stringResource(id = R.string.screen_app_lock_setup_biometric_unlock_subtitle, biometricAuth),
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -71,11 +70,8 @@ private fun SetupBiometricHeader(modifier: Modifier = Modifier) {
|
|||
private fun SetupBiometricFooter(
|
||||
onAllowClicked: () -> Unit,
|
||||
onSkipClicked: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
ButtonColumnMolecule(
|
||||
modifier = modifier,
|
||||
) {
|
||||
ButtonColumnMolecule {
|
||||
val biometricAuth = stringResource(id = R.string.screen_app_lock_biometric_authentication)
|
||||
Button(
|
||||
text = stringResource(id = R.string.screen_app_lock_setup_biometric_unlock_allow_title, biometricAuth),
|
||||
|
|
|
|||
|
|
@ -86,10 +86,8 @@ fun SetupPinView(
|
|||
private fun SetupPinHeader(
|
||||
isValidationStep: Boolean,
|
||||
appName: String,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
IconTitleSubtitleMolecule(
|
||||
|
|
@ -107,7 +105,6 @@ private fun SetupPinHeader(
|
|||
@Composable
|
||||
private fun SetupPinContent(
|
||||
state: SetupPinState,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
LaunchedEffect(Unit) {
|
||||
|
|
@ -119,14 +116,13 @@ private fun SetupPinContent(
|
|||
onValueChange = { entry ->
|
||||
state.eventSink(SetupPinEvents.OnPinEntryChanged(entry, state.isConfirmationStep))
|
||||
},
|
||||
modifier = modifier
|
||||
modifier = Modifier
|
||||
.focusRequester(focusRequester)
|
||||
.padding(top = 36.dp)
|
||||
.fillMaxWidth()
|
||||
)
|
||||
if (state.setupPinFailure != null) {
|
||||
ErrorDialog(
|
||||
modifier = modifier,
|
||||
title = state.setupPinFailure.title(),
|
||||
content = state.setupPinFailure.content(),
|
||||
onDismiss = {
|
||||
|
|
|
|||
|
|
@ -107,10 +107,9 @@ fun PinUnlockView(
|
|||
private fun PinUnlockPage(
|
||||
state: PinUnlockState,
|
||||
isInAppUnlock: Boolean,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
BoxWithConstraints {
|
||||
val commonModifier = modifier
|
||||
val commonModifier = Modifier
|
||||
.fillMaxSize()
|
||||
.systemBarsPadding()
|
||||
.imePadding()
|
||||
|
|
@ -188,7 +187,6 @@ private fun SignOutPrompt(
|
|||
isCancellable: Boolean,
|
||||
onSignOut: () -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
if (isCancellable) {
|
||||
ConfirmationDialog(
|
||||
|
|
@ -196,14 +194,12 @@ private fun SignOutPrompt(
|
|||
content = stringResource(id = R.string.screen_app_lock_signout_alert_message),
|
||||
onSubmitClicked = onSignOut,
|
||||
onDismiss = onDismiss,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
ErrorDialog(
|
||||
title = stringResource(id = R.string.screen_app_lock_signout_alert_title),
|
||||
content = stringResource(id = R.string.screen_app_lock_signout_alert_message),
|
||||
onDismiss = onSignOut,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -258,9 +254,11 @@ private fun PinUnlockExpandedView(
|
|||
@Composable
|
||||
private fun PinDotsRow(
|
||||
pinEntry: PinEntry,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(modifier, horizontalArrangement = spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Row(
|
||||
horizontalArrangement = spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
for (digit in pinEntry.digits) {
|
||||
PinDot(isFilled = digit is PinDigit.Filled)
|
||||
}
|
||||
|
|
@ -270,7 +268,6 @@ private fun PinDotsRow(
|
|||
@Composable
|
||||
private fun PinDot(
|
||||
isFilled: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val backgroundColor = if (isFilled) {
|
||||
ElementTheme.colors.iconPrimary
|
||||
|
|
@ -278,7 +275,7 @@ private fun PinDot(
|
|||
ElementTheme.colors.bgSubtlePrimary
|
||||
}
|
||||
Box(
|
||||
modifier = modifier
|
||||
modifier = Modifier
|
||||
.size(14.dp)
|
||||
.background(backgroundColor, CircleShape)
|
||||
)
|
||||
|
|
@ -290,7 +287,10 @@ private fun PinUnlockHeader(
|
|||
isInAppUnlock: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(modifier, horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
if (isInAppUnlock) {
|
||||
RoundedIconAtom(imageVector = Icons.Filled.Lock)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -108,14 +108,13 @@ private fun PinKeypadRow(
|
|||
models: ImmutableList<PinKeypadModel>,
|
||||
onClick: (PinKeypadModel) -> Unit,
|
||||
pinKeySize: Dp,
|
||||
modifier: Modifier = Modifier,
|
||||
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
|
||||
verticalAlignment: Alignment.Vertical = Alignment.Top,
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = horizontalArrangement,
|
||||
verticalAlignment = verticalAlignment,
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
val commonModifier = Modifier.size(pinKeySize)
|
||||
for (model in models) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<plurals name="screen_app_lock_subtitle">
|
||||
<item quantity="one">"У вас %1$d спроба разблакіроўкі"</item>
|
||||
<item quantity="few">"У вас %1$d спроб разблакіроўкі"</item>
|
||||
<item quantity="many">"У вас %1$d спроб разблакіроўкі"</item>
|
||||
</plurals>
|
||||
<plurals name="screen_app_lock_subtitle_wrong_pin">
|
||||
<item quantity="one">"Няправільны PIN-код. У вас застаўся %1$d шанец"</item>
|
||||
<item quantity="few">"Няправільны PIN-код. У вас застаўася %1$d шанцаў"</item>
|
||||
<item quantity="many">"Няправільны PIN-код. У вас застаўася %1$d шанцаў"</item>
|
||||
</plurals>
|
||||
<string name="screen_app_lock_biometric_authentication">"біяметрычная аўтэнтыфікацыя"</string>
|
||||
<string name="screen_app_lock_biometric_unlock">"біяметрычная разблакіроўка"</string>
|
||||
<string name="screen_app_lock_biometric_unlock_title_android">"Разблакіроўка з дапамогай біяметрыі"</string>
|
||||
<string name="screen_app_lock_forgot_pin">"Забыліся PIN-код?"</string>
|
||||
<string name="screen_app_lock_settings_change_pin">"Змяніць PIN-код"</string>
|
||||
<string name="screen_app_lock_settings_enable_biometric_unlock">"Дазволіць біяметрычную разблакіроўку"</string>
|
||||
<string name="screen_app_lock_settings_remove_pin">"Выдаліць PIN-код"</string>
|
||||
<string name="screen_app_lock_settings_remove_pin_alert_message">"Вы ўпэўнены, што жадаеце выдаліць PIN-код?"</string>
|
||||
<string name="screen_app_lock_settings_remove_pin_alert_title">"Выдаліць PIN-код?"</string>
|
||||
<string name="screen_app_lock_setup_biometric_unlock_allow_title">"Дазволіць %1$s"</string>
|
||||
<string name="screen_app_lock_setup_biometric_unlock_skip">"Я хацеў бы выкарыстоўваць PIN-код"</string>
|
||||
<string name="screen_app_lock_setup_biometric_unlock_subtitle">"Эканомце час і выкарыстоўвайце %1$s для разблакіроўкі праграмы"</string>
|
||||
<string name="screen_app_lock_setup_choose_pin">"Выберыце PIN-код"</string>
|
||||
<string name="screen_app_lock_setup_confirm_pin">"Пацвярджэнне PIN-кода"</string>
|
||||
<string name="screen_app_lock_setup_pin_blacklisted_dialog_content">"Вы не можаце выбраць гэты PIN-код з меркаванняў бяспекі"</string>
|
||||
<string name="screen_app_lock_setup_pin_blacklisted_dialog_title">"Выберыце іншы PIN-код"</string>
|
||||
<string name="screen_app_lock_setup_pin_context">"Заблакіруйце %1$s, каб павялічыць бяспеку вашых чатаў.
|
||||
|
||||
Абярыце што-небудзь незабыўнае. Калі вы забудзецеся гэты PIN-код, вы выйдзеце з праграмы."</string>
|
||||
<string name="screen_app_lock_setup_pin_mismatch_dialog_content">"Увядзіце адзін і той жа PIN двойчы"</string>
|
||||
<string name="screen_app_lock_setup_pin_mismatch_dialog_title">"PIN-коды не супадаюць"</string>
|
||||
<string name="screen_app_lock_signout_alert_message">"Каб працягнуць, вам неабходна паўторна ўвайсці ў сістэму і стварыць новы PIN-код"</string>
|
||||
<string name="screen_app_lock_signout_alert_title">"Вы выходзіце з сістэмы"</string>
|
||||
<string name="screen_app_lock_use_biometric_android">"Выкарыстоўваць біяметрыю"</string>
|
||||
<string name="screen_app_lock_use_pin_android">"Выкарыстоўваць PIN-код"</string>
|
||||
<string name="screen_signout_in_progress_dialog_content">"Выхад…"</string>
|
||||
</resources>
|
||||
|
|
@ -76,7 +76,7 @@ fun AccountProviderView(
|
|||
} else {
|
||||
RoundedIconAtom(
|
||||
size = RoundedIconAtomSize.Medium,
|
||||
imageVector = CompoundIcons.Search,
|
||||
imageVector = CompoundIcons.Search(),
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package io.element.android.features.login.impl.screens.loginpassword
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
|
|
@ -55,6 +56,7 @@ import io.element.android.features.login.impl.R
|
|||
import io.element.android.features.login.impl.error.isWaitListError
|
||||
import io.element.android.features.login.impl.error.loginError
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
|
||||
|
|
@ -114,7 +116,7 @@ fun LoginPasswordView(
|
|||
.padding(padding)
|
||||
.consumeWindowInsets(padding)
|
||||
.verticalScroll(state = scrollState)
|
||||
.padding(horizontal = 16.dp),
|
||||
.padding(start = 20.dp, end = 20.dp, bottom = 20.dp),
|
||||
) {
|
||||
// Title
|
||||
IconTitleSubtitleMolecule(
|
||||
|
|
@ -137,16 +139,23 @@ fun LoginPasswordView(
|
|||
// Flexible spacing to keep the submit button at the bottom
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
// Submit
|
||||
Button(
|
||||
text = stringResource(CommonStrings.action_continue),
|
||||
showProgress = isLoading,
|
||||
onClick = ::submit,
|
||||
enabled = state.submitEnabled || isLoading,
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag(TestTags.loginContinue)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(60.dp))
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
ButtonColumnMolecule {
|
||||
Button(
|
||||
text = stringResource(CommonStrings.action_continue),
|
||||
showProgress = isLoading,
|
||||
onClick = ::submit,
|
||||
enabled = state.submitEnabled || isLoading,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag(TestTags.loginContinue)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(48.dp))
|
||||
}
|
||||
}
|
||||
|
||||
if (state.loginAction is AsyncData.Failure) {
|
||||
when {
|
||||
|
|
@ -170,7 +179,6 @@ private fun LoginForm(
|
|||
state: LoginPasswordState,
|
||||
isLoading: Boolean,
|
||||
onSubmit: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
var loginFieldState by textFieldState(stateValue = state.formState.login)
|
||||
var passwordFieldState by textFieldState(stateValue = state.formState.password)
|
||||
|
|
@ -178,7 +186,7 @@ private fun LoginForm(
|
|||
val focusManager = LocalFocusManager.current
|
||||
val eventSink = state.eventSink
|
||||
|
||||
Column(modifier) {
|
||||
Column {
|
||||
Text(
|
||||
text = stringResource(R.string.screen_login_form_header),
|
||||
modifier = Modifier.padding(start = 16.dp),
|
||||
|
|
@ -219,7 +227,7 @@ private fun LoginForm(
|
|||
IconButton(onClick = {
|
||||
loginFieldState = ""
|
||||
}) {
|
||||
Icon(imageVector = CompoundIcons.Close, contentDescription = stringResource(CommonStrings.action_clear))
|
||||
Icon(imageVector = CompoundIcons.Close(), contentDescription = stringResource(CommonStrings.action_clear))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -255,7 +263,7 @@ private fun LoginForm(
|
|||
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
trailingIcon = {
|
||||
val image =
|
||||
if (passwordVisible) CompoundIcons.VisibilityOn else CompoundIcons.VisibilityOff
|
||||
if (passwordVisible) CompoundIcons.VisibilityOn() else CompoundIcons.VisibilityOff()
|
||||
val description =
|
||||
if (passwordVisible) stringResource(CommonStrings.a11y_hide_password) else stringResource(CommonStrings.a11y_show_password)
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ fun SearchAccountProviderView(
|
|||
item {
|
||||
IconTitleSubtitleMolecule(
|
||||
modifier = Modifier.padding(top = 16.dp, bottom = 40.dp, start = 16.dp, end = 16.dp),
|
||||
iconImageVector = CompoundIcons.Search,
|
||||
iconImageVector = CompoundIcons.Search(),
|
||||
title = stringResource(id = R.string.screen_account_provider_form_title),
|
||||
subTitle = stringResource(id = R.string.screen_account_provider_form_subtitle),
|
||||
)
|
||||
|
|
@ -139,7 +139,7 @@ fun SearchAccountProviderView(
|
|||
eventSink(SearchAccountProviderEvents.UserInput(""))
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = CompoundIcons.Close,
|
||||
imageVector = CompoundIcons.Close(),
|
||||
contentDescription = stringResource(CommonStrings.action_clear)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,11 +25,11 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.features.login.impl.R
|
||||
import io.element.android.features.login.impl.error.isWaitListError
|
||||
import io.element.android.features.login.impl.error.loginError
|
||||
|
|
@ -119,11 +119,10 @@ private fun WaitListContent(
|
|||
private fun OverallContent(
|
||||
state: WaitListState,
|
||||
onCancelClicked: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(modifier = modifier.fillMaxSize()) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
if (state.loginAction !is AsyncData.Success) {
|
||||
CompositionLocalProvider(LocalContentColor provides Color.Black) {
|
||||
CompositionLocalProvider(LocalContentColor provides ElementTheme.colors.textOnSolidPrimary) {
|
||||
TextButton(
|
||||
text = stringResource(CommonStrings.action_cancel),
|
||||
onClick = onCancelClicked,
|
||||
|
|
|
|||
41
features/login/impl/src/main/res/values-be/translations.xml
Normal file
41
features/login/impl/src/main/res/values-be/translations.xml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_account_provider_change">"Змяніць правайдара ўліковага запісу"</string>
|
||||
<string name="screen_account_provider_form_hint">"Адрас хатняга сервера"</string>
|
||||
<string name="screen_account_provider_form_notice">"Увядзіце пошукавы запыт або адрас дамена."</string>
|
||||
<string name="screen_account_provider_form_subtitle">"Пошук кампаніі, супольнасці або прыватнага сервера."</string>
|
||||
<string name="screen_account_provider_form_title">"Знайдзіце правайдара ўліковых запісаў"</string>
|
||||
<string name="screen_account_provider_signin_title">"Вы збіраецеся ўвайсці ў %s"</string>
|
||||
<string name="screen_account_provider_signup_title">"Вы збіраецеся стварыць уліковы запіс на %s"</string>
|
||||
<string name="screen_change_account_provider_matrix_org_subtitle">"Matrix.org - гэта вялікі бясплатны сервер у агульнадаступнай сетцы Matrix для бяспечнай дэцэнтралізаванай сувязі, якім кіруе фонд Matrix.org."</string>
|
||||
<string name="screen_change_account_provider_other">"Іншае"</string>
|
||||
<string name="screen_change_account_provider_subtitle">"Выкарыстоўвайце іншага правайдара ўліковых запісаў, напрыклад, уласны прыватны сервер або працоўны ўліковы запіс."</string>
|
||||
<string name="screen_change_account_provider_title">"Змяніць правайдара ўліковага запісу"</string>
|
||||
<string name="screen_change_server_error_invalid_homeserver">"Нам не ўдалося звязацца з гэтым хатнім серверам. Упэўніцеся, што вы правільна ўвялі URL-адрас хатняга сервера. Калі URL-адрас пазначаны правільна, звярніцеся да адміністратара хатняга сервера за дадатковай дапамогай."</string>
|
||||
<string name="screen_change_server_error_no_sliding_sync_message">"На жаль, гэты сервер не падтрымлівае sliding sync."</string>
|
||||
<string name="screen_change_server_form_header">"URL хатняга сервера"</string>
|
||||
<string name="screen_change_server_form_notice">"Вы можаце падключыцца толькі да існуючага сервера, які падтрымлівае sliding sync. Адміністратару хатняга сервера запатрабуецца наладзіць яго. %1$s"</string>
|
||||
<string name="screen_change_server_subtitle">"Які адрас вашага сервера?"</string>
|
||||
<string name="screen_change_server_title">"Выберыце свой сервер"</string>
|
||||
<string name="screen_login_error_deactivated_account">"Гэты ўліковы запіс быў дэактываваны."</string>
|
||||
<string name="screen_login_error_invalid_credentials">"Няправільнае імя карыстальніка і/або пароль"</string>
|
||||
<string name="screen_login_error_invalid_user_id">"Гэта несапраўдны ідэнтыфікатар карыстальніка. Чаканы фармат: ‘@user:homeserver.org’"</string>
|
||||
<string name="screen_login_error_unsupported_authentication">"Выбраны хатні сервер не падтрымлівае пароль або ўваход у OIDC. Калі ласка, звярніцеся да адміністратара або абярыце іншы хатні сервер."</string>
|
||||
<string name="screen_login_form_header">"Увядзіце свае даныя"</string>
|
||||
<string name="screen_login_title">"Сардэчна запрашаем!"</string>
|
||||
<string name="screen_login_title_with_homeserver">"Увайдзіце ў %1$s"</string>
|
||||
<string name="screen_server_confirmation_change_server">"Змяніць правайдара ўліковага запісу"</string>
|
||||
<string name="screen_server_confirmation_message_login_element_dot_io">"Прыватны сервер для супрацоўнікаў Element."</string>
|
||||
<string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix - гэта адкрытая сетка для бяспечнай, дэцэнтралізаванай сувязі."</string>
|
||||
<string name="screen_server_confirmation_message_register">"Тут будуць захоўвацца вашыя размовы - сапраўды гэтак жа, як вы выкарыстоўваеце паштовага правайдара для захоўвання сваіх лістоў."</string>
|
||||
<string name="screen_server_confirmation_title_login">"Вы збіраецеся ўвайсці ў %1$s"</string>
|
||||
<string name="screen_server_confirmation_title_register">"Вы збіраецеся стварыць уліковы запіс на %1$s"</string>
|
||||
<string name="screen_waitlist_message">"Зараз існуе высокі попыт на %1$s на %2$s. Калі ласка, вярніцеся ў дадатак праз некалькі дзён і паспрабуйце зноў.
|
||||
|
||||
Дзякуй за цярпенне!"</string>
|
||||
<string name="screen_waitlist_title">"Амаль гатова."</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Тут будуць захоўвацца вашыя размовы - сапраўды гэтак жа, як вы выкарыстоўваеце паштовага правайдара для захоўвання сваіх лістоў."</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Тут будуць захоўвацца вашыя размовы - сапраўды гэтак жа, як вы выкарыстоўваеце паштовага правайдара для захоўвання сваіх лістоў."</string>
|
||||
<string name="screen_login_subtitle">"Matrix - гэта адкрытая сетка для бяспечнай, дэцэнтралізаванай сувязі."</string>
|
||||
<string name="screen_waitlist_message_success">"Вітаем у %1$s!"</string>
|
||||
</resources>
|
||||
|
|
@ -5,9 +5,7 @@
|
|||
<string name="screen_account_provider_form_notice">"Zadejte hledaný výraz nebo adresu domény."</string>
|
||||
<string name="screen_account_provider_form_subtitle">"Vyhledejte společnost, komunitu nebo soukromý server."</string>
|
||||
<string name="screen_account_provider_form_title">"Najít poskytovatele účtu"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Zde budou uloženy vaše konverzace - podobně jako u poskytovatele e-mailových služeb uchováváte své e-maily."</string>
|
||||
<string name="screen_account_provider_signin_title">"Chystáte se přihlásit do %s"</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Zde budou uloženy vaše konverzace - podobně jako u poskytovatele e-mailových služeb uchováváte své e-maily."</string>
|
||||
<string name="screen_account_provider_signup_title">"Chystáte se vytvořit účet na %s"</string>
|
||||
<string name="screen_change_account_provider_matrix_org_subtitle">"Matrix.org je velký bezplatný server ve veřejné síti Matrix pro bezpečnou decentralizovanou komunikaci, který provozuje nadace Matrix.org."</string>
|
||||
<string name="screen_change_account_provider_other">"Jiný"</string>
|
||||
|
|
@ -37,6 +35,8 @@
|
|||
Díky za trpělivost!"</string>
|
||||
<string name="screen_waitlist_title">"Jste v pořadníku!"</string>
|
||||
<string name="screen_waitlist_title_success">"Jdete do toho!"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Zde budou uloženy vaše konverzace - podobně jako u poskytovatele e-mailových služeb uchováváte své e-maily."</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Zde budou uloženy vaše konverzace - podobně jako u poskytovatele e-mailových služeb uchováváte své e-maily."</string>
|
||||
<string name="screen_login_subtitle">"Matrix je otevřená síť pro bezpečnou a decentralizovanou komunikaci."</string>
|
||||
<string name="screen_waitlist_message_success">"Vítá vás %1$s!"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@
|
|||
<string name="screen_account_provider_form_notice">"Gib einen Suchbegriff oder eine Domainadresse ein."</string>
|
||||
<string name="screen_account_provider_form_subtitle">"Suche nach einem Unternehmen, einer Community oder einem privaten Server."</string>
|
||||
<string name="screen_account_provider_form_title">"Kontoanbieter finden"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Hier werden deine Gespräche gespeichert – genau so, wie du einen E-Mail-Anbieter nutzen würdest, um deine E-Mails aufzubewahren."</string>
|
||||
<string name="screen_account_provider_signin_title">"Du bist dabei, dich bei %s anzumelden"</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Hier werden deine Gespräche gespeichert – genau so, wie du einen E-Mail-Anbieter nutzen würdest, um deine E-Mails aufzubewahren."</string>
|
||||
<string name="screen_account_provider_signup_title">"Du bist dabei, ein Konto bei %s zu erstellen"</string>
|
||||
<string name="screen_change_account_provider_matrix_org_subtitle">"Matrix.org ist ein großer, kostenloser Server im öffentlichen Matrix-Netzwerk für eine sichere, dezentralisierte Kommunikation, der von der Matrix.org Foundation betrieben wird."</string>
|
||||
<string name="screen_change_account_provider_other">"Sonstige"</string>
|
||||
|
|
@ -37,6 +35,8 @@
|
|||
Danke für deine Geduld!"</string>
|
||||
<string name="screen_waitlist_title">"Du bist fast am Ziel."</string>
|
||||
<string name="screen_waitlist_title_success">"Du bist dabei."</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Hier werden deine Gespräche gespeichert - so wie du deine E-Mails bei einem E-Mail-Anbieter aufbewahren würden."</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Hier werden deine Gespräche gespeichert - so wie du deine E-Mails bei einem E-Mail-Anbieter aufbewahren würden."</string>
|
||||
<string name="screen_login_subtitle">"Matrix ist ein offenes Netzwerk für eine sichere, dezentrale Kommunikation."</string>
|
||||
<string name="screen_waitlist_message_success">"Willkommen bei %1$s!"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@
|
|||
<string name="screen_account_provider_form_notice">"Introduzca un término de búsqueda o una dirección de dominio."</string>
|
||||
<string name="screen_account_provider_form_subtitle">"Busca una empresa, comunidad o servidor privado."</string>
|
||||
<string name="screen_account_provider_form_title">"Encontrar un proveedor de cuenta"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Aquí es donde se alojarán tus conversaciones — justo como si utilizaras un proveedor de correo electrónico para guardar tus correos electrónicos."</string>
|
||||
<string name="screen_account_provider_signin_title">"Estás a punto de iniciar sesión en %s"</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Aquí es donde se alojarán tus conversaciones — justo como si utilizaras un proveedor de correo electrónico para guardar tus correos electrónicos."</string>
|
||||
<string name="screen_account_provider_signup_title">"Estás a punto de crear una cuenta en %s"</string>
|
||||
<string name="screen_change_account_provider_matrix_org_subtitle">"Matrix.org es un servidor grande y gratuito en la red pública Matrix para una comunicación segura y descentralizada, administrado por la Fundación Matrix.org."</string>
|
||||
<string name="screen_change_account_provider_other">"Otro"</string>
|
||||
|
|
@ -37,6 +35,8 @@
|
|||
¡Gracias por tu paciencia!"</string>
|
||||
<string name="screen_waitlist_title">"Ya casi has terminado."</string>
|
||||
<string name="screen_waitlist_title_success">"Estás dentro."</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Aquí es donde se alojarán tus conversaciones — justo como utilizarías un proveedor de correo electrónico para guardar tus correos electrónicos."</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Aquí es donde se alojarán tus conversaciones — justo como utilizarías un proveedor de correo electrónico para guardar tus correos electrónicos."</string>
|
||||
<string name="screen_login_subtitle">"Matrix es una red abierta para una comunicación segura y descentralizada."</string>
|
||||
<string name="screen_waitlist_message_success">"¡Bienvenido a %1$s!"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@
|
|||
<string name="screen_account_provider_form_notice">"Entrez un terme de recherche ou une adresse de domaine."</string>
|
||||
<string name="screen_account_provider_form_subtitle">"Recherchez une entreprise, une communauté ou un serveur privé."</string>
|
||||
<string name="screen_account_provider_form_title">"Trouver un fournisseur de comptes"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"C’est ici que vos conversations seront enregistrées, comme vous le feriez avec un fournisseur de messagerie pour conserver vos e-mails."</string>
|
||||
<string name="screen_account_provider_signin_title">"Vous êtes sur le point de vous connecter à %s"</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"C’est ici que vos conversations seront enregistrées, comme vous le feriez avec un fournisseur de messagerie pour conserver vos e-mails."</string>
|
||||
<string name="screen_account_provider_signup_title">"Vous êtes sur le point de créer un compte sur %s"</string>
|
||||
<string name="screen_change_account_provider_matrix_org_subtitle">"Matrix.org est un grand serveur gratuit sur le réseau public Matrix pour une communication sécurisée et décentralisée, géré par la Fondation Matrix.org."</string>
|
||||
<string name="screen_change_account_provider_other">"Autres"</string>
|
||||
|
|
@ -37,6 +35,8 @@
|
|||
Merci pour votre patience !"</string>
|
||||
<string name="screen_waitlist_title">"Vous y êtes presque."</string>
|
||||
<string name="screen_waitlist_title_success">"Vous y êtes."</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"C’est ici que vos conversations seront enregistrées, comme vous le feriez avec un fournisseur de messagerie pour conserver vos e-mails."</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"C’est ici que vos conversations seront enregistrées, comme vous le feriez avec un fournisseur de messagerie pour conserver vos e-mails."</string>
|
||||
<string name="screen_login_subtitle">"Matrix est un réseau ouvert pour une communication sécurisée et décentralisée."</string>
|
||||
<string name="screen_waitlist_message_success">"Bienvenue dans %1$s !"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -5,10 +5,8 @@
|
|||
<string name="screen_account_provider_form_notice">"Adjon meg egy keresési kifejezést vagy egy tartománycímet."</string>
|
||||
<string name="screen_account_provider_form_subtitle">"Keresés egy cégre, közösségre vagy privát kiszolgálóra."</string>
|
||||
<string name="screen_account_provider_form_title">"Fiókszolgáltató keresése"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Itt lesznek a beszélgetései – ahogyan egy e-mail-szolgáltatást is használna a levelei kezeléséhez."</string>
|
||||
<string name="screen_account_provider_signin_title">"Hamarosan bejelentkezik ide: %s"</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Itt lesznek a beszélgetéseid – ahogyan egy e-mail-szolgáltatást is használnál a leveleid kezeléséhez."</string>
|
||||
<string name="screen_account_provider_signup_title">"Hamarosan létrehoz egy fiókot itt: %s"</string>
|
||||
<string name="screen_account_provider_signup_title">"Hamarosan létrehozol egy fiókot itt: %s"</string>
|
||||
<string name="screen_change_account_provider_matrix_org_subtitle">"A Matrix.org egy nagy, ingyenes kiszolgáló a nyilvános Matrix-hálózaton, a biztonságos, decentralizált kommunikáció érdekében, amelyet a Matrix.org Alapítvány üzemeltet."</string>
|
||||
<string name="screen_change_account_provider_other">"Egyéb"</string>
|
||||
<string name="screen_change_account_provider_subtitle">"Másik fiókszolgáltató, például a saját privát kiszolgáló vagy egy munkahelyi fiók használata."</string>
|
||||
|
|
@ -37,6 +35,8 @@
|
|||
Köszönjük a türelmét!"</string>
|
||||
<string name="screen_waitlist_title">"Már majdnem kész van."</string>
|
||||
<string name="screen_waitlist_title_success">"Bent van."</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Itt lesznek a beszélgetései – ahogyan egy e-mail-szolgáltatást is használna a levelei kezeléséhez."</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Itt lesznek a beszélgetései – ahogyan egy e-mail-szolgáltatást is használna a levelei kezeléséhez."</string>
|
||||
<string name="screen_login_subtitle">"A Matrix egy nyitott hálózat a biztonságos, decentralizált kommunikációhoz."</string>
|
||||
<string name="screen_waitlist_message_success">"Üdvözli az %1$s!"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@
|
|||
<string name="screen_account_provider_form_notice">"Masukkan istilah pencarian atau alamat domain."</string>
|
||||
<string name="screen_account_provider_form_subtitle">"Cari perusahaan, komunitas, atau server pribadi."</string>
|
||||
<string name="screen_account_provider_form_title">"Cari penyedia akun"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Di sinilah percakapan Anda akan berlangsung — sama seperti Anda menggunakan penyedia surel untuk menyimpan surel Anda."</string>
|
||||
<string name="screen_account_provider_signin_title">"Anda akan masuk ke %s"</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Di sinilah percakapan Anda akan berlangsung — sama seperti Anda menggunakan penyedia surel untuk menyimpan surel Anda."</string>
|
||||
<string name="screen_account_provider_signup_title">"Anda akan membuat akun di %s"</string>
|
||||
<string name="screen_change_account_provider_matrix_org_subtitle">"Matrix.org adalah server besar dan gratis di jaringan Matrix publik untuk komunikasi yang aman dan terdesentralisasi, disediakan oleh Yayasan Matrix.org."</string>
|
||||
<string name="screen_change_account_provider_other">"Lainnya"</string>
|
||||
|
|
@ -37,6 +35,8 @@
|
|||
Terima kasih atas kesabaran Anda!"</string>
|
||||
<string name="screen_waitlist_title">"Anda hampir selesai."</string>
|
||||
<string name="screen_waitlist_title_success">"Anda sudah masuk."</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Di sinilah percakapan Anda akan berlangsung — sama seperti Anda menggunakan penyedia surel untuk menyimpan surel Anda."</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Di sinilah percakapan Anda akan berlangsung — sama seperti Anda menggunakan penyedia surel untuk menyimpan surel Anda."</string>
|
||||
<string name="screen_login_subtitle">"Matrix adalah jaringan terbuka untuk komunikasi yang aman dan terdesentralisasi."</string>
|
||||
<string name="screen_waitlist_message_success">"Selamat datang di %1$s!"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@
|
|||
<string name="screen_account_provider_form_notice">"Inserisci un termine di ricerca o un indirizzo di dominio."</string>
|
||||
<string name="screen_account_provider_form_subtitle">"Cerca un\' azienda, una comunità o un server privato."</string>
|
||||
<string name="screen_account_provider_form_title">"Trova un fornitore di account"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Qui è dove vivranno le tue conversazioni - proprio come useresti un fornitore di posta elettronica per conservare le tue email."</string>
|
||||
<string name="screen_account_provider_signin_title">"Stai per accedere a %s"</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Qui è dove vivranno le tue conversazioni - proprio come useresti un fornitore di posta elettronica per conservare le tue email."</string>
|
||||
<string name="screen_account_provider_signup_title">"Stai per creare un account su %s"</string>
|
||||
<string name="screen_change_account_provider_matrix_org_subtitle">"Matrix.org è un grande server gratuito nella rete pubblica Matrix per una comunicazione sicura e decentralizzata, gestito dalla Fondazione Matrix.org."</string>
|
||||
<string name="screen_change_account_provider_other">"Altro"</string>
|
||||
|
|
@ -37,6 +35,8 @@
|
|||
Grazie per la pazienza!"</string>
|
||||
<string name="screen_waitlist_title">"Ci sei quasi."</string>
|
||||
<string name="screen_waitlist_title_success">"Sei dentro."</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Qui è dove vivranno le tue conversazioni — proprio come useresti un fornitore di posta elettronica per conservare le tue email."</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Qui è dove vivranno le tue conversazioni — proprio come useresti un fornitore di posta elettronica per conservare le tue email."</string>
|
||||
<string name="screen_login_subtitle">"Matrix è una rete aperta per comunicazioni sicure e decentralizzate."</string>
|
||||
<string name="screen_waitlist_message_success">"Benvenuti in %1$s!"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@
|
|||
<string name="screen_account_provider_form_notice">"Introduceţi un termen de căutare sau o adresă de domeniu."</string>
|
||||
<string name="screen_account_provider_form_subtitle">"Căutați o companie, o comunitate sau un server privat."</string>
|
||||
<string name="screen_account_provider_form_title">"Găsiți un furnizor de cont"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Aici vor trăi conversațiile dumneavoastră - la fel cum ați folosi un furnizor de e-mail pentru a vă păstra e-mailurile."</string>
|
||||
<string name="screen_account_provider_signin_title">"Sunteți pe cale să vă conectați la %s"</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Aici vor trăi conversațiile dumneavoastră - la fel cum ați folosi un furnizor de e-mail pentru a vă păstra e-mailurile."</string>
|
||||
<string name="screen_account_provider_signup_title">"Sunteți pe cale să creați un cont pe %s"</string>
|
||||
<string name="screen_change_account_provider_matrix_org_subtitle">"Matrix.org este un server mare și gratuit din rețeaua publică Matrix pentru comunicații sigure și descentralizate, administrat de Fundația Matrix.org."</string>
|
||||
<string name="screen_change_account_provider_other">"Altul"</string>
|
||||
|
|
@ -36,6 +34,8 @@
|
|||
Vă mulțumim pentru răbdare!"</string>
|
||||
<string name="screen_waitlist_title">"Sunteți pe lista de așteptare"</string>
|
||||
<string name="screen_waitlist_title_success">"Sunteți conectat!"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Aici vor trăi conversațiile dvs. - la fel cum ați folosi un furnizor de e-mail pentru a vă păstra e-mailurile."</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Aici vor trăi conversațiile dvs. - la fel cum ați folosi un furnizor de e-mail pentru a vă păstra e-mailurile."</string>
|
||||
<string name="screen_login_subtitle">"Matrix este o rețea deschisă pentru o comunicare sigură și descentralizată."</string>
|
||||
<string name="screen_waitlist_message_success">"Bun venit la%1$s!"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@
|
|||
<string name="screen_account_provider_form_notice">"Введите поисковый запрос или адрес домена."</string>
|
||||
<string name="screen_account_provider_form_subtitle">"Поиск компании, сообщества или частного сервера."</string>
|
||||
<string name="screen_account_provider_form_title">"Поиск сервера учетной записи"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Здесь будут храниться ваши разговоры - точно так же, как вы используете почтового провайдера для хранения своих писем."</string>
|
||||
<string name="screen_account_provider_signin_title">"Вы собираетесь войти в %s"</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Здесь будут храниться ваши разговоры - точно так же, как вы используете почтового провайдера для хранения своих писем."</string>
|
||||
<string name="screen_account_provider_signup_title">"Вы собираетесь создать учетную запись на %s"</string>
|
||||
<string name="screen_change_account_provider_matrix_org_subtitle">"Matrix.org — это большой бесплатный сервер в общедоступной сети Matrix для безопасной децентрализованной связи, управляемый Matrix.org Foundation."</string>
|
||||
<string name="screen_change_account_provider_other">"Другое"</string>
|
||||
|
|
@ -37,6 +35,8 @@
|
|||
Спасибо за терпение!"</string>
|
||||
<string name="screen_waitlist_title">"Почти готово."</string>
|
||||
<string name="screen_waitlist_title_success">"Вы зарегистрированы."</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Здесь будут храниться ваши разговоры - точно так же, как вы используете почтового провайдера для хранения своих писем."</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Здесь будут храниться ваши разговоры - точно так же, как вы используете почтового провайдера для хранения своих писем."</string>
|
||||
<string name="screen_login_subtitle">"Matrix — это открытая сеть для безопасной децентрализованной связи."</string>
|
||||
<string name="screen_waitlist_message_success">"Добро пожаловать в %1$s!"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@
|
|||
<string name="screen_account_provider_form_notice">"Zadajte hľadaný výraz alebo adresu domény."</string>
|
||||
<string name="screen_account_provider_form_subtitle">"Vyhľadať spoločnosť, komunitu alebo súkromný server."</string>
|
||||
<string name="screen_account_provider_form_title">"Nájsť poskytovateľa účtu"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Tu budú žiť vaše konverzácie — podobne ako používate poskytovateľa e-mailových služieb na uchovávanie e-mailov."</string>
|
||||
<string name="screen_account_provider_signin_title">"Chystáte sa prihlásiť do %s"</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Tu budú žiť vaše konverzácie — podobne ako používate poskytovateľa e-mailových služieb na uchovávanie e-mailov."</string>
|
||||
<string name="screen_account_provider_signup_title">"Chystáte sa vytvoriť účet na %s"</string>
|
||||
<string name="screen_change_account_provider_matrix_org_subtitle">"Matrix.org je veľký bezplatný server vo verejnej sieti Matrix na bezpečnú, decentralizovanú komunikáciu, ktorý prevádzkuje nadácia Matrix.org."</string>
|
||||
<string name="screen_change_account_provider_other">"Iný"</string>
|
||||
|
|
@ -37,6 +35,8 @@
|
|||
Ďakujeme za trpezlivosť!"</string>
|
||||
<string name="screen_waitlist_title">"Ste na čakanej listine!"</string>
|
||||
<string name="screen_waitlist_title_success">"Ste dnu!"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Tu budú žiť vaše konverzácie - podobne ako používate poskytovateľa e-mailových služieb na uchovávanie e-mailov."</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Tu budú žiť vaše konverzácie - podobne ako používate poskytovateľa e-mailových služieb na uchovávanie e-mailov."</string>
|
||||
<string name="screen_login_subtitle">"Matrix je otvorená sieť pre bezpečnú a decentralizovanú komunikáciu."</string>
|
||||
<string name="screen_waitlist_message_success">"Vitajte v %1$s!"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@
|
|||
<string name="screen_account_provider_form_notice">"輸入關鍵字或網域名稱。"</string>
|
||||
<string name="screen_account_provider_form_subtitle">"搜尋公司、社群、私有伺服器。"</string>
|
||||
<string name="screen_account_provider_form_title">"尋找帳號提供者"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"您的所有對話將保存於此,就如同您的電子郵件供應商會保存您的電子郵件一樣。"</string>
|
||||
<string name="screen_account_provider_signin_title">"您即將登入 %s"</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"您的所有對話將保存於此,就如同您的電子郵件供應商會保存您的電子郵件一樣。"</string>
|
||||
<string name="screen_account_provider_signup_title">"您即將在 %s 建立帳號"</string>
|
||||
<string name="screen_change_account_provider_matrix_org_subtitle">"Matrix.org 由 Matrix.org 基金會營運,是用於安全、去中心化通訊的公共 Matrix 網路上的大型免費伺服器。"</string>
|
||||
<string name="screen_change_account_provider_other">"其他"</string>
|
||||
|
|
@ -27,6 +25,8 @@
|
|||
<string name="screen_server_confirmation_message_register">"您的所有對話將保存於此,就如同您的電子郵件供應商會保存您的電子郵件一樣。"</string>
|
||||
<string name="screen_server_confirmation_title_login">"您即將登入 %1$s"</string>
|
||||
<string name="screen_server_confirmation_title_register">"您即將在 %1$s 建立帳號"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"您的所有對話將保存於此,就如同您的電子郵件供應商會保存您的電子郵件一樣。"</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"您的所有對話將保存於此,就如同您的電子郵件供應商會保存您的電子郵件一樣。"</string>
|
||||
<string name="screen_login_subtitle">"Matrix 是一個開放網路,為了安全且去中心化的通訊而生。"</string>
|
||||
<string name="screen_waitlist_message_success">"歡迎使用 %1$s!"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@
|
|||
<string name="screen_account_provider_form_notice">"Enter a search term or a domain address."</string>
|
||||
<string name="screen_account_provider_form_subtitle">"Search for a company, community, or private server."</string>
|
||||
<string name="screen_account_provider_form_title">"Find an account provider"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"This is where your conversations will live — just like you would use an email provider to keep your emails."</string>
|
||||
<string name="screen_account_provider_signin_title">"You’re about to sign in to %s"</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"This is where your conversations will live — just like you would use an email provider to keep your emails."</string>
|
||||
<string name="screen_account_provider_signup_title">"You’re about to create an account on %s"</string>
|
||||
<string name="screen_change_account_provider_matrix_org_subtitle">"Matrix.org is a large, free server on the public Matrix network for secure, decentralised communication, run by the Matrix.org Foundation."</string>
|
||||
<string name="screen_change_account_provider_other">"Other"</string>
|
||||
|
|
@ -37,6 +35,8 @@
|
|||
Thanks for your patience!"</string>
|
||||
<string name="screen_waitlist_title">"You’re almost there."</string>
|
||||
<string name="screen_waitlist_title_success">"You\'re in."</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"This is where your conversations will live — just like you would use an email provider to keep your emails."</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"This is where your conversations will live — just like you would use an email provider to keep your emails."</string>
|
||||
<string name="screen_login_subtitle">"Matrix is an open network for secure, decentralised communication."</string>
|
||||
<string name="screen_waitlist_message_success">"Welcome to %1$s!"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -24,12 +24,11 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.features.logout.impl.tools.isBackingUp
|
||||
import io.element.android.features.logout.impl.ui.LogoutActionDialog
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
|
|
@ -41,7 +40,6 @@ import io.element.android.libraries.designsystem.theme.components.LinearProgress
|
|||
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.theme.progressIndicatorTrackColor
|
||||
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
||||
import io.element.android.libraries.matrix.api.encryption.BackupState
|
||||
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
|
||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||
|
|
@ -64,7 +62,7 @@ fun LogoutView(
|
|||
onBackClicked = onBackClicked,
|
||||
title = title(state),
|
||||
subTitle = subtitle(state),
|
||||
iconVector = ImageVector.vectorResource(CommonDrawables.ic_key),
|
||||
iconVector = CompoundIcons.KeySolid(),
|
||||
modifier = modifier,
|
||||
content = { Content(state) },
|
||||
buttons = {
|
||||
|
|
@ -86,7 +84,7 @@ fun LogoutView(
|
|||
onForceLogoutClicked = {
|
||||
eventSink(LogoutEvents.Logout(ignoreSdkError = true))
|
||||
},
|
||||
onDismissError = {
|
||||
onDismissDialog = {
|
||||
eventSink(LogoutEvents.CloseDialogs)
|
||||
},
|
||||
onSuccessLogout = {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class DefaultDirectLogoutView @Inject constructor() : DirectLogoutView {
|
|||
onForceLogoutClicked = {
|
||||
eventSink(DirectLogoutEvents.Logout(ignoreSdkError = true))
|
||||
},
|
||||
onDismissError = {
|
||||
onDismissDialog = {
|
||||
eventSink(DirectLogoutEvents.CloseDialogs)
|
||||
},
|
||||
onSuccessLogout = {
|
||||
|
|
|
|||
|
|
@ -32,8 +32,7 @@ fun LogoutActionDialog(
|
|||
state: AsyncAction<String?>,
|
||||
onConfirmClicked: () -> Unit,
|
||||
onForceLogoutClicked: () -> Unit,
|
||||
// TODO Rename
|
||||
onDismissError: () -> Unit,
|
||||
onDismissDialog: () -> Unit,
|
||||
onSuccessLogout: (String?) -> Unit,
|
||||
) {
|
||||
when (state) {
|
||||
|
|
@ -42,7 +41,7 @@ fun LogoutActionDialog(
|
|||
AsyncAction.Confirming ->
|
||||
LogoutConfirmationDialog(
|
||||
onSubmitClicked = onConfirmClicked,
|
||||
onDismiss = onDismissError
|
||||
onDismiss = onDismissDialog
|
||||
)
|
||||
is AsyncAction.Loading ->
|
||||
ProgressDialog(text = stringResource(id = R.string.screen_signout_in_progress_dialog_content))
|
||||
|
|
@ -52,7 +51,7 @@ fun LogoutActionDialog(
|
|||
content = stringResource(id = CommonStrings.error_unknown),
|
||||
retryText = stringResource(id = CommonStrings.action_signout_anyway),
|
||||
onRetry = onForceLogoutClicked,
|
||||
onDismiss = onDismissError,
|
||||
onDismiss = onDismissDialog,
|
||||
)
|
||||
is AsyncAction.Success -> {
|
||||
val latestOnSuccessLogout by rememberUpdatedState(onSuccessLogout)
|
||||
|
|
|
|||
18
features/logout/impl/src/main/res/values-be/translations.xml
Normal file
18
features/logout/impl/src/main/res/values-be/translations.xml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_signout_confirmation_dialog_content">"Вы ўпэўнены, што жадаеце выйсці?"</string>
|
||||
<string name="screen_signout_in_progress_dialog_content">"Выхад…"</string>
|
||||
<string name="screen_signout_key_backup_disabled_subtitle">"Вы збіраецеся выйсці з апошняга сеанса. Калі вы выйдзеце з сістэмы зараз, вы страціце доступ да зашыфраваных паведамленняў."</string>
|
||||
<string name="screen_signout_key_backup_disabled_title">"Вы адключылі рэзервовае капіраванне"</string>
|
||||
<string name="screen_signout_key_backup_offline_subtitle">"Вашы ключы ўсё яшчэ захоўваліся, калі вы выйшлі з сеткі. Паўторна падключыцеся, каб можна было стварыць рэзервовую копію вашых ключоў перад выхадам."</string>
|
||||
<string name="screen_signout_key_backup_offline_title">"Рэзервовае капіраванне ключоў усё яшчэ працягваецца"</string>
|
||||
<string name="screen_signout_key_backup_ongoing_subtitle">"Калі ласка, дачакайцеся завяршэння працэсу, перш чым выходзіць з сістэмы."</string>
|
||||
<string name="screen_signout_key_backup_ongoing_title">"Вашы ключы ўсё яшчэ ствараюцца"</string>
|
||||
<string name="screen_signout_recovery_disabled_subtitle">"Вы збіраецеся выйсці з апошняга сеанса. Калі вы выйдзеце з сістэмы зараз, вы страціце доступ да зашыфраваных паведамленняў."</string>
|
||||
<string name="screen_signout_recovery_disabled_title">"Аднаўленне не наладжана"</string>
|
||||
<string name="screen_signout_save_recovery_key_subtitle">"Вы збіраецеся выйсці з апошняга сеанса. Калі вы выйдзеце з сістэмы зараз, вы страціце доступ да зашыфраваных паведамленняў."</string>
|
||||
<string name="screen_signout_save_recovery_key_title">"Вы захавалі свой ключ аднаўлення?"</string>
|
||||
<string name="screen_signout_confirmation_dialog_submit">"Выйсці"</string>
|
||||
<string name="screen_signout_confirmation_dialog_title">"Выйсці"</string>
|
||||
<string name="screen_signout_preference_item">"Выйсці"</string>
|
||||
</resources>
|
||||
|
|
@ -62,6 +62,7 @@ dependencies {
|
|||
implementation(projects.libraries.voicerecorder.api)
|
||||
implementation(projects.libraries.mediaplayer.api)
|
||||
implementation(projects.libraries.uiUtils)
|
||||
implementation(projects.libraries.testtags)
|
||||
implementation(projects.features.networkmonitor.api)
|
||||
implementation(projects.services.analytics.api)
|
||||
implementation(libs.coil.compose)
|
||||
|
|
@ -94,6 +95,7 @@ dependencies {
|
|||
testImplementation(projects.libraries.voicerecorder.test)
|
||||
testImplementation(projects.libraries.mediaplayer.test)
|
||||
testImplementation(projects.libraries.mediaviewer.test)
|
||||
testImplementation(projects.libraries.testtags)
|
||||
testImplementation(libs.test.mockk)
|
||||
testImplementation(libs.test.junitext)
|
||||
testImplementation(libs.test.robolectric)
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
|||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
|
||||
import io.element.android.features.messages.impl.typing.TypingNotificationPresenter
|
||||
import io.element.android.features.messages.impl.utils.messagesummary.MessageSummaryFormatter
|
||||
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageComposerPresenter
|
||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
||||
|
|
@ -97,6 +98,7 @@ class MessagesPresenter @AssistedInject constructor(
|
|||
private val composerPresenter: MessageComposerPresenter,
|
||||
private val voiceMessageComposerPresenter: VoiceMessageComposerPresenter,
|
||||
timelinePresenterFactory: TimelinePresenter.Factory,
|
||||
private val typingNotificationPresenter: TypingNotificationPresenter,
|
||||
private val actionListPresenter: ActionListPresenter,
|
||||
private val customReactionPresenter: CustomReactionPresenter,
|
||||
private val reactionSummaryPresenter: ReactionSummaryPresenter,
|
||||
|
|
@ -129,6 +131,7 @@ class MessagesPresenter @AssistedInject constructor(
|
|||
val composerState = composerPresenter.present()
|
||||
val voiceMessageComposerState = voiceMessageComposerPresenter.present()
|
||||
val timelineState = timelinePresenter.present()
|
||||
val typingNotificationState = typingNotificationPresenter.present()
|
||||
val actionListState = actionListPresenter.present()
|
||||
val customReactionState = customReactionPresenter.present()
|
||||
val reactionSummaryState = reactionSummaryPresenter.present()
|
||||
|
|
@ -139,7 +142,7 @@ class MessagesPresenter @AssistedInject constructor(
|
|||
val userHasPermissionToSendMessage by room.canSendMessageAsState(type = MessageEventType.ROOM_MESSAGE, updateKey = syncUpdateFlow.value)
|
||||
val userHasPermissionToRedactOwn by room.canRedactOwnAsState(updateKey = syncUpdateFlow.value)
|
||||
val userHasPermissionToRedactOther by room.canRedactOtherAsState(updateKey = syncUpdateFlow.value)
|
||||
val userHasPermissionToSendReaction by room.canSendMessageAsState(type = MessageEventType.REACTION_SENT, updateKey = syncUpdateFlow.value)
|
||||
val userHasPermissionToSendReaction by room.canSendMessageAsState(type = MessageEventType.REACTION, updateKey = syncUpdateFlow.value)
|
||||
val roomName: AsyncData<String> by remember {
|
||||
derivedStateOf { roomInfo?.name?.let { AsyncData.Success(it) } ?: AsyncData.Uninitialized }
|
||||
}
|
||||
|
|
@ -155,6 +158,14 @@ class MessagesPresenter @AssistedInject constructor(
|
|||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
// Remove the unread flag on entering but don't send read receipts
|
||||
// as those will be handled by the timeline.
|
||||
withContext(dispatchers.io) {
|
||||
room.setUnreadFlag(isUnread = false)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(syncUpdateFlow.value) {
|
||||
withContext(dispatchers.io) {
|
||||
canJoinCall = room.canUserJoinCall(room.sessionId).getOrDefault(false)
|
||||
|
|
@ -225,6 +236,7 @@ class MessagesPresenter @AssistedInject constructor(
|
|||
composerState = composerState,
|
||||
voiceMessageComposerState = voiceMessageComposerState,
|
||||
timelineState = timelineState,
|
||||
typingNotificationState = typingNotificationState,
|
||||
actionListState = actionListState,
|
||||
customReactionState = customReactionState,
|
||||
reactionSummaryState = reactionSummaryState,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import io.element.android.features.messages.impl.timeline.components.customreact
|
|||
import io.element.android.features.messages.impl.timeline.components.reactionsummary.ReactionSummaryState
|
||||
import io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet.ReadReceiptBottomSheetState
|
||||
import io.element.android.features.messages.impl.timeline.components.retrysendmenu.RetrySendMenuState
|
||||
import io.element.android.features.messages.impl.typing.TypingNotificationState
|
||||
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageComposerState
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
|
|
@ -42,6 +43,7 @@ data class MessagesState(
|
|||
val composerState: MessageComposerState,
|
||||
val voiceMessageComposerState: VoiceMessageComposerState,
|
||||
val timelineState: TimelineState,
|
||||
val typingNotificationState: TypingNotificationState,
|
||||
val actionListState: ActionListState,
|
||||
val customReactionState: CustomReactionState,
|
||||
val reactionSummaryState: ReactionSummaryState,
|
||||
|
|
|
|||
|
|
@ -17,16 +17,26 @@
|
|||
package io.element.android.features.messages.impl
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.features.messages.impl.actionlist.ActionListState
|
||||
import io.element.android.features.messages.impl.actionlist.anActionListState
|
||||
import io.element.android.features.messages.impl.messagecomposer.AttachmentsState
|
||||
import io.element.android.features.messages.impl.messagecomposer.MessageComposerState
|
||||
import io.element.android.features.messages.impl.messagecomposer.aMessageComposerState
|
||||
import io.element.android.features.messages.impl.timeline.TimelineState
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemList
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineState
|
||||
import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionEvents
|
||||
import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionState
|
||||
import io.element.android.features.messages.impl.timeline.components.reactionsummary.ReactionSummaryEvents
|
||||
import io.element.android.features.messages.impl.timeline.components.reactionsummary.ReactionSummaryState
|
||||
import io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet.ReadReceiptBottomSheetEvents
|
||||
import io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet.ReadReceiptBottomSheetState
|
||||
import io.element.android.features.messages.impl.timeline.components.retrysendmenu.RetrySendMenuState
|
||||
import io.element.android.features.messages.impl.timeline.components.retrysendmenu.aRetrySendMenuState
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent
|
||||
import io.element.android.features.messages.impl.typing.aTypingNotificationState
|
||||
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageComposerState
|
||||
import io.element.android.features.messages.impl.voicemessages.composer.aVoiceMessageComposerState
|
||||
import io.element.android.features.messages.impl.voicemessages.composer.aVoiceMessagePreviewState
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
|
|
@ -42,87 +52,120 @@ open class MessagesStateProvider : PreviewParameterProvider<MessagesState> {
|
|||
override val values: Sequence<MessagesState>
|
||||
get() = sequenceOf(
|
||||
aMessagesState(),
|
||||
aMessagesState().copy(hasNetworkConnection = false),
|
||||
aMessagesState().copy(composerState = aMessageComposerState().copy(showAttachmentSourcePicker = true)),
|
||||
aMessagesState().copy(userHasPermissionToSendMessage = false),
|
||||
aMessagesState().copy(showReinvitePrompt = true),
|
||||
aMessagesState().copy(
|
||||
aMessagesState(hasNetworkConnection = false),
|
||||
aMessagesState(composerState = aMessageComposerState(showAttachmentSourcePicker = true)),
|
||||
aMessagesState(userHasPermissionToSendMessage = false),
|
||||
aMessagesState(showReinvitePrompt = true),
|
||||
aMessagesState(
|
||||
roomName = AsyncData.Uninitialized,
|
||||
roomAvatar = AsyncData.Uninitialized,
|
||||
),
|
||||
aMessagesState().copy(composerState = aMessageComposerState().copy(showTextFormatting = true)),
|
||||
aMessagesState().copy(
|
||||
aMessagesState(composerState = aMessageComposerState(showTextFormatting = true)),
|
||||
aMessagesState(
|
||||
enableVoiceMessages = true,
|
||||
voiceMessageComposerState = aVoiceMessageComposerState(showPermissionRationaleDialog = true),
|
||||
),
|
||||
aMessagesState().copy(
|
||||
composerState = aMessageComposerState().copy(
|
||||
aMessagesState(
|
||||
composerState = aMessageComposerState(
|
||||
attachmentsState = AttachmentsState.Sending.Processing(persistentListOf())
|
||||
),
|
||||
),
|
||||
aMessagesState().copy(
|
||||
composerState = aMessageComposerState().copy(
|
||||
aMessagesState(
|
||||
composerState = aMessageComposerState(
|
||||
attachmentsState = AttachmentsState.Sending.Uploading(0.33f)
|
||||
),
|
||||
),
|
||||
aMessagesState().copy(
|
||||
aMessagesState(
|
||||
callState = RoomCallState.ONGOING,
|
||||
),
|
||||
aMessagesState().copy(
|
||||
aMessagesState(
|
||||
enableVoiceMessages = true,
|
||||
voiceMessageComposerState = aVoiceMessageComposerState(
|
||||
voiceMessageState = aVoiceMessagePreviewState(),
|
||||
showSendFailureDialog = true
|
||||
),
|
||||
),
|
||||
aMessagesState().copy(
|
||||
aMessagesState(
|
||||
callState = RoomCallState.DISABLED,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun aMessagesState() = MessagesState(
|
||||
roomId = RoomId("!id:domain"),
|
||||
roomName = AsyncData.Success("Room name"),
|
||||
roomAvatar = AsyncData.Success(AvatarData("!id:domain", "Room name", size = AvatarSize.TimelineRoom)),
|
||||
userHasPermissionToSendMessage = true,
|
||||
userHasPermissionToRedactOwn = false,
|
||||
userHasPermissionToRedactOther = false,
|
||||
userHasPermissionToSendReaction = true,
|
||||
composerState = aMessageComposerState().copy(
|
||||
fun aMessagesState(
|
||||
roomName: AsyncData<String> = AsyncData.Success("Room name"),
|
||||
roomAvatar: AsyncData<AvatarData> = AsyncData.Success(AvatarData("!id:domain", "Room name", size = AvatarSize.TimelineRoom)),
|
||||
userHasPermissionToSendMessage: Boolean = true,
|
||||
userHasPermissionToRedactOwn: Boolean = false,
|
||||
userHasPermissionToRedactOther: Boolean = false,
|
||||
userHasPermissionToSendReaction: Boolean = true,
|
||||
composerState: MessageComposerState = aMessageComposerState(
|
||||
richTextEditorState = RichTextEditorState("Hello", initialFocus = true),
|
||||
isFullScreen = false,
|
||||
mode = MessageComposerMode.Normal,
|
||||
),
|
||||
voiceMessageComposerState = aVoiceMessageComposerState(),
|
||||
timelineState = aTimelineState().copy(
|
||||
voiceMessageComposerState: VoiceMessageComposerState = aVoiceMessageComposerState(),
|
||||
timelineState: TimelineState = aTimelineState(
|
||||
timelineItems = aTimelineItemList(aTimelineItemTextContent()),
|
||||
),
|
||||
retrySendMenuState = RetrySendMenuState(
|
||||
selectedEvent = null,
|
||||
eventSink = {},
|
||||
),
|
||||
readReceiptBottomSheetState = ReadReceiptBottomSheetState(
|
||||
selectedEvent = null,
|
||||
eventSink = {},
|
||||
),
|
||||
actionListState = anActionListState(),
|
||||
customReactionState = CustomReactionState(
|
||||
target = CustomReactionState.Target.None,
|
||||
eventSink = {},
|
||||
selectedEmoji = persistentSetOf(),
|
||||
),
|
||||
reactionSummaryState = ReactionSummaryState(
|
||||
target = null,
|
||||
eventSink = {},
|
||||
),
|
||||
hasNetworkConnection = true,
|
||||
retrySendMenuState: RetrySendMenuState = aRetrySendMenuState(),
|
||||
readReceiptBottomSheetState: ReadReceiptBottomSheetState = aReadReceiptBottomSheetState(),
|
||||
actionListState: ActionListState = anActionListState(),
|
||||
customReactionState: CustomReactionState = aCustomReactionState(),
|
||||
reactionSummaryState: ReactionSummaryState = aReactionSummaryState(),
|
||||
hasNetworkConnection: Boolean = true,
|
||||
showReinvitePrompt: Boolean = false,
|
||||
enableVoiceMessages: Boolean = true,
|
||||
callState: RoomCallState = RoomCallState.ENABLED,
|
||||
eventSink: (MessagesEvents) -> Unit = {},
|
||||
) = MessagesState(
|
||||
roomId = RoomId("!id:domain"),
|
||||
roomName = roomName,
|
||||
roomAvatar = roomAvatar,
|
||||
userHasPermissionToSendMessage = userHasPermissionToSendMessage,
|
||||
userHasPermissionToRedactOwn = userHasPermissionToRedactOwn,
|
||||
userHasPermissionToRedactOther = userHasPermissionToRedactOther,
|
||||
userHasPermissionToSendReaction = userHasPermissionToSendReaction,
|
||||
composerState = composerState,
|
||||
voiceMessageComposerState = voiceMessageComposerState,
|
||||
typingNotificationState = aTypingNotificationState(),
|
||||
timelineState = timelineState,
|
||||
retrySendMenuState = retrySendMenuState,
|
||||
readReceiptBottomSheetState = readReceiptBottomSheetState,
|
||||
actionListState = actionListState,
|
||||
customReactionState = customReactionState,
|
||||
reactionSummaryState = reactionSummaryState,
|
||||
hasNetworkConnection = hasNetworkConnection,
|
||||
snackbarMessage = null,
|
||||
inviteProgress = AsyncData.Uninitialized,
|
||||
showReinvitePrompt = false,
|
||||
showReinvitePrompt = showReinvitePrompt,
|
||||
enableTextFormatting = true,
|
||||
enableVoiceMessages = true,
|
||||
callState = RoomCallState.ENABLED,
|
||||
enableVoiceMessages = enableVoiceMessages,
|
||||
callState = callState,
|
||||
appName = "Element",
|
||||
eventSink = {}
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
||||
fun aReactionSummaryState(
|
||||
target: ReactionSummaryState.Summary? = null,
|
||||
eventSink: (ReactionSummaryEvents) -> Unit = {}
|
||||
) = ReactionSummaryState(
|
||||
target = target,
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
||||
fun aCustomReactionState(
|
||||
target: CustomReactionState.Target = CustomReactionState.Target.None,
|
||||
eventSink: (CustomReactionEvents) -> Unit = {},
|
||||
) = CustomReactionState(
|
||||
target = target,
|
||||
selectedEmoji = persistentSetOf(),
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
||||
fun aReadReceiptBottomSheetState(
|
||||
selectedEvent: TimelineItem.Event? = null,
|
||||
eventSink: (ReadReceiptBottomSheetEvents) -> Unit = {},
|
||||
) = ReadReceiptBottomSheetState(
|
||||
selectedEvent = selectedEvent,
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ import androidx.compose.material3.ButtonDefaults
|
|||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
|
|
@ -102,7 +101,6 @@ import io.element.android.libraries.designsystem.theme.components.Scaffold
|
|||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||
import io.element.android.libraries.designsystem.utils.KeepScreenOn
|
||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
|
||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost
|
||||
import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState
|
||||
|
|
@ -126,9 +124,8 @@ fun MessagesView(
|
|||
onCreatePollClicked: () -> Unit,
|
||||
onJoinCallClicked: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
forceJumpToBottomVisibility: Boolean = false
|
||||
) {
|
||||
LogCompositions(tag = "MessagesScreen", msg = "Root")
|
||||
|
||||
OnLifecycleEvent { _, event ->
|
||||
state.voiceMessageComposerState.eventSink(VoiceMessageComposerEvents.LifecycleEvent(event))
|
||||
}
|
||||
|
|
@ -146,8 +143,6 @@ fun MessagesView(
|
|||
// This is needed because the composer is inside an AndroidView that can't be affected by the FocusManager in Compose
|
||||
val localView = LocalView.current
|
||||
|
||||
LogCompositions(tag = "MessagesScreen", msg = "Content")
|
||||
|
||||
fun onMessageClicked(event: TimelineItem.Event) {
|
||||
Timber.v("OnMessageClicked= ${event.id}")
|
||||
val hideKeyboard = onEventClicked(event)
|
||||
|
|
@ -198,7 +193,12 @@ fun MessagesView(
|
|||
roomName = state.roomName.dataOrNull(),
|
||||
roomAvatar = state.roomAvatar.dataOrNull(),
|
||||
callState = state.callState,
|
||||
onBackPressed = onBackPressed,
|
||||
onBackPressed = {
|
||||
// Since the textfield is now based on an Android view, this is no longer done automatically.
|
||||
// We need to hide the keyboard when navigating out of this screen.
|
||||
localView.hideKeyboard()
|
||||
onBackPressed()
|
||||
},
|
||||
onRoomDetailsClicked = onRoomDetailsClicked,
|
||||
onJoinCallClicked = onJoinCallClicked,
|
||||
)
|
||||
|
|
@ -229,6 +229,7 @@ fun MessagesView(
|
|||
onSwipeToReply = { targetEvent ->
|
||||
state.eventSink(MessagesEvents.HandleAction(TimelineItemAction.Reply, targetEvent))
|
||||
},
|
||||
forceJumpToBottomVisibility = forceJumpToBottomVisibility,
|
||||
)
|
||||
},
|
||||
snackbarHost = {
|
||||
|
|
@ -253,7 +254,6 @@ fun MessagesView(
|
|||
state = state.customReactionState,
|
||||
onEmojiSelected = { eventId, emoji ->
|
||||
state.eventSink(MessagesEvents.ToggleReaction(emoji.unicode, eventId))
|
||||
state.customReactionState.eventSink(CustomReactionEvents.DismissCustomReactionSheet)
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -264,14 +264,6 @@ fun MessagesView(
|
|||
onUserDataClicked = onUserDataClicked,
|
||||
)
|
||||
ReinviteDialog(state = state)
|
||||
|
||||
// Since the textfield is now based on an Android view, this is no longer done automatically.
|
||||
// We need to hide the keyboard automatically when navigating out of this screen.
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
localView.hideKeyboard()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
@ -329,6 +321,7 @@ private fun MessagesViewContent(
|
|||
onTimestampClicked: (TimelineItem.Event) -> Unit,
|
||||
onSendLocationClicked: () -> Unit,
|
||||
onCreatePollClicked: () -> Unit,
|
||||
forceJumpToBottomVisibility: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
onSwipeToReply: (TimelineItem.Event) -> Unit,
|
||||
) {
|
||||
|
|
@ -389,6 +382,7 @@ private fun MessagesViewContent(
|
|||
modifier = Modifier.padding(paddingValues),
|
||||
state = state.timelineState,
|
||||
roomName = state.roomName.dataOrNull(),
|
||||
typingNotificationState = state.typingNotificationState,
|
||||
onMessageClicked = onMessageClicked,
|
||||
onMessageLongClicked = onMessageLongClicked,
|
||||
onUserDataClicked = onUserDataClicked,
|
||||
|
|
@ -398,6 +392,7 @@ private fun MessagesViewContent(
|
|||
onMoreReactionsClicked = onMoreReactionsClicked,
|
||||
onReadReceiptClick = onReadReceiptClick,
|
||||
onSwipeToReply = onSwipeToReply,
|
||||
forceJumpToBottomVisibility = forceJumpToBottomVisibility,
|
||||
)
|
||||
},
|
||||
sheetContent = { subcomposing: Boolean ->
|
||||
|
|
@ -417,10 +412,9 @@ private fun MessagesViewContent(
|
|||
private fun MessagesViewComposerBottomSheetContents(
|
||||
subcomposing: Boolean,
|
||||
state: MessagesState,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (state.userHasPermissionToSendMessage) {
|
||||
Column(modifier = modifier.fillMaxWidth()) {
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
MentionSuggestionsPickerView(
|
||||
modifier = Modifier
|
||||
.heightIn(max = 230.dp)
|
||||
|
|
@ -448,7 +442,7 @@ private fun MessagesViewComposerBottomSheetContents(
|
|||
)
|
||||
}
|
||||
} else {
|
||||
CantSendMessageBanner(modifier = modifier)
|
||||
CantSendMessageBanner()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -461,10 +455,8 @@ private fun MessagesViewTopBar(
|
|||
onRoomDetailsClicked: () -> Unit,
|
||||
onJoinCallClicked: () -> Unit,
|
||||
onBackPressed: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
TopAppBar(
|
||||
modifier = modifier,
|
||||
navigationIcon = {
|
||||
BackButton(onClick = onBackPressed)
|
||||
},
|
||||
|
|
@ -489,7 +481,7 @@ private fun MessagesViewTopBar(
|
|||
} else {
|
||||
IconButton(onClick = onJoinCallClicked, enabled = callState != RoomCallState.DISABLED) {
|
||||
Icon(
|
||||
imageVector = CompoundIcons.VideoCallSolid,
|
||||
imageVector = CompoundIcons.VideoCallSolid(),
|
||||
contentDescription = stringResource(CommonStrings.a11y_start_call),
|
||||
)
|
||||
}
|
||||
|
|
@ -502,7 +494,6 @@ private fun MessagesViewTopBar(
|
|||
|
||||
@Composable
|
||||
private fun JoinCallMenuItem(
|
||||
modifier: Modifier = Modifier,
|
||||
onJoinCallClicked: () -> Unit,
|
||||
) {
|
||||
Material3Button(
|
||||
|
|
@ -512,11 +503,11 @@ private fun JoinCallMenuItem(
|
|||
containerColor = ElementTheme.colors.iconAccentTertiary
|
||||
),
|
||||
contentPadding = PaddingValues(horizontal = 10.dp, vertical = 0.dp),
|
||||
modifier = modifier.heightIn(min = 36.dp),
|
||||
modifier = Modifier.heightIn(min = 36.dp),
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(20.dp),
|
||||
imageVector = CompoundIcons.VideoCallSolid,
|
||||
imageVector = CompoundIcons.VideoCallSolid(),
|
||||
contentDescription = null
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
|
|
@ -550,11 +541,9 @@ private fun RoomAvatarAndNameRow(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun CantSendMessageBanner(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
private fun CantSendMessageBanner() {
|
||||
Row(
|
||||
modifier = modifier
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(MaterialTheme.colorScheme.secondary)
|
||||
.padding(16.dp),
|
||||
|
|
@ -584,5 +573,6 @@ internal fun MessagesViewPreview(@PreviewParameter(MessagesStateProvider::class)
|
|||
onSendLocationClicked = {},
|
||||
onCreatePollClicked = {},
|
||||
onJoinCallClicked = {},
|
||||
forceJumpToBottomVisibility = true,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,9 +122,12 @@ open class ActionListStateProvider : PreviewParameterProvider<ActionListState> {
|
|||
}
|
||||
}
|
||||
|
||||
fun anActionListState() = ActionListState(
|
||||
target = ActionListState.Target.None,
|
||||
eventSink = {}
|
||||
fun anActionListState(
|
||||
target: ActionListState.Target = ActionListState.Target.None,
|
||||
eventSink: (ActionListEvents) -> Unit = {},
|
||||
) = ActionListState(
|
||||
target = target,
|
||||
eventSink = eventSink
|
||||
)
|
||||
|
||||
fun aTimelineItemActionList(): ImmutableList<TimelineItemAction> {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue