mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-02 03:06:14 +00:00
Sync automatic call status with user status flag and server support
This commit is contained in:
@@ -60,6 +60,7 @@ dependencies {
|
||||
testCommonDependencies(libs)
|
||||
testImplementation(projects.features.login.test)
|
||||
testImplementation(projects.features.share.test)
|
||||
testImplementation(projects.libraries.featureflag.test)
|
||||
testImplementation(projects.libraries.matrix.test)
|
||||
testImplementation(projects.libraries.oauth.test)
|
||||
testImplementation(projects.libraries.permissions.test)
|
||||
|
||||
@@ -30,6 +30,8 @@ import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||
@@ -65,6 +67,7 @@ class LoggedInPresenter(
|
||||
private val buildMeta: BuildMeta,
|
||||
private val networkMonitor: NetworkMonitor,
|
||||
private val localNetworkPermissionAdvisor: LocalNetworkPermissionAdvisor,
|
||||
private val featureFlagService: FeatureFlagService,
|
||||
permissionsPresenterFactory: PermissionsPresenter.Factory,
|
||||
) : Presenter<LoggedInState> {
|
||||
private val localNetworkPermissionsPresenter: PermissionsPresenter =
|
||||
@@ -120,6 +123,16 @@ class LoggedInPresenter(
|
||||
}.launchIn(this)
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
// Keep automatic call status (m.call) in sync with the feature flag and homeserver support.
|
||||
featureFlagService.isFeatureEnabledFlow(FeatureFlags.UserStatus)
|
||||
.onEach { isUserStatusEnabled ->
|
||||
val enabled = isUserStatusEnabled && matrixClient.isUserStatusSupported().getOrDefault(false)
|
||||
matrixClient.enableAutomaticCallStatus(enabled)
|
||||
}
|
||||
.launchIn(this)
|
||||
}
|
||||
|
||||
val networkConnectivity by networkMonitor.connectivity.collectAsState()
|
||||
LaunchedEffect(networkConnectivity) {
|
||||
if (networkConnectivity == NetworkStatus.Connected) {
|
||||
|
||||
@@ -17,6 +17,9 @@ import im.vector.app.features.analytics.plan.UserProperties
|
||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
||||
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||
@@ -48,6 +51,7 @@ import io.element.android.services.analytics.api.AnalyticsService
|
||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
||||
import io.element.android.tests.testutils.lambda.assert
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.lambda.value
|
||||
@@ -127,6 +131,7 @@ class LoggedInPresenterTest {
|
||||
buildMeta = buildMeta,
|
||||
networkMonitor = networkMonitor,
|
||||
localNetworkPermissionAdvisor = FakeLocalNetworkPermissionAdvisor(),
|
||||
featureFlagService = FakeFeatureFlagService(),
|
||||
permissionsPresenterFactory = FakePermissionsPresenterFactory(),
|
||||
).test {
|
||||
encryptionService.emitRecoveryState(RecoveryState.UNKNOWN)
|
||||
@@ -346,6 +351,57 @@ class LoggedInPresenterTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - does not enable automatic call status when server does not support it`() = runTest {
|
||||
val enableAutomaticCallStatusLambda = lambdaRecorder<Boolean, Unit> { }
|
||||
val matrixClient = FakeMatrixClient(
|
||||
accountManagementUrlResult = { Result.success(null) },
|
||||
enableAutomaticCallStatusLambda = enableAutomaticCallStatusLambda,
|
||||
).apply {
|
||||
isUserStatusSupportedResult = Result.success(false)
|
||||
}
|
||||
createLoggedInPresenter(
|
||||
matrixClient = matrixClient,
|
||||
featureFlagService = FakeFeatureFlagService(
|
||||
initialState = mapOf(FeatureFlags.UserStatus.key to true),
|
||||
),
|
||||
).test {
|
||||
cancelAndConsumeRemainingEvents()
|
||||
assert(enableAutomaticCallStatusLambda)
|
||||
.isCalledOnce()
|
||||
.with(value(false))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - reacts to user status flag being toggled at runtime`() = runTest {
|
||||
val enableAutomaticCallStatusLambda = lambdaRecorder<Boolean, Unit> { }
|
||||
val matrixClient = FakeMatrixClient(
|
||||
accountManagementUrlResult = { Result.success(null) },
|
||||
enableAutomaticCallStatusLambda = enableAutomaticCallStatusLambda,
|
||||
).apply {
|
||||
isUserStatusSupportedResult = Result.success(true)
|
||||
}
|
||||
val featureFlagService = FakeFeatureFlagService(
|
||||
initialState = mapOf(FeatureFlags.UserStatus.key to false),
|
||||
)
|
||||
createLoggedInPresenter(
|
||||
matrixClient = matrixClient,
|
||||
featureFlagService = featureFlagService,
|
||||
).test {
|
||||
awaitItem()
|
||||
// Turning the flag on at runtime enables it.
|
||||
featureFlagService.setFeatureEnabled(FeatureFlags.UserStatus, true)
|
||||
cancelAndConsumeRemainingEvents()
|
||||
assert(enableAutomaticCallStatusLambda)
|
||||
.isCalledExactly(2)
|
||||
.withSequence(
|
||||
listOf(value(false)),
|
||||
listOf(value(true)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun <T> ReceiveTurbine<T>.awaitFirstItem(): T {
|
||||
skipItems(1)
|
||||
return awaitItem()
|
||||
@@ -362,6 +418,7 @@ class LoggedInPresenterTest {
|
||||
),
|
||||
buildMeta: BuildMeta = aBuildMeta(),
|
||||
networkMonitor: FakeNetworkMonitor = FakeNetworkMonitor(),
|
||||
featureFlagService: FeatureFlagService = FakeFeatureFlagService(),
|
||||
): LoggedInPresenter {
|
||||
return LoggedInPresenter(
|
||||
matrixClient = matrixClient,
|
||||
@@ -373,6 +430,7 @@ class LoggedInPresenterTest {
|
||||
buildMeta = buildMeta,
|
||||
networkMonitor = networkMonitor,
|
||||
localNetworkPermissionAdvisor = FakeLocalNetworkPermissionAdvisor(),
|
||||
featureFlagService = featureFlagService,
|
||||
permissionsPresenterFactory = FakePermissionsPresenterFactory(),
|
||||
)
|
||||
}
|
||||
|
||||
+3
@@ -102,6 +102,9 @@ interface MatrixClient {
|
||||
|
||||
/** Whether the homeserver advertises support for user status (MSC4426). */
|
||||
suspend fun isUserStatusSupported(): Result<Boolean>
|
||||
|
||||
/** Enable or disable automatically setting the user's status to "in a call" (m.call) while in a call. */
|
||||
fun enableAutomaticCallStatus(enabled: Boolean)
|
||||
suspend fun joinRoom(roomId: RoomId): Result<RoomInfo?>
|
||||
suspend fun joinRoomByIdOrAlias(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomInfo?>
|
||||
suspend fun knockRoom(roomIdOrAlias: RoomIdOrAlias, message: String, serverNames: List<String>): Result<RoomInfo?>
|
||||
|
||||
+4
@@ -530,6 +530,10 @@ class RustMatrixClient(
|
||||
}
|
||||
}
|
||||
|
||||
override fun enableAutomaticCallStatus(enabled: Boolean) {
|
||||
innerClient.enableAutomaticCallStatus(enabled)
|
||||
}
|
||||
|
||||
override suspend fun joinRoom(roomId: RoomId): Result<RoomInfo?> = withContext(sessionDispatcher) {
|
||||
runCatchingExceptions {
|
||||
innerClient.joinRoomById(roomId.value).destroy()
|
||||
|
||||
+3
@@ -130,6 +130,7 @@ class FakeMatrixClient(
|
||||
private val getMapStyleUrlResult: () -> Result<String?> = { lambdaError() },
|
||||
private val getDatabaseSizesLambda: () -> Result<SdkStoreSizes> = { lambdaError() },
|
||||
private val resetWellKnownConfigLambda: () -> Result<Unit> = { lambdaError() },
|
||||
private val enableAutomaticCallStatusLambda: (Boolean) -> Unit = { },
|
||||
override val contentScanner: ContentScanner? = null,
|
||||
) : MatrixClient {
|
||||
var setDisplayNameCalled: Boolean = false
|
||||
@@ -291,6 +292,8 @@ class FakeMatrixClient(
|
||||
|
||||
override suspend fun isUserStatusSupported(): Result<Boolean> = isUserStatusSupportedResult
|
||||
|
||||
override fun enableAutomaticCallStatus(enabled: Boolean) = enableAutomaticCallStatusLambda(enabled)
|
||||
|
||||
override suspend fun joinRoom(roomId: RoomId): Result<RoomInfo?> = joinRoomLambda(roomId)
|
||||
|
||||
override suspend fun joinRoomByIdOrAlias(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomInfo?> {
|
||||
|
||||
Reference in New Issue
Block a user