<!-- Please read [CONTRIBUTING.md](https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md) before submitting your pull request -->

## Type of change

- [ ] Feature
- [x] Bugfix
- [ ] Technical
- [ ] Other :

## Content

Added a filter for the timeline items that removes 'hidden' or 'not visible' state events from the timeline.

## Motivation and context

Fixes #2216.

## Screenshots / GIFs

No changes in screenshots.

## Tests

- Create a new room or open a recently created one.

Instead of 7-8 state events you should only see 3-4 (created & joined room, room encrypted, invited another user).

## Tested devices

- [x] Physical
- [ ] Emulator
- OS version(s): 14

## Checklist

<!-- Depending on the Pull Request content, it can be acceptable if some of the following checkboxes stay unchecked. -->

- [ ] Changes have been tested on an Android device or Android emulator with API 23
- [ ] UI change has been tested on both light and dark themes
- [ ] Accessibility has been taken into account. See https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md#accessibility
- [x] Pull request is based on the develop branch
- [x] Pull request includes a new file under ./changelog.d. See https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md#changelog
- [ ] Pull request includes screenshots or videos if containing UI changes
- [ ] Pull request includes a [sign off](https://matrix-org.github.io/synapse/latest/development/contributing_guide.html#sign-off)
- [x] You've made a self review of your PR

Remove verbose state events from the timeline
When creating a room, we can see at least 7 state events being added to the timeline:

- Who created the room (`m.room.create`).
- The same person joining the room (`m.room.member` with membership `join`).
- The room power levels being set (`m.room.power_levels`).
- The room join rules being set up (`m.room.join_rules`).
- The room history visibility being set up (`m.room.history_visibility`).
- The room guest access being set up (`m.room.guest_access`).
- If encryption is enabled or disabled (`m.room.encryption`).

Plus any invites.

From those, we only want to display:

- Who created the room.
- Who joined the room.
- If encryption is enabled.
- The invites.

So we need to filter out the rest of the events from the timeline. Following iOS' implementation, this removal should be done globally in the timeline, not just for the few first items.

diff --git a/changelog.d/2216.bugfix b/changelog.d/2216.bugfix
new file mode 100644
index 00000000000..a47f2976b54
--- /dev/null
+++ b/changelog.d/2216.bugfix
@@ -0,0 +1,1 @@
+Hide verbose state events from the timeline
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt
index fc4840d6105..87e4f4ab73d 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt
@@ -85,7 +85,11 @@ data class ProfileChangeContent(
 data class StateContent(
     val stateKey: String,
     val content: OtherState
-) : EventContent
+) : EventContent {
+    fun isVisibleInTimeline(): Boolean {
+        return content.isVisibleInTimeline()
+    }
+}

 data class FailedToParseMessageLikeContent(
     val eventType: String,
diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/OtherState.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/OtherState.kt
index 6960b3565d2..e5119c388e0 100644
--- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/OtherState.kt
+++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/OtherState.kt
@@ -41,4 +41,30 @@ sealed interface OtherState {
     data object SpaceChild : OtherState
     data object SpaceParent : OtherState
     data class Custom(val eventType: String) : OtherState
+
+    fun isVisibleInTimeline() = when (this) {
+        // Visible
+        is RoomAvatar,
+        is RoomName,
+        is RoomTopic,
+        is RoomThirdPartyInvite,
+        is RoomCreate,
+        is RoomEncryption,
+        is Custom -> true
+        // Hidden
+        is RoomAliases,
+        is RoomCanonicalAlias,
+        is RoomGuestAccess,
+        is RoomHistoryVisibility,
+        is RoomJoinRules,
+        is RoomPinnedEvents,
+        is RoomPowerLevels,
+        is RoomServerAcl,
+        is RoomTombstone,
+        is SpaceChild,
+        is SpaceParent,
+        is PolicyRuleRoom,
+        is PolicyRuleServer,
+        is PolicyRuleUser -> false
+    }
 }
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt
index 80c8f1d391a..1841aa4b595 100644
--- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt
@@ -27,6 +27,7 @@ import io.element.android.libraries.matrix.impl.timeline.item.event.EventMessage
 import io.element.android.libraries.matrix.impl.timeline.item.event.EventTimelineItemMapper
 import io.element.android.libraries.matrix.impl.timeline.item.event.TimelineEventContentMapper
 import io.element.android.libraries.matrix.impl.timeline.item.virtual.VirtualTimelineItemMapper
+import io.element.android.libraries.matrix.impl.timeline.postprocessor.FilterHiddenStateEventsProcessor
 import io.element.android.libraries.matrix.impl.timeline.postprocessor.TimelineEncryptedHistoryPostProcessor
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.CoroutineDispatcher
@@ -82,6 +83,8 @@ class RustMatrixTimeline(
         dispatcher = dispatcher,
     )

+    private val filterHiddenStateEventsProcessor = FilterHiddenStateEventsProcessor()
+
     private val timelineItemFactory = MatrixTimelineItemMapper(
         fetchDetailsForEvent = this::fetchDetailsForEvent,
         roomCoroutineScope = roomCoroutineScope,
@@ -101,9 +104,9 @@ class RustMatrixTimeline(
     override val paginationState: StateFlow<MatrixTimeline.PaginationState> = _paginationState.asStateFlow()

     @OptIn(ExperimentalCoroutinesApi::class)
-    override val timelineItems: Flow<List<MatrixTimelineItem>> = _timelineItems.mapLatest { items ->
-        encryptedHistoryPostProcessor.process(items)
-    }
+    override val timelineItems: Flow<List<MatrixTimelineItem>> = _timelineItems
+        .mapLatest { items -> encryptedHistoryPostProcessor.process(items) }
+        .mapLatest { items -> filterHiddenStateEventsProcessor.process(items) }

     init {
         Timber.d("Initialize timeline for room ${matrixRoom.roomId}")
diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterHiddenStateEventsProcessor.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterHiddenStateEventsProcessor.kt
new file mode 100644
index 00000000000..c54221d84eb
--- /dev/null
+++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterHiddenStateEventsProcessor.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.matrix.impl.timeline.postprocessor
+
+import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
+import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
+
+/**
+ * This class is used to filter out 'hidden' state events from the timeline.
+ */
+class FilterHiddenStateEventsProcessor {
+    fun process(items: List<MatrixTimelineItem>): List<MatrixTimelineItem> {
+        return items.filter { item ->
+            when (item) {
+                is MatrixTimelineItem.Event -> {
+                    when (val content = item.event.content) {
+                        // If it's a state event, make sure it's visible
+                        is StateContent -> content.isVisibleInTimeline()
+                        // We can display any other event
+                        else -> true
+                    }
+                }
+                is MatrixTimelineItem.Virtual -> true
+                is MatrixTimelineItem.Other -> true
+            }
+        }
+    }
+}

diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterHiddenStateEventsProcessorTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterHiddenStateEventsProcessorTest.kt
new file mode 100644
index 00000000000..0532d1b7624
--- /dev/null
+++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterHiddenStateEventsProcessorTest.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2024 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.element.android.libraries.matrix.impl.timeline.postprocessor
+
+import com.google.common.truth.Truth.assertThat
+import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
+import io.element.android.libraries.matrix.api.timeline.item.event.OtherState
+import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
+import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem
+import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
+import org.junit.Test
+
+class FilterHiddenStateEventsProcessorTest {
+    @Test
+    fun test() {
+        val items = listOf(
+            // These are visible because they're not state events
+            MatrixTimelineItem.Other,
+            MatrixTimelineItem.Virtual("virtual", VirtualTimelineItem.ReadMarker),
+            MatrixTimelineItem.Event("event", anEventTimelineItem()),
+            // These are visible state events
+            MatrixTimelineItem.Event("m.room.avatar", anEventTimelineItem(content = StateContent("", OtherState.RoomAvatar("")))),
+            MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(content = StateContent("", OtherState.RoomCreate))),
+            MatrixTimelineItem.Event("m.room.encrypted", anEventTimelineItem(content = StateContent("", OtherState.RoomEncryption))),
+            MatrixTimelineItem.Event("m.room.name", anEventTimelineItem(content = StateContent("", OtherState.RoomName("")))),
+            MatrixTimelineItem.Event("m.room.third_party_invite", anEventTimelineItem(content = StateContent("", OtherState.RoomThirdPartyInvite("")))),
+            MatrixTimelineItem.Event("m.room.topic", anEventTimelineItem(content = StateContent("", OtherState.RoomTopic("")))),
+            MatrixTimelineItem.Event("m.room.custom", anEventTimelineItem(content = StateContent("", OtherState.Custom("")))),
+            // These ones are hidden
+            MatrixTimelineItem.Event("m.room.aliases", anEventTimelineItem(content = StateContent("", OtherState.RoomAliases))),
+            MatrixTimelineItem.Event("m.room.canonical_alias", anEventTimelineItem(content = StateContent("", OtherState.RoomCanonicalAlias))),
+            MatrixTimelineItem.Event("m.room.guest_access", anEventTimelineItem(content = StateContent("", OtherState.RoomGuestAccess))),
+            MatrixTimelineItem.Event("m.room.history_visibility", anEventTimelineItem(content = StateContent("", OtherState.RoomHistoryVisibility))),
+            MatrixTimelineItem.Event("m.room.join_rules", anEventTimelineItem(content = StateContent("", OtherState.RoomJoinRules))),
+            MatrixTimelineItem.Event("m.room.pinned_events", anEventTimelineItem(content = StateContent("", OtherState.RoomPinnedEvents))),
+            MatrixTimelineItem.Event("m.room.power_levels", anEventTimelineItem(content = StateContent("", OtherState.RoomPowerLevels))),
+            MatrixTimelineItem.Event("m.room.server_acl", anEventTimelineItem(content = StateContent("", OtherState.RoomServerAcl))),
+            MatrixTimelineItem.Event("m.room.tombstone", anEventTimelineItem(content = StateContent("", OtherState.RoomTombstone))),
+            MatrixTimelineItem.Event("m.space.child", anEventTimelineItem(content = StateContent("", OtherState.SpaceChild))),
+            MatrixTimelineItem.Event("m.space.parent", anEventTimelineItem(content = StateContent("", OtherState.SpaceParent))),
+            MatrixTimelineItem.Event("m.room.policy.rule.room", anEventTimelineItem(content = StateContent("", OtherState.PolicyRuleRoom))),
+            MatrixTimelineItem.Event("m.room.policy.rule.server", anEventTimelineItem(content = StateContent("", OtherState.PolicyRuleServer))),
+            MatrixTimelineItem.Event("m.room.policy.rule.user", anEventTimelineItem(content = StateContent("", OtherState.PolicyRuleUser))),
+        )
+
+        val expected = listOf(
+            MatrixTimelineItem.Other,
+            MatrixTimelineItem.Virtual("virtual", VirtualTimelineItem.ReadMarker),
+            MatrixTimelineItem.Event("event", anEventTimelineItem()),
+            MatrixTimelineItem.Event("m.room.avatar", anEventTimelineItem(content = StateContent("", OtherState.RoomAvatar("")))),
+            MatrixTimelineItem.Event("m.room.create", anEventTimelineItem(content = StateContent("", OtherState.RoomCreate))),
+            MatrixTimelineItem.Event("m.room.encrypted", anEventTimelineItem(content = StateContent("", OtherState.RoomEncryption))),
+            MatrixTimelineItem.Event("m.room.name", anEventTimelineItem(content = StateContent("", OtherState.RoomName("")))),
+            MatrixTimelineItem.Event("m.room.third_party_invite", anEventTimelineItem(content = StateContent("", OtherState.RoomThirdPartyInvite("")))),
+            MatrixTimelineItem.Event("m.room.topic", anEventTimelineItem(content = StateContent("", OtherState.RoomTopic("")))),
+            MatrixTimelineItem.Event("m.room.custom", anEventTimelineItem(content = StateContent("", OtherState.Custom("")))),
+        )
+
+        val processor = FilterHiddenStateEventsProcessor()
+
+        assertThat(processor.process(items)).isEqualTo(expected)
+    }
+}


<!-- Please read [CONTRIBUTING.md](https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md) before submitting your pull request -->

## Type of change

- [ ] Feature
- [x] Bugfix
- [ ] Technical
- [ ] Other :

## Content

Makes the room name, topic and avatar update with the `RoomInfo` contents.

## Motivation and context

Fixes #921  (the issue name is a bit misleading).

## Screenshots / GIFs

https://github.com/element-hq/element-x-android/assets/480955/a1ccc08a-151a-4b05-aca6-325a0571f258

## Tests

<!-- Explain how you tested your development -->

- Go to a room, open its settings.
- Either from another client or this same client, change either the name, topic and avatar or a combination of them.

They should update automatically in this screen.

## Tested devices

- [x] Physical
- [ ] Emulator
- OS version(s): 14

## Checklist

<!-- Depending on the Pull Request content, it can be acceptable if some of the following checkboxes stay unchecked. -->

- [ ] Changes have been tested on an Android device or Android emulator with API 23
- [ ] UI change has been tested on both light and dark themes
- [ ] Accessibility has been taken into account. See https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md#accessibility
- [x] Pull request is based on the develop branch
- [x] Pull request includes a new file under ./changelog.d. See https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md#changelog
- [x] Pull request includes screenshots or videos if containing UI changes
- [ ] Pull request includes a [sign off](https://matrix-org.github.io/synapse/latest/development/contributing_guide.html#sign-off)
- [x] You've made a self review of your PR

Local echo for new room picture isn't there
### Steps to reproduce

1. Go to a room where you are admin
2. Change the room avatar
3. Save

### Outcome

#### What did you expect?
I see a local echo of the room avatar when I land back in the room detail view after saving the new photo

#### What happened instead?
I still see a blank picture (there was no room avatar before)

### Your phone model

Pixel 6a

### Operating system version

Graphene OS

### Application version and app store

Nightly

### Homeserver

matrix.org

### Will you send logs?

No

### Are you willing to provide a PR?

No

Should be possible now that we have https://github.com/matrix-org/matrix-rust-sdk/pull/2411
Well, not so easy. It's the same thing as sending media, we can't have a local echo before the image is uploaded. This will be fixed by the async upload MSC (Synapse PR still pending merge).
It does not need to be a "local echo". There is already an update of the room happening and the picture has been uploaded. The Android App just deos not update the room-detail screen.

diff --git a/changelog.d/921.bugfix b/changelog.d/921.bugfix
new file mode 100644
index 00000000000..939455b1779
--- /dev/null
+++ b/changelog.d/921.bugfix
@@ -0,0 +1,1 @@
+Make the room settings screen update automatically when new room info (name, avatar, topic) is available.
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 e9aebe104b2..c832cab6664 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
@@ -63,6 +63,12 @@ class RoomDetailsPresenter @Inject constructor(
         val scope = rememberCoroutineScope()
         val leaveRoomState = leaveRoomPresenter.present()
         val canShowNotificationSettings = remember { mutableStateOf(false) }
+        val roomInfo = room.roomInfoFlow.collectAsState(initial = null).value
+
+        val roomAvatar by remember { derivedStateOf { roomInfo?.avatarUrl ?: room.avatarUrl } }
+
+        val roomName by remember { derivedStateOf { (roomInfo?.name ?: room.name ?: room.displayName).trim() } }
+        val roomTopic by remember { derivedStateOf { roomInfo?.topic ?: room.topic } }

         LaunchedEffect(Unit) {
             canShowNotificationSettings.value = featureFlagService.isFeatureEnabled(FeatureFlags.NotificationSettings)
@@ -82,8 +88,8 @@ class RoomDetailsPresenter @Inject constructor(
         val roomMemberDetailsPresenter = roomMemberDetailsPresenter(dmMember)
         val roomType by getRoomType(dmMember)

-        val topicState = remember(canEditTopic, room.topic, roomType) {
-            val topic = room.topic
+        val topicState = remember(canEditTopic, roomTopic, roomType) {
+            val topic = roomTopic

             when {
                 !topic.isNullOrBlank() -> RoomTopicState.ExistingTopic(topic)
@@ -115,9 +121,9 @@ class RoomDetailsPresenter @Inject constructor(

         return RoomDetailsState(
             roomId = room.roomId.value,
-            roomName = room.displayName,
+            roomName = roomName,
             roomAlias = room.alias,
-            roomAvatarUrl = room.avatarUrl,
+            roomAvatarUrl = roomAvatar,
             roomTopic = topicState,
             memberCount = room.joinedMemberCount,
             isEncrypted = room.isEncrypted,

diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt
index 0a25434339c..95deffad315 100644
--- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt
+++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt
@@ -46,6 +46,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID_2
 import io.element.android.libraries.matrix.test.FakeMatrixClient
 import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
 import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
+import io.element.android.libraries.matrix.test.room.aRoomInfo
 import io.element.android.tests.testutils.WarmUpRule
 import io.element.android.tests.testutils.consumeItemsUntilPredicate
 import io.element.android.tests.testutils.testCoroutineDispatchers
@@ -89,7 +90,7 @@ class RoomDetailsPresenterTests {
     }

     @Test
-    fun `present - initial state is created from room info`() = runTest {
+    fun `present - initial state is created from room if roomInfo is null`() = runTest {
         val room = aMatrixRoom()
         val presenter = createRoomDetailsPresenter(room)
         moleculeFlow(RecompositionMode.Immediate) {
@@ -97,7 +98,7 @@ class RoomDetailsPresenterTests {
         }.test {
             val initialState = awaitItem()
             assertThat(initialState.roomId).isEqualTo(room.roomId.value)
-            assertThat(initialState.roomName).isEqualTo(room.displayName)
+            assertThat(initialState.roomName).isEqualTo(room.name)
             assertThat(initialState.roomAvatarUrl).isEqualTo(room.avatarUrl)
             assertThat(initialState.roomTopic).isEqualTo(RoomTopicState.ExistingTopic(room.topic!!))
             assertThat(initialState.memberCount).isEqualTo(room.joinedMemberCount)
@@ -107,6 +108,26 @@ class RoomDetailsPresenterTests {
         }
     }

+    @Test
+    fun `present - initial state is updated with roomInfo if it exists`() = runTest {
+        val roomInfo = aRoomInfo(name = "A room name", topic = "A topic", avatarUrl = "https://matrix.org/avatar.jpg")
+        val room = aMatrixRoom().apply {
+            givenRoomInfo(roomInfo)
+        }
+        val presenter = createRoomDetailsPresenter(room)
+        moleculeFlow(RecompositionMode.Immediate) {
+            presenter.present()
+        }.test {
+            skipItems(1)
+            val updatedState = awaitItem()
+            assertThat(updatedState.roomName).isEqualTo(roomInfo.name)
+            assertThat(updatedState.roomAvatarUrl).isEqualTo(roomInfo.avatarUrl)
+            assertThat(updatedState.roomTopic).isEqualTo(RoomTopicState.ExistingTopic(roomInfo.topic!!))
+
+            cancelAndIgnoreRemainingEvents()
+        }
+    }
+
     @Test
     fun `present - initial state with no room name`() = runTest {
         val room = aMatrixRoom(name = null)
@@ -334,6 +355,7 @@ class RoomDetailsPresenterTests {
         val room = aMatrixRoom(topic = null).apply {
             givenCanSendStateResult(StateEventType.ROOM_TOPIC, Result.success(true))
             givenCanInviteResult(Result.success(false))
+            givenRoomInfo(aRoomInfo(topic = null))
         }

         val presenter = createRoomDetailsPresenter(room)
diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt
index 9c12ba1f4fa..b4e0001e844 100644
--- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt
+++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt
@@ -161,7 +161,7 @@ class FakeMatrixRoom(

     private var leaveRoomError: Throwable? = null

-    private val _roomInfoFlow: MutableSharedFlow<MatrixRoomInfo> = MutableStateFlow(aRoomInfo())
+    private val _roomInfoFlow: MutableSharedFlow<MatrixRoomInfo> = MutableSharedFlow(replay = 1)
     override val roomInfoFlow: Flow<MatrixRoomInfo> = _roomInfoFlow

     override val membersStateFlow: MutableStateFlow<MatrixRoomMembersState> = MutableStateFlow(MatrixRoomMembersState.Unknown)