Reduce FeatureFlags Knock effect on room creation and room edition form.
Closes #6701
This commit is contained in:
parent
4975f61eb8
commit
206c3b7dac
7 changed files with 10 additions and 59 deletions
|
|
@ -33,9 +33,7 @@ dependencies {
|
||||||
implementation(projects.libraries.matrixui)
|
implementation(projects.libraries.matrixui)
|
||||||
implementation(projects.libraries.uiStrings)
|
implementation(projects.libraries.uiStrings)
|
||||||
implementation(projects.libraries.designsystem)
|
implementation(projects.libraries.designsystem)
|
||||||
implementation(projects.libraries.featureflag.api)
|
|
||||||
|
|
||||||
testCommonDependencies(libs, true)
|
testCommonDependencies(libs, true)
|
||||||
testImplementation(projects.libraries.matrix.test)
|
testImplementation(projects.libraries.matrix.test)
|
||||||
testImplementation(projects.libraries.featureflag.test)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,6 @@ import dev.zacsweers.metro.SingleIn
|
||||||
import io.element.android.features.knockrequests.api.KnockRequestPermissions
|
import io.element.android.features.knockrequests.api.KnockRequestPermissions
|
||||||
import io.element.android.features.knockrequests.api.knockRequestPermissions
|
import io.element.android.features.knockrequests.api.knockRequestPermissions
|
||||||
import io.element.android.libraries.di.RoomScope
|
import io.element.android.libraries.di.RoomScope
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsFlow
|
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsFlow
|
||||||
|
|
||||||
|
|
@ -25,14 +23,13 @@ import io.element.android.libraries.matrix.api.room.powerlevels.permissionsFlow
|
||||||
object KnockRequestsModule {
|
object KnockRequestsModule {
|
||||||
@Provides
|
@Provides
|
||||||
@SingleIn(RoomScope::class)
|
@SingleIn(RoomScope::class)
|
||||||
fun knockRequestsService(room: JoinedRoom, featureFlagService: FeatureFlagService): KnockRequestsService {
|
fun knockRequestsService(room: JoinedRoom): KnockRequestsService {
|
||||||
return KnockRequestsService(
|
return KnockRequestsService(
|
||||||
knockRequestsFlow = room.knockRequestsFlow,
|
knockRequestsFlow = room.knockRequestsFlow,
|
||||||
permissionsFlow = room.permissionsFlow(KnockRequestPermissions.DEFAULT) { perms ->
|
permissionsFlow = room.permissionsFlow(KnockRequestPermissions.DEFAULT) { perms ->
|
||||||
perms.knockRequestPermissions()
|
perms.knockRequestPermissions()
|
||||||
},
|
},
|
||||||
isKnockFeatureEnabledFlow = featureFlagService.isFeatureEnabledFlow(FeatureFlags.Knock),
|
coroutineScope = room.roomCoroutineScope,
|
||||||
coroutineScope = room.roomCoroutineScope
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import io.element.android.features.knockrequests.api.KnockRequestPermissions
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
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.room.knock.KnockRequest
|
import io.element.android.libraries.matrix.api.room.knock.KnockRequest
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
|
|
@ -28,26 +27,20 @@ import kotlinx.coroutines.supervisorScope
|
||||||
class KnockRequestsService(
|
class KnockRequestsService(
|
||||||
knockRequestsFlow: Flow<List<KnockRequest>>,
|
knockRequestsFlow: Flow<List<KnockRequest>>,
|
||||||
permissionsFlow: Flow<KnockRequestPermissions>,
|
permissionsFlow: Flow<KnockRequestPermissions>,
|
||||||
isKnockFeatureEnabledFlow: Flow<Boolean>,
|
|
||||||
coroutineScope: CoroutineScope,
|
coroutineScope: CoroutineScope,
|
||||||
) {
|
) {
|
||||||
// Keep track of the knock requests that have been handled, so we don't have to wait for sync to remove them.
|
// Keep track of the knock requests that have been handled, so we don't have to wait for sync to remove them.
|
||||||
private val handledKnockRequestIds = MutableStateFlow<Set<EventId>>(emptySet())
|
private val handledKnockRequestIds = MutableStateFlow<Set<EventId>>(emptySet())
|
||||||
|
|
||||||
val knockRequestsFlow = combine(
|
val knockRequestsFlow = combine(
|
||||||
isKnockFeatureEnabledFlow,
|
|
||||||
knockRequestsFlow,
|
knockRequestsFlow,
|
||||||
handledKnockRequestIds,
|
handledKnockRequestIds,
|
||||||
) { isKnockEnabled, knockRequests, handledKnockIds ->
|
) { knockRequests, handledKnockIds ->
|
||||||
if (!isKnockEnabled) {
|
val presentableKnockRequests = knockRequests
|
||||||
AsyncData.Success(persistentListOf())
|
.filter { it.eventId !in handledKnockIds }
|
||||||
} else {
|
.map { inner -> KnockRequestWrapper(inner) }
|
||||||
val presentableKnockRequests = knockRequests
|
.toImmutableList()
|
||||||
.filter { it.eventId !in handledKnockIds }
|
AsyncData.Success(presentableKnockRequests)
|
||||||
.map { inner -> KnockRequestWrapper(inner) }
|
|
||||||
.toImmutableList()
|
|
||||||
AsyncData.Success(presentableKnockRequests)
|
|
||||||
}
|
|
||||||
}.stateIn(coroutineScope, SharingStarted.Lazily, AsyncData.Loading())
|
}.stateIn(coroutineScope, SharingStarted.Lazily, AsyncData.Loading())
|
||||||
|
|
||||||
val permissionsFlow = permissionsFlow.stateIn(
|
val permissionsFlow = permissionsFlow.stateIn(
|
||||||
|
|
|
||||||
|
|
@ -28,18 +28,6 @@ import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class) class KnockRequestsBannerPresenterTest {
|
@OptIn(ExperimentalCoroutinesApi::class) class KnockRequestsBannerPresenterTest {
|
||||||
@Test
|
|
||||||
fun `present - when feature is disabled then the banner should be hidden`() = runTest {
|
|
||||||
val knockRequests = flowOf(listOf(FakeKnockRequest()))
|
|
||||||
val presenter = createKnockRequestsBannerPresenter(isFeatureEnabled = false, knockRequestsFlow = knockRequests)
|
|
||||||
presenter.test {
|
|
||||||
skipItems(1)
|
|
||||||
awaitItem().also { state ->
|
|
||||||
assertThat(state.isVisible).isFalse()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - when empty knock request list then the banner should be hidden`() = runTest {
|
fun `present - when empty knock request list then the banner should be hidden`() = runTest {
|
||||||
val knockRequests = flowOf(emptyList<KnockRequest>())
|
val knockRequests = flowOf(emptyList<KnockRequest>())
|
||||||
|
|
@ -229,12 +217,10 @@ import org.junit.Test
|
||||||
private fun TestScope.createKnockRequestsBannerPresenter(
|
private fun TestScope.createKnockRequestsBannerPresenter(
|
||||||
knockRequestsFlow: Flow<List<KnockRequest>> = flowOf(emptyList()),
|
knockRequestsFlow: Flow<List<KnockRequest>> = flowOf(emptyList()),
|
||||||
canAcceptKnockRequests: Boolean = true,
|
canAcceptKnockRequests: Boolean = true,
|
||||||
isFeatureEnabled: Boolean = true,
|
|
||||||
): KnockRequestsBannerPresenter {
|
): KnockRequestsBannerPresenter {
|
||||||
val knockRequestsService = KnockRequestsService(
|
val knockRequestsService = KnockRequestsService(
|
||||||
knockRequestsFlow = knockRequestsFlow,
|
knockRequestsFlow = knockRequestsFlow,
|
||||||
coroutineScope = backgroundScope,
|
coroutineScope = backgroundScope,
|
||||||
isKnockFeatureEnabledFlow = flowOf(isFeatureEnabled),
|
|
||||||
permissionsFlow = flowOf(KnockRequestPermissions(canAcceptKnockRequests, canAcceptKnockRequests, canAcceptKnockRequests)),
|
permissionsFlow = flowOf(KnockRequestPermissions(canAcceptKnockRequests, canAcceptKnockRequests, canAcceptKnockRequests)),
|
||||||
)
|
)
|
||||||
return KnockRequestsBannerPresenter(
|
return KnockRequestsBannerPresenter(
|
||||||
|
|
|
||||||
|
|
@ -298,7 +298,6 @@ internal fun TestScope.createKnockRequestsListPresenter(
|
||||||
val knockRequestsService = KnockRequestsService(
|
val knockRequestsService = KnockRequestsService(
|
||||||
knockRequestsFlow = knockRequestsFlow,
|
knockRequestsFlow = knockRequestsFlow,
|
||||||
coroutineScope = backgroundScope,
|
coroutineScope = backgroundScope,
|
||||||
isKnockFeatureEnabledFlow = flowOf(true),
|
|
||||||
permissionsFlow = flowOf(KnockRequestPermissions(canAccept, canDecline, canBan)),
|
permissionsFlow = flowOf(KnockRequestPermissions(canAccept, canDecline, canBan)),
|
||||||
)
|
)
|
||||||
return KnockRequestsListPresenter(knockRequestsService = knockRequestsService)
|
return KnockRequestsListPresenter(knockRequestsService = knockRequestsService)
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,6 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||||
import io.element.android.libraries.designsystem.utils.snackbar.LocalSnackbarDispatcher
|
import io.element.android.libraries.designsystem.utils.snackbar.LocalSnackbarDispatcher
|
||||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
|
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
|
||||||
import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState
|
import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState
|
||||||
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.encryption.identity.IdentityState
|
import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
|
||||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||||
|
|
@ -61,7 +59,6 @@ import kotlinx.coroutines.launch
|
||||||
class RoomDetailsPresenter(
|
class RoomDetailsPresenter(
|
||||||
private val client: MatrixClient,
|
private val client: MatrixClient,
|
||||||
private val room: JoinedRoom,
|
private val room: JoinedRoom,
|
||||||
private val featureFlagService: FeatureFlagService,
|
|
||||||
private val notificationSettingsService: NotificationSettingsService,
|
private val notificationSettingsService: NotificationSettingsService,
|
||||||
private val roomMembersDetailsPresenterFactory: RoomMemberDetailsPresenter.Factory,
|
private val roomMembersDetailsPresenterFactory: RoomMemberDetailsPresenter.Factory,
|
||||||
private val leaveRoomPresenter: Presenter<LeaveRoomState>,
|
private val leaveRoomPresenter: Presenter<LeaveRoomState>,
|
||||||
|
|
@ -110,14 +107,11 @@ class RoomDetailsPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val isKnockRequestsEnabled by remember {
|
|
||||||
featureFlagService.isFeatureEnabledFlow(FeatureFlags.Knock)
|
|
||||||
}.collectAsState(false)
|
|
||||||
val knockRequestsCount by produceState<Int?>(null) {
|
val knockRequestsCount by produceState<Int?>(null) {
|
||||||
room.knockRequestsFlow.collect { value = it.size }
|
room.knockRequestsFlow.collect { value = it.size }
|
||||||
}
|
}
|
||||||
val canShowKnockRequests by remember {
|
val canShowKnockRequests by remember {
|
||||||
derivedStateOf { isKnockRequestsEnabled && permissions.knockRequestsPermissions.hasAny && joinRule == JoinRule.Knock }
|
derivedStateOf { permissions.knockRequestsPermissions.hasAny && joinRule == JoinRule.Knock }
|
||||||
}
|
}
|
||||||
val canShowSecurityAndPrivacy by remember {
|
val canShowSecurityAndPrivacy by remember {
|
||||||
derivedStateOf { !isDm && permissions.securityAndPrivacyPermissions.hasAny(isSpace = false, joinRule = joinRule) }
|
derivedStateOf { !isDm && permissions.securityAndPrivacyPermissions.hasAny(isSpace = false, joinRule = joinRule) }
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,6 @@ import io.element.android.libraries.androidutils.clipboard.ClipboardHelper
|
||||||
import io.element.android.libraries.androidutils.clipboard.FakeClipboardHelper
|
import io.element.android.libraries.androidutils.clipboard.FakeClipboardHelper
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||||
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.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
||||||
|
|
@ -80,11 +77,6 @@ class RoomDetailsPresenterTest {
|
||||||
dispatchers: CoroutineDispatchers = testCoroutineDispatchers(),
|
dispatchers: CoroutineDispatchers = testCoroutineDispatchers(),
|
||||||
notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(),
|
notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(),
|
||||||
analyticsService: AnalyticsService = FakeAnalyticsService(),
|
analyticsService: AnalyticsService = FakeAnalyticsService(),
|
||||||
featureFlagService: FeatureFlagService = FakeFeatureFlagService(
|
|
||||||
mapOf(
|
|
||||||
FeatureFlags.Knock.key to false,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
encryptionService: FakeEncryptionService = FakeEncryptionService(),
|
encryptionService: FakeEncryptionService = FakeEncryptionService(),
|
||||||
clipboardHelper: ClipboardHelper = FakeClipboardHelper(),
|
clipboardHelper: ClipboardHelper = FakeClipboardHelper(),
|
||||||
appPreferencesStore: AppPreferencesStore = InMemoryAppPreferencesStore()
|
appPreferencesStore: AppPreferencesStore = InMemoryAppPreferencesStore()
|
||||||
|
|
@ -106,7 +98,6 @@ class RoomDetailsPresenterTest {
|
||||||
return RoomDetailsPresenter(
|
return RoomDetailsPresenter(
|
||||||
client = matrixClient,
|
client = matrixClient,
|
||||||
room = room,
|
room = room,
|
||||||
featureFlagService = featureFlagService,
|
|
||||||
notificationSettingsService = matrixClient.notificationSettingsService,
|
notificationSettingsService = matrixClient.notificationSettingsService,
|
||||||
roomMembersDetailsPresenterFactory = roomMemberDetailsPresenterFactory,
|
roomMembersDetailsPresenterFactory = roomMemberDetailsPresenterFactory,
|
||||||
leaveRoomPresenter = { leaveRoomState },
|
leaveRoomPresenter = { leaveRoomState },
|
||||||
|
|
@ -564,17 +555,11 @@ class RoomDetailsPresenterTest {
|
||||||
roomPermissions = roomPermissions(),
|
roomPermissions = roomPermissions(),
|
||||||
joinRule = JoinRule.Knock,
|
joinRule = JoinRule.Knock,
|
||||||
)
|
)
|
||||||
val featureFlagService = FakeFeatureFlagService(
|
|
||||||
mapOf(FeatureFlags.Knock.key to false)
|
|
||||||
)
|
|
||||||
val presenter = createRoomDetailsPresenter(
|
val presenter = createRoomDetailsPresenter(
|
||||||
room = room,
|
room = room,
|
||||||
featureFlagService = featureFlagService,
|
|
||||||
)
|
)
|
||||||
presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) {
|
presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) {
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
assertThat(awaitItem().canShowKnockRequests).isFalse()
|
|
||||||
featureFlagService.setFeatureEnabled(FeatureFlags.Knock, true)
|
|
||||||
assertThat(awaitItem().canShowKnockRequests).isTrue()
|
assertThat(awaitItem().canShowKnockRequests).isTrue()
|
||||||
room.givenRoomInfo(aRoomInfo(joinRule = JoinRule.Invite))
|
room.givenRoomInfo(aRoomInfo(joinRule = JoinRule.Invite))
|
||||||
assertThat(awaitItem().canShowKnockRequests).isFalse()
|
assertThat(awaitItem().canShowKnockRequests).isFalse()
|
||||||
|
|
@ -587,8 +572,7 @@ class RoomDetailsPresenterTest {
|
||||||
val room = aJoinedRoom(
|
val room = aJoinedRoom(
|
||||||
roomPermissions = roomPermissions(),
|
roomPermissions = roomPermissions(),
|
||||||
)
|
)
|
||||||
val featureFlagService = FakeFeatureFlagService()
|
val presenter = createRoomDetailsPresenter(room = room)
|
||||||
val presenter = createRoomDetailsPresenter(room = room, featureFlagService = featureFlagService)
|
|
||||||
presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) {
|
presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) {
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
with(awaitItem()) {
|
with(awaitItem()) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue