diff --git a/enterprise b/enterprise index dac93821a6..867d1118e1 160000 --- a/enterprise +++ b/enterprise @@ -1 +1 @@ -Subproject commit dac93821a6f9f9ad1494d3c69c115ef0696eb7ce +Subproject commit 867d1118e157ba89a4f5462f8d9c13e206f10026 diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accesscontrol/DefaultAccountProviderAccessControl.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accesscontrol/DefaultAccountProviderAccessControl.kt index af0bf65591..3f94074a82 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accesscontrol/DefaultAccountProviderAccessControl.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accesscontrol/DefaultAccountProviderAccessControl.kt @@ -39,7 +39,7 @@ class DefaultAccountProviderAccessControl( // Ensure that Element Pro is not required for this account provider val wellKnown = wellknownRetriever.getElementWellKnown( baseUrl = accountProviderUrl.ensureProtocol(), - ) + ).dataOrNull() if (wellKnown?.enforceElementPro == true) { throw AccountProviderAccessException.NeedElementProException( unauthorisedAccountProviderTitle = title, diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/resolver/HomeserverResolver.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/resolver/HomeserverResolver.kt index 5612a56d5e..7b6f3e4102 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/resolver/HomeserverResolver.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/resolver/HomeserverResolver.kt @@ -46,7 +46,7 @@ class HomeserverResolver( wellknownRetriever.getWellKnown(url) } } - val isValid = wellKnown?.isValid().orFalse() + val isValid = wellKnown?.dataOrNull()?.isValid().orFalse() if (isValid) { // Emit the list as soon as possible currentList.add( diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/web/WebClientUrlForAuthenticationRetriever.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/web/WebClientUrlForAuthenticationRetriever.kt index 554e20b90f..6038c1a398 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/web/WebClientUrlForAuthenticationRetriever.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/web/WebClientUrlForAuthenticationRetriever.kt @@ -28,7 +28,7 @@ class DefaultWebClientUrlForAuthenticationRetriever( Timber.w("Temporary account creation flow is only supported on matrix.org") throw AccountCreationNotSupported() } - val wellknown = wellknownRetriever.getElementWellKnown(homeServerUrl) + val wellknown = wellknownRetriever.getElementWellKnown(homeServerUrl).dataOrNull() ?: throw AccountCreationNotSupported() val registrationHelperUrl = wellknown.registrationHelperUrl return if (registrationHelperUrl != null) { diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/accesscontrol/DefaultAccountProviderAccessControlTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/accesscontrol/DefaultAccountProviderAccessControlTest.kt index f559c57bf0..c5ace5ca3f 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/accesscontrol/DefaultAccountProviderAccessControlTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/accesscontrol/DefaultAccountProviderAccessControlTest.kt @@ -16,6 +16,7 @@ import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER_2 import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER_URL import io.element.android.libraries.wellknown.api.ElementWellKnown +import io.element.android.libraries.wellknown.api.WellknownRetrieverResult import kotlinx.coroutines.test.runTest import org.junit.Assert.assertThrows import org.junit.Test @@ -155,7 +156,13 @@ class DefaultAccountProviderAccessControlTest { defaultHomeserverListResult = { allowedAccountProviders }, ), wellknownRetriever = FakeWellknownRetriever( - getElementWellKnownResult = { elementWellKnown }, + getElementWellKnownResult = { + if (elementWellKnown == null) { + WellknownRetrieverResult.NotFound + } else { + WellknownRetrieverResult.Success(elementWellKnown) + } + }, ), ) diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerPresenterTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerPresenterTest.kt index 620df9bba4..3b88ab03c0 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerPresenterTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerPresenterTest.kt @@ -23,6 +23,7 @@ import io.element.android.libraries.matrix.test.A_HOMESERVER_URL import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService import io.element.android.libraries.wellknown.api.ElementWellKnown import io.element.android.libraries.wellknown.api.WellknownRetriever +import io.element.android.libraries.wellknown.api.WellknownRetrieverResult import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value @@ -114,9 +115,11 @@ class ChangeServerPresenterTest { @Test fun `present - change server element pro required error`() = runTest { - val getElementWellKnownResult = lambdaRecorder { - anElementWellKnown( - enforceElementPro = true, + val getElementWellKnownResult = lambdaRecorder> { + WellknownRetrieverResult.Success( + anElementWellKnown( + enforceElementPro = true, + ) ) } createPresenter( diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/searchaccountprovider/SearchAccountProviderPresenterTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/searchaccountprovider/SearchAccountProviderPresenterTest.kt index b679c92ee1..79cd3c954a 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/searchaccountprovider/SearchAccountProviderPresenterTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/searchaccountprovider/SearchAccountProviderPresenterTest.kt @@ -18,6 +18,7 @@ import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.matrix.test.A_HOMESERVER_URL import io.element.android.libraries.wellknown.api.WellKnown import io.element.android.libraries.wellknown.api.WellKnownBaseConfig +import io.element.android.libraries.wellknown.api.WellknownRetrieverResult import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value @@ -94,12 +95,12 @@ class SearchAccountProviderPresenterTest { @Test fun `present - enter text one result with wellknown`() = runTest { - val getWellKnownResult = lambdaRecorder { + val getWellKnownResult = lambdaRecorder> { when (it) { - "https://test.org" -> error("not found") - "https://test.com" -> error("not found") - "https://test.io" -> aWellKnown() - "https://test" -> error("not found") + "https://test.org" -> WellknownRetrieverResult.NotFound + "https://test.com" -> WellknownRetrieverResult.NotFound + "https://test.io" -> WellknownRetrieverResult.Success(aWellKnown()) + "https://test" -> WellknownRetrieverResult.NotFound else -> error("should not happen") } } @@ -138,12 +139,12 @@ class SearchAccountProviderPresenterTest { @Test fun `present - enter text two results with wellknown`() = runTest { - val getWellKnownResult = lambdaRecorder { + val getWellKnownResult = lambdaRecorder> { when (it) { - "https://test.org" -> aWellKnown() - "https://test.com" -> error("not found") - "https://test.io" -> aWellKnown() - "https://test" -> error("not found") + "https://test.org" -> WellknownRetrieverResult.Success(aWellKnown()) + "https://test.com" -> WellknownRetrieverResult.NotFound + "https://test.io" -> WellknownRetrieverResult.Success(aWellKnown()) + "https://test" -> WellknownRetrieverResult.NotFound else -> error("should not happen") } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt index 4408deab1e..ccb4c48e7e 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt @@ -164,7 +164,7 @@ class RoomDetailsPresenter( val securityAndPrivacyPermissions = room.securityAndPrivacyPermissionsAsState(syncUpdateFlow.value) val canShowSecurityAndPrivacy by remember { derivedStateOf { - isKnockRequestsEnabled && roomType is RoomDetailsType.Room && securityAndPrivacyPermissions.value.hasAny + roomType is RoomDetailsType.Room && securityAndPrivacyPermissions.value.hasAny } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenter.kt index abc0ff72af..4ff45bb588 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenter.kt @@ -27,6 +27,8 @@ import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState import io.element.android.libraries.architecture.runUpdatingState +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.core.RoomAlias import io.element.android.libraries.matrix.api.room.JoinedRoom @@ -45,6 +47,7 @@ class SecurityAndPrivacyPresenter( @Assisted private val navigator: SecurityAndPrivacyNavigator, private val matrixClient: MatrixClient, private val room: JoinedRoom, + private val featureFlagService: FeatureFlagService, ) : Presenter { @AssistedFactory interface Factory { @@ -55,6 +58,9 @@ class SecurityAndPrivacyPresenter( override fun present(): SecurityAndPrivacyState { val coroutineScope = rememberCoroutineScope() + val isKnockEnabled by remember { + featureFlagService.isFeatureEnabledFlow(FeatureFlags.Knock) + }.collectAsState(false) val saveAction = remember { mutableStateOf>(AsyncAction.Uninitialized) } val homeserverName = remember { matrixClient.userIdServerName() } val syncUpdateFlow = room.syncUpdateFlow.collectAsState() @@ -149,6 +155,7 @@ class SecurityAndPrivacyPresenter( editedSettings = editedSettings, homeserverName = homeserverName, showEnableEncryptionConfirmation = showEnableEncryptionConfirmation, + isKnockEnabled = isKnockEnabled, saveAction = saveAction.value, permissions = permissions, eventSink = ::handleEvents diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyState.kt index eb22ec2597..dbc0125abb 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyState.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyState.kt @@ -19,6 +19,7 @@ data class SecurityAndPrivacyState( val editedSettings: SecurityAndPrivacySettings, val homeserverName: String, val showEnableEncryptionConfirmation: Boolean, + val isKnockEnabled: Boolean, val saveAction: AsyncAction, private val permissions: SecurityAndPrivacyPermissions, val eventSink: (SecurityAndPrivacyEvents) -> Unit diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyStateProvider.kt index 00001ff69d..8964ee59c5 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyStateProvider.kt @@ -30,7 +30,8 @@ open class SecurityAndPrivacyStateProvider : PreviewParameterProvider Unit = {} ) = SecurityAndPrivacyState( editedSettings = editedSettings, @@ -90,6 +98,7 @@ fun aSecurityAndPrivacyState( homeserverName = homeserverName, showEnableEncryptionConfirmation = showEncryptionConfirmation, saveAction = saveAction, + isKnockEnabled = isKnockEnabled, permissions = permissions, eventSink = eventSink ) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyView.kt index c46f8a7a6f..7428763dd8 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyView.kt @@ -81,6 +81,7 @@ fun SecurityAndPrivacyView( modifier = Modifier.padding(top = 24.dp), edited = state.editedSettings.roomAccess, saved = state.savedSettings.roomAccess, + isKnockEnabled = state.isKnockEnabled, onSelectOption = { state.eventSink(SecurityAndPrivacyEvents.ChangeRoomAccess(it)) }, ) } @@ -176,6 +177,7 @@ private fun SecurityAndPrivacySection( private fun RoomAccessSection( edited: SecurityAndPrivacyRoomAccess, saved: SecurityAndPrivacyRoomAccess, + isKnockEnabled: Boolean, onSelectOption: (SecurityAndPrivacyRoomAccess) -> Unit, modifier: Modifier = Modifier, ) { @@ -189,12 +191,18 @@ private fun RoomAccessSection( trailingContent = ListItemContent.RadioButton(selected = edited == SecurityAndPrivacyRoomAccess.InviteOnly), onClick = { onSelectOption(SecurityAndPrivacyRoomAccess.InviteOnly) }, ) - ListItem( - headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_ask_to_join_option_title)) }, - supportingContent = { Text(text = stringResource(R.string.screen_security_and_privacy_ask_to_join_option_description)) }, - trailingContent = ListItemContent.RadioButton(selected = edited == SecurityAndPrivacyRoomAccess.AskToJoin), - onClick = { onSelectOption(SecurityAndPrivacyRoomAccess.AskToJoin) }, - ) + // Show Ask to join option in two cases: + // - the Knock FF is enabled + // - AskToJoin is the current saved value + if (saved == SecurityAndPrivacyRoomAccess.AskToJoin || isKnockEnabled) { + ListItem( + headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_ask_to_join_option_title)) }, + supportingContent = { Text(text = stringResource(R.string.screen_security_and_privacy_ask_to_join_option_description)) }, + trailingContent = ListItemContent.RadioButton(selected = edited == SecurityAndPrivacyRoomAccess.AskToJoin), + onClick = { onSelectOption(SecurityAndPrivacyRoomAccess.AskToJoin) }, + enabled = isKnockEnabled, + ) + } ListItem( headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_anyone_option_title)) }, supportingContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_anyone_option_description)) }, diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt index 695168aa16..27adc6cb44 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt @@ -719,10 +719,6 @@ class RoomDetailsPresenterTest { val presenter = createRoomDetailsPresenter(room = room, featureFlagService = featureFlagService) presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) { skipItems(1) - with(awaitItem()) { - assertThat(canShowSecurityAndPrivacy).isFalse() - } - featureFlagService.setFeatureEnabled(FeatureFlags.Knock, true) with(awaitItem()) { assertThat(canShowSecurityAndPrivacy).isTrue() } diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenterTest.kt index bc2a3f62f7..10df56e639 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenterTest.kt @@ -10,6 +10,9 @@ package io.element.android.features.roomdetails.impl.securityandprivacy import com.google.common.truth.Truth.assertThat import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncData +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.room.history.RoomHistoryVisibility import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility @@ -38,6 +41,7 @@ class SecurityAndPrivacyPresenterTest { assertThat(showRoomVisibilitySections).isFalse() assertThat(showHistoryVisibilitySection).isFalse() assertThat(showEncryptionSection).isFalse() + assertThat(isKnockEnabled).isFalse() } with(awaitItem()) { assertThat(editedSettings).isEqualTo(savedSettings) @@ -48,6 +52,7 @@ class SecurityAndPrivacyPresenterTest { assertThat(showRoomVisibilitySections).isFalse() assertThat(showHistoryVisibilitySection).isTrue() assertThat(showEncryptionSection).isTrue() + assertThat(isKnockEnabled).isFalse() } } } @@ -56,14 +61,14 @@ class SecurityAndPrivacyPresenterTest { fun `present - room info change updates saved and edited settings`() = runTest { val room = FakeJoinedRoom( baseRoom = FakeBaseRoom( - canSendStateResult = { _, _ -> Result.success(true) }, - initialRoomInfo = aRoomInfo( - joinRule = JoinRule.Public, - historyVisibility = RoomHistoryVisibility.WorldReadable, - canonicalAlias = A_ROOM_ALIAS, + canSendStateResult = { _, _ -> Result.success(true) }, + initialRoomInfo = aRoomInfo( + joinRule = JoinRule.Public, + historyVisibility = RoomHistoryVisibility.WorldReadable, + canonicalAlias = A_ROOM_ALIAS, + ) ) ) - ) val presenter = createSecurityAndPrivacyPresenter(room = room) presenter.test { skipItems(1) @@ -163,10 +168,10 @@ class SecurityAndPrivacyPresenterTest { fun `present - room visibility loading and change`() = runTest { val room = FakeJoinedRoom( baseRoom = FakeBaseRoom( - canSendStateResult = { _, _ -> Result.success(true) }, - getRoomVisibilityResult = { Result.success(RoomVisibility.Private) }, - initialRoomInfo = aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared) - ) + canSendStateResult = { _, _ -> Result.success(true) }, + getRoomVisibilityResult = { Result.success(RoomVisibility.Private) }, + initialRoomInfo = aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared) + ) ) val presenter = createSecurityAndPrivacyPresenter(room = room) presenter.test { @@ -212,10 +217,10 @@ class SecurityAndPrivacyPresenterTest { val updateRoomHistoryVisibilityLambda = lambdaRecorder> { Result.success(Unit) } val room = FakeJoinedRoom( baseRoom = FakeBaseRoom( - canSendStateResult = { _, _ -> Result.success(true) }, - getRoomVisibilityResult = { Result.success(RoomVisibility.Private) }, - initialRoomInfo = aRoomInfo(joinRule = JoinRule.Invite, historyVisibility = RoomHistoryVisibility.Shared) - ), + canSendStateResult = { _, _ -> Result.success(true) }, + getRoomVisibilityResult = { Result.success(RoomVisibility.Private) }, + initialRoomInfo = aRoomInfo(joinRule = JoinRule.Invite, historyVisibility = RoomHistoryVisibility.Shared) + ), enableEncryptionResult = enableEncryptionLambda, updateJoinRuleResult = updateJoinRuleLambda, updateRoomVisibilityResult = updateRoomVisibilityLambda, @@ -279,10 +284,10 @@ class SecurityAndPrivacyPresenterTest { val updateRoomHistoryVisibilityLambda = lambdaRecorder> { Result.success(Unit) } val room = FakeJoinedRoom( baseRoom = FakeBaseRoom( - canSendStateResult = { _, _ -> Result.success(true) }, - getRoomVisibilityResult = { Result.success(RoomVisibility.Private) }, - initialRoomInfo = aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, joinRule = JoinRule.Private) - ), + canSendStateResult = { _, _ -> Result.success(true) }, + getRoomVisibilityResult = { Result.success(RoomVisibility.Private) }, + initialRoomInfo = aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, joinRule = JoinRule.Private) + ), enableEncryptionResult = enableEncryptionLambda, updateJoinRuleResult = updateJoinRuleLambda, updateRoomVisibilityResult = updateRoomVisibilityLambda, @@ -323,7 +328,8 @@ class SecurityAndPrivacyPresenterTest { ) // Saved settings are updated 2 times to match the edited settings skipItems(3) - with(awaitItem()) { + val state = awaitItem() + with(state) { assertThat(saveAction).isInstanceOf(AsyncAction.Failure::class.java) assertThat(savedSettings.isVisibleInRoomDirectory).isNotEqualTo(editedSettings.isVisibleInRoomDirectory) assertThat(canBeSaved).isTrue() @@ -332,6 +338,26 @@ class SecurityAndPrivacyPresenterTest { assert(updateJoinRuleLambda).isCalledOnce() assert(updateRoomVisibilityLambda).isCalledOnce() assert(updateRoomHistoryVisibilityLambda).isCalledOnce() + // Clear error + state.eventSink(SecurityAndPrivacyEvents.DismissSaveError) + with(awaitItem()) { + assertThat(saveAction).isEqualTo(AsyncAction.Uninitialized) + } + } + } + + @Test + fun `present - isKnockEnabled is true if the Knock feature flag is enabled`() = runTest { + val presenter = createSecurityAndPrivacyPresenter( + featureFlagService = FakeFeatureFlagService( + initialState = mapOf( + FeatureFlags.Knock.key to true, + ) + ) + ) + presenter.test { + assertThat(awaitItem().isKnockEnabled).isFalse() + assertThat(awaitItem().isKnockEnabled).isTrue() } } @@ -345,13 +371,15 @@ class SecurityAndPrivacyPresenterTest { ), ), navigator: SecurityAndPrivacyNavigator = FakeSecurityAndPrivacyNavigator(), + featureFlagService: FeatureFlagService = FakeFeatureFlagService(), ): SecurityAndPrivacyPresenter { return SecurityAndPrivacyPresenter( room = room, matrixClient = FakeMatrixClient( userIdServerNameLambda = { serverName }, ), - navigator = navigator + navigator = navigator, + featureFlagService = featureFlagService, ) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ff4309c833..e61114bc65 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,7 +20,7 @@ lifecycle = "2.9.2" activity = "1.11.0" media3 = "1.8.0" camera = "1.5.1" -work = "2.10.5" +work = "2.11.0" # Compose compose_bom = "2025.07.00" @@ -210,7 +210,7 @@ haze_materials = { module = "dev.chrisbanes.haze:haze-materials", version.ref = color_picker = "io.mhssn:colorpicker:1.0.0" # Analytics -posthog = "com.posthog:posthog-android:3.24.0" +posthog = "com.posthog:posthog-android:3.25.0" sentry = "io.sentry:sentry-android:8.24.0" # main branch can be tested replacing the version with main-SNAPSHOT matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.28.0" diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/previews/CompoundIconsPreview.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/previews/CompoundIconsPreview.kt index 0ee0546ca4..f4aa54d77b 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/previews/CompoundIconsPreview.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/previews/CompoundIconsPreview.kt @@ -41,13 +41,13 @@ import io.element.android.compound.tokens.generated.CompoundIcons import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList -@Preview(widthDp = 730, heightDp = 1800) +@Preview(widthDp = 730, heightDp = 1920) @Composable internal fun IconsCompoundPreviewLight() = ElementTheme { IconsCompoundPreview() } -@Preview(widthDp = 730, heightDp = 1800) +@Preview(widthDp = 730, heightDp = 1920) @Composable internal fun IconsCompoundPreviewRtl() = ElementTheme { CompositionLocalProvider( @@ -59,7 +59,7 @@ internal fun IconsCompoundPreviewRtl() = ElementTheme { } } -@Preview(widthDp = 730, heightDp = 1800) +@Preview(widthDp = 730, heightDp = 1920) @Composable internal fun IconsCompoundPreviewDark() = ElementTheme(darkTheme = true) { IconsCompoundPreview() diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/icons/IconsList.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/icons/IconsList.kt index ff98ab5b1e..b9911e25a8 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/icons/IconsList.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/icons/IconsList.kt @@ -15,4 +15,5 @@ internal val iconsOther = listOf( R.drawable.ic_notification, R.drawable.ic_stop, R.drawable.pin, + R.drawable.ic_winner, ) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/icons/IconsPreview.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/icons/IconsPreview.kt index e2da9bdcc0..73300d2cdf 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/icons/IconsPreview.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/icons/IconsPreview.kt @@ -18,11 +18,8 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme -import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Icon @@ -30,53 +27,12 @@ import io.element.android.libraries.designsystem.theme.components.Text import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList -internal class CompoundIconChunkProvider : PreviewParameterProvider { - override val values: Sequence - get() { - val chunks = CompoundIcons.allResIds.chunked(36) - return chunks.mapIndexed { index, chunk -> - IconChunk(index = index + 1, total = chunks.size, icons = chunk.toImmutableList()) - } - .asSequence() - } -} - -internal class OtherIconChunkProvider : PreviewParameterProvider { - override val values: Sequence - get() { - val chunks = iconsOther.chunked(36) - return chunks.mapIndexed { index, chunk -> - IconChunk(index = index + 1, total = chunks.size, icons = chunk.toImmutableList()) - } - .asSequence() - } -} - -internal data class IconChunk( - val index: Int, - val total: Int, - val icons: ImmutableList, -) - @PreviewsDayNight @Composable -internal fun IconsCompoundPreview(@PreviewParameter(CompoundIconChunkProvider::class) chunk: IconChunk) = ElementPreview { +internal fun IconsOtherPreview() = ElementPreview { IconsPreview( - title = "R.drawable.ic_compound_* ${chunk.index}/${chunk.total}", - iconsList = chunk.icons, - iconNameTransform = { name -> - name.removePrefix("ic_compound_") - .replace("_", " ") - } - ) -} - -@PreviewsDayNight -@Composable -internal fun IconsOtherPreview(@PreviewParameter(OtherIconChunkProvider::class) iconChunk: IconChunk) = ElementPreview { - IconsPreview( - title = "R.drawable.ic_* ${iconChunk.index}/${iconChunk.total}", - iconsList = iconChunk.icons, + title = "Other icons", + iconsList = iconsOther.toImmutableList(), iconNameTransform = { name -> name.removePrefix("ic_") .replace("_", " ") diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index c646e2ee18..94a562c160 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -286,7 +286,7 @@ class RustMatrixClient( override suspend fun getUrl(url: String): Result = withContext(sessionDispatcher) { runCatchingExceptions { innerClient.getUrl(url) - } + }.mapFailure { it.mapClientException() } } override suspend fun getRoom(roomId: RoomId): BaseRoom? = withContext(sessionDispatcher) { diff --git a/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/SessionWellknownRetriever.kt b/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/SessionWellknownRetriever.kt index 7f7b9b983f..1c5570db94 100644 --- a/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/SessionWellknownRetriever.kt +++ b/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/SessionWellknownRetriever.kt @@ -8,6 +8,6 @@ package io.element.android.libraries.wellknown.api interface SessionWellknownRetriever { - suspend fun getWellKnown(): WellKnown? - suspend fun getElementWellKnown(): ElementWellKnown? + suspend fun getWellKnown(): WellknownRetrieverResult + suspend fun getElementWellKnown(): WellknownRetrieverResult } diff --git a/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/WellknownRetriever.kt b/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/WellknownRetriever.kt index e617bc8e13..4675a0cb18 100644 --- a/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/WellknownRetriever.kt +++ b/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/WellknownRetriever.kt @@ -8,6 +8,6 @@ package io.element.android.libraries.wellknown.api interface WellknownRetriever { - suspend fun getWellKnown(baseUrl: String): WellKnown? - suspend fun getElementWellKnown(baseUrl: String): ElementWellKnown? + suspend fun getWellKnown(baseUrl: String): WellknownRetrieverResult + suspend fun getElementWellKnown(baseUrl: String): WellknownRetrieverResult } diff --git a/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/WellknownRetrieverResult.kt b/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/WellknownRetrieverResult.kt new file mode 100644 index 0000000000..a094380b82 --- /dev/null +++ b/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/WellknownRetrieverResult.kt @@ -0,0 +1,31 @@ +/* + * 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.libraries.wellknown.api + +sealed interface WellknownRetrieverResult { + /** + * Well-known data has been successfully retrieved. + */ + data class Success(val data: T) : WellknownRetrieverResult + + /** + * Well-known data is not found (file does not exist server side, we got a 404). + */ + data object NotFound : WellknownRetrieverResult + + /** + * Any other error. + */ + data class Error(val exception: Exception) : WellknownRetrieverResult + + fun dataOrNull(): T? = when (this) { + is Success -> data + is Error -> null + NotFound -> null + } +} diff --git a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetriever.kt b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetriever.kt index 570b95679f..ad463bd2d2 100644 --- a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetriever.kt +++ b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetriever.kt @@ -12,9 +12,11 @@ import io.element.android.libraries.androidutils.json.JsonProvider import io.element.android.libraries.core.extensions.mapCatchingExceptions import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.matrix.api.exception.ClientException import io.element.android.libraries.wellknown.api.ElementWellKnown import io.element.android.libraries.wellknown.api.SessionWellknownRetriever import io.element.android.libraries.wellknown.api.WellKnown +import io.element.android.libraries.wellknown.api.WellknownRetrieverResult import timber.log.Timber @ContributesBinding(SessionScope::class) @@ -24,29 +26,40 @@ class DefaultSessionWellknownRetriever( ) : SessionWellknownRetriever { private val domain by lazy { matrixClient.userIdServerName() } - override suspend fun getWellKnown(): WellKnown? { + override suspend fun getWellKnown(): WellknownRetrieverResult { val url = "https://$domain/.well-known/matrix/client" return matrixClient .getUrl(url) .mapCatchingExceptions { val data = String(it) - json().decodeFromString(InternalWellKnown.serializer(), data) + json().decodeFromString(data).map() } - .onFailure { Timber.e(it, "Failed to retrieve .well-known from $domain") } - .map { it.map() } - .getOrNull() + .toWellknownRetrieverResult() } - override suspend fun getElementWellKnown(): ElementWellKnown? { + override suspend fun getElementWellKnown(): WellknownRetrieverResult { val url = "https://$domain/.well-known/element/element.json" return matrixClient .getUrl(url) .mapCatchingExceptions { val data = String(it) - json().decodeFromString(InternalElementWellKnown.serializer(), data) + json().decodeFromString(data).map() } - .onFailure { Timber.e(it, "Failed to retrieve Element .well-known from $domain") } - .map { it.map() } - .getOrNull() + .toWellknownRetrieverResult() } + + private fun Result.toWellknownRetrieverResult(): WellknownRetrieverResult = fold( + onSuccess = { + WellknownRetrieverResult.Success(it) + }, + onFailure = { + Timber.e(it, "Failed to retrieve Element .well-known from $domain") + // This check on message value is not ideal but this is what we got from the SDK. + if ((it as? ClientException.Generic)?.message?.contains("404") == true) { + WellknownRetrieverResult.NotFound + } else { + WellknownRetrieverResult.Error(it as Exception) + } + } + ) } diff --git a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellknownRetriever.kt b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellknownRetriever.kt index 65daf21f18..a6014f773c 100644 --- a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellknownRetriever.kt +++ b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellknownRetriever.kt @@ -9,45 +9,71 @@ package io.element.android.libraries.wellknown.impl import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding +import io.element.android.libraries.core.extensions.runCatchingExceptions import io.element.android.libraries.core.uri.ensureProtocol import io.element.android.libraries.network.RetrofitFactory import io.element.android.libraries.wellknown.api.ElementWellKnown import io.element.android.libraries.wellknown.api.WellKnown import io.element.android.libraries.wellknown.api.WellknownRetriever +import io.element.android.libraries.wellknown.api.WellknownRetrieverResult +import retrofit2.HttpException import timber.log.Timber +import java.net.HttpURLConnection @ContributesBinding(AppScope::class) class DefaultWellknownRetriever( private val retrofitFactory: RetrofitFactory, ) : WellknownRetriever { - override suspend fun getWellKnown(baseUrl: String): WellKnown? { - val wellknownApi = buildWellknownApi(baseUrl) ?: return null - return try { - wellknownApi.getWellKnown().map() - } catch (e: Exception) { - Timber.e(e, "Failed to retrieve well-known data for $baseUrl") - null - } + override suspend fun getWellKnown(baseUrl: String): WellknownRetrieverResult { + return buildWellknownApi(baseUrl) + .map { wellknownApi -> + try { + val result = wellknownApi.getWellKnown().map() + WellknownRetrieverResult.Success(result) + } catch (e: Exception) { + Timber.e(e, "Failed to retrieve well-known data for $baseUrl") + if ((e as? HttpException)?.code() == HttpURLConnection.HTTP_NOT_FOUND) { + WellknownRetrieverResult.NotFound + } else { + WellknownRetrieverResult.Error(e) + } + } + } + .fold( + onSuccess = { it }, + onFailure = { WellknownRetrieverResult.Error(it as Exception) } + ) } - override suspend fun getElementWellKnown(baseUrl: String): ElementWellKnown? { - val wellknownApi = buildWellknownApi(baseUrl) ?: return null - return try { - wellknownApi.getElementWellKnown().map() - } catch (e: Exception) { - Timber.e(e, "Failed to retrieve Element well-known data for $baseUrl") - null - } + override suspend fun getElementWellKnown(baseUrl: String): WellknownRetrieverResult { + return buildWellknownApi(baseUrl) + .map { wellknownApi -> + try { + val result = wellknownApi.getElementWellKnown().map() + WellknownRetrieverResult.Success(result) + } catch (e: Exception) { + // Is it a 404? + Timber.e(e, "Failed to retrieve Element well-known data for $baseUrl") + if ((e as? HttpException)?.code() == HttpURLConnection.HTTP_NOT_FOUND) { + WellknownRetrieverResult.NotFound + } else { + WellknownRetrieverResult.Error(e) + } + } + } + .fold( + onSuccess = { it }, + onFailure = { WellknownRetrieverResult.Error(it as Exception) } + ) } - private fun buildWellknownApi(accountProviderUrl: String): WellknownAPI? { - return try { + private fun buildWellknownApi(accountProviderUrl: String): Result { + return runCatchingExceptions { retrofitFactory.create(accountProviderUrl.ensureProtocol()) .create(WellknownAPI::class.java) - } catch (e: Exception) { + }.onFailure { e -> // If the base URL is not valid, we cannot retrieve the well-known data Timber.e(e, "Failed to create Retrofit instance for $accountProviderUrl") - null } } } diff --git a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt index 9356648a3a..12b961ff9e 100644 --- a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt +++ b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt @@ -14,6 +14,7 @@ import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.wellknown.api.ElementWellKnown import io.element.android.libraries.wellknown.api.WellKnown import io.element.android.libraries.wellknown.api.WellKnownBaseConfig +import io.element.android.libraries.wellknown.api.WellknownRetrieverResult import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value import kotlinx.coroutines.test.runTest @@ -29,9 +30,11 @@ class DefaultSessionWellknownRetrieverTest { getUrlLambda = getUrlLambda, ) assertThat(sut.getWellKnown()).isEqualTo( - WellKnown( - homeServer = null, - identityServer = null, + WellknownRetrieverResult.Success( + WellKnown( + homeServer = null, + identityServer = null, + ) ) ) getUrlLambda.assertions().isCalledOnce() @@ -55,13 +58,15 @@ class DefaultSessionWellknownRetrieverTest { } ) assertThat(sut.getWellKnown()).isEqualTo( - WellKnown( - homeServer = WellKnownBaseConfig( - baseURL = "https://example.org", - ), - identityServer = WellKnownBaseConfig( - baseURL = "https://identity.example.org", - ), + WellknownRetrieverResult.Success( + WellKnown( + homeServer = WellKnownBaseConfig( + baseURL = "https://example.org", + ), + identityServer = WellKnownBaseConfig( + baseURL = "https://identity.example.org", + ), + ) ) ) } @@ -81,13 +86,15 @@ class DefaultSessionWellknownRetrieverTest { } ) assertThat(sut.getWellKnown()).isEqualTo( - WellKnown( - homeServer = WellKnownBaseConfig( - baseURL = "https://example.org", - ), - identityServer = WellKnownBaseConfig( - baseURL = null, - ), + WellknownRetrieverResult.Success( + WellKnown( + homeServer = WellKnownBaseConfig( + baseURL = "https://example.org", + ), + identityServer = WellKnownBaseConfig( + baseURL = null, + ), + ) ) ) } @@ -110,13 +117,15 @@ class DefaultSessionWellknownRetrieverTest { }, ) assertThat(sut.getWellKnown()).isEqualTo( - WellKnown( - homeServer = WellKnownBaseConfig( - baseURL = "https://example.org", - ), - identityServer = WellKnownBaseConfig( - baseURL = "https://identity.example.org", - ), + WellknownRetrieverResult.Success( + WellKnown( + homeServer = WellKnownBaseConfig( + baseURL = "https://example.org", + ), + identityServer = WellKnownBaseConfig( + baseURL = "https://identity.example.org", + ), + ) ) ) } @@ -135,7 +144,7 @@ class DefaultSessionWellknownRetrieverTest { ) } ) - assertThat(sut.getWellKnown()).isNull() + assertThat(sut.getWellKnown()).isInstanceOf(WellknownRetrieverResult.Error::class.java) } @Test @@ -145,7 +154,7 @@ class DefaultSessionWellknownRetrieverTest { Result.failure(AN_EXCEPTION) } ) - assertThat(sut.getWellKnown()).isNull() + assertThat(sut.getWellKnown()).isInstanceOf(WellknownRetrieverResult.Error::class.java) } @Test @@ -157,11 +166,13 @@ class DefaultSessionWellknownRetrieverTest { getUrlLambda = getUrlLambda, ) assertThat(sut.getElementWellKnown()).isEqualTo( - ElementWellKnown( - registrationHelperUrl = null, - enforceElementPro = null, - rageshakeUrl = null, - brandColor = null, + WellknownRetrieverResult.Success( + ElementWellKnown( + registrationHelperUrl = null, + enforceElementPro = null, + rageshakeUrl = null, + brandColor = null, + ) ) ) getUrlLambda.assertions().isCalledOnce() @@ -183,11 +194,13 @@ class DefaultSessionWellknownRetrieverTest { } ) assertThat(sut.getElementWellKnown()).isEqualTo( - ElementWellKnown( - registrationHelperUrl = "a_registration_url", - enforceElementPro = true, - rageshakeUrl = "a_rageshake_url", - brandColor = "#FF0000", + WellknownRetrieverResult.Success( + ElementWellKnown( + registrationHelperUrl = "a_registration_url", + enforceElementPro = true, + rageshakeUrl = "a_rageshake_url", + brandColor = "#FF0000", + ) ) ) } @@ -207,11 +220,13 @@ class DefaultSessionWellknownRetrieverTest { }, ) assertThat(sut.getElementWellKnown()).isEqualTo( - ElementWellKnown( - registrationHelperUrl = "a_registration_url", - enforceElementPro = true, - rageshakeUrl = "a_rageshake_url", - brandColor = null, + WellknownRetrieverResult.Success( + ElementWellKnown( + registrationHelperUrl = "a_registration_url", + enforceElementPro = true, + rageshakeUrl = "a_rageshake_url", + brandColor = null, + ) ) ) } @@ -228,7 +243,7 @@ class DefaultSessionWellknownRetrieverTest { ) } ) - assertThat(sut.getElementWellKnown()).isNull() + assertThat(sut.getElementWellKnown()).isInstanceOf(WellknownRetrieverResult.Error::class.java) } @Test @@ -238,7 +253,7 @@ class DefaultSessionWellknownRetrieverTest { Result.failure(AN_EXCEPTION) } ) - assertThat(sut.getElementWellKnown()).isNull() + assertThat(sut.getElementWellKnown()).isInstanceOf(WellknownRetrieverResult.Error::class.java) } private fun createDefaultSessionWellknownRetriever( diff --git a/libraries/wellknown/test/src/main/kotlin/io/element/android/features/wellknown/test/FakeSessionWellknownRetriever.kt b/libraries/wellknown/test/src/main/kotlin/io/element/android/features/wellknown/test/FakeSessionWellknownRetriever.kt index 6c2c141622..d90a02ac96 100644 --- a/libraries/wellknown/test/src/main/kotlin/io/element/android/features/wellknown/test/FakeSessionWellknownRetriever.kt +++ b/libraries/wellknown/test/src/main/kotlin/io/element/android/features/wellknown/test/FakeSessionWellknownRetriever.kt @@ -10,17 +10,18 @@ package io.element.android.features.wellknown.test import io.element.android.libraries.wellknown.api.ElementWellKnown import io.element.android.libraries.wellknown.api.SessionWellknownRetriever import io.element.android.libraries.wellknown.api.WellKnown +import io.element.android.libraries.wellknown.api.WellknownRetrieverResult import io.element.android.tests.testutils.simulateLongTask class FakeSessionWellknownRetriever( - private val getWellKnownResult: () -> WellKnown? = { null }, - private val getElementWellKnownResult: () -> ElementWellKnown? = { null }, + private val getWellKnownResult: () -> WellknownRetrieverResult = { WellknownRetrieverResult.NotFound }, + private val getElementWellKnownResult: () -> WellknownRetrieverResult = { WellknownRetrieverResult.NotFound }, ) : SessionWellknownRetriever { - override suspend fun getWellKnown(): WellKnown? = simulateLongTask { + override suspend fun getWellKnown(): WellknownRetrieverResult = simulateLongTask { getWellKnownResult() } - override suspend fun getElementWellKnown(): ElementWellKnown? = simulateLongTask { + override suspend fun getElementWellKnown(): WellknownRetrieverResult = simulateLongTask { getElementWellKnownResult() } } diff --git a/libraries/wellknown/test/src/main/kotlin/io/element/android/features/wellknown/test/FakeWellknownRetriever.kt b/libraries/wellknown/test/src/main/kotlin/io/element/android/features/wellknown/test/FakeWellknownRetriever.kt index c8bbbde26d..52bb1cfa4c 100644 --- a/libraries/wellknown/test/src/main/kotlin/io/element/android/features/wellknown/test/FakeWellknownRetriever.kt +++ b/libraries/wellknown/test/src/main/kotlin/io/element/android/features/wellknown/test/FakeWellknownRetriever.kt @@ -10,17 +10,18 @@ package io.element.android.features.wellknown.test import io.element.android.libraries.wellknown.api.ElementWellKnown import io.element.android.libraries.wellknown.api.WellKnown import io.element.android.libraries.wellknown.api.WellknownRetriever +import io.element.android.libraries.wellknown.api.WellknownRetrieverResult import io.element.android.tests.testutils.simulateLongTask class FakeWellknownRetriever( - private val getWellKnownResult: (String) -> WellKnown? = { null }, - private val getElementWellKnownResult: (String) -> ElementWellKnown? = { null }, + private val getWellKnownResult: (String) -> WellknownRetrieverResult = { WellknownRetrieverResult.NotFound }, + private val getElementWellKnownResult: (String) -> WellknownRetrieverResult = { WellknownRetrieverResult.NotFound }, ) : WellknownRetriever { - override suspend fun getWellKnown(baseUrl: String): WellKnown? = simulateLongTask { + override suspend fun getWellKnown(baseUrl: String): WellknownRetrieverResult = simulateLongTask { getWellKnownResult(baseUrl) } - override suspend fun getElementWellKnown(baseUrl: String): ElementWellKnown? = simulateLongTask { + override suspend fun getElementWellKnown(baseUrl: String): WellknownRetrieverResult = simulateLongTask { getElementWellKnownResult(baseUrl) } } diff --git a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt index 941fde0124..8120e2ff2e 100644 --- a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt +++ b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt @@ -86,7 +86,6 @@ class KonsistPreviewTest { "FocusedEventPreview", "GradientFloatingActionButtonCircleShapePreview", "HeaderFooterPageScrollablePreview", - "IconsCompoundPreview", "IconsOtherPreview", "MarkdownTextComposerEditPreview", "MatrixBadgeAtomInfoPreview", diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_3_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_3_en.png index 8b30aa7bf4..ee9db33a17 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d627cd374fe0746d2fc84fffecf6a1636fb68784ed5edae3b830fe4ee2b3751a -size 61398 +oid sha256:9807bf17918c39f2e6e4cddf87237fa26f63732f48210b0f803114bcf4c98451 +size 61360 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_9_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_9_en.png new file mode 100644 index 0000000000..2456c5ce5e --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewDark_9_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1ad13a47522e6365928e7209e515a47a7e4fafc28ad87361dffdf92c95b3ff06 +size 62563 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_3_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_3_en.png index bf00730127..d1d6c2f15e 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:70979d3b81a521b6208da2f3a95187bc7b3ae0ea52e3dd35e2bbd91df14c007f -size 63318 +oid sha256:ade5d824f6f466960931abcbc86cb9a286cbf6bd9a3adf875f446dc094e291d5 +size 63393 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_9_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_9_en.png new file mode 100644 index 0000000000..d646d3d526 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.securityandprivacy_SecurityAndPrivacyViewLight_9_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f2cfda5b044d11e4e75fa83c9bad7b7f03a328422881cbededfaee8ab091d1db +size 64586 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_0_en.png deleted file mode 100644 index 761c7dbe49..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_0_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5c68e00a3f0697a9f179fe8541876fbd371da1d8b55e72c02fbb92d64814863a -size 67653 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_1_en.png deleted file mode 100644 index 40bafedca7..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_1_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0332e0bbea7856b02adb7a660c758a313235351891428fdfb1816d0fa26df4d6 -size 68540 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_2_en.png deleted file mode 100644 index a7a65b89fb..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_2_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4c798bec96147f50016dad808d51de76c24339a8b9afe0119993dadd7dbff845 -size 73047 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_3_en.png deleted file mode 100644 index 0458ab3442..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_3_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5cf492cd78477c2ce4c296fb6baa2af8baed6549fb51f58c06da9d4181aa8ac9 -size 73796 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_4_en.png deleted file mode 100644 index 091df51555..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_4_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a3ab14628f86c883effa49f51c02255a96a0050a9b4261322b2cf596ed5298ed -size 73233 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_5_en.png deleted file mode 100644 index 06fe965ca2..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Day_5_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f2151c4bbd49af17c8af90b946c94ec40b3f51edd25157abc5e87e1b4f7b7922 -size 53698 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_0_en.png deleted file mode 100644 index 30e8ec09d4..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_0_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:50113ec351ed12a7ee31b5b9333dabbcce242bf762d9d09d41301484e04f33ff -size 64549 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_1_en.png deleted file mode 100644 index 3098aa900e..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_1_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:78f6f70dbc14f5b035f6f7d3cc042328be0894771443f188c9bf5581e40bcf59 -size 65190 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_2_en.png deleted file mode 100644 index c9e430c3a8..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_2_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cab2c2d5b07a795080fc887c6c8776a9a8630d9b2f6e5fde7ebb9f5f462fc41c -size 69708 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_3_en.png deleted file mode 100644 index 8b1e249670..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_3_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ffb53277e999c57096a8d11a03b2835d30ba7f0e8b83db85d5d1a417bbe35502 -size 70680 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_4_en.png deleted file mode 100644 index 1e290d9420..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_4_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d21b4e71d6d52f1e9d844dbff96dcec86f5a04871b861ce0b619f173edca66cd -size 69772 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_5_en.png deleted file mode 100644 index 99c55da156..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsCompound_Night_5_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f209a674db2371d1e85ec2b6d92468f92595f6b87948db19dd7aba8432221b67 -size 51793 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsOther_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsOther_Day_0_en.png index 98b70f5c35..279c1855d5 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsOther_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsOther_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e71f4f5c0d8f299ff91699612604f5b285160f5830a2b1e3e0c4092e85bd8aa7 -size 14064 +oid sha256:49f3e81d0a713630723c463c8705463e1ba04266624f71d6e29cd7d3a693c115 +size 13789 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsOther_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsOther_Night_0_en.png index ed0853de74..e396168a4d 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsOther_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsOther_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e526b48b8f340e5e5c31e0e976286a5d64f27928d3cdf00b3175e5840bc494f3 -size 13282 +oid sha256:76ecf55d5a354374db7b9ac14fb64fae7637b35b2908efcf73163b514710fcb0 +size 13127