From d4388062b04c4c8a83570ef9d4bb95788fc927d0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 20 Jun 2025 10:11:17 +0200 Subject: [PATCH 1/5] Debug info: render the roomId in the room details screen when developer mode is enabled. --- features/roomdetails/impl/build.gradle.kts | 1 + .../roomdetails/impl/RoomDetailsPresenter.kt | 6 ++++ .../roomdetails/impl/RoomDetailsState.kt | 1 + .../impl/RoomDetailsStateProvider.kt | 4 ++- .../roomdetails/impl/RoomDetailsView.kt | 35 +++++++++++++++++++ .../impl/RoomDetailsPresenterTest.kt | 24 +++++++++++++ 6 files changed, 70 insertions(+), 1 deletion(-) diff --git a/features/roomdetails/impl/build.gradle.kts b/features/roomdetails/impl/build.gradle.kts index a23997b43d..4e87946ba4 100644 --- a/features/roomdetails/impl/build.gradle.kts +++ b/features/roomdetails/impl/build.gradle.kts @@ -67,6 +67,7 @@ dependencies { testImplementation(projects.libraries.mediaupload.test) testImplementation(projects.libraries.mediapickers.test) testImplementation(projects.libraries.permissions.test) + testImplementation(projects.libraries.preferences.test) testImplementation(projects.libraries.usersearch.test) testImplementation(projects.libraries.featureflag.test) testImplementation(projects.tests.testutils) 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 3e34f8d62b..d35d1a313b 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 @@ -48,6 +48,7 @@ import io.element.android.libraries.matrix.ui.room.getDirectRoomMember import io.element.android.libraries.matrix.ui.room.isDmAsState import io.element.android.libraries.matrix.ui.room.isOwnUserAdmin import io.element.android.libraries.matrix.ui.room.roomMemberIdentityStateChange +import io.element.android.libraries.preferences.api.store.AppPreferencesStore import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analyticsproviders.api.trackers.captureInteraction @@ -70,6 +71,7 @@ class RoomDetailsPresenter @Inject constructor( private val analyticsService: AnalyticsService, private val isPinnedMessagesFeatureEnabled: IsPinnedMessagesFeatureEnabled, private val clipboardHelper: ClipboardHelper, + private val appPreferencesStore: AppPreferencesStore, ) : Presenter { @Composable override fun present(): RoomDetailsState { @@ -136,6 +138,9 @@ class RoomDetailsPresenter @Inject constructor( val canShowKnockRequests by remember { derivedStateOf { isKnockRequestsEnabled && canHandleKnockRequests && joinRule == JoinRule.Knock } } + val isDeveloperModeEnabled by remember { + appPreferencesStore.isDeveloperModeEnabledFlow() + }.collectAsState(initial = false) val roomNotificationSettingsState by room.roomNotificationSettingsStateFlow.collectAsState() @@ -211,6 +216,7 @@ class RoomDetailsPresenter @Inject constructor( hasMemberVerificationViolations = hasMemberVerificationViolations, canReportRoom = canReportRoom, isTombstoned = roomInfo.successorRoom != null, + showDebugInfo = isDeveloperModeEnabled, eventSink = ::handleEvents, ) } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt index e589eaaed9..331329a034 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt @@ -50,6 +50,7 @@ data class RoomDetailsState( val hasMemberVerificationViolations: Boolean, val canReportRoom: Boolean, val isTombstoned: Boolean, + val showDebugInfo: Boolean, val eventSink: (RoomDetailsEvent) -> Unit ) { val roomBadges = buildList { diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt index 64f9976841..a5e81040e8 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt @@ -33,7 +33,7 @@ open class RoomDetailsStateProvider : PreviewParameterProvider override val values: Sequence get() = sequenceOf( aRoomDetailsState(displayAdminSettings = true), - aRoomDetailsState(roomTopic = RoomTopicState.Hidden), + aRoomDetailsState(roomTopic = RoomTopicState.Hidden, showDebugInfo = true), aRoomDetailsState(roomTopic = RoomTopicState.CanAddTopic), aRoomDetailsState(isEncrypted = false), aRoomDetailsState(roomAlias = null), @@ -120,6 +120,7 @@ fun aRoomDetailsState( hasMemberVerificationViolations: Boolean = false, canReportRoom: Boolean = true, isTombstoned: Boolean = false, + showDebugInfo: Boolean = false, eventSink: (RoomDetailsEvent) -> Unit = {}, ) = RoomDetailsState( roomId = roomId, @@ -151,6 +152,7 @@ fun aRoomDetailsState( hasMemberVerificationViolations = hasMemberVerificationViolations, canReportRoom = canReportRoom, isTombstoned = isTombstoned, + showDebugInfo = showDebugInfo, eventSink = eventSink, ) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt index 254c31023d..d093fd7e58 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt @@ -30,6 +30,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.PreviewParameter @@ -42,6 +43,7 @@ import io.element.android.features.roomcall.api.hasPermissionToJoin import io.element.android.features.userprofile.api.UserProfileVerificationState import io.element.android.features.userprofile.shared.blockuser.BlockUserDialogs import io.element.android.features.userprofile.shared.blockuser.BlockUserSection +import io.element.android.libraries.androidutils.system.copyToClipboard import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage import io.element.android.libraries.designsystem.atomic.atoms.MatrixBadgeAtom import io.element.android.libraries.designsystem.atomic.molecules.MatrixBadgeRowMolecule @@ -261,6 +263,12 @@ fun RoomDetailsView( onReportRoomClick = onReportRoomClick, onLeaveRoomClick = { state.eventSink(RoomDetailsEvent.LeaveRoom) } ) + + if (state.showDebugInfo) { + DebugInfoSection( + roomId = state.roomId, + ) + } } } } @@ -701,6 +709,33 @@ private fun OtherActionsSection( } } +@Composable +private fun DebugInfoSection(roomId: RoomId) { + val context = LocalContext.current + PreferenceCategory(showTopDivider = true) { + ListItem( + headlineContent = { + Text("Internal room ID") + }, + supportingContent = { + Text( + text = roomId.value, + style = ElementTheme.typography.fontBodySmRegular, + color = ElementTheme.colors.textSecondary, + ) + }, + leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Code())), + trailingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Copy())), + onClick = { + context.copyToClipboard( + roomId.value, + context.getString(CommonStrings.common_copied_to_clipboard) + ) + }, + ) + } +} + @PreviewWithLargeHeight @Composable internal fun RoomDetailsPreview(@PreviewParameter(RoomDetailsStateProvider::class) state: RoomDetailsState) = diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt index ee85c61944..64fc30d1f0 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt @@ -41,6 +41,8 @@ import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService import io.element.android.libraries.matrix.test.room.aRoomInfo +import io.element.android.libraries.preferences.api.store.AppPreferencesStore +import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.EventsRecorder @@ -84,6 +86,7 @@ class RoomDetailsPresenterTest { isPinnedMessagesFeatureEnabled: Boolean = true, encryptionService: FakeEncryptionService = FakeEncryptionService(), clipboardHelper: ClipboardHelper = FakeClipboardHelper(), + appPreferencesStore: AppPreferencesStore = InMemoryAppPreferencesStore() ): RoomDetailsPresenter { val matrixClient = FakeMatrixClient(notificationSettingsService = notificationSettingsService) val roomMemberDetailsPresenterFactory = object : RoomMemberDetailsPresenter.Factory { @@ -111,6 +114,7 @@ class RoomDetailsPresenterTest { isPinnedMessagesFeatureEnabled = { isPinnedMessagesFeatureEnabled }, analyticsService = analyticsService, clipboardHelper = clipboardHelper, + appPreferencesStore = appPreferencesStore, ) } @@ -132,6 +136,7 @@ class RoomDetailsPresenterTest { assertThat(initialState.canShowPinnedMessages).isTrue() assertThat(initialState.pinnedMessagesCount).isEqualTo(0) assertThat(initialState.canShowSecurityAndPrivacy).isFalse() + assertThat(initialState.showDebugInfo).isFalse() cancelAndIgnoreRemainingEvents() } @@ -727,4 +732,23 @@ class RoomDetailsPresenterTest { } } } + + @Test + fun `present - show debug info`() = runTest { + val room = aJoinedRoom( + canInviteResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canSendStateResult = { _, _ -> Result.success(true) }, + ) + val inMemoryAppPreferencesStore = InMemoryAppPreferencesStore( + isDeveloperModeEnabled = true, + ) + val presenter = createRoomDetailsPresenter(room = room, appPreferencesStore = inMemoryAppPreferencesStore) + presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) { + skipItems(1) + with(awaitItem()) { + assertThat(showDebugInfo).isTrue() + } + } + } } From 9baa54028171589f656a88449dd4da4af88ea886 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 20 Jun 2025 10:13:48 +0200 Subject: [PATCH 2/5] Use CompoundIcons.Code() instead of CompoundDrawables.ic_compound_code --- .../features/preferences/impl/root/PreferencesRootView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt index b63919cd26..836d68b1c4 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt @@ -272,7 +272,7 @@ private fun ColumnScope.Footer( private fun DeveloperPreferencesView(onOpenDeveloperSettings: () -> Unit) { ListItem( headlineContent = { Text(stringResource(id = CommonStrings.common_developer_options)) }, - leadingContent = ListItemContent.Icon(IconSource.Resource(CompoundDrawables.ic_compound_code)), + leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Code())), onClick = onOpenDeveloperSettings ) } From e53280aabe16eda0ca1044d4c5896ea4d5c916c4 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Fri, 20 Jun 2025 08:28:21 +0000 Subject: [PATCH 3/5] Update screenshots --- .../images/features.roomdetails.impl_RoomDetailsDark_1_en.png | 4 ++-- .../images/features.roomdetails.impl_RoomDetails_1_en.png | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_1_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_1_en.png index d57c2018ca..42c26d9648 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:efe7ab9fb0d5a0d8e14039ae73bb947558ae8c9ac0be1b146d4fba78c7f96f84 -size 34280 +oid sha256:adaa2dedb41e4717fab78875fa5e11572ff768cebe3a8ca94a1871acc634d319 +size 37705 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_1_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_1_en.png index 4d9769f32d..43582278ef 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b1835abce4bbf94590dd7e53387987bfee770bca173639c42b4b2b2587719198 -size 35113 +oid sha256:49f36e08fb97b0530ef46c557d04d49fe8e8df9afdabcedec823fa6727bf15a4 +size 38670 From d8a09535ba92ecacc95801dc51958ed5722ed9be Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 20 Jun 2025 10:29:52 +0200 Subject: [PATCH 4/5] Remove unused import --- .../features/preferences/impl/root/PreferencesRootView.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt index 836d68b1c4..337544ed7f 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt @@ -25,7 +25,6 @@ import io.element.android.features.preferences.impl.user.UserPreferences import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage import io.element.android.libraries.designsystem.components.list.ListItemContent import io.element.android.libraries.designsystem.components.preferences.PreferencePage -import io.element.android.libraries.designsystem.icons.CompoundDrawables import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.PreviewWithLargeHeight From 416188824d91cd30aa26dc9e754ced99e3d83604 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 20 Jun 2025 10:33:30 +0200 Subject: [PATCH 5/5] Suppress LargeClass on test. --- .../features/roomdetails/impl/RoomDetailsPresenterTest.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt index 64fc30d1f0..6c8f29d873 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt @@ -62,6 +62,7 @@ import org.junit.Rule import org.junit.Test import kotlin.time.Duration.Companion.milliseconds +@Suppress("LargeClass") @ExperimentalCoroutinesApi class RoomDetailsPresenterTest { @get:Rule