Repository: element-hq/element-x-android (language: kotlin)

Issue:
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


Discussion hints:
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.

Pull request: Make the room settings screen update automatically
<!-- 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


Test command: ./gradlew :features:roomdetails:impl:testDebugUnitTest --tests "io.element.android.features.roomdetails.RoomDetailsPresenterTests"

Fix patch:
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,


Test patch:
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)