Merge pull request #6811 from element-hq/feature/live_location_remove_feature_flag

Remove LiveLocationSharing feature flag
This commit is contained in:
ganfra 2026-05-19 09:16:18 +02:00 committed by GitHub
commit 087e0fcd8c
6 changed files with 5 additions and 77 deletions

View file

@ -40,8 +40,6 @@ import io.element.android.libraries.architecture.runUpdatingState
import io.element.android.libraries.core.extensions.flatMap import io.element.android.libraries.core.extensions.flatMap
import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.dateformatter.api.DurationFormatter import io.element.android.libraries.dateformatter.api.DurationFormatter
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.MatrixClient
import io.element.android.libraries.matrix.api.room.CreateTimelineParams import io.element.android.libraries.matrix.api.room.CreateTimelineParams
import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.JoinedRoom
@ -66,7 +64,6 @@ class ShareLocationPresenter(
private val messageComposerContext: MessageComposerContext, private val messageComposerContext: MessageComposerContext,
private val locationActions: LocationActions, private val locationActions: LocationActions,
private val buildMeta: BuildMeta, private val buildMeta: BuildMeta,
private val featureFlagService: FeatureFlagService,
private val client: MatrixClient, private val client: MatrixClient,
private val durationFormatter: DurationFormatter, private val durationFormatter: DurationFormatter,
private val liveLocationShareManager: ActiveLiveLocationShareManager, private val liveLocationShareManager: ActiveLiveLocationShareManager,
@ -83,9 +80,6 @@ class ShareLocationPresenter(
override fun present(): ShareLocationState { override fun present(): ShareLocationState {
val permissionsState: PermissionsState = permissionsPresenter.present() val permissionsState: PermissionsState = permissionsPresenter.present()
var trackUserPosition: Boolean by remember { mutableStateOf(permissionsState.isAnyGranted && locationActions.isLocationEnabled()) } var trackUserPosition: Boolean by remember { mutableStateOf(permissionsState.isAnyGranted && locationActions.isLocationEnabled()) }
val isLiveLocationSharingEnabled by remember {
featureFlagService.isFeatureEnabledFlow(FeatureFlags.LiveLocationSharing)
}.collectAsState(false)
val appName by remember { derivedStateOf { buildMeta.applicationName } } val appName by remember { derivedStateOf { buildMeta.applicationName } }
var dialogState: ShareLocationState.Dialog by remember { var dialogState: ShareLocationState.Dialog by remember {
mutableStateOf(ShareLocationState.Dialog.None) mutableStateOf(ShareLocationState.Dialog.None)
@ -171,7 +165,7 @@ class ShareLocationPresenter(
dialogState = dialogState, dialogState = dialogState,
trackUserLocation = trackUserPosition, trackUserLocation = trackUserPosition,
hasLocationPermission = permissionsState.isAnyGranted, hasLocationPermission = permissionsState.isAnyGranted,
canShareLiveLocation = isLiveLocationSharingEnabled && timelineMode.canShareLiveLocation(), canShareLiveLocation = timelineMode.canShareLiveLocation(),
appName = appName, appName = appName,
startLiveLocationAction = startLiveLocationAction.value, startLiveLocationAction = startLiveLocationAction.value,
eventSink = ::handleEvent, eventSink = ::handleEvent,

View file

@ -17,7 +17,6 @@ import io.element.android.features.location.impl.live.LiveLocationStore
import io.element.android.features.location.test.FakeActiveLiveLocationShareManager import io.element.android.features.location.test.FakeActiveLiveLocationShareManager
import io.element.android.features.messages.test.FakeMessageComposerContext import io.element.android.features.messages.test.FakeMessageComposerContext
import io.element.android.libraries.dateformatter.test.FakeDurationFormatter import io.element.android.libraries.dateformatter.test.FakeDurationFormatter
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.Timeline
import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.core.aBuildMeta import io.element.android.libraries.matrix.test.core.aBuildMeta
@ -50,7 +49,6 @@ class DefaultShareLocationEntryPointTest {
messageComposerContext = FakeMessageComposerContext(), messageComposerContext = FakeMessageComposerContext(),
locationActions = FakeLocationActions(), locationActions = FakeLocationActions(),
buildMeta = aBuildMeta(), buildMeta = aBuildMeta(),
featureFlagService = FakeFeatureFlagService(),
client = FakeMatrixClient(), client = FakeMatrixClient(),
durationFormatter = FakeDurationFormatter(), durationFormatter = FakeDurationFormatter(),
liveLocationShareManager = FakeActiveLiveLocationShareManager(), liveLocationShareManager = FakeActiveLiveLocationShareManager(),

View file

@ -29,8 +29,6 @@ import io.element.android.features.location.impl.live.LiveLocationStore
import io.element.android.features.location.test.FakeActiveLiveLocationShareManager import io.element.android.features.location.test.FakeActiveLiveLocationShareManager
import io.element.android.features.messages.test.FakeMessageComposerContext import io.element.android.features.messages.test.FakeMessageComposerContext
import io.element.android.libraries.dateformatter.test.FakeDurationFormatter import io.element.android.libraries.dateformatter.test.FakeDurationFormatter
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.EventId
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.SessionId import io.element.android.libraries.matrix.api.core.SessionId
@ -77,7 +75,6 @@ class ShareLocationPresenterTest {
private val fakeMessageComposerContext = FakeMessageComposerContext() private val fakeMessageComposerContext = FakeMessageComposerContext()
private val fakeLocationActions = FakeLocationActions() private val fakeLocationActions = FakeLocationActions()
private val fakeBuildMeta = aBuildMeta(applicationName = "app name") private val fakeBuildMeta = aBuildMeta(applicationName = "app name")
private val fakeFeatureFlagService = FakeFeatureFlagService()
private val fakeMatrixClient = FakeMatrixClient(sessionId = A_USER_ID) private val fakeMatrixClient = FakeMatrixClient(sessionId = A_USER_ID)
private val durationFormatter = FakeDurationFormatter() private val durationFormatter = FakeDurationFormatter()
@ -96,7 +93,6 @@ class ShareLocationPresenterTest {
messageComposerContext = fakeMessageComposerContext, messageComposerContext = fakeMessageComposerContext,
locationActions = locationActions, locationActions = locationActions,
buildMeta = fakeBuildMeta, buildMeta = fakeBuildMeta,
featureFlagService = fakeFeatureFlagService,
client = fakeMatrixClient, client = fakeMatrixClient,
durationFormatter = durationFormatter, durationFormatter = durationFormatter,
liveLocationShareManager = liveLocationShareManager, liveLocationShareManager = liveLocationShareManager,
@ -658,21 +654,7 @@ class ShareLocationPresenterTest {
} }
@Test @Test
fun `canShareLiveLocation is false when the feature is disabled`() = runTest { fun `canShareLiveLocation is true in live timeline`() = runTest {
fakeFeatureFlagService.setFeatureEnabled(FeatureFlags.LiveLocationSharing, false)
val shareLocationPresenter = createShareLocationPresenter(
timelineMode = Timeline.Mode.Live,
)
shareLocationPresenter.test {
skipItems(1)
val state = awaitItem()
assertThat(state.canShareLiveLocation).isFalse()
}
}
@Test
fun `canShareLiveLocation is true when the feature is enabled`() = runTest {
fakeFeatureFlagService.setFeatureEnabled(FeatureFlags.LiveLocationSharing, true)
val shareLocationPresenter = createShareLocationPresenter( val shareLocationPresenter = createShareLocationPresenter(
timelineMode = Timeline.Mode.Live, timelineMode = Timeline.Mode.Live,
) )
@ -685,7 +667,6 @@ class ShareLocationPresenterTest {
@Test @Test
fun `canShareLiveLocation is false in thread timeline`() = runTest { fun `canShareLiveLocation is false in thread timeline`() = runTest {
fakeFeatureFlagService.setFeatureEnabled(FeatureFlags.LiveLocationSharing, true)
val shareLocationPresenter = createShareLocationPresenter( val shareLocationPresenter = createShareLocationPresenter(
timelineMode = Timeline.Mode.Thread(A_THREAD_ID), timelineMode = Timeline.Mode.Thread(A_THREAD_ID),
) )

View file

@ -25,11 +25,8 @@ import io.element.android.libraries.preferences.api.store.AppPreferencesStore
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@Inject @Inject
@ -56,17 +53,8 @@ class AdvancedSettingsPresenter(
appPreferencesStore.getThemeFlow().mapToTheme(isBlackThemeAllowed) appPreferencesStore.getThemeFlow().mapToTheme(isBlackThemeAllowed)
}.collectAsState(initial = Theme.System) }.collectAsState(initial = Theme.System)
@OptIn(ExperimentalCoroutinesApi::class)
val liveLocationMinimumDistanceUpdate by produceState<Int?>(null) { val liveLocationMinimumDistanceUpdate by produceState<Int?>(null) {
featureFlagService.isFeatureEnabledFlow(FeatureFlags.LiveLocationSharing) appPreferencesStore.getLiveLocationMinimumDistanceInMetersUpdateFlow().collect { value = it }
.flatMapLatest { isEnabled ->
if (isEnabled) {
appPreferencesStore.getLiveLocationMinimumDistanceInMetersUpdateFlow()
} else {
emptyFlow()
}
}
.collect { value = it }
} }
val mediaPreviewConfigState = mediaPreviewConfigStateStore.state() val mediaPreviewConfigState = mediaPreviewConfigStateStore.state()

View file

@ -210,35 +210,12 @@ class AdvancedSettingsPresenterTest {
} }
} }
@Test
fun `present - live location minimum distance is null when feature is disabled`() = runTest {
val appPreferencesStore = InMemoryAppPreferencesStore(
liveLocationMinimumDistanceUpdate = 50,
)
val featureFlagService = FakeFeatureFlagService().apply {
setFeatureEnabled(FeatureFlags.LiveLocationSharing, false)
}
val presenter = createAdvancedSettingsPresenter(appPreferencesStore = appPreferencesStore, featureFlagService = featureFlagService)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
skipItems(1)
with(awaitItem()) {
assertThat(liveLocationMinimumDistanceUpdate).isNull()
}
}
}
@Test @Test
fun `present - exposes live location minimum distance from app preferences`() = runTest { fun `present - exposes live location minimum distance from app preferences`() = runTest {
val appPreferencesStore = InMemoryAppPreferencesStore( val appPreferencesStore = InMemoryAppPreferencesStore(
liveLocationMinimumDistanceUpdate = 50, liveLocationMinimumDistanceUpdate = 50,
) )
val featureFlagService = FakeFeatureFlagService().apply { val presenter = createAdvancedSettingsPresenter(appPreferencesStore = appPreferencesStore)
setFeatureEnabled(FeatureFlags.LiveLocationSharing, true)
}
val presenter = createAdvancedSettingsPresenter(appPreferencesStore = appPreferencesStore, featureFlagService = featureFlagService)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
@ -256,10 +233,7 @@ class AdvancedSettingsPresenterTest {
val appPreferencesStore = InMemoryAppPreferencesStore( val appPreferencesStore = InMemoryAppPreferencesStore(
liveLocationMinimumDistanceUpdate = 10, liveLocationMinimumDistanceUpdate = 10,
) )
val featureFlagService = FakeFeatureFlagService().apply { val presenter = createAdvancedSettingsPresenter(appPreferencesStore = appPreferencesStore)
setFeatureEnabled(FeatureFlags.LiveLocationSharing, true)
}
val presenter = createAdvancedSettingsPresenter(appPreferencesStore = appPreferencesStore, featureFlagService = featureFlagService)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()

View file

@ -100,13 +100,6 @@ enum class FeatureFlags(
defaultValue = { false }, defaultValue = { false },
isFinished = false, isFinished = false,
), ),
LiveLocationSharing(
key = "feature.liveLocationSharing",
title = "Live location sharing",
description = "Allow sharing live location in rooms.",
defaultValue = { false },
isFinished = false,
),
ValidateNetworkWhenSchedulingNotificationFetching( ValidateNetworkWhenSchedulingNotificationFetching(
key = "feature.validate_network_when_scheduling_notification_fetching", key = "feature.validate_network_when_scheduling_notification_fetching",
title = "Validate internet connectivity when scheduling notification fetching", title = "Validate internet connectivity when scheduling notification fetching",