Merge branch 'release/25.05.4' into main

This commit is contained in:
Benoit Marty 2025-05-21 17:45:01 +02:00
commit 7103f2ac2b
260 changed files with 2798 additions and 2459 deletions

32
.github/renovate.json vendored
View file

@ -1,29 +1,29 @@
{ {
"$schema" : "https://docs.renovatebot.com/renovate-schema.json", "$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends" : [ "extends": [
"config:base" "config:recommended"
], ],
"labels" : [ "labels": [
"PR-Dependencies" "PR-Dependencies"
], ],
"ignoreDeps" : [ "ignoreDeps": [
"string:app_name", "string:app_name",
"gradle" "gradle"
], ],
"packageRules" : [ "packageRules": [
{ {
"matchPackagePatterns" : [ "groupName": "kotlin",
"^org.jetbrains.kotlin", "matchPackageNames": [
"^com.google.devtools.ksp", "/^org.jetbrains.kotlin/",
"^androidx.compose.compiler" "/^com.google.devtools.ksp/",
], "/^androidx.compose.compiler/"
"groupName" : "kotlin" ]
}, },
{ {
"matchPackagePatterns" : [ "versioning": "semver",
"^org.maplibre" "matchPackageNames": [
], "/^org.maplibre/"
"versioning" : "semver" ]
} }
] ]
} }

View file

@ -56,7 +56,7 @@ jobs:
maestro-cloud: maestro-cloud:
name: Maestro test suite name: Maestro test suite
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [build-apk] needs: [ build-apk ]
# Allow one per PR. # Allow one per PR.
concurrency: concurrency:
group: ${{ format('maestro-{0}', github.ref) }} group: ${{ format('maestro-{0}', github.ref) }}
@ -80,6 +80,7 @@ jobs:
- name: Install maestro - name: Install maestro
run: curl -fsSL "https://get.maestro.mobile.dev" | bash run: curl -fsSL "https://get.maestro.mobile.dev" | bash
- name: Run Maestro tests in emulator - name: Run Maestro tests in emulator
id: maestro_test
uses: reactivecircus/android-emulator-runner@v2 uses: reactivecircus/android-emulator-runner@v2
continue-on-error: true continue-on-error: true
env: env:
@ -109,3 +110,8 @@ jobs:
retention-days: 5 retention-days: 5
overwrite: true overwrite: true
if-no-files-found: error if-no-files-found: error
- name: Fail the workflow in case of error in test
if: steps.maestro_test.outcome != 'success'
run: |
echo "Maestro tests failed. Please check the logs."
exit 1

28
.github/workflows/post-release.yml vendored Normal file
View file

@ -0,0 +1,28 @@
name: Post-release
on:
push:
tags:
- 'v*'
jobs:
post-release:
runs-on: ubuntu-latest
# Skip in forks
if: github.repository == 'element-hq/element-x-android'
steps:
- name: Trigger pipeline
uses: actions/github-script@v7
with:
github-token: ${{ secrets.ENTERPRISE_ACTIONS_TOKEN }}
script: |
const tag = context.ref.replace('refs/tags/', '');
const inputs = { git_tag: tag };
await github.rest.actions.createWorkflowDispatch({
owner: 'element-hq',
repo: 'element-enterprise',
workflow_id: 'pipeline-android.yml',
ref: 'main',
inputs: inputs
});

View file

@ -82,7 +82,7 @@ jobs:
# https://github.com/codecov/codecov-action # https://github.com/codecov/codecov-action
- name: ☂️ Upload coverage reports to codecov - name: ☂️ Upload coverage reports to codecov
uses: codecov/codecov-action@ad3126e916f78f00edff4ed0317cf185271ccc2d # v5.4.2 uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
with: with:
fail_ci_if_error: true fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}

2
.idea/kotlinc.xml generated
View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="KotlinJpsPluginSettings"> <component name="KotlinJpsPluginSettings">
<option name="version" value="2.1.20" /> <option name="version" value="2.1.21" />
</component> </component>
</project> </project>

View file

@ -7,22 +7,24 @@ appId: ${MAESTRO_APP_ID}
- runFlow: ../assertions/assertLoginDisplayed.yaml - runFlow: ../assertions/assertLoginDisplayed.yaml
- tapOn: - tapOn:
id: "login-continue" id: "login-continue"
## MAS page
## Conditional workflow to pass the Chrome first launch welcome page.
- runFlow:
when:
visible: 'Use without an account'
commands:
- tapOn: "Use without an account"
## Working when running Maestro locally, but not on the CI yet.
- tapOn: - tapOn:
id: "login-email_username" id: "form-1"
- inputText: ${MAESTRO_USERNAME} - inputText: ${MAESTRO_USERNAME}
- pressKey: Enter - pressKey: Enter
- tapOn: - tapOn:
id: "login-password" id: "form-3"
- inputText: "wrong-password"
- pressKey: Enter
- tapOn: "Continue"
- tapOn: "OK"
- tapOn:
id: "login-password"
- eraseText: 20
- inputText: ${MAESTRO_PASSWORD} - inputText: ${MAESTRO_PASSWORD}
- pressKey: Enter - pressKey: Enter
- tapOn: "Continue" - tapOn: "Continue"
## Back to native world
- runFlow: ../assertions/assertSessionVerificationDisplayed.yaml - runFlow: ../assertions/assertSessionVerificationDisplayed.yaml
- runFlow: ./verifySession.yaml - runFlow: ./verifySession.yaml
- runFlow: ../assertions/assertAnalyticsDisplayed.yaml - runFlow: ../assertions/assertAnalyticsDisplayed.yaml

View file

@ -8,6 +8,6 @@ appId: ${MAESTRO_APP_ID}
- hideKeyboard - hideKeyboard
- tapOn: "Continue" - tapOn: "Continue"
- extendedWaitUntil: - extendedWaitUntil:
visible: "Device verified" visible: "Verification complete"
timeout: 30000 timeout: 30000
- tapOn: "Continue" - tapOn: "Continue"

View file

@ -7,8 +7,9 @@ appId: ${MAESTRO_APP_ID}
- tapOn: - tapOn:
text: ${MAESTRO_INVITEE1_MXID} text: ${MAESTRO_INVITEE1_MXID}
index: 1 index: 1
- tapOn: "Send invite"
- takeScreenshot: build/maestro/330-createAndDeleteDM - takeScreenshot: build/maestro/330-createAndDeleteDM
- tapOn: "maestroelement2" - tapOn: "maestroelement2"
- scroll - scroll
- tapOn: "Leave conversation" - tapOn: "Leave room"
- tapOn: "Leave" - tapOn: "Leave"

View file

@ -0,0 +1,13 @@
appId: ${MAESTRO_APP_ID}
---
- tapOn: "Start a call"
- takeScreenshot: build/maestro/700-Call
- extendedWaitUntil:
visible: "maestroelement"
timeout: 10000
- takeScreenshot: build/maestro/710-Call
# Hangup
- tapOn: "End call"
- extendedWaitUntil:
visible: "MyRoom"
timeout: 10000

View file

@ -6,5 +6,6 @@ appId: ${MAESTRO_APP_ID}
- runFlow: messages/text.yaml - runFlow: messages/text.yaml
- runFlow: messages/location.yaml - runFlow: messages/location.yaml
- runFlow: messages/poll.yaml - runFlow: messages/poll.yaml
- runFlow: call/call.yaml
- back - back
- runFlow: ../../assertions/assertHomeDisplayed.yaml - runFlow: ../../assertions/assertHomeDisplayed.yaml

View file

@ -1,3 +1,27 @@
Changes in Element X v25.05.3
=============================
Version 25.05.2 was skipped.
## What's Changed
### 🐛 Bugfixes
* Disable Continue button when the login field is cleared. by @bmarty in https://github.com/element-hq/element-x-android/pull/4699
* Revert "fix(deps): update dependency io.element.android:element-call-embedded to v0.10.0", which caused an issue with to-device events in the latest version by @jmartinesp in https://github.com/element-hq/element-x-android/pull/4706
### 🗣 Translations
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/4703
### 🧱 Build
* Update Gradle Wrapper from 8.13 to 8.14 by @ElementBot in https://github.com/element-hq/element-x-android/pull/4645
### Dependency upgrades
* fix(deps): update datastore to v1.1.6 by @renovate in https://github.com/element-hq/element-x-android/pull/4630
* fix(deps): update lifecycle to v2.9.0 by @renovate in https://github.com/element-hq/element-x-android/pull/4693
* fix(deps): update dependency androidx.sqlite:sqlite-ktx to v2.5.1 by @renovate in https://github.com/element-hq/element-x-android/pull/4692
### Others
* Update "Learn more" link by @bmarty in https://github.com/element-hq/element-x-android/pull/4686
* Keep call notification ringing while a call is present in the room by @jmartinesp in https://github.com/element-hq/element-x-android/pull/4634
**Full Changelog**: https://github.com/element-hq/element-x-android/compare/v25.05.1...v25.05.3
Changes in Element X v25.05.1 Changes in Element X v25.05.1
============================= =============================

View file

@ -87,7 +87,7 @@ Just clone the project and open it in Android Studio. Make sure to select the
`app` configuration when building (as we also have sample apps in the project). `app` configuration when building (as we also have sample apps in the project).
To build against a local copy of the Rust SDK, see the [Developer To build against a local copy of the Rust SDK, see the [Developer
onboarding](docs/_developer_onboarding.md#build-the-sdk-locally) instructions. onboarding](docs/_developer_onboarding.md#building-the-sdk-locally) instructions.
## Support ## Support

View file

@ -10,7 +10,4 @@ package io.element.android.appconfig
object MatrixConfiguration { object MatrixConfiguration {
const val MATRIX_TO_PERMALINK_BASE_URL: String = "https://matrix.to/#/" const val MATRIX_TO_PERMALINK_BASE_URL: String = "https://matrix.to/#/"
val clientPermalinkBaseUrl: String? = null val clientPermalinkBaseUrl: String? = null
// TODO remove this when report is fixed
const val CAN_REPORT_ROOM = false
} }

View file

@ -20,13 +20,10 @@ import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.Plugin
import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.core.plugin.plugins
import com.bumble.appyx.navmodel.backstack.BackStack import com.bumble.appyx.navmodel.backstack.BackStack
import com.bumble.appyx.navmodel.backstack.operation.push
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.login.api.LoginEntryPoint import io.element.android.features.login.api.LoginEntryPoint
import io.element.android.features.login.api.LoginFlowType
import io.element.android.features.onboarding.api.OnBoardingEntryPoint
import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.designsystem.utils.ForceOrientationInMobileDevices import io.element.android.libraries.designsystem.utils.ForceOrientationInMobileDevices
@ -39,12 +36,11 @@ import kotlinx.parcelize.Parcelize
class NotLoggedInFlowNode @AssistedInject constructor( class NotLoggedInFlowNode @AssistedInject constructor(
@Assisted buildContext: BuildContext, @Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>, @Assisted plugins: List<Plugin>,
private val onBoardingEntryPoint: OnBoardingEntryPoint,
private val loginEntryPoint: LoginEntryPoint, private val loginEntryPoint: LoginEntryPoint,
private val notLoggedInImageLoaderFactory: NotLoggedInImageLoaderFactory, private val notLoggedInImageLoaderFactory: NotLoggedInImageLoaderFactory,
) : BaseFlowNode<NotLoggedInFlowNode.NavTarget>( ) : BaseFlowNode<NotLoggedInFlowNode.NavTarget>(
backstack = BackStack( backstack = BackStack(
initialElement = NavTarget.OnBoarding, initialElement = NavTarget.Root,
savedStateMap = buildContext.savedStateMap savedStateMap = buildContext.savedStateMap
), ),
buildContext = buildContext, buildContext = buildContext,
@ -65,42 +61,22 @@ class NotLoggedInFlowNode @AssistedInject constructor(
sealed interface NavTarget : Parcelable { sealed interface NavTarget : Parcelable {
@Parcelize @Parcelize
data object OnBoarding : NavTarget data object Root : NavTarget
@Parcelize
data class LoginFlow(val type: LoginFlowType) : NavTarget
} }
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
return when (navTarget) { return when (navTarget) {
NavTarget.OnBoarding -> { NavTarget.Root -> {
val callback = object : OnBoardingEntryPoint.Callback { val callback = object : LoginEntryPoint.Callback {
override fun onSignUp() {
backstack.push(NavTarget.LoginFlow(type = LoginFlowType.SIGN_UP))
}
override fun onSignIn() {
backstack.push(NavTarget.LoginFlow(type = LoginFlowType.SIGN_IN_MANUAL))
}
override fun onSignInWithQrCode() {
backstack.push(NavTarget.LoginFlow(type = LoginFlowType.SIGN_IN_QR_CODE))
}
override fun onReportProblem() { override fun onReportProblem() {
plugins<Callback>().forEach { it.onOpenBugReport() } plugins<Callback>().forEach { it.onOpenBugReport() }
} }
} }
onBoardingEntryPoint loginEntryPoint
.nodeBuilder(this, buildContext) .nodeBuilder(this, buildContext)
.callback(callback) .callback(callback)
.build() .build()
} }
is NavTarget.LoginFlow -> {
loginEntryPoint.nodeBuilder(this, buildContext)
.params(LoginEntryPoint.Params(flowType = navTarget.type))
.build()
}
} }
} }

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="banner_migrate_to_native_sliding_sync_action">"Abmelden und aktualisieren"</string> <string name="banner_migrate_to_native_sliding_sync_action">"Abmelden und aktualisieren"</string>
<string name="banner_migrate_to_native_sliding_sync_app_force_logout_title">"%1$sunterstützt das alte Protokoll nicht mehr. Bitte melden Sie sich ab und wieder an, um die App weiter nutzen zu können."</string> <string name="banner_migrate_to_native_sliding_sync_app_force_logout_title">"%1$s unterstützt das alte Protokoll nicht mehr. Bitte melden Sie sich ab und wieder an, um die App weiter nutzen zu können."</string>
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Dein Homeserver unterstützt das alte Protokoll nicht mehr. Bitte logge dich aus und melde dich wieder an, um die App weiter zu nutzen."</string> <string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Dein Homeserver unterstützt das alte Protokoll nicht mehr. Bitte logge dich aus und melde dich wieder an, um die App weiter zu nutzen."</string>
</resources> </resources>

@ -1 +1 @@
Subproject commit c754703e720bcb20f5dfa1ea0dcd32976825f71c Subproject commit d3dffc97bf8b39386ace2db7d857bbff05c73c18

View file

@ -0,0 +1,2 @@
Main changes in this version: bug fixes and improvements.
Full changelog: https://github.com/element-hq/element-x-android/releases

View file

@ -67,6 +67,7 @@ dependencies {
implementation(projects.features.enterprise.api) implementation(projects.features.enterprise.api)
implementation(projects.libraries.architecture) implementation(projects.libraries.architecture)
implementation(projects.libraries.androidutils) implementation(projects.libraries.androidutils)
implementation(projects.libraries.audio.api)
implementation(projects.libraries.core) implementation(projects.libraries.core)
implementation(projects.libraries.designsystem) implementation(projects.libraries.designsystem)
implementation(projects.libraries.featureflag.api) implementation(projects.libraries.featureflag.api)

View file

@ -10,9 +10,6 @@ package io.element.android.features.call.impl.ui
import android.Manifest import android.Manifest
import android.app.PictureInPictureParams import android.app.PictureInPictureParams
import android.content.Intent import android.content.Intent
import android.media.AudioAttributes
import android.media.AudioFocusRequest
import android.media.AudioManager
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Rational import android.util.Rational
@ -46,6 +43,8 @@ import io.element.android.features.call.impl.utils.CallIntentDataParser
import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.bindings import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.audio.api.AudioFocus
import io.element.android.libraries.audio.api.AudioFocusRequester
import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.designsystem.theme.ElementThemeApp import io.element.android.libraries.designsystem.theme.ElementThemeApp
@ -65,16 +64,12 @@ class ElementCallActivity :
@Inject lateinit var enterpriseService: EnterpriseService @Inject lateinit var enterpriseService: EnterpriseService
@Inject lateinit var pictureInPicturePresenter: PictureInPicturePresenter @Inject lateinit var pictureInPicturePresenter: PictureInPicturePresenter
@Inject lateinit var buildMeta: BuildMeta @Inject lateinit var buildMeta: BuildMeta
@Inject lateinit var audioFocus: AudioFocus
private lateinit var presenter: Presenter<CallScreenState> private lateinit var presenter: Presenter<CallScreenState>
private lateinit var audioManager: AudioManager
private var requestPermissionCallback: RequestPermissionCallback? = null private var requestPermissionCallback: RequestPermissionCallback? = null
private var audiofocusRequest: AudioFocusRequest? = null
private var audioFocusChangeListener: AudioManager.OnAudioFocusChangeListener? = null
private val requestPermissionsLauncher = registerPermissionResultLauncher() private val requestPermissionsLauncher = registerPermissionResultLauncher()
private val webViewTarget = mutableStateOf<CallType?>(null) private val webViewTarget = mutableStateOf<CallType?>(null)
@ -102,8 +97,6 @@ class ElementCallActivity :
pictureInPicturePresenter.setPipView(this) pictureInPicturePresenter.setPipView(this)
audioManager = getSystemService(AUDIO_SERVICE) as AudioManager
setContent { setContent {
val pipState = pictureInPicturePresenter.present() val pipState = pictureInPicturePresenter.present()
ListenToAndroidEvents(pipState) ListenToAndroidEvents(pipState)
@ -133,7 +126,13 @@ class ElementCallActivity :
} }
private fun setCallIsActive() { private fun setCallIsActive() {
requestAudioFocus() audioFocus.requestAudioFocus(
requester = AudioFocusRequester.ElementCall,
onFocusLost = {
// If the audio focus is lost, we do not stop the call.
Timber.tag(loggerTag.value).w("Audio focus lost")
}
)
CallForegroundService.start(this) CallForegroundService.start(this)
} }
@ -175,7 +174,7 @@ class ElementCallActivity :
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
releaseAudioFocus() audioFocus.releaseAudioFocus()
CallForegroundService.stop(this) CallForegroundService.stop(this)
pictureInPicturePresenter.setPipView(null) pictureInPicturePresenter.setPipView(null)
} }
@ -241,37 +240,6 @@ class ElementCallActivity :
} }
} }
@Suppress("DEPRECATION")
private fun requestAudioFocus() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val audioAttributes = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.build()
val request = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
.setAudioAttributes(audioAttributes)
.build()
audioManager.requestAudioFocus(request)
audiofocusRequest = request
} else {
val listener = AudioManager.OnAudioFocusChangeListener { }
audioManager.requestAudioFocus(
listener,
AudioManager.STREAM_VOICE_CALL,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE,
)
audioFocusChangeListener = listener
}
}
@Suppress("DEPRECATION")
private fun releaseAudioFocus() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
audiofocusRequest?.let { audioManager.abandonAudioFocusRequest(it) }
} else {
audioFocusChangeListener?.let { audioManager.abandonAudioFocus(it) }
}
}
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
override fun setPipParams() { override fun setPipParams() {
setPictureInPictureParams(getPictureInPictureParams()) setPictureInPictureParams(getPictureInPictureParams())

View file

@ -13,7 +13,7 @@ import io.element.android.libraries.matrix.api.core.SessionId
interface EnterpriseService { interface EnterpriseService {
val isEnterpriseBuild: Boolean val isEnterpriseBuild: Boolean
suspend fun isEnterpriseUser(sessionId: SessionId): Boolean suspend fun isEnterpriseUser(sessionId: SessionId): Boolean
fun defaultHomeserver(): String? fun defaultHomeserverList(): List<String>
suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String): Boolean suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String): Boolean
fun semanticColorsLight(): SemanticColors fun semanticColorsLight(): SemanticColors

View file

@ -22,7 +22,7 @@ class DefaultEnterpriseService @Inject constructor() : EnterpriseService {
override suspend fun isEnterpriseUser(sessionId: SessionId) = false override suspend fun isEnterpriseUser(sessionId: SessionId) = false
override fun defaultHomeserver() = null override fun defaultHomeserverList(): List<String> = emptyList()
override suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String) = true override suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String) = true
override fun semanticColorsLight(): SemanticColors = compoundColorsLight override fun semanticColorsLight(): SemanticColors = compoundColorsLight

View file

@ -21,9 +21,9 @@ class DefaultEnterpriseServiceTest {
} }
@Test @Test
fun `defaultHomeserver should return null`() { fun `defaultHomeserverList should return empty list`() {
val defaultEnterpriseService = DefaultEnterpriseService() val defaultEnterpriseService = DefaultEnterpriseService()
assertThat<String?>(defaultEnterpriseService.defaultHomeserver()).isNull() assertThat(defaultEnterpriseService.defaultHomeserverList()).isEmpty()
} }
@Test @Test

View file

@ -16,7 +16,7 @@ import io.element.android.tests.testutils.simulateLongTask
class FakeEnterpriseService( class FakeEnterpriseService(
override val isEnterpriseBuild: Boolean = false, override val isEnterpriseBuild: Boolean = false,
private val isEnterpriseUserResult: (SessionId) -> Boolean = { lambdaError() }, private val isEnterpriseUserResult: (SessionId) -> Boolean = { lambdaError() },
private val defaultHomeserverResult: () -> String? = { A_FAKE_HOMESERVER }, private val defaultHomeserverListResult: () -> List<String> = { emptyList() },
private val isAllowedToConnectToHomeserverResult: (String) -> Boolean = { lambdaError() }, private val isAllowedToConnectToHomeserverResult: (String) -> Boolean = { lambdaError() },
private val semanticColorsLightResult: () -> SemanticColors = { lambdaError() }, private val semanticColorsLightResult: () -> SemanticColors = { lambdaError() },
private val semanticColorsDarkResult: () -> SemanticColors = { lambdaError() }, private val semanticColorsDarkResult: () -> SemanticColors = { lambdaError() },
@ -27,8 +27,8 @@ class FakeEnterpriseService(
isEnterpriseUserResult(sessionId) isEnterpriseUserResult(sessionId)
} }
override fun defaultHomeserver(): String? { override fun defaultHomeserverList(): List<String> {
return defaultHomeserverResult() return defaultHomeserverListResult()
} }
override suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String): Boolean = simulateLongTask { override suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String): Boolean = simulateLongTask {

View file

@ -23,7 +23,6 @@ import androidx.compose.runtime.setValue
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import im.vector.app.features.analytics.plan.JoinedRoom import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.appconfig.MatrixConfiguration
import io.element.android.features.invite.api.SeenInvitesStore import io.element.android.features.invite.api.SeenInvitesStore
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
@ -100,6 +99,8 @@ class JoinRoomPresenter @AssistedInject constructor(
val hideInviteAvatars by remember { val hideInviteAvatars by remember {
appPreferencesStore.getHideInviteAvatarsFlow() appPreferencesStore.getHideInviteAvatarsFlow()
}.collectAsState(initial = false) }.collectAsState(initial = false)
val canReportRoom by produceState(false) { value = matrixClient.canReportRoom() }
val contentState by produceState<ContentState>( val contentState by produceState<ContentState>(
initialValue = ContentState.Loading, initialValue = ContentState.Loading,
key1 = roomInfo, key1 = roomInfo,
@ -212,7 +213,7 @@ class JoinRoomPresenter @AssistedInject constructor(
applicationName = buildMeta.applicationName, applicationName = buildMeta.applicationName,
knockMessage = knockMessage, knockMessage = knockMessage,
hideInviteAvatars = hideInviteAvatars, hideInviteAvatars = hideInviteAvatars,
canReportRoom = MatrixConfiguration.CAN_REPORT_ROOM, canReportRoom = canReportRoom,
eventSink = ::handleEvents eventSink = ::handleEvents
) )
} }

View file

@ -25,14 +25,6 @@
<string name="screen_knock_requests_list_empty_state_title">"Dim cais i ymuno yn disgwyl"</string> <string name="screen_knock_requests_list_empty_state_title">"Dim cais i ymuno yn disgwyl"</string>
<string name="screen_knock_requests_list_initial_loading_title">"Yn llwytho ceisiadau i ymuno…"</string> <string name="screen_knock_requests_list_initial_loading_title">"Yn llwytho ceisiadau i ymuno…"</string>
<string name="screen_knock_requests_list_title">"Ceisiadau i ymuno"</string> <string name="screen_knock_requests_list_title">"Ceisiadau i ymuno"</string>
<plurals name="screen_room_multiple_knock_requests_title">
<item quantity="zero">"Dyw %1$s na +%2$d arall eisiau ymuno â\'r ystafell hon"</item>
<item quantity="one">"Mae %1$s +%2$d arall eisiau ymuno â\'r ystafell hon"</item>
<item quantity="two">"Mae %1$s +%2$d arall eisiau ymuno â\'r ystafell hon"</item>
<item quantity="few">"Mae %1$s +%2$d arall eisiau ymuno â\'r ystafell hon"</item>
<item quantity="many">"Mae %1$s +%2$d arall eisiau ymuno â\'r ystafell hon"</item>
<item quantity="other">"Mae %1$s +%2$d arall eisiau ymuno â\'r ystafell hon"</item>
</plurals>
<string name="screen_room_multiple_knock_requests_view_all_button_title">"Gweld y cyfan"</string> <string name="screen_room_multiple_knock_requests_view_all_button_title">"Gweld y cyfan"</string>
<string name="screen_room_single_knock_request_accept_button_title">"Derbyn"</string> <string name="screen_room_single_knock_request_accept_button_title">"Derbyn"</string>
<string name="screen_room_single_knock_request_title">"Mae %1$s eisiau ymuno â\'r ystafell hon"</string> <string name="screen_room_single_knock_request_title">"Mae %1$s eisiau ymuno â\'r ystafell hon"</string>

View file

@ -101,7 +101,7 @@ class SendLocationPresenter @Inject constructor(
when (mode) { when (mode) {
SendLocationState.Mode.PinLocation -> { SendLocationState.Mode.PinLocation -> {
val geoUri = event.cameraPosition.toGeoUri() val geoUri = event.cameraPosition.toGeoUri()
room.sendLocation( room.liveTimeline.sendLocation(
body = generateBody(geoUri), body = generateBody(geoUri),
geoUri = geoUri, geoUri = geoUri,
description = null, description = null,
@ -119,7 +119,7 @@ class SendLocationPresenter @Inject constructor(
} }
SendLocationState.Mode.SenderLocation -> { SendLocationState.Mode.SenderLocation -> {
val geoUri = event.toGeoUri() val geoUri = event.toGeoUri()
room.sendLocation( room.liveTimeline.sendLocation(
body = generateBody(geoUri), body = generateBody(geoUri),
geoUri = geoUri, geoUri = geoUri,
description = null, description = null,

View file

@ -26,6 +26,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTran
import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.core.aBuildMeta import io.element.android.libraries.matrix.test.core.aBuildMeta
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.textcomposer.model.MessageComposerMode import io.element.android.libraries.textcomposer.model.MessageComposerMode
import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.WarmUpRule
@ -266,7 +267,9 @@ class SendLocationPresenterTest {
Result.success(Unit) Result.success(Unit)
} }
val joinedRoom = FakeJoinedRoom( val joinedRoom = FakeJoinedRoom(
sendLocationResult = sendLocationResult, liveTimeline = FakeTimeline().apply {
sendLocationLambda = sendLocationResult
},
) )
val sendLocationPresenter = createSendLocationPresenter(joinedRoom) val sendLocationPresenter = createSendLocationPresenter(joinedRoom)
fakePermissionsPresenter.givenState( fakePermissionsPresenter.givenState(
@ -327,7 +330,9 @@ class SendLocationPresenterTest {
Result.success(Unit) Result.success(Unit)
} }
val joinedRoom = FakeJoinedRoom( val joinedRoom = FakeJoinedRoom(
sendLocationResult = sendLocationResult, liveTimeline = FakeTimeline().apply {
sendLocationLambda = sendLocationResult
},
) )
val sendLocationPresenter = createSendLocationPresenter(joinedRoom) val sendLocationPresenter = createSendLocationPresenter(joinedRoom)
fakePermissionsPresenter.givenState( fakePermissionsPresenter.givenState(
@ -388,7 +393,9 @@ class SendLocationPresenterTest {
Result.success(Unit) Result.success(Unit)
} }
val joinedRoom = FakeJoinedRoom( val joinedRoom = FakeJoinedRoom(
sendLocationResult = sendLocationResult, liveTimeline = FakeTimeline().apply {
sendLocationLambda = sendLocationResult
},
) )
val sendLocationPresenter = createSendLocationPresenter(joinedRoom) val sendLocationPresenter = createSendLocationPresenter(joinedRoom)
fakePermissionsPresenter.givenState( fakePermissionsPresenter.givenState(

View file

@ -24,22 +24,6 @@ Dewiswch rywbeth cofiadwy. Os byddwch chi\'n anghofio\'r PIN hwn, byddwch chi\'n
<string name="screen_app_lock_setup_pin_mismatch_dialog_title">"Nid yw\'r PINau\'n cyfateb"</string> <string name="screen_app_lock_setup_pin_mismatch_dialog_title">"Nid yw\'r PINau\'n cyfateb"</string>
<string name="screen_app_lock_signout_alert_message">"Bydd angen i chi ail-fewngofnodi a chreu PIN newydd i barhau"</string> <string name="screen_app_lock_signout_alert_message">"Bydd angen i chi ail-fewngofnodi a chreu PIN newydd i barhau"</string>
<string name="screen_app_lock_signout_alert_title">"Rydych chi\'n cael eich allgofnodi"</string> <string name="screen_app_lock_signout_alert_title">"Rydych chi\'n cael eich allgofnodi"</string>
<plurals name="screen_app_lock_subtitle">
<item quantity="zero">"Does gennych %1$d ceisiadau i ddatgloi"</item>
<item quantity="one">"Mae gennych %1$d cais i ddatgloi"</item>
<item quantity="two">"Mae gennych %1$d gais i ddatgloi"</item>
<item quantity="few">"Mae gennych %1$d chais i ddatgloi"</item>
<item quantity="many">"Mae gennych %1$d chais i ddatgloi"</item>
<item quantity="other">"Mae gennych %1$d cais i ddatgloi"</item>
</plurals>
<plurals name="screen_app_lock_subtitle_wrong_pin">
<item quantity="zero">"PIN anghywir. Does gennych %1$d cais arall"</item>
<item quantity="one">"PIN anghywir. Mae gennych %1$d cais arall"</item>
<item quantity="two">"PIN anghywir. Mae gennych %1$d gais arall"</item>
<item quantity="few">"PIN anghywir. Mae gennych %1$d chais arall"</item>
<item quantity="many">"PIN anghywir. Mae gennych %1$d chais arall"</item>
<item quantity="other">"PIN anghywir. Mae gennych %1$d cais arall"</item>
</plurals>
<string name="screen_app_lock_use_biometric_android">"Defnyddio biometreg"</string> <string name="screen_app_lock_use_biometric_android">"Defnyddio biometreg"</string>
<string name="screen_app_lock_use_pin_android">"Defnyddio PIN"</string> <string name="screen_app_lock_use_pin_android">"Defnyddio PIN"</string>
<string name="screen_signout_in_progress_dialog_content">"Yn allgofnodi…"</string> <string name="screen_signout_in_progress_dialog_content">"Yn allgofnodi…"</string>

View file

@ -7,28 +7,20 @@
package io.element.android.features.login.api package io.element.android.features.login.api
import android.os.Parcelable
import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import io.element.android.libraries.architecture.FeatureEntryPoint import io.element.android.libraries.architecture.FeatureEntryPoint
import kotlinx.parcelize.Parcelize
interface LoginEntryPoint : FeatureEntryPoint { interface LoginEntryPoint : FeatureEntryPoint {
data class Params( interface Callback : Plugin {
val flowType: LoginFlowType fun onReportProblem()
) }
fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder
interface NodeBuilder { interface NodeBuilder {
fun params(params: Params): NodeBuilder fun callback(callback: Callback): NodeBuilder
fun build(): Node fun build(): Node
} }
} }
@Parcelize
enum class LoginFlowType : Parcelable {
SIGN_IN_MANUAL,
SIGN_IN_QR_CODE,
SIGN_UP
}

View file

@ -29,9 +29,11 @@ setupAnvil(componentMergingStrategy = ComponentMergingStrategy.KSP)
dependencies { dependencies {
implementation(projects.appconfig) implementation(projects.appconfig)
implementation(projects.features.enterprise.api) implementation(projects.features.enterprise.api)
implementation(projects.features.rageshake.api)
implementation(projects.libraries.core) implementation(projects.libraries.core)
implementation(projects.libraries.androidutils) implementation(projects.libraries.androidutils)
implementation(projects.libraries.architecture) implementation(projects.libraries.architecture)
implementation(projects.libraries.featureflag.api)
implementation(projects.libraries.matrix.api) implementation(projects.libraries.matrix.api)
implementation(projects.libraries.matrix.api) implementation(projects.libraries.matrix.api)
implementation(projects.libraries.network) implementation(projects.libraries.network)
@ -57,6 +59,7 @@ dependencies {
testImplementation(libs.test.truth) testImplementation(libs.test.truth)
testImplementation(libs.test.turbine) testImplementation(libs.test.turbine)
testImplementation(projects.features.enterprise.test) testImplementation(projects.features.enterprise.test)
testImplementation(projects.libraries.featureflag.test)
testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.oidc.impl) testImplementation(projects.libraries.oidc.impl)
testImplementation(projects.libraries.permissions.test) testImplementation(projects.libraries.permissions.test)

View file

@ -22,8 +22,8 @@ class DefaultLoginEntryPoint @Inject constructor() : LoginEntryPoint {
val plugins = ArrayList<Plugin>() val plugins = ArrayList<Plugin>()
return object : LoginEntryPoint.NodeBuilder { return object : LoginEntryPoint.NodeBuilder {
override fun params(params: LoginEntryPoint.Params): LoginEntryPoint.NodeBuilder { override fun callback(callback: LoginEntryPoint.Callback): LoginEntryPoint.NodeBuilder {
plugins += LoginFlowNode.Inputs(flowType = params.flowType) plugins += callback
return this return this
} }

View file

@ -18,6 +18,7 @@ import com.bumble.appyx.core.lifecycle.subscribe
import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.Plugin
import com.bumble.appyx.core.plugin.plugins
import com.bumble.appyx.navmodel.backstack.BackStack import com.bumble.appyx.navmodel.backstack.BackStack
import com.bumble.appyx.navmodel.backstack.operation.push import com.bumble.appyx.navmodel.backstack.operation.push
import com.bumble.appyx.navmodel.backstack.operation.singleTop import com.bumble.appyx.navmodel.backstack.operation.singleTop
@ -25,8 +26,9 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode import io.element.android.anvilannotations.ContributesNode
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.features.login.api.LoginFlowType import io.element.android.features.login.api.LoginEntryPoint
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
import io.element.android.features.login.impl.onboarding.OnBoardingNode
import io.element.android.features.login.impl.qrcode.QrCodeLoginFlowNode import io.element.android.features.login.impl.qrcode.QrCodeLoginFlowNode
import io.element.android.features.login.impl.screens.changeaccountprovider.ChangeAccountProviderNode import io.element.android.features.login.impl.screens.changeaccountprovider.ChangeAccountProviderNode
import io.element.android.features.login.impl.screens.confirmaccountprovider.ConfirmAccountProviderNode import io.element.android.features.login.impl.screens.confirmaccountprovider.ConfirmAccountProviderNode
@ -35,9 +37,7 @@ import io.element.android.features.login.impl.screens.loginpassword.LoginPasswor
import io.element.android.features.login.impl.screens.searchaccountprovider.SearchAccountProviderNode import io.element.android.features.login.impl.screens.searchaccountprovider.SearchAccountProviderNode
import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.NodeInputs
import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
import io.element.android.libraries.matrix.api.auth.OidcDetails import io.element.android.libraries.matrix.api.auth.OidcDetails
import io.element.android.libraries.oidc.api.OidcAction import io.element.android.libraries.oidc.api.OidcAction
@ -57,7 +57,7 @@ class LoginFlowNode @AssistedInject constructor(
private val oidcEntryPoint: OidcEntryPoint, private val oidcEntryPoint: OidcEntryPoint,
) : BaseFlowNode<LoginFlowNode.NavTarget>( ) : BaseFlowNode<LoginFlowNode.NavTarget>(
backstack = BackStack( backstack = BackStack(
initialElement = NavTarget.Root, initialElement = NavTarget.OnBoarding,
savedStateMap = buildContext.savedStateMap, savedStateMap = buildContext.savedStateMap,
), ),
buildContext = buildContext, buildContext = buildContext,
@ -66,12 +66,6 @@ class LoginFlowNode @AssistedInject constructor(
private var activity: Activity? = null private var activity: Activity? = null
private var darkTheme: Boolean = false private var darkTheme: Boolean = false
data class Inputs(
val flowType: LoginFlowType,
) : NodeInputs
private val inputs: Inputs = inputs()
private var customChromeTabStarted = false private var customChromeTabStarted = false
override fun onBuilt() { override fun onBuilt() {
@ -96,10 +90,15 @@ class LoginFlowNode @AssistedInject constructor(
sealed interface NavTarget : Parcelable { sealed interface NavTarget : Parcelable {
@Parcelize @Parcelize
data object Root : NavTarget data object OnBoarding : NavTarget
@Parcelize @Parcelize
data object ConfirmAccountProvider : NavTarget data object QrCode : NavTarget
@Parcelize
data class ConfirmAccountProvider(
val isAccountCreation: Boolean,
) : NavTarget
@Parcelize @Parcelize
data object ChangeAccountProvider : NavTarget data object ChangeAccountProvider : NavTarget
@ -119,16 +118,36 @@ class LoginFlowNode @AssistedInject constructor(
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
return when (navTarget) { return when (navTarget) {
NavTarget.Root -> { NavTarget.OnBoarding -> {
if (inputs.flowType == LoginFlowType.SIGN_IN_QR_CODE) { val callback = object : OnBoardingNode.Callback {
createNode<QrCodeLoginFlowNode>(buildContext) override fun onSignUp() {
} else { backstack.push(
resolve(NavTarget.ConfirmAccountProvider, buildContext) NavTarget.ConfirmAccountProvider(isAccountCreation = true)
)
}
override fun onSignIn() {
backstack.push(
NavTarget.ConfirmAccountProvider(isAccountCreation = false)
)
}
override fun onSignInWithQrCode() {
backstack.push(NavTarget.QrCode)
}
override fun onReportProblem() {
plugins<LoginEntryPoint.Callback>().forEach { it.onReportProblem() }
}
} }
createNode<OnBoardingNode>(buildContext, listOf(callback))
} }
NavTarget.ConfirmAccountProvider -> { NavTarget.QrCode -> {
createNode<QrCodeLoginFlowNode>(buildContext)
}
is NavTarget.ConfirmAccountProvider -> {
val inputs = ConfirmAccountProviderNode.Inputs( val inputs = ConfirmAccountProviderNode.Inputs(
isAccountCreation = inputs.flowType == LoginFlowType.SIGN_UP, isAccountCreation = navTarget.isAccountCreation,
) )
val callback = object : ConfirmAccountProviderNode.Callback { val callback = object : ConfirmAccountProviderNode.Callback {
override fun onOidcDetails(oidcDetails: OidcDetails) { override fun onOidcDetails(oidcDetails: OidcDetails) {
@ -162,7 +181,10 @@ class LoginFlowNode @AssistedInject constructor(
val callback = object : ChangeAccountProviderNode.Callback { val callback = object : ChangeAccountProviderNode.Callback {
override fun onDone() { override fun onDone() {
// Go back to the Account Provider screen // Go back to the Account Provider screen
backstack.singleTop(NavTarget.ConfirmAccountProvider) val confirmAccountProvider = backstack.elements.value.firstOrNull {
it.key.navTarget is NavTarget.ConfirmAccountProvider
}?.key?.navTarget ?: NavTarget.ConfirmAccountProvider(isAccountCreation = false)
backstack.singleTop(confirmAccountProvider)
} }
override fun onOtherClick() { override fun onOtherClick() {
@ -176,7 +198,10 @@ class LoginFlowNode @AssistedInject constructor(
val callback = object : SearchAccountProviderNode.Callback { val callback = object : SearchAccountProviderNode.Callback {
override fun onDone() { override fun onDone() {
// Go back to the Account Provider screen // Go back to the Account Provider screen
backstack.singleTop(NavTarget.ConfirmAccountProvider) val confirmAccountProvider = backstack.elements.value.firstOrNull {
it.key.navTarget is NavTarget.ConfirmAccountProvider
}?.key?.navTarget ?: NavTarget.ConfirmAccountProvider(isAccountCreation = false)
backstack.singleTop(confirmAccountProvider)
} }
} }

View file

@ -20,14 +20,15 @@ import javax.inject.Inject
class AccountProviderDataSource @Inject constructor( class AccountProviderDataSource @Inject constructor(
enterpriseService: EnterpriseService, enterpriseService: EnterpriseService,
) { ) {
private val defaultAccountProvider = (enterpriseService.defaultHomeserver() ?: AuthenticationConfig.MATRIX_ORG_URL).let { url -> private val defaultAccountProvider = (enterpriseService.defaultHomeserverList().firstOrNull() ?: AuthenticationConfig.MATRIX_ORG_URL)
AccountProvider( .let { url ->
url = url, AccountProvider(
subtitle = null, url = url,
isPublic = url == AuthenticationConfig.MATRIX_ORG_URL, subtitle = null,
isMatrixOrg = url == AuthenticationConfig.MATRIX_ORG_URL, isPublic = url == AuthenticationConfig.MATRIX_ORG_URL,
) isMatrixOrg = url == AuthenticationConfig.MATRIX_ORG_URL,
} )
}
private val accountProvider: MutableStateFlow<AccountProvider> = MutableStateFlow( private val accountProvider: MutableStateFlow<AccountProvider> = MutableStateFlow(
defaultAccountProvider defaultAccountProvider

View file

@ -21,8 +21,10 @@ open class AccountProviderProvider : PreviewParameterProvider<AccountProvider> {
) )
} }
fun anAccountProvider() = AccountProvider( fun anAccountProvider(
url = AuthenticationConfig.MATRIX_ORG_URL, url: String = AuthenticationConfig.MATRIX_ORG_URL,
) = AccountProvider(
url = url,
subtitle = "Matrix.org is an open network for secure, decentralized communication.", subtitle = "Matrix.org is an open network for secure, decentralized communication.",
isPublic = true, isPublic = true,
isMatrixOrg = true, isMatrixOrg = true,

View file

@ -56,7 +56,10 @@ class ChangeServerPresenter @Inject constructor(
) = launch { ) = launch {
suspend { suspend {
if (enterpriseService.isAllowedToConnectToHomeserver(data.url).not()) { if (enterpriseService.isAllowedToConnectToHomeserver(data.url).not()) {
throw UnauthorizedAccountProviderException(data) throw UnauthorizedAccountProviderException(
unauthorisedAccountProviderTitle = data.title,
authorisedAccountProviderTitles = enterpriseService.defaultHomeserverList(),
)
} }
authenticationService.setHomeserver(data.url).map { authenticationService.setHomeserver(data.url).map {
authenticationService.getHomeserverDetails().value!! authenticationService.getHomeserverDetails().value!!

View file

@ -8,7 +8,6 @@
package io.element.android.features.login.impl.changeserver package io.element.android.features.login.impl.changeserver
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.login.impl.accountprovider.anAccountProvider
import io.element.android.features.login.impl.error.ChangeServerError import io.element.android.features.login.impl.error.ChangeServerError
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
@ -19,7 +18,14 @@ open class ChangeServerStateProvider : PreviewParameterProvider<ChangeServerStat
aChangeServerState(), aChangeServerState(),
aChangeServerState(changeServerAction = AsyncData.Failure(ChangeServerError.Error(CommonStrings.error_unknown))), aChangeServerState(changeServerAction = AsyncData.Failure(ChangeServerError.Error(CommonStrings.error_unknown))),
aChangeServerState(changeServerAction = AsyncData.Failure(ChangeServerError.SlidingSyncAlert)), aChangeServerState(changeServerAction = AsyncData.Failure(ChangeServerError.SlidingSyncAlert)),
aChangeServerState(changeServerAction = AsyncData.Failure(ChangeServerError.UnauthorizedAccountProvider(anAccountProvider()))), aChangeServerState(
changeServerAction = AsyncData.Failure(
ChangeServerError.UnauthorizedAccountProvider(
unauthorisedAccountProviderTitle = "example.com",
authorisedAccountProviderTitles = listOf("element.io", "element.org"),
)
)
),
) )
} }

View file

@ -62,7 +62,7 @@ fun ChangeServerView(
content = stringResource( content = stringResource(
id = R.string.screen_change_server_error_unauthorized_homeserver, id = R.string.screen_change_server_error_unauthorized_homeserver,
LocalBuildMeta.current.applicationName, LocalBuildMeta.current.applicationName,
error.accountProvider.title, error.unauthorisedAccountProviderTitle,
), ),
onSubmit = { onSubmit = {
eventSink.invoke(ChangeServerEvents.ClearError) eventSink.invoke(ChangeServerEvents.ClearError)

View file

@ -7,8 +7,7 @@
package io.element.android.features.login.impl.changeserver package io.element.android.features.login.impl.changeserver
import io.element.android.features.login.impl.accountprovider.AccountProvider
class UnauthorizedAccountProviderException( class UnauthorizedAccountProviderException(
val accountProvider: AccountProvider, val unauthorisedAccountProviderTitle: String,
val authorisedAccountProviderTitles: List<String>,
) : Exception() ) : Exception()

View file

@ -11,7 +11,6 @@ import androidx.annotation.StringRes
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import io.element.android.features.login.impl.R import io.element.android.features.login.impl.R
import io.element.android.features.login.impl.accountprovider.AccountProvider
import io.element.android.features.login.impl.changeserver.UnauthorizedAccountProviderException import io.element.android.features.login.impl.changeserver.UnauthorizedAccountProviderException
import io.element.android.libraries.matrix.api.auth.AuthenticationException import io.element.android.libraries.matrix.api.auth.AuthenticationException
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
@ -26,7 +25,8 @@ sealed class ChangeServerError : Throwable() {
} }
data class UnauthorizedAccountProvider( data class UnauthorizedAccountProvider(
val accountProvider: AccountProvider, val unauthorisedAccountProviderTitle: String,
val authorisedAccountProviderTitles: List<String>,
) : ChangeServerError() ) : ChangeServerError()
data object SlidingSyncAlert : ChangeServerError() data object SlidingSyncAlert : ChangeServerError()
@ -35,7 +35,10 @@ sealed class ChangeServerError : Throwable() {
fun from(error: Throwable): ChangeServerError = when (error) { fun from(error: Throwable): ChangeServerError = when (error) {
is AuthenticationException.SlidingSyncVersion -> SlidingSyncAlert is AuthenticationException.SlidingSyncVersion -> SlidingSyncAlert
is AuthenticationException.Oidc -> Error(messageStr = error.message) is AuthenticationException.Oidc -> Error(messageStr = error.message)
is UnauthorizedAccountProviderException -> UnauthorizedAccountProvider(error.accountProvider) is UnauthorizedAccountProviderException -> UnauthorizedAccountProvider(
unauthorisedAccountProviderTitle = error.unauthorisedAccountProviderTitle,
authorisedAccountProviderTitles = error.authorisedAccountProviderTitles,
)
else -> Error(messageId = R.string.screen_change_server_error_invalid_homeserver) else -> Error(messageId = R.string.screen_change_server_error_invalid_homeserver)
} }
} }

View file

@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
package io.element.android.features.onboarding.impl package io.element.android.features.login.impl.onboarding
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -16,7 +16,6 @@ import com.bumble.appyx.core.plugin.plugins
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.onboarding.api.OnBoardingEntryPoint
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
@ContributesNode(AppScope::class) @ContributesNode(AppScope::class)
@ -28,20 +27,27 @@ class OnBoardingNode @AssistedInject constructor(
buildContext = buildContext, buildContext = buildContext,
plugins = plugins plugins = plugins
) { ) {
interface Callback : Plugin {
fun onSignUp()
fun onSignIn()
fun onSignInWithQrCode()
fun onReportProblem()
}
private fun onSignIn() { private fun onSignIn() {
plugins<OnBoardingEntryPoint.Callback>().forEach { it.onSignIn() } plugins<Callback>().forEach { it.onSignIn() }
} }
private fun onSignUp() { private fun onSignUp() {
plugins<OnBoardingEntryPoint.Callback>().forEach { it.onSignUp() } plugins<Callback>().forEach { it.onSignUp() }
} }
private fun onSignInWithQrCode() { private fun onSignInWithQrCode() {
plugins<OnBoardingEntryPoint.Callback>().forEach { it.onSignInWithQrCode() } plugins<Callback>().forEach { it.onSignInWithQrCode() }
} }
private fun onReportProblem() { private fun onReportProblem() {
plugins<OnBoardingEntryPoint.Callback>().forEach { it.onReportProblem() } plugins<Callback>().forEach { it.onReportProblem() }
} }
@Composable @Composable

View file

@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
package io.element.android.features.onboarding.impl package io.element.android.features.login.impl.onboarding
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue

View file

@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
package io.element.android.features.onboarding.impl package io.element.android.features.login.impl.onboarding
data class OnBoardingState( data class OnBoardingState(
val productionApplicationName: String, val productionApplicationName: String,

View file

@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
package io.element.android.features.onboarding.impl package io.element.android.features.login.impl.onboarding
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider

View file

@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
package io.element.android.features.onboarding.impl package io.element.android.features.login.impl.onboarding
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
@ -26,6 +26,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.login.impl.R
import io.element.android.libraries.designsystem.atomic.atoms.ElementLogoAtom import io.element.android.libraries.designsystem.atomic.atoms.ElementLogoAtom
import io.element.android.libraries.designsystem.atomic.atoms.ElementLogoAtomSize import io.element.android.libraries.designsystem.atomic.atoms.ElementLogoAtomSize
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule

View file

@ -8,29 +8,39 @@
package io.element.android.features.login.impl.screens.changeaccountprovider package io.element.android.features.login.impl.screens.changeaccountprovider
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import io.element.android.appconfig.AuthenticationConfig import io.element.android.appconfig.AuthenticationConfig
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.features.login.impl.accountprovider.AccountProvider import io.element.android.features.login.impl.accountprovider.AccountProvider
import io.element.android.features.login.impl.changeserver.ChangeServerState import io.element.android.features.login.impl.changeserver.ChangeServerState
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.uri.ensureProtocol
import javax.inject.Inject import javax.inject.Inject
class ChangeAccountProviderPresenter @Inject constructor( class ChangeAccountProviderPresenter @Inject constructor(
private val changeServerPresenter: Presenter<ChangeServerState>, private val changeServerPresenter: Presenter<ChangeServerState>,
private val enterpriseService: EnterpriseService,
) : Presenter<ChangeAccountProviderState> { ) : Presenter<ChangeAccountProviderState> {
@Composable @Composable
override fun present(): ChangeAccountProviderState { override fun present(): ChangeAccountProviderState {
val staticAccountProviderList = remember {
enterpriseService.defaultHomeserverList()
.map { it.ensureProtocol() }
.ifEmpty { listOf(AuthenticationConfig.MATRIX_ORG_URL) }
.map { url ->
AccountProvider(
url = url,
subtitle = null,
isPublic = url == AuthenticationConfig.MATRIX_ORG_URL,
isMatrixOrg = url == AuthenticationConfig.MATRIX_ORG_URL,
isValid = true,
)
}
}
val changeServerState = changeServerPresenter.present() val changeServerState = changeServerPresenter.present()
return ChangeAccountProviderState( return ChangeAccountProviderState(
// Just matrix.org by default for now accountProviders = staticAccountProviderList,
accountProviders = listOf(
AccountProvider(
url = AuthenticationConfig.MATRIX_ORG_URL,
subtitle = null,
isPublic = true,
isMatrixOrg = true,
isValid = true,
)
),
changeServerState = changeServerState, changeServerState = changeServerState,
) )
} }

View file

@ -11,7 +11,7 @@ import io.element.android.features.login.impl.accountprovider.AccountProvider
import io.element.android.features.login.impl.changeserver.ChangeServerState import io.element.android.features.login.impl.changeserver.ChangeServerState
// Do not use default value, so no member get forgotten in the presenters. // Do not use default value, so no member get forgotten in the presenters.
data class ChangeAccountProviderState constructor( data class ChangeAccountProviderState(
val accountProviders: List<AccountProvider>, val accountProviders: List<AccountProvider>,
val changeServerState: ChangeServerState, val changeServerState: ChangeServerState,
) )

View file

@ -15,6 +15,8 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.features.login.impl.changeserver.UnauthorizedAccountProviderException
import io.element.android.features.login.impl.qrcode.QrCodeLoginManager import io.element.android.features.login.impl.qrcode.QrCodeLoginManager
import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
@ -36,6 +38,7 @@ class QrCodeScanPresenter @Inject constructor(
private val qrCodeLoginDataFactory: MatrixQrCodeLoginDataFactory, private val qrCodeLoginDataFactory: MatrixQrCodeLoginDataFactory,
private val qrCodeLoginManager: QrCodeLoginManager, private val qrCodeLoginManager: QrCodeLoginManager,
private val coroutineDispatchers: CoroutineDispatchers, private val coroutineDispatchers: CoroutineDispatchers,
private val enterpriseService: EnterpriseService,
) : Presenter<QrCodeScanState> { ) : Presenter<QrCodeScanState> {
private var isScanning by mutableStateOf(true) private var isScanning by mutableStateOf(true)
@ -90,9 +93,17 @@ class QrCodeScanPresenter @Inject constructor(
launch(coroutineDispatchers.computation) { launch(coroutineDispatchers.computation) {
suspend { suspend {
qrCodeLoginDataFactory.parseQrCodeData(code).onFailure { val data = qrCodeLoginDataFactory.parseQrCodeData(code).onFailure {
Timber.e(it, "Error parsing QR code data") Timber.e(it, "Error parsing QR code data")
}.getOrThrow() }.getOrThrow()
val serverName = data.serverName()
if (serverName != null && enterpriseService.isAllowedToConnectToHomeserver(serverName).not()) {
throw UnauthorizedAccountProviderException(
unauthorisedAccountProviderTitle = serverName,
authorisedAccountProviderTitles = enterpriseService.defaultHomeserverList(),
)
}
data
}.runCatchingUpdatingState(codeScannedAction) }.runCatchingUpdatingState(codeScannedAction)
}.invokeOnCompletion { }.invokeOnCompletion {
isProcessingCode.set(false) isProcessingCode.set(false)

View file

@ -8,6 +8,7 @@
package io.element.android.features.login.impl.screens.qrcode.scan package io.element.android.features.login.impl.screens.qrcode.scan
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.login.impl.changeserver.UnauthorizedAccountProviderException
import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginData import io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginData
import io.element.android.libraries.matrix.api.auth.qrlogin.QrLoginException import io.element.android.libraries.matrix.api.auth.qrlogin.QrLoginException
@ -19,6 +20,15 @@ open class QrCodeScanStateProvider : PreviewParameterProvider<QrCodeScanState> {
aQrCodeScanState(isScanning = false, authenticationAction = AsyncAction.Loading), aQrCodeScanState(isScanning = false, authenticationAction = AsyncAction.Loading),
aQrCodeScanState(isScanning = false, authenticationAction = AsyncAction.Failure(Exception("Error"))), aQrCodeScanState(isScanning = false, authenticationAction = AsyncAction.Failure(Exception("Error"))),
aQrCodeScanState(isScanning = false, authenticationAction = AsyncAction.Failure(QrLoginException.OtherDeviceNotSignedIn)), aQrCodeScanState(isScanning = false, authenticationAction = AsyncAction.Failure(QrLoginException.OtherDeviceNotSignedIn)),
aQrCodeScanState(
isScanning = false,
authenticationAction = AsyncAction.Failure(
UnauthorizedAccountProviderException(
unauthorisedAccountProviderTitle = "example.com",
authorisedAccountProviderTitles = listOf("element.io", "element.org"),
)
)
),
// Add other state here // Add other state here
) )
} }

View file

@ -35,6 +35,7 @@ import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.login.impl.R import io.element.android.features.login.impl.R
import io.element.android.features.login.impl.changeserver.UnauthorizedAccountProviderException
import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.designsystem.atomic.pages.FlowStepPage import io.element.android.libraries.designsystem.atomic.pages.FlowStepPage
import io.element.android.libraries.designsystem.components.BigIcon import io.element.android.libraries.designsystem.components.BigIcon
@ -144,6 +145,12 @@ private fun ColumnScope.Buttons(
Spacer(modifier = Modifier.width(4.dp)) Spacer(modifier = Modifier.width(4.dp))
Text( Text(
text = when (error) { text = when (error) {
is UnauthorizedAccountProviderException -> {
stringResource(
id = R.string.screen_change_server_error_unauthorized_homeserver_title,
error.unauthorisedAccountProviderTitle,
)
}
is QrLoginException.OtherDeviceNotSignedIn -> { is QrLoginException.OtherDeviceNotSignedIn -> {
stringResource(R.string.screen_qr_code_login_device_not_signed_in_scan_state_subtitle) stringResource(R.string.screen_qr_code_login_device_not_signed_in_scan_state_subtitle)
} }
@ -156,6 +163,12 @@ private fun ColumnScope.Buttons(
} }
Text( Text(
text = when (error) { text = when (error) {
is UnauthorizedAccountProviderException -> {
stringResource(
id = R.string.screen_change_server_error_unauthorized_homeserver_content,
error.authorisedAccountProviderTitles.joinToString(),
)
}
is QrLoginException.OtherDeviceNotSignedIn -> { is QrLoginException.OtherDeviceNotSignedIn -> {
stringResource(R.string.screen_qr_code_login_device_not_signed_in_scan_state_description) stringResource(R.string.screen_qr_code_login_device_not_signed_in_scan_state_description)
} }

View file

@ -29,6 +29,12 @@
<string name="screen_login_subtitle">"Matrix - гэта адкрытая сетка для бяспечнай, дэцэнтралізаванай сувязі."</string> <string name="screen_login_subtitle">"Matrix - гэта адкрытая сетка для бяспечнай, дэцэнтралізаванай сувязі."</string>
<string name="screen_login_title">"Сардэчна запрашаем!"</string> <string name="screen_login_title">"Сардэчна запрашаем!"</string>
<string name="screen_login_title_with_homeserver">"Увайсці ў %1$s"</string> <string name="screen_login_title_with_homeserver">"Увайсці ў %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Увайсці ўручную"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Увайсці з QR-кодам"</string>
<string name="screen_onboarding_sign_up">"Стварыць уліковы запіс"</string>
<string name="screen_onboarding_welcome_message">"Сардэчна запрашаем у самы хуткі %1$s. Перавага ў хуткасці і прастаце."</string>
<string name="screen_onboarding_welcome_subtitle">"Сардэчна запрашаем у %1$s. Зараджаны, для хуткасці і прастаты."</string>
<string name="screen_onboarding_welcome_title">"Будзьце ў сваім element"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Ўсталяванне бяспечнага злучэння"</string> <string name="screen_qr_code_login_connecting_subtitle">"Ўсталяванне бяспечнага злучэння"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Не атрымалася ўсталяваць бяспечнае злучэнне з новай прыладай. Існуючыя прылады па-ранейшаму ў бяспецы, і вам не трэба турбавацца пра іх."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Не атрымалася ўсталяваць бяспечнае злучэнне з новай прыладай. Існуючыя прылады па-ранейшаму ў бяспецы, і вам не трэба турбавацца пра іх."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Што зараз?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Што зараз?"</string>

View file

@ -19,6 +19,12 @@
<string name="screen_login_subtitle">"Matrix е отворена мрежа за сигурна, децентрализирана комуникация."</string> <string name="screen_login_subtitle">"Matrix е отворена мрежа за сигурна, децентрализирана комуникация."</string>
<string name="screen_login_title">"Добре дошли отново!"</string> <string name="screen_login_title">"Добре дошли отново!"</string>
<string name="screen_login_title_with_homeserver">"Влизане в %1$s"</string> <string name="screen_login_title_with_homeserver">"Влизане в %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Влизане ръчно"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Влизане с QR код"</string>
<string name="screen_onboarding_sign_up">"Създаване на акаунт"</string>
<string name="screen_onboarding_welcome_message">"Добре дошли в най-бързия %1$s досега. Супер зареден за скорост и простота."</string>
<string name="screen_onboarding_welcome_subtitle">"Добре дошли в %1$s. Супер зареден за скорост и простота."</string>
<string name="screen_onboarding_welcome_title">"Бъдете в стихията си"</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Повторен опит"</string> <string name="screen_qr_code_login_invalid_scan_state_retry_button">"Повторен опит"</string>
<string name="screen_server_confirmation_change_server">"Промяна на доставчика на акаунт"</string> <string name="screen_server_confirmation_change_server">"Промяна на доставчика на акаунт"</string>
<string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix е отворена мрежа за сигурна, децентрализирана комуникация."</string> <string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix е отворена мрежа за сигурна, децентрализирана комуникация."</string>

View file

@ -17,6 +17,9 @@
<string name="screen_change_server_error_invalid_well_known">"Server není k dispozici kvůli problému se souborem well-known: <string name="screen_change_server_error_invalid_well_known">"Server není k dispozici kvůli problému se souborem well-known:
%1$s"</string> %1$s"</string>
<string name="screen_change_server_error_no_sliding_sync_message">"Vybraný poskytovatel účtu nepodporuje klouzavou synchronizaci. Pro použití %1$s je nutná aktualizace serveru."</string> <string name="screen_change_server_error_no_sliding_sync_message">"Vybraný poskytovatel účtu nepodporuje klouzavou synchronizaci. Pro použití %1$s je nutná aktualizace serveru."</string>
<string name="screen_change_server_error_unauthorized_homeserver">"Uživateli %1$s není dovoleno se připojit do %2$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver_content">"Tato aplikace byla nakonfigurována tak, aby umožňovala: %1$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver_title">"Poskytovatel účtu %1$s není povolen."</string>
<string name="screen_change_server_form_header">"Adresa URL domovského serveru"</string> <string name="screen_change_server_form_header">"Adresa URL domovského serveru"</string>
<string name="screen_change_server_form_notice">"Zadejte adresu domény."</string> <string name="screen_change_server_form_notice">"Zadejte adresu domény."</string>
<string name="screen_change_server_subtitle">"Jaká je adresa vašeho serveru?"</string> <string name="screen_change_server_subtitle">"Jaká je adresa vašeho serveru?"</string>
@ -31,6 +34,13 @@
<string name="screen_login_subtitle">"Matrix je otevřená síť pro bezpečnou a decentralizovanou komunikaci."</string> <string name="screen_login_subtitle">"Matrix je otevřená síť pro bezpečnou a decentralizovanou komunikaci."</string>
<string name="screen_login_title">"Vítejte zpět!"</string> <string name="screen_login_title">"Vítejte zpět!"</string>
<string name="screen_login_title_with_homeserver">"Přihlaste se k %1$s"</string> <string name="screen_login_title_with_homeserver">"Přihlaste se k %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Ruční přihlášení"</string>
<string name="screen_onboarding_sign_in_to">"Přihlásit se do %1$s"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Přihlásit se pomocí QR kódu"</string>
<string name="screen_onboarding_sign_up">"Vytvořit účet"</string>
<string name="screen_onboarding_welcome_message">"Vítejte v dosud nejrychlejším %1$su. Vylepšený pro rychlost a jednoduchost."</string>
<string name="screen_onboarding_welcome_subtitle">"Vítejte v %1$su. Vylepšený, pro rychlost a jednoduchost."</string>
<string name="screen_onboarding_welcome_title">"Buďte ve svém živlu"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Navazování zabezpečeného spojení"</string> <string name="screen_qr_code_login_connecting_subtitle">"Navazování zabezpečeného spojení"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"K novému zařízení se nepodařilo navázat bezpečné připojení. Vaše stávající zařízení jsou stále v bezpečí a nemusíte se o ně obávat."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"K novému zařízení se nepodařilo navázat bezpečné připojení. Vaše stávající zařízení jsou stále v bezpečí a nemusíte se o ně obávat."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Co teď?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Co teď?"</string>

View file

@ -14,9 +14,12 @@
<string name="screen_change_account_provider_subtitle">"Defnyddiwch ddarparwr cyfrif gwahanol, fel eich gweinydd preifat eich hun neu gyfrif gwaith."</string> <string name="screen_change_account_provider_subtitle">"Defnyddiwch ddarparwr cyfrif gwahanol, fel eich gweinydd preifat eich hun neu gyfrif gwaith."</string>
<string name="screen_change_account_provider_title">"Newid darparwr cyfrif"</string> <string name="screen_change_account_provider_title">"Newid darparwr cyfrif"</string>
<string name="screen_change_server_error_invalid_homeserver">"Doedd dim modd i ni gyrraedd y gweinydd cartref hwn. Gwiriwch eich bod wedi rhoi URL y gweinydd cartref yn gywir. Os yw\'r URL yn gywir, cysylltwch â gweinyddwr eich gweinydd cartref am ragor o help."</string> <string name="screen_change_server_error_invalid_homeserver">"Doedd dim modd i ni gyrraedd y gweinydd cartref hwn. Gwiriwch eich bod wedi rhoi URL y gweinydd cartref yn gywir. Os yw\'r URL yn gywir, cysylltwch â gweinyddwr eich gweinydd cartref am ragor o help."</string>
<string name="screen_change_server_error_invalid_well_known">"Nid yw cydweddu llithrig ar gael oherwydd problem yn y ffeil adnabyddus: <string name="screen_change_server_error_invalid_well_known">"Dyw cydweddu llithrig ddim ar gael oherwydd problem yn y ffeil .well-known:
%1$s"</string> %1$s"</string>
<string name="screen_change_server_error_no_sliding_sync_message">"Dyw\'r darparwr cyfrif hwn ddim yn cefnogi cydweddu llithro. Mae angen uwchraddio\'r gweinydd i ddefnyddio %1$s."</string> <string name="screen_change_server_error_no_sliding_sync_message">"Dyw\'r darparwr cyfrif hwn ddim yn cefnogi cydweddu llithro. Mae angen uwchraddio\'r gweinydd i ddefnyddio %1$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver">"Does dim caniatâd i %1$s gysylltu â %2$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver_content">"Mae\'r ap hwn wedi\'i ffurfweddu i ganiatáu: %1$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver_title">"Dyw darparwr cyfrif %1$s dddim yn cael ei ganiatáu."</string>
<string name="screen_change_server_form_header">"URL y Gweinydd Cartref"</string> <string name="screen_change_server_form_header">"URL y Gweinydd Cartref"</string>
<string name="screen_change_server_form_notice">"Rhowch gyfeiriad parth."</string> <string name="screen_change_server_form_notice">"Rhowch gyfeiriad parth."</string>
<string name="screen_change_server_subtitle">"Beth yw cyfeiriad eich gweinydd?"</string> <string name="screen_change_server_subtitle">"Beth yw cyfeiriad eich gweinydd?"</string>
@ -31,6 +34,13 @@
<string name="screen_login_subtitle">"Mae Matrix yn rhwydwaith agored ar gyfer cyfathrebu diogel, datganoledig."</string> <string name="screen_login_subtitle">"Mae Matrix yn rhwydwaith agored ar gyfer cyfathrebu diogel, datganoledig."</string>
<string name="screen_login_title">"Croeso nôl!"</string> <string name="screen_login_title">"Croeso nôl!"</string>
<string name="screen_login_title_with_homeserver">"Mewngofnodi i %1$s"</string> <string name="screen_login_title_with_homeserver">"Mewngofnodi i %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Mewngofnodwch â llaw"</string>
<string name="screen_onboarding_sign_in_to">"Mewngofnodi i %1$s"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Mewngofnodwch gyda chod QR"</string>
<string name="screen_onboarding_sign_up">"Creu cyfrif"</string>
<string name="screen_onboarding_welcome_message">"Croeso i\'r %1$s cyflymaf erioed. Yn nodedig am gyflymder a symlrwydd."</string>
<string name="screen_onboarding_welcome_subtitle">"Croeso i %1$s. Yn nodedig ar gyfer cyflymder a symlrwydd."</string>
<string name="screen_onboarding_welcome_title">"Byddwch yn eich elfen"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Yn creu cysylltiad diogel"</string> <string name="screen_qr_code_login_connecting_subtitle">"Yn creu cysylltiad diogel"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Nid oedd modd gwneud cysylltiad diogel â\'r ddyfais newydd. Mae eich dyfeisiau presennol yn dal yn ddiogel a does dim angen i chi boeni amdanyn nhw."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Nid oedd modd gwneud cysylltiad diogel â\'r ddyfais newydd. Mae eich dyfeisiau presennol yn dal yn ddiogel a does dim angen i chi boeni amdanyn nhw."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Beth nawr?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Beth nawr?"</string>

View file

@ -17,7 +17,7 @@
<string name="screen_change_server_error_invalid_well_known">"Der Server ist aufgrund eines Problems im \"well-known file\" nicht verfügbar: <string name="screen_change_server_error_invalid_well_known">"Der Server ist aufgrund eines Problems im \"well-known file\" nicht verfügbar:
%1$s"</string> %1$s"</string>
<string name="screen_change_server_error_no_sliding_sync_message">"Der gewählte Kontoanbieter unterstützt Sliding Sync nicht. Für die Verwendung von %1$s ist ein Upgrade des Servers erforderlich."</string> <string name="screen_change_server_error_no_sliding_sync_message">"Der gewählte Kontoanbieter unterstützt Sliding Sync nicht. Für die Verwendung von %1$s ist ein Upgrade des Servers erforderlich."</string>
<string name="screen_change_server_error_unauthorized_homeserver">"%1$sdarf keine Verbindung herstellen zu%2$s."</string> <string name="screen_change_server_error_unauthorized_homeserver">"%1$s darf keine Verbindung herstellen zu %2$s."</string>
<string name="screen_change_server_form_header">"Homeserver-URL"</string> <string name="screen_change_server_form_header">"Homeserver-URL"</string>
<string name="screen_change_server_form_notice">"Geben Sie eine Domainadresse ein."</string> <string name="screen_change_server_form_notice">"Geben Sie eine Domainadresse ein."</string>
<string name="screen_change_server_subtitle">"Wie lautet die Adresse deines Servers?"</string> <string name="screen_change_server_subtitle">"Wie lautet die Adresse deines Servers?"</string>
@ -32,6 +32,12 @@
<string name="screen_login_subtitle">"Matrix ist ein offenes Netzwerk für eine sichere, dezentrale Kommunikation."</string> <string name="screen_login_subtitle">"Matrix ist ein offenes Netzwerk für eine sichere, dezentrale Kommunikation."</string>
<string name="screen_login_title">"Willkommen zurück!"</string> <string name="screen_login_title">"Willkommen zurück!"</string>
<string name="screen_login_title_with_homeserver">"Anmelden bei %1$s"</string> <string name="screen_login_title_with_homeserver">"Anmelden bei %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Manuell anmelden"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Mit QR-Code anmelden"</string>
<string name="screen_onboarding_sign_up">"Konto erstellen"</string>
<string name="screen_onboarding_welcome_message">"Willkommen beim schnellsten %1$s aller Zeiten. Optimiert für Geschwindigkeit und Einfachheit."</string>
<string name="screen_onboarding_welcome_subtitle">"Willkommen zu %1$s. Aufgeladen, für Geschwindigkeit und Einfachheit."</string>
<string name="screen_onboarding_welcome_title">"Sei in Deinem Element"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Sichere Verbindung aufbauen"</string> <string name="screen_qr_code_login_connecting_subtitle">"Sichere Verbindung aufbauen"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Es konnte keine sichere Verbindung zu dem neuen Gerät hergestellt werden."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Es konnte keine sichere Verbindung zu dem neuen Gerät hergestellt werden."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Und jetzt?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Und jetzt?"</string>
@ -54,7 +60,7 @@
Versuche, dich manuell anzumelden, oder scanne den QR-Code mit einem anderen Gerät."</string> Versuche, dich manuell anzumelden, oder scanne den QR-Code mit einem anderen Gerät."</string>
<string name="screen_qr_code_login_error_linking_not_suported_title">"QR-Code wird nicht unterstützt"</string> <string name="screen_qr_code_login_error_linking_not_suported_title">"QR-Code wird nicht unterstützt"</string>
<string name="screen_qr_code_login_error_sliding_sync_not_supported_subtitle">"Ihr Kontoanbieter unterstützt %1$s nicht."</string> <string name="screen_qr_code_login_error_sliding_sync_not_supported_subtitle">"Ihr Kontoanbieter unterstützt %1$s nicht."</string>
<string name="screen_qr_code_login_error_sliding_sync_not_supported_title">"%1$swird nicht unterstützt"</string> <string name="screen_qr_code_login_error_sliding_sync_not_supported_title">"%1$s wird nicht unterstützt"</string>
<string name="screen_qr_code_login_initial_state_button_title">"Bereit zum Scannen"</string> <string name="screen_qr_code_login_initial_state_button_title">"Bereit zum Scannen"</string>
<string name="screen_qr_code_login_initial_state_item_1">"%1$s auf einem Desktop-Gerät öffnen"</string> <string name="screen_qr_code_login_initial_state_item_1">"%1$s auf einem Desktop-Gerät öffnen"</string>
<string name="screen_qr_code_login_initial_state_item_2">"Klick auf deinen Avatar"</string> <string name="screen_qr_code_login_initial_state_item_2">"Klick auf deinen Avatar"</string>

View file

@ -29,6 +29,12 @@
<string name="screen_login_subtitle">"Το Matrix είναι ένα ανοιχτό δίκτυο για ασφαλή, αποκεντρωμένη επικοινωνία."</string> <string name="screen_login_subtitle">"Το Matrix είναι ένα ανοιχτό δίκτυο για ασφαλή, αποκεντρωμένη επικοινωνία."</string>
<string name="screen_login_title">"Καλωσόρισες ξανά!"</string> <string name="screen_login_title">"Καλωσόρισες ξανά!"</string>
<string name="screen_login_title_with_homeserver">"Συνδέσου στο %1$s"</string> <string name="screen_login_title_with_homeserver">"Συνδέσου στο %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Σύνδεση χειροκίνητα"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Συνδέσου με κωδικό QR"</string>
<string name="screen_onboarding_sign_up">"Δημιουργία λογαριασμού"</string>
<string name="screen_onboarding_welcome_message">"Καλώς ήλθατε στο γρηγορότερο %1$s όλων των εποχών. Υπερτροφοδοτούμενο με ταχύτητα και απλότητα."</string>
<string name="screen_onboarding_welcome_subtitle">"Καλώς ήρθες στο %1$s. Υπερφορτισμένο, για ταχύτητα και απλότητα."</string>
<string name="screen_onboarding_welcome_title">"Μείνε στο element σου"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Εγκαθίδρυση ασφαλούς σύνδεσης"</string> <string name="screen_qr_code_login_connecting_subtitle">"Εγκαθίδρυση ασφαλούς σύνδεσης"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Δεν ήταν δυνατή η πραγματοποίηση ασφαλούς σύνδεσης στη νέα συσκευή. Οι υπάρχουσες συσκευές σας εξακολουθούν να είναι ασφαλείς και δεν χρειάζεται να ανησυχείς για αυτές."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Δεν ήταν δυνατή η πραγματοποίηση ασφαλούς σύνδεσης στη νέα συσκευή. Οι υπάρχουσες συσκευές σας εξακολουθούν να είναι ασφαλείς και δεν χρειάζεται να ανησυχείς για αυτές."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Τί είναι πάλι;"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Τί είναι πάλι;"</string>

View file

@ -29,6 +29,12 @@
<string name="screen_login_subtitle">"Matrix es una red abierta para una comunicación segura y descentralizada."</string> <string name="screen_login_subtitle">"Matrix es una red abierta para una comunicación segura y descentralizada."</string>
<string name="screen_login_title">"¡Hola de nuevo!"</string> <string name="screen_login_title">"¡Hola de nuevo!"</string>
<string name="screen_login_title_with_homeserver">"Iniciar sesión en %1$s"</string> <string name="screen_login_title_with_homeserver">"Iniciar sesión en %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Iniciar sesión manualmente"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Iniciar sesión con un código QR"</string>
<string name="screen_onboarding_sign_up">"Crear cuenta"</string>
<string name="screen_onboarding_welcome_message">"Bienvenido al %1$s más rápido de todos los tiempos. Diseñado para la velocidad y la simplicidad."</string>
<string name="screen_onboarding_welcome_subtitle">"Bienvenido a %1$s. Vitaminado, para mayor rapidez y sencillez."</string>
<string name="screen_onboarding_welcome_title">"Siéntete en tu Elemento"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Estableciendo una conexión segura"</string> <string name="screen_qr_code_login_connecting_subtitle">"Estableciendo una conexión segura"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"No se pudo establecer una conexión segura con el nuevo dispositivo. Tus dispositivos actuales siguen siendo seguros y no tienes que preocuparte por ellos."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"No se pudo establecer una conexión segura con el nuevo dispositivo. Tus dispositivos actuales siguen siendo seguros y no tienes que preocuparte por ellos."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"¿Y ahora qué?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"¿Y ahora qué?"</string>

View file

@ -18,6 +18,8 @@
%1$s"</string> %1$s"</string>
<string name="screen_change_server_error_no_sliding_sync_message">"Valitud teenusepakkuja ei toeta „sliding sync“ režiimi. Rakenduse %1$s kasutamiseks on vaja serverit uuendada."</string> <string name="screen_change_server_error_no_sliding_sync_message">"Valitud teenusepakkuja ei toeta „sliding sync“ režiimi. Rakenduse %1$s kasutamiseks on vaja serverit uuendada."</string>
<string name="screen_change_server_error_unauthorized_homeserver">"%1$s ei saa kasutada %2$s koduserverit."</string> <string name="screen_change_server_error_unauthorized_homeserver">"%1$s ei saa kasutada %2$s koduserverit."</string>
<string name="screen_change_server_error_unauthorized_homeserver_content">"See rakendus on seadistatud järgneva koduserveri kasutamiseks: %1$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver_title">"%1$s teenusepakkuja pole lubatud."</string>
<string name="screen_change_server_form_header">"Koduserveri url"</string> <string name="screen_change_server_form_header">"Koduserveri url"</string>
<string name="screen_change_server_form_notice">"Sisesta domeeni aadress."</string> <string name="screen_change_server_form_notice">"Sisesta domeeni aadress."</string>
<string name="screen_change_server_subtitle">"Mis on sinu koduserveri aadress?"</string> <string name="screen_change_server_subtitle">"Mis on sinu koduserveri aadress?"</string>
@ -32,6 +34,13 @@
<string name="screen_login_subtitle">"Matrix on avatud võrk turvalise ja hajutatud suhtluse jaoks."</string> <string name="screen_login_subtitle">"Matrix on avatud võrk turvalise ja hajutatud suhtluse jaoks."</string>
<string name="screen_login_title">"Tere tulemast tagasi!"</string> <string name="screen_login_title">"Tere tulemast tagasi!"</string>
<string name="screen_login_title_with_homeserver">"Logi sisse serverisse %1$s"</string> <string name="screen_login_title_with_homeserver">"Logi sisse serverisse %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Logi sisse käsitsi"</string>
<string name="screen_onboarding_sign_in_to">"Logi sisse teenusesse %1$s"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Logi sisse QR-koodi alusel"</string>
<string name="screen_onboarding_sign_up">"Loo kasutajakonto"</string>
<string name="screen_onboarding_welcome_message">"Läbi aegade kiireim ja mugavaim %1$s."</string>
<string name="screen_onboarding_welcome_subtitle">"Tere tulemast kasutama kiiret ja lihtsat suhtlusrakendust %1$s."</string>
<string name="screen_onboarding_welcome_title">"Ole oma elemendis"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Loome turvalist ühendust"</string> <string name="screen_qr_code_login_connecting_subtitle">"Loome turvalist ühendust"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Turvalise ühenduse loomine uue seadmega ei õnnestunud. Sinu olemasolevad seadmed on jätkuvalt turvatud ja sa ei pea nende pärast muretsema."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Turvalise ühenduse loomine uue seadmega ei õnnestunud. Sinu olemasolevad seadmed on jätkuvalt turvatud ja sa ei pea nende pärast muretsema."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Mida järgmiseks teeme?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Mida järgmiseks teeme?"</string>

View file

@ -20,6 +20,12 @@
<string name="screen_login_subtitle">"Matrix komunikazio seguru eta deszentralizaturako sare irekia da."</string> <string name="screen_login_subtitle">"Matrix komunikazio seguru eta deszentralizaturako sare irekia da."</string>
<string name="screen_login_title">"Ongi etorri!"</string> <string name="screen_login_title">"Ongi etorri!"</string>
<string name="screen_login_title_with_homeserver">"Hasi saioa %1$s(e)n"</string> <string name="screen_login_title_with_homeserver">"Hasi saioa %1$s(e)n"</string>
<string name="screen_onboarding_sign_in_manually">"Hasi saioa eskuz"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Hasi saioa QR kodearekin"</string>
<string name="screen_onboarding_sign_up">"Sortu kontua"</string>
<string name="screen_onboarding_welcome_message">"Ongi etorri inoizko %1$s azkarrenera. Abiaduraz eta sinpletasunaz gainkargatua."</string>
<string name="screen_onboarding_welcome_subtitle">"Ongi etorri %1$s-ra. Abiaduraz eta sinpletasunez gainezka."</string>
<string name="screen_onboarding_welcome_title">"Egon zure saltsan"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Konexio segurua ezartzen"</string> <string name="screen_qr_code_login_connecting_subtitle">"Konexio segurua ezartzen"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Ezin izan da konexio segururik ezarri gailu berriarekin. Lehendik dauden gailuak seguru daude oraindik ere eta ez duzu haietaz kezkatu beharrik."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Ezin izan da konexio segururik ezarri gailu berriarekin. Lehendik dauden gailuak seguru daude oraindik ere eta ez duzu haietaz kezkatu beharrik."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Orain zer?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Orain zer?"</string>

View file

@ -25,6 +25,12 @@
<string name="screen_login_subtitle">"ماتریکس شبکه‌ای بار برای ارتباطات نامتمرکز و امن است."</string> <string name="screen_login_subtitle">"ماتریکس شبکه‌ای بار برای ارتباطات نامتمرکز و امن است."</string>
<string name="screen_login_title">"خوش برگشتید!"</string> <string name="screen_login_title">"خوش برگشتید!"</string>
<string name="screen_login_title_with_homeserver">"ورود به %1$s"</string> <string name="screen_login_title_with_homeserver">"ورود به %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"ورود دستی"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"ورود با کد QR"</string>
<string name="screen_onboarding_sign_up">"ایجاد حساب"</string>
<string name="screen_onboarding_welcome_message">"به سریع‌ترین %1$s خوش آمدید. بازطرّاحی شده برای سرعت و سادگی."</string>
<string name="screen_onboarding_welcome_subtitle">"به %1$s خوش آمدید. بازطرّاحی شده برای سرعت و سادگی."</string>
<string name="screen_onboarding_welcome_title">"در المنتتان باشید"</string>
<string name="screen_qr_code_login_connecting_subtitle">"برقرار کدن اتّصالی امن"</string> <string name="screen_qr_code_login_connecting_subtitle">"برقرار کدن اتّصالی امن"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"نتوانست اتّصالی امن به افزارهٔ جدید بسازد. افزاره‌های موجودتان هنوز امنند و نیازی نیست نگرانشان باشید."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"نتوانست اتّصالی امن به افزارهٔ جدید بسازد. افزاره‌های موجودتان هنوز امنند و نیازی نیست نگرانشان باشید."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"اکنون چه؟"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"اکنون چه؟"</string>

View file

@ -17,6 +17,9 @@
<string name="screen_change_server_error_invalid_well_known">"Sliding sync ei ole saatavilla well-known tiedostossa olevan ongelman vuoksi: <string name="screen_change_server_error_invalid_well_known">"Sliding sync ei ole saatavilla well-known tiedostossa olevan ongelman vuoksi:
%1$s"</string> %1$s"</string>
<string name="screen_change_server_error_no_sliding_sync_message">"Valitsemasi palveluntarjoaja ei tue sliding syncia. Palvelimen päivitys tarvitaan %1$s -sovelluksen käyttämiseen."</string> <string name="screen_change_server_error_no_sliding_sync_message">"Valitsemasi palveluntarjoaja ei tue sliding syncia. Palvelimen päivitys tarvitaan %1$s -sovelluksen käyttämiseen."</string>
<string name="screen_change_server_error_unauthorized_homeserver">"%1$s ei saa yhdistää %2$s -palvelimeen."</string>
<string name="screen_change_server_error_unauthorized_homeserver_content">"Tämä sovellus on määritetty sallimaan: %1$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver_title">"Palveluntarjoaja %1$s ei ole sallittu."</string>
<string name="screen_change_server_form_header">"Kotipalvelimen osoite"</string> <string name="screen_change_server_form_header">"Kotipalvelimen osoite"</string>
<string name="screen_change_server_form_notice">"Anna verkkotunnuksen osoite."</string> <string name="screen_change_server_form_notice">"Anna verkkotunnuksen osoite."</string>
<string name="screen_change_server_subtitle">"Mikä on palvelimesi osoite?"</string> <string name="screen_change_server_subtitle">"Mikä on palvelimesi osoite?"</string>
@ -31,6 +34,13 @@
<string name="screen_login_subtitle">"Matrix on avoin verkko turvallista, hajautettua viestintää varten."</string> <string name="screen_login_subtitle">"Matrix on avoin verkko turvallista, hajautettua viestintää varten."</string>
<string name="screen_login_title">"Tervetuloa takaisin!"</string> <string name="screen_login_title">"Tervetuloa takaisin!"</string>
<string name="screen_login_title_with_homeserver">"Kirjaudu sisään %1$s -palvelimelle"</string> <string name="screen_login_title_with_homeserver">"Kirjaudu sisään %1$s -palvelimelle"</string>
<string name="screen_onboarding_sign_in_manually">"Kirjaudu sisään manuaalisesti"</string>
<string name="screen_onboarding_sign_in_to">"Kirjaudu sisään %1$s -palvelimelle"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Kirjaudu sisään QR-koodilla"</string>
<string name="screen_onboarding_sign_up">"Luo tili"</string>
<string name="screen_onboarding_welcome_message">"Tervetuloa kaikkien aikojen nopeimpaan %1$s -sovellukseen. Ahdettu nopeudella ja yksinkertaisuudella."</string>
<string name="screen_onboarding_welcome_subtitle">"Tervetuloa %1$s -sovellukseen. Ahdettu nopeudella ja yksinkertaisuudella."</string>
<string name="screen_onboarding_welcome_title">"Ole elementissäsi"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Muodostetaan turvallista yhteyttä"</string> <string name="screen_qr_code_login_connecting_subtitle">"Muodostetaan turvallista yhteyttä"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Turvallista yhteyttä uuteen laitteeseen ei voitu muodostaa. Olemassa olevat laitteesi ovat edelleen turvassa, eikä sinun tarvitse huolehtia niistä."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Turvallista yhteyttä uuteen laitteeseen ei voitu muodostaa. Olemassa olevat laitteesi ovat edelleen turvassa, eikä sinun tarvitse huolehtia niistä."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Mitä nyt?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Mitä nyt?"</string>

View file

@ -17,6 +17,9 @@
<string name="screen_change_server_error_invalid_well_known">"Ce fournisseur de compte nest pas disponible en raison dun problème dans le fichier .well-known: <string name="screen_change_server_error_invalid_well_known">"Ce fournisseur de compte nest pas disponible en raison dun problème dans le fichier .well-known:
%1$s"</string> %1$s"</string>
<string name="screen_change_server_error_no_sliding_sync_message">"Le fournisseur de compte sélectionné ne prend pas en charge le sliding sync. Une mise à jour du serveur est nécessaire pour pouvoir utiliser %1$s."</string> <string name="screen_change_server_error_no_sliding_sync_message">"Le fournisseur de compte sélectionné ne prend pas en charge le sliding sync. Une mise à jour du serveur est nécessaire pour pouvoir utiliser %1$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver">"%1$s nest pas autorisé à se connecter à %2$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver_content">"Cette application a été configurée pour autoriser: %1$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver_title">"Le fournisseur de compte %1$s nest pas autorisé."</string>
<string name="screen_change_server_form_header">"URL du serveur daccueil"</string> <string name="screen_change_server_form_header">"URL du serveur daccueil"</string>
<string name="screen_change_server_form_notice">"Saisissez une adresse de domaine."</string> <string name="screen_change_server_form_notice">"Saisissez une adresse de domaine."</string>
<string name="screen_change_server_subtitle">"Quelle est ladresse de votre serveur ?"</string> <string name="screen_change_server_subtitle">"Quelle est ladresse de votre serveur ?"</string>
@ -31,6 +34,13 @@
<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_login_subtitle">"Matrix est un réseau ouvert pour une communication sécurisée et décentralisée."</string>
<string name="screen_login_title">"Content de vous revoir !"</string> <string name="screen_login_title">"Content de vous revoir !"</string>
<string name="screen_login_title_with_homeserver">"Connectez-vous à %1$s"</string> <string name="screen_login_title_with_homeserver">"Connectez-vous à %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Se connecter manuellement"</string>
<string name="screen_onboarding_sign_in_to">"Se connecter à %1$s"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Se connecter avec un QR code"</string>
<string name="screen_onboarding_sign_up">"Créer un compte"</string>
<string name="screen_onboarding_welcome_message">"Bienvenue dans lapplication %1$s la plus rapide de tous les temps. Boosté pour plus de rapidité et de simplicité."</string>
<string name="screen_onboarding_welcome_subtitle">"Bienvenue sur %1$s. Boosté, pour plus de rapidité et de simplicité."</string>
<string name="screen_onboarding_welcome_title">"Soyez dans votre Element"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Établissement dune connexion sécurisée"</string> <string name="screen_qr_code_login_connecting_subtitle">"Établissement dune connexion sécurisée"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Aucune connexion sécurisée na pu être établie avec la nouvelle session. Vos sessions existantes sont toujours en sécurité et vous navez pas à vous en soucier."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Aucune connexion sécurisée na pu être établie avec la nouvelle session. Vos sessions existantes sont toujours en sécurité et vous navez pas à vous en soucier."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Et maintenant ?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Et maintenant ?"</string>

View file

@ -17,6 +17,9 @@
<string name="screen_change_server_error_invalid_well_known">"A kiszolgáló a well-known fájl problémája miatt nem érhető el: <string name="screen_change_server_error_invalid_well_known">"A kiszolgáló a well-known fájl problémája miatt nem érhető el:
%1$s"</string> %1$s"</string>
<string name="screen_change_server_error_no_sliding_sync_message">"A kiválasztott fiókszolgáltató nem támogatja a csúszóablakos szinkronizálást. Az %1$s használatához kiszolgálófrissítés szükséges."</string> <string name="screen_change_server_error_no_sliding_sync_message">"A kiválasztott fiókszolgáltató nem támogatja a csúszóablakos szinkronizálást. Az %1$s használatához kiszolgálófrissítés szükséges."</string>
<string name="screen_change_server_error_unauthorized_homeserver">"%1$s nem csatlakozhat ide: %2$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver_content">"Ezt az alkalmazást úgy konfigurálták, hogy engedélyezi ezt: %1$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver_title">"A(z) %1$s fiókszolgáltató nem engedélyezett."</string>
<string name="screen_change_server_form_header">"Matrix-kiszolgáló webcíme"</string> <string name="screen_change_server_form_header">"Matrix-kiszolgáló webcíme"</string>
<string name="screen_change_server_form_notice">"Adjon meg egy domaincímet."</string> <string name="screen_change_server_form_notice">"Adjon meg egy domaincímet."</string>
<string name="screen_change_server_subtitle">"Mi a kiszolgálója címe?"</string> <string name="screen_change_server_subtitle">"Mi a kiszolgálója címe?"</string>
@ -31,6 +34,13 @@
<string name="screen_login_subtitle">"A Matrix egy nyitott hálózat a biztonságos, decentralizált kommunikációhoz."</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_login_title">"Örülünk, hogy visszatért!"</string> <string name="screen_login_title">"Örülünk, hogy visszatért!"</string>
<string name="screen_login_title_with_homeserver">"Bejelentkezés ide: %1$s"</string> <string name="screen_login_title_with_homeserver">"Bejelentkezés ide: %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Kézi bejelentkezés"</string>
<string name="screen_onboarding_sign_in_to">"Bejelentkezés ide: %1$s"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Bejelentkezés QR-kóddal"</string>
<string name="screen_onboarding_sign_up">"Fiók létrehozása"</string>
<string name="screen_onboarding_welcome_message">"Üdvözöljük a valaha volt leggyorsabb %1$sben. Felturbózva, a sebesség és az egyszerűség érdekében."</string>
<string name="screen_onboarding_welcome_subtitle">"Üdvözli az %1$s. Felturbózva, a sebesség és az egyszerűség jegyében."</string>
<string name="screen_onboarding_welcome_title">"Legyen elemében"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Biztonságos kapcsolat létesítése"</string> <string name="screen_qr_code_login_connecting_subtitle">"Biztonságos kapcsolat létesítése"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Nem sikerült biztonságos kapcsolatot létesíteni az új eszközzel. A meglévő eszközei továbbra is biztonságban vannak, és nem kell aggódnia miattuk."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Nem sikerült biztonságos kapcsolatot létesíteni az új eszközzel. A meglévő eszközei továbbra is biztonságban vannak, és nem kell aggódnia miattuk."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Most mi lesz?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Most mi lesz?"</string>

View file

@ -29,6 +29,12 @@
<string name="screen_login_subtitle">"Matrix adalah jaringan terbuka untuk komunikasi yang aman dan terdesentralisasi."</string> <string name="screen_login_subtitle">"Matrix adalah jaringan terbuka untuk komunikasi yang aman dan terdesentralisasi."</string>
<string name="screen_login_title">"Selamat datang kembali!"</string> <string name="screen_login_title">"Selamat datang kembali!"</string>
<string name="screen_login_title_with_homeserver">"Masuk ke %1$s"</string> <string name="screen_login_title_with_homeserver">"Masuk ke %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Masuk secara manual"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Masuk dengan kode QR"</string>
<string name="screen_onboarding_sign_up">"Buat akun"</string>
<string name="screen_onboarding_welcome_message">"Selamat datang di %1$s tercepat yang pernah ada. Berdaya besar untuk kecepatan dan kesederhanaan."</string>
<string name="screen_onboarding_welcome_subtitle">"Selamat datang di %1$s. Berdaya penuh, untuk kecepatan dan kesederhanaan."</string>
<string name="screen_onboarding_welcome_title">"Berada di elemen Anda"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Membuat koneksi aman"</string> <string name="screen_qr_code_login_connecting_subtitle">"Membuat koneksi aman"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Koneksi aman tidak dapat dibuat ke perangkat baru. Perangkat Anda yang ada masih aman dan Anda tidak perlu khawatir tentang mereka."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Koneksi aman tidak dapat dibuat ke perangkat baru. Perangkat Anda yang ada masih aman dan Anda tidak perlu khawatir tentang mereka."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Apa sekarang?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Apa sekarang?"</string>

View file

@ -29,6 +29,12 @@
<string name="screen_login_subtitle">"Matrix è una rete aperta per comunicazioni sicure e decentralizzate."</string> <string name="screen_login_subtitle">"Matrix è una rete aperta per comunicazioni sicure e decentralizzate."</string>
<string name="screen_login_title">"Bentornato!"</string> <string name="screen_login_title">"Bentornato!"</string>
<string name="screen_login_title_with_homeserver">"Accedi a %1$s"</string> <string name="screen_login_title_with_homeserver">"Accedi a %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Accedi manualmente"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Accedi con codice QR"</string>
<string name="screen_onboarding_sign_up">"Crea account"</string>
<string name="screen_onboarding_welcome_message">"Benvenuti nell\'%1$s più veloce di sempre. Potenziato per velocità e semplicità."</string>
<string name="screen_onboarding_welcome_subtitle">"Benvenuto su %1$s. Potenziato in velocità e semplicità."</string>
<string name="screen_onboarding_welcome_title">"Sii nel tuo elemento"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Stabilendo la connessione"</string> <string name="screen_qr_code_login_connecting_subtitle">"Stabilendo la connessione"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Non è stato possibile stabilire una connessione sicura con il nuovo dispositivo. I tuoi dispositivi esistenti sono ancora al sicuro e non devi preoccuparti di loro."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Non è stato possibile stabilire una connessione sicura con il nuovo dispositivo. I tuoi dispositivi esistenti sono ancora al sicuro e non devi preoccuparti di loro."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"E adesso?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"E adesso?"</string>

View file

@ -28,6 +28,12 @@
<string name="screen_login_subtitle">"Matrix არის ღია ქსელი უსაფრთხო, დეცენტრალიზებული კომუნიკაციისთვის."</string> <string name="screen_login_subtitle">"Matrix არის ღია ქსელი უსაფრთხო, დეცენტრალიზებული კომუნიკაციისთვის."</string>
<string name="screen_login_title">"კეთილი იყოს თქვენი მობრძანება!"</string> <string name="screen_login_title">"კეთილი იყოს თქვენი მობრძანება!"</string>
<string name="screen_login_title_with_homeserver">"შესვლა %1$s-ში"</string> <string name="screen_login_title_with_homeserver">"შესვლა %1$s-ში"</string>
<string name="screen_onboarding_sign_in_manually">"ხელით შესვლა"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"შესვლა QR კოდით"</string>
<string name="screen_onboarding_sign_up">"ანგარიშის შექმნა"</string>
<string name="screen_onboarding_welcome_message">"კეთილი იყოს თქვენი მობრძანება უსწრაფეს %1$s-ში. დამუხტულია სიჩქარისა და სიმარტივისათვის."</string>
<string name="screen_onboarding_welcome_subtitle">"კეთილი იყოს თქვენი მობრძანება %1$s-ში! დამუხტული სიჩქარისა და სიმარტივისთვის."</string>
<string name="screen_onboarding_welcome_title">"იყავი შენს element-ში"</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"ხელახლა ცდა"</string> <string name="screen_qr_code_login_invalid_scan_state_retry_button">"ხელახლა ცდა"</string>
<string name="screen_server_confirmation_change_server">"შეცვალეთ ანგარიშის მომწოდებელი"</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_element_dot_io">"კერძო სერვერი Element-ის თანამშრომლებისთვის."</string>

View file

@ -22,6 +22,11 @@
<string name="screen_login_subtitle">"Matrix yra atviras tinklas, skirtas saugiam, decentralizuotam bendravimui."</string> <string name="screen_login_subtitle">"Matrix yra atviras tinklas, skirtas saugiam, decentralizuotam bendravimui."</string>
<string name="screen_login_title">"Sveiki sugrįžę!"</string> <string name="screen_login_title">"Sveiki sugrįžę!"</string>
<string name="screen_login_title_with_homeserver">"Prisijungti prie %1$s"</string> <string name="screen_login_title_with_homeserver">"Prisijungti prie %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Prisijunkite rankiniu būdu"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Prisijunkite naudodami QR kodą"</string>
<string name="screen_onboarding_sign_up">"Sukurti paskyrą"</string>
<string name="screen_onboarding_welcome_subtitle">"Sveiki atvykę į %1$s. Įkrautas greitumui ir paprastumui."</string>
<string name="screen_onboarding_welcome_title">"Būkite savo elemente"</string>
<string name="screen_server_confirmation_change_server">"Keisti paskyros teikėją"</string> <string name="screen_server_confirmation_change_server">"Keisti paskyros teikėją"</string>
<string name="screen_server_confirmation_message_login_element_dot_io">"Privatus serveris “Element” darbuotojams."</string> <string name="screen_server_confirmation_message_login_element_dot_io">"Privatus serveris “Element” darbuotojams."</string>
<string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix yra atviras tinklas, skirtas saugiam, decentralizuotam bendravimui."</string> <string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix yra atviras tinklas, skirtas saugiam, decentralizuotam bendravimui."</string>

View file

@ -17,6 +17,9 @@
<string name="screen_change_server_error_invalid_well_known">"Serveren er ikke tilgjengelig på grunn av et problem i den velkjente filen: <string name="screen_change_server_error_invalid_well_known">"Serveren er ikke tilgjengelig på grunn av et problem i den velkjente filen:
%1$s"</string> %1$s"</string>
<string name="screen_change_server_error_no_sliding_sync_message">"Den valgte kontoleverandøren støtter ikke sliding sync. En oppgradering av serveren er nødvendig for å bruke %1$s."</string> <string name="screen_change_server_error_no_sliding_sync_message">"Den valgte kontoleverandøren støtter ikke sliding sync. En oppgradering av serveren er nødvendig for å bruke %1$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver">"%1$s har ikke lov til å koble seg til %2$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver_content">"Denne appen er konfigurert til å tillate: %1$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver_title">"Kontoleverandør %1$s er ikke tillatt."</string>
<string name="screen_change_server_form_header">"URL til hjemmeserver"</string> <string name="screen_change_server_form_header">"URL til hjemmeserver"</string>
<string name="screen_change_server_form_notice">"Skriv inn en domeneadresse."</string> <string name="screen_change_server_form_notice">"Skriv inn en domeneadresse."</string>
<string name="screen_change_server_subtitle">"Hva er adressen til serveren din?"</string> <string name="screen_change_server_subtitle">"Hva er adressen til serveren din?"</string>
@ -31,6 +34,13 @@
<string name="screen_login_subtitle">"Matrix er et åpent nettverk for sikker, desentralisert kommunikasjon."</string> <string name="screen_login_subtitle">"Matrix er et åpent nettverk for sikker, desentralisert kommunikasjon."</string>
<string name="screen_login_title">"Velkommen tilbake!"</string> <string name="screen_login_title">"Velkommen tilbake!"</string>
<string name="screen_login_title_with_homeserver">"Logg inn på %1$s"</string> <string name="screen_login_title_with_homeserver">"Logg inn på %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Logg på manuelt"</string>
<string name="screen_onboarding_sign_in_to">"Logg inn på %1$s"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Logg inn med QR-kode"</string>
<string name="screen_onboarding_sign_up">"Opprett konto"</string>
<string name="screen_onboarding_welcome_message">"Velkommen til den raskeste %1$s noensinne. Superladet for hastighet og enkelhet."</string>
<string name="screen_onboarding_welcome_subtitle">"Velkommen til %1$s. Supercharged, for hastighet og enkelhet."</string>
<string name="screen_onboarding_welcome_title">"Vær i ditt rette element"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Etablere en sikker forbindelse"</string> <string name="screen_qr_code_login_connecting_subtitle">"Etablere en sikker forbindelse"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"En sikker tilkobling kunne ikke opprettes til den nye enheten. Dine eksisterende enheter er fortsatt trygge, og du trenger ikke å bekymre deg for dem."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"En sikker tilkobling kunne ikke opprettes til den nye enheten. Dine eksisterende enheter er fortsatt trygge, og du trenger ikke å bekymre deg for dem."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Hva nå?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Hva nå?"</string>

View file

@ -29,6 +29,12 @@
<string name="screen_login_subtitle">"Matrix is een open netwerk voor veilige, gedecentraliseerde communicatie."</string> <string name="screen_login_subtitle">"Matrix is een open netwerk voor veilige, gedecentraliseerde communicatie."</string>
<string name="screen_login_title">"Welkom terug!"</string> <string name="screen_login_title">"Welkom terug!"</string>
<string name="screen_login_title_with_homeserver">"Inloggen bij %1$s"</string> <string name="screen_login_title_with_homeserver">"Inloggen bij %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Handmatig inloggen"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Inloggen met QR-code"</string>
<string name="screen_onboarding_sign_up">"Account aanmaken"</string>
<string name="screen_onboarding_welcome_message">"Welkom bij de snelste %1$s ooit. Supercharged, voor snelheid en eenvoud."</string>
<string name="screen_onboarding_welcome_subtitle">"Welkom bij %1$s. Supercharged, voor snelheid en eenvoud."</string>
<string name="screen_onboarding_welcome_title">"Wees in je element"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Een beveiligde verbinding tot stand brengen"</string> <string name="screen_qr_code_login_connecting_subtitle">"Een beveiligde verbinding tot stand brengen"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Er kon geen beveiligde verbinding worden gemaakt met het nieuwe apparaat. Je bestaande apparaten zijn nog steeds veilig en je hoeft je daarover geen zorgen te maken."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Er kon geen beveiligde verbinding worden gemaakt met het nieuwe apparaat. Je bestaande apparaten zijn nog steeds veilig en je hoeft je daarover geen zorgen te maken."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Wat nu?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Wat nu?"</string>

View file

@ -32,6 +32,13 @@
<string name="screen_login_subtitle">"Matrix to otwarta sieć do bezpiecznej i zdecentralizowanej komunikacji."</string> <string name="screen_login_subtitle">"Matrix to otwarta sieć do bezpiecznej i zdecentralizowanej komunikacji."</string>
<string name="screen_login_title">"Witaj ponownie!"</string> <string name="screen_login_title">"Witaj ponownie!"</string>
<string name="screen_login_title_with_homeserver">"Zaloguj się do %1$s"</string> <string name="screen_login_title_with_homeserver">"Zaloguj się do %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Zaloguj się ręcznie"</string>
<string name="screen_onboarding_sign_in_to">"Zaloguj się do %1$s"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Zaloguj się za pomocą kodu QR"</string>
<string name="screen_onboarding_sign_up">"Utwórz konto"</string>
<string name="screen_onboarding_welcome_message">"Witamy w %1$s. Szybszy i prostszy niż kiedykolwiek."</string>
<string name="screen_onboarding_welcome_subtitle">"Witamy w %1$s. Doładowany, dla szybkości i prostoty."</string>
<string name="screen_onboarding_welcome_title">"Be in your element"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Nawiązanie bezpiecznego połączenia"</string> <string name="screen_qr_code_login_connecting_subtitle">"Nawiązanie bezpiecznego połączenia"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Nie udało się nawiązać bezpiecznego połączenia z nowym urządzeniem. Twoje istniejące urządzenia są nadal bezpieczne i nie musisz się o nie martwić."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Nie udało się nawiązać bezpiecznego połączenia z nowym urządzeniem. Twoje istniejące urządzenia są nadal bezpieczne i nie musisz się o nie martwić."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Co teraz?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Co teraz?"</string>

View file

@ -27,6 +27,12 @@
<string name="screen_login_subtitle">"A Matrix é uma rede aberta para comunicação segura e descentralizada."</string> <string name="screen_login_subtitle">"A Matrix é uma rede aberta para comunicação segura e descentralizada."</string>
<string name="screen_login_title">"Bem-vindo de volta!"</string> <string name="screen_login_title">"Bem-vindo de volta!"</string>
<string name="screen_login_title_with_homeserver">"Iniciar sessão em %1$s"</string> <string name="screen_login_title_with_homeserver">"Iniciar sessão em %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Iniciar sessão manualmente"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Iniciar sessão com código QR"</string>
<string name="screen_onboarding_sign_up">"Criar conta"</string>
<string name="screen_onboarding_welcome_message">"Bem-vindo ao mais rápido %1$s de todos os tempos. Turbinado para velocidade e simplicidade."</string>
<string name="screen_onboarding_welcome_subtitle">"Bem-vindo ao %1$s. Turbinado, para velocidade e simplicidade"</string>
<string name="screen_onboarding_welcome_title">"Esteja no seu elemento"</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Tente novamente"</string> <string name="screen_qr_code_login_invalid_scan_state_retry_button">"Tente novamente"</string>
<string name="screen_qr_code_login_no_camera_permission_state_description">"Você deve permitir ao %1$s usar a câmera do seu dispositivo para continuar."</string> <string name="screen_qr_code_login_no_camera_permission_state_description">"Você deve permitir ao %1$s usar a câmera do seu dispositivo para continuar."</string>
<string name="screen_qr_code_login_verify_code_title">"Seu código de verificação"</string> <string name="screen_qr_code_login_verify_code_title">"Seu código de verificação"</string>

View file

@ -29,6 +29,12 @@
<string name="screen_login_subtitle">"A Matrix é uma rede aberta de comunicação descentralizada e segura."</string> <string name="screen_login_subtitle">"A Matrix é uma rede aberta de comunicação descentralizada e segura."</string>
<string name="screen_login_title">"Bem-vindo(a) de volta!"</string> <string name="screen_login_title">"Bem-vindo(a) de volta!"</string>
<string name="screen_login_title_with_homeserver">"Iniciar sessão em %1$s"</string> <string name="screen_login_title_with_homeserver">"Iniciar sessão em %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Iniciar sessão manualmente"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Iniciar sessão com código QR"</string>
<string name="screen_onboarding_sign_up">"Criar conta"</string>
<string name="screen_onboarding_welcome_message">"Bem-vindo(a) à %1$s mais rápida de sempre. Super rápida e simples."</string>
<string name="screen_onboarding_welcome_subtitle">"Bem-vindo(a) à %1$s. Revitalizado, rápido e simples."</string>
<string name="screen_onboarding_welcome_title">"A liberdade do teu elemento"</string>
<string name="screen_qr_code_login_connecting_subtitle">"A estabelecer uma ligação segura"</string> <string name="screen_qr_code_login_connecting_subtitle">"A estabelecer uma ligação segura"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Não foi possível estabelecer uma ligação segura com o novo dispositivo. Os teus outros dispositivos continuam seguros, não precisas de te preocupar com eles."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Não foi possível estabelecer uma ligação segura com o novo dispositivo. Os teus outros dispositivos continuam seguros, não precisas de te preocupar com eles."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"E agora?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"E agora?"</string>

View file

@ -29,6 +29,12 @@
<string name="screen_login_subtitle">"Matrix este o rețea deschisă pentru o comunicare sigură și descentralizată."</string> <string name="screen_login_subtitle">"Matrix este o rețea deschisă pentru o comunicare sigură și descentralizată."</string>
<string name="screen_login_title">"Bine ați revenit!"</string> <string name="screen_login_title">"Bine ați revenit!"</string>
<string name="screen_login_title_with_homeserver">"Conectați-vă la %1$s"</string> <string name="screen_login_title_with_homeserver">"Conectați-vă la %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Conectați-vă manual"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Conectați-vă cu un cod QR"</string>
<string name="screen_onboarding_sign_up">"Creați un cont"</string>
<string name="screen_onboarding_welcome_message">"Bine ați venit la cel mai rapid %1$s din toate timpurile. Supraalimentat pentru viteză și simplitate."</string>
<string name="screen_onboarding_welcome_subtitle">"Bun venit în %1$s. Supraalimentat, pentru viteză și simplitate."</string>
<string name="screen_onboarding_welcome_title">"Fii în Elementul tău"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Se stabilește o conexiune securizată"</string> <string name="screen_qr_code_login_connecting_subtitle">"Se stabilește o conexiune securizată"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Nu a putut fi făcută o conexiune sigură la noul dispozitiv. Dispozitivele existente sunt încă în siguranță și nu trebuie să vă faceți griji cu privire la ele."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Nu a putut fi făcută o conexiune sigură la noul dispozitiv. Dispozitivele existente sunt încă în siguranță și nu trebuie să vă faceți griji cu privire la ele."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Și acum?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Și acum?"</string>

View file

@ -30,6 +30,12 @@
<string name="screen_login_subtitle">"Matrix — это открытая сеть для безопасной децентрализованной связи."</string> <string name="screen_login_subtitle">"Matrix — это открытая сеть для безопасной децентрализованной связи."</string>
<string name="screen_login_title">"Рады видеть вас снова!"</string> <string name="screen_login_title">"Рады видеть вас снова!"</string>
<string name="screen_login_title_with_homeserver">"Войти в %1$s"</string> <string name="screen_login_title_with_homeserver">"Войти в %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Войти вручную"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Войти QR-кодом"</string>
<string name="screen_onboarding_sign_up">"Создать учетную запись"</string>
<string name="screen_onboarding_welcome_message">"Добро пожаловать в самый быстрый клиент %1$s. Ориентирован на скорость и простоту."</string>
<string name="screen_onboarding_welcome_subtitle">"Добро пожаловать в %1$s. Ориентирован на скорость и простоту."</string>
<string name="screen_onboarding_welcome_title">"Чувствуйте себя как дома с Element"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Установление безопасного соединения"</string> <string name="screen_qr_code_login_connecting_subtitle">"Установление безопасного соединения"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Не удалось установить безопасное соединение с новым устройством. Существующие устройства по-прежнему в безопасности, и вам не нужно беспокоиться о них."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Не удалось установить безопасное соединение с новым устройством. Существующие устройства по-прежнему в безопасности, и вам не нужно беспокоиться о них."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Что теперь?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Что теперь?"</string>

View file

@ -18,6 +18,8 @@
%1$s"</string> %1$s"</string>
<string name="screen_change_server_error_no_sliding_sync_message">"Vybraný poskytovateľ účtu nepodporuje kĺzavú synchronizáciu. Na používanie aplikácie %1$s je potrebná aktualizácia servera,"</string> <string name="screen_change_server_error_no_sliding_sync_message">"Vybraný poskytovateľ účtu nepodporuje kĺzavú synchronizáciu. Na používanie aplikácie %1$s je potrebná aktualizácia servera,"</string>
<string name="screen_change_server_error_unauthorized_homeserver">"%1$s nemá dovolené pripojiť sa k %2$s."</string> <string name="screen_change_server_error_unauthorized_homeserver">"%1$s nemá dovolené pripojiť sa k %2$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver_content">"Táto aplikácia bola nastavená tak, aby povoľovala: %1$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver_title">"Poskytovateľ účtu %1$s nie je povolený."</string>
<string name="screen_change_server_form_header">"Adresa URL domovského servera"</string> <string name="screen_change_server_form_header">"Adresa URL domovského servera"</string>
<string name="screen_change_server_form_notice">"Zadajte adresu domény."</string> <string name="screen_change_server_form_notice">"Zadajte adresu domény."</string>
<string name="screen_change_server_subtitle">"Aká je adresa vášho servera?"</string> <string name="screen_change_server_subtitle">"Aká je adresa vášho servera?"</string>
@ -32,6 +34,13 @@
<string name="screen_login_subtitle">"Matrix je otvorená sieť pre bezpečnú a decentralizovanú komunikáciu."</string> <string name="screen_login_subtitle">"Matrix je otvorená sieť pre bezpečnú a decentralizovanú komunikáciu."</string>
<string name="screen_login_title">"Vitajte späť!"</string> <string name="screen_login_title">"Vitajte späť!"</string>
<string name="screen_login_title_with_homeserver">"Prihlásiť sa do %1$s"</string> <string name="screen_login_title_with_homeserver">"Prihlásiť sa do %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Prihlásiť sa manuálne"</string>
<string name="screen_onboarding_sign_in_to">"Prihlásiť sa do %1$s"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Prihlásiť sa pomocou QR kódu"</string>
<string name="screen_onboarding_sign_up">"Vytvoriť účet"</string>
<string name="screen_onboarding_welcome_message">"Vitajte v najrýchlejšom %1$s vôbec. Nadupaný pre rýchlosť a jednoduchosť."</string>
<string name="screen_onboarding_welcome_subtitle">"Vitajte v %1$s. Nadupaný, pre rýchlosť a jednoduchosť."</string>
<string name="screen_onboarding_welcome_title">"Buďte vo svojom elemente"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Nadväzovanie bezpečného spojenia"</string> <string name="screen_qr_code_login_connecting_subtitle">"Nadväzovanie bezpečného spojenia"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"K novému zariadeniu sa nepodarilo vytvoriť bezpečné pripojenie. Vaše existujúce zariadenia sú stále v bezpečí a nemusíte sa o ne obávať."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"K novému zariadeniu sa nepodarilo vytvoriť bezpečné pripojenie. Vaše existujúce zariadenia sú stále v bezpečí a nemusíte sa o ne obávať."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Čo teraz?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Čo teraz?"</string>

View file

@ -29,6 +29,12 @@
<string name="screen_login_subtitle">"Matrix är ett öppet nätverk för säker, decentraliserad kommunikation."</string> <string name="screen_login_subtitle">"Matrix är ett öppet nätverk för säker, decentraliserad kommunikation."</string>
<string name="screen_login_title">"Välkommen tillbaka!"</string> <string name="screen_login_title">"Välkommen tillbaka!"</string>
<string name="screen_login_title_with_homeserver">"Logga in på %1$s"</string> <string name="screen_login_title_with_homeserver">"Logga in på %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Logga in manuellt"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Logga in med QR-kod"</string>
<string name="screen_onboarding_sign_up">"Skapa konto"</string>
<string name="screen_onboarding_welcome_message">"Välkommen till den snabbaste %1$s någonsin. Superladdad för snabbhet och enkelhet."</string>
<string name="screen_onboarding_welcome_subtitle">"Välkommen till %1$s. Superladdad, för snabbhet och enkelhet."</string>
<string name="screen_onboarding_welcome_title">"Var i ditt rätta element"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Upprättar en säker anslutning"</string> <string name="screen_qr_code_login_connecting_subtitle">"Upprättar en säker anslutning"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"En säker anslutning kunde inte göras till den nya enheten. Dina befintliga enheter är fortfarande säkra och du behöver inte oroa dig för dem."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"En säker anslutning kunde inte göras till den nya enheten. Dina befintliga enheter är fortfarande säkra och du behöver inte oroa dig för dem."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Nu då?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Nu då?"</string>

View file

@ -29,6 +29,12 @@
<string name="screen_login_subtitle">"Matrix, güvenli, merkezi olmayan iletişim için açık bir ağdır."</string> <string name="screen_login_subtitle">"Matrix, güvenli, merkezi olmayan iletişim için açık bir ağdır."</string>
<string name="screen_login_title">"Tekrar hoş geldiniz!"</string> <string name="screen_login_title">"Tekrar hoş geldiniz!"</string>
<string name="screen_login_title_with_homeserver">"%1$s adresinde oturum aç"</string> <string name="screen_login_title_with_homeserver">"%1$s adresinde oturum aç"</string>
<string name="screen_onboarding_sign_in_manually">"Manuel olarak oturum aç"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"QR kodu ile giriş yap"</string>
<string name="screen_onboarding_sign_up">"Hesap oluştur"</string>
<string name="screen_onboarding_welcome_message">"Şimdiye kadarki en hızlı %1$s hoş geldiniz. Hız ve basitlik için güçlendirildi."</string>
<string name="screen_onboarding_welcome_subtitle">"%1$s\'e hoş geldiniz. Hız ve basitlik için süper şarjlı."</string>
<string name="screen_onboarding_welcome_title">"Kendi elementinizde olun"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Güvenli bir bağlantı kuruluyor"</string> <string name="screen_qr_code_login_connecting_subtitle">"Güvenli bir bağlantı kuruluyor"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Yeni cihaza güvenli bir bağlantı kurulamadı. Mevcut cihazlarınız hala güvende ve onlar için endişelenmenize gerek yok."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Yeni cihaza güvenli bir bağlantı kurulamadı. Mevcut cihazlarınız hala güvende ve onlar için endişelenmenize gerek yok."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Şimdi ne olacak?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Şimdi ne olacak?"</string>

View file

@ -14,9 +14,10 @@
<string name="screen_change_account_provider_subtitle">"Використати іншого провайдера облікових записів, наприклад, власний приватний сервер або робочий обліковий запис."</string> <string name="screen_change_account_provider_subtitle">"Використати іншого провайдера облікових записів, наприклад, власний приватний сервер або робочий обліковий запис."</string>
<string name="screen_change_account_provider_title">"Змінити провайдера облікового запису"</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_invalid_homeserver">"Не вдалося під\'єднатися до цього домашнього сервера. Перевірте правильність введеної URL-адреси домашнього сервера. Якщо URL-адреса правильна, зверніться по додаткову допомогу до адміністратора домашнього сервера."</string>
<string name="screen_change_server_error_invalid_well_known">"Sliding sync недоступний через проблему у файлі well-known: <string name="screen_change_server_error_invalid_well_known">"Сервер недоступний через помилку у файлі well-known:
%1$s"</string> %1$s"</string>
<string name="screen_change_server_form_header">"URL-адреса домашнього сервера"</string> <string name="screen_change_server_form_header">"URL-адреса домашнього сервера"</string>
<string name="screen_change_server_form_notice">"Введіть адресу домену."</string>
<string name="screen_change_server_subtitle">"Яка адреса вашого сервера?"</string> <string name="screen_change_server_subtitle">"Яка адреса вашого сервера?"</string>
<string name="screen_change_server_title">"Виберіть свій сервер"</string> <string name="screen_change_server_title">"Виберіть свій сервер"</string>
<string name="screen_create_account_title">"Створити обліковий запис"</string> <string name="screen_create_account_title">"Створити обліковий запис"</string>
@ -29,6 +30,13 @@
<string name="screen_login_subtitle">"Matrix — це відкрита мережа для безпечної, децентралізованої комунікації."</string> <string name="screen_login_subtitle">"Matrix — це відкрита мережа для безпечної, децентралізованої комунікації."</string>
<string name="screen_login_title">"З поверненням!"</string> <string name="screen_login_title">"З поверненням!"</string>
<string name="screen_login_title_with_homeserver">"Увійти в %1$s"</string> <string name="screen_login_title_with_homeserver">"Увійти в %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Увійти вручну"</string>
<string name="screen_onboarding_sign_in_to">"Увійти в %1$s"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Увійти за допомогою QR-коду"</string>
<string name="screen_onboarding_sign_up">"Створити обліковий запис"</string>
<string name="screen_onboarding_welcome_message">"Ласкаво просимо до найшвидшого %1$s. Заряджений для швидкості та простоти."</string>
<string name="screen_onboarding_welcome_subtitle">"Ласкаво просимо до %1$s. Заряджений, для швидкості та простоти."</string>
<string name="screen_onboarding_welcome_title">"Будьте у своєму element"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Встановлення безпечного з\'єднання"</string> <string name="screen_qr_code_login_connecting_subtitle">"Встановлення безпечного з\'єднання"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Не вдалося встановити безпечне з\'єднання з новим пристроєм. Ваші наявні пристрої досі в безпеці, і вам не потрібно про них турбуватися."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"Не вдалося встановити безпечне з\'єднання з новим пристроєм. Ваші наявні пристрої досі в безпеці, і вам не потрібно про них турбуватися."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Що тепер?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"Що тепер?"</string>

View file

@ -26,6 +26,12 @@
<string name="screen_login_subtitle">"Matrix xavfsiz, markazlashmagan aloqa uchun ochiq tarmoqdir."</string> <string name="screen_login_subtitle">"Matrix xavfsiz, markazlashmagan aloqa uchun ochiq tarmoqdir."</string>
<string name="screen_login_title">"Qaytib kelganingizdan xursandmiz!"</string> <string name="screen_login_title">"Qaytib kelganingizdan xursandmiz!"</string>
<string name="screen_login_title_with_homeserver">"Kirish%1$s"</string> <string name="screen_login_title_with_homeserver">"Kirish%1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Qo\'lda tizimga kiring"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"QR kod bilan tizimga kiring"</string>
<string name="screen_onboarding_sign_up">"Hisob yaratish"</string>
<string name="screen_onboarding_welcome_message">"Eng tezkor %1$sga xush kelibsiz. Tezlik va oddylik uchun super zaryadlangan."</string>
<string name="screen_onboarding_welcome_subtitle">"%1$sga Xush kelibsiz. Tezlik va oddylik uchun o\'ta zaryadlangan."</string>
<string name="screen_onboarding_welcome_title">"Elementingizda bo\'ling"</string>
<string name="screen_server_confirmation_change_server">"Hisob provayderini o\'zgartiring"</string> <string name="screen_server_confirmation_change_server">"Hisob provayderini o\'zgartiring"</string>
<string name="screen_server_confirmation_message_login_element_dot_io">"Element xodimlari uchun shaxsiy server."</string> <string name="screen_server_confirmation_message_login_element_dot_io">"Element xodimlari uchun shaxsiy server."</string>
<string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix xavfsiz, markazlashmagan aloqa uchun ochiq tarmoqdir."</string> <string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix xavfsiz, markazlashmagan aloqa uchun ochiq tarmoqdir."</string>

View file

@ -29,6 +29,12 @@
<string name="screen_login_subtitle">"Matrix 是一個開放網路,為了安全且去中心化的通訊而生。"</string> <string name="screen_login_subtitle">"Matrix 是一個開放網路,為了安全且去中心化的通訊而生。"</string>
<string name="screen_login_title">"歡迎回來!"</string> <string name="screen_login_title">"歡迎回來!"</string>
<string name="screen_login_title_with_homeserver">"登入 %1$s"</string> <string name="screen_login_title_with_homeserver">"登入 %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"手動登入"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"使用 QR code 登入"</string>
<string name="screen_onboarding_sign_up">"建立帳號"</string>
<string name="screen_onboarding_welcome_message">"歡迎使用有史以來最快的 %1$s。速度超快操作簡便。"</string>
<string name="screen_onboarding_welcome_subtitle">"歡迎使用 %1$s。速度超快且簡單。"</string>
<string name="screen_onboarding_welcome_title">"Be in your element"</string>
<string name="screen_qr_code_login_connecting_subtitle">"建立安全連線"</string> <string name="screen_qr_code_login_connecting_subtitle">"建立安全連線"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"無法與新裝置建立安全連線。您現有的裝置仍然安全,您不必擔心它們。"</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"無法與新裝置建立安全連線。您現有的裝置仍然安全,您不必擔心它們。"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"現在怎麼辦?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"現在怎麼辦?"</string>

View file

@ -29,6 +29,12 @@
<string name="screen_login_subtitle">"Matrix 是一个用于安全、去中心化通信的开放网络。"</string> <string name="screen_login_subtitle">"Matrix 是一个用于安全、去中心化通信的开放网络。"</string>
<string name="screen_login_title">"欢迎回来!"</string> <string name="screen_login_title">"欢迎回来!"</string>
<string name="screen_login_title_with_homeserver">"登录到 %1$s"</string> <string name="screen_login_title_with_homeserver">"登录到 %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"手动登录"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"使用二维码登录"</string>
<string name="screen_onboarding_sign_up">"创建账户"</string>
<string name="screen_onboarding_welcome_message">"欢迎使用 %1$s快而简约的消息应用。"</string>
<string name="screen_onboarding_welcome_subtitle">"欢迎使用 %1$s速度与简洁的极致。"</string>
<string name="screen_onboarding_welcome_title">"融入您的 Element"</string>
<string name="screen_qr_code_login_connecting_subtitle">"建立安全连接"</string> <string name="screen_qr_code_login_connecting_subtitle">"建立安全连接"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"无法与新设备建立安全连接。您现有的设备仍然安全,无需担心。"</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"无法与新设备建立安全连接。您现有的设备仍然安全,无需担心。"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"现在怎么办?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"现在怎么办?"</string>

View file

@ -18,6 +18,8 @@
%1$s"</string> %1$s"</string>
<string name="screen_change_server_error_no_sliding_sync_message">"The selected account provider does not support sliding sync. An upgrade to the server is needed to use %1$s."</string> <string name="screen_change_server_error_no_sliding_sync_message">"The selected account provider does not support sliding sync. An upgrade to the server is needed to use %1$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver">"%1$s is not allowed to connect to %2$s."</string> <string name="screen_change_server_error_unauthorized_homeserver">"%1$s is not allowed to connect to %2$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver_content">"This app has been configured to allow: %1$s."</string>
<string name="screen_change_server_error_unauthorized_homeserver_title">"Account provider %1$s not allowed."</string>
<string name="screen_change_server_form_header">"Homeserver URL"</string> <string name="screen_change_server_form_header">"Homeserver URL"</string>
<string name="screen_change_server_form_notice">"Enter a domain address."</string> <string name="screen_change_server_form_notice">"Enter a domain address."</string>
<string name="screen_change_server_subtitle">"What is the address of your server?"</string> <string name="screen_change_server_subtitle">"What is the address of your server?"</string>
@ -32,6 +34,13 @@
<string name="screen_login_subtitle">"Matrix is an open network for secure, decentralised communication."</string> <string name="screen_login_subtitle">"Matrix is an open network for secure, decentralised communication."</string>
<string name="screen_login_title">"Welcome back!"</string> <string name="screen_login_title">"Welcome back!"</string>
<string name="screen_login_title_with_homeserver">"Sign in to %1$s"</string> <string name="screen_login_title_with_homeserver">"Sign in to %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Sign in manually"</string>
<string name="screen_onboarding_sign_in_to">"Sign in to %1$s"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Sign in with QR code"</string>
<string name="screen_onboarding_sign_up">"Create account"</string>
<string name="screen_onboarding_welcome_message">"Welcome to the fastest %1$s ever. Supercharged for speed and simplicity."</string>
<string name="screen_onboarding_welcome_subtitle">"Welcome to %1$s. Supercharged, for speed and simplicity."</string>
<string name="screen_onboarding_welcome_title">"Be in your element"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Establishing a secure connection"</string> <string name="screen_qr_code_login_connecting_subtitle">"Establishing a secure connection"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"A secure connection could not be made to the new device. Your existing devices are still safe and you don\'t need to worry about them."</string> <string name="screen_qr_code_login_connection_note_secure_state_description">"A secure connection could not be made to the new device. Your existing devices are still safe and you don\'t need to worry about them."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"What now?"</string> <string name="screen_qr_code_login_connection_note_secure_state_list_header">"What now?"</string>

View file

@ -27,11 +27,11 @@ class AccountProviderDataSourceTest {
val initialState = awaitItem() val initialState = awaitItem()
assertThat(initialState).isEqualTo( assertThat(initialState).isEqualTo(
AccountProvider( AccountProvider(
url = FakeEnterpriseService.A_FAKE_HOMESERVER, url = AuthenticationConfig.MATRIX_ORG_URL,
title = FakeEnterpriseService.A_FAKE_HOMESERVER, title = "matrix.org",
subtitle = null, subtitle = null,
isPublic = false, isPublic = true,
isMatrixOrg = false, isMatrixOrg = true,
isValid = false, isValid = false,
) )
) )
@ -40,9 +40,11 @@ class AccountProviderDataSourceTest {
@Test @Test
fun `present - initial state - matrix org`() = runTest { fun `present - initial state - matrix org`() = runTest {
val sut = AccountProviderDataSource(FakeEnterpriseService( val sut = AccountProviderDataSource(
defaultHomeserverResult = { AuthenticationConfig.MATRIX_ORG_URL } FakeEnterpriseService(
)) defaultHomeserverListResult = { listOf(AuthenticationConfig.MATRIX_ORG_URL) }
)
)
sut.flow.test { sut.flow.test {
val initialState = awaitItem() val initialState = awaitItem()
assertThat(initialState).isEqualTo( assertThat(initialState).isEqualTo(
@ -63,7 +65,7 @@ class AccountProviderDataSourceTest {
val sut = AccountProviderDataSource(FakeEnterpriseService()) val sut = AccountProviderDataSource(FakeEnterpriseService())
sut.flow.test { sut.flow.test {
val initialState = awaitItem() val initialState = awaitItem()
assertThat(initialState.url).isEqualTo(FakeEnterpriseService.A_FAKE_HOMESERVER) assertThat(initialState.url).isEqualTo(AuthenticationConfig.MATRIX_ORG_URL)
sut.userSelection(AccountProvider(url = "https://example.com")) sut.userSelection(AccountProvider(url = "https://example.com"))
val changedState = awaitItem() val changedState = awaitItem()
assertThat(changedState).isEqualTo( assertThat(changedState).isEqualTo(
@ -78,7 +80,7 @@ class AccountProviderDataSourceTest {
) )
sut.reset() sut.reset()
val resetState = awaitItem() val resetState = awaitItem()
assertThat(resetState.url).isEqualTo(FakeEnterpriseService.A_FAKE_HOMESERVER) assertThat(resetState.url).isEqualTo(AuthenticationConfig.MATRIX_ORG_URL)
} }
} }
} }

View file

@ -84,6 +84,7 @@ class ChangeServerPresenterTest {
createPresenter( createPresenter(
enterpriseService = FakeEnterpriseService( enterpriseService = FakeEnterpriseService(
isAllowedToConnectToHomeserverResult = isAllowedToConnectToHomeserverResult, isAllowedToConnectToHomeserverResult = isAllowedToConnectToHomeserverResult,
defaultHomeserverListResult = { listOf("element.io") },
), ),
).test { ).test {
val initialState = awaitItem() val initialState = awaitItem()
@ -94,8 +95,11 @@ class ChangeServerPresenterTest {
assertThat(loadingState.changeServerAction).isInstanceOf(AsyncData.Loading::class.java) assertThat(loadingState.changeServerAction).isInstanceOf(AsyncData.Loading::class.java)
val failureState = awaitItem() val failureState = awaitItem()
assertThat( assertThat(
(failureState.changeServerAction.errorOrNull() as ChangeServerError.UnauthorizedAccountProvider).accountProvider (failureState.changeServerAction.errorOrNull() as ChangeServerError.UnauthorizedAccountProvider).unauthorisedAccountProviderTitle
).isEqualTo(anAccountProvider) ).isEqualTo(anAccountProvider.title)
assertThat(
(failureState.changeServerAction.errorOrNull() as ChangeServerError.UnauthorizedAccountProvider).authorisedAccountProviderTitles
).containsExactly("element.io")
isAllowedToConnectToHomeserverResult.assertions() isAllowedToConnectToHomeserverResult.assertions()
.isCalledOnce() .isCalledOnce()
.with(value(A_HOMESERVER_URL)) .with(value(A_HOMESERVER_URL))

View file

@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
package io.element.android.features.onboarding.impl package io.element.android.features.login.impl.onboarding
import app.cash.molecule.RecompositionMode import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow import app.cash.molecule.moleculeFlow

View file

@ -5,13 +5,14 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
package io.element.android.features.onboarding.impl package io.element.android.features.login.impl.onboarding
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.AndroidComposeTestRule import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.onNodeWithText
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import io.element.android.features.login.impl.R
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EnsureNeverCalled
import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.clickOn

View file

@ -11,6 +11,7 @@ import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow import app.cash.molecule.moleculeFlow
import app.cash.turbine.test import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import io.element.android.features.enterprise.test.FakeEnterpriseService
import io.element.android.features.login.impl.accountprovider.AccountProvider import io.element.android.features.login.impl.accountprovider.AccountProvider
import io.element.android.features.login.impl.changeserver.aChangeServerState import io.element.android.features.login.impl.changeserver.aChangeServerState
import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.WarmUpRule
@ -25,7 +26,8 @@ class ChangeAccountProviderPresenterTest {
@Test @Test
fun `present - initial state`() = runTest { fun `present - initial state`() = runTest {
val presenter = ChangeAccountProviderPresenter( val presenter = ChangeAccountProviderPresenter(
changeServerPresenter = { aChangeServerState() } changeServerPresenter = { aChangeServerState() },
enterpriseService = FakeEnterpriseService(),
) )
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()

View file

@ -11,6 +11,7 @@ import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow import app.cash.molecule.moleculeFlow
import app.cash.turbine.test import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import io.element.android.appconfig.AuthenticationConfig
import io.element.android.features.enterprise.test.FakeEnterpriseService import io.element.android.features.enterprise.test.FakeEnterpriseService
import io.element.android.features.login.impl.DefaultLoginUserStory import io.element.android.features.login.impl.DefaultLoginUserStory
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
@ -44,7 +45,7 @@ class ConfirmAccountProviderPresenterTest {
val initialState = awaitItem() val initialState = awaitItem()
assertThat(initialState.isAccountCreation).isFalse() assertThat(initialState.isAccountCreation).isFalse()
assertThat(initialState.submitEnabled).isTrue() assertThat(initialState.submitEnabled).isTrue()
assertThat(initialState.accountProvider.url).isEqualTo(FakeEnterpriseService.A_FAKE_HOMESERVER) assertThat(initialState.accountProvider.url).isEqualTo(AuthenticationConfig.MATRIX_ORG_URL)
assertThat(initialState.loginFlow).isEqualTo(AsyncData.Uninitialized) assertThat(initialState.loginFlow).isEqualTo(AsyncData.Uninitialized)
} }
} }

View file

@ -8,6 +8,7 @@
package io.element.android.features.login.impl.screens.createaccount package io.element.android.features.login.impl.screens.createaccount
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import io.element.android.appconfig.AuthenticationConfig
import io.element.android.features.enterprise.test.FakeEnterpriseService import io.element.android.features.enterprise.test.FakeEnterpriseService
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
import io.element.android.libraries.matrix.api.auth.external.ExternalSession import io.element.android.libraries.matrix.api.auth.external.ExternalSession
@ -60,7 +61,7 @@ class DefaultMessageParserTest {
// missing homeServer // missing homeServer
assertThat(sut.parse(validMessage.replace(""""home_server": "home_server",""", ""))).isEqualTo( assertThat(sut.parse(validMessage.replace(""""home_server": "home_server",""", ""))).isEqualTo(
anExternalSession( anExternalSession(
homeserverUrl = FakeEnterpriseService.A_FAKE_HOMESERVER, homeserverUrl = AuthenticationConfig.MATRIX_ORG_URL,
) )
) )
} }

View file

@ -8,6 +8,7 @@
package io.element.android.features.login.impl.screens.loginpassword package io.element.android.features.login.impl.screens.loginpassword
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import io.element.android.appconfig.AuthenticationConfig
import io.element.android.features.enterprise.test.FakeEnterpriseService import io.element.android.features.enterprise.test.FakeEnterpriseService
import io.element.android.features.login.impl.DefaultLoginUserStory import io.element.android.features.login.impl.DefaultLoginUserStory
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
@ -33,7 +34,7 @@ class LoginPasswordPresenterTest {
fun `present - initial state`() = runTest { fun `present - initial state`() = runTest {
createLoginPasswordPresenter().test { createLoginPasswordPresenter().test {
val initialState = awaitItem() val initialState = awaitItem()
assertThat(initialState.accountProvider.url).isEqualTo(FakeEnterpriseService.A_FAKE_HOMESERVER) assertThat(initialState.accountProvider.url).isEqualTo(AuthenticationConfig.MATRIX_ORG_URL)
assertThat(initialState.formState).isEqualTo(LoginFormState.Default) assertThat(initialState.formState).isEqualTo(LoginFormState.Default)
assertThat(initialState.loginAction).isEqualTo(AsyncData.Uninitialized) assertThat(initialState.loginAction).isEqualTo(AsyncData.Uninitialized)
assertThat(initialState.submitEnabled).isFalse() assertThat(initialState.submitEnabled).isFalse()

View file

@ -11,12 +11,17 @@ import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow import app.cash.molecule.moleculeFlow
import app.cash.turbine.test import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.features.enterprise.test.FakeEnterpriseService
import io.element.android.features.login.impl.changeserver.UnauthorizedAccountProviderException
import io.element.android.features.login.impl.qrcode.FakeQrCodeLoginManager import io.element.android.features.login.impl.qrcode.FakeQrCodeLoginManager
import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.api.auth.qrlogin.QrCodeLoginStep import io.element.android.libraries.matrix.api.auth.qrlogin.QrCodeLoginStep
import io.element.android.libraries.matrix.api.auth.qrlogin.QrLoginException import io.element.android.libraries.matrix.api.auth.qrlogin.QrLoginException
import io.element.android.libraries.matrix.test.auth.qrlogin.FakeMatrixQrCodeLoginData
import io.element.android.libraries.matrix.test.auth.qrlogin.FakeMatrixQrCodeLoginDataFactory import io.element.android.libraries.matrix.test.auth.qrlogin.FakeMatrixQrCodeLoginDataFactory
import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.test
import io.element.android.tests.testutils.testCoroutineDispatchers import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -38,10 +43,22 @@ class QrCodeScanPresenterTest {
@Test @Test
fun `present - scanned QR code successfully`() = runTest { fun `present - scanned QR code successfully`() = runTest {
val presenter = createQrCodeScanPresenter() val qrCodeLoginDataFactory = FakeMatrixQrCodeLoginDataFactory(
moleculeFlow(RecompositionMode.Immediate) { parseQrCodeLoginDataResult = {
presenter.present() Result.success(
}.test { FakeMatrixQrCodeLoginData(
serverNameResult = { "example.com" }
)
)
}
)
val presenter = createQrCodeScanPresenter(
qrCodeLoginDataFactory = qrCodeLoginDataFactory,
enterpriseService = FakeEnterpriseService(
isAllowedToConnectToHomeserverResult = { true },
)
)
presenter.test {
val initialState = awaitItem() val initialState = awaitItem()
initialState.eventSink(QrCodeScanEvents.QrCodeScanned(byteArrayOf())) initialState.eventSink(QrCodeScanEvents.QrCodeScanned(byteArrayOf()))
assertThat(awaitItem().isScanning).isFalse() assertThat(awaitItem().isScanning).isFalse()
@ -50,6 +67,38 @@ class QrCodeScanPresenterTest {
} }
} }
@Test
fun `present - scanned QR code successfully, but homeserver not allowed`() = runTest {
val qrCodeLoginDataFactory = FakeMatrixQrCodeLoginDataFactory(
parseQrCodeLoginDataResult = {
Result.success(
FakeMatrixQrCodeLoginData(
serverNameResult = { "example.com" }
)
)
}
)
val presenter = createQrCodeScanPresenter(
qrCodeLoginDataFactory = qrCodeLoginDataFactory,
enterpriseService = FakeEnterpriseService(
isAllowedToConnectToHomeserverResult = { false },
defaultHomeserverListResult = { listOf("element.io") },
)
)
presenter.test {
val initialState = awaitItem()
initialState.eventSink(QrCodeScanEvents.QrCodeScanned(byteArrayOf()))
assertThat(awaitItem().isScanning).isFalse()
assertThat(awaitItem().authenticationAction.isLoading()).isTrue()
awaitItem().also { state ->
assertThat((state.authenticationAction.errorOrNull() as UnauthorizedAccountProviderException).unauthorisedAccountProviderTitle)
.isEqualTo("example.com")
assertThat((state.authenticationAction.errorOrNull() as UnauthorizedAccountProviderException).authorisedAccountProviderTitles)
.containsExactly("element.io")
}
}
}
@Test @Test
fun `present - scanned QR code failed and can be retried`() = runTest { fun `present - scanned QR code failed and can be retried`() = runTest {
val qrCodeLoginDataFactory = FakeMatrixQrCodeLoginDataFactory( val qrCodeLoginDataFactory = FakeMatrixQrCodeLoginDataFactory(
@ -103,9 +152,11 @@ class QrCodeScanPresenterTest {
qrCodeLoginDataFactory: FakeMatrixQrCodeLoginDataFactory = FakeMatrixQrCodeLoginDataFactory(), qrCodeLoginDataFactory: FakeMatrixQrCodeLoginDataFactory = FakeMatrixQrCodeLoginDataFactory(),
coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(), coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(),
qrCodeLoginManager: FakeQrCodeLoginManager = FakeQrCodeLoginManager(), qrCodeLoginManager: FakeQrCodeLoginManager = FakeQrCodeLoginManager(),
enterpriseService: EnterpriseService = FakeEnterpriseService(),
) = QrCodeScanPresenter( ) = QrCodeScanPresenter(
qrCodeLoginDataFactory = qrCodeLoginDataFactory, qrCodeLoginDataFactory = qrCodeLoginDataFactory,
qrCodeLoginManager = qrCodeLoginManager, qrCodeLoginManager = qrCodeLoginManager,
coroutineDispatchers = coroutineDispatchers, coroutineDispatchers = coroutineDispatchers,
enterpriseService = enterpriseService,
) )
} }

View file

@ -424,7 +424,7 @@ class MessageComposerPresenter @AssistedInject constructor(
resetComposer(markdownTextEditorState, richTextEditorState, fromEdit = capturedMode is MessageComposerMode.Edit) resetComposer(markdownTextEditorState, richTextEditorState, fromEdit = capturedMode is MessageComposerMode.Edit)
when (capturedMode) { when (capturedMode) {
is MessageComposerMode.Attachment, is MessageComposerMode.Attachment,
is MessageComposerMode.Normal -> room.sendMessage( is MessageComposerMode.Normal -> room.liveTimeline.sendMessage(
body = message.markdown, body = message.markdown,
htmlBody = message.html, htmlBody = message.html,
intentionalMentions = message.intentionalMentions intentionalMentions = message.intentionalMentions

View file

@ -38,29 +38,5 @@
<string name="screen_room_timeline_reactions_show_less">"Dangos llai"</string> <string name="screen_room_timeline_reactions_show_less">"Dangos llai"</string>
<string name="screen_room_timeline_reactions_show_more">"Dangos rhagor"</string> <string name="screen_room_timeline_reactions_show_more">"Dangos rhagor"</string>
<string name="screen_room_timeline_read_marker_title">"Newydd"</string> <string name="screen_room_timeline_read_marker_title">"Newydd"</string>
<plurals name="screen_room_timeline_state_changes">
<item quantity="zero">"%1$d newid ystafelloedd"</item>
<item quantity="one">"%1$d newid ystafell"</item>
<item quantity="two">"%1$d newid ystafell"</item>
<item quantity="few">"%1$d newid ystafell"</item>
<item quantity="many">"%1$d newid ystafell"</item>
<item quantity="other">"%1$d newid ystafell"</item>
</plurals>
<plurals name="screen_room_typing_many_members">
<item quantity="zero">"%1$s, %2$s a %3$d arall"</item>
<item quantity="one">"%1$s, %2$s a %3$d arall"</item>
<item quantity="two">"%1$s, %2$s a %3$d arall"</item>
<item quantity="few">"%1$s, %2$s a %3$d arall"</item>
<item quantity="many">"%1$s, %2$s a %3$d arall"</item>
<item quantity="other">"%1$s, %2$s a %3$d arall"</item>
</plurals>
<plurals name="screen_room_typing_notification">
<item quantity="zero">"Mae %1$s yn teipio"</item>
<item quantity="one">"Mae %1$s yn teipio"</item>
<item quantity="two">"Mae %1$s yn teipio"</item>
<item quantity="few">"Mae %1$s yn teipio"</item>
<item quantity="many">"Mae %1$s yn teipio"</item>
<item quantity="other">"Mae %1$s yn teipio"</item>
</plurals>
<string name="screen_room_typing_two_members">"%1$s a %2$s"</string> <string name="screen_room_typing_two_members">"%1$s a %2$s"</string>
</resources> </resources>

View file

@ -5,6 +5,8 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
@file:OptIn(ExperimentalCoroutinesApi::class)
package io.element.android.features.messages.impl package io.element.android.features.messages.impl
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
@ -96,6 +98,7 @@ import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Rule import org.junit.Rule
@ -173,12 +176,14 @@ class MessagesPresenterTest {
skipItems(1) skipItems(1)
val initialState = awaitItem() val initialState = awaitItem()
initialState.eventSink(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID.toEventOrTransactionId())) initialState.eventSink(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID.toEventOrTransactionId()))
advanceUntilIdle()
assert(toggleReactionSuccess) assert(toggleReactionSuccess)
.isCalledOnce() .isCalledOnce()
.with(value("👍"), value(AN_EVENT_ID.toEventOrTransactionId())) .with(value("👍"), value(AN_EVENT_ID.toEventOrTransactionId()))
// No crashes when sending a reaction failed // No crashes when sending a reaction failed
timeline.apply { toggleReactionLambda = toggleReactionFailure } timeline.toggleReactionLambda = toggleReactionFailure
initialState.eventSink(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID.toEventOrTransactionId())) initialState.eventSink(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID.toEventOrTransactionId()))
advanceUntilIdle()
assert(toggleReactionFailure) assert(toggleReactionFailure)
.isCalledOnce() .isCalledOnce()
.with(value("👍"), value(AN_EVENT_ID.toEventOrTransactionId())) .with(value("👍"), value(AN_EVENT_ID.toEventOrTransactionId()))
@ -209,6 +214,7 @@ class MessagesPresenterTest {
val initialState = awaitItem() val initialState = awaitItem()
initialState.eventSink(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID.toEventOrTransactionId())) initialState.eventSink(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID.toEventOrTransactionId()))
initialState.eventSink(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID.toEventOrTransactionId())) initialState.eventSink(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID.toEventOrTransactionId()))
advanceUntilIdle()
assert(toggleReactionSuccess) assert(toggleReactionSuccess)
.isCalledExactly(2) .isCalledExactly(2)
.withSequence( .withSequence(

View file

@ -35,6 +35,7 @@ import io.element.android.libraries.matrix.test.A_CAPTION
import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler
import io.element.android.libraries.matrix.test.permalink.FakePermalinkBuilder import io.element.android.libraries.matrix.test.permalink.FakePermalinkBuilder
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.mediaupload.api.MediaPreProcessor import io.element.android.libraries.mediaupload.api.MediaPreProcessor
import io.element.android.libraries.mediaupload.api.MediaSender import io.element.android.libraries.mediaupload.api.MediaSender
import io.element.android.libraries.mediaupload.api.MediaUploadInfo import io.element.android.libraries.mediaupload.api.MediaUploadInfo
@ -108,15 +109,18 @@ class AttachmentsPreviewPresenterTest {
fun `present - send media success scenario`() = runTest { fun `present - send media success scenario`() = runTest {
val sendFileResult = val sendFileResult =
lambdaRecorder<File, FileInfo, String?, String?, ProgressCallback?, ReplyParameters?, Result<FakeMediaUploadHandler>> { _, _, _, _, _, _ -> lambdaRecorder<File, FileInfo, String?, String?, ProgressCallback?, ReplyParameters?, Result<FakeMediaUploadHandler>> { _, _, _, _, _, _ ->
Result.success(FakeMediaUploadHandler()) Result.success(FakeMediaUploadHandler())
} }
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
progressCallbackValues = listOf( liveTimeline = FakeTimeline(
Pair(0, 10), progressCallbackValues = listOf(
Pair(5, 10), Pair(0, 10),
Pair(10, 10) Pair(5, 10),
), Pair(10, 10)
sendFileResult = sendFileResult, ),
).apply {
sendFileLambda = sendFileResult
},
) )
val onDoneListener = lambdaRecorder<Unit> { } val onDoneListener = lambdaRecorder<Unit> { }
val presenter = createAttachmentsPreviewPresenter( val presenter = createAttachmentsPreviewPresenter(
@ -146,10 +150,12 @@ class AttachmentsPreviewPresenterTest {
fun `present - send media after pre-processing success scenario`() = runTest { fun `present - send media after pre-processing success scenario`() = runTest {
val sendFileResult = val sendFileResult =
lambdaRecorder<File, FileInfo, String?, String?, ProgressCallback?, ReplyParameters?, Result<FakeMediaUploadHandler>> { _, _, _, _, _, _ -> lambdaRecorder<File, FileInfo, String?, String?, ProgressCallback?, ReplyParameters?, Result<FakeMediaUploadHandler>> { _, _, _, _, _, _ ->
Result.success(FakeMediaUploadHandler()) Result.success(FakeMediaUploadHandler())
} }
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
sendFileResult = sendFileResult, liveTimeline = FakeTimeline().apply {
sendFileLambda = sendFileResult
},
) )
val onDoneListener = lambdaRecorder<Unit> { } val onDoneListener = lambdaRecorder<Unit> { }
val processLatch = CompletableDeferred<Unit>() val processLatch = CompletableDeferred<Unit>()
@ -182,10 +188,12 @@ class AttachmentsPreviewPresenterTest {
fun `present - send media before pre-processing success scenario`() = runTest { fun `present - send media before pre-processing success scenario`() = runTest {
val sendFileResult = val sendFileResult =
lambdaRecorder<File, FileInfo, String?, String?, ProgressCallback?, ReplyParameters?, Result<FakeMediaUploadHandler>> { _, _, _, _, _, _ -> lambdaRecorder<File, FileInfo, String?, String?, ProgressCallback?, ReplyParameters?, Result<FakeMediaUploadHandler>> { _, _, _, _, _, _ ->
Result.success(FakeMediaUploadHandler()) Result.success(FakeMediaUploadHandler())
} }
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
sendFileResult = sendFileResult, liveTimeline = FakeTimeline().apply {
sendFileLambda = sendFileResult
},
) )
val onDoneListener = lambdaRecorder<Unit> { } val onDoneListener = lambdaRecorder<Unit> { }
val processLatch = CompletableDeferred<Unit>() val processLatch = CompletableDeferred<Unit>()
@ -298,7 +306,9 @@ class AttachmentsPreviewPresenterTest {
givenImageResult() givenImageResult()
} }
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
sendImageResult = sendImageResult, liveTimeline = FakeTimeline().apply {
sendImageLambda = sendImageResult
},
) )
val onDoneListener = lambdaRecorder<Unit> { } val onDoneListener = lambdaRecorder<Unit> { }
val presenter = createAttachmentsPreviewPresenter( val presenter = createAttachmentsPreviewPresenter(
@ -340,7 +350,9 @@ class AttachmentsPreviewPresenterTest {
givenVideoResult() givenVideoResult()
} }
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
sendVideoResult = sendVideoResult, liveTimeline = FakeTimeline().apply {
sendVideoLambda = sendVideoResult
},
) )
val onDoneListener = lambdaRecorder<Unit> { } val onDoneListener = lambdaRecorder<Unit> { }
val presenter = createAttachmentsPreviewPresenter( val presenter = createAttachmentsPreviewPresenter(
@ -382,7 +394,9 @@ class AttachmentsPreviewPresenterTest {
givenAudioResult() givenAudioResult()
} }
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
sendAudioResult = sendAudioResult, liveTimeline = FakeTimeline().apply {
sendAudioLambda = sendAudioResult
},
) )
val onDoneListener = lambdaRecorder<Unit> { } val onDoneListener = lambdaRecorder<Unit> { }
val presenter = createAttachmentsPreviewPresenter( val presenter = createAttachmentsPreviewPresenter(
@ -416,10 +430,12 @@ class AttachmentsPreviewPresenterTest {
val failure = MediaPreProcessor.Failure(null) val failure = MediaPreProcessor.Failure(null)
val sendFileResult = val sendFileResult =
lambdaRecorder<File, FileInfo, String?, String?, ProgressCallback?, ReplyParameters?, Result<FakeMediaUploadHandler>> { _, _, _, _, _, _ -> lambdaRecorder<File, FileInfo, String?, String?, ProgressCallback?, ReplyParameters?, Result<FakeMediaUploadHandler>> { _, _, _, _, _, _ ->
Result.failure(failure) Result.failure(failure)
} }
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
sendFileResult = sendFileResult, liveTimeline = FakeTimeline().apply {
sendFileLambda = sendFileResult
},
) )
val presenter = createAttachmentsPreviewPresenter(room = room, mediaUploadOnSendQueueEnabled = false) val presenter = createAttachmentsPreviewPresenter(room = room, mediaUploadOnSendQueueEnabled = false)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
@ -445,11 +461,13 @@ class AttachmentsPreviewPresenterTest {
val failure = MediaPreProcessor.Failure(null) val failure = MediaPreProcessor.Failure(null)
val sendFileResult = val sendFileResult =
lambdaRecorder<File, FileInfo, String?, String?, ProgressCallback?, ReplyParameters?, Result<FakeMediaUploadHandler>> { _, _, _, _, _, _ -> lambdaRecorder<File, FileInfo, String?, String?, ProgressCallback?, ReplyParameters?, Result<FakeMediaUploadHandler>> { _, _, _, _, _, _ ->
Result.failure(failure) Result.failure(failure)
} }
val onDoneListenerResult = lambdaRecorder<Unit> {} val onDoneListenerResult = lambdaRecorder<Unit> {}
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
sendFileResult = sendFileResult, liveTimeline = FakeTimeline().apply {
sendFileLambda = sendFileResult
},
) )
val presenter = createAttachmentsPreviewPresenter(room = room, mediaUploadOnSendQueueEnabled = true, onDoneListener = onDoneListenerResult) val presenter = createAttachmentsPreviewPresenter(room = room, mediaUploadOnSendQueueEnabled = true, onDoneListener = onDoneListenerResult)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {

View file

@ -384,7 +384,9 @@ class MessageComposerPresenterTest {
val presenter = createPresenter( val presenter = createPresenter(
coroutineScope = this, coroutineScope = this,
room = FakeJoinedRoom( room = FakeJoinedRoom(
sendMessageResult = { _, _, _ -> Result.success(Unit) }, liveTimeline = FakeTimeline().apply {
sendMessageLambda = { _, _, _ -> Result.success(Unit) }
},
typingNoticeResult = { Result.success(Unit) } typingNoticeResult = { Result.success(Unit) }
), ),
) )
@ -418,7 +420,9 @@ class MessageComposerPresenterTest {
coroutineScope = this, coroutineScope = this,
isRichTextEditorEnabled = false, isRichTextEditorEnabled = false,
room = FakeJoinedRoom( room = FakeJoinedRoom(
sendMessageResult = { _, _, _ -> Result.success(Unit) }, liveTimeline = FakeTimeline().apply {
sendMessageLambda = { _, _, _ -> Result.success(Unit) }
},
typingNoticeResult = { Result.success(Unit) } typingNoticeResult = { Result.success(Unit) }
), ),
) )
@ -1118,16 +1122,16 @@ class MessageComposerPresenterTest {
val editMessageLambda = lambdaRecorder { _: EventOrTransactionId, _: String, _: String?, _: List<IntentionalMention> -> val editMessageLambda = lambdaRecorder { _: EventOrTransactionId, _: String, _: String?, _: List<IntentionalMention> ->
Result.success(Unit) Result.success(Unit)
} }
val timeline = FakeTimeline().apply {
this.replyMessageLambda = replyMessageLambda
this.editMessageLambda = editMessageLambda
}
val sendMessageResult = lambdaRecorder { _: String, _: String?, _: List<IntentionalMention> -> val sendMessageResult = lambdaRecorder { _: String, _: String?, _: List<IntentionalMention> ->
Result.success(Unit) Result.success(Unit)
} }
val timeline = FakeTimeline().apply {
this.replyMessageLambda = replyMessageLambda
this.editMessageLambda = editMessageLambda
sendMessageLambda = sendMessageResult
}
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
liveTimeline = timeline, liveTimeline = timeline,
sendMessageResult = sendMessageResult,
typingNoticeResult = { Result.success(Unit) } typingNoticeResult = { Result.success(Unit) }
) )
val presenter = createPresenter(room = room, coroutineScope = this) val presenter = createPresenter(room = room, coroutineScope = this)

View file

@ -24,6 +24,7 @@ import io.element.android.libraries.matrix.api.media.AudioInfo
import io.element.android.libraries.matrix.api.room.message.ReplyParameters import io.element.android.libraries.matrix.api.room.message.ReplyParameters
import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.mediaplayer.test.FakeMediaPlayer import io.element.android.libraries.mediaplayer.test.FakeMediaPlayer
import io.element.android.libraries.mediaupload.api.MediaSender import io.element.android.libraries.mediaupload.api.MediaSender
import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor
@ -45,6 +46,7 @@ import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toPersistentList import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -65,7 +67,9 @@ class VoiceMessageComposerPresenterTest {
Result.success(FakeMediaUploadHandler()) Result.success(FakeMediaUploadHandler())
} }
private val joinedRoom = FakeJoinedRoom( private val joinedRoom = FakeJoinedRoom(
sendVoiceMessageResult = sendVoiceMessageResult liveTimeline = FakeTimeline().apply {
sendVoiceMessageLambda = sendVoiceMessageResult
},
) )
private val mediaPreProcessor = FakeMediaPreProcessor().apply { givenAudioResult() } private val mediaPreProcessor = FakeMediaPreProcessor().apply { givenAudioResult() }
private val mediaSender = MediaSender(mediaPreProcessor, joinedRoom, InMemorySessionPreferencesStore()) private val mediaSender = MediaSender(mediaPreProcessor, joinedRoom, InMemorySessionPreferencesStore())
@ -295,7 +299,6 @@ class VoiceMessageComposerPresenterTest {
awaitItem().eventSink(VoiceMessageComposerEvents.RecorderEvent(VoiceMessageRecorderEvent.Stop)) awaitItem().eventSink(VoiceMessageComposerEvents.RecorderEvent(VoiceMessageRecorderEvent.Stop))
awaitItem().eventSink(VoiceMessageComposerEvents.SendVoiceMessage) awaitItem().eventSink(VoiceMessageComposerEvents.SendVoiceMessage)
assertThat(awaitItem().voiceMessageState).isEqualTo(aPreviewState().toSendingState()) assertThat(awaitItem().voiceMessageState).isEqualTo(aPreviewState().toSendingState())
val finalState = awaitItem() val finalState = awaitItem()
assertThat(finalState.voiceMessageState).isEqualTo(VoiceMessageState.Idle) assertThat(finalState.voiceMessageState).isEqualTo(VoiceMessageState.Idle)
sendVoiceMessageResult.assertions().isCalledOnce() sendVoiceMessageResult.assertions().isCalledOnce()
@ -317,7 +320,7 @@ class VoiceMessageComposerPresenterTest {
awaitItem().eventSink(VoiceMessageComposerEvents.RecorderEvent(VoiceMessageRecorderEvent.Stop)) awaitItem().eventSink(VoiceMessageComposerEvents.RecorderEvent(VoiceMessageRecorderEvent.Stop))
awaitItem().eventSink(VoiceMessageComposerEvents.SendVoiceMessage) awaitItem().eventSink(VoiceMessageComposerEvents.SendVoiceMessage)
skipItems(1) // Sending state skipItems(1) // Sending state
advanceUntilIdle()
// Now reply with a voice message // Now reply with a voice message
messageComposerContext.composerMode = aReplyMode() messageComposerContext.composerMode = aReplyMode()
awaitItem().eventSink(VoiceMessageComposerEvents.RecorderEvent(VoiceMessageRecorderEvent.Start)) awaitItem().eventSink(VoiceMessageComposerEvents.RecorderEvent(VoiceMessageRecorderEvent.Start))
@ -653,7 +656,7 @@ class VoiceMessageComposerPresenterTest {
permissionsPresenter: PermissionsPresenter = createFakePermissionsPresenter(), permissionsPresenter: PermissionsPresenter = createFakePermissionsPresenter(),
): VoiceMessageComposerPresenter { ): VoiceMessageComposerPresenter {
return VoiceMessageComposerPresenter( return VoiceMessageComposerPresenter(
this, backgroundScope,
voiceRecorder, voiceRecorder,
analyticsService, analyticsService,
mediaSender, mediaSender,

View file

@ -1,29 +0,0 @@
/*
* Copyright 2023, 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.onboarding.api
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import io.element.android.libraries.architecture.FeatureEntryPoint
interface OnBoardingEntryPoint : FeatureEntryPoint {
fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder
interface NodeBuilder {
fun callback(callback: Callback): NodeBuilder
fun build(): Node
}
interface Callback : Plugin {
fun onSignUp()
fun onSignIn()
fun onSignInWithQrCode()
fun onReportProblem()
}
}

View file

@ -1,52 +0,0 @@
import extension.setupAnvil
/*
* Copyright 2022-2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
plugins {
id("io.element.android-compose-library")
id("kotlin-parcelize")
}
android {
namespace = "io.element.android.features.onboarding.impl"
testOptions {
unitTests {
isIncludeAndroidResources = true
}
}
}
setupAnvil()
dependencies {
implementation(projects.appconfig)
implementation(projects.features.rageshake.api)
implementation(projects.libraries.core)
implementation(projects.libraries.androidutils)
implementation(projects.libraries.architecture)
implementation(projects.libraries.designsystem)
implementation(projects.libraries.featureflag.api)
implementation(projects.libraries.matrix.api)
implementation(projects.libraries.testtags)
implementation(projects.libraries.uiStrings)
api(projects.features.onboarding.api)
testImplementation(libs.test.junit)
testImplementation(libs.androidx.compose.ui.test.junit)
testImplementation(libs.androidx.test.ext.junit)
testImplementation(libs.coroutines.test)
testImplementation(libs.molecule.runtime)
testImplementation(libs.test.robolectric)
testImplementation(libs.test.truth)
testImplementation(libs.test.turbine)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.featureflag.test)
testImplementation(projects.tests.testutils)
testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
}

View file

@ -1,35 +0,0 @@
/*
* Copyright 2023, 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.onboarding.impl
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.features.onboarding.api.OnBoardingEntryPoint
import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.di.AppScope
import javax.inject.Inject
@ContributesBinding(AppScope::class)
class DefaultOnBoardingEntryPoint @Inject constructor() : OnBoardingEntryPoint {
override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): OnBoardingEntryPoint.NodeBuilder {
return object : OnBoardingEntryPoint.NodeBuilder {
val plugins = ArrayList<Plugin>()
override fun callback(callback: OnBoardingEntryPoint.Callback): OnBoardingEntryPoint.NodeBuilder {
plugins += callback
return this
}
override fun build(): Node {
return parentNode.createNode<OnBoardingNode>(buildContext, plugins)
}
}
}
}

View file

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_onboarding_sign_in_manually">"Увайсці ўручную"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Увайсці з QR-кодам"</string>
<string name="screen_onboarding_sign_up">"Стварыць уліковы запіс"</string>
<string name="screen_onboarding_welcome_message">"Сардэчна запрашаем у самы хуткі %1$s. Перавага ў хуткасці і прастаце."</string>
<string name="screen_onboarding_welcome_subtitle">"Сардэчна запрашаем у %1$s. Зараджаны, для хуткасці і прастаты."</string>
<string name="screen_onboarding_welcome_title">"Будзьце ў сваім element"</string>
</resources>

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