Remove RoomDirectorySearch feature flag — always enable the feature (#6736)

* Remove RoomDirectorySearch feature flag, always enable the feature

Co-authored-by: stefanceriu <637564+stefanceriu@users.noreply.github.com>

* Apply ktlint formatting

Co-authored-by: jmartinesp <480955+jmartinesp@users.noreply.github.com>

* Update screenshots

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: stefanceriu <637564+stefanceriu@users.noreply.github.com>
Co-authored-by: jmartinesp <480955+jmartinesp@users.noreply.github.com>
Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
Copilot
2026-05-06 16:05:19 +02:00
committed by GitHub
parent 9b91fabbd6
commit 6ef9315468
17 changed files with 18 additions and 100 deletions
@@ -25,10 +25,7 @@ import io.element.android.features.rageshake.api.preferences.RageshakePreference
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.extensions.runCatchingExceptions import io.element.android.libraries.core.extensions.runCatchingExceptions
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.ui.model.FeatureUiModel import io.element.android.libraries.featureflag.ui.model.FeatureUiModel
import io.element.android.libraries.preferences.api.store.AppPreferencesStore import io.element.android.libraries.preferences.api.store.AppPreferencesStore
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
@@ -45,7 +42,6 @@ class AppDeveloperSettingsPresenter(
private val featureFlagService: FeatureFlagService, private val featureFlagService: FeatureFlagService,
private val rageshakePresenter: Presenter<RageshakePreferencesState>, private val rageshakePresenter: Presenter<RageshakePreferencesState>,
private val appPreferencesStore: AppPreferencesStore, private val appPreferencesStore: AppPreferencesStore,
private val buildMeta: BuildMeta,
) : Presenter<AppDeveloperSettingsState> { ) : Presenter<AppDeveloperSettingsState> {
@Composable @Composable
override fun present(): AppDeveloperSettingsState { override fun present(): AppDeveloperSettingsState {
@@ -71,14 +67,6 @@ class AppDeveloperSettingsPresenter(
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
featureFlagService.getAvailableFeatures() featureFlagService.getAvailableFeatures()
.run {
// Never display room directory search in release builds for Play Store
if (buildMeta.flavorDescription == "GooglePlay" && buildMeta.buildType == BuildType.RELEASE) {
filterNot { it.key == FeatureFlags.RoomDirectorySearch.key }
} else {
this
}
}
.forEach { feature -> .forEach { feature ->
enabledFeatures.add(EnabledFeature(feature, featureFlagService.isFeatureEnabled(feature))) enabledFeatures.add(EnabledFeature(feature, featureFlagService.isFeatureEnabled(feature)))
} }
@@ -13,13 +13,9 @@ import com.google.common.truth.Truth.assertThat
import io.element.android.features.preferences.impl.developer.tracing.LogLevelItem import io.element.android.features.preferences.impl.developer.tracing.LogLevelItem
import io.element.android.features.rageshake.api.preferences.aRageshakePreferencesState import io.element.android.features.rageshake.api.preferences.aRageshakePreferencesState
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.featureflag.api.Feature import io.element.android.libraries.featureflag.api.Feature
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.test.FakeFeature import io.element.android.libraries.featureflag.test.FakeFeature
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.matrix.test.core.aBuildMeta
import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore
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.lambdaRecorder
@@ -68,18 +64,6 @@ class AppDeveloperSettingsPresenterTest {
} }
} }
@Test
fun `present - ensures Room directory search is not present on release Google Play builds`() = runTest {
val buildMeta = aBuildMeta(buildType = BuildType.RELEASE, flavorDescription = "GooglePlay")
val presenter = createAppDeveloperSettingsPresenter(buildMeta = buildMeta)
presenter.test {
skipItems(1)
awaitItem().also { state ->
assertThat(state.features).doesNotContain(FeatureFlags.RoomDirectorySearch)
}
}
}
@Test @Test
fun `present - ensures state is updated when enabled feature event is triggered`() = runTest { fun `present - ensures state is updated when enabled feature event is triggered`() = runTest {
val presenter = createAppDeveloperSettingsPresenter() val presenter = createAppDeveloperSettingsPresenter()
@@ -156,13 +140,11 @@ class AppDeveloperSettingsPresenterTest {
} }
), ),
preferencesStore: InMemoryAppPreferencesStore = InMemoryAppPreferencesStore(), preferencesStore: InMemoryAppPreferencesStore = InMemoryAppPreferencesStore(),
buildMeta: BuildMeta = aBuildMeta(),
): AppDeveloperSettingsPresenter { ): AppDeveloperSettingsPresenter {
return AppDeveloperSettingsPresenter( return AppDeveloperSettingsPresenter(
featureFlagService = featureFlagService, featureFlagService = featureFlagService,
rageshakePresenter = { aRageshakePreferencesState() }, rageshakePresenter = { aRageshakePreferencesState() },
appPreferencesStore = preferencesStore, appPreferencesStore = preferencesStore,
buildMeta = buildMeta,
) )
} }
} }
@@ -10,8 +10,6 @@ package io.element.android.features.startchat.impl.root
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
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
@@ -24,8 +22,6 @@ import io.element.android.features.startchat.impl.userlist.UserListPresenterArgs
import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.meta.BuildMeta 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.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.usersearch.api.UserRepository import io.element.android.libraries.usersearch.api.UserRepository
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -37,7 +33,6 @@ class StartChatPresenter(
userListDataStore: UserListDataStore, userListDataStore: UserListDataStore,
private val startDMAction: StartDMAction, private val startDMAction: StartDMAction,
private val buildMeta: BuildMeta, private val buildMeta: BuildMeta,
private val featureFlagService: FeatureFlagService,
) : Presenter<StartChatState> { ) : Presenter<StartChatState> {
private val presenter = presenterFactory.create( private val presenter = presenterFactory.create(
UserListPresenterArgs( UserListPresenterArgs(
@@ -54,10 +49,6 @@ class StartChatPresenter(
val localCoroutineScope = rememberCoroutineScope() val localCoroutineScope = rememberCoroutineScope()
val startDmActionState: MutableState<AsyncAction<RoomId>> = remember { mutableStateOf(AsyncAction.Uninitialized) } val startDmActionState: MutableState<AsyncAction<RoomId>> = remember { mutableStateOf(AsyncAction.Uninitialized) }
val isRoomDirectorySearchEnabled by remember {
featureFlagService.isFeatureEnabledFlow(FeatureFlags.RoomDirectorySearch)
}.collectAsState(initial = false)
fun handleEvent(event: StartChatEvents) { fun handleEvent(event: StartChatEvents) {
when (event) { when (event) {
is StartChatEvents.StartDM -> localCoroutineScope.launch { is StartChatEvents.StartDM -> localCoroutineScope.launch {
@@ -75,7 +66,6 @@ class StartChatPresenter(
applicationName = buildMeta.applicationName, applicationName = buildMeta.applicationName,
userListState = userListState, userListState = userListState,
startDmAction = startDmActionState.value, startDmAction = startDmActionState.value,
isRoomDirectorySearchEnabled = isRoomDirectorySearchEnabled,
eventSink = ::handleEvent, eventSink = ::handleEvent,
) )
} }
@@ -16,6 +16,5 @@ data class StartChatState(
val applicationName: String, val applicationName: String,
val userListState: UserListState, val userListState: UserListState,
val startDmAction: AsyncAction<RoomId>, val startDmAction: AsyncAction<RoomId>,
val isRoomDirectorySearchEnabled: Boolean,
val eventSink: (StartChatEvents) -> Unit, val eventSink: (StartChatEvents) -> Unit,
) )
@@ -55,9 +55,6 @@ open class StartChatStateProvider : PreviewParameterProvider<StartChatState> {
aCreateRoomRootState( aCreateRoomRootState(
startDmAction = aConfirmingStartDmWithMatrixUser() startDmAction = aConfirmingStartDmWithMatrixUser()
), ),
aCreateRoomRootState(
isRoomDirectorySearchEnabled = true,
),
) )
} }
@@ -75,12 +72,10 @@ fun aCreateRoomRootState(
applicationName: String = "Element X Preview", applicationName: String = "Element X Preview",
userListState: UserListState = aUserListState(), userListState: UserListState = aUserListState(),
startDmAction: AsyncAction<RoomId> = AsyncAction.Uninitialized, startDmAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
isRoomDirectorySearchEnabled: Boolean = false,
eventSink: (StartChatEvents) -> Unit = {}, eventSink: (StartChatEvents) -> Unit = {},
) = StartChatState( ) = StartChatState(
applicationName = applicationName, applicationName = applicationName,
userListState = userListState, userListState = userListState,
startDmAction = startDmAction, startDmAction = startDmAction,
isRoomDirectorySearchEnabled = isRoomDirectorySearchEnabled,
eventSink = eventSink, eventSink = eventSink,
) )
@@ -176,14 +176,12 @@ private fun CreateRoomActionButtonsList(
onClick = onNewRoomClick, onClick = onNewRoomClick,
) )
} }
if (state.isRoomDirectorySearchEnabled) { item {
item { CreateRoomActionButton(
CreateRoomActionButton( iconRes = CompoundDrawables.ic_compound_list_bulleted,
iconRes = CompoundDrawables.ic_compound_list_bulleted, text = stringResource(id = R.string.screen_room_directory_search_title),
text = stringResource(id = R.string.screen_room_directory_search_title), onClick = onRoomDirectorySearchClick,
onClick = onRoomDirectorySearchClick, )
)
}
} }
item { item {
CreateRoomActionButton( CreateRoomActionButton(
@@ -17,8 +17,6 @@ import io.element.android.features.startchat.impl.userlist.FakeUserListPresenter
import io.element.android.features.startchat.impl.userlist.FakeUserListPresenterFactory import io.element.android.features.startchat.impl.userlist.FakeUserListPresenterFactory
import io.element.android.features.startchat.impl.userlist.UserListDataStore import io.element.android.features.startchat.impl.userlist.UserListDataStore
import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
@@ -155,34 +153,16 @@ class StartChatPresenterTest {
) )
} }
} }
@Test
fun `present - room directory search`() = runTest {
val presenter = createStartChatPresenter(isRoomDirectorySearchEnabled = true)
presenter.test {
skipItems(1)
awaitItem().let { state ->
assertThat(state.isRoomDirectorySearchEnabled).isTrue()
}
}
}
} }
internal fun createStartChatPresenter( internal fun createStartChatPresenter(
startDMAction: StartDMAction = FakeStartDMAction(), startDMAction: StartDMAction = FakeStartDMAction(),
isRoomDirectorySearchEnabled: Boolean = false,
): StartChatPresenter { ): StartChatPresenter {
val featureFlagService = FakeFeatureFlagService(
initialState = mapOf(
FeatureFlags.RoomDirectorySearch.key to isRoomDirectorySearchEnabled,
),
)
return StartChatPresenter( return StartChatPresenter(
presenterFactory = FakeUserListPresenterFactory(FakeUserListPresenter()), presenterFactory = FakeUserListPresenterFactory(FakeUserListPresenter()),
userRepository = FakeUserRepository(), userRepository = FakeUserRepository(),
userListDataStore = UserListDataStore(), userListDataStore = UserListDataStore(),
startDMAction = startDMAction, startDMAction = startDMAction,
featureFlagService = featureFlagService,
buildMeta = aBuildMeta(), buildMeta = aBuildMeta(),
) )
} }
@@ -123,7 +123,6 @@ class StartChatViewTest {
setStartChatView( setStartChatView(
aCreateRoomRootState( aCreateRoomRootState(
eventSink = eventsRecorder, eventSink = eventsRecorder,
isRoomDirectorySearchEnabled = true
), ),
onRoomDirectorySearchClick = it onRoomDirectorySearchClick = it
) )
@@ -22,13 +22,6 @@ enum class FeatureFlags(
override val isFinished: Boolean, override val isFinished: Boolean,
override val isInLabs: Boolean = false, override val isInLabs: Boolean = false,
) : Feature { ) : Feature {
RoomDirectorySearch(
key = "feature.roomdirectorysearch",
title = "Room directory search",
description = "Allow user to search for public rooms in their homeserver",
defaultValue = { false },
isFinished = false,
),
ShowBlockedUsersDetails( ShowBlockedUsersDetails(
key = "feature.showBlockedUsersDetails", key = "feature.showBlockedUsersDetails",
title = "Show blocked users details", title = "Show blocked users details",
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:bf3add28f315b5f7de06dbdf5b6d5fb96552f648a95a620e50b65fa970de32dd oid sha256:657e469b19b815ad54ef7ccd6a140d33031301de504690cb520c482f469fa8c4
size 41513 size 38559
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:81be06688e135d746d30140e61aa168f0d7bfecad1a12e54d9d26e3eb55be0be oid sha256:02a03b83eaf866a7a65ec26f57fa810a08ad7128d11d2db6ad203bf405a1bb05
size 39897 size 37097