Skip to content

Commit 38c03d6

Browse files
authored
Merge pull request #5710 from element-hq/feature/bma/textComposerLayout
Fix layout issue in text composer
2 parents e7e2f38 + 30cc45c commit 38c03d6

File tree

13 files changed

+226
-221
lines changed

13 files changed

+226
-221
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import io.element.android.features.knockrequests.api.banner.KnockRequestsBannerR
3333
import io.element.android.features.messages.impl.actionlist.ActionListPresenter
3434
import io.element.android.features.messages.impl.actionlist.model.TimelineItemActionPostProcessor
3535
import io.element.android.features.messages.impl.attachments.Attachment
36-
import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvents
36+
import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvent
3737
import io.element.android.features.messages.impl.messagecomposer.MessageComposerPresenter
3838
import io.element.android.features.messages.impl.timeline.TimelineController
3939
import io.element.android.features.messages.impl.timeline.TimelineEvents
@@ -242,7 +242,7 @@ class MessagesNode(
242242

243243
OnLifecycleEvent { _, event ->
244244
when (event) {
245-
Lifecycle.Event.ON_PAUSE -> state.composerState.eventSink(MessageComposerEvents.SaveDraft)
245+
Lifecycle.Event.ON_PAUSE -> state.composerState.eventSink(MessageComposerEvent.SaveDraft)
246246
else -> Unit
247247
}
248248
}

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import io.element.android.features.messages.impl.actionlist.ActionListState
3434
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
3535
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState
3636
import io.element.android.features.messages.impl.link.LinkState
37-
import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvents
37+
import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvent
3838
import io.element.android.features.messages.impl.messagecomposer.MessageComposerState
3939
import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerState
4040
import io.element.android.features.messages.impl.timeline.MarkAsFullyRead
@@ -479,7 +479,7 @@ class MessagesPresenter(
479479
}.orEmpty(),
480480
)
481481
composerState.eventSink(
482-
MessageComposerEvents.SetMode(composerMode)
482+
MessageComposerEvent.SetMode(composerMode)
483483
)
484484
}
485485
}
@@ -494,7 +494,7 @@ class MessagesPresenter(
494494
content = "",
495495
)
496496
composerState.eventSink(
497-
MessageComposerEvents.SetMode(composerMode)
497+
MessageComposerEvent.SetMode(composerMode)
498498
)
499499
}
500500

@@ -507,7 +507,7 @@ class MessagesPresenter(
507507
content = (targetEvent.content as? TimelineItemEventContentWithAttachment)?.caption.orEmpty(),
508508
)
509509
composerState.eventSink(
510-
MessageComposerEvents.SetMode(composerMode)
510+
MessageComposerEvent.SetMode(composerMode)
511511
)
512512
}
513513

@@ -524,7 +524,7 @@ class MessagesPresenter(
524524
hideImage = timelineProtectionState.hideMediaContent(targetEvent.eventId),
525525
)
526526
composerState.eventSink(
527-
MessageComposerEvents.SetMode(composerMode)
527+
MessageComposerEvent.SetMode(composerMode)
528528
)
529529
}
530530
}

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

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import androidx.compose.foundation.layout.statusBars
2828
import androidx.compose.foundation.layout.systemBarsPadding
2929
import androidx.compose.material3.MaterialTheme
3030
import androidx.compose.runtime.Composable
31+
import androidx.compose.runtime.LaunchedEffect
3132
import androidx.compose.ui.Alignment
3233
import androidx.compose.ui.Modifier
3334
import androidx.compose.ui.draw.shadow
@@ -52,7 +53,7 @@ import io.element.android.features.messages.impl.link.LinkEvents
5253
import io.element.android.features.messages.impl.link.LinkView
5354
import io.element.android.features.messages.impl.messagecomposer.AttachmentsBottomSheet
5455
import io.element.android.features.messages.impl.messagecomposer.DisabledComposerView
55-
import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvents
56+
import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvent
5657
import io.element.android.features.messages.impl.messagecomposer.MessageComposerView
5758
import io.element.android.features.messages.impl.messagecomposer.suggestions.SuggestionsPickerView
5859
import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerState
@@ -183,27 +184,27 @@ fun MessagesView(
183184
Scaffold(
184185
contentWindowInsets = WindowInsets.statusBars,
185186
topBar = {
186-
if (state.timelineState.timelineMode is Timeline.Mode.Thread) {
187-
ThreadTopBar(
188-
roomName = state.roomName,
189-
roomAvatarData = state.roomAvatar,
190-
heroes = state.heroes,
191-
isTombstoned = state.isTombstoned,
192-
onBackClick = onBackClick,
193-
)
194-
} else {
195-
MessagesViewTopBar(
196-
roomName = state.roomName,
197-
roomAvatar = state.roomAvatar,
198-
isTombstoned = state.isTombstoned,
199-
heroes = state.heroes,
200-
roomCallState = state.roomCallState,
201-
dmUserIdentityState = state.dmUserVerificationState,
202-
onBackClick = { hidingKeyboard { onBackClick() } },
203-
onRoomDetailsClick = { hidingKeyboard { onRoomDetailsClick() } },
204-
onJoinCallClick = onJoinCallClick,
205-
)
206-
}
187+
if (state.timelineState.timelineMode is Timeline.Mode.Thread) {
188+
ThreadTopBar(
189+
roomName = state.roomName,
190+
roomAvatarData = state.roomAvatar,
191+
heroes = state.heroes,
192+
isTombstoned = state.isTombstoned,
193+
onBackClick = onBackClick,
194+
)
195+
} else {
196+
MessagesViewTopBar(
197+
roomName = state.roomName,
198+
roomAvatar = state.roomAvatar,
199+
isTombstoned = state.isTombstoned,
200+
heroes = state.heroes,
201+
roomCallState = state.roomCallState,
202+
dmUserIdentityState = state.dmUserVerificationState,
203+
onBackClick = { hidingKeyboard { onBackClick() } },
204+
onRoomDetailsClick = { hidingKeyboard { onRoomDetailsClick() } },
205+
onJoinCallClick = onJoinCallClick,
206+
)
207+
}
207208
},
208209
content = { padding ->
209210
Box(
@@ -256,7 +257,7 @@ fun MessagesView(
256257
roomAvatarData = state.roomAvatar,
257258
suggestions = state.composerState.suggestions,
258259
onSelectSuggestion = {
259-
state.composerState.eventSink(MessageComposerEvents.InsertSuggestion(it))
260+
state.composerState.eventSink(MessageComposerEvent.InsertSuggestion(it))
260261
}
261262
)
262263
}
@@ -278,14 +279,13 @@ fun MessagesView(
278279
},
279280
)
280281
},
281-
sheetDragHandle = if (state.composerState.showTextFormatting) {
282-
@Composable { toggleAction ->
282+
sheetDragHandle = @Composable { toggleAction ->
283+
if (state.composerState.showTextFormatting) {
283284
val expandA11yLabel = stringResource(CommonStrings.a11y_expand_message_text_field)
284285
val collapseA11yLabel = stringResource(CommonStrings.a11y_collapse_message_text_field)
285286
BottomSheetDragHandle(
286287
modifier = Modifier.semantics {
287288
role = Role.Button
288-
289289
// Accessibility action to toggle the bottom sheet state
290290
val label = when (expandableState.position) {
291291
ExpandableBottomSheetLayoutState.Position.COLLAPSED, ExpandableBottomSheetLayoutState.Position.DRAGGING -> expandA11yLabel
@@ -297,9 +297,14 @@ fun MessagesView(
297297
}
298298
}
299299
)
300+
} else {
301+
LaunchedEffect(Unit) {
302+
// Ensure that the bottom sheet is collapsed
303+
if (expandableState.position == ExpandableBottomSheetLayoutState.Position.EXPANDED) {
304+
toggleAction()
305+
}
306+
}
300307
}
301-
} else {
302-
@Composable {}
303308
},
304309
isSwipeGestureEnabled = state.composerState.showTextFormatting,
305310
state = expandableState,

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ internal fun AttachmentsBottomSheet(
6464
// Send 'DismissAttachmentMenu' event when the bottomsheet was just hidden
6565
LaunchedEffect(isVisible) {
6666
if (!isVisible) {
67-
state.eventSink(MessageComposerEvents.DismissAttachmentMenu)
67+
state.eventSink(MessageComposerEvent.DismissAttachmentMenu)
6868
}
6969
}
7070

@@ -99,33 +99,33 @@ private fun AttachmentSourcePickerMenu(
9999
.imePadding()
100100
) {
101101
ListItem(
102-
modifier = Modifier.clickable { state.eventSink(MessageComposerEvents.PickAttachmentSource.PhotoFromCamera) },
102+
modifier = Modifier.clickable { state.eventSink(MessageComposerEvent.PickAttachmentSource.PhotoFromCamera) },
103103
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.TakePhoto())),
104104
headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_camera_photo)) },
105105
style = ListItemStyle.Primary,
106106
)
107107
ListItem(
108-
modifier = Modifier.clickable { state.eventSink(MessageComposerEvents.PickAttachmentSource.VideoFromCamera) },
108+
modifier = Modifier.clickable { state.eventSink(MessageComposerEvent.PickAttachmentSource.VideoFromCamera) },
109109
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.VideoCall())),
110110
headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_camera_video)) },
111111
style = ListItemStyle.Primary,
112112
)
113113
ListItem(
114-
modifier = Modifier.clickable { state.eventSink(MessageComposerEvents.PickAttachmentSource.FromGallery) },
114+
modifier = Modifier.clickable { state.eventSink(MessageComposerEvent.PickAttachmentSource.FromGallery) },
115115
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Image())),
116116
headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_gallery)) },
117117
style = ListItemStyle.Primary,
118118
)
119119
ListItem(
120-
modifier = Modifier.clickable { state.eventSink(MessageComposerEvents.PickAttachmentSource.FromFiles) },
120+
modifier = Modifier.clickable { state.eventSink(MessageComposerEvent.PickAttachmentSource.FromFiles) },
121121
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Attachment())),
122122
headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_files)) },
123123
style = ListItemStyle.Primary,
124124
)
125125
if (state.canShareLocation) {
126126
ListItem(
127127
modifier = Modifier.clickable {
128-
state.eventSink(MessageComposerEvents.PickAttachmentSource.Location)
128+
state.eventSink(MessageComposerEvent.PickAttachmentSource.Location)
129129
onSendLocationClick()
130130
},
131131
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.LocationPin())),
@@ -135,7 +135,7 @@ private fun AttachmentSourcePickerMenu(
135135
}
136136
ListItem(
137137
modifier = Modifier.clickable {
138-
state.eventSink(MessageComposerEvents.PickAttachmentSource.Poll)
138+
state.eventSink(MessageComposerEvent.PickAttachmentSource.Poll)
139139
onCreatePollClick()
140140
},
141141
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Polls())),
@@ -144,7 +144,7 @@ private fun AttachmentSourcePickerMenu(
144144
)
145145
if (enableTextFormatting) {
146146
ListItem(
147-
modifier = Modifier.clickable { state.eventSink(MessageComposerEvents.ToggleTextFormatting(enabled = true)) },
147+
modifier = Modifier.clickable { state.eventSink(MessageComposerEvent.ToggleTextFormatting(enabled = true)) },
148148
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.TextFormatting())),
149149
headlineContent = { Text(stringResource(R.string.screen_room_attachment_text_formatting)) },
150150
style = ListItemStyle.Primary,
Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion
1313
import io.element.android.libraries.textcomposer.model.MessageComposerMode
1414
import io.element.android.libraries.textcomposer.model.Suggestion
1515

16-
sealed interface MessageComposerEvents {
17-
data object ToggleFullScreenState : MessageComposerEvents
18-
data object SendMessage : MessageComposerEvents
19-
data class SendUri(val uri: Uri) : MessageComposerEvents
20-
data object CloseSpecialMode : MessageComposerEvents
21-
data class SetMode(val composerMode: MessageComposerMode) : MessageComposerEvents
22-
data object AddAttachment : MessageComposerEvents
23-
data object DismissAttachmentMenu : MessageComposerEvents
24-
sealed interface PickAttachmentSource : MessageComposerEvents {
16+
sealed interface MessageComposerEvent {
17+
data object ToggleFullScreenState : MessageComposerEvent
18+
data object SendMessage : MessageComposerEvent
19+
data class SendUri(val uri: Uri) : MessageComposerEvent
20+
data object CloseSpecialMode : MessageComposerEvent
21+
data class SetMode(val composerMode: MessageComposerMode) : MessageComposerEvent
22+
data object AddAttachment : MessageComposerEvent
23+
data object DismissAttachmentMenu : MessageComposerEvent
24+
sealed interface PickAttachmentSource : MessageComposerEvent {
2525
data object FromGallery : PickAttachmentSource
2626
data object FromFiles : PickAttachmentSource
2727
data object PhotoFromCamera : PickAttachmentSource
@@ -30,10 +30,10 @@ sealed interface MessageComposerEvents {
3030
data object Poll : PickAttachmentSource
3131
}
3232

33-
data class ToggleTextFormatting(val enabled: Boolean) : MessageComposerEvents
34-
data class Error(val error: Throwable) : MessageComposerEvents
35-
data class TypingNotice(val isTyping: Boolean) : MessageComposerEvents
36-
data class SuggestionReceived(val suggestion: Suggestion?) : MessageComposerEvents
37-
data class InsertSuggestion(val resolvedSuggestion: ResolvedSuggestion) : MessageComposerEvents
38-
data object SaveDraft : MessageComposerEvents
33+
data class ToggleTextFormatting(val enabled: Boolean) : MessageComposerEvent
34+
data class Error(val error: Throwable) : MessageComposerEvent
35+
data class TypingNotice(val isTyping: Boolean) : MessageComposerEvent
36+
data class SuggestionReceived(val suggestion: Suggestion?) : MessageComposerEvent
37+
data class InsertSuggestion(val resolvedSuggestion: ResolvedSuggestion) : MessageComposerEvent
38+
data object SaveDraft : MessageComposerEvent
3939
}

0 commit comments

Comments
 (0)