diff --git a/changelog.d/360.feature b/changelog.d/360.feature
new file mode 100644
index 0000000000..7532c338ba
--- /dev/null
+++ b/changelog.d/360.feature
@@ -0,0 +1 @@
+Add media pickers to the room screen.
diff --git a/features/createroom/impl/src/main/res/values/localazy.xml b/features/createroom/impl/src/main/res/values/localazy.xml
index 5d78791ee4..578c8334da 100644
--- a/features/createroom/impl/src/main/res/values/localazy.xml
+++ b/features/createroom/impl/src/main/res/values/localazy.xml
@@ -10,9 +10,9 @@
"Public room (anyone)"
"Room name"
"e.g. Product Sprint"
- "Create a room"
"Topic (optional)"
"What is this room about?"
"An error occurred when trying to start a chat"
"We can’t validate this user’s Matrix ID. The invite might not be received."
+ "Create a room"
\ No newline at end of file
diff --git a/features/logout/api/src/main/res/values/localazy.xml b/features/logout/api/src/main/res/values/localazy.xml
index 594475f35c..514c002567 100644
--- a/features/logout/api/src/main/res/values/localazy.xml
+++ b/features/logout/api/src/main/res/values/localazy.xml
@@ -1,8 +1,8 @@
"Are you sure you want to sign out?"
- "Sign out"
"Sign out"
"Signing out…"
+ "Sign out"
"Sign out"
\ No newline at end of file
diff --git a/features/messages/impl/build.gradle.kts b/features/messages/impl/build.gradle.kts
index 3bd73d5ed2..f53f130bf7 100644
--- a/features/messages/impl/build.gradle.kts
+++ b/features/messages/impl/build.gradle.kts
@@ -32,6 +32,7 @@ dependencies {
implementation(projects.anvilannotations)
anvil(projects.anvilcodegen)
api(projects.features.messages.api)
+ implementation(projects.libraries.androidutils)
implementation(projects.libraries.core)
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt
index 9665907eb2..ebc7f9e829 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt
@@ -27,7 +27,6 @@ import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.messages.api.MessagesEntryPoint
import io.element.android.libraries.di.RoomScope
-import io.element.android.libraries.matrix.api.core.RoomId
@ContributesNode(RoomScope::class)
class MessagesNode @AssistedInject constructor(
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt
index 619298b4f5..8426f79721 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt
@@ -18,6 +18,7 @@ package io.element.android.features.messages.impl
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.messages.impl.actionlist.anActionListState
+import io.element.android.features.messages.impl.textcomposer.AttachmentSourcePicker
import io.element.android.features.messages.impl.textcomposer.aMessageComposerState
import io.element.android.features.messages.impl.timeline.aTimelineItemContent
import io.element.android.features.messages.impl.timeline.aTimelineItemList
@@ -32,6 +33,8 @@ open class MessagesStateProvider : PreviewParameterProvider {
get() = sequenceOf(
aMessagesState(),
aMessagesState().copy(hasNetworkConnection = false),
+ aMessagesState().copy(composerState = aMessageComposerState().copy(attachmentSourcePicker = AttachmentSourcePicker.AllMedia)),
+ aMessagesState().copy(composerState = aMessageComposerState().copy(attachmentSourcePicker = AttachmentSourcePicker.Camera)),
)
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt
index 132d139174..5bf26d88bc 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt
@@ -21,6 +21,7 @@
package io.element.android.features.messages.impl
+import androidx.activity.compose.BackHandler
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -35,6 +36,7 @@ import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material.ExperimentalMaterialApi
+import androidx.compose.material.ListItem
import androidx.compose.material.ModalBottomSheetValue
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
@@ -43,11 +45,14 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.platform.LocalInspectionMode
+import androidx.compose.ui.platform.LocalView
+import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
@@ -57,20 +62,24 @@ import androidx.compose.ui.unit.sp
import io.element.android.features.messages.impl.actionlist.ActionListEvents
import io.element.android.features.messages.impl.actionlist.ActionListView
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
+import io.element.android.features.messages.impl.textcomposer.AttachmentSourcePicker
+import io.element.android.features.messages.impl.textcomposer.MessageComposerEvents
import io.element.android.features.messages.impl.textcomposer.MessageComposerView
import io.element.android.features.messages.impl.timeline.TimelineView
import io.element.android.features.messages.impl.timeline.model.TimelineItem
+import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorView
+import io.element.android.libraries.androidutils.ui.hideKeyboard
import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
+import io.element.android.libraries.designsystem.theme.components.ModalBottomSheetLayout
import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.designsystem.utils.LogCompositions
-import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorView
import kotlinx.coroutines.launch
import timber.log.Timber
@@ -86,9 +95,24 @@ fun MessagesView(
initialValue = ModalBottomSheetValue.Hidden,
)
val snackbarHostState = remember { SnackbarHostState() }
- val focusManager = LocalFocusManager.current
+ val composerState = state.composerState
+ val initialBottomSheetState = if (LocalInspectionMode.current && composerState.attachmentSourcePicker != null) {
+ ModalBottomSheetValue.Expanded
+ } else {
+ ModalBottomSheetValue.Hidden
+ }
+ val bottomSheetState = rememberModalBottomSheetState(initialValue = initialBottomSheetState)
val coroutineScope = rememberCoroutineScope()
+ BackHandler(enabled = bottomSheetState.isVisible) {
+ coroutineScope.launch {
+ bottomSheetState.hide()
+ }
+ }
+
+ // This is needed because the composer is inside an AndroidView that can't be affected by the FocusManager in Compose
+ val localView = LocalView.current
+
LogCompositions(tag = "MessagesScreen", msg = "Content")
fun onMessageClicked(event: TimelineItem.Event) {
@@ -97,7 +121,7 @@ fun MessagesView(
fun onMessageLongClicked(event: TimelineItem.Event) {
Timber.v("OnMessageLongClicked= ${event.id}")
- focusManager.clearFocus(force = true)
+ localView.hideKeyboard()
state.actionListState.eventSink(ActionListEvents.ComputeForMessage(event))
coroutineScope.launch {
itemActionsBottomSheetState.show()
@@ -108,41 +132,67 @@ fun MessagesView(
state.eventSink(MessagesEvents.HandleAction(action, event))
}
- Scaffold(
- modifier = modifier,
- contentWindowInsets = WindowInsets.statusBars,
- topBar = {
- Column {
- ConnectivityIndicatorView(isOnline = state.hasNetworkConnection)
- MessagesViewTopBar(
- roomTitle = state.roomName,
- roomAvatar = state.roomAvatar,
- onBackPressed = onBackPressed,
- onRoomDetailsClicked = onRoomDetailsClicked,
+ LaunchedEffect(composerState.attachmentSourcePicker) {
+ if (composerState.attachmentSourcePicker != null) {
+ // We need to use this instead of `LocalFocusManager.clearFocus()` to hide the keyboard when focus is on an Android View
+ localView.hideKeyboard()
+ bottomSheetState.show()
+ } else {
+ bottomSheetState.hide()
+ }
+ }
+ // Send 'DismissAttachmentMenu' event when the bottomsheet was just hidden
+ LaunchedEffect(bottomSheetState.isVisible) {
+ if (!bottomSheetState.isVisible) {
+ composerState.eventSink(MessageComposerEvents.DismissAttachmentMenu)
+ }
+ }
+ ModalBottomSheetLayout(
+ sheetState = bottomSheetState,
+ displayHandle = true,
+ sheetContent = {
+ MediaPickerMenu(
+ addAttachmentSourcePicker = composerState.attachmentSourcePicker,
+ eventSink = composerState.eventSink
+ )
+ }
+ ) {
+ Scaffold(
+ modifier = modifier,
+ contentWindowInsets = WindowInsets.statusBars,
+ topBar = {
+ Column {
+ ConnectivityIndicatorView(isOnline = state.hasNetworkConnection)
+ MessagesViewTopBar(
+ roomTitle = state.roomName,
+ roomAvatar = state.roomAvatar,
+ onBackPressed = onBackPressed,
+ onRoomDetailsClicked = onRoomDetailsClicked,
+ )
+ }
+ },
+ content = { padding ->
+ MessagesViewContent(
+ state = state,
+ modifier = Modifier.padding(padding),
+ onMessageClicked = ::onMessageClicked,
+ onMessageLongClicked = ::onMessageLongClicked
)
- }
- },
- content = { padding ->
- MessagesViewContent(
- state = state,
- modifier = Modifier.padding(padding),
- onMessageClicked = ::onMessageClicked,
- onMessageLongClicked = ::onMessageLongClicked
- )
- },
- snackbarHost = {
- SnackbarHost(
- snackbarHostState,
- modifier = Modifier.navigationBarsPadding()
- )
- },
- )
+ },
+ snackbarHost = {
+ SnackbarHost(
+ snackbarHostState,
+ modifier = Modifier.navigationBarsPadding()
+ )
+ },
+ )
- ActionListView(
- state = state.actionListState,
- modalBottomSheetState = itemActionsBottomSheetState,
- onActionSelected = ::onActionSelected
- )
+ ActionListView(
+ state = state.actionListState,
+ modalBottomSheetState = itemActionsBottomSheetState,
+ onActionSelected = ::onActionSelected
+ )
+ }
}
@Composable
@@ -216,6 +266,53 @@ fun MessagesViewTopBar(
)
}
+@Composable
+internal fun MediaPickerMenu(
+ addAttachmentSourcePicker: AttachmentSourcePicker?,
+ eventSink: (MessageComposerEvents) -> Unit,
+) {
+ when (addAttachmentSourcePicker) {
+ null -> return
+ AttachmentSourcePicker.AllMedia -> AllMediaSourcePickerMenu(eventSink = eventSink)
+ AttachmentSourcePicker.Camera -> CameraSourcePickerMenu(eventSink = eventSink)
+ }
+}
+
+@OptIn(ExperimentalMaterialApi::class)
+@Composable
+internal fun AllMediaSourcePickerMenu(
+ eventSink: (MessageComposerEvents) -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ Column(modifier) {
+ ListItem(Modifier.clickable { eventSink(MessageComposerEvents.PickAttachmentSource.FromGallery) }) {
+ Text(stringResource(R.string.screen_room_attachment_source_gallery))
+ }
+ ListItem(Modifier.clickable { eventSink(MessageComposerEvents.PickAttachmentSource.FromFiles) }) {
+ Text(stringResource(R.string.screen_room_attachment_source_files))
+ }
+ ListItem(Modifier.clickable { eventSink(MessageComposerEvents.PickAttachmentSource.FromCamera) }) {
+ Text(stringResource(R.string.screen_room_attachment_source_camera))
+ }
+ }
+}
+
+@OptIn(ExperimentalMaterialApi::class)
+@Composable
+internal fun CameraSourcePickerMenu(
+ eventSink: (MessageComposerEvents) -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ Column(modifier) {
+ ListItem(Modifier.clickable { eventSink(MessageComposerEvents.PickCameraAttachmentSource.Photo) }) {
+ Text(stringResource(R.string.screen_room_attachment_source_camera_photo))
+ }
+ ListItem(Modifier.clickable { eventSink(MessageComposerEvents.PickCameraAttachmentSource.Video) }) {
+ Text(stringResource(R.string.screen_room_attachment_source_camera_video))
+ }
+ }
+}
+
@Preview
@Composable
internal fun MessagesViewLightPreview(@PreviewParameter(MessagesStateProvider::class) state: MessagesState) =
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerEvents.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerEvents.kt
index 610f6e1ec0..b3728d1367 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerEvents.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerEvents.kt
@@ -24,6 +24,15 @@ sealed interface MessageComposerEvents {
object CloseSpecialMode : MessageComposerEvents
data class SetMode(val composerMode: MessageComposerMode) : MessageComposerEvents
data class UpdateText(val text: CharSequence) : MessageComposerEvents
-
- object TakePhoto : MessageComposerEvents
+ object AddAttachment : MessageComposerEvents
+ object DismissAttachmentMenu : MessageComposerEvents
+ sealed interface PickAttachmentSource : MessageComposerEvents {
+ object FromGallery : PickAttachmentSource
+ object FromCamera : PickAttachmentSource
+ object FromFiles : PickAttachmentSource
+ }
+ sealed interface PickCameraAttachmentSource : MessageComposerEvents {
+ object Photo : PickCameraAttachmentSource
+ object Video : PickCameraAttachmentSource
+ }
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerPresenter.kt
index 603776e518..8d495aa269 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerPresenter.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerPresenter.kt
@@ -19,13 +19,17 @@ package io.element.android.features.messages.impl.textcomposer
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.data.StableCharSequence
import io.element.android.libraries.core.data.toStableCharSequence
+import io.element.android.libraries.di.RoomScope
+import io.element.android.libraries.di.SingleIn
import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.matrix.api.room.MatrixRoom
@@ -36,6 +40,7 @@ import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
+@SingleIn(RoomScope::class)
class MessageComposerPresenter @Inject constructor(
private val appCoroutineScope: CoroutineScope,
private val room: MatrixRoom,
@@ -47,11 +52,22 @@ class MessageComposerPresenter @Inject constructor(
override fun present(): MessageComposerState {
val localCoroutineScope = rememberCoroutineScope()
- // Example usage of custom pickers
+ val galleryMediaPicker = mediaPickerProvider.registerGalleryPicker(onResult = { uri ->
+ Timber.d("Media picked from $uri")
+ })
+
+ val filesPicker = mediaPickerProvider.registerFilePicker(onResult = { uri ->
+ Timber.d("File picked from $uri")
+ })
+
val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker(onResult = { uri ->
Timber.d("Photo saved at $uri")
})
+ val cameraVideoPicker = mediaPickerProvider.registerCameraVideoPicker(onResult = { uri ->
+ Timber.d("Video saved at $uri")
+ })
+
val isFullScreen = rememberSaveable {
mutableStateOf(false)
}
@@ -62,6 +78,8 @@ class MessageComposerPresenter @Inject constructor(
mutableStateOf(MessageComposerMode.Normal(""))
}
+ var attachmentSourcePicker: AttachmentSourcePicker? by remember { mutableStateOf(null) }
+
LaunchedEffect(composerMode.value) {
when (val modeValue = composerMode.value) {
is MessageComposerMode.Edit -> text.value = modeValue.defaultContent.toStableCharSequence()
@@ -80,21 +98,47 @@ class MessageComposerPresenter @Inject constructor(
is MessageComposerEvents.SendMessage -> appCoroutineScope.sendMessage(event.message, composerMode, text)
is MessageComposerEvents.SetMode -> composerMode.value = event.composerMode
- MessageComposerEvents.TakePhoto -> localCoroutineScope.launch {
- if (featureFlagService.isFeatureEnabled(FeatureFlags.ShowMediaUploadingFlow)) {
- cameraPhotoPicker.launch()
- }
- }}
+ MessageComposerEvents.AddAttachment -> localCoroutineScope.ifMediaPickersEnabled {
+ attachmentSourcePicker = AttachmentSourcePicker.AllMedia
+ }
+ MessageComposerEvents.DismissAttachmentMenu -> attachmentSourcePicker = null
+ MessageComposerEvents.PickAttachmentSource.FromGallery -> localCoroutineScope.ifMediaPickersEnabled {
+ attachmentSourcePicker = null
+ galleryMediaPicker.launch()
+ }
+ MessageComposerEvents.PickAttachmentSource.FromFiles -> localCoroutineScope.ifMediaPickersEnabled {
+ attachmentSourcePicker = null
+ filesPicker.launch()
+ }
+ MessageComposerEvents.PickAttachmentSource.FromCamera -> localCoroutineScope.ifMediaPickersEnabled {
+ attachmentSourcePicker = AttachmentSourcePicker.Camera
+ }
+ MessageComposerEvents.PickCameraAttachmentSource.Photo -> localCoroutineScope.ifMediaPickersEnabled {
+ attachmentSourcePicker = null
+ cameraPhotoPicker.launch()
+ }
+ MessageComposerEvents.PickCameraAttachmentSource.Video -> localCoroutineScope.ifMediaPickersEnabled {
+ attachmentSourcePicker = null
+ cameraVideoPicker.launch()
+ }
+ }
}
return MessageComposerState(
text = text.value,
isFullScreen = isFullScreen.value,
mode = composerMode.value,
+ attachmentSourcePicker = attachmentSourcePicker,
eventSink = ::handleEvents
)
}
+ private fun CoroutineScope.ifMediaPickersEnabled(action: suspend () -> Unit) = launch {
+ if (featureFlagService.isFeatureEnabled(FeatureFlags.ShowMediaUploadingFlow)) {
+ action()
+ }
+ }
+
private fun MutableState.setToNormal() {
value = MessageComposerMode.Normal("")
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerState.kt
index ce6d68f8f7..7824f1f242 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerState.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerState.kt
@@ -25,7 +25,13 @@ data class MessageComposerState(
val text: StableCharSequence?,
val isFullScreen: Boolean,
val mode: MessageComposerMode,
+ val attachmentSourcePicker: AttachmentSourcePicker?,
val eventSink: (MessageComposerEvents) -> Unit
) {
val isSendButtonVisible: Boolean = text?.charSequence.isNullOrEmpty().not()
}
+
+sealed interface AttachmentSourcePicker {
+ object AllMedia : AttachmentSourcePicker
+ object Camera : AttachmentSourcePicker
+}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerStateProvider.kt
index 6a8ec37e30..38a88ee91f 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerStateProvider.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerStateProvider.kt
@@ -31,5 +31,6 @@ fun aMessageComposerState() = MessageComposerState(
text = StableCharSequence(""),
isFullScreen = false,
mode = MessageComposerMode.Normal(content = ""),
+ attachmentSourcePicker = null,
eventSink = {}
)
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerView.kt
index ebdfca6f9e..9b167013da 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/textcomposer/MessageComposerView.kt
@@ -54,7 +54,7 @@ fun MessageComposerView(
onCloseSpecialMode = ::onCloseSpecialMode,
onComposerTextChange = ::onComposerTextChange,
onAddAttachment = {
- state.eventSink(MessageComposerEvents.TakePhoto)
+ state.eventSink(MessageComposerEvents.AddAttachment)
},
composerCanSendMessage = state.isSendButtonVisible,
composerText = state.text?.charSequence?.toString(),
diff --git a/features/messages/impl/src/main/res/values/localazy.xml b/features/messages/impl/src/main/res/values/localazy.xml
new file mode 100644
index 0000000000..8c53bca6c4
--- /dev/null
+++ b/features/messages/impl/src/main/res/values/localazy.xml
@@ -0,0 +1,9 @@
+
+
+ "Camera"
+ "Take photo"
+ "Record a video"
+ "Attachment"
+ "Photo & Video Library"
+ "Failed processing media to upload, please try again."
+
\ No newline at end of file
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/textcomposer/MessageComposerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/textcomposer/MessageComposerPresenterTest.kt
index b18e9631ef..e550371abd 100644
--- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/textcomposer/MessageComposerPresenterTest.kt
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/textcomposer/MessageComposerPresenterTest.kt
@@ -22,7 +22,9 @@ import app.cash.molecule.RecompositionClock
import app.cash.molecule.moleculeFlow
import app.cash.turbine.ReceiveTurbine
import app.cash.turbine.test
+import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
+import io.element.android.features.messages.impl.textcomposer.AttachmentSourcePicker
import io.element.android.features.messages.impl.textcomposer.MessageComposerEvents
import io.element.android.features.messages.impl.textcomposer.MessageComposerPresenter
import io.element.android.features.messages.impl.textcomposer.MessageComposerState
@@ -279,6 +281,103 @@ class MessageComposerPresenterTest {
}
}
+ @Test
+ fun `present - Open attachments menu`() = runTest {
+ val fakeMatrixRoom = FakeMatrixRoom()
+ val presenter = MessageComposerPresenter(
+ this,
+ fakeMatrixRoom,
+ pickerProvider,
+ featureFlagService,
+ )
+ moleculeFlow(RecompositionClock.Immediate) {
+ presenter.present()
+ }.test {
+ val initialState = awaitItem()
+ initialState.eventSink(MessageComposerEvents.AddAttachment)
+
+ assertThat(awaitItem().attachmentSourcePicker).isEqualTo(AttachmentSourcePicker.AllMedia)
+ }
+ }
+
+ @Test
+ fun `present - Open camera attachments menu`() = runTest {
+ val fakeMatrixRoom = FakeMatrixRoom()
+ val presenter = MessageComposerPresenter(
+ this,
+ fakeMatrixRoom,
+ pickerProvider,
+ featureFlagService,
+ )
+ moleculeFlow(RecompositionClock.Immediate) {
+ presenter.present()
+ }.test {
+ val initialState = awaitItem()
+ initialState.eventSink(MessageComposerEvents.PickAttachmentSource.FromCamera)
+
+ assertThat(awaitItem().attachmentSourcePicker).isEqualTo(AttachmentSourcePicker.Camera)
+ }
+ }
+
+ @Test
+ fun `present - Dismiss attachments menu`() = runTest {
+ val fakeMatrixRoom = FakeMatrixRoom()
+ val presenter = MessageComposerPresenter(
+ this,
+ fakeMatrixRoom,
+ pickerProvider,
+ featureFlagService,
+ )
+ moleculeFlow(RecompositionClock.Immediate) {
+ presenter.present()
+ }.test {
+ val initialState = awaitItem()
+ initialState.eventSink(MessageComposerEvents.AddAttachment)
+ skipItems(1)
+
+ initialState.eventSink(MessageComposerEvents.DismissAttachmentMenu)
+ assertThat(awaitItem().attachmentSourcePicker).isNull()
+ }
+ }
+
+ @Test
+ fun `present - Pick media from gallery`() = runTest {
+ val fakeMatrixRoom = FakeMatrixRoom()
+ val presenter = MessageComposerPresenter(
+ this,
+ fakeMatrixRoom,
+ pickerProvider,
+ featureFlagService,
+ )
+ moleculeFlow(RecompositionClock.Immediate) {
+ presenter.present()
+ }.test {
+ val initialState = awaitItem()
+ initialState.eventSink(MessageComposerEvents.PickAttachmentSource.FromGallery)
+
+ // TODO verify some post processing of the selected media is done
+ }
+ }
+
+ @Test
+ fun `present - Pick file from storage`() = runTest {
+ val fakeMatrixRoom = FakeMatrixRoom()
+ val presenter = MessageComposerPresenter(
+ this,
+ fakeMatrixRoom,
+ pickerProvider,
+ featureFlagService,
+ )
+ moleculeFlow(RecompositionClock.Immediate) {
+ presenter.present()
+ }.test {
+ val initialState = awaitItem()
+ initialState.eventSink(MessageComposerEvents.PickAttachmentSource.FromFiles)
+
+ // TODO verify some post processing of the selected media is done
+ }
+ }
+
@Test
fun `present - Take photo`() = runTest {
val fakeMatrixRoom = FakeMatrixRoom()
@@ -292,11 +391,30 @@ class MessageComposerPresenterTest {
presenter.present()
}.test {
val initialState = awaitItem()
- initialState.eventSink(MessageComposerEvents.TakePhoto)
+ initialState.eventSink(MessageComposerEvents.PickCameraAttachmentSource.Photo)
// TODO verify some post processing of the captured image is done
}
}
+
+ @Test
+ fun `present - Record video`() = runTest {
+ val fakeMatrixRoom = FakeMatrixRoom()
+ val presenter = MessageComposerPresenter(
+ this,
+ fakeMatrixRoom,
+ pickerProvider,
+ featureFlagService,
+ )
+ moleculeFlow(RecompositionClock.Immediate) {
+ presenter.present()
+ }.test {
+ val initialState = awaitItem()
+ initialState.eventSink(MessageComposerEvents.PickCameraAttachmentSource.Video)
+
+ // TODO verify some post processing of the captured video is done
+ }
+ }
}
fun anEditMode() = MessageComposerMode.Edit(AN_EVENT_ID, A_MESSAGE)
diff --git a/features/roomdetails/impl/src/main/res/values/localazy.xml b/features/roomdetails/impl/src/main/res/values/localazy.xml
index 584f4322d3..d1356896d0 100644
--- a/features/roomdetails/impl/src/main/res/values/localazy.xml
+++ b/features/roomdetails/impl/src/main/res/values/localazy.xml
@@ -6,7 +6,6 @@
"Messages are secured with locks. Only you and the recipients have the unique keys to unlock them."
"Message encryption enabled"
- "Invite people"
"Share room"
"Block"
"Blocked users will not be able to send you messages and all message by them will be hidden. You can reverse this action anytime."
@@ -14,6 +13,7 @@
"Unblock"
"On unblocking the user, you will be able to see all messages by them again."
"Unblock user"
+ "Invite people"
"Leave room"
"People"
"Security"
diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ModalBottomSheetLayout.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ModalBottomSheetLayout.kt
index fe64256164..95d603b9dd 100644
--- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ModalBottomSheetLayout.kt
+++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ModalBottomSheetLayout.kt
@@ -19,9 +19,17 @@
package io.element.android.libraries.designsystem.theme.components
import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CornerSize
+import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.ModalBottomSheetDefaults
import androidx.compose.material.ModalBottomSheetState
@@ -30,12 +38,14 @@ import androidx.compose.material.rememberModalBottomSheetState
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
+import io.element.android.libraries.designsystem.modifiers.applyIf
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.preview.PreviewGroup
@@ -46,15 +56,36 @@ fun ModalBottomSheetLayout(
sheetContent: @Composable ColumnScope.() -> Unit,
modifier: Modifier = Modifier,
sheetState: ModalBottomSheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden),
- sheetShape: Shape = MaterialTheme.shapes.large,
+ sheetShape: Shape = MaterialTheme.shapes.large.copy(bottomStart = CornerSize(0.dp), bottomEnd = CornerSize(0.dp)),
sheetElevation: Dp = ModalBottomSheetDefaults.Elevation,
sheetBackgroundColor: Color = MaterialTheme.colorScheme.surface,
sheetContentColor: Color = contentColorFor(sheetBackgroundColor),
scrimColor: Color = ModalBottomSheetDefaults.scrimColor,
+ displayHandle: Boolean = false,
+ useSystemPadding: Boolean = true,
content: @Composable () -> Unit = {}
) {
androidx.compose.material.ModalBottomSheetLayout(
- sheetContent = sheetContent,
+ sheetContent = {
+ Column(
+ Modifier.fillMaxWidth()
+ .applyIf(useSystemPadding, ifTrue = {
+ navigationBarsPadding()
+ })
+ ) {
+ if (displayHandle) {
+ Spacer(modifier = Modifier.height(16.dp))
+ Box(
+ modifier = Modifier
+ .background(MaterialTheme.colorScheme.onSurfaceVariant, RoundedCornerShape(2.dp))
+ .size(width = 32.dp, height = 4.dp)
+ .align(Alignment.CenterHorizontally),
+ )
+ Spacer(modifier = Modifier.height(24.dp))
+ }
+ sheetContent()
+ }
+ },
modifier = modifier,
sheetState = sheetState,
sheetShape = sheetShape,
@@ -79,10 +110,13 @@ internal fun ModalBottomSheetLayoutDarkPreview() =
@Composable
private fun ContentToPreview() {
ModalBottomSheetLayout(
- modifier = Modifier.height(100.dp),
+ modifier = Modifier.height(140.dp),
+ displayHandle = true,
sheetState = ModalBottomSheetState(ModalBottomSheetValue.Expanded),
sheetContent = {
- Text(text = "Sheet Content", modifier = Modifier.padding(16.dp).background(color = Color.Green))
+ Text(text = "Sheet Content", modifier = Modifier
+ .padding(start = 16.dp, end = 16.dp, bottom = 20.dp)
+ .background(color = Color.Green))
}
) {
Text(text = "Content", modifier = Modifier.background(color = Color.Red))
diff --git a/libraries/textcomposer/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt b/libraries/textcomposer/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt
index bab573de58..1ede7be8fa 100644
--- a/libraries/textcomposer/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt
+++ b/libraries/textcomposer/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt
@@ -25,6 +25,8 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@@ -55,8 +57,9 @@ fun TextComposer(
if (LocalInspectionMode.current) {
FakeComposer(modifier)
} else {
+ val focusRequester = FocusRequester()
AndroidView(
- modifier = modifier,
+ modifier = modifier.focusRequester(focusRequester),
factory = { context ->
RichTextComposerLayout(context).apply {
// Sets up listeners for View -> Compose communication
diff --git a/libraries/ui-strings/src/main/res/values-de/translations.xml b/libraries/ui-strings/src/main/res/values-de/translations.xml
index 0ee60c0b88..dfedf9cf23 100644
--- a/libraries/ui-strings/src/main/res/values-de/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-de/translations.xml
@@ -95,14 +95,10 @@
"Neu"
"Teile Analyse-Daten"
"Medienauswahl fehlgeschlagen, bitte versuche es erneut."
- "Blockieren"
- "Nutzer blockieren"
- "Blockierung aufheben"
- "Nutzer entblockieren"
"Erkennungsschwelle"
"Version: %1$s (%2$s)"
"de"
"Fehler"
"Erfolg"
"Nutzer blockieren"
-
\ No newline at end of file
+
diff --git a/libraries/ui-strings/src/main/res/values-es/translations.xml b/libraries/ui-strings/src/main/res/values-es/translations.xml
index b430048f79..4ec790f330 100644
--- a/libraries/ui-strings/src/main/res/values-es/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-es/translations.xml
@@ -128,12 +128,6 @@
"Este es el principio de esta conversación."
"Nuevos"
"Marque si quieres ocultar todos los mensajes actuales y futuros de este usuario"
- "Bloquear"
- "Los usuarios bloqueados no podrán enviarte mensajes y se ocultarán todos sus mensajes. Puede revertir esta acción en cualquier momento."
- "Bloquear usuario"
- "Desbloquear"
- "Al desbloquear al usuario, podrás volver a ver todos sus mensajes."
- "Desbloquear usuario"
"Agitar con fuerza"
"Umbral de detección"
"General"
@@ -142,4 +136,4 @@
"Error"
"Terminado"
"Bloquear usuario"
-
\ No newline at end of file
+
diff --git a/libraries/ui-strings/src/main/res/values-it/translations.xml b/libraries/ui-strings/src/main/res/values-it/translations.xml
index 8fbe54dae2..a0e90ece3e 100644
--- a/libraries/ui-strings/src/main/res/values-it/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-it/translations.xml
@@ -128,12 +128,6 @@
"Questo è l\'inizio della conversazione."
"Nuovo"
"Seleziona se vuoi nascondere tutti i messaggi attuali e futuri di questo utente"
- "Blocca"
- "Gli utenti bloccati non saranno in grado di inviarti nuovi messaggi e tutti quelli già esistenti saranno nascosti. Potrai annullare questa azione in qualsiasi momento."
- "Blocca utente"
- "Sblocca"
- "Dopo aver sbloccato l\'utente, potrai vedere nuovamente tutti i suoi messaggi."
- "Sblocca utente"
"Rageshake"
"Soglia di rilevamento"
"Generali"
@@ -142,4 +136,4 @@
"Errore"
"Operazione riuscita"
"Blocca utente"
-
\ No newline at end of file
+
diff --git a/libraries/ui-strings/src/main/res/values-ro/translations.xml b/libraries/ui-strings/src/main/res/values-ro/translations.xml
index d9602214d0..32a7e62d45 100644
--- a/libraries/ui-strings/src/main/res/values-ro/translations.xml
+++ b/libraries/ui-strings/src/main/res/values-ro/translations.xml
@@ -143,12 +143,6 @@
"Nu"" împărtășim informații cu terți"
"Ajutați la îmbunătățirea %1$s"
"Confirmați că doriți să ascundeți toate mesajele curente și viitoare de la acest utilizator"
- "Blocați"
- "Utilizatorii blocați nu vă vor putea trimite mesaje și toate mesajele lor vor fi ascunse. Puteți anula această acțiune oricând."
- "Blocați utilizatorul"
- "Deblocați"
- "La deblocarea utilizatorului, veți putea vedea din nou toate mesajele de la acesta."
- "Deblocați utilizatorul"
"Rageshake"
"Prag de detecție"
"General"
@@ -160,4 +154,4 @@
"Puteți citi toate condițiile noastre %1$s."
"aici"
"Blocați utilizatorul"
-
\ No newline at end of file
+
diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml
index de7750a3ee..fe7cc27a84 100644
--- a/libraries/ui-strings/src/main/res/values/localazy.xml
+++ b/libraries/ui-strings/src/main/res/values/localazy.xml
@@ -147,12 +147,6 @@
"Failed processing media to upload, please try again."
"Failed uploading media, please try again."
"Check if you want to hide all current and future messages from this user"
- "Block"
- "Blocked users will not be able to send you messages and all message by them will be hidden. You can reverse this action anytime."
- "Block user"
- "Unblock"
- "On unblocking the user, you will be able to see all messages by them again."
- "Unblock user"
"Rageshake"
"Detection threshold"
"General"
diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_0,NEXUS_5,1.0,en].png
index 5555d6e6b3..860002e3dd 100644
--- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:21698ff1c1f2b30ee9c3cc0c2539b35fe7cf54aac07cb0dc376d7c1a03c8814b
-size 4483
+oid sha256:e3cb476c16c2cae9f3230cc4030b66662b9f63cef22208fc5bf577d0b16bf946
+size 4484
diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_1,NEXUS_5,1.0,en].png
index 5555d6e6b3..860002e3dd 100644
--- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:21698ff1c1f2b30ee9c3cc0c2539b35fe7cf54aac07cb0dc376d7c1a03c8814b
-size 4483
+oid sha256:e3cb476c16c2cae9f3230cc4030b66662b9f63cef22208fc5bf577d0b16bf946
+size 4484
diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_2,NEXUS_5,1.0,en].png
index c18cc0dd08..29104a87c0 100644
--- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentDarkPreview_0_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:db69f27f60dd9d93bb4d313741b84aa4a3ed008d229590338514c7683c0e3a11
-size 14786
+oid sha256:dea394d708a714603ea77543a7ab31550baaea72c75255c56ac9162589096128
+size 14453
diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_0,NEXUS_5,1.0,en].png
index eb47d1cd71..4c04d9893f 100644
--- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:fc3bf884b0425c72cafecdd4afa4e2c28064799f695962360ae4c979a3fe542e
-size 4490
+oid sha256:54b434198b8b6b534e0e82310e58eec162f18aba876f0dca9a1790c137230595
+size 4496
diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_1,NEXUS_5,1.0,en].png
index eb47d1cd71..4c04d9893f 100644
--- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:fc3bf884b0425c72cafecdd4afa4e2c28064799f695962360ae4c979a3fe542e
-size 4490
+oid sha256:54b434198b8b6b534e0e82310e58eec162f18aba876f0dca9a1790c137230595
+size 4496
diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_2,NEXUS_5,1.0,en].png
index 94f6bbbd99..9734dff6c3 100644
--- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_2,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl.actionlist_null_DefaultGroup_SheetContentLightPreview_0_null_2,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6c630475e03d86195a0ebcc57bd12934b799fee956c635b30df60913cd9a3f50
-size 16032
+oid sha256:f3080445c87d85fd5c51228e33ef7f91eb3a718f2f8288bdfa2a48d6769a25a1
+size 15480
diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png
index 7391b6f1d2..580da9ceb6 100644
--- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d6de6a4dee8a62839c15a84de8cb9817b3de8ae9fd2317e723c47bb679a72b7d
-size 39603
+oid sha256:01f54909964a4ed07d8850ab2bffad8b99ed641d731c1808b04f164ff3e0cbba
+size 39632
diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png
index a56c033ac1..ff59a95d62 100644
--- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4d8f233685a21a72081b24ee91bc90e94b340c39f7e2c498f76a69e5b7e129ff
-size 41480
+oid sha256:4ea39fdf1cb61657bc1eafb7d353ee15517c26c0e6bb2804b7c8350fa651299e
+size 41508
diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewDarkPreview_0_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewDarkPreview_0_null_2,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..1d82aaf60b
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewDarkPreview_0_null_2,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b7d7470933e27c64182c5f8acec7b4ce3896db1cc3836ff6aa6cf33fe8688f10
+size 37524
diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewDarkPreview_0_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewDarkPreview_0_null_3,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..a943b1245f
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewDarkPreview_0_null_3,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3ac05963f89ac0d3045700447a40a4a6f38cc155812de7eb9a87fb9a01643033
+size 36300
diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewLightPreview_0_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewLightPreview_0_null_0,NEXUS_5,1.0,en].png
index 7186b2e07d..a24d98a08c 100644
--- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewLightPreview_0_null_0,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewLightPreview_0_null_0,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:caaf172ddb39cbd1a77bfb2295202e5c0aa95c846353a17da6abe6c50316cf63
-size 38510
+oid sha256:c6c558d2a8e6adb4831b91aff249d16dfc48389adef5ada6e1215df1d597639a
+size 38654
diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewLightPreview_0_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewLightPreview_0_null_1,NEXUS_5,1.0,en].png
index b9628a18da..549011130b 100644
--- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewLightPreview_0_null_1,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewLightPreview_0_null_1,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:91a5fe69790f195bba47a878efb1d93a4e35bff9ec11f262cdf9c237b4cc3639
-size 40563
+oid sha256:946802d97d29f9fe41a71f1ee343e298e1b0d9dbbc6561cc82fed712e623f89c
+size 40708
diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewLightPreview_0_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewLightPreview_0_null_2,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..3586f9c218
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewLightPreview_0_null_2,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:97f10ca5290a0b4b1e034e157abb0f069fac2f2c2e88234edb1efc25c6c111f0
+size 36228
diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewLightPreview_0_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewLightPreview_0_null_3,NEXUS_5,1.0,en].png
new file mode 100644
index 0000000000..8866feaf6f
--- /dev/null
+++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.messages.impl_null_DefaultGroup_MessagesViewLightPreview_0_null_3,NEXUS_5,1.0,en].png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:cfc76bb6a8d8b269f53c2cc1c369a5c5ffb0f0fb858ebfa50c613a793bc1b421
+size 35195
diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_BottomSheets_ModalBottomSheetLayoutDarkPreview_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_BottomSheets_ModalBottomSheetLayoutDarkPreview_0_null,NEXUS_5,1.0,en].png
index 452e9b46b0..7d690c9e94 100644
--- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_BottomSheets_ModalBottomSheetLayoutDarkPreview_0_null,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_BottomSheets_ModalBottomSheetLayoutDarkPreview_0_null,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4b36389c997a7796eb7c070d4927c9a5197bca08b24cf58797de9d622c8a6176
-size 13945
+oid sha256:5eb57bf5069755caaa2188db848517a915b298ec3ba72334e27c90b354d0b4ef
+size 14302
diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_BottomSheets_ModalBottomSheetLayoutLightPreview_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_BottomSheets_ModalBottomSheetLayoutLightPreview_0_null,NEXUS_5,1.0,en].png
index e3c83080c7..a5ab66d757 100644
--- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_BottomSheets_ModalBottomSheetLayoutLightPreview_0_null,NEXUS_5,1.0,en].png
+++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_BottomSheets_ModalBottomSheetLayoutLightPreview_0_null,NEXUS_5,1.0,en].png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1579ab462c62f872774fbdb820da1f6abc09e4b8e6fb2e3baaf3d46a0722ed94
-size 15471
+oid sha256:4c37402ebdad96583f879614d07ea45f5193f6976ce5f2382333106dda77f095
+size 15520
diff --git a/tools/localazy/config.json b/tools/localazy/config.json
index ec6d5e65c8..5219187f75 100644
--- a/tools/localazy/config.json
+++ b/tools/localazy/config.json
@@ -85,6 +85,18 @@
"screen_room_member_list_.*",
"screen_dm_details_.*"
]
+ },
+ {
+ "name": ":features:messages:impl",
+ "includeRegex": [
+ "screen_room_.*",
+ "screen_dm_details_.*"
+ ],
+ "excludeRegex": [
+ "screen_room_details_.*",
+ "screen_room_member.*",
+ "screen_dm_.*"
+ ]
}
]
}
diff --git a/tools/localazy/generateLocalazyConfig.py b/tools/localazy/generateLocalazyConfig.py
index e2bc310e1e..6dfffa9c69 100755
--- a/tools/localazy/generateLocalazyConfig.py
+++ b/tools/localazy/generateLocalazyConfig.py
@@ -36,10 +36,13 @@ allActions = []
# Iterating on the config
for entry in config["modules"]:
# Create action for the default language
+ excludeRegex = regexToAlwaysExclude
+ if "excludeRegex" in entry:
+ excludeRegex += entry["excludeRegex"]
action = baseAction | {
"output": convertModuleToPath(entry["name"]) + "/src/main/res/values/localazy.xml",
"includeKeys": list(map(lambda i: "REGEX:" + i, entry["includeRegex"])),
- "excludeKeys": list(map(lambda i: "REGEX:" + i, regexToAlwaysExclude)),
+ "excludeKeys": list(map(lambda i: "REGEX:" + i, excludeRegex)),
"conditions": [
"equals: ${languageCode}, en"
]
@@ -51,7 +54,7 @@ for entry in config["modules"]:
actionTranslation = baseAction | {
"output": convertModuleToPath(entry["name"]) + "/src/main/res/values-${langAndroidResNoScript}/translations.xml",
"includeKeys": list(map(lambda i: "REGEX:" + i, entry["includeRegex"])),
- "excludeKeys": list(map(lambda i: "REGEX:" + i, regexToAlwaysExclude)),
+ "excludeKeys": list(map(lambda i: "REGEX:" + i, excludeRegex)),
"conditions": [
"!equals: ${languageCode}, en"
]