From fcdc737a816ed63891cd9ce01c8a6bfb5d6958e9 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Tue, 9 May 2023 18:08:45 +0200 Subject: [PATCH 01/36] WIP pick avatar image --- features/createroom/impl/build.gradle.kts | 1 + .../impl/configureroom/ConfigureRoomEvents.kt | 2 - .../configureroom/ConfigureRoomPresenter.kt | 32 ++++- .../impl/configureroom/ConfigureRoomState.kt | 2 + .../ConfigureRoomStateProvider.kt | 9 +- .../impl/configureroom/ConfigureRoomView.kt | 33 ++++- .../impl/configureroom/avatar/AvatarAction.kt | 34 +++++ .../avatar/AvatarActionListEvents.kt | 21 +++ .../avatar/AvatarActionListState.kt | 26 ++++ .../avatar/AvatarActionListStateProvider.kt | 30 +++++ .../avatar/AvatarActionListView.kt | 121 ++++++++++++++++++ .../libraries/mediapickers/api/PickerType.kt | 7 + .../mediapickers/impl/PickerProviderImpl.kt | 14 ++ 13 files changed, 323 insertions(+), 9 deletions(-) create mode 100644 features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarAction.kt create mode 100644 features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListEvents.kt create mode 100644 features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListState.kt create mode 100644 features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListStateProvider.kt create mode 100644 features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListView.kt diff --git a/features/createroom/impl/build.gradle.kts b/features/createroom/impl/build.gradle.kts index 0515bbbfc7..6a9b0c28ff 100644 --- a/features/createroom/impl/build.gradle.kts +++ b/features/createroom/impl/build.gradle.kts @@ -48,6 +48,7 @@ dependencies { implementation(projects.features.userlist.api) api(projects.features.createroom.api) implementation(libs.coil.compose) // FIXME temp + implementation(projects.libraries.mediapickers) testImplementation(libs.test.junit) testImplementation(libs.coroutines.test) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt index f2c454656c..58cdae613c 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt @@ -16,14 +16,12 @@ package io.element.android.features.createroom.impl.configureroom -import android.net.Uri import io.element.android.features.createroom.impl.CreateRoomConfig import io.element.android.libraries.matrix.api.user.MatrixUser sealed interface ConfigureRoomEvents { data class RoomNameChanged(val name: String) : ConfigureRoomEvents data class TopicChanged(val topic: String) : ConfigureRoomEvents - data class AvatarUriChanged(val uri: Uri?) : ConfigureRoomEvents data class RoomPrivacyChanged(val privacy: RoomPrivacy?) : ConfigureRoomEvents data class RemoveFromSelection(val matrixUser: MatrixUser) : ConfigureRoomEvents data class CreateRoom(val config: CreateRoomConfig) : ConfigureRoomEvents diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt index fa61c7f643..e38b9c06a7 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt @@ -26,6 +26,9 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import io.element.android.features.createroom.impl.CreateRoomConfig import io.element.android.features.createroom.impl.CreateRoomDataStore +import io.element.android.features.createroom.impl.configureroom.avatar.AvatarAction +import io.element.android.features.createroom.impl.configureroom.avatar.AvatarActionListEvents +import io.element.android.features.createroom.impl.configureroom.avatar.AvatarActionListState import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.execute @@ -34,6 +37,8 @@ import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters import io.element.android.libraries.matrix.api.createroom.RoomPreset import io.element.android.libraries.matrix.api.createroom.RoomVisibility +import io.element.android.libraries.mediapickers.PickerProvider +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import javax.inject.Inject @@ -41,6 +46,7 @@ import javax.inject.Inject class ConfigureRoomPresenter @Inject constructor( private val dataStore: CreateRoomDataStore, private val matrixClient: MatrixClient, + private val mediaPickerProvider: PickerProvider, ) : Presenter { @Composable @@ -52,6 +58,13 @@ class ConfigureRoomPresenter @Inject constructor( } } + val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker(onResult = { uri -> + if (uri != null) dataStore.setAvatarUrl(uri.toString()) + }) + val galleryImagePicker = mediaPickerProvider.registerGalleryImagePicker(onResult = { uri -> + if (uri != null) dataStore.setAvatarUrl(uri.toString()) + }) + val localCoroutineScope = rememberCoroutineScope() val createRoomAction: MutableState> = remember { mutableStateOf(Async.Uninitialized) } @@ -62,7 +75,6 @@ class ConfigureRoomPresenter @Inject constructor( fun handleEvents(event: ConfigureRoomEvents) { when (event) { - is ConfigureRoomEvents.AvatarUriChanged -> dataStore.setAvatarUrl(event.uri?.toString()) is ConfigureRoomEvents.RoomNameChanged -> dataStore.setRoomName(event.name) is ConfigureRoomEvents.TopicChanged -> dataStore.setTopic(event.topic) is ConfigureRoomEvents.RoomPrivacyChanged -> dataStore.setPrivacy(event.privacy) @@ -72,9 +84,27 @@ class ConfigureRoomPresenter @Inject constructor( } } + fun handleAvatarEvents(event: AvatarActionListEvents) { + when (event) { + is AvatarActionListEvents.HandleAction -> when (event.action) { + AvatarAction.ChoosePhoto -> galleryImagePicker.launch() + AvatarAction.TakePhoto -> cameraPhotoPicker.launch() + } + } + } + + val avatarActionListState = AvatarActionListState( + actions = persistentListOf( + AvatarAction.ChoosePhoto, + AvatarAction.TakePhoto, + ), + eventSink = ::handleAvatarEvents, + ) + return ConfigureRoomState( config = createRoomConfig.value, isCreateButtonEnabled = isCreateButtonEnabled, + avatarActionListState = avatarActionListState, createRoomAction = createRoomAction.value, eventSink = ::handleEvents, ) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomState.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomState.kt index b5f804fcde..1b01c3a642 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomState.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomState.kt @@ -17,12 +17,14 @@ package io.element.android.features.createroom.impl.configureroom import io.element.android.features.createroom.impl.CreateRoomConfig +import io.element.android.features.createroom.impl.configureroom.avatar.AvatarActionListState import io.element.android.libraries.architecture.Async import io.element.android.libraries.matrix.api.core.RoomId data class ConfigureRoomState( val config: CreateRoomConfig, val isCreateButtonEnabled: Boolean, + val avatarActionListState: AvatarActionListState, val createRoomAction: Async, val eventSink: (ConfigureRoomEvents) -> Unit ) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomStateProvider.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomStateProvider.kt index 67e0b91bba..3383b13b2a 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomStateProvider.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomStateProvider.kt @@ -18,8 +18,11 @@ package io.element.android.features.createroom.impl.configureroom import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.features.createroom.impl.CreateRoomConfig +import io.element.android.features.createroom.impl.configureroom.avatar.AvatarAction +import io.element.android.features.createroom.impl.configureroom.avatar.AvatarActionListState import io.element.android.features.userlist.api.aListOfSelectedUsers import io.element.android.libraries.architecture.Async +import kotlinx.collections.immutable.persistentListOf open class ConfigureRoomStateProvider : PreviewParameterProvider { override val values: Sequence @@ -40,6 +43,10 @@ open class ConfigureRoomStateProvider : PreviewParameterProvider Unit = {}, onRoomCreated: (RoomId) -> Unit = {}, ) { + val coroutineScope = rememberCoroutineScope() + val itemActionsBottomSheetState = rememberModalBottomSheetState( + initialValue = ModalBottomSheetValue.Hidden, + ) + if (state.createRoomAction is Async.Success) { LaunchedEffect(state.createRoomAction) { onRoomCreated(state.createRoomAction.state) } } - val context = LocalContext.current + fun onAvatarClicked() { + coroutineScope.launch { + itemActionsBottomSheetState.show() + } + } + Scaffold( modifier = modifier, topBar = { @@ -92,7 +107,7 @@ fun ConfigureRoomView( modifier = Modifier.padding(horizontal = 16.dp), avatarUri = state.config.avatarUrl?.toUri(), roomName = state.config.roomName.orEmpty(), - onAvatarClick = { Toast.makeText(context, "not implemented yet", Toast.LENGTH_SHORT).show() }, + onAvatarClick = ::onAvatarClicked, onRoomNameChanged = { state.eventSink(ConfigureRoomEvents.RoomNameChanged(it)) }, ) RoomTopic( @@ -114,10 +129,17 @@ fun ConfigureRoomView( } } + AvatarActionListView( + state = state.avatarActionListState, + modalBottomSheetState = itemActionsBottomSheetState, + onActionSelected = { state.avatarActionListState.eventSink(AvatarActionListEvents.HandleAction(it)) } + ) + when (state.createRoomAction) { is Async.Loading -> { ProgressDialog(text = stringResource(StringR.string.common_creating_room)) } + is Async.Failure -> { RetryDialog( content = stringResource(R.string.screen_create_room_error_creating_room), @@ -125,6 +147,7 @@ fun ConfigureRoomView( onRetry = { state.eventSink(ConfigureRoomEvents.CreateRoom(state.config)) }, ) } + else -> Unit } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarAction.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarAction.kt new file mode 100644 index 0000000000..029732f173 --- /dev/null +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarAction.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.createroom.impl.configureroom.avatar + +import androidx.annotation.StringRes +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.PhotoCamera +import androidx.compose.material.icons.filled.PhotoLibrary +import androidx.compose.runtime.Immutable +import androidx.compose.ui.graphics.vector.ImageVector +import io.element.android.libraries.ui.strings.R + +@Immutable +sealed class AvatarAction( + @StringRes val titleResId: Int, + val icon: ImageVector, +) { + object TakePhoto : AvatarAction(titleResId = R.string.action_take_photo, icon = Icons.Default.PhotoCamera) + object ChoosePhoto : AvatarAction(titleResId = R.string.action_choose_photo, icon = Icons.Default.PhotoLibrary) +} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListEvents.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListEvents.kt new file mode 100644 index 0000000000..2e81ea6500 --- /dev/null +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListEvents.kt @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.createroom.impl.configureroom.avatar + +sealed interface AvatarActionListEvents { + data class HandleAction(val action: AvatarAction) : AvatarActionListEvents +} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListState.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListState.kt new file mode 100644 index 0000000000..35a34b20a9 --- /dev/null +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListState.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.createroom.impl.configureroom.avatar + +import androidx.compose.runtime.Immutable +import kotlinx.collections.immutable.ImmutableList + +@Immutable +data class AvatarActionListState( + val actions: ImmutableList, + val eventSink: (AvatarActionListEvents) -> Unit, +) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListStateProvider.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListStateProvider.kt new file mode 100644 index 0000000000..6cb6ce1361 --- /dev/null +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListStateProvider.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.createroom.impl.configureroom.avatar + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import kotlinx.collections.immutable.persistentListOf + +open class ActionListStateProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf(anActionListState()) +} + +fun anActionListState() = AvatarActionListState( + actions = persistentListOf(AvatarAction.TakePhoto, AvatarAction.ChoosePhoto), + eventSink = {} +) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListView.kt new file mode 100644 index 0000000000..515faee0f5 --- /dev/null +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListView.kt @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:OptIn(ExperimentalMaterialApi::class, ExperimentalMaterialApi::class) + +package io.element.android.features.createroom.impl.configureroom.avatar + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.ListItem +import androidx.compose.material.ModalBottomSheetState +import androidx.compose.material.ModalBottomSheetValue +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +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.ModalBottomSheetLayout +import kotlinx.coroutines.launch + +@Composable +fun AvatarActionListView( + state: AvatarActionListState, + modalBottomSheetState: ModalBottomSheetState, + modifier: Modifier = Modifier, + onActionSelected: (action: AvatarAction) -> Unit = {}, +) { + val coroutineScope = rememberCoroutineScope() + fun onItemActionClicked(itemAction: AvatarAction) { + onActionSelected(itemAction) + coroutineScope.launch { + modalBottomSheetState.hide() + } + } + + ModalBottomSheetLayout( + modifier = modifier, + sheetState = modalBottomSheetState, + sheetContent = { + SheetContent( + state = state, + onActionClicked = ::onItemActionClicked, + modifier = Modifier + .navigationBarsPadding() + .imePadding() + ) + } + ) +} + +@Composable +private fun SheetContent( + state: AvatarActionListState, + modifier: Modifier = Modifier, + onActionClicked: (AvatarAction) -> Unit = { }, +) { + val actions = state.actions + LazyColumn( + modifier = modifier.fillMaxWidth() + ) { + items( + items = actions, + ) { action -> + ListItem( + modifier = Modifier.clickable { onActionClicked(action) }, + text = { + Text(text = stringResource(action.titleResId)) + }, + icon = { + Icon( + imageVector = action.icon, + contentDescription = stringResource(action.titleResId), + ) + } + ) + } + } +} + +@Preview +@Composable +fun SheetContentLightPreview(@PreviewParameter(ActionListStateProvider::class) state: AvatarActionListState) = + ElementPreviewLight { ContentToPreview(state) } + +@Preview +@Composable +fun SheetContentDarkPreview(@PreviewParameter(ActionListStateProvider::class) state: AvatarActionListState) = + ElementPreviewDark { ContentToPreview(state) } + +@Composable +private fun ContentToPreview(state: AvatarActionListState) { + AvatarActionListView( + state = state, + modalBottomSheetState = ModalBottomSheetState( + initialValue = ModalBottomSheetValue.Expanded + ), + ) +} diff --git a/libraries/mediapickers/api/src/main/kotlin/io/element/android/libraries/mediapickers/api/PickerType.kt b/libraries/mediapickers/api/src/main/kotlin/io/element/android/libraries/mediapickers/api/PickerType.kt index ad89175ddf..7c86009d34 100644 --- a/libraries/mediapickers/api/src/main/kotlin/io/element/android/libraries/mediapickers/api/PickerType.kt +++ b/libraries/mediapickers/api/src/main/kotlin/io/element/android/libraries/mediapickers/api/PickerType.kt @@ -26,6 +26,13 @@ sealed interface PickerType { fun getContract(): ActivityResultContract fun getDefaultRequest(): Input + object Image : PickerType { + override fun getContract() = ActivityResultContracts.PickVisualMedia() + override fun getDefaultRequest(): PickVisualMediaRequest { + return PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly) + } + } + object ImageAndVideo : PickerType { override fun getContract() = ActivityResultContracts.PickVisualMedia() override fun getDefaultRequest(): PickVisualMediaRequest { diff --git a/libraries/mediapickers/impl/src/main/kotlin/io/element/android/libraries/mediapickers/impl/PickerProviderImpl.kt b/libraries/mediapickers/impl/src/main/kotlin/io/element/android/libraries/mediapickers/impl/PickerProviderImpl.kt index b7e9bad420..11f172fd4c 100644 --- a/libraries/mediapickers/impl/src/main/kotlin/io/element/android/libraries/mediapickers/impl/PickerProviderImpl.kt +++ b/libraries/mediapickers/impl/src/main/kotlin/io/element/android/libraries/mediapickers/impl/PickerProviderImpl.kt @@ -59,6 +59,20 @@ class PickerProviderImpl constructor(private val isInTest: Boolean) : PickerProv } } + /** + * Remembers and returns a [PickerLauncher] for a gallery picture. + * [onResult] will be called with either the selected file's [Uri] or `null` if nothing was selected. + */ + @Composable + fun registerGalleryImagePicker(onResult: (Uri?) -> Unit): PickerLauncher { + // Tests and UI preview can't handle Contexts, so we might as well disable the whole picker + return if (LocalInspectionMode.current || isInTest) { + NoOpPickerLauncher { onResult(null) } + } else { + rememberPickerLauncher(type = PickerType.Image) { uri -> onResult(uri) } + } + } + /** * Remembers and returns a [PickerLauncher] for a gallery item, either a picture or a video. * [onResult] will be called with either the selected file's [Uri] or `null` if nothing was selected. From a28c0170f6a3e05213a67820ecd84a8805845dc6 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Tue, 9 May 2023 22:08:47 +0200 Subject: [PATCH 02/36] Rework and add remove button --- .../impl/configureroom/ConfigureRoomEvents.kt | 2 + .../configureroom/ConfigureRoomPresenter.kt | 44 ++++++++++--------- .../impl/configureroom/ConfigureRoomState.kt | 5 ++- .../ConfigureRoomStateProvider.kt | 7 +-- .../impl/configureroom/ConfigureRoomView.kt | 5 +-- .../impl/configureroom/avatar/AvatarAction.kt | 11 +++-- .../avatar/AvatarActionListEvents.kt | 21 --------- .../avatar/AvatarActionListState.kt | 26 ----------- .../avatar/AvatarActionListStateProvider.kt | 30 ------------- .../avatar/AvatarActionListView.kt | 29 +++++++----- 10 files changed, 55 insertions(+), 125 deletions(-) delete mode 100644 features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListEvents.kt delete mode 100644 features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListState.kt delete mode 100644 features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListStateProvider.kt diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt index 58cdae613c..52389d97fb 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt @@ -17,6 +17,7 @@ package io.element.android.features.createroom.impl.configureroom import io.element.android.features.createroom.impl.CreateRoomConfig +import io.element.android.features.createroom.impl.configureroom.avatar.AvatarAction import io.element.android.libraries.matrix.api.user.MatrixUser sealed interface ConfigureRoomEvents { @@ -25,5 +26,6 @@ sealed interface ConfigureRoomEvents { data class RoomPrivacyChanged(val privacy: RoomPrivacy?) : ConfigureRoomEvents data class RemoveFromSelection(val matrixUser: MatrixUser) : ConfigureRoomEvents data class CreateRoom(val config: CreateRoomConfig) : ConfigureRoomEvents + data class HandleAvatarAction(val action: AvatarAction) : ConfigureRoomEvents object CancelCreateRoom : ConfigureRoomEvents } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt index e38b9c06a7..399bb2d763 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt @@ -27,8 +27,6 @@ import androidx.compose.runtime.rememberCoroutineScope import io.element.android.features.createroom.impl.CreateRoomConfig import io.element.android.features.createroom.impl.CreateRoomDataStore import io.element.android.features.createroom.impl.configureroom.avatar.AvatarAction -import io.element.android.features.createroom.impl.configureroom.avatar.AvatarActionListEvents -import io.element.android.features.createroom.impl.configureroom.avatar.AvatarActionListState import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.execute @@ -38,7 +36,7 @@ import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters import io.element.android.libraries.matrix.api.createroom.RoomPreset import io.element.android.libraries.matrix.api.createroom.RoomVisibility import io.element.android.libraries.mediapickers.PickerProvider -import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import javax.inject.Inject @@ -65,6 +63,19 @@ class ConfigureRoomPresenter @Inject constructor( if (uri != null) dataStore.setAvatarUrl(uri.toString()) }) + val avatarActions by remember(createRoomConfig.value.avatarUrl) { + derivedStateOf { + mutableListOf( + AvatarAction.TakePhoto, + AvatarAction.ChoosePhoto, + ).apply { + if (createRoomConfig.value.avatarUrl != null) { + add(AvatarAction.Remove) + } + }.toImmutableList() + } + } + val localCoroutineScope = rememberCoroutineScope() val createRoomAction: MutableState> = remember { mutableStateOf(Async.Uninitialized) } @@ -80,31 +91,22 @@ class ConfigureRoomPresenter @Inject constructor( is ConfigureRoomEvents.RoomPrivacyChanged -> dataStore.setPrivacy(event.privacy) is ConfigureRoomEvents.RemoveFromSelection -> dataStore.selectedUserListDataStore.removeUserFromSelection(event.matrixUser) is ConfigureRoomEvents.CreateRoom -> createRoom(event.config) + is ConfigureRoomEvents.HandleAvatarAction -> { + when (event.action) { + AvatarAction.ChoosePhoto -> galleryImagePicker.launch() + AvatarAction.TakePhoto -> cameraPhotoPicker.launch() + AvatarAction.Remove -> dataStore.setAvatarUrl(null) + } + } + ConfigureRoomEvents.CancelCreateRoom -> createRoomAction.value = Async.Uninitialized } } - fun handleAvatarEvents(event: AvatarActionListEvents) { - when (event) { - is AvatarActionListEvents.HandleAction -> when (event.action) { - AvatarAction.ChoosePhoto -> galleryImagePicker.launch() - AvatarAction.TakePhoto -> cameraPhotoPicker.launch() - } - } - } - - val avatarActionListState = AvatarActionListState( - actions = persistentListOf( - AvatarAction.ChoosePhoto, - AvatarAction.TakePhoto, - ), - eventSink = ::handleAvatarEvents, - ) - return ConfigureRoomState( config = createRoomConfig.value, isCreateButtonEnabled = isCreateButtonEnabled, - avatarActionListState = avatarActionListState, + avatarActions = avatarActions, createRoomAction = createRoomAction.value, eventSink = ::handleEvents, ) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomState.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomState.kt index 1b01c3a642..0e0c465b52 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomState.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomState.kt @@ -17,14 +17,15 @@ package io.element.android.features.createroom.impl.configureroom import io.element.android.features.createroom.impl.CreateRoomConfig -import io.element.android.features.createroom.impl.configureroom.avatar.AvatarActionListState +import io.element.android.features.createroom.impl.configureroom.avatar.AvatarAction import io.element.android.libraries.architecture.Async import io.element.android.libraries.matrix.api.core.RoomId +import kotlinx.collections.immutable.ImmutableList data class ConfigureRoomState( val config: CreateRoomConfig, val isCreateButtonEnabled: Boolean, - val avatarActionListState: AvatarActionListState, + val avatarActions: ImmutableList, val createRoomAction: Async, val eventSink: (ConfigureRoomEvents) -> Unit ) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomStateProvider.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomStateProvider.kt index 3383b13b2a..2dd4854f3a 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomStateProvider.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomStateProvider.kt @@ -18,8 +18,6 @@ package io.element.android.features.createroom.impl.configureroom import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.features.createroom.impl.CreateRoomConfig -import io.element.android.features.createroom.impl.configureroom.avatar.AvatarAction -import io.element.android.features.createroom.impl.configureroom.avatar.AvatarActionListState import io.element.android.features.userlist.api.aListOfSelectedUsers import io.element.android.libraries.architecture.Async import kotlinx.collections.immutable.persistentListOf @@ -43,10 +41,7 @@ open class ConfigureRoomStateProvider : PreviewParameterProvider, - val eventSink: (AvatarActionListEvents) -> Unit, -) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListStateProvider.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListStateProvider.kt deleted file mode 100644 index 6cb6ce1361..0000000000 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListStateProvider.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2023 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.element.android.features.createroom.impl.configureroom.avatar - -import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import kotlinx.collections.immutable.persistentListOf - -open class ActionListStateProvider : PreviewParameterProvider { - override val values: Sequence - get() = sequenceOf(anActionListState()) -} - -fun anActionListState() = AvatarActionListState( - actions = persistentListOf(AvatarAction.TakePhoto, AvatarAction.ChoosePhoto), - eventSink = {} -) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListView.kt index 515faee0f5..f68db3a4b7 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListView.kt @@ -29,21 +29,23 @@ import androidx.compose.material.ListItem import androidx.compose.material.ModalBottomSheetState import androidx.compose.material.ModalBottomSheetValue import androidx.compose.material.Text +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter 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.ModalBottomSheetLayout +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.launch @Composable fun AvatarActionListView( - state: AvatarActionListState, + actions: ImmutableList, modalBottomSheetState: ModalBottomSheetState, modifier: Modifier = Modifier, onActionSelected: (action: AvatarAction) -> Unit = {}, @@ -61,7 +63,7 @@ fun AvatarActionListView( sheetState = modalBottomSheetState, sheetContent = { SheetContent( - state = state, + actions = actions, onActionClicked = ::onItemActionClicked, modifier = Modifier .navigationBarsPadding() @@ -73,11 +75,10 @@ fun AvatarActionListView( @Composable private fun SheetContent( - state: AvatarActionListState, + actions: ImmutableList, modifier: Modifier = Modifier, onActionClicked: (AvatarAction) -> Unit = { }, ) { - val actions = state.actions LazyColumn( modifier = modifier.fillMaxWidth() ) { @@ -87,12 +88,16 @@ private fun SheetContent( ListItem( modifier = Modifier.clickable { onActionClicked(action) }, text = { - Text(text = stringResource(action.titleResId)) + Text( + text = stringResource(action.titleResId), + color = if (action.destructive) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.primary, + ) }, icon = { Icon( imageVector = action.icon, contentDescription = stringResource(action.titleResId), + tint = if (action.destructive) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.primary, ) } ) @@ -102,18 +107,18 @@ private fun SheetContent( @Preview @Composable -fun SheetContentLightPreview(@PreviewParameter(ActionListStateProvider::class) state: AvatarActionListState) = - ElementPreviewLight { ContentToPreview(state) } +fun SheetContentLightPreview() = + ElementPreviewLight { ContentToPreview() } @Preview @Composable -fun SheetContentDarkPreview(@PreviewParameter(ActionListStateProvider::class) state: AvatarActionListState) = - ElementPreviewDark { ContentToPreview(state) } +fun SheetContentDarkPreview() = + ElementPreviewDark { ContentToPreview() } @Composable -private fun ContentToPreview(state: AvatarActionListState) { +private fun ContentToPreview() { AvatarActionListView( - state = state, + actions = persistentListOf(AvatarAction.ChoosePhoto, AvatarAction.TakePhoto, AvatarAction.Remove), modalBottomSheetState = ModalBottomSheetState( initialValue = ModalBottomSheetValue.Expanded ), From 929ebc79c5255c8022a5b4bcf1dea46f1661d1af Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Wed, 10 May 2023 11:08:43 +0200 Subject: [PATCH 03/36] Delete cached avatar URI --- .../createroom/impl/CreateRoomConfig.kt | 3 ++- .../createroom/impl/CreateRoomDataStore.kt | 12 +++++++++-- .../configureroom/ConfigureRoomPresenter.kt | 21 ++++++++++--------- .../impl/configureroom/ConfigureRoomView.kt | 3 +-- .../ConfigureRoomPresenterTests.kt | 21 ++++++++++++++----- 5 files changed, 40 insertions(+), 20 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomConfig.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomConfig.kt index 21662fdb64..23b6f3239d 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomConfig.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomConfig.kt @@ -16,6 +16,7 @@ package io.element.android.features.createroom.impl +import android.net.Uri import io.element.android.features.createroom.impl.configureroom.RoomPrivacy import io.element.android.libraries.matrix.api.user.MatrixUser import kotlinx.collections.immutable.ImmutableList @@ -24,7 +25,7 @@ import kotlinx.collections.immutable.persistentListOf data class CreateRoomConfig( val roomName: String? = null, val topic: String? = null, - val avatarUrl: String? = null, + val avatarUri: Uri? = null, val invites: ImmutableList = persistentListOf(), val privacy: RoomPrivacy? = null, ) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt index e55fca755d..8d124d25de 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt @@ -16,6 +16,7 @@ package io.element.android.features.createroom.impl +import android.net.Uri import io.element.android.features.createroom.impl.configureroom.RoomPrivacy import io.element.android.features.createroom.impl.di.CreateRoomScope import io.element.android.features.userlist.api.UserListDataStore @@ -24,6 +25,7 @@ import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine +import java.io.File import javax.inject.Inject @SingleIn(CreateRoomScope::class) @@ -32,6 +34,11 @@ class CreateRoomDataStore @Inject constructor( ) { private val createRoomConfigFlow: MutableStateFlow = MutableStateFlow(CreateRoomConfig()) + private var cachedAvatarUri: Uri? = null + set(value) { + field?.path?.let { File(it) }?.delete() + field = value + } fun getCreateRoomConfig(): Flow = combine( selectedUserListDataStore.selectedUsers(), @@ -48,8 +55,9 @@ class CreateRoomDataStore @Inject constructor( createRoomConfigFlow.tryEmit(createRoomConfigFlow.value.copy(topic = topic?.takeIf { it.isNotEmpty() })) } - fun setAvatarUrl(avatarUrl: String?) { - createRoomConfigFlow.tryEmit(createRoomConfigFlow.value.copy(avatarUrl = avatarUrl)) + fun setAvatarUri(uri: Uri?, cached: Boolean = false) { + cachedAvatarUri = uri.takeIf { cached } + createRoomConfigFlow.tryEmit(createRoomConfigFlow.value.copy(avatarUri = uri)) } fun setPrivacy(privacy: RoomPrivacy?) { diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt index 399bb2d763..941a03f84c 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt @@ -56,20 +56,21 @@ class ConfigureRoomPresenter @Inject constructor( } } - val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker(onResult = { uri -> - if (uri != null) dataStore.setAvatarUrl(uri.toString()) - }) - val galleryImagePicker = mediaPickerProvider.registerGalleryImagePicker(onResult = { uri -> - if (uri != null) dataStore.setAvatarUrl(uri.toString()) - }) + val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker( + onResult = { uri -> if (uri != null) dataStore.setAvatarUri(uri = uri, cached = true) }, + deleteAfter = false, + ) + val galleryImagePicker = mediaPickerProvider.registerGalleryImagePicker( + onResult = { uri -> if (uri != null) dataStore.setAvatarUri(uri = uri) } + ) - val avatarActions by remember(createRoomConfig.value.avatarUrl) { + val avatarActions by remember(createRoomConfig.value.avatarUri) { derivedStateOf { mutableListOf( AvatarAction.TakePhoto, AvatarAction.ChoosePhoto, ).apply { - if (createRoomConfig.value.avatarUrl != null) { + if (createRoomConfig.value.avatarUri != null) { add(AvatarAction.Remove) } }.toImmutableList() @@ -95,7 +96,7 @@ class ConfigureRoomPresenter @Inject constructor( when (event.action) { AvatarAction.ChoosePhoto -> galleryImagePicker.launch() AvatarAction.TakePhoto -> cameraPhotoPicker.launch() - AvatarAction.Remove -> dataStore.setAvatarUrl(null) + AvatarAction.Remove -> dataStore.setAvatarUri(uri = null) } } @@ -122,7 +123,7 @@ class ConfigureRoomPresenter @Inject constructor( visibility = if (config.privacy == RoomPrivacy.Public) RoomVisibility.PUBLIC else RoomVisibility.PRIVATE, preset = if (config.privacy == RoomPrivacy.Public) RoomPreset.PUBLIC_CHAT else RoomPreset.PRIVATE_CHAT, invite = config.invites.map { it.userId }, - avatar = config.avatarUrl, + avatar = config.avatarUri?.toString(), ) matrixClient.createRoom(params).getOrThrow() }.execute(createRoomAction) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt index 214ec89efb..b019e693e0 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt @@ -41,7 +41,6 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.core.net.toUri import io.element.android.features.createroom.impl.R import io.element.android.features.createroom.impl.components.Avatar import io.element.android.features.createroom.impl.components.LabelledTextField @@ -104,7 +103,7 @@ fun ConfigureRoomView( ) { RoomNameWithAvatar( modifier = Modifier.padding(horizontal = 16.dp), - avatarUri = state.config.avatarUrl?.toUri(), + avatarUri = state.config.avatarUri, roomName = state.config.roomName.orEmpty(), onAvatarClick = ::onAvatarClicked, onRoomNameChanged = { state.eventSink(ConfigureRoomEvents.RoomNameChanged(it)) }, diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt index 8be1e777a8..e1ed1f9c71 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt @@ -25,6 +25,7 @@ import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.features.createroom.impl.CreateRoomConfig import io.element.android.features.createroom.impl.CreateRoomDataStore +import io.element.android.features.createroom.impl.configureroom.avatar.AvatarAction import io.element.android.features.userlist.api.UserListDataStore import io.element.android.libraries.architecture.Async import io.element.android.libraries.matrix.api.core.RoomId @@ -34,6 +35,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_THROWABLE import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.ui.components.aMatrixUser +import io.element.android.libraries.mediapickers.PickerProvider import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -48,15 +50,18 @@ class ConfigureRoomPresenterTests { private lateinit var presenter: ConfigureRoomPresenter private lateinit var userListDataStore: UserListDataStore + private lateinit var createRoomDataStore: CreateRoomDataStore private lateinit var fakeMatrixClient: FakeMatrixClient @Before fun setup() { fakeMatrixClient = FakeMatrixClient() userListDataStore = UserListDataStore() + createRoomDataStore = CreateRoomDataStore(userListDataStore) presenter = ConfigureRoomPresenter( - dataStore = CreateRoomDataStore(userListDataStore), - matrixClient = fakeMatrixClient + dataStore = createRoomDataStore, + matrixClient = fakeMatrixClient, + mediaPickerProvider = PickerProvider(isInTest = true), ) } @@ -70,7 +75,7 @@ class ConfigureRoomPresenterTests { assertThat(initialState.config.roomName).isNull() assertThat(initialState.config.topic).isNull() assertThat(initialState.config.invites).isEmpty() - assertThat(initialState.config.avatarUrl).isNull() + assertThat(initialState.config.avatarUri).isNull() assertThat(initialState.config.privacy).isNull() } } @@ -139,10 +144,16 @@ class ConfigureRoomPresenterTests { assertThat(newState.config).isEqualTo(expectedConfig) // Room avatar + // Add val anUri = Uri.parse(AN_AVATAR_URL) - newState.eventSink(ConfigureRoomEvents.AvatarUriChanged(anUri)) + createRoomDataStore.setAvatarUri(anUri) newState = awaitItem() - expectedConfig = expectedConfig.copy(avatarUrl = anUri.toString()) + expectedConfig = expectedConfig.copy(avatarUri = anUri) + assertThat(newState.config).isEqualTo(expectedConfig) + // Remove + newState.eventSink(ConfigureRoomEvents.HandleAvatarAction(AvatarAction.Remove)) + newState = awaitItem() + expectedConfig = expectedConfig.copy(avatarUri = null) assertThat(newState.config).isEqualTo(expectedConfig) // Room privacy From 33ee366c8dca8664c79e0e0b286dfc5fb56308a4 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Wed, 10 May 2023 11:45:27 +0200 Subject: [PATCH 04/36] Fix tests after rebase --- features/createroom/impl/build.gradle.kts | 5 +++-- .../impl/configureroom/ConfigureRoomPresenter.kt | 3 +-- .../impl/configureroom/ConfigureRoomPresenterTests.kt | 9 ++++++--- .../android/libraries/mediapickers/api/PickerProvider.kt | 6 +++++- .../libraries/mediapickers/impl/PickerProviderImpl.kt | 2 +- .../libraries/mediapickers/test/FakePickerProvider.kt | 5 +++++ 6 files changed, 21 insertions(+), 9 deletions(-) diff --git a/features/createroom/impl/build.gradle.kts b/features/createroom/impl/build.gradle.kts index 6a9b0c28ff..08cd6fa0e8 100644 --- a/features/createroom/impl/build.gradle.kts +++ b/features/createroom/impl/build.gradle.kts @@ -46,9 +46,9 @@ dependencies { implementation(projects.libraries.elementresources) implementation(projects.libraries.uiStrings) implementation(projects.features.userlist.api) + implementation(projects.libraries.mediapickers.api) + implementation(libs.coil.compose) api(projects.features.createroom.api) - implementation(libs.coil.compose) // FIXME temp - implementation(projects.libraries.mediapickers) testImplementation(libs.test.junit) testImplementation(libs.coroutines.test) @@ -59,6 +59,7 @@ dependencies { testImplementation(projects.libraries.matrix.test) testImplementation(projects.features.userlist.impl) testImplementation(projects.features.userlist.test) + testImplementation(projects.libraries.mediapickers.test) androidTestImplementation(libs.test.junitext) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt index 941a03f84c..553ddf795b 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt @@ -35,7 +35,7 @@ import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters import io.element.android.libraries.matrix.api.createroom.RoomPreset import io.element.android.libraries.matrix.api.createroom.RoomVisibility -import io.element.android.libraries.mediapickers.PickerProvider +import io.element.android.libraries.mediapickers.api.PickerProvider import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -58,7 +58,6 @@ class ConfigureRoomPresenter @Inject constructor( val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker( onResult = { uri -> if (uri != null) dataStore.setAvatarUri(uri = uri, cached = true) }, - deleteAfter = false, ) val galleryImagePicker = mediaPickerProvider.registerGalleryImagePicker( onResult = { uri -> if (uri != null) dataStore.setAvatarUri(uri = uri) } diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt index e1ed1f9c71..9eefdb8929 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt @@ -35,7 +35,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_THROWABLE import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.ui.components.aMatrixUser -import io.element.android.libraries.mediapickers.PickerProvider +import io.element.android.libraries.mediapickers.test.FakePickerProvider import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -52,16 +52,18 @@ class ConfigureRoomPresenterTests { private lateinit var userListDataStore: UserListDataStore private lateinit var createRoomDataStore: CreateRoomDataStore private lateinit var fakeMatrixClient: FakeMatrixClient + private lateinit var fakePickerProvider: FakePickerProvider @Before fun setup() { fakeMatrixClient = FakeMatrixClient() userListDataStore = UserListDataStore() createRoomDataStore = CreateRoomDataStore(userListDataStore) + fakePickerProvider = FakePickerProvider() presenter = ConfigureRoomPresenter( dataStore = createRoomDataStore, matrixClient = fakeMatrixClient, - mediaPickerProvider = PickerProvider(isInTest = true), + mediaPickerProvider = fakePickerProvider, ) } @@ -146,7 +148,8 @@ class ConfigureRoomPresenterTests { // Room avatar // Add val anUri = Uri.parse(AN_AVATAR_URL) - createRoomDataStore.setAvatarUri(anUri) + fakePickerProvider.givenResult(anUri) + newState.eventSink(ConfigureRoomEvents.HandleAvatarAction(AvatarAction.ChoosePhoto)) newState = awaitItem() expectedConfig = expectedConfig.copy(avatarUri = anUri) assertThat(newState.config).isEqualTo(expectedConfig) diff --git a/libraries/mediapickers/api/src/main/kotlin/io/element/android/libraries/mediapickers/api/PickerProvider.kt b/libraries/mediapickers/api/src/main/kotlin/io/element/android/libraries/mediapickers/api/PickerProvider.kt index 9b0b248aa5..9becdc8aee 100644 --- a/libraries/mediapickers/api/src/main/kotlin/io/element/android/libraries/mediapickers/api/PickerProvider.kt +++ b/libraries/mediapickers/api/src/main/kotlin/io/element/android/libraries/mediapickers/api/PickerProvider.kt @@ -27,6 +27,11 @@ interface PickerProvider { onResult: (uri: Uri?, mimeType: String?) -> Unit ): PickerLauncher + @Composable + fun registerGalleryImagePicker( + onResult: (Uri?) -> Unit + ): PickerLauncher + @Composable fun registerFilePicker( mimeType: String, @@ -38,5 +43,4 @@ interface PickerProvider { @Composable fun registerCameraVideoPicker(onResult: (Uri?) -> Unit): PickerLauncher - } diff --git a/libraries/mediapickers/impl/src/main/kotlin/io/element/android/libraries/mediapickers/impl/PickerProviderImpl.kt b/libraries/mediapickers/impl/src/main/kotlin/io/element/android/libraries/mediapickers/impl/PickerProviderImpl.kt index 11f172fd4c..201fd9b069 100644 --- a/libraries/mediapickers/impl/src/main/kotlin/io/element/android/libraries/mediapickers/impl/PickerProviderImpl.kt +++ b/libraries/mediapickers/impl/src/main/kotlin/io/element/android/libraries/mediapickers/impl/PickerProviderImpl.kt @@ -64,7 +64,7 @@ class PickerProviderImpl constructor(private val isInTest: Boolean) : PickerProv * [onResult] will be called with either the selected file's [Uri] or `null` if nothing was selected. */ @Composable - fun registerGalleryImagePicker(onResult: (Uri?) -> Unit): PickerLauncher { + override fun registerGalleryImagePicker(onResult: (Uri?) -> Unit): PickerLauncher { // Tests and UI preview can't handle Contexts, so we might as well disable the whole picker return if (LocalInspectionMode.current || isInTest) { NoOpPickerLauncher { onResult(null) } diff --git a/libraries/mediapickers/test/src/main/kotlin/io/element/android/libraries/mediapickers/test/FakePickerProvider.kt b/libraries/mediapickers/test/src/main/kotlin/io/element/android/libraries/mediapickers/test/FakePickerProvider.kt index 2a32387db4..e243a22138 100644 --- a/libraries/mediapickers/test/src/main/kotlin/io/element/android/libraries/mediapickers/test/FakePickerProvider.kt +++ b/libraries/mediapickers/test/src/main/kotlin/io/element/android/libraries/mediapickers/test/FakePickerProvider.kt @@ -33,6 +33,11 @@ class FakePickerProvider : PickerProvider { return NoOpPickerLauncher { onResult(result, mimeType) } } + @Composable + override fun registerGalleryImagePicker(onResult: (uri: Uri?) -> Unit): PickerLauncher { + return NoOpPickerLauncher { onResult(result) } + } + @Composable override fun registerFilePicker(mimeType: String, onResult: (Uri?) -> Unit): PickerLauncher { return NoOpPickerLauncher { onResult(result) } From 750b427bc4ad7e2491cd39a81ba42b737f80b4b8 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Wed, 10 May 2023 15:13:56 +0200 Subject: [PATCH 05/36] Add todo and screenshot tests --- .../createroom/impl/configureroom/ConfigureRoomPresenter.kt | 1 + ...ultGroup_SheetContentDarkPreview_0_null,NEXUS_5,1.0,en].png | 3 +++ ...ltGroup_SheetContentLightPreview_0_null,NEXUS_5,1.0,en].png | 3 +++ 3 files changed, 7 insertions(+) create mode 100644 tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom.avatar_null_DefaultGroup_SheetContentDarkPreview_0_null,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom.avatar_null_DefaultGroup_SheetContentLightPreview_0_null,NEXUS_5,1.0,en].png diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt index 553ddf795b..3117be0657 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt @@ -114,6 +114,7 @@ class ConfigureRoomPresenter @Inject constructor( private fun CoroutineScope.createRoom(config: CreateRoomConfig, createRoomAction: MutableState>) = launch { suspend { + // TODO pre-process and upload the avatar before creating the room val params = CreateRoomParameters( name = config.roomName, topic = config.topic, diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom.avatar_null_DefaultGroup_SheetContentDarkPreview_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.features.createroom.impl.configureroom.avatar_null_DefaultGroup_SheetContentDarkPreview_0_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..6b5ba60f36 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom.avatar_null_DefaultGroup_SheetContentDarkPreview_0_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:58efadd0883968cedfe5d74c4269edb3e7cadd1150fd0e9bd3425efcc717ec01 +size 14040 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom.avatar_null_DefaultGroup_SheetContentLightPreview_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.features.createroom.impl.configureroom.avatar_null_DefaultGroup_SheetContentLightPreview_0_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..fdfcbb6e11 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom.avatar_null_DefaultGroup_SheetContentLightPreview_0_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6cd407cdbaab5e3fe6b42ceb98c5b9b6a4012e3781ad7e754531c2ce04d9ee4e +size 14810 From 7a4ed72da5517be46b5e41272fee1f7e996b8801 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Wed, 10 May 2023 15:29:46 +0200 Subject: [PATCH 06/36] changelogs --- changelog.d/122.feature | 1 + changelog.d/123.feature | 1 + 2 files changed, 2 insertions(+) create mode 100644 changelog.d/122.feature create mode 100644 changelog.d/123.feature diff --git a/changelog.d/122.feature b/changelog.d/122.feature new file mode 100644 index 0000000000..c163e6d53b --- /dev/null +++ b/changelog.d/122.feature @@ -0,0 +1 @@ +[Create and join rooms] Select a media from the camera diff --git a/changelog.d/123.feature b/changelog.d/123.feature new file mode 100644 index 0000000000..f8b4d36f2d --- /dev/null +++ b/changelog.d/123.feature @@ -0,0 +1 @@ +[Create and join rooms] Select a media from the gallery From 17dd489e6ab07ce488e9ab012b7a42bc37ccefa4 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Wed, 10 May 2023 16:16:26 +0200 Subject: [PATCH 07/36] Add missing tests --- .../ConfigureRoomPresenterTests.kt | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt index 9eefdb8929..8710a28735 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt @@ -29,7 +29,6 @@ import io.element.android.features.createroom.impl.configureroom.avatar.AvatarAc import io.element.android.features.userlist.api.UserListDataStore import io.element.android.libraries.architecture.Async import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.A_MESSAGE import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_THROWABLE @@ -45,6 +44,9 @@ import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner +private const val AN_URI_FROM_CAMERA = "content://uri_from_camera" +private const val AN_URI_FROM_GALLERY = "content://uri_from_gallery" + @RunWith(RobolectricTestRunner::class) class ConfigureRoomPresenterTests { @@ -146,12 +148,23 @@ class ConfigureRoomPresenterTests { assertThat(newState.config).isEqualTo(expectedConfig) // Room avatar - // Add - val anUri = Uri.parse(AN_AVATAR_URL) - fakePickerProvider.givenResult(anUri) + // Pick avatar + fakePickerProvider.givenResult(null) + newState.eventSink(ConfigureRoomEvents.HandleAvatarAction(AvatarAction.ChoosePhoto)) + newState.eventSink(ConfigureRoomEvents.HandleAvatarAction(AvatarAction.TakePhoto)) + // From gallery + val uriFromGallery = Uri.parse(AN_URI_FROM_GALLERY) + fakePickerProvider.givenResult(uriFromGallery) newState.eventSink(ConfigureRoomEvents.HandleAvatarAction(AvatarAction.ChoosePhoto)) newState = awaitItem() - expectedConfig = expectedConfig.copy(avatarUri = anUri) + expectedConfig = expectedConfig.copy(avatarUri = uriFromGallery) + assertThat(newState.config).isEqualTo(expectedConfig) + // From camera + val uriFromCamera = Uri.parse(AN_URI_FROM_CAMERA) + fakePickerProvider.givenResult(uriFromCamera) + newState.eventSink(ConfigureRoomEvents.HandleAvatarAction(AvatarAction.TakePhoto)) + newState = awaitItem() + expectedConfig = expectedConfig.copy(avatarUri = uriFromCamera) assertThat(newState.config).isEqualTo(expectedConfig) // Remove newState.eventSink(ConfigureRoomEvents.HandleAvatarAction(AvatarAction.Remove)) From 27f6f5cd3b2ef2a9b86f983d79e2e42fdabd20ed Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Thu, 11 May 2023 08:32:08 +0200 Subject: [PATCH 08/36] upload avatar within the room creation --- features/createroom/impl/build.gradle.kts | 1 + .../configureroom/ConfigureRoomPresenter.kt | 21 ++++++++++++++++--- .../libraries/matrix/api/MatrixClient.kt | 4 +++- .../libraries/matrix/impl/RustMatrixClient.kt | 21 ++++++++++++------- .../libraries/matrix/test/FakeMatrixClient.kt | 12 +++++++---- 5 files changed, 44 insertions(+), 15 deletions(-) diff --git a/features/createroom/impl/build.gradle.kts b/features/createroom/impl/build.gradle.kts index 08cd6fa0e8..2f8894b402 100644 --- a/features/createroom/impl/build.gradle.kts +++ b/features/createroom/impl/build.gradle.kts @@ -47,6 +47,7 @@ dependencies { implementation(projects.libraries.uiStrings) implementation(projects.features.userlist.api) implementation(projects.libraries.mediapickers.api) + implementation(projects.libraries.mediaupload.api) implementation(libs.coil.compose) api(projects.features.createroom.api) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt index 3117be0657..0d60158b8d 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt @@ -16,6 +16,7 @@ package io.element.android.features.createroom.impl.configureroom +import android.net.Uri import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.collectAsState @@ -30,12 +31,16 @@ import io.element.android.features.createroom.impl.configureroom.avatar.AvatarAc import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.execute +import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters import io.element.android.libraries.matrix.api.createroom.RoomPreset import io.element.android.libraries.matrix.api.createroom.RoomVisibility import io.element.android.libraries.mediapickers.api.PickerProvider +import io.element.android.libraries.mediaupload.api.MediaPreProcessor +import io.element.android.libraries.mediaupload.api.MediaType +import io.element.android.libraries.mediaupload.api.MediaUploadInfo import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -45,6 +50,7 @@ class ConfigureRoomPresenter @Inject constructor( private val dataStore: CreateRoomDataStore, private val matrixClient: MatrixClient, private val mediaPickerProvider: PickerProvider, + private val mediaPreProcessor: MediaPreProcessor, ) : Presenter { @Composable @@ -112,9 +118,12 @@ class ConfigureRoomPresenter @Inject constructor( ) } - private fun CoroutineScope.createRoom(config: CreateRoomConfig, createRoomAction: MutableState>) = launch { + private fun CoroutineScope.createRoom( + config: CreateRoomConfig, + createRoomAction: MutableState> + ) = launch { + val mxc = config.avatarUri?.let { uploadAvatar(it) } suspend { - // TODO pre-process and upload the avatar before creating the room val params = CreateRoomParameters( name = config.roomName, topic = config.topic, @@ -123,9 +132,15 @@ class ConfigureRoomPresenter @Inject constructor( visibility = if (config.privacy == RoomPrivacy.Public) RoomVisibility.PUBLIC else RoomVisibility.PRIVATE, preset = if (config.privacy == RoomPrivacy.Public) RoomPreset.PUBLIC_CHAT else RoomPreset.PRIVATE_CHAT, invite = config.invites.map { it.userId }, - avatar = config.avatarUri?.toString(), + avatar = mxc, ) matrixClient.createRoom(params).getOrThrow() }.execute(createRoomAction) } + + private suspend fun uploadAvatar(avatarUri: Uri): String? { + val preprocessed = mediaPreProcessor.process(avatarUri, MediaType.Image).getOrThrow() as? MediaUploadInfo.Image + val byteArray = preprocessed?.file?.readBytes() + return byteArray?.let { matrixClient.uploadMedia(MimeTypes.Jpeg, it) }?.getOrThrow() + } } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt index dce2b15485..6d357ad912 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt @@ -42,6 +42,7 @@ interface MatrixClient : Closeable { suspend fun createRoom(createRoomParams: CreateRoomParameters): Result suspend fun createDM(userId: UserId): Result suspend fun getProfile(userId: UserId): Result + suspend fun searchUsers(searchTerm: String, limit: Long): Result fun startSync() fun stopSync() fun mediaResolver(): MediaResolver @@ -58,9 +59,10 @@ interface MatrixClient : Closeable { height: Long ): Result + suspend fun uploadMedia(mimeType: String, data: ByteArray): Result + fun onSlidingSyncUpdate() fun roomMembershipObserver(): RoomMembershipObserver - suspend fun searchUsers(searchTerm: String, limit: Long): Result } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index cce7ac90c7..0381869503 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -280,6 +280,13 @@ class RustMatrixClient constructor( } } + override suspend fun searchUsers(searchTerm: String, limit: Long): Result = + withContext(dispatchers.io) { + runCatching { + client.searchUsers(searchTerm, limit.toULong()).let(UserSearchResultMapper::map) + } + } + override fun mediaResolver(): MediaResolver = mediaResolver override fun sessionVerificationService(): SessionVerificationService = verificationService @@ -368,6 +375,13 @@ class RustMatrixClient constructor( } } + @OptIn(ExperimentalUnsignedTypes::class) + override suspend fun uploadMedia(mimeType: String, data: ByteArray): Result = withContext(dispatchers.io) { + runCatching { + client.uploadMedia(mimeType, data.toUByteArray().toList()) + } + } + override fun onSlidingSyncUpdate() { if (!verificationService.isReady.value) { try { @@ -380,13 +394,6 @@ class RustMatrixClient constructor( override fun roomMembershipObserver(): RoomMembershipObserver = roomMembershipObserver - override suspend fun searchUsers(searchTerm: String, limit: Long): Result = - withContext(dispatchers.io) { - runCatching { - client.searchUsers(searchTerm, limit.toULong()).let(UserSearchResultMapper::map) - } - } - private fun File.deleteSessionDirectory(userID: String): Boolean { // Rust sanitises the user ID replacing invalid characters with an _ val sanitisedUserID = userID.replace(":", "_") diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt index 9d3ce40da1..51088115ed 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt @@ -91,6 +91,10 @@ class FakeMatrixClient( return getProfileResults[userId] ?: Result.failure(IllegalStateException("No profile found for $userId")) } + override suspend fun searchUsers(searchTerm: String, limit: Long): Result { + return searchUserResults[searchTerm] ?: Result.failure(IllegalStateException("No response defined for $searchTerm")) + } + override fun startSync() = Unit override fun stopSync() = Unit @@ -122,6 +126,10 @@ class FakeMatrixClient( return Result.success(ByteArray(0)) } + override suspend fun uploadMedia(mimeType: String, data: ByteArray): Result { + return Result.success("") + } + override fun sessionVerificationService(): SessionVerificationService = sessionVerificationService override fun pushersService(): PushersService = pushersService @@ -134,10 +142,6 @@ class FakeMatrixClient( return RoomMembershipObserver() } - override suspend fun searchUsers(searchTerm: String, limit: Long): Result { - return searchUserResults[searchTerm] ?: Result.failure(IllegalStateException("No response defined for $searchTerm")) - } - // Mocks fun givenLogoutError(failure: Throwable?) { From edb2cee3611e8d65f52ec2b3d928a1a2dafc492b Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Thu, 11 May 2023 16:30:20 +0200 Subject: [PATCH 09/36] Clear cached image after room creation --- .../android/features/createroom/impl/CreateRoomDataStore.kt | 4 ++++ .../createroom/impl/configureroom/ConfigureRoomPresenter.kt | 1 + 2 files changed, 5 insertions(+) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt index 8d124d25de..3c594a0f1e 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt @@ -63,4 +63,8 @@ class CreateRoomDataStore @Inject constructor( fun setPrivacy(privacy: RoomPrivacy?) { createRoomConfigFlow.tryEmit(createRoomConfigFlow.value.copy(privacy = privacy)) } + + fun clearCachedData() { + cachedAvatarUri = null + } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt index 0d60158b8d..8ce4a58e43 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt @@ -135,6 +135,7 @@ class ConfigureRoomPresenter @Inject constructor( avatar = mxc, ) matrixClient.createRoom(params).getOrThrow() + .also { dataStore.clearCachedData() } }.execute(createRoomAction) } From 610faf942d04fbdb108e5bc9fdd49f7f68667bf5 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Thu, 11 May 2023 17:31:46 +0200 Subject: [PATCH 10/36] Reformat some code --- .../impl/configureroom/ConfigureRoomPresenter.kt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt index 8ce4a58e43..c0a43784f7 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt @@ -71,14 +71,11 @@ class ConfigureRoomPresenter @Inject constructor( val avatarActions by remember(createRoomConfig.value.avatarUri) { derivedStateOf { - mutableListOf( + listOfNotNull( AvatarAction.TakePhoto, AvatarAction.ChoosePhoto, - ).apply { - if (createRoomConfig.value.avatarUri != null) { - add(AvatarAction.Remove) - } - }.toImmutableList() + AvatarAction.Remove.takeIf { createRoomConfig.value.avatarUri != null }, + ).toImmutableList() } } From 42e5a86c549d6ad69b2e8cfba8ae795e16d21237 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Thu, 11 May 2023 17:34:40 +0200 Subject: [PATCH 11/36] Fix test build --- features/createroom/impl/build.gradle.kts | 1 + .../impl/configureroom/ConfigureRoomPresenterTests.kt | 2 ++ 2 files changed, 3 insertions(+) diff --git a/features/createroom/impl/build.gradle.kts b/features/createroom/impl/build.gradle.kts index 2f8894b402..4d3e8f191d 100644 --- a/features/createroom/impl/build.gradle.kts +++ b/features/createroom/impl/build.gradle.kts @@ -61,6 +61,7 @@ dependencies { testImplementation(projects.features.userlist.impl) testImplementation(projects.features.userlist.test) testImplementation(projects.libraries.mediapickers.test) + testImplementation(projects.libraries.mediaupload.test) androidTestImplementation(libs.test.junitext) diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt index 8710a28735..71ea4062f1 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt @@ -35,6 +35,7 @@ import io.element.android.libraries.matrix.test.A_THROWABLE import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.mediapickers.test.FakePickerProvider +import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -66,6 +67,7 @@ class ConfigureRoomPresenterTests { dataStore = createRoomDataStore, matrixClient = fakeMatrixClient, mediaPickerProvider = fakePickerProvider, + mediaPreProcessor = FakeMediaPreProcessor(), ) } From 38967a2f4d26789421577b00fe032f104aaa7723 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Thu, 11 May 2023 23:03:47 +0200 Subject: [PATCH 12/36] Add more tests --- features/createroom/impl/build.gradle.kts | 1 + .../configureroom/ConfigureRoomPresenter.kt | 2 +- .../ConfigureRoomPresenterTests.kt | 44 ++++++++++++++++++- .../libraries/matrix/test/FakeMatrixClient.kt | 7 ++- 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/features/createroom/impl/build.gradle.kts b/features/createroom/impl/build.gradle.kts index 4d3e8f191d..2026ac5214 100644 --- a/features/createroom/impl/build.gradle.kts +++ b/features/createroom/impl/build.gradle.kts @@ -52,6 +52,7 @@ dependencies { api(projects.features.createroom.api) testImplementation(libs.test.junit) + testImplementation(libs.test.mockk) testImplementation(libs.coroutines.test) testImplementation(libs.molecule.runtime) testImplementation(libs.test.truth) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt index c0a43784f7..7659226bd9 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt @@ -119,8 +119,8 @@ class ConfigureRoomPresenter @Inject constructor( config: CreateRoomConfig, createRoomAction: MutableState> ) = launch { - val mxc = config.avatarUri?.let { uploadAvatar(it) } suspend { + val mxc = config.avatarUri?.let { uploadAvatar(it) } val params = CreateRoomParameters( name = config.roomName, topic = config.topic, diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt index 71ea4062f1..eadad19d23 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt @@ -29,21 +29,29 @@ import io.element.android.features.createroom.impl.configureroom.avatar.AvatarAc import io.element.android.features.userlist.api.UserListDataStore import io.element.android.libraries.architecture.Async import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.A_MESSAGE import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_THROWABLE import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.mediapickers.test.FakePickerProvider +import io.element.android.libraries.mediaupload.api.MediaUploadInfo import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkAll import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest +import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner +import java.io.File private const val AN_URI_FROM_CAMERA = "content://uri_from_camera" private const val AN_URI_FROM_GALLERY = "content://uri_from_gallery" @@ -56,6 +64,7 @@ class ConfigureRoomPresenterTests { private lateinit var createRoomDataStore: CreateRoomDataStore private lateinit var fakeMatrixClient: FakeMatrixClient private lateinit var fakePickerProvider: FakePickerProvider + private lateinit var fakeMediaPreProcessor: FakeMediaPreProcessor @Before fun setup() { @@ -63,12 +72,21 @@ class ConfigureRoomPresenterTests { userListDataStore = UserListDataStore() createRoomDataStore = CreateRoomDataStore(userListDataStore) fakePickerProvider = FakePickerProvider() + fakeMediaPreProcessor = FakeMediaPreProcessor() presenter = ConfigureRoomPresenter( dataStore = createRoomDataStore, matrixClient = fakeMatrixClient, mediaPickerProvider = fakePickerProvider, - mediaPreProcessor = FakeMediaPreProcessor(), + mediaPreProcessor = fakeMediaPreProcessor, ) + + mockkStatic(File::readBytes) + every { any().readBytes() } returns byteArrayOf() + } + + @After + fun tearDown() { + unmockkAll() } @Test @@ -206,6 +224,30 @@ class ConfigureRoomPresenterTests { } } + @Test + fun `present - trigger create room with upload error and retry`() = runTest { + moleculeFlow(RecompositionClock.Immediate) { + presenter.present() + }.test { + skipItems(1) + createRoomDataStore.setAvatarUri(Uri.parse(AN_URI_FROM_GALLERY)) + fakeMediaPreProcessor.givenResult(Result.success(MediaUploadInfo.Image(mockk(), mockk(), null))) + fakeMatrixClient.givenUploadMediaResult(Result.failure(A_THROWABLE)) + + val initialState = awaitItem() + initialState.eventSink(ConfigureRoomEvents.CreateRoom(initialState.config)) + val stateAfterCreateRoom = awaitItem() + assertThat(stateAfterCreateRoom.createRoomAction).isInstanceOf(Async.Failure::class.java) + + fakeMatrixClient.givenUploadMediaResult(Result.success(AN_AVATAR_URL)) + stateAfterCreateRoom.eventSink(ConfigureRoomEvents.CreateRoom(initialState.config)) + assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Uninitialized::class.java) + assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Loading::class.java) + assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Success::class.java) + + } + } + @Test fun `present - trigger retry and cancel actions`() = runTest { moleculeFlow(RecompositionClock.Immediate) { diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt index 51088115ed..bdf76c8e05 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt @@ -59,6 +59,7 @@ class FakeMatrixClient( private val getRoomResults = mutableMapOf() private val searchUserResults = mutableMapOf>() private val getProfileResults = mutableMapOf>() + private var uploadMediaResult: Result = Result.success(AN_AVATAR_URL) override fun getRoom(roomId: RoomId): MatrixRoom? { return getRoomResults[roomId] @@ -127,7 +128,7 @@ class FakeMatrixClient( } override suspend fun uploadMedia(mimeType: String, data: ByteArray): Result { - return Result.success("") + return uploadMediaResult } override fun sessionVerificationService(): SessionVerificationService = sessionVerificationService @@ -183,4 +184,8 @@ class FakeMatrixClient( fun givenGetProfileResult(userId: UserId, result: Result) { getProfileResults[userId] = result } + + fun givenUploadMediaResult(result: Result) { + uploadMediaResult = result + } } From 04930167a399604b40ea4c48449187cb4a3386e4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 May 2023 10:55:58 +0000 Subject: [PATCH 13/36] Update dependency org.matrix.rustcomponents:sdk-android to v0.1.13 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3504a3b0fe..11131203d8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -129,7 +129,7 @@ jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" } appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } molecule-runtime = { module = "app.cash.molecule:molecule-runtime", version.ref = "molecule" } timber = "com.jakewharton.timber:timber:5.0.1" -matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.12" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.13" sqldelight-driver-android = { module = "com.squareup.sqldelight:android-driver", version.ref = "sqldelight" } sqldelight-driver-jvm = { module = "com.squareup.sqldelight:sqlite-driver", version.ref = "sqldelight" } sqldelight-coroutines = { module = "com.squareup.sqldelight:coroutines-extensions", version.ref = "sqldelight" } From 32d8bf0b9daf5dceb407d7aafd73b6c5abacadb8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 May 2023 19:15:53 +0000 Subject: [PATCH 14/36] Update dependency org.jetbrains.kotlinx:kotlinx-coroutines-test to v1.7.1 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 40d89b7dd2..4a841a0d64 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ compose_bom = "2023.04.01" composecompiler = "1.4.7" # Coroutines -coroutines = "1.7.0" +coroutines = "1.7.1" # Accompanist accompanist = "0.30.1" From a336e5cad67b8c80a3d61dccbd5cdc8092d9735b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 May 2023 21:51:50 +0000 Subject: [PATCH 15/36] Update dependency com.google.dagger:dagger-compiler to v2.46.1 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 40d89b7dd2..c4ff7595e1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -43,7 +43,7 @@ stem = "2.3.0" sqldelight = "1.5.5" # DI -dagger = "2.46" +dagger = "2.46.1" anvil = "2.4.5" # quality From 457b83184a046df877be3fd7907514f9f94aab71 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 15 May 2023 12:28:31 +0200 Subject: [PATCH 16/36] Use default material3 version again and cleanup `@OptIn` annotations. Material3 is now 1.1.0 --- .../features/createroom/impl/addpeople/AddPeopleView.kt | 1 - .../createroom/impl/configureroom/ConfigureRoomView.kt | 3 +-- .../features/createroom/impl/root/CreateRoomRootView.kt | 1 - .../element/android/features/messages/impl/MessagesView.kt | 7 ++----- .../features/messages/impl/actionlist/ActionListView.kt | 5 +++-- .../messages/textcomposer/MessageComposerPresenterTest.kt | 3 --- .../android/features/onboarding/impl/OnBoardingScreen.kt | 3 --- .../roomdetails/impl/members/RoomMemberListView.kt | 1 - .../element/android/features/roomlist/impl/RoomListView.kt | 2 +- .../features/roomlist/impl/components/RoomListTopBar.kt | 2 -- gradle/libs.versions.toml | 2 +- .../components/preferences/PreferenceScreen.kt | 1 - .../theme/components/CenterAlignedTopAppBar.kt | 2 -- .../designsystem/theme/components/MediumTopAppBar.kt | 3 +-- .../theme/components/ModalBottomSheetLayout.kt | 3 +-- .../designsystem/theme/components/OutlinedTextField.kt | 2 +- .../libraries/designsystem/theme/components/Scaffold.kt | 2 -- .../libraries/designsystem/theme/components/SearchBar.kt | 3 +-- .../libraries/designsystem/theme/components/TopAppBar.kt | 2 -- .../android/libraries/matrix/impl/RustMatrixClient.kt | 3 --- .../matrix/impl/room/RustRoomSummaryDataSource.kt | 1 - plugins/src/main/kotlin/extension/DependencyHandleScope.kt | 4 +--- .../io/element/android/samples/minimal/MainActivity.kt | 3 --- .../android/tests/testutils/TestCoroutineDispatchers.kt | 3 --- 24 files changed, 13 insertions(+), 49 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt index ebf3e9d508..3746fef4df 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt @@ -41,7 +41,6 @@ import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.ui.strings.R as StringR -@OptIn(ExperimentalMaterial3Api::class) @Composable fun AddPeopleView( state: UserListState, diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt index cb699f4599..3a59760ac8 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalMaterial3Api::class) - package io.element.android.features.createroom.impl.configureroom import android.net.Uri @@ -129,6 +127,7 @@ fun ConfigureRoomView( } } +@OptIn(ExperimentalMaterial3Api::class) @Composable fun ConfigureRoomToolbar( isNextActionEnabled: Boolean, diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt index a80cf821fd..2de52b89f7 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt @@ -55,7 +55,6 @@ import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.designsystem.R as DrawableR import io.element.android.libraries.ui.strings.R as StringR -@OptIn(ExperimentalMaterial3Api::class) @Composable fun CreateRoomRootView( state: CreateRoomRootState, 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 cd70dc97cd..f98b19575a 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 @@ -14,11 +14,6 @@ * limitations under the License. */ -@file:OptIn( - ExperimentalMaterial3Api::class, - ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class, -) - package io.element.android.features.messages.impl import androidx.activity.compose.BackHandler @@ -84,6 +79,7 @@ import io.element.android.libraries.designsystem.utils.LogCompositions import kotlinx.coroutines.launch import timber.log.Timber +@OptIn(ExperimentalMaterialApi::class) @Composable fun MessagesView( state: MessagesState, @@ -239,6 +235,7 @@ fun MessagesViewContent( } } +@OptIn(ExperimentalMaterial3Api::class) @Composable fun MessagesViewTopBar( roomTitle: String?, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt index c2becf71cf..9dcabd8af7 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalMaterialApi::class) - package io.element.android.features.messages.impl.actionlist import androidx.compose.foundation.clickable @@ -49,6 +47,7 @@ import io.element.android.libraries.designsystem.theme.components.ModalBottomShe import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch +@OptIn(ExperimentalMaterialApi::class) @Composable fun ActionListView( state: ActionListState, @@ -90,6 +89,7 @@ fun ActionListView( ) } +@OptIn(ExperimentalMaterialApi::class) @Composable private fun SheetContent( state: ActionListState, @@ -145,6 +145,7 @@ fun SheetContentLightPreview(@PreviewParameter(ActionListStateProvider::class) s fun SheetContentDarkPreview(@PreviewParameter(ActionListStateProvider::class) state: ActionListState) = ElementPreviewDark { ContentToPreview(state) } +@OptIn(ExperimentalMaterialApi::class) @Composable private fun ContentToPreview(state: ActionListState) { ActionListView( 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 0c0b46cbe2..9639759529 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 @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package io.element.android.features.messages.textcomposer import app.cash.molecule.RecompositionClock @@ -52,7 +50,6 @@ import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor import io.element.android.libraries.textcomposer.MessageComposerMode import io.mockk.mockk import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest diff --git a/features/onboarding/impl/src/main/kotlin/io/element/android/features/onboarding/impl/OnBoardingScreen.kt b/features/onboarding/impl/src/main/kotlin/io/element/android/features/onboarding/impl/OnBoardingScreen.kt index 9fb54c7b45..8694865938 100644 --- a/features/onboarding/impl/src/main/kotlin/io/element/android/features/onboarding/impl/OnBoardingScreen.kt +++ b/features/onboarding/impl/src/main/kotlin/io/element/android/features/onboarding/impl/OnBoardingScreen.kt @@ -41,7 +41,6 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.HorizontalPagerIndicator import com.google.accompanist.pager.rememberPagerState @@ -53,9 +52,7 @@ import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.testtags.testTag import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import io.element.android.libraries.ui.strings.R as StringR -@OptIn(ExperimentalPagerApi::class) @Composable fun OnBoardingScreen( modifier: Modifier = Modifier, diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt index 3a3ea3daa1..07facd77bd 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt @@ -54,7 +54,6 @@ import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.user.MatrixUser -@OptIn(ExperimentalMaterial3Api::class) @Composable fun RoomMemberListView( state: RoomMemberListState, diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListView.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListView.kt index d41b8c28fc..acfc822658 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListView.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListView.kt @@ -116,7 +116,7 @@ fun RoomListView( } } -@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) +@OptIn(ExperimentalMaterial3Api::class) @Composable fun RoomListContent( state: RoomListState, diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListTopBar.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListTopBar.kt index 32bf30b082..f7fee35c75 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListTopBar.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListTopBar.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalMaterial3Api::class) - package io.element.android.features.roomlist.impl.components import androidx.activity.compose.BackHandler diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 40d89b7dd2..1138ad49d3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,7 +19,7 @@ activity = "1.7.1" startup = "1.1.1" # Compose -compose_bom = "2023.04.01" +compose_bom = "2023.05.01" composecompiler = "1.4.7" # Coroutines diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/preferences/PreferenceScreen.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/preferences/PreferenceScreen.kt index 531c18ed6b..03ba290829 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/preferences/PreferenceScreen.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/preferences/PreferenceScreen.kt @@ -45,7 +45,6 @@ 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 -@OptIn(ExperimentalMaterial3Api::class) @Composable fun PreferenceView( title: String, diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/CenterAlignedTopAppBar.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/CenterAlignedTopAppBar.kt index 5c2e741814..dab180e1c2 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/CenterAlignedTopAppBar.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/CenterAlignedTopAppBar.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalMaterial3Api::class) - package io.element.android.libraries.designsystem.theme.components import androidx.compose.foundation.layout.RowScope diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/MediumTopAppBar.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/MediumTopAppBar.kt index 7f864bcb5c..d3cd2fee07 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/MediumTopAppBar.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/MediumTopAppBar.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalMaterial3Api::class) - package io.element.android.libraries.designsystem.theme.components import androidx.compose.foundation.layout.RowScope @@ -57,6 +55,7 @@ fun MediumTopAppBar( internal fun MediumTopAppBarPreview() = ElementThemedPreview { ContentToPreview() } +@OptIn(ExperimentalMaterial3Api::class) @Composable private fun ContentToPreview() { MediumTopAppBar(title = { Text(text = "Title") }) 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 95d603b9dd..2f40a90615 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 @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalMaterialApi::class, ExperimentalMaterialApi::class) - package io.element.android.libraries.designsystem.theme.components import androidx.compose.foundation.background @@ -107,6 +105,7 @@ internal fun ModalBottomSheetLayoutLightPreview() = internal fun ModalBottomSheetLayoutDarkPreview() = ElementPreviewDark { ContentToPreview() } +@OptIn(ExperimentalMaterialApi::class) @Composable private fun ContentToPreview() { ModalBottomSheetLayout( diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/OutlinedTextField.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/OutlinedTextField.kt index 046dc5aa89..4bca15daca 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/OutlinedTextField.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/OutlinedTextField.kt @@ -49,7 +49,7 @@ import io.element.android.libraries.designsystem.preview.PreviewGroup import io.element.android.libraries.designsystem.utils.allBooleans import io.element.android.libraries.designsystem.utils.asInt -@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class) +@OptIn(ExperimentalMaterial3Api::class) @Composable fun OutlinedTextField( value: String, diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/Scaffold.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/Scaffold.kt index 99a69c0553..20e30e55b3 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/Scaffold.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/Scaffold.kt @@ -18,7 +18,6 @@ package io.element.android.libraries.designsystem.theme.components import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FabPosition import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ScaffoldDefaults @@ -27,7 +26,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -@OptIn(ExperimentalMaterial3Api::class) @Composable fun Scaffold( modifier: Modifier = Modifier, diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SearchBar.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SearchBar.kt index ca25501446..9a037cb7bb 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SearchBar.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SearchBar.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalMaterial3Api::class) - package io.element.android.libraries.designsystem.theme.components import androidx.compose.foundation.interaction.MutableInteractionSource @@ -77,6 +75,7 @@ fun SearchBar( @Composable internal fun DockedSearchBarPreview() = ElementThemedPreview { ContentToPreview() } +@OptIn(ExperimentalMaterial3Api::class) @Composable private fun ContentToPreview() { SearchBar( diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/TopAppBar.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/TopAppBar.kt index 602818f233..23848ef76d 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/TopAppBar.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/TopAppBar.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalMaterial3Api::class) - package io.element.android.libraries.designsystem.theme.components import androidx.compose.foundation.layout.RowScope diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index 8709db67f0..7f1b78ebf7 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package io.element.android.libraries.matrix.impl import io.element.android.libraries.core.coroutine.CoroutineDispatchers @@ -46,7 +44,6 @@ import io.element.android.libraries.matrix.impl.verification.RustSessionVerifica import io.element.android.libraries.sessionstorage.api.SessionStore import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.filter diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomSummaryDataSource.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomSummaryDataSource.kt index c908651e75..2574e96d3b 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomSummaryDataSource.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomSummaryDataSource.kt @@ -91,7 +91,6 @@ internal class RustRoomSummaryDataSource( coroutineScope.cancel() } - //@OptIn(FlowPreview::class) override fun roomSummaries(): StateFlow> { return roomSummaries } diff --git a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt index 885a830b96..962cb2c18d 100644 --- a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt +++ b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt @@ -43,9 +43,7 @@ fun DependencyHandlerScope.composeDependencies(libs: LibrariesForLibs) { androidTestImplementation(composeBom) implementation("androidx.compose.ui:ui") implementation("androidx.compose.material:material") - // Override BOM version, SearchBar is not available in the actual version - // do not use latest version because of clashes on androidx lifecycle dependency - implementation("androidx.compose.material3:material3:1.1.0-alpha04") + implementation("androidx.compose.material3:material3") implementation("androidx.compose.material:material-icons-extended") implementation("androidx.compose.ui:ui-tooling-preview") implementation(libs.androidx.activity.compose) diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt index 1accae8464..ef776c613c 100644 --- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalMaterial3Api::class) - package io.element.android.samples.minimal import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue diff --git a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/TestCoroutineDispatchers.kt b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/TestCoroutineDispatchers.kt index 1309a14cb1..e155eabd73 100644 --- a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/TestCoroutineDispatchers.kt +++ b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/TestCoroutineDispatchers.kt @@ -14,12 +14,9 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package io.element.android.tests.testutils import io.element.android.libraries.core.coroutine.CoroutineDispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestCoroutineScheduler import kotlinx.coroutines.test.TestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher From ac515afae33cea42f3ee078ae638ac3093993db5 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 15 May 2023 13:24:27 +0200 Subject: [PATCH 17/36] Now that we have a CODEOWNERS file, there is no need for Renovate to assign a reviewer. It will be done automatically by GitHub. --- .github/renovate.json | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/renovate.json b/.github/renovate.json index 11f993516f..f9e1469496 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -4,7 +4,6 @@ "config:base" ], "labels": ["dependencies"], - "reviewers": ["team:element-x-android-reviewers"], "ignoreDeps": ["string:app_name"], "packageRules": [ { From e2f4ec3cf0eb629eb5fa9dc78e49676dd2dfbbde Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 15 May 2023 13:43:27 +0200 Subject: [PATCH 18/36] Fix more warning and replace deprecated code. Also use `TextField` from our components. --- .../features/roomlist/impl/search/RoomListSearch.kt | 11 ++++++----- .../theme/components/OutlinedTextField.kt | 8 +++----- .../designsystem/theme/components/TextField.kt | 6 ++---- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/search/RoomListSearch.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/search/RoomListSearch.kt index c2baca9a6b..021959c3aa 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/search/RoomListSearch.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/search/RoomListSearch.kt @@ -20,7 +20,6 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn @@ -30,7 +29,6 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable @@ -60,6 +58,7 @@ import io.element.android.libraries.designsystem.modifiers.applyIf 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.Scaffold +import io.element.android.libraries.designsystem.theme.components.TextField import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.utils.copy import io.element.android.libraries.matrix.api.core.RoomId @@ -128,12 +127,14 @@ internal fun RoomListSearchResultContent( .focusRequester(focusRequester), value = filter, onValueChange = { state.eventSink(RoomListEvents.UpdateFilter(it)) }, - colors = TextFieldDefaults.textFieldColors( - containerColor = Color.Transparent, + colors = TextFieldDefaults.colors( + focusedContainerColor = Color.Transparent, + unfocusedContainerColor = Color.Transparent, + disabledContainerColor = Color.Transparent, focusedIndicatorColor = Color.Transparent, unfocusedIndicatorColor = Color.Transparent, + disabledIndicatorColor = Color.Transparent, errorIndicatorColor = Color.Transparent, - disabledIndicatorColor = Color.Transparent ), trailingIcon = { if (filter.isNotEmpty()) { diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/OutlinedTextField.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/OutlinedTextField.kt index 4bca15daca..e0edeed050 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/OutlinedTextField.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/OutlinedTextField.kt @@ -23,10 +23,9 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.LocalTextStyle +import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.TextFieldColors -import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.ExperimentalComposeUiApi @@ -49,7 +48,6 @@ import io.element.android.libraries.designsystem.preview.PreviewGroup import io.element.android.libraries.designsystem.utils.allBooleans import io.element.android.libraries.designsystem.utils.asInt -@OptIn(ExperimentalMaterial3Api::class) @Composable fun OutlinedTextField( value: String, @@ -70,8 +68,8 @@ fun OutlinedTextField( singleLine: Boolean = false, maxLines: Int = Int.MAX_VALUE, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, - shape: Shape = TextFieldDefaults.outlinedShape, - colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors() + shape: Shape = OutlinedTextFieldDefaults.shape, + colors: TextFieldColors = OutlinedTextFieldDefaults.colors() ) { androidx.compose.material3.OutlinedTextField( value = value, diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/TextField.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/TextField.kt index a4f07a61fb..54fe50b8bf 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/TextField.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/TextField.kt @@ -23,7 +23,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.TextFieldColors import androidx.compose.material3.TextFieldDefaults @@ -50,7 +49,6 @@ import io.element.android.libraries.designsystem.preview.PreviewGroup import io.element.android.libraries.designsystem.utils.allBooleans import io.element.android.libraries.designsystem.utils.asInt -@OptIn(ExperimentalMaterial3Api::class) @Composable fun TextField( value: String, @@ -71,8 +69,8 @@ fun TextField( singleLine: Boolean = false, maxLines: Int = Int.MAX_VALUE, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, - shape: Shape = TextFieldDefaults.filledShape, - colors: TextFieldColors = TextFieldDefaults.textFieldColors() + shape: Shape = TextFieldDefaults.shape, + colors: TextFieldColors = TextFieldDefaults.colors() ) { androidx.compose.material3.TextField( value = value, From 8547d5f267881c3e692d1014db909cb530a4a4db Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 15 May 2023 13:50:21 +0200 Subject: [PATCH 19/36] Record screenshots. --- ...up_LabelledTextFieldDarkPreview_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...p_LabelledTextFieldLightPreview_0_null,NEXUS_5,1.0,en].png | 4 ++-- ..._ConfigureRoomViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png | 4 ++-- ..._ConfigureRoomViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...ConfigureRoomViewLightPreview_0_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ConfigureRoomViewLightPreview_0_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...p_ChangeServerViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...p_ChangeServerViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...p_ChangeServerViewDarkPreview_0_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...p_ChangeServerViewDarkPreview_0_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...p_ChangeServerViewDarkPreview_0_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...p_ChangeServerViewDarkPreview_0_null_5,NEXUS_5,1.0,en].png | 4 ++-- ..._ChangeServerViewLightPreview_0_null_0,NEXUS_5,1.0,en].png | 4 ++-- ..._ChangeServerViewLightPreview_0_null_1,NEXUS_5,1.0,en].png | 4 ++-- ..._ChangeServerViewLightPreview_0_null_2,NEXUS_5,1.0,en].png | 4 ++-- ..._ChangeServerViewLightPreview_0_null_3,NEXUS_5,1.0,en].png | 4 ++-- ..._ChangeServerViewLightPreview_0_null_4,NEXUS_5,1.0,en].png | 4 ++-- ..._ChangeServerViewLightPreview_0_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...up_LoginRootScreenDarkPreview_0_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...up_LoginRootScreenDarkPreview_0_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...up_LoginRootScreenDarkPreview_0_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...up_LoginRootScreenDarkPreview_0_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...p_LoginRootScreenLightPreview_0_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...p_LoginRootScreenLightPreview_0_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...p_LoginRootScreenLightPreview_0_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...p_LoginRootScreenLightPreview_0_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...roup_BugReportViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...roup_BugReportViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...roup_BugReportViewDarkPreview_0_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...oup_BugReportViewLightPreview_0_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...oup_BugReportViewLightPreview_0_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...oup_BugReportViewLightPreview_0_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...s_OutlinedTextFieldsDarkPreview_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...ields_OutlinedTextFieldsPreview_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...TextFields_TextFieldDarkPreview_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...extFields_TextFieldLightPreview_0_null,NEXUS_5,1.0,en].png | 4 ++-- 36 files changed, 72 insertions(+), 72 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.components_null_DefaultGroup_LabelledTextFieldDarkPreview_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.features.createroom.impl.components_null_DefaultGroup_LabelledTextFieldDarkPreview_0_null,NEXUS_5,1.0,en].png index 2b77d948e4..7daf56c098 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.components_null_DefaultGroup_LabelledTextFieldDarkPreview_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.features.createroom.impl.components_null_DefaultGroup_LabelledTextFieldDarkPreview_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f92e4287ae8db895d18452840a29240989597dea560640244b8188ee61e8c266 -size 30730 +oid sha256:57c89db393e87207bb9628244c435ee1541df327814d1ef7f296b80df8b8100c +size 30821 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.components_null_DefaultGroup_LabelledTextFieldLightPreview_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.features.createroom.impl.components_null_DefaultGroup_LabelledTextFieldLightPreview_0_null,NEXUS_5,1.0,en].png index c36b73a560..55b5f262b6 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.components_null_DefaultGroup_LabelledTextFieldLightPreview_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.features.createroom.impl.components_null_DefaultGroup_LabelledTextFieldLightPreview_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c66806646645afee1654b50818c539863e60129eba7fcd608e9801bd34d0fe30 -size 30028 +oid sha256:89bcb8fd5b3f68fbfc1568cd5e7d5c7bbabd3ca05836fbb1d8e75fbc32379317 +size 30222 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewDarkPreview_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.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png index 699b8973c1..160def016f 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewDarkPreview_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.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:756d835de7820c96019995ab47d34c2663330c4ddc9ca124eac266ea9eeef0ab -size 64397 +oid sha256:24ad0b5edc27ddddca573b37f82579715d880793c0dc880248d2b572dd6d6a40 +size 64379 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewDarkPreview_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.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png index 62e855dab1..c6a054a2d3 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewDarkPreview_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.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:df7631ad85dc6b3fbdabfc820b11b4e12a6128202e3faa2d105ba22793fe8c22 -size 103428 +oid sha256:b0c9d4eaaaf6a691f43d25e0855ee056b69fa090ad8c53b26732c8f2532e2138 +size 103384 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewLightPreview_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.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewLightPreview_0_null_0,NEXUS_5,1.0,en].png index a9a3720ece..26129e266a 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewLightPreview_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.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewLightPreview_0_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a03aa11c787804adc5b2947359421b90e6abcdc7e840983a0276a6e02da59a2f -size 58526 +oid sha256:4023481d2a045d7e0d824db81b28ee47c4bcdc568d98537b3573d554e0b76e32 +size 58445 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewLightPreview_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.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewLightPreview_0_null_1,NEXUS_5,1.0,en].png index 4045dae649..af4d0b2046 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewLightPreview_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.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewLightPreview_0_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3c2731ea21ca5b001aadc29ecbb15a2b263b0c042b7344cb10149174ff88ec0a -size 96835 +oid sha256:8f953d0df467ad4cd1ae24291e9593945b945712506f093bdcae3da975f8ca91 +size 96800 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png index 7aa5b9b9ba..f2249286f5 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2fac7314c1dee8d4570922b984b0749f24ec8984e5e602892e2e4ed925d143b6 -size 41145 +oid sha256:c9e1058bff99d3193f3e69d7635a0446f76295ecdd47a16b03e39690a7a4852f +size 41232 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png index bcae624eb5..5332196c0c 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dff29249aabb7818151e55dbc9a1290bc09cf0e638e3ad2842791904b14368ca -size 44381 +oid sha256:42e2f813350feb63441492b67653fd22edb311d4e7068d32a42a537c9e78e94f +size 44632 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_2,NEXUS_5,1.0,en].png index ba0061da9b..eae8a2c125 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5450116320f6d75befbc784a31a8ad51c868936794e75e65bf24e6e1b69f1e23 -size 44421 +oid sha256:29c3ac70cd3f7a66d2be73996fe93825f850bb5a73312e9a0f2434a5e7003035 +size 44631 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_3,NEXUS_5,1.0,en].png index 1bea49ba74..3f6519d314 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4363256d328a0ab2cc3966b42827c7a7319bee962710a0bac542f6494799ff71 -size 48526 +oid sha256:494167e5d7f96bf16b16f5b7c53b304dacf4015b31ce0cd51bfe9e05802664df +size 48831 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_4,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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_4,NEXUS_5,1.0,en].png index 6740abc12a..7f8690a106 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_4,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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:afa9ab67471727f4c396d1919fd1187ec28a40b8cb9b03c2b35400c5e32f4eda -size 43776 +oid sha256:746b009cb527d5ed6be3c8b30bac9465c42970bd9766e259aee2957aaeb96da7 +size 44007 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_5,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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_5,NEXUS_5,1.0,en].png index 17f36f745e..d6ebbc9165 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_5,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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewDarkPreview_0_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6b724d1b93a04117fc3cc405920fd22530e004cc9ba9c39f88ca1a2a2a4229c4 -size 43743 +oid sha256:cc677f36b2262eabc091023be5a373aaa51d47237fc6777d9b4950f16efa6ea2 +size 43964 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_0,NEXUS_5,1.0,en].png index d97cb348db..0827e7d026 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28c23058fdd9b24a7079251a2ab1ae2f85dafe0c1d4f01be3ffeca91984e0805 -size 37703 +oid sha256:ad6c6bdc7d4e4c405231c2c8944613ff151eb309e00821ac7eda107e853ed456 +size 37891 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_1,NEXUS_5,1.0,en].png index 2520176bfd..e005e5910d 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7779d6bf28eca6e72f9f1bcbd8b27881d0df0e594041269367a1f909e941cec9 -size 41368 +oid sha256:4cfd887060df1a1b7e12e3f47010e813678fec822595d90b19c51af99b42ab16 +size 41714 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_2,NEXUS_5,1.0,en].png index c48eee4f48..32208a1dde 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:af77d0276f38c78524201c49484548e29d1c99168e68e11874c49f0db0803df2 -size 41392 +oid sha256:ede9377d3fbceae95a10e02cb1c033f9bbd53901137ef88ca52fdd4041737c70 +size 41695 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_3,NEXUS_5,1.0,en].png index d5c33e67c3..72944ac735 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:27d2d879493e8ed1cc17dcdbb384504126fad63eb7e53a069f530457c35b94b3 -size 47609 +oid sha256:6a976609ec6f5ce83388242db7a43ff6c062f84011ce7d2263e5ff8d23c64a96 +size 47912 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_4,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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_4,NEXUS_5,1.0,en].png index 488e1403d4..2b16953c1c 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_4,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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:66e9060ad93cec0e1bf8e284ac959a713a8201a33ff931aeb61aaf29ab7d9640 -size 40335 +oid sha256:e0a065c5a4c0af748524b0600e1b5233023cdff0eaae8a2039649323e8a19fe3 +size 40635 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_5,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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_5,NEXUS_5,1.0,en].png index 1cc8419b21..bb4d824ee8 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_5,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.login.impl.changeserver_null_DefaultGroup_ChangeServerViewLightPreview_0_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7f7ecb805b73afe15db56853fec77d92f28fc9f8080dc7f1b2bb9f99cc262719 -size 40317 +oid sha256:dfa33ed990249e2d3e0097521bc51a3028bf51537736839a1301b54f99ad473b +size 40598 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.root_null_DefaultGroup_LoginRootScreenDarkPreview_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.login.impl.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_2,NEXUS_5,1.0,en].png index 558ba024ca..1277ac6fa1 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.root_null_DefaultGroup_LoginRootScreenDarkPreview_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.login.impl.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1501fd1372e15cd6f7693c4c854afcfd5ade3eb7a972f8cc76aea10de8416a20 -size 33382 +oid sha256:2bd0026073c5d0b7bb916bff9a034aca6393d005e299298f089f2f64d541f166 +size 33301 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.root_null_DefaultGroup_LoginRootScreenDarkPreview_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.login.impl.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_3,NEXUS_5,1.0,en].png index 8341e4aa97..9919e584a6 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.root_null_DefaultGroup_LoginRootScreenDarkPreview_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.login.impl.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:762a1d43dc3bc9edfa47f081b8385614f7075b5cecdd3eb3cb6b4959baf6811c -size 33445 +oid sha256:cbf81d780ebde2c089327df2b1397a6b879b9729dacefa78304e0d16e0a4dc11 +size 33318 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_4,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.login.impl.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_4,NEXUS_5,1.0,en].png index a0dbfd3863..a73c22ff1a 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_4,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.login.impl.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7559f64cb74c33ef441dd15d557607061b72ffcdd3dce7ec7f8a663d928fd681 -size 29585 +oid sha256:4777def89f3b8717c8f9cba0023d33d8e244b3041270d283da28b813fd8f52ad +size 29606 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_5,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.login.impl.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_5,NEXUS_5,1.0,en].png index 558ba024ca..1277ac6fa1 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_5,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.login.impl.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1501fd1372e15cd6f7693c4c854afcfd5ade3eb7a972f8cc76aea10de8416a20 -size 33382 +oid sha256:2bd0026073c5d0b7bb916bff9a034aca6393d005e299298f089f2f64d541f166 +size 33301 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.root_null_DefaultGroup_LoginRootScreenLightPreview_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.login.impl.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_2,NEXUS_5,1.0,en].png index d713681419..0ec9d0351d 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.root_null_DefaultGroup_LoginRootScreenLightPreview_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.login.impl.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:68ef9478a9bbf361a7ace91b9214c6fca449a23b2756f0e0692e634f25c98181 -size 32385 +oid sha256:3eaf06ed9c04ad6b2d9314e7305b4c090cc5d78e6621628eed5c16a9e2738c0d +size 32196 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.root_null_DefaultGroup_LoginRootScreenLightPreview_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.login.impl.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_3,NEXUS_5,1.0,en].png index 7140bc573f..bd0731900e 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.root_null_DefaultGroup_LoginRootScreenLightPreview_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.login.impl.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2fafe08ac635bf3f0e62753c832ead92de297f0826ec735efe1a1f90481cb421 -size 32417 +oid sha256:227596a612d3e87d4dd55ef43068875b1d50e334056b48e956e2708e5ed10645 +size 32220 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_4,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.login.impl.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_4,NEXUS_5,1.0,en].png index a7010b4602..36576c6d42 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_4,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.login.impl.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7954d3f7064666b287ce6ab05fb6814f0e4570db2db6a44437291f0f90d8e87f -size 29062 +oid sha256:beeb25a16dd5662be9b633b761fae145b91515859f87bda2399323c38cc0e561 +size 28995 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_5,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.login.impl.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_5,NEXUS_5,1.0,en].png index d713681419..0ec9d0351d 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.impl.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_5,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.login.impl.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:68ef9478a9bbf361a7ace91b9214c6fca449a23b2756f0e0692e634f25c98181 -size 32385 +oid sha256:3eaf06ed9c04ad6b2d9314e7305b4c090cc5d78e6621628eed5c16a9e2738c0d +size 32196 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewDarkPreview_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.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png index a1f391b1b1..cd34f90d2b 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewDarkPreview_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.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d38eddd629e8c46993e616ed5bab2689fa5f24bb023ae43afca1a41ef5381ea5 -size 59843 +oid sha256:847c42b0aec8b12708f2a429bbbe2a86ca2b149b5963dd16135f3b34d9d0c073 +size 60153 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewDarkPreview_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.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png index 2968e30033..07451a0330 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewDarkPreview_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.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9630d9b5e3d26b677eaa8c0496d76d73f95d28a487ef0ef845d3a89747d6a8cb -size 179668 +oid sha256:628f1f00dca9d15faabd8288a3c54b1b8581a380cf14edf364f0dee9ecc187d5 +size 180117 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewDarkPreview_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.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewDarkPreview_0_null_2,NEXUS_5,1.0,en].png index 2d89c7181f..87ba73daee 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewDarkPreview_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.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewDarkPreview_0_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dcff656fe8f2b1233dc55e5e4bc80800aa8ed511bb328b178f8944c83d4199a2 -size 59284 +oid sha256:43974ffd4bec4c2d8e07a6d4798f00db1aec316a11633c6d2eb5c6608deb694d +size 59586 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewLightPreview_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.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewLightPreview_0_null_0,NEXUS_5,1.0,en].png index 3dba4f5dbc..a86c5980de 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewLightPreview_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.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewLightPreview_0_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:60ee09b1052414f00af4d80dcf63c738d7dc937f5d58a3a043840cacc3618317 -size 58781 +oid sha256:18597d5e200b7079201cfa169ac3f9266c089b7dadde691c750192d2e22c1dea +size 59035 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewLightPreview_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.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewLightPreview_0_null_1,NEXUS_5,1.0,en].png index 3292b422ee..8146c241cb 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewLightPreview_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.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewLightPreview_0_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f8ad5f69dbcda0284f731a01851fc73dc93ba9b1fad9e778b23f0155bfc7107 -size 178346 +oid sha256:827bccb0fdd3106fb24a95d665b4da2cfc15de48e8f508ae809c9f75d6d1bbf0 +size 178915 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewLightPreview_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.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewLightPreview_0_null_2,NEXUS_5,1.0,en].png index 4470d22005..7aa17c8c18 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewLightPreview_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.rageshake.impl.bugreport_null_DefaultGroup_BugReportViewLightPreview_0_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f01532b48a428362db2f963861a0ec5731ee3b1f13869a526facce3a85f82e8f -size 56677 +oid sha256:6bfb40e55460e4c11fdf0f020982b63e2b726a329902ceaa57522bafa328789d +size 56987 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_TextFields_OutlinedTextFieldsDarkPreview_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_TextFields_OutlinedTextFieldsDarkPreview_0_null,NEXUS_5,1.0,en].png index a1f82c98d8..a75c5f4399 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_TextFields_OutlinedTextFieldsDarkPreview_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_TextFields_OutlinedTextFieldsDarkPreview_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:02be8bb5887ed87aadc9758466cd4f3c622255fd32bccd347cedb70f509efa73 -size 49879 +oid sha256:916228ae8244eb2dd1602d6e3030890138d92c0775e1c8d8c11fcea810b32e6a +size 50153 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_TextFields_OutlinedTextFieldsPreview_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_TextFields_OutlinedTextFieldsPreview_0_null,NEXUS_5,1.0,en].png index 29d860ddc9..2fe01fc5ff 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_TextFields_OutlinedTextFieldsPreview_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_TextFields_OutlinedTextFieldsPreview_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:38fdce46be1fd5acf8c8f9e23e59a1cae5f458daa191d7ba9fde6c929b380823 -size 45128 +oid sha256:914aecd8cef405ffd0c8d33b65d718ecad50060e95cb4b866de914a79c5ce6aa +size 45342 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_TextFields_TextFieldDarkPreview_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_TextFields_TextFieldDarkPreview_0_null,NEXUS_5,1.0,en].png index 80f1a795af..c802637d6c 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_TextFields_TextFieldDarkPreview_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_TextFields_TextFieldDarkPreview_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:505c2f4449cf297eec253c4a027b268e7f774bebd65dce94b651578b4659cb1f -size 55908 +oid sha256:52de83a9b21ff774b53db05f287fd76dcae248e6f509f8ff9873d1a252313dc2 +size 55177 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_TextFields_TextFieldLightPreview_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_TextFields_TextFieldLightPreview_0_null,NEXUS_5,1.0,en].png index 70831eed9a..afe53b155a 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_TextFields_TextFieldLightPreview_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_TextFields_TextFieldLightPreview_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f44ac6df2ab5199c0243c2b01e503912f2272657223abf1de22b359b2df2dfd -size 55733 +oid sha256:12283d22402cc6bb118e8ea5c2ef6c294f46e8c0f5d594ddfb374931e2717069 +size 55224 From b51c19af19198f01e549706aa3473d44ff3434f8 Mon Sep 17 00:00:00 2001 From: Marco Romano Date: Mon, 15 May 2023 14:39:27 +0200 Subject: [PATCH 20/36] Show pending invitations in room members list (#385) Splits a Room's member list in 2 showing pending invitees first and then the actual room member. This simple user facing change entails a host of under the hood changes: - It copies the logic from the `userlist` module and merges it into the `roomdetails` module removing all details not related to the member list (e.g. gets rid of multiple selection, debouncing etc.). - Uncouples the `roomdetails` module from the `userlist` one. Now leaving only the `createroom` module to depend on the `userlist` module. Therefore the `userlist` module could be in the future completely removed and merged into the `createroom` module. - Changes the room members count in the room details screen to only show the members who have joined (i.e. don't count those still in the invited state). Missed ACs: - This change does not make the member list live update. Discussion is ongoing on how to make this technically feasible. Parent issue: - https://github.com/vector-im/element-x-android/issues/246 --- changelog.d/385.feature | 1 + features/roomdetails/impl/build.gradle.kts | 2 - .../roomdetails/impl/RoomDetailsPresenter.kt | 3 +- ...omMemberModules.kt => RoomMemberModule.kt} | 16 +- ...aSource.kt => RoomMemberListDataSource.kt} | 16 +- .../impl/members/RoomMemberListEvents.kt | 5 +- .../impl/members/RoomMemberListPresenter.kt | 71 ++++-- .../impl/members/RoomMemberListState.kt | 26 +- .../members/RoomMemberListStateProvider.kt | 94 ++++++-- .../impl/members/RoomMemberListView.kt | 228 +++++++++++++++--- .../roomdetails/RoomDetailsPresenterTests.kt | 25 +- .../members/RoomMemberListPresenterTests.kt | 127 +++++++--- .../RoomMemberDetailsPresenterTests.kt | 2 +- .../libraries/matrix/api/room/RoomMember.kt | 7 - ...stDarkPreview_0_null_0,NEXUS_5,1.0,en].png | 4 +- ...stDarkPreview_0_null_2,NEXUS_5,1.0,en].png | 3 + ...stDarkPreview_0_null_3,NEXUS_5,1.0,en].png | 3 + ...stDarkPreview_0_null_4,NEXUS_5,1.0,en].png | 3 + ...stDarkPreview_0_null_5,NEXUS_5,1.0,en].png | 3 + ...stDarkPreview_0_null_6,NEXUS_5,1.0,en].png | 3 + ...tLightPreview_0_null_0,NEXUS_5,1.0,en].png | 4 +- ...tLightPreview_0_null_2,NEXUS_5,1.0,en].png | 3 + ...tLightPreview_0_null_3,NEXUS_5,1.0,en].png | 3 + ...tLightPreview_0_null_4,NEXUS_5,1.0,en].png | 3 + ...tLightPreview_0_null_5,NEXUS_5,1.0,en].png | 3 + ...tLightPreview_0_null_6,NEXUS_5,1.0,en].png | 3 + 26 files changed, 477 insertions(+), 184 deletions(-) create mode 100644 changelog.d/385.feature rename features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/di/{RoomMemberModules.kt => RoomMemberModule.kt} (75%) rename features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/{RoomUserListDataSource.kt => RoomMemberListDataSource.kt} (75%) create mode 100644 tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_2,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_3,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_4,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_5,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_6,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_2,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_3,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_4,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_5,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_6,NEXUS_5,1.0,en].png diff --git a/changelog.d/385.feature b/changelog.d/385.feature new file mode 100644 index 0000000000..5b6cfbfff1 --- /dev/null +++ b/changelog.d/385.feature @@ -0,0 +1 @@ +Show pending invitations in room members list diff --git a/features/roomdetails/impl/build.gradle.kts b/features/roomdetails/impl/build.gradle.kts index 41f117d6a4..7b072a5faf 100644 --- a/features/roomdetails/impl/build.gradle.kts +++ b/features/roomdetails/impl/build.gradle.kts @@ -40,7 +40,6 @@ dependencies { implementation(projects.libraries.designsystem) implementation(projects.libraries.elementresources) implementation(projects.libraries.uiStrings) - implementation(projects.features.userlist.api) implementation(projects.libraries.androidutils) api(projects.features.roomdetails.api) implementation(libs.coil.compose) @@ -51,7 +50,6 @@ dependencies { testImplementation(libs.test.truth) testImplementation(libs.test.turbine) testImplementation(projects.libraries.matrix.test) - testImplementation(projects.features.userlist.impl) testImplementation(projects.features.userlist.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 8f96487583..81b2e1e383 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 @@ -34,6 +34,7 @@ import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomMembershipObserver +import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.ui.room.getDirectRoomMember import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -124,7 +125,7 @@ class RoomDetailsPresenter @Inject constructor( MatrixRoomMembersState.Unknown -> Async.Uninitialized is MatrixRoomMembersState.Pending -> Async.Loading(prevState = membersState.prevRoomMembers?.size) is MatrixRoomMembersState.Error -> Async.Failure(membersState.failure, prevState = membersState.prevRoomMembers?.size) - is MatrixRoomMembersState.Ready -> Async.Success(membersState.roomMembers.size) + is MatrixRoomMembersState.Ready -> Async.Success(membersState.roomMembers.count { it.membership == RoomMembershipState.JOIN }) } } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/di/RoomMemberModules.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/di/RoomMemberModule.kt similarity index 75% rename from features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/di/RoomMemberModules.kt rename to features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/di/RoomMemberModule.kt index 2cd3b7eb08..ca462c6507 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/di/RoomMemberModules.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/di/RoomMemberModule.kt @@ -17,31 +17,17 @@ package io.element.android.features.roomdetails.impl.di import com.squareup.anvil.annotations.ContributesTo -import dagger.Binds import dagger.Module import dagger.Provides -import io.element.android.features.roomdetails.impl.members.RoomUserListDataSource import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter -import io.element.android.features.userlist.api.UserListDataSource import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.RoomMember -import javax.inject.Named @Module @ContributesTo(RoomScope::class) -interface RoomMemberBindsModule { - - @Binds - @Named("RoomMembers") - fun bindRoomMemberUserListDataSource(dataSource: RoomUserListDataSource): UserListDataSource -} - -@Module -@ContributesTo(RoomScope::class) -object RoomMemberProvidesModule { +object RoomMemberModule { @Provides fun provideRoomMemberDetailsPresenterFactory( diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomUserListDataSource.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListDataSource.kt similarity index 75% rename from features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomUserListDataSource.kt rename to features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListDataSource.kt index b8c73526ed..5a9c30698b 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomUserListDataSource.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListDataSource.kt @@ -16,27 +16,23 @@ package io.element.android.features.roomdetails.impl.members -import io.element.android.features.userlist.api.UserListDataSource import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.core.coroutine.CoroutineDispatchers -import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.roomMembers -import io.element.android.libraries.matrix.api.room.toMatrixUser -import io.element.android.libraries.matrix.api.user.MatrixUser import kotlinx.coroutines.flow.dropWhile import kotlinx.coroutines.flow.first import kotlinx.coroutines.withContext import javax.inject.Inject -class RoomUserListDataSource @Inject constructor( +class RoomMemberListDataSource @Inject constructor( private val room: MatrixRoom, private val coroutineDispatchers: CoroutineDispatchers, -) : UserListDataSource { +) { - override suspend fun search(query: String): List = withContext(coroutineDispatchers.io) { + suspend fun search(query: String): List = withContext(coroutineDispatchers.io) { val roomMembers = room.membersStateFlow .dropWhile { it !is MatrixRoomMembersState.Ready } .first() @@ -50,11 +46,7 @@ class RoomUserListDataSource @Inject constructor( || member.displayName?.contains(query, ignoreCase = true).orFalse() } } - filteredMembers.map(RoomMember::toMatrixUser) - } - - override suspend fun getProfile(userId: UserId): MatrixUser? { - return null + filteredMembers } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListEvents.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListEvents.kt index 964a87eaf0..43716660eb 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListEvents.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListEvents.kt @@ -16,8 +16,7 @@ package io.element.android.features.roomdetails.impl.members -import io.element.android.libraries.matrix.api.user.MatrixUser - sealed interface RoomMemberListEvents { - data class SelectUser(val user: MatrixUser) : RoomMemberListEvents + data class UpdateSearchQuery(val query: String) : RoomMemberListEvents + data class OnSearchActiveChanged(val active: Boolean) : RoomMemberListEvents } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt index 0cc893f9e1..3a719983b6 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt @@ -18,54 +18,73 @@ package io.element.android.features.roomdetails.impl.members import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import io.element.android.features.userlist.api.SelectionMode -import io.element.android.features.userlist.api.UserListDataSource -import io.element.android.features.userlist.api.UserListDataStore -import io.element.android.features.userlist.api.UserListPresenter -import io.element.android.features.userlist.api.UserListPresenterArgs +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.coroutine.CoroutineDispatchers -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.user.MatrixUser -import kotlinx.collections.immutable.ImmutableList +import io.element.android.libraries.matrix.api.room.RoomMembershipState import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.withContext import javax.inject.Inject -import javax.inject.Named class RoomMemberListPresenter @Inject constructor( - private val userListPresenterFactory: UserListPresenter.Factory, - @Named("RoomMembers") private val userListDataSource: UserListDataSource, - private val userListDataStore: UserListDataStore, - private val room: MatrixRoom, + private val roomMemberListDataSource: RoomMemberListDataSource, private val coroutineDispatchers: CoroutineDispatchers, ) : Presenter { - private val userListPresenter by lazy { - userListPresenterFactory.create( - UserListPresenterArgs(selectionMode = SelectionMode.Single), - userListDataSource, - userListDataStore, - ) - } - @Composable override fun present(): RoomMemberListState { - val userListState = userListPresenter.present() - val allUsers = remember { mutableStateOf>>(Async.Loading()) } + var roomMembers by remember { mutableStateOf>(Async.Loading()) } + var searchQuery by rememberSaveable { mutableStateOf("") } + var searchResults by remember { + mutableStateOf(RoomMemberSearchResultState.NotSearching) + } + var isSearchActive by rememberSaveable { mutableStateOf(false) } LaunchedEffect(Unit) { withContext(coroutineDispatchers.io) { - allUsers.value = Async.Success(userListDataSource.search("").toImmutableList()) + val members = roomMemberListDataSource.search("").groupBy { it.membership } + roomMembers = Async.Success( + RoomMembers( + invited = members.getOrDefault(RoomMembershipState.INVITE, emptyList()).toImmutableList(), + joined = members.getOrDefault(RoomMembershipState.JOIN, emptyList()).toImmutableList(), + ) + ) + } + } + + LaunchedEffect(searchQuery) { + withContext(coroutineDispatchers.io) { + searchResults = if (searchQuery.isEmpty()) { + RoomMemberSearchResultState.NotSearching + } else { + val results = roomMemberListDataSource.search(searchQuery).groupBy { it.membership } + if (results.isEmpty()) RoomMemberSearchResultState.NoResults + else RoomMemberSearchResultState.Results( + RoomMembers( + invited = results.getOrDefault(RoomMembershipState.INVITE, emptyList()).toImmutableList(), + joined = results.getOrDefault(RoomMembershipState.JOIN, emptyList()).toImmutableList(), + ) + ) + } } } return RoomMemberListState( - allUsers = allUsers.value, - userListState = userListState, + roomMembers = roomMembers, + searchQuery = searchQuery, + searchResults = searchResults, + isSearchActive = isSearchActive, + eventSink = { event -> + when (event) { + is RoomMemberListEvents.OnSearchActiveChanged -> isSearchActive = event.active + is RoomMemberListEvents.UpdateSearchQuery -> searchQuery = event.query + } + }, ) } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListState.kt index ef9d1f3839..a689ad1fd2 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListState.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListState.kt @@ -16,12 +16,30 @@ package io.element.android.features.roomdetails.impl.members -import io.element.android.features.userlist.api.UserListState import io.element.android.libraries.architecture.Async -import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.matrix.api.room.RoomMember import kotlinx.collections.immutable.ImmutableList data class RoomMemberListState( - val allUsers: Async>, - val userListState: UserListState, + val roomMembers: Async, + val searchQuery: String, + val searchResults: RoomMemberSearchResultState, + val isSearchActive: Boolean, + val eventSink: (RoomMemberListEvents) -> Unit, ) + +data class RoomMembers( + val invited: ImmutableList, + val joined: ImmutableList +) + +sealed interface RoomMemberSearchResultState { + /** No search results are available yet (e.g. because the user hasn't entered a (long enough) search term). */ + object NotSearching : RoomMemberSearchResultState + + /** The search has completed, but no results were found. */ + object NoResults : RoomMemberSearchResultState + + /** The search has completed, and some matching users were found. */ + data class Results(val results: RoomMembers) : RoomMemberSearchResultState +} diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt index a9babf57d8..7f91969bcd 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt @@ -17,27 +17,93 @@ package io.element.android.features.roomdetails.impl.members import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.features.userlist.api.UserSearchResultState -import io.element.android.features.userlist.api.aUserListState import io.element.android.libraries.architecture.Async -import io.element.android.libraries.matrix.api.user.MatrixUser -import io.element.android.libraries.matrix.ui.components.aMatrixUser -import kotlinx.collections.immutable.ImmutableList +import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.room.RoomMembershipState import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList internal class RoomMemberListStateProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( - aRoomMemberListState(allUsers = Async.Success(persistentListOf(aMatrixUser()))), - aRoomMemberListState(allUsers = Async.Loading()) + aRoomMemberListState( + roomMembers = Async.Success( + RoomMembers( + invited = persistentListOf(aVictor(), aWalter()), + joined = persistentListOf(anAlice(), aBob()), + ) + ) + ), + aRoomMemberListState(roomMembers = Async.Loading()), + aRoomMemberListState().copy(isSearchActive = false), + aRoomMemberListState().copy(isSearchActive = true), + aRoomMemberListState().copy(isSearchActive = true, searchQuery = "someone"), + aRoomMemberListState().copy( + isSearchActive = true, + searchQuery = "@someone:matrix.org", + searchResults = RoomMemberSearchResultState.Results( + RoomMembers( + invited = persistentListOf(aVictor()), + joined = persistentListOf(anAlice()), + ) + ), + ), + aRoomMemberListState().copy( + isSearchActive = true, + searchQuery = "something-with-no-results", + searchResults = RoomMemberSearchResultState.NoResults + ), ) } internal fun aRoomMemberListState( - searchResults: UserSearchResultState = UserSearchResultState.NotSearching, - allUsers: Async> = Async.Uninitialized, -) = - RoomMemberListState( - userListState = aUserListState().copy(searchResults = searchResults), - allUsers = allUsers, - ) + roomMembers: Async = Async.Uninitialized, + searchResults: RoomMemberSearchResultState = RoomMemberSearchResultState.NotSearching, +) = RoomMemberListState( + roomMembers = roomMembers, + searchQuery = "", + searchResults = searchResults, + isSearchActive = false, + eventSink = {} +) + +fun aRoomMember( + userId: UserId = UserId("@alice:server.org"), + displayName: String? = null, + avatarUrl: String? = null, + membership: RoomMembershipState = RoomMembershipState.JOIN, + isNameAmbiguous: Boolean = false, + powerLevel: Long = 0L, + normalizedPowerLevel: Long = 0L, + isIgnored: Boolean = false, +) = RoomMember( + userId = userId, + displayName = displayName, + avatarUrl = avatarUrl, + membership = membership, + isNameAmbiguous = isNameAmbiguous, + powerLevel = powerLevel, + normalizedPowerLevel = normalizedPowerLevel, + isIgnored = isIgnored, +) + +fun aRoomMemberList() = listOf( + anAlice(), + aBob(), + aRoomMember(UserId("@carol:server.org"), "Carol"), + aRoomMember(UserId("@david:server.org"), "David"), + aRoomMember(UserId("@eve:server.org"), "Eve"), + aRoomMember(UserId("@justin:server.org"), "Justin"), + aRoomMember(UserId("@mallory:server.org"), "Mallory"), + aRoomMember(UserId("@susie:server.org"), "Susie"), + aVictor(), + aWalter(), +) + +fun anAlice() = aRoomMember(UserId("@alice:server.org"), "Alice") +fun aBob() = aRoomMember(UserId("@bob:server.org"), "Bob") + +fun aVictor() = aRoomMember(UserId("@victor:server.org"), "Victor", membership = RoomMembershipState.INVITE) + +fun aWalter() = aRoomMember(UserId("@walter:server.org"), "Walter", membership = RoomMembershipState.INVITE) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt index 3a3ea3daa1..db38bbcf8b 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt @@ -16,20 +16,31 @@ package io.element.android.features.roomdetails.impl.members +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.Search import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SearchBarDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight @@ -39,37 +50,43 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import io.element.android.features.roomdetails.impl.R -import io.element.android.features.userlist.api.components.SearchSingleUserResultItem -import io.element.android.features.userlist.api.components.UserListView import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.isLoading import io.element.android.libraries.designsystem.ElementTextStyles +import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.theme.components.CenterAlignedTopAppBar import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator +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.Scaffold +import io.element.android.libraries.designsystem.theme.components.SearchBar import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.matrix.ui.components.MatrixUserRow +import kotlinx.collections.immutable.ImmutableList +import io.element.android.libraries.ui.strings.R as StringR @OptIn(ExperimentalMaterial3Api::class) @Composable fun RoomMemberListView( state: RoomMemberListState, + onBackPressed: () -> Unit, + onMemberSelected: (UserId) -> Unit, modifier: Modifier = Modifier, - onBackPressed: () -> Unit = {}, - onMemberSelected: (UserId) -> Unit = {}, ) { - fun onUserSelected(user: MatrixUser) { - onMemberSelected(user.userId) + fun onUserSelected(roomMember: RoomMember) { + onMemberSelected(roomMember.userId) } Scaffold( topBar = { - if (!state.userListState.isSearchActive) { + if (!state.isSearchActive) { RoomMemberListTopBar(onBackPressed = onBackPressed) } } @@ -80,33 +97,26 @@ fun RoomMemberListView( .padding(padding), verticalArrangement = Arrangement.spacedBy(16.dp), ) { - UserListView( - state = state.userListState, - onUserSelected = ::onUserSelected, - ) + Column { + RoomMemberSearchBar( + query = state.searchQuery, + state = state.searchResults, + active = state.isSearchActive, + placeHolderTitle = stringResource(StringR.string.common_search_for_someone), + onActiveChanged = { state.eventSink(RoomMemberListEvents.OnSearchActiveChanged(it)) }, + onTextChanged = { state.eventSink(RoomMemberListEvents.UpdateSearchQuery(it)) }, + onUserSelected = ::onUserSelected, + modifier = Modifier.fillMaxWidth() + ) + } - if (!state.userListState.isSearchActive) { - if (state.allUsers is Async.Success) { - LazyColumn(modifier = Modifier.fillMaxWidth(), state = rememberLazyListState()) { - item { - val memberCount = state.allUsers.state.count() - Text( - modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp), - text = pluralStringResource(id = R.plurals.screen_room_member_list_header_title, count = memberCount, memberCount), - style = ElementTextStyles.Regular.callout, - color = MaterialTheme.colorScheme.secondary, - textAlign = TextAlign.Start, - ) - } - items(state.allUsers.state) { matrixUser -> - SearchSingleUserResultItem( - modifier = Modifier.fillMaxWidth(), - matrixUser = matrixUser, - onClick = { onUserSelected(matrixUser) } - ) - } - } - } else if (state.allUsers.isLoading()) { + if (!state.isSearchActive) { + if (state.roomMembers is Async.Success) { + RoomMemberList( + roomMembers = state.roomMembers.state, + onUserSelected = ::onUserSelected, + ) + } else if (state.roomMembers.isLoading()) { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { CircularProgressIndicator() } @@ -116,9 +126,73 @@ fun RoomMemberListView( } } +@Composable +private fun RoomMemberList( + roomMembers: RoomMembers, + onUserSelected: (RoomMember) -> Unit, +) { + LazyColumn(modifier = Modifier.fillMaxWidth(), state = rememberLazyListState()) { + if (roomMembers.invited.isNotEmpty()) { + roomMemberListSection( + headerText = { stringResource(id = R.string.screen_room_member_list_pending_header_title) }, + members = roomMembers.invited, + onMemberSelected = { onUserSelected(it) } + ) + } + if (roomMembers.joined.isNotEmpty()) { + val memberCount = roomMembers.joined.count() + roomMemberListSection( + headerText = { pluralStringResource(id = R.plurals.screen_room_member_list_header_title, count = memberCount, memberCount) }, + members = roomMembers.joined, + onMemberSelected = { onUserSelected(it) } + ) + } + } +} + +private fun LazyListScope.roomMemberListSection( + headerText: @Composable () -> String, + members: ImmutableList, + onMemberSelected: (RoomMember) -> Unit, +) { + item { + Text( + modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp), + text = headerText(), + style = ElementTextStyles.Regular.callout, + color = MaterialTheme.colorScheme.secondary, + textAlign = TextAlign.Start, + ) + } + items(members) { matrixUser -> + RoomMemberListItem( + modifier = Modifier.fillMaxWidth(), + roomMember = matrixUser, + onClick = { onMemberSelected(matrixUser) } + ) + } +} + +@Composable +private fun RoomMemberListItem( + roomMember: RoomMember, + modifier: Modifier = Modifier, + onClick: () -> Unit = {}, +) { + MatrixUserRow( + modifier = modifier.clickable(onClick = onClick), + matrixUser = MatrixUser( + userId = roomMember.userId, + displayName = roomMember.displayName, + avatarUrl = roomMember.avatarUrl + ), + avatarSize = AvatarSize.Custom(36.dp), + ) +} + @OptIn(ExperimentalMaterial3Api::class) @Composable -fun RoomMemberListTopBar( +private fun RoomMemberListTopBar( modifier: Modifier = Modifier, onBackPressed: () -> Unit = {}, ) { @@ -135,6 +209,86 @@ fun RoomMemberListTopBar( ) } +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun RoomMemberSearchBar( + query: String, + state: RoomMemberSearchResultState, + active: Boolean, + placeHolderTitle: String, + onActiveChanged: (Boolean) -> Unit, + onTextChanged: (String) -> Unit, + onUserSelected: (RoomMember) -> Unit, + modifier: Modifier = Modifier, +) { + val focusManager = LocalFocusManager.current + + if (!active) { + onTextChanged("") + focusManager.clearFocus() + } + + SearchBar( + query = query, + onQueryChange = onTextChanged, + onSearch = { focusManager.clearFocus() }, + active = active, + onActiveChange = onActiveChanged, + modifier = modifier + .padding(horizontal = if (!active) 16.dp else 0.dp), + placeholder = { + Text( + text = placeHolderTitle, + modifier = Modifier.alpha(0.4f), // FIXME align on Design system theme (removing alpha should be fine) + ) + }, + leadingIcon = if (active) { + { BackButton(onClick = { onActiveChanged(false) }) } + } else { + null + }, + trailingIcon = when { + active && query.isNotEmpty() -> { + { + IconButton(onClick = { onTextChanged("") }) { + Icon(Icons.Default.Close, stringResource(StringR.string.action_clear)) + } + } + } + + !active -> { + { + Icon( + imageVector = Icons.Default.Search, + contentDescription = stringResource(StringR.string.action_search), + modifier = Modifier.alpha(0.4f), // FIXME align on Design system theme (removing alpha should be fine) + ) + } + } + + else -> null + }, + colors = if (!active) SearchBarDefaults.colors() else SearchBarDefaults.colors(containerColor = Color.Transparent), + content = { + if (state is RoomMemberSearchResultState.Results) { + RoomMemberList( + roomMembers = state.results, + onUserSelected = { onUserSelected(it) } + ) + } else if (state is RoomMemberSearchResultState.NoResults) { + Spacer(Modifier.size(80.dp)) + + Text( + text = stringResource(StringR.string.common_no_results), + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.tertiary, + modifier = Modifier.fillMaxWidth() + ) + } + }, + ) +} + @Preview @Composable fun RoomMemberListLightPreview(@PreviewParameter(RoomMemberListStateProvider::class) state: RoomMemberListState) = @@ -147,5 +301,9 @@ fun RoomMemberListDarkPreview(@PreviewParameter(RoomMemberListStateProvider::cla @Composable private fun ContentToPreview(state: RoomMemberListState) { - RoomMemberListView(state) + RoomMemberListView( + state = state, + onBackPressed = {}, + onMemberSelected = {} + ) } diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt index 2cc6d0ec24..b3717f4244 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt @@ -24,6 +24,8 @@ import io.element.android.features.roomdetails.impl.LeaveRoomWarning import io.element.android.features.roomdetails.impl.RoomDetailsEvent import io.element.android.features.roomdetails.impl.RoomDetailsPresenter import io.element.android.features.roomdetails.impl.RoomDetailsType +import io.element.android.features.roomdetails.impl.members.aRoomMember +import io.element.android.features.roomdetails.impl.members.aRoomMemberList import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter import io.element.android.libraries.architecture.Async import io.element.android.libraries.matrix.api.core.RoomId @@ -90,7 +92,7 @@ class RoomDetailsPresenterTests { val room = aMatrixRoom() val roomMembers = listOf( aRoomMember(A_USER_ID), - aRoomMember(A_USER_ID_2), + aRoomMember(A_USER_ID_2, membership = RoomMembershipState.INVITE), ) val presenter = aRoomDetailsPresenter(room) moleculeFlow(RecompositionClock.Immediate) { @@ -112,7 +114,7 @@ class RoomDetailsPresenterTests { room.givenRoomMembersState(MatrixRoomMembersState.Ready(roomMembers)) //skipItems(1) val successState = awaitItem() - Truth.assertThat(successState.memberCount).isEqualTo(Async.Success(roomMembers.size)) + Truth.assertThat(successState.memberCount).isEqualTo(Async.Success(1)) cancelAndIgnoreRemainingEvents() } @@ -266,22 +268,3 @@ fun aMatrixRoom( isDirect = isDirect, ) -fun aRoomMember( - userId: UserId = A_USER_ID, - displayName: String? = null, - avatarUrl: String? = null, - membership: RoomMembershipState = RoomMembershipState.JOIN, - isNameAmbiguous: Boolean = false, - powerLevel: Long = 0L, - normalizedPowerLevel: Long = 0L, - isIgnored: Boolean = false, -) = RoomMember( - userId = userId, - displayName = displayName, - avatarUrl = avatarUrl, - membership = membership, - isNameAmbiguous = isNameAmbiguous, - powerLevel = powerLevel, - normalizedPowerLevel = normalizedPowerLevel, - isIgnored = isIgnored, -) diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt index 7eb650c937..48cf660877 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt @@ -20,62 +20,111 @@ import app.cash.molecule.RecompositionClock import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth +import io.element.android.features.roomdetails.aMatrixRoom +import io.element.android.features.roomdetails.impl.members.RoomMemberListDataSource +import io.element.android.features.roomdetails.impl.members.RoomMemberListEvents import io.element.android.features.roomdetails.impl.members.RoomMemberListPresenter -import io.element.android.features.userlist.api.SelectionMode -import io.element.android.features.userlist.api.UserListDataSource -import io.element.android.features.userlist.api.UserListDataStore -import io.element.android.features.userlist.api.UserListPresenter -import io.element.android.features.userlist.api.UserListPresenterArgs -import io.element.android.features.userlist.api.UserSearchResultState -import io.element.android.features.userlist.impl.DefaultUserListPresenter -import io.element.android.features.userlist.test.FakeUserListDataSource +import io.element.android.features.roomdetails.impl.members.RoomMemberSearchResultState +import io.element.android.features.roomdetails.impl.members.aRoomMemberList +import io.element.android.features.roomdetails.impl.members.aVictor +import io.element.android.features.roomdetails.impl.members.aWalter import io.element.android.libraries.architecture.Async -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom -import io.element.android.libraries.matrix.ui.components.aMatrixUser +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest -import okhttp3.internal.toImmutableList import org.junit.Test @ExperimentalCoroutinesApi class RoomMemberListPresenterTests { - private val testCoroutineDispatchers = testCoroutineDispatchers() - @Test - fun `present - search is done automatically on start, but is async`() = runTest { - val searchResult = listOf(aMatrixUser()) - val userListDataSource = FakeUserListDataSource().apply { - givenSearchResult(searchResult) - } - val userListDataStore = UserListDataStore() - val userListFactory = object : UserListPresenter.Factory { - override fun create( - args: UserListPresenterArgs, - userListDataSource: UserListDataSource, - userListDataStore: UserListDataStore, - ) = DefaultUserListPresenter(args, userListDataSource, userListDataStore) - } - val fakeRoom = FakeMatrixRoom() - val presenter = RoomMemberListPresenter( - userListPresenterFactory = userListFactory, - userListDataSource = userListDataSource, - userListDataStore = userListDataStore, - room = fakeRoom, - coroutineDispatchers = testCoroutineDispatchers - ) + fun `search is done automatically on start, but is async`() = runTest { + val presenter = createPresenter() moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { val initialState = awaitItem() - Truth.assertThat(initialState.allUsers).isInstanceOf(Async.Loading::class.java) - Truth.assertThat(initialState.userListState.isSearchActive).isFalse() - Truth.assertThat(initialState.userListState.searchResults).isEqualTo(UserSearchResultState.NotSearching) - Truth.assertThat(initialState.userListState.selectionMode).isEqualTo(SelectionMode.Single) + Truth.assertThat(initialState.roomMembers).isInstanceOf(Async.Loading::class.java) + Truth.assertThat(initialState.searchQuery).isEmpty() + Truth.assertThat(initialState.searchResults).isEqualTo(RoomMemberSearchResultState.NotSearching) + Truth.assertThat(initialState.isSearchActive).isFalse() val loadedState = awaitItem() - Truth.assertThat((loadedState.allUsers as? Async.Success)?.state).isEqualTo(searchResult.toImmutableList()) + Truth.assertThat(loadedState.roomMembers).isInstanceOf(Async.Success::class.java) + Truth.assertThat((loadedState.roomMembers as Async.Success).state.invited).isEqualTo(listOf(aVictor(), aWalter())) + Truth.assertThat((loadedState.roomMembers as Async.Success).state.joined).isNotEmpty() + } + } + + @Test + fun `open search`() = runTest { + val presenter = createPresenter() + moleculeFlow(RecompositionClock.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + val loadedState = awaitItem() + + loadedState.eventSink(RoomMemberListEvents.OnSearchActiveChanged(true)) + + val searchActiveState = awaitItem() + Truth.assertThat((searchActiveState.isSearchActive)).isTrue() + } + } + + @Test + fun `search for something which is not found`() = runTest { + val presenter = createPresenter() + moleculeFlow(RecompositionClock.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + val loadedState = awaitItem() + loadedState.eventSink(RoomMemberListEvents.OnSearchActiveChanged(true)) + val searchActiveState = awaitItem() + loadedState.eventSink(RoomMemberListEvents.UpdateSearchQuery("something")) + val searchQueryUpdatedState = awaitItem() + Truth.assertThat((searchQueryUpdatedState.searchQuery)).isEqualTo("something") + val searchSearchResultDelivered = awaitItem() + Truth.assertThat((searchSearchResultDelivered.searchResults)).isInstanceOf(RoomMemberSearchResultState.NoResults::class.java) + } + } + + @Test + fun `search for something which is found`() = runTest { + val presenter = createPresenter() + moleculeFlow(RecompositionClock.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + val loadedState = awaitItem() + loadedState.eventSink(RoomMemberListEvents.OnSearchActiveChanged(true)) + val searchActiveState = awaitItem() + loadedState.eventSink(RoomMemberListEvents.UpdateSearchQuery("Alice")) + val searchQueryUpdatedState = awaitItem() + Truth.assertThat((searchQueryUpdatedState.searchQuery)).isEqualTo("Alice") + val searchSearchResultDelivered = awaitItem() + Truth.assertThat((searchSearchResultDelivered.searchResults)).isInstanceOf(RoomMemberSearchResultState.Results::class.java) + Truth.assertThat((searchSearchResultDelivered.searchResults as RoomMemberSearchResultState.Results).results.joined.first().displayName) + .isEqualTo("Alice") + } } } + +@ExperimentalCoroutinesApi +private fun createDataSource( + matrixRoom: MatrixRoom = aMatrixRoom().apply { + givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + }, + coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers() +) = RoomMemberListDataSource(matrixRoom, coroutineDispatchers) + +@ExperimentalCoroutinesApi +private fun createPresenter( + roomMemberListDataSource: RoomMemberListDataSource = createDataSource(), + coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers() +) = RoomMemberListPresenter(roomMemberListDataSource, coroutineDispatchers) diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt index 13eb28ca85..294b689ea9 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt @@ -22,7 +22,7 @@ import app.cash.turbine.test import com.google.common.truth.Truth import io.element.android.features.roomdetails.aMatrixClient import io.element.android.features.roomdetails.aMatrixRoom -import io.element.android.features.roomdetails.aRoomMember +import io.element.android.features.roomdetails.impl.members.aRoomMember import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsEvents import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsState diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt index 7c977f7569..3c9bd030b0 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMember.kt @@ -17,7 +17,6 @@ package io.element.android.libraries.matrix.api.room import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.user.MatrixUser data class RoomMember( val userId: UserId, @@ -30,12 +29,6 @@ data class RoomMember( val isIgnored: Boolean, ) -fun RoomMember.toMatrixUser() = MatrixUser( - userId = userId, - displayName = displayName, - avatarUrl = avatarUrl, -) - enum class RoomMembershipState { BAN, INVITE, JOIN, KNOCK, LEAVE } diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_0,NEXUS_5,1.0,en].png index 27f36f9248..f96c3b07b9 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6893108aabbf06f43af90f17b6b1a8a521312559f407647ce08db06ecb9a8f84 -size 22033 +oid sha256:29fa45284bef52648e02629a440b335595c7d4a4d04d0da5c4acbe9ae457bad6 +size 46918 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_2,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..d03094bab0 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_2,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:49e7533e6afba903219942193e0cc5cfbe2f67ba3b57516f77c259e7c42e8e3f +size 11813 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_3,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..f13a65f8e2 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_3,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:89ea65099fb4981bbeb24e49afb7400b0e8da79e3b783e198519ba1e970404a8 +size 8317 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_4,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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_4,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..74a7f599cd --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_4,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9a8ba207cf61c56b64c6855d04c8a30def0b3daf325adf57edd45b40981ed745 +size 7733 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_5,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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_5,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..31ca39b498 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_5,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:92c4537ed8794f4db08b4edec74a0de41847c4fd8c4fe03b7112bc63124b0a61 +size 29326 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_6,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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_6,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..0f9a5a79cc --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_6,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d5b879b74654fdad0638f432a71adfc9186fbe00dafd5d963a3affb33ec8c5c8 +size 12841 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_0,NEXUS_5,1.0,en].png index b493c070d2..c6b9c1b3ab 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3e7b5bd916d4d3067b5013400b4ac864fab560e96fcb75ec895684021a00b8ba -size 21808 +oid sha256:3d40819700e3cbe9ca8ae1e5886de036a6dc05a7da6dd366490cc79c27ae3e8d +size 45653 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_2,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..3d261cb40b --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_2,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9c3abebbe9e55706af5f4d1089e4308b0e975258a9d6a0e1793a4208b36c9c93 +size 11754 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_3,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..eb23dcec96 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_3,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b8de2f28cf9918a7eddcc1311c34ba0376242a4708724b57689df000b7480524 +size 8197 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_4,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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_4,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..e2e4a33e67 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_4,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:687133e4729ea42382ac0b76af6ceaf8b20cbc65923412fb97b077d2475c70f7 +size 7514 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_5,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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_5,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..4275020d4c --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_5,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1f663a70c43b9f2e66b651f17169b63859fe7c87c21312b61ed61a9136eabe5f +size 27989 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_6,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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_6,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..787c71d87e --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_6,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:534cba0c13aa52b3557ab8df854c521dd13b82e5a1550d73abcef12925e389da +size 11878 From b3c6d64fa30857c3d24b40b163fd8ad90b936dc8 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 15 May 2023 18:16:52 +0200 Subject: [PATCH 21/36] SDK - fix compilation --- .../libraries/matrix/impl/notification/NotificationMapper.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/NotificationMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/NotificationMapper.kt index 079b1e0a5a..4b121db9bf 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/NotificationMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/NotificationMapper.kt @@ -16,6 +16,7 @@ package io.element.android.libraries.matrix.impl.notification +import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId @@ -36,7 +37,7 @@ class NotificationMapper @Inject constructor() { senderDisplayName = it.senderDisplayName, roomAvatarUrl = it.roomAvatarUrl, isDirect = it.isDirect, - isEncrypted = it.isEncrypted, + isEncrypted = it.isEncrypted.orFalse(), isNoisy = it.isNoisy ) } From c42154d66d80629920d63b9d1ea6f961258e1866 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 May 2023 17:32:55 +0000 Subject: [PATCH 22/36] Update dependency org.matrix.rustcomponents:sdk-android to v0.1.14 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7b343e4980..ec47b2eea0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -129,7 +129,7 @@ jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" } appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } molecule-runtime = { module = "app.cash.molecule:molecule-runtime", version.ref = "molecule" } timber = "com.jakewharton.timber:timber:5.0.1" -matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.13" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.14" sqldelight-driver-android = { module = "com.squareup.sqldelight:android-driver", version.ref = "sqldelight" } sqldelight-driver-jvm = { module = "com.squareup.sqldelight:sqlite-driver", version.ref = "sqldelight" } sqldelight-coroutines = { module = "com.squareup.sqldelight:coroutines-extensions", version.ref = "sqldelight" } From f6ec8357f2a76aed2aee22599849fc336f84b552 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Tue, 16 May 2023 14:29:18 +0200 Subject: [PATCH 23/36] Use material3 ListItem --- .../impl/configureroom/avatar/AvatarActionListView.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListView.kt index f68db3a4b7..422a187290 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/avatar/AvatarActionListView.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -@file:OptIn(ExperimentalMaterialApi::class, ExperimentalMaterialApi::class) +@file:OptIn(ExperimentalMaterialApi::class) package io.element.android.features.createroom.impl.configureroom.avatar @@ -25,10 +25,10 @@ import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.ListItem import androidx.compose.material.ModalBottomSheetState import androidx.compose.material.ModalBottomSheetValue import androidx.compose.material.Text +import androidx.compose.material3.ListItem import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope @@ -87,13 +87,13 @@ private fun SheetContent( ) { action -> ListItem( modifier = Modifier.clickable { onActionClicked(action) }, - text = { + headlineContent = { Text( text = stringResource(action.titleResId), color = if (action.destructive) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.primary, ) }, - icon = { + leadingContent = { Icon( imageVector = action.icon, contentDescription = stringResource(action.titleResId), @@ -118,7 +118,7 @@ fun SheetContentDarkPreview() = @Composable private fun ContentToPreview() { AvatarActionListView( - actions = persistentListOf(AvatarAction.ChoosePhoto, AvatarAction.TakePhoto, AvatarAction.Remove), + actions = persistentListOf(AvatarAction.TakePhoto, AvatarAction.ChoosePhoto, AvatarAction.Remove), modalBottomSheetState = ModalBottomSheetState( initialValue = ModalBottomSheetValue.Expanded ), From 4d3cd0709e6609afa797463f54e226be8063fbff Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Tue, 16 May 2023 14:32:23 +0200 Subject: [PATCH 24/36] Update screenshots --- ...ltGroup_SheetContentDarkPreview_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...tGroup_SheetContentLightPreview_0_null,NEXUS_5,1.0,en].png | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom.avatar_null_DefaultGroup_SheetContentDarkPreview_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.features.createroom.impl.configureroom.avatar_null_DefaultGroup_SheetContentDarkPreview_0_null,NEXUS_5,1.0,en].png index 6b5ba60f36..1a8de3bbb4 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom.avatar_null_DefaultGroup_SheetContentDarkPreview_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.features.createroom.impl.configureroom.avatar_null_DefaultGroup_SheetContentDarkPreview_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:58efadd0883968cedfe5d74c4269edb3e7cadd1150fd0e9bd3425efcc717ec01 -size 14040 +oid sha256:c824fcf4167c6315d0d6568a4d300375a7bf6d4818e3d0dae9ed055f3269313d +size 13072 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom.avatar_null_DefaultGroup_SheetContentLightPreview_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.features.createroom.impl.configureroom.avatar_null_DefaultGroup_SheetContentLightPreview_0_null,NEXUS_5,1.0,en].png index fdfcbb6e11..809b8135eb 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom.avatar_null_DefaultGroup_SheetContentLightPreview_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.features.createroom.impl.configureroom.avatar_null_DefaultGroup_SheetContentLightPreview_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6cd407cdbaab5e3fe6b42ceb98c5b9b6a4012e3781ad7e754531c2ce04d9ee4e -size 14810 +oid sha256:8bad887952347b21606a783a19390fe73e5d6deb19390e2d413304398cff810c +size 13872 From 2c39e8f9fc432624bb0e118d26d5b4dc540516b4 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Tue, 16 May 2023 15:37:22 +0200 Subject: [PATCH 25/36] Fix test compilation --- .../impl/configureroom/ConfigureRoomPresenterTests.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt index 0c3f64b056..b4632ab0e8 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt @@ -228,7 +228,7 @@ class ConfigureRoomPresenterTests { }.test { skipItems(1) createRoomDataStore.setAvatarUri(Uri.parse(AN_URI_FROM_GALLERY)) - fakeMediaPreProcessor.givenResult(Result.success(MediaUploadInfo.Image(mockk(), mockk(), null))) + fakeMediaPreProcessor.givenResult(Result.success(MediaUploadInfo.Image(mockk(), mockk(), mockk()))) fakeMatrixClient.givenUploadMediaResult(Result.failure(A_THROWABLE)) val initialState = awaitItem() From 6d9f6664d8c1ca30c8260828e7776ed773da8206 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Thu, 11 May 2023 23:37:00 +0200 Subject: [PATCH 26/36] Make the configure room screen scrollable --- .../impl/configureroom/ConfigureRoomView.kt | 59 +++++++++++-------- ...ewDarkPreview_0_null_0,NEXUS_5,1.0,en].png | 4 +- ...ewDarkPreview_0_null_1,NEXUS_5,1.0,en].png | 4 +- ...wLightPreview_0_null_0,NEXUS_5,1.0,en].png | 4 +- ...wLightPreview_0_null_1,NEXUS_5,1.0,en].png | 4 +- 5 files changed, 42 insertions(+), 33 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt index 6f7f21875b..4b23d5f389 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt @@ -21,8 +21,8 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.selection.selectableGroup import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ModalBottomSheetValue @@ -96,33 +96,42 @@ fun ConfigureRoomView( ) } ) { padding -> - Column( + LazyColumn( modifier = Modifier.padding(padding), verticalArrangement = Arrangement.spacedBy(24.dp), ) { - RoomNameWithAvatar( - modifier = Modifier.padding(horizontal = 16.dp), - avatarUri = state.config.avatarUri, - roomName = state.config.roomName.orEmpty(), - onAvatarClick = ::onAvatarClicked, - onRoomNameChanged = { state.eventSink(ConfigureRoomEvents.RoomNameChanged(it)) }, - ) - RoomTopic( - modifier = Modifier.padding(horizontal = 16.dp), - topic = state.config.topic.orEmpty(), - onTopicChanged = { state.eventSink(ConfigureRoomEvents.TopicChanged(it)) }, - ) - SelectedUsersList( - contentPadding = PaddingValues(horizontal = 24.dp), - selectedUsers = state.config.invites, - onUserRemoved = { state.eventSink(ConfigureRoomEvents.RemoveFromSelection(it)) }, - ) - Spacer(Modifier.weight(1f)) - RoomPrivacyOptions( - modifier = Modifier.padding(bottom = 40.dp), - selected = state.config.privacy, - onOptionSelected = { state.eventSink(ConfigureRoomEvents.RoomPrivacyChanged(it.privacy)) }, - ) + item { + RoomNameWithAvatar( + modifier = Modifier.padding(horizontal = 16.dp), + avatarUri = state.config.avatarUri, + roomName = state.config.roomName.orEmpty(), + onAvatarClick = ::onAvatarClicked, + onRoomNameChanged = { state.eventSink(ConfigureRoomEvents.RoomNameChanged(it)) }, + ) + } + item { + RoomTopic( + modifier = Modifier.padding(horizontal = 16.dp), + topic = state.config.topic.orEmpty(), + onTopicChanged = { state.eventSink(ConfigureRoomEvents.TopicChanged(it)) }, + ) + } + if (state.config.invites.isNotEmpty()) { + item { + SelectedUsersList( + contentPadding = PaddingValues(horizontal = 24.dp), + selectedUsers = state.config.invites, + onUserRemoved = { state.eventSink(ConfigureRoomEvents.RemoveFromSelection(it)) }, + ) + } + } + item { + RoomPrivacyOptions( + modifier = Modifier.padding(bottom = 40.dp), + selected = state.config.privacy, + onOptionSelected = { state.eventSink(ConfigureRoomEvents.RoomPrivacyChanged(it.privacy)) }, + ) + } } } diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewDarkPreview_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.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png index 160def016f..dbf9ad3653 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewDarkPreview_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.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:24ad0b5edc27ddddca573b37f82579715d880793c0dc880248d2b572dd6d6a40 -size 64379 +oid sha256:7a3923915741c22054ceb2f34acdfdb629ccc14b8aad844206c64a7c63ef6cf6 +size 63704 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewDarkPreview_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.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png index c6a054a2d3..a04545bc27 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewDarkPreview_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.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b0c9d4eaaaf6a691f43d25e0855ee056b69fa090ad8c53b26732c8f2532e2138 -size 103384 +oid sha256:6c6f2959adf84474dba18c44d81c2d9805ebb06ba8c8bf204f1845d2e62be84d +size 103395 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewLightPreview_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.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewLightPreview_0_null_0,NEXUS_5,1.0,en].png index 26129e266a..2990badc15 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewLightPreview_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.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewLightPreview_0_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4023481d2a045d7e0d824db81b28ee47c4bcdc568d98537b3573d554e0b76e32 -size 58445 +oid sha256:02c3a6d536136e6c4db7e1b40a53506ec21e29810ee4067be4066851edfe8aee +size 57519 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewLightPreview_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.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewLightPreview_0_null_1,NEXUS_5,1.0,en].png index af4d0b2046..996b70e65e 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewLightPreview_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.createroom.impl.configureroom_null_DefaultGroup_ConfigureRoomViewLightPreview_0_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8f953d0df467ad4cd1ae24291e9593945b945712506f093bdcae3da975f8ca91 -size 96800 +oid sha256:758362366ee7b50a33761401fd400698c124e468183459d4657cb707ea965424 +size 96777 From d90390145785ea9980d95f1f6a0159422a23bf72 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Thu, 11 May 2023 23:46:37 +0200 Subject: [PATCH 27/36] Select private privacy by default --- .../android/features/createroom/impl/CreateRoomConfig.kt | 2 +- .../features/createroom/impl/CreateRoomDataStore.kt | 2 +- .../createroom/impl/configureroom/ConfigureRoomEvents.kt | 2 +- .../impl/configureroom/ConfigureRoomPresenter.kt | 6 ------ .../createroom/impl/configureroom/ConfigureRoomState.kt | 5 +++-- .../impl/configureroom/ConfigureRoomStateProvider.kt | 4 +--- .../impl/configureroom/ConfigureRoomPresenterTests.kt | 9 +-------- ...igureRoomViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...igureRoomViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...gureRoomViewLightPreview_0_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...gureRoomViewLightPreview_0_null_1,NEXUS_5,1.0,en].png | 4 ++-- 11 files changed, 16 insertions(+), 30 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomConfig.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomConfig.kt index 23b6f3239d..8f6f6e14d9 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomConfig.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomConfig.kt @@ -27,5 +27,5 @@ data class CreateRoomConfig( val topic: String? = null, val avatarUri: Uri? = null, val invites: ImmutableList = persistentListOf(), - val privacy: RoomPrivacy? = null, + val privacy: RoomPrivacy = RoomPrivacy.Private, ) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt index 3c594a0f1e..2a0dedc3e5 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt @@ -60,7 +60,7 @@ class CreateRoomDataStore @Inject constructor( createRoomConfigFlow.tryEmit(createRoomConfigFlow.value.copy(avatarUri = uri)) } - fun setPrivacy(privacy: RoomPrivacy?) { + fun setPrivacy(privacy: RoomPrivacy) { createRoomConfigFlow.tryEmit(createRoomConfigFlow.value.copy(privacy = privacy)) } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt index 52389d97fb..9082849954 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt @@ -23,7 +23,7 @@ import io.element.android.libraries.matrix.api.user.MatrixUser sealed interface ConfigureRoomEvents { data class RoomNameChanged(val name: String) : ConfigureRoomEvents data class TopicChanged(val topic: String) : ConfigureRoomEvents - data class RoomPrivacyChanged(val privacy: RoomPrivacy?) : ConfigureRoomEvents + data class RoomPrivacyChanged(val privacy: RoomPrivacy) : ConfigureRoomEvents data class RemoveFromSelection(val matrixUser: MatrixUser) : ConfigureRoomEvents data class CreateRoom(val config: CreateRoomConfig) : ConfigureRoomEvents data class HandleAvatarAction(val action: AvatarAction) : ConfigureRoomEvents diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt index 7659226bd9..cf43c9ceb6 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt @@ -56,11 +56,6 @@ class ConfigureRoomPresenter @Inject constructor( @Composable override fun present(): ConfigureRoomState { val createRoomConfig = dataStore.getCreateRoomConfig().collectAsState(CreateRoomConfig()) - val isCreateButtonEnabled by remember(createRoomConfig.value.roomName, createRoomConfig.value.privacy) { - derivedStateOf { - createRoomConfig.value.roomName.isNullOrEmpty().not() && createRoomConfig.value.privacy != null - } - } val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker( onResult = { uri -> if (uri != null) dataStore.setAvatarUri(uri = uri, cached = true) }, @@ -108,7 +103,6 @@ class ConfigureRoomPresenter @Inject constructor( return ConfigureRoomState( config = createRoomConfig.value, - isCreateButtonEnabled = isCreateButtonEnabled, avatarActions = avatarActions, createRoomAction = createRoomAction.value, eventSink = ::handleEvents, diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomState.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomState.kt index 0e0c465b52..b99d70bb13 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomState.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomState.kt @@ -24,8 +24,9 @@ import kotlinx.collections.immutable.ImmutableList data class ConfigureRoomState( val config: CreateRoomConfig, - val isCreateButtonEnabled: Boolean, val avatarActions: ImmutableList, val createRoomAction: Async, val eventSink: (ConfigureRoomEvents) -> Unit -) +) { + val isCreateButtonEnabled: Boolean = config.roomName.isNullOrEmpty().not() +} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomStateProvider.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomStateProvider.kt index 2dd4854f3a..9cb62d4f28 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomStateProvider.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomStateProvider.kt @@ -31,16 +31,14 @@ open class ConfigureRoomStateProvider : PreviewParameterProvider Date: Fri, 12 May 2023 00:24:03 +0200 Subject: [PATCH 28/36] Close keyboard when textfields lose focus --- .../impl/configureroom/ConfigureRoomView.kt | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt index 4b23d5f389..3fb3675e62 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt @@ -17,6 +17,7 @@ package io.element.android.features.createroom.impl.configureroom import android.net.Uri +import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -33,6 +34,10 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import androidx.compose.ui.focus.FocusManager +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview @@ -68,6 +73,7 @@ fun ConfigureRoomView( onRoomCreated: (RoomId) -> Unit = {}, ) { val coroutineScope = rememberCoroutineScope() + val focusManager = LocalFocusManager.current val itemActionsBottomSheetState = rememberModalBottomSheetState( initialValue = ModalBottomSheetValue.Hidden, ) @@ -79,18 +85,20 @@ fun ConfigureRoomView( } fun onAvatarClicked() { + focusManager.clearFocus() coroutineScope.launch { itemActionsBottomSheetState.show() } } Scaffold( - modifier = modifier, + modifier = modifier.clearFocusOnTap(focusManager), topBar = { ConfigureRoomToolbar( isNextActionEnabled = state.isCreateButtonEnabled, onBackPressed = onBackPressed, onNextPressed = { + focusManager.clearFocus() state.eventSink(ConfigureRoomEvents.CreateRoom(state.config)) }, ) @@ -121,7 +129,10 @@ fun ConfigureRoomView( SelectedUsersList( contentPadding = PaddingValues(horizontal = 24.dp), selectedUsers = state.config.invites, - onUserRemoved = { state.eventSink(ConfigureRoomEvents.RemoveFromSelection(it)) }, + onUserRemoved = { + focusManager.clearFocus() + state.eventSink(ConfigureRoomEvents.RemoveFromSelection(it)) + }, ) } } @@ -129,7 +140,10 @@ fun ConfigureRoomView( RoomPrivacyOptions( modifier = Modifier.padding(bottom = 40.dp), selected = state.config.privacy, - onOptionSelected = { state.eventSink(ConfigureRoomEvents.RoomPrivacyChanged(it.privacy)) }, + onOptionSelected = { + focusManager.clearFocus() + state.eventSink(ConfigureRoomEvents.RoomPrivacyChanged(it.privacy)) + }, ) } } @@ -268,3 +282,11 @@ private fun ContentToPreview(state: ConfigureRoomState) { state = state, ) } + +private fun Modifier.clearFocusOnTap(focusManager: FocusManager) = composed { + pointerInput(Unit) { + detectTapGestures(onTap = { + focusManager.clearFocus() + }) + } +} From 2ed8515231237a5e6e4a82a3fbd25c59f8af25a8 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Fri, 12 May 2023 00:26:50 +0200 Subject: [PATCH 29/36] restrict room name to single line --- .../features/createroom/impl/components/LabelledTextField.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/LabelledTextField.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/LabelledTextField.kt index 382e4b8de2..2a28c56253 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/LabelledTextField.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/LabelledTextField.kt @@ -54,6 +54,7 @@ fun LabelledTextField( value = value, placeholder = { Text(placeholder) }, onValueChange = onValueChange, + singleLine = maxLines == 1, maxLines = maxLines, ) } From 7ffe463e23d2883e4ec0539b51679fe1301c3f45 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Fri, 12 May 2023 08:40:24 +0200 Subject: [PATCH 30/36] Rename preview --- .../libraries/designsystem/theme/components/SearchBar.kt | 3 +-- ...ll_Searchviews_SearchBarPreview_0_null,NEXUS_5,1.0,en].png} | 0 2 files changed, 1 insertion(+), 2 deletions(-) rename tests/uitests/src/test/snapshots/images/{io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_Searchviews_DockedSearchBarPreview_0_null,NEXUS_5,1.0,en].png => io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_Searchviews_SearchBarPreview_0_null,NEXUS_5,1.0,en].png} (100%) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SearchBar.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SearchBar.kt index 9a037cb7bb..4a0990bee4 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SearchBar.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SearchBar.kt @@ -31,7 +31,6 @@ import androidx.compose.ui.unit.Dp import io.element.android.libraries.designsystem.preview.ElementThemedPreview import io.element.android.libraries.designsystem.preview.PreviewGroup -@OptIn(ExperimentalMaterial3Api::class) @Composable fun SearchBar( query: String, @@ -73,7 +72,7 @@ fun SearchBar( @Preview(group = PreviewGroup.Search) @Composable -internal fun DockedSearchBarPreview() = ElementThemedPreview { ContentToPreview() } +internal fun SearchBarPreview() = ElementThemedPreview { ContentToPreview() } @OptIn(ExperimentalMaterial3Api::class) @Composable 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_Searchviews_DockedSearchBarPreview_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_Searchviews_SearchBarPreview_0_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_Searchviews_DockedSearchBarPreview_0_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_Searchviews_SearchBarPreview_0_null,NEXUS_5,1.0,en].png From 7a36d084e62bb2c10279dde8d1fd89c159b2e647 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Fri, 12 May 2023 08:57:06 +0200 Subject: [PATCH 31/36] change wording for DM creation dialog --- .../features/createroom/impl/root/CreateRoomRootView.kt | 2 +- libraries/ui-strings/src/main/res/values/localazy.xml | 4 +++- ...CreateRoomRootViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...reateRoomRootViewLightPreview_0_null_1,NEXUS_5,1.0,en].png | 4 ++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt index 2de52b89f7..8d78311dc1 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt @@ -101,7 +101,7 @@ fun CreateRoomRootView( when (state.startDmAction) { is Async.Loading -> { - ProgressDialog(text = stringResource(id = StringR.string.common_creating_room)) + ProgressDialog(text = stringResource(id = StringR.string.common_starting_chat)) } is Async.Failure -> { diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index fe7cc27a84..5e28338e22 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -63,6 +63,7 @@ "Developer options" "(edited)" "Editing" + "* %1$@ %2$@" "Encryption enabled" "Error" "File" @@ -90,6 +91,7 @@ "Server not supported" "Server URL" "Settings" + "Starting chat…" "Sticker" "Success" "Suggestions" @@ -159,4 +161,4 @@ "You can read all our terms %1$s." "here" "Block user" - \ No newline at end of file + diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.root_null_DefaultGroup_CreateRoomRootViewDarkPreview_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.createroom.impl.root_null_DefaultGroup_CreateRoomRootViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png index 1e92cf978d..2a7a10f2c1 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.root_null_DefaultGroup_CreateRoomRootViewDarkPreview_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.createroom.impl.root_null_DefaultGroup_CreateRoomRootViewDarkPreview_0_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8f29da5d5aeb65659b065b7bd6afe276f83e020545a027780d2391308d1a4076 -size 20750 +oid sha256:56c23bd0880524cc56b713c93c5358e9f3771291c20f7a149bad00465f3f987a +size 20648 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.root_null_DefaultGroup_CreateRoomRootViewLightPreview_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.createroom.impl.root_null_DefaultGroup_CreateRoomRootViewLightPreview_0_null_1,NEXUS_5,1.0,en].png index 23c4de3194..69d05b132c 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.impl.root_null_DefaultGroup_CreateRoomRootViewLightPreview_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.createroom.impl.root_null_DefaultGroup_CreateRoomRootViewLightPreview_0_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ae3e8c4e952b97628d026dfe78781aef894d6c2e742ac6ae1f1a2c0170df159e -size 20382 +oid sha256:f12591531cfdce24378003dda48940c20d8c9cf7bfac73ac1e7713e925bfac4d +size 20214 From 56251fedd985745fb0caaa6d3fa89b6889ab1571 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Fri, 12 May 2023 09:54:00 +0200 Subject: [PATCH 32/36] Remove useless `composed` call --- .../createroom/impl/configureroom/ConfigureRoomView.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt index 3fb3675e62..0b1e3d71c0 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt @@ -34,7 +34,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.composed import androidx.compose.ui.focus.FocusManager import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalFocusManager @@ -283,10 +282,10 @@ private fun ContentToPreview(state: ConfigureRoomState) { ) } -private fun Modifier.clearFocusOnTap(focusManager: FocusManager) = composed { +private fun Modifier.clearFocusOnTap(focusManager: FocusManager): Modifier = pointerInput(Unit) { detectTapGestures(onTap = { focusManager.clearFocus() }) } -} + From e407b51f6b2dece9e9c0fda7f6c38cfc5dc67533 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Mon, 15 May 2023 18:08:24 +0200 Subject: [PATCH 33/36] Sync strings --- .../impl/src/main/res/values/localazy.xml | 32 ++++++++++--------- .../src/main/res/values/localazy.xml | 3 +- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/features/roomdetails/impl/src/main/res/values/localazy.xml b/features/roomdetails/impl/src/main/res/values/localazy.xml index 7c5006cc21..e7ffee267a 100644 --- a/features/roomdetails/impl/src/main/res/values/localazy.xml +++ b/features/roomdetails/impl/src/main/res/values/localazy.xml @@ -1,22 +1,24 @@ - - "1 person" - "%1$d people" - - "Messages are secured with locks. Only you and the recipients have the unique keys to unlock them." - "Message encryption enabled" - "Share room" - "Pending" - "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" + + "1 person" + "%1$d people" + + "Already a member" + "Already invited" + "Messages are secured with locks. Only you and the recipients have the unique keys to unlock them." + "Message encryption enabled" + "Share room" + "Pending" + "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" "Invite people" "Leave room" "People" "Security" "Topic" - \ 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 5e28338e22..849f306133 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -63,7 +63,7 @@ "Developer options" "(edited)" "Editing" - "* %1$@ %2$@" + "* %1$s %2$s" "Encryption enabled" "Error" "File" @@ -85,6 +85,7 @@ "Report a bug" "Report submitted" "Search for someone" + "Search results" "Security" "Select your server" "Sending…" From c54e4acd57abeeb0044e8b323b85028175ddacbb Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Tue, 16 May 2023 16:41:43 +0200 Subject: [PATCH 34/36] Restore missing OptIn annotation --- .../android/libraries/designsystem/theme/components/SearchBar.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SearchBar.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SearchBar.kt index 4a0990bee4..f0e9eaf906 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SearchBar.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SearchBar.kt @@ -31,6 +31,7 @@ import androidx.compose.ui.unit.Dp import io.element.android.libraries.designsystem.preview.ElementThemedPreview import io.element.android.libraries.designsystem.preview.PreviewGroup +@OptIn(ExperimentalMaterial3Api::class) @Composable fun SearchBar( query: String, From 8b986b57f0ba225373d065fc39d50fb9db4e12cf Mon Sep 17 00:00:00 2001 From: Marco Romano Date: Wed, 17 May 2023 15:21:23 +0200 Subject: [PATCH 35/36] New copy for members search results (#430) * New copy for members search results Context: https://matrix.to/#/!dypRwVXIkJaTAACHPd:element.io/$Obt7MbgGtHBqJHpZqcdd6OQ5XgxxNXSJofnFG1NyWWM?via=matrix.org&via=element.io&via=t2l.io Related to: https://github.com/vector-im/element-x-android/issues/246 --- .../impl/members/RoomMemberListView.kt | 17 ++++++--- .../impl/src/main/res/values/localazy.xml | 35 ++++++++++--------- ...stDarkPreview_0_null_5,NEXUS_5,1.0,en].png | 4 +-- ...tLightPreview_0_null_5,NEXUS_5,1.0,en].png | 4 +-- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt index ab52b9774a..3358451784 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt @@ -113,7 +113,8 @@ fun RoomMemberListView( if (state.roomMembers is Async.Success) { RoomMemberList( roomMembers = state.roomMembers.state, - onUserSelected = ::onUserSelected, + showMembersCount = true, + onUserSelected = ::onUserSelected ) } else if (state.roomMembers.isLoading()) { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { @@ -128,6 +129,7 @@ fun RoomMemberListView( @Composable private fun RoomMemberList( roomMembers: RoomMembers, + showMembersCount: Boolean, onUserSelected: (RoomMember) -> Unit, ) { LazyColumn(modifier = Modifier.fillMaxWidth(), state = rememberLazyListState()) { @@ -139,9 +141,15 @@ private fun RoomMemberList( ) } if (roomMembers.joined.isNotEmpty()) { - val memberCount = roomMembers.joined.count() roomMemberListSection( - headerText = { pluralStringResource(id = R.plurals.screen_room_member_list_header_title, count = memberCount, memberCount) }, + headerText = { + if (showMembersCount) { + val memberCount = roomMembers.joined.count() + pluralStringResource(id = R.plurals.screen_room_member_list_header_title, count = memberCount, memberCount) + } else { + stringResource(id = R.string.screen_room_member_list_room_members_header_title) + } + }, members = roomMembers.joined, onMemberSelected = { onUserSelected(it) } ) @@ -272,7 +280,8 @@ private fun RoomMemberSearchBar( if (state is RoomMemberSearchResultState.Results) { RoomMemberList( roomMembers = state.results, - onUserSelected = { onUserSelected(it) } + showMembersCount = false, + onUserSelected = onUserSelected ) } else if (state is RoomMemberSearchResultState.NoResults) { Spacer(Modifier.size(80.dp)) diff --git a/features/roomdetails/impl/src/main/res/values/localazy.xml b/features/roomdetails/impl/src/main/res/values/localazy.xml index e7ffee267a..156261f66a 100644 --- a/features/roomdetails/impl/src/main/res/values/localazy.xml +++ b/features/roomdetails/impl/src/main/res/values/localazy.xml @@ -1,24 +1,25 @@ - - "1 person" - "%1$d people" - - "Already a member" - "Already invited" - "Messages are secured with locks. Only you and the recipients have the unique keys to unlock them." - "Message encryption enabled" - "Share room" - "Pending" - "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" + + "1 person" + "%1$d people" + + "Already a member" + "Already invited" + "Messages are secured with locks. Only you and the recipients have the unique keys to unlock them." + "Message encryption enabled" + "Share room" + "Pending" + "Room members" + "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" "Invite people" "Leave room" "People" "Security" "Topic" - + \ No newline at end of file diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_5,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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_5,NEXUS_5,1.0,en].png index 31ca39b498..22fe768986 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_5,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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListDarkPreview_0_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:92c4537ed8794f4db08b4edec74a0de41847c4fd8c4fe03b7112bc63124b0a61 -size 29326 +oid sha256:070c93168058fded5a76e49050f6c4554c7fe483a19aae13c1af4426a6b575f1 +size 30582 diff --git a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_5,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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_5,NEXUS_5,1.0,en].png index 4275020d4c..1b35815820 100644 --- a/tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_5,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.roomdetails.impl.members_null_DefaultGroup_RoomMemberListLightPreview_0_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1f663a70c43b9f2e66b651f17169b63859fe7c87c21312b61ed61a9136eabe5f -size 27989 +oid sha256:9dd67135f57c6e8a336e238384b02cd6068770b84f429f357d03d5e1e4c22ab6 +size 29286 From 85136f3688073aab90babed33c35243f99e26d12 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 21 May 2023 19:57:07 +0000 Subject: [PATCH 36/36] Update coil to v2.4.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cbd56b3ed6..8e5ac0ba87 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,7 +32,7 @@ accompanist = "0.30.1" test_core = "1.5.0" #other -coil = "2.3.0" +coil = "2.4.0" datetime = "0.4.0" serialization_json = "1.5.0" showkase = "1.0.0-beta18"