Merge branch 'release/25.05.1'
This commit is contained in:
commit
957a7432fe
25 changed files with 173 additions and 16 deletions
49
CHANGES.md
49
CHANGES.md
|
|
@ -1,3 +1,52 @@
|
||||||
|
Changes in Element X v25.05.0
|
||||||
|
=============================
|
||||||
|
|
||||||
|
## What's Changed
|
||||||
|
### ✨ Features
|
||||||
|
* Feature : Report room by @ganfra in https://github.com/element-hq/element-x-android/pull/4654
|
||||||
|
### 🙌 Improvements
|
||||||
|
* Render kick and ban reason in the timeline when available by @bmarty in https://github.com/element-hq/element-x-android/pull/4642
|
||||||
|
### 🐛 Bugfixes
|
||||||
|
* Accessibility: improve behavior of list items by @bmarty in https://github.com/element-hq/element-x-android/pull/4626
|
||||||
|
* Render caller avatar on Incoming call screen by @bmarty in https://github.com/element-hq/element-x-android/pull/4635
|
||||||
|
* Fix `Client.getJoinedRoom` crash when a room doesn't exist locally by @jmartinesp in https://github.com/element-hq/element-x-android/pull/4656
|
||||||
|
* Fix wrong member count in join room screen for invitation by @bmarty in https://github.com/element-hq/element-x-android/pull/4651
|
||||||
|
* Make sure any `JoinedRustRoom` is destroyed after being used by @jmartinesp in https://github.com/element-hq/element-x-android/pull/4678
|
||||||
|
* Fix read receipt behavior when the timeline is opened. by @bmarty in https://github.com/element-hq/element-x-android/pull/4679
|
||||||
|
### 🗣 Translations
|
||||||
|
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/4648
|
||||||
|
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/4677
|
||||||
|
### 🧱 Build
|
||||||
|
* OIDC configuration by @bmarty in https://github.com/element-hq/element-x-android/pull/4623
|
||||||
|
* Pin commit sha on GitHub actions by @bmarty in https://github.com/element-hq/element-x-android/pull/4653
|
||||||
|
### Dependency upgrades
|
||||||
|
* fix(deps): update dependency io.sentry:sentry-android to v8.9.0 by @renovate in https://github.com/element-hq/element-x-android/pull/4624
|
||||||
|
* fix(deps): update dependency com.posthog:posthog-android to v3.14.1 by @renovate in https://github.com/element-hq/element-x-android/pull/4628
|
||||||
|
* fix(deps): update dependency androidx.exifinterface:exifinterface to v1.4.1 by @renovate in https://github.com/element-hq/element-x-android/pull/4632
|
||||||
|
* fix(deps): update dependencyanalysis to v2.17.0 by @renovate in https://github.com/element-hq/element-x-android/pull/4638
|
||||||
|
* fix(deps): update dependency com.google.firebase:firebase-bom to v33.13.0 - autoclosed by @renovate in https://github.com/element-hq/element-x-android/pull/4637
|
||||||
|
* fix(deps): update dependency io.sentry:sentry-android to v8.10.0 by @renovate in https://github.com/element-hq/element-x-android/pull/4644
|
||||||
|
* fix(deps): update dependency org.jsoup:jsoup to v1.20.1 by @renovate in https://github.com/element-hq/element-x-android/pull/4655
|
||||||
|
* fix(deps): update dependency com.google.accompanist:accompanist-permissions to v0.37.3 by @renovate in https://github.com/element-hq/element-x-android/pull/4649
|
||||||
|
* fix(deps): update dependency io.sentry:sentry-android to v8.11.0 by @renovate in https://github.com/element-hq/element-x-android/pull/4660
|
||||||
|
* fix(deps): update dependency io.mockk:mockk to v1.14.2 by @renovate in https://github.com/element-hq/element-x-android/pull/4658
|
||||||
|
* fix(deps): update dependency io.github.sergio-sastre.composablepreviewscanner:android to v0.6.1 by @renovate in https://github.com/element-hq/element-x-android/pull/4647
|
||||||
|
* fix(deps): update dependency org.matrix.rustcomponents:sdk-android to v25.4.30 by @renovate in https://github.com/element-hq/element-x-android/pull/4665
|
||||||
|
* fix(deps): update kotlin to v2.1.20-2.0.1 by @renovate in https://github.com/element-hq/element-x-android/pull/4670
|
||||||
|
* fix(deps): update dependency io.sentry:sentry-android to v8.11.1 by @renovate in https://github.com/element-hq/element-x-android/pull/4668
|
||||||
|
* fix(deps): update dependency io.element.android:element-call-embedded to v0.10.0 by @renovate in https://github.com/element-hq/element-x-android/pull/4667
|
||||||
|
* chore(deps): update rnkdsh/action-upload-diawi action to v1.5.9 by @renovate in https://github.com/element-hq/element-x-android/pull/4674
|
||||||
|
* fix(deps): update dependency org.maplibre.gl:android-sdk to v11.8.7 by @renovate in https://github.com/element-hq/element-x-android/pull/4673
|
||||||
|
* fix(deps): update dependency org.matrix.rustcomponents:sdk-android to v25.5.6 by @renovate in https://github.com/element-hq/element-x-android/pull/4681
|
||||||
|
### Others
|
||||||
|
* Split `MatrixRoom` into `MatrixRoom` and `JoinedMatrixRoom` by @jmartinesp in https://github.com/element-hq/element-x-android/pull/4561
|
||||||
|
* Cleanup element call and UI by @bmarty in https://github.com/element-hq/element-x-android/pull/4641
|
||||||
|
* Take change of screen_change_server_error_no_sliding_sync_message into account by @bmarty in https://github.com/element-hq/element-x-android/pull/4650
|
||||||
|
* Improve the callback uri format and customization. by @bmarty in https://github.com/element-hq/element-x-android/pull/4664
|
||||||
|
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/element-hq/element-x-android/compare/v25.04.3...v25.05.0
|
||||||
|
|
||||||
Changes in Element X v25.04.3
|
Changes in Element X v25.04.3
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0299b8ec4f4233a39230d4c35b97f89728c35fd1
|
Subproject commit c754703e720bcb20f5dfa1ea0dcd32976825f71c
|
||||||
2
fastlane/metadata/android/en-US/changelogs/202505010.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/202505010.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
Main changes in this version: fix Element Call not working.
|
||||||
|
Full changelog: https://github.com/element-hq/element-x-android/releases
|
||||||
|
|
@ -48,7 +48,6 @@ class DefaultCallWidgetProvider @Inject constructor(
|
||||||
).getOrThrow()
|
).getOrThrow()
|
||||||
|
|
||||||
val driver = room.getWidgetDriver(widgetSettings).getOrThrow()
|
val driver = room.getWidgetDriver(widgetSettings).getOrThrow()
|
||||||
room.destroy()
|
|
||||||
|
|
||||||
CallWidgetProvider.GetWidgetResult(
|
CallWidgetProvider.GetWidgetResult(
|
||||||
driver = driver,
|
driver = driver,
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ interface EnterpriseService {
|
||||||
val isEnterpriseBuild: Boolean
|
val isEnterpriseBuild: Boolean
|
||||||
suspend fun isEnterpriseUser(sessionId: SessionId): Boolean
|
suspend fun isEnterpriseUser(sessionId: SessionId): Boolean
|
||||||
fun defaultHomeserver(): String?
|
fun defaultHomeserver(): String?
|
||||||
|
suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String): Boolean
|
||||||
|
|
||||||
fun semanticColorsLight(): SemanticColors
|
fun semanticColorsLight(): SemanticColors
|
||||||
fun semanticColorsDark(): SemanticColors
|
fun semanticColorsDark(): SemanticColors
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,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 defaultHomeserver() = null
|
||||||
|
override suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String) = true
|
||||||
|
|
||||||
override fun semanticColorsLight(): SemanticColors = compoundColorsLight
|
override fun semanticColorsLight(): SemanticColors = compoundColorsLight
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
package io.element.android.features.enterprise.impl
|
package io.element.android.features.enterprise.impl
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.libraries.matrix.test.A_HOMESERVER_URL
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
@ -25,6 +26,12 @@ class DefaultEnterpriseServiceTest {
|
||||||
assertThat<String?>(defaultEnterpriseService.defaultHomeserver()).isNull()
|
assertThat<String?>(defaultEnterpriseService.defaultHomeserver()).isNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `isAllowedToConnectToHomeserver is true for all homeserver urls`() = runTest {
|
||||||
|
val defaultEnterpriseService = DefaultEnterpriseService()
|
||||||
|
assertThat(defaultEnterpriseService.isAllowedToConnectToHomeserver(A_HOMESERVER_URL)).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `isEnterpriseUser always return false`() = runTest {
|
fun `isEnterpriseUser always return false`() = runTest {
|
||||||
val defaultEnterpriseService = DefaultEnterpriseService()
|
val defaultEnterpriseService = DefaultEnterpriseService()
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ 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 defaultHomeserverResult: () -> String? = { A_FAKE_HOMESERVER },
|
||||||
|
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() },
|
||||||
private val firebasePushGatewayResult: () -> String? = { lambdaError() },
|
private val firebasePushGatewayResult: () -> String? = { lambdaError() },
|
||||||
|
|
@ -30,6 +31,10 @@ class FakeEnterpriseService(
|
||||||
return defaultHomeserverResult()
|
return defaultHomeserverResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String): Boolean = simulateLongTask {
|
||||||
|
isAllowedToConnectToHomeserverResult(homeserverUrl)
|
||||||
|
}
|
||||||
|
|
||||||
override fun semanticColorsLight(): SemanticColors {
|
override fun semanticColorsLight(): SemanticColors {
|
||||||
return semanticColorsLightResult()
|
return semanticColorsLightResult()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,13 @@ import androidx.compose.ui.unit.IntOffset
|
||||||
* Horizontally aligns the content to the center of the space.
|
* Horizontally aligns the content to the center of the space.
|
||||||
* Vertically aligns the bottom edge of the content to the center of the space.
|
* Vertically aligns the bottom edge of the content to the center of the space.
|
||||||
*/
|
*/
|
||||||
fun Modifier.centerBottomEdge(scope: BoxScope): Modifier = with(scope) {
|
fun Modifier.centerBottomEdge(scope: BoxScope): Modifier = this.then(
|
||||||
then(
|
with(scope) {
|
||||||
Modifier.align { size, space, _ ->
|
Modifier.align { size, space, _ ->
|
||||||
IntOffset(
|
IntOffset(
|
||||||
x = (space.width - size.width) / 2,
|
x = (space.width - size.width) / 2,
|
||||||
y = space.height / 2 - size.height,
|
y = space.height / 2 - size.height,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
}
|
)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
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 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.accountprovider.AccountProviderDataSource
|
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
|
||||||
import io.element.android.features.login.impl.error.ChangeServerError
|
import io.element.android.features.login.impl.error.ChangeServerError
|
||||||
|
|
@ -26,6 +27,7 @@ import javax.inject.Inject
|
||||||
class ChangeServerPresenter @Inject constructor(
|
class ChangeServerPresenter @Inject constructor(
|
||||||
private val authenticationService: MatrixAuthenticationService,
|
private val authenticationService: MatrixAuthenticationService,
|
||||||
private val accountProviderDataSource: AccountProviderDataSource,
|
private val accountProviderDataSource: AccountProviderDataSource,
|
||||||
|
private val enterpriseService: EnterpriseService,
|
||||||
) : Presenter<ChangeServerState> {
|
) : Presenter<ChangeServerState> {
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): ChangeServerState {
|
override fun present(): ChangeServerState {
|
||||||
|
|
@ -53,6 +55,9 @@ class ChangeServerPresenter @Inject constructor(
|
||||||
changeServerAction: MutableState<AsyncData<Unit>>,
|
changeServerAction: MutableState<AsyncData<Unit>>,
|
||||||
) = launch {
|
) = launch {
|
||||||
suspend {
|
suspend {
|
||||||
|
if (enterpriseService.isAllowedToConnectToHomeserver(data.url).not()) {
|
||||||
|
throw UnauthorizedAccountProviderException(data)
|
||||||
|
}
|
||||||
authenticationService.setHomeserver(data.url).map {
|
authenticationService.setHomeserver(data.url).map {
|
||||||
authenticationService.getHomeserverDetails().value!!
|
authenticationService.getHomeserverDetails().value!!
|
||||||
// Valid, remember user choice
|
// Valid, remember user choice
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
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
|
||||||
|
|
@ -18,6 +19,7 @@ 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()))),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,9 @@ import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.rememberUpdatedState
|
import androidx.compose.runtime.rememberUpdatedState
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
|
import io.element.android.features.login.impl.R
|
||||||
import io.element.android.features.login.impl.dialogs.SlidingSyncNotSupportedDialog
|
import io.element.android.features.login.impl.dialogs.SlidingSyncNotSupportedDialog
|
||||||
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
|
||||||
|
|
@ -20,6 +22,7 @@ import io.element.android.libraries.designsystem.components.ProgressDialog
|
||||||
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
|
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
|
import io.element.android.libraries.designsystem.theme.LocalBuildMeta
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ChangeServerView(
|
fun ChangeServerView(
|
||||||
|
|
@ -31,7 +34,7 @@ fun ChangeServerView(
|
||||||
val eventSink = state.eventSink
|
val eventSink = state.eventSink
|
||||||
when (state.changeServerAction) {
|
when (state.changeServerAction) {
|
||||||
is AsyncData.Failure -> {
|
is AsyncData.Failure -> {
|
||||||
when (val error = state.changeServerAction.error) {
|
when (val error = state.changeServerAction.error as? ChangeServerError) {
|
||||||
is ChangeServerError.Error -> {
|
is ChangeServerError.Error -> {
|
||||||
ErrorDialog(
|
ErrorDialog(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
|
@ -53,6 +56,20 @@ fun ChangeServerView(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
is ChangeServerError.UnauthorizedAccountProvider -> {
|
||||||
|
ErrorDialog(
|
||||||
|
modifier = modifier,
|
||||||
|
content = stringResource(
|
||||||
|
id = R.string.screen_change_server_error_unauthorized_homeserver,
|
||||||
|
LocalBuildMeta.current.applicationName,
|
||||||
|
error.accountProvider.title,
|
||||||
|
),
|
||||||
|
onSubmit = {
|
||||||
|
eventSink.invoke(ChangeServerEvents.ClearError)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
null -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is AsyncData.Loading -> ProgressDialog()
|
is AsyncData.Loading -> ProgressDialog()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 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.login.impl.changeserver
|
||||||
|
|
||||||
|
import io.element.android.features.login.impl.accountprovider.AccountProvider
|
||||||
|
|
||||||
|
class UnauthorizedAccountProviderException(
|
||||||
|
val accountProvider: AccountProvider,
|
||||||
|
) : Exception()
|
||||||
|
|
@ -11,6 +11,8 @@ 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.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
|
||||||
|
|
||||||
|
|
@ -23,12 +25,17 @@ sealed class ChangeServerError : Throwable() {
|
||||||
fun message(): String = messageStr ?: stringResource(messageId ?: CommonStrings.error_unknown)
|
fun message(): String = messageStr ?: stringResource(messageId ?: CommonStrings.error_unknown)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class UnauthorizedAccountProvider(
|
||||||
|
val accountProvider: AccountProvider,
|
||||||
|
) : ChangeServerError()
|
||||||
|
|
||||||
data object SlidingSyncAlert : ChangeServerError()
|
data object SlidingSyncAlert : ChangeServerError()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
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)
|
||||||
else -> Error(messageId = R.string.screen_change_server_error_invalid_homeserver)
|
else -> Error(messageId = R.string.screen_change_server_error_invalid_homeserver)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,10 @@
|
||||||
<string name="screen_change_account_provider_subtitle">"Use a different account provider, such as your own private server or a work account."</string>
|
<string name="screen_change_account_provider_subtitle">"Use a different account provider, such as your own private server or a work account."</string>
|
||||||
<string name="screen_change_account_provider_title">"Change account provider"</string>
|
<string name="screen_change_account_provider_title">"Change account provider"</string>
|
||||||
<string name="screen_change_server_error_invalid_homeserver">"We couldn\'t reach this homeserver. Please check that you have entered the homeserver URL correctly. If the URL is correct, contact your homeserver administrator for further help."</string>
|
<string name="screen_change_server_error_invalid_homeserver">"We couldn\'t reach this homeserver. Please check that you have entered the homeserver URL correctly. If the URL is correct, contact your homeserver administrator for further help."</string>
|
||||||
<string name="screen_change_server_error_invalid_well_known">"Server isn\'t available due to an issue in the well-known file:
|
<string name="screen_change_server_error_invalid_well_known">"Server isn\'t available due to an issue in the .well-known file:
|
||||||
%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_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>
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,18 @@
|
||||||
package io.element.android.features.login.impl.changeserver
|
package io.element.android.features.login.impl.changeserver
|
||||||
|
|
||||||
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.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.accountprovider.AccountProviderDataSource
|
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
|
||||||
|
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.matrix.test.A_HOMESERVER
|
import io.element.android.libraries.matrix.test.A_HOMESERVER
|
||||||
import io.element.android.libraries.matrix.test.A_HOMESERVER_URL
|
import io.element.android.libraries.matrix.test.A_HOMESERVER_URL
|
||||||
import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService
|
import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
|
import io.element.android.tests.testutils.lambda.value
|
||||||
import io.element.android.tests.testutils.test
|
import io.element.android.tests.testutils.test
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
|
|
@ -38,6 +42,9 @@ class ChangeServerPresenterTest {
|
||||||
val authenticationService = FakeMatrixAuthenticationService()
|
val authenticationService = FakeMatrixAuthenticationService()
|
||||||
createPresenter(
|
createPresenter(
|
||||||
authenticationService = authenticationService,
|
authenticationService = authenticationService,
|
||||||
|
enterpriseService = FakeEnterpriseService(
|
||||||
|
isAllowedToConnectToHomeserverResult = { true },
|
||||||
|
),
|
||||||
).test {
|
).test {
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.changeServerAction).isEqualTo(AsyncData.Uninitialized)
|
assertThat(initialState.changeServerAction).isEqualTo(AsyncData.Uninitialized)
|
||||||
|
|
@ -52,7 +59,11 @@ class ChangeServerPresenterTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - change server error`() = runTest {
|
fun `present - change server error`() = runTest {
|
||||||
createPresenter().test {
|
createPresenter(
|
||||||
|
enterpriseService = FakeEnterpriseService(
|
||||||
|
isAllowedToConnectToHomeserverResult = { true },
|
||||||
|
),
|
||||||
|
).test {
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.changeServerAction).isEqualTo(AsyncData.Uninitialized)
|
assertThat(initialState.changeServerAction).isEqualTo(AsyncData.Uninitialized)
|
||||||
initialState.eventSink.invoke(ChangeServerEvents.ChangeServer(AccountProvider(url = A_HOMESERVER_URL)))
|
initialState.eventSink.invoke(ChangeServerEvents.ChangeServer(AccountProvider(url = A_HOMESERVER_URL)))
|
||||||
|
|
@ -67,11 +78,37 @@ class ChangeServerPresenterTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - change server not allowed error`() = runTest {
|
||||||
|
val isAllowedToConnectToHomeserverResult = lambdaRecorder<String, Boolean> { false }
|
||||||
|
createPresenter(
|
||||||
|
enterpriseService = FakeEnterpriseService(
|
||||||
|
isAllowedToConnectToHomeserverResult = isAllowedToConnectToHomeserverResult,
|
||||||
|
),
|
||||||
|
).test {
|
||||||
|
val initialState = awaitItem()
|
||||||
|
assertThat(initialState.changeServerAction).isEqualTo(AsyncData.Uninitialized)
|
||||||
|
val anAccountProvider = AccountProvider(url = A_HOMESERVER_URL)
|
||||||
|
initialState.eventSink.invoke(ChangeServerEvents.ChangeServer(anAccountProvider))
|
||||||
|
val loadingState = awaitItem()
|
||||||
|
assertThat(loadingState.changeServerAction).isInstanceOf(AsyncData.Loading::class.java)
|
||||||
|
val failureState = awaitItem()
|
||||||
|
assertThat(
|
||||||
|
(failureState.changeServerAction.errorOrNull() as ChangeServerError.UnauthorizedAccountProvider).accountProvider
|
||||||
|
).isEqualTo(anAccountProvider)
|
||||||
|
isAllowedToConnectToHomeserverResult.assertions()
|
||||||
|
.isCalledOnce()
|
||||||
|
.with(value(A_HOMESERVER_URL))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun createPresenter(
|
private fun createPresenter(
|
||||||
authenticationService: FakeMatrixAuthenticationService = FakeMatrixAuthenticationService(),
|
authenticationService: FakeMatrixAuthenticationService = FakeMatrixAuthenticationService(),
|
||||||
accountProviderDataSource: AccountProviderDataSource = AccountProviderDataSource(FakeEnterpriseService()),
|
accountProviderDataSource: AccountProviderDataSource = AccountProviderDataSource(FakeEnterpriseService()),
|
||||||
|
enterpriseService: EnterpriseService = FakeEnterpriseService(),
|
||||||
) = ChangeServerPresenter(
|
) = ChangeServerPresenter(
|
||||||
authenticationService = authenticationService,
|
authenticationService = authenticationService,
|
||||||
accountProviderDataSource = accountProviderDataSource
|
accountProviderDataSource = accountProviderDataSource,
|
||||||
|
enterpriseService = enterpriseService,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ signing.element.nightly.keyPassword=Secret
|
||||||
|
|
||||||
# Customise the Lint version to use a more recent version than the one bundled with AGP
|
# Customise the Lint version to use a more recent version than the one bundled with AGP
|
||||||
# https://googlesamples.github.io/android-custom-lint-rules/usage/newer-lint.md.html
|
# https://googlesamples.github.io/android-custom-lint-rules/usage/newer-lint.md.html
|
||||||
android.experimental.lint.version=8.10.0-alpha08
|
android.experimental.lint.version=8.11.0-alpha09
|
||||||
|
|
||||||
# Enable test fixture for all modules by default
|
# Enable test fixture for all modules by default
|
||||||
android.experimental.enableTestFixtures=true
|
android.experimental.enableTestFixtures=true
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
[versions]
|
[versions]
|
||||||
# Project
|
# Project
|
||||||
android_gradle_plugin = "8.9.2"
|
android_gradle_plugin = "8.10.0"
|
||||||
kotlin = "2.1.20"
|
kotlin = "2.1.20"
|
||||||
kotlinpoet = "2.1.0"
|
kotlinpoet = "2.1.0"
|
||||||
ksp = "2.1.20-2.0.1"
|
ksp = "2.1.20-2.0.1"
|
||||||
|
|
@ -169,7 +169,7 @@ jsoup = "org.jsoup:jsoup:1.20.1"
|
||||||
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
|
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
|
||||||
molecule-runtime = "app.cash.molecule:molecule-runtime:2.1.0"
|
molecule-runtime = "app.cash.molecule:molecule-runtime:2.1.0"
|
||||||
timber = "com.jakewharton.timber:timber:5.0.1"
|
timber = "com.jakewharton.timber:timber:5.0.1"
|
||||||
matrix_sdk = "org.matrix.rustcomponents:sdk-android:25.5.6"
|
matrix_sdk = "org.matrix.rustcomponents:sdk-android:25.5.8"
|
||||||
matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
|
matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
|
||||||
matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" }
|
matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" }
|
||||||
sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
|
sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
fun Modifier.clickableIfNotNull(onClick: (() -> Unit)? = null): Modifier = then(
|
fun Modifier.clickableIfNotNull(onClick: (() -> Unit)? = null): Modifier = this.then(
|
||||||
if (onClick != null) {
|
if (onClick != null) {
|
||||||
Modifier.clickable { onClick() }
|
Modifier.clickable { onClick() }
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ private fun Modifier.withAccessibilityModifier(
|
||||||
content: ListItemContent?,
|
content: ListItemContent?,
|
||||||
enabled: Boolean,
|
enabled: Boolean,
|
||||||
onClick: (() -> Unit)?,
|
onClick: (() -> Unit)?,
|
||||||
): Modifier = then(
|
): Modifier = this.then(
|
||||||
when (content) {
|
when (content) {
|
||||||
is ListItemContent.Checkbox -> {
|
is ListItemContent.Checkbox -> {
|
||||||
Modifier.toggleable(
|
Modifier.toggleable(
|
||||||
|
|
|
||||||
|
|
@ -595,6 +595,7 @@ class JoinedRustRoom(
|
||||||
RustWidgetDriver(
|
RustWidgetDriver(
|
||||||
widgetSettings = widgetSettings,
|
widgetSettings = widgetSettings,
|
||||||
room = innerRoom,
|
room = innerRoom,
|
||||||
|
joinedRustRoom = this,
|
||||||
widgetCapabilitiesProvider = object : WidgetCapabilitiesProvider {
|
widgetCapabilitiesProvider = object : WidgetCapabilitiesProvider {
|
||||||
override fun acquireCapabilities(capabilities: WidgetCapabilities): WidgetCapabilities {
|
override fun acquireCapabilities(capabilities: WidgetCapabilities): WidgetCapabilities {
|
||||||
return getElementCallRequiredPermissions(sessionId.value, baseRoom.deviceId.value)
|
return getElementCallRequiredPermissions(sessionId.value, baseRoom.deviceId.value)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ package io.element.android.libraries.matrix.impl.widget
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
|
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
|
||||||
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
|
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
|
||||||
|
import io.element.android.libraries.matrix.impl.room.JoinedRustRoom
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
|
@ -24,6 +25,7 @@ import kotlin.coroutines.coroutineContext
|
||||||
class RustWidgetDriver(
|
class RustWidgetDriver(
|
||||||
widgetSettings: MatrixWidgetSettings,
|
widgetSettings: MatrixWidgetSettings,
|
||||||
private val room: Room,
|
private val room: Room,
|
||||||
|
private val joinedRustRoom: JoinedRustRoom,
|
||||||
private val widgetCapabilitiesProvider: WidgetCapabilitiesProvider,
|
private val widgetCapabilitiesProvider: WidgetCapabilitiesProvider,
|
||||||
) : MatrixWidgetDriver {
|
) : MatrixWidgetDriver {
|
||||||
// It's important to have extra capacity here to make sure we don't drop any messages
|
// It's important to have extra capacity here to make sure we don't drop any messages
|
||||||
|
|
@ -69,5 +71,6 @@ class RustWidgetDriver(
|
||||||
override fun close() {
|
override fun close() {
|
||||||
receiveMessageJob?.cancel()
|
receiveMessageJob?.cancel()
|
||||||
driverAndHandle.driver.close()
|
driverAndHandle.driver.close()
|
||||||
|
joinedRustRoom.destroy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ private const val versionYear = 25
|
||||||
private const val versionMonth = 5
|
private const val versionMonth = 5
|
||||||
|
|
||||||
// Note: must be in [0,99]
|
// Note: must be in [0,99]
|
||||||
private const val versionReleaseNumber = 0
|
private const val versionReleaseNumber = 1
|
||||||
|
|
||||||
object Versions {
|
object Versions {
|
||||||
const val VERSION_CODE = (2000 + versionYear) * 10_000 + versionMonth * 100 + versionReleaseNumber
|
const val VERSION_CODE = (2000 + versionYear) * 10_000 + versionMonth * 100 + versionReleaseNumber
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:6c1257fbdf388933be8fb2ae211c8abacc4cdb01c2a924a7ba3729337c9b6707
|
||||||
|
size 15434
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:cb9a2d2145791122cc2ab7d903485de361fb6098216bf578dca7cc350e9f94a0
|
||||||
|
size 13650
|
||||||
Loading…
Add table
Add a link
Reference in a new issue