Skip to content

Commit b1250a4

Browse files
authored
Merge pull request #1329 from vector-im/feature/bma/advancedSettings
New advanced settings screen
2 parents de835f9 + e058402 commit b1250a4

File tree

41 files changed

+702
-73
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+702
-73
lines changed

features/messages/impl/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ dependencies {
4848
implementation(projects.libraries.mediapickers.api)
4949
implementation(projects.libraries.featureflag.api)
5050
implementation(projects.libraries.mediaupload.api)
51+
implementation(projects.libraries.preferences.api)
5152
implementation(projects.features.networkmonitor.api)
5253
implementation(projects.services.analytics.api)
5354
implementation(libs.coil.compose)
@@ -76,6 +77,7 @@ dependencies {
7677
testImplementation(projects.libraries.featureflag.test)
7778
testImplementation(projects.libraries.mediaupload.test)
7879
testImplementation(projects.libraries.mediapickers.test)
80+
testImplementation(projects.libraries.preferences.test)
7981
testImplementation(projects.libraries.textcomposer.test)
8082
testImplementation(libs.test.mockk)
8183

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
5757
import io.element.android.features.messages.impl.utils.messagesummary.MessageSummaryFormatter
5858
import io.element.android.features.networkmonitor.api.NetworkMonitor
5959
import io.element.android.features.networkmonitor.api.NetworkStatus
60+
import io.element.android.features.preferences.api.store.PreferencesStore
6061
import io.element.android.libraries.androidutils.clipboard.ClipboardHelper
6162
import io.element.android.libraries.architecture.Async
6263
import io.element.android.libraries.architecture.Presenter
@@ -66,8 +67,6 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
6667
import io.element.android.libraries.designsystem.utils.SnackbarDispatcher
6768
import io.element.android.libraries.designsystem.utils.SnackbarMessage
6869
import io.element.android.libraries.designsystem.utils.collectSnackbarMessageAsState
69-
import io.element.android.libraries.featureflag.api.FeatureFlagService
70-
import io.element.android.libraries.featureflag.api.FeatureFlags
7170
import io.element.android.libraries.matrix.api.core.EventId
7271
import io.element.android.libraries.matrix.api.room.MatrixRoom
7372
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
@@ -97,7 +96,7 @@ class MessagesPresenter @AssistedInject constructor(
9796
private val dispatchers: CoroutineDispatchers,
9897
private val clipboardHelper: ClipboardHelper,
9998
private val analyticsService: AnalyticsService,
100-
private val featureFlagService: FeatureFlagService,
99+
private val preferencesStore: PreferencesStore,
101100
@Assisted private val navigator: MessagesNavigator,
102101
) : Presenter<MessagesState> {
103102

@@ -146,15 +145,17 @@ class MessagesPresenter @AssistedInject constructor(
146145
timelineState.eventSink(TimelineEvents.SetHighlightedEvent(composerState.mode.relatedEventId))
147146
}
148147

149-
var enableTextFormatting by remember { mutableStateOf(true) }
150-
LaunchedEffect(Unit) {
151-
enableTextFormatting = featureFlagService.isFeatureEnabled(FeatureFlags.RichTextEditor)
152-
}
148+
val enableTextFormatting by preferencesStore.isRichTextEditorEnabledFlow().collectAsState(initial = true)
153149

154150
fun handleEvents(event: MessagesEvents) {
155151
when (event) {
156152
is MessagesEvents.HandleAction -> {
157-
localCoroutineScope.handleTimelineAction(event.action, event.event, composerState)
153+
localCoroutineScope.handleTimelineAction(
154+
action = event.action,
155+
targetEvent = event.event,
156+
composerState = composerState,
157+
enableTextFormatting = enableTextFormatting,
158+
)
158159
}
159160
is MessagesEvents.ToggleReaction -> {
160161
localCoroutineScope.toggleReaction(event.emoji, event.eventId)
@@ -204,14 +205,15 @@ class MessagesPresenter @AssistedInject constructor(
204205
action: TimelineItemAction,
205206
targetEvent: TimelineItem.Event,
206207
composerState: MessageComposerState,
208+
enableTextFormatting: Boolean,
207209
) = launch {
208210
when (action) {
209211
TimelineItemAction.Copy -> handleCopyContents(targetEvent)
210212
TimelineItemAction.Redact -> handleActionRedact(targetEvent)
211-
TimelineItemAction.Edit -> handleActionEdit(targetEvent, composerState)
213+
TimelineItemAction.Edit -> handleActionEdit(targetEvent, composerState, enableTextFormatting)
212214
TimelineItemAction.Reply,
213215
TimelineItemAction.ReplyInThread -> handleActionReply(targetEvent, composerState)
214-
TimelineItemAction.Developer -> handleShowDebugInfoAction(targetEvent)
216+
TimelineItemAction.ViewSource -> handleShowDebugInfoAction(targetEvent)
215217
TimelineItemAction.Forward -> handleForwardAction(targetEvent)
216218
TimelineItemAction.ReportContent -> handleReportAction(targetEvent)
217219
TimelineItemAction.EndPoll -> handleEndPollAction(targetEvent)
@@ -260,11 +262,15 @@ class MessagesPresenter @AssistedInject constructor(
260262
}
261263
}
262264

263-
private suspend fun handleActionEdit(targetEvent: TimelineItem.Event, composerState: MessageComposerState) {
265+
private suspend fun handleActionEdit(
266+
targetEvent: TimelineItem.Event,
267+
composerState: MessageComposerState,
268+
enableTextFormatting: Boolean,
269+
) {
264270
val composerMode = MessageComposerMode.Edit(
265271
targetEvent.eventId,
266272
(targetEvent.content as? TimelineItemTextBasedContent)?.let {
267-
if (featureFlagService.isFeatureEnabled(FeatureFlags.RichTextEditor)) {
273+
if (enableTextFormatting) {
268274
it.htmlBody ?: it.body
269275
} else {
270276
it.body

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package io.element.android.features.messages.impl.actionlist
1818

1919
import androidx.compose.runtime.Composable
2020
import androidx.compose.runtime.MutableState
21+
import androidx.compose.runtime.collectAsState
2122
import androidx.compose.runtime.derivedStateOf
2223
import androidx.compose.runtime.getValue
2324
import androidx.compose.runtime.mutableStateOf
@@ -30,15 +31,15 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
3031
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
3132
import io.element.android.features.messages.impl.timeline.model.event.canBeCopied
3233
import io.element.android.features.messages.impl.timeline.model.event.canReact
34+
import io.element.android.features.preferences.api.store.PreferencesStore
3335
import io.element.android.libraries.architecture.Presenter
34-
import io.element.android.libraries.core.meta.BuildMeta
3536
import kotlinx.collections.immutable.toImmutableList
3637
import kotlinx.coroutines.CoroutineScope
3738
import kotlinx.coroutines.launch
3839
import javax.inject.Inject
3940

4041
class ActionListPresenter @Inject constructor(
41-
private val buildMeta: BuildMeta,
42+
private val preferencesStore: PreferencesStore,
4243
) : Presenter<ActionListState> {
4344

4445
@Composable
@@ -49,6 +50,8 @@ class ActionListPresenter @Inject constructor(
4950
mutableStateOf(ActionListState.Target.None)
5051
}
5152

53+
val isDeveloperModeEnabled by preferencesStore.isDeveloperModeEnabledFlow().collectAsState(initial = false)
54+
5255
val displayEmojiReactions by remember {
5356
derivedStateOf {
5457
val event = (target.value as? ActionListState.Target.Success)?.event
@@ -63,6 +66,7 @@ class ActionListPresenter @Inject constructor(
6366
timelineItem = event.event,
6467
userCanRedact = event.canRedact,
6568
userCanSendMessage = event.canSendMessage,
69+
isDeveloperModeEnabled = isDeveloperModeEnabled,
6670
target = target,
6771
)
6872
}
@@ -79,23 +83,24 @@ class ActionListPresenter @Inject constructor(
7983
timelineItem: TimelineItem.Event,
8084
userCanRedact: Boolean,
8185
userCanSendMessage: Boolean,
86+
isDeveloperModeEnabled: Boolean,
8287
target: MutableState<ActionListState.Target>
8388
) = launch {
8489
target.value = ActionListState.Target.Loading(timelineItem)
8590
val actions =
8691
when (timelineItem.content) {
8792
is TimelineItemRedactedContent -> {
88-
if (buildMeta.isDebuggable) {
89-
listOf(TimelineItemAction.Developer)
93+
if (isDeveloperModeEnabled) {
94+
listOf(TimelineItemAction.ViewSource)
9095
} else {
9196
emptyList()
9297
}
9398
}
9499
is TimelineItemStateContent -> {
95100
buildList {
96101
add(TimelineItemAction.Copy)
97-
if (buildMeta.isDebuggable) {
98-
add(TimelineItemAction.Developer)
102+
if (isDeveloperModeEnabled) {
103+
add(TimelineItemAction.ViewSource)
99104
}
100105
}
101106
}
@@ -115,8 +120,8 @@ class ActionListPresenter @Inject constructor(
115120
if (timelineItem.content.canBeCopied()) {
116121
add(TimelineItemAction.Copy)
117122
}
118-
if (buildMeta.isDebuggable) {
119-
add(TimelineItemAction.Developer)
123+
if (isDeveloperModeEnabled) {
124+
add(TimelineItemAction.ViewSource)
120125
}
121126
if (!timelineItem.isMine) {
122127
add(TimelineItemAction.ReportContent)
@@ -144,8 +149,8 @@ class ActionListPresenter @Inject constructor(
144149
if (timelineItem.content.canBeCopied()) {
145150
add(TimelineItemAction.Copy)
146151
}
147-
if (buildMeta.isDebuggable) {
148-
add(TimelineItemAction.Developer)
152+
if (isDeveloperModeEnabled) {
153+
add(TimelineItemAction.ViewSource)
149154
}
150155
if (!timelineItem.isMine) {
151156
add(TimelineItemAction.ReportContent)

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,15 +111,15 @@ fun aTimelineItemActionList(): ImmutableList<TimelineItemAction> {
111111
TimelineItemAction.Edit,
112112
TimelineItemAction.Redact,
113113
TimelineItemAction.ReportContent,
114-
TimelineItemAction.Developer,
114+
TimelineItemAction.ViewSource,
115115
)
116116
}
117117
fun aTimelineItemPollActionList(): ImmutableList<TimelineItemAction> {
118118
return persistentListOf(
119119
TimelineItemAction.EndPoll,
120120
TimelineItemAction.Reply,
121121
TimelineItemAction.Copy,
122-
TimelineItemAction.Developer,
122+
TimelineItemAction.ViewSource,
123123
TimelineItemAction.ReportContent,
124124
TimelineItemAction.Redact,
125125
)

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ sealed class TimelineItemAction(
3434
data object Reply : TimelineItemAction(CommonStrings.action_reply, VectorIcons.Reply)
3535
data object ReplyInThread : TimelineItemAction(CommonStrings.action_reply_in_thread, VectorIcons.Reply)
3636
data object Edit : TimelineItemAction(CommonStrings.action_edit, VectorIcons.Edit)
37-
data object Developer : TimelineItemAction(CommonStrings.action_view_source, VectorIcons.DeveloperMode)
37+
data object ViewSource : TimelineItemAction(CommonStrings.action_view_source, VectorIcons.DeveloperMode)
3838
data object ReportContent : TimelineItemAction(CommonStrings.action_report_content, VectorIcons.ReportContent, destructive = true)
3939
data object EndPoll : TimelineItemAction(CommonStrings.action_end_poll, VectorIcons.PollEnd)
4040
}

features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
5454
import io.element.android.libraries.designsystem.utils.SnackbarDispatcher
5555
import io.element.android.libraries.featureflag.api.FeatureFlags
5656
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
57+
import io.element.android.libraries.featureflag.test.InMemoryPreferencesStore
5758
import io.element.android.libraries.matrix.api.media.MediaSource
5859
import io.element.android.libraries.matrix.api.room.MatrixRoom
5960
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
@@ -64,7 +65,6 @@ import io.element.android.libraries.matrix.test.AN_EVENT_ID
6465
import io.element.android.libraries.matrix.test.A_ROOM_ID
6566
import io.element.android.libraries.matrix.test.A_SESSION_ID
6667
import io.element.android.libraries.matrix.test.A_SESSION_ID_2
67-
import io.element.android.libraries.matrix.test.core.aBuildMeta
6868
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
6969
import io.element.android.libraries.matrix.test.room.aRoomMember
7070
import io.element.android.libraries.mediapickers.test.FakePickerProvider
@@ -364,7 +364,7 @@ class MessagesPresenterTest {
364364
presenter.present()
365365
}.test {
366366
val initialState = awaitItem()
367-
initialState.eventSink.invoke(MessagesEvents.HandleAction(TimelineItemAction.Developer, aMessageEvent()))
367+
initialState.eventSink.invoke(MessagesEvents.HandleAction(TimelineItemAction.ViewSource, aMessageEvent()))
368368
assertThat(awaitItem().actionListState.target).isEqualTo(ActionListState.Target.None)
369369
assertThat(navigator.onShowEventDebugInfoClickedCount).isEqualTo(1)
370370
}
@@ -614,20 +614,19 @@ class MessagesPresenterTest {
614614
messageComposerContext = MessageComposerContextImpl(),
615615
richTextEditorStateFactory = TestRichTextEditorStateFactory(),
616616

617-
)
617+
)
618618
val timelinePresenter = TimelinePresenter(
619619
timelineItemsFactory = aTimelineItemsFactory(),
620620
room = matrixRoom,
621621
dispatchers = coroutineDispatchers,
622622
appScope = this,
623623
analyticsService = analyticsService,
624624
)
625-
val buildMeta = aBuildMeta()
626-
val actionListPresenter = ActionListPresenter(buildMeta = buildMeta)
625+
val preferencesStore = InMemoryPreferencesStore(isRichTextEditorEnabled = true)
626+
val actionListPresenter = ActionListPresenter(preferencesStore = preferencesStore)
627627
val customReactionPresenter = CustomReactionPresenter(emojibaseProvider = FakeEmojibaseProvider())
628628
val reactionSummaryPresenter = ReactionSummaryPresenter(room = matrixRoom)
629629
val retrySendMenuPresenter = RetrySendMenuPresenter(room = matrixRoom)
630-
val featureFlagsService = FakeFeatureFlagService(mapOf(FeatureFlags.RichTextEditor.key to true))
631630
return MessagesPresenter(
632631
room = matrixRoom,
633632
composerPresenter = messageComposerPresenter,
@@ -642,7 +641,7 @@ class MessagesPresenterTest {
642641
navigator = navigator,
643642
clipboardHelper = clipboardHelper,
644643
analyticsService = analyticsService,
645-
featureFlagService = featureFlagsService,
644+
preferencesStore = preferencesStore,
646645
dispatchers = coroutineDispatchers,
647646
)
648647
}

0 commit comments

Comments
 (0)