diff --git a/.maestro/tests/roomList/createAndDeleteRoom.yaml b/.maestro/tests/roomList/createAndDeleteRoom.yaml index e957d04bdf..a72fb80075 100644 --- a/.maestro/tests/roomList/createAndDeleteRoom.yaml +++ b/.maestro/tests/roomList/createAndDeleteRoom.yaml @@ -3,18 +3,18 @@ appId: ${MAESTRO_APP_ID} # Purpose: Test the creation and deletion of a room - tapOn: "Create a new conversation or room" - tapOn: "New room" -- tapOn: "Search for someone" -- inputText: ${MAESTRO_INVITEE1_MXID} -- tapOn: - text: ${MAESTRO_INVITEE1_MXID} - index: 1 -- tapOn: "Next" - tapOn: "e.g. your project name" - inputText: "aRoomName" - tapOn: "What is this room about?" - inputText: "aRoomTopic" - tapOn: "Create" - takeScreenshot: build/maestro/320-createAndDeleteRoom +- tapOn: "Search for someone" +- inputText: ${MAESTRO_INVITEE1_MXID} +- tapOn: + text: ${MAESTRO_INVITEE1_MXID} + index: 1 +- tapOn: "Finish" - tapOn: "aRoomName" - tapOn: "Invite" # assert there's 1 member and 1 invitee diff --git a/appnav/build.gradle.kts b/appnav/build.gradle.kts index e6b50eaaf6..bc0fa405a7 100644 --- a/appnav/build.gradle.kts +++ b/appnav/build.gradle.kts @@ -65,6 +65,7 @@ dependencies { testImplementation(projects.features.rageshake.test) testImplementation(projects.services.appnavstate.test) testImplementation(projects.services.analytics.test) + testImplementation(projects.services.toolbox.test) testImplementation(libs.test.appyx.junit) testImplementation(libs.test.arch.core) } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt index fb9b38352c..ae22e5aa97 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -46,7 +46,6 @@ import io.element.android.appnav.loggedin.SendQueues import io.element.android.appnav.room.RoomFlowNode import io.element.android.appnav.room.RoomNavigationTarget import io.element.android.appnav.room.joined.JoinedRoomLoadedFlowNode -import io.element.android.features.createroom.api.CreateRoomEntryPoint import io.element.android.features.enterprise.api.SessionEnterpriseService import io.element.android.features.ftue.api.FtueEntryPoint import io.element.android.features.ftue.api.state.FtueService @@ -60,6 +59,7 @@ import io.element.android.features.roomdirectory.api.RoomDescription import io.element.android.features.roomdirectory.api.RoomDirectoryEntryPoint import io.element.android.features.securebackup.api.SecureBackupEntryPoint import io.element.android.features.share.api.ShareEntryPoint +import io.element.android.features.startchat.api.StartChatEntryPoint import io.element.android.features.userprofile.api.UserProfileEntryPoint import io.element.android.features.verifysession.api.IncomingVerificationEntryPoint import io.element.android.libraries.architecture.BackstackView @@ -94,15 +94,6 @@ import java.time.Duration import java.time.Instant import java.util.Optional import java.util.UUID -import kotlin.collections.List -import kotlin.collections.any -import kotlin.collections.emptyList -import kotlin.collections.first -import kotlin.collections.forEach -import kotlin.collections.listOf -import kotlin.collections.mapNotNull -import kotlin.collections.plus -import kotlin.collections.setOf import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds import kotlin.time.toKotlinDuration @@ -113,7 +104,7 @@ class LoggedInFlowNode @AssistedInject constructor( @Assisted plugins: List, private val homeEntryPoint: HomeEntryPoint, private val preferencesEntryPoint: PreferencesEntryPoint, - private val createRoomEntryPoint: CreateRoomEntryPoint, + private val startChatEntryPoint: StartChatEntryPoint, private val appNavigationStateService: AppNavigationStateService, private val secureBackupEntryPoint: SecureBackupEntryPoint, private val userProfileEntryPoint: UserProfileEntryPoint, @@ -304,7 +295,7 @@ class LoggedInFlowNode @AssistedInject constructor( backstack.push(NavTarget.Settings()) } - override fun onCreateRoomClick() { + override fun onStartChatClick() { backstack.push(NavTarget.CreateRoom) } @@ -422,7 +413,7 @@ class LoggedInFlowNode @AssistedInject constructor( .build() } NavTarget.CreateRoom -> { - val callback = object : CreateRoomEntryPoint.Callback { + val callback = object : StartChatEntryPoint.Callback { override fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias, serverNames: List) { backstack.replace(NavTarget.Room(roomIdOrAlias = roomIdOrAlias, serverNames = serverNames)) } @@ -432,7 +423,7 @@ class LoggedInFlowNode @AssistedInject constructor( } } - createRoomEntryPoint + startChatEntryPoint .nodeBuilder(this, buildContext) .callback(callback) .build() diff --git a/appnav/src/test/kotlin/io/element/android/appnav/RootPresenterTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/RootPresenterTest.kt index 4c8b2a803d..2a343a1592 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/RootPresenterTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/RootPresenterTest.kt @@ -19,6 +19,7 @@ import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.services.apperror.api.AppErrorState import io.element.android.services.apperror.api.AppErrorStateService import io.element.android.services.apperror.impl.DefaultAppErrorStateService +import io.element.android.services.toolbox.test.strings.FakeStringProvider import io.element.android.tests.testutils.WarmUpRule import kotlinx.coroutines.test.runTest import org.junit.Rule @@ -42,7 +43,9 @@ class RootPresenterTest { @Test fun `present - passes app error state`() = runTest { val presenter = createRootPresenter( - appErrorService = DefaultAppErrorStateService().apply { + appErrorService = DefaultAppErrorStateService( + stringProvider = FakeStringProvider(), + ).apply { showError("Bad news", "Something bad happened") } ) @@ -61,7 +64,9 @@ class RootPresenterTest { } private fun createRootPresenter( - appErrorService: AppErrorStateService = DefaultAppErrorStateService(), + appErrorService: AppErrorStateService = DefaultAppErrorStateService( + stringProvider = FakeStringProvider(), + ), ): RootPresenter { return RootPresenter( crashDetectionPresenter = { aCrashDetectionState() }, diff --git a/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/CreateRoomEntryPoint.kt b/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/CreateRoomEntryPoint.kt index 3b35d0a3e1..5fc71f2a3b 100644 --- a/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/CreateRoomEntryPoint.kt +++ b/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/CreateRoomEntryPoint.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023, 2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. @@ -11,17 +11,17 @@ import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin import io.element.android.libraries.architecture.FeatureEntryPoint -import io.element.android.libraries.matrix.api.core.RoomIdOrAlias +import io.element.android.libraries.matrix.api.core.RoomId interface CreateRoomEntryPoint : FeatureEntryPoint { fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder + interface NodeBuilder { fun callback(callback: Callback): NodeBuilder fun build(): Node } interface Callback : Plugin { - fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias, serverNames: List) - fun onOpenRoomDirectory() + fun onRoomCreated(roomId: RoomId) } } diff --git a/features/createroom/impl/build.gradle.kts b/features/createroom/impl/build.gradle.kts index 769f7b5628..99e8fc653f 100644 --- a/features/createroom/impl/build.gradle.kts +++ b/features/createroom/impl/build.gradle.kts @@ -1,4 +1,3 @@ -import extension.ComponentMergingStrategy import extension.setupAnvil /* @@ -23,7 +22,7 @@ android { } } -setupAnvil(componentMergingStrategy = ComponentMergingStrategy.KSP) +setupAnvil() dependencies { implementation(projects.libraries.core) @@ -41,6 +40,7 @@ dependencies { implementation(projects.services.analytics.api) implementation(libs.coil.compose) implementation(projects.libraries.featureflag.api) + implementation(projects.features.invitepeople.api) api(projects.features.createroom.api) testImplementation(libs.test.junit) @@ -56,7 +56,7 @@ dependencies { testImplementation(projects.libraries.mediaupload.test) testImplementation(projects.libraries.permissions.test) testImplementation(projects.libraries.usersearch.test) - testImplementation(projects.features.createroom.test) + testImplementation(projects.features.startchat.test) testImplementation(projects.libraries.featureflag.test) testImplementation(projects.tests.testutils) testImplementation(libs.androidx.compose.ui.test.junit) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/ConfigureRoomFlowNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/ConfigureRoomFlowNode.kt deleted file mode 100644 index a7678f130f..0000000000 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/ConfigureRoomFlowNode.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2023, 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.features.createroom.impl - -import android.os.Parcelable -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import com.bumble.appyx.core.modality.BuildContext -import com.bumble.appyx.core.node.Node -import com.bumble.appyx.core.plugin.Plugin -import com.bumble.appyx.core.plugin.plugins -import com.bumble.appyx.navmodel.backstack.BackStack -import com.bumble.appyx.navmodel.backstack.operation.push -import dagger.assisted.Assisted -import dagger.assisted.AssistedInject -import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.createroom.CreateRoomNavigator -import io.element.android.features.createroom.impl.addpeople.AddPeopleNode -import io.element.android.features.createroom.impl.configureroom.ConfigureRoomNode -import io.element.android.features.createroom.impl.di.CreateRoomComponent -import io.element.android.libraries.architecture.BackstackView -import io.element.android.libraries.architecture.BaseFlowNode -import io.element.android.libraries.architecture.bindings -import io.element.android.libraries.architecture.createNode -import io.element.android.libraries.di.DaggerComponentOwner -import io.element.android.libraries.di.SessionScope -import kotlinx.parcelize.Parcelize - -@ContributesNode(SessionScope::class) -class ConfigureRoomFlowNode @AssistedInject constructor( - @Assisted buildContext: BuildContext, - @Assisted plugins: List, -) : DaggerComponentOwner, - BaseFlowNode( - backstack = BackStack( - initialElement = NavTarget.Root, - savedStateMap = buildContext.savedStateMap, - ), - buildContext = buildContext, - plugins = plugins - ) { - private val component by lazy { - parent!!.bindings().createRoomComponentBuilder().build() - } - private val navigator = plugins().first() - - override val daggerComponent: Any - get() = component - - sealed interface NavTarget : Parcelable { - @Parcelize - data object Root : NavTarget - - @Parcelize - data object ConfigureRoom : NavTarget - } - - override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { - return when (navTarget) { - NavTarget.Root -> { - val callback = object : AddPeopleNode.Callback { - override fun onContinue() { - backstack.push(NavTarget.ConfigureRoom) - } - } - createNode(buildContext = buildContext, plugins = listOf(callback)) - } - NavTarget.ConfigureRoom -> { - createNode(buildContext = buildContext, plugins = listOf(navigator)) - } - } - } - - @Composable - override fun View(modifier: Modifier) { - BackstackView() - } -} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt index b8b755a0b3..6c819edf5a 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023, 2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. @@ -8,28 +8,25 @@ package io.element.android.features.createroom.impl import android.os.Parcelable -import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import com.bumble.appyx.core.modality.BuildContext -import com.bumble.appyx.core.navigation.transition.JumpToEndTransitionHandler import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.operation.replace import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.createroom.DefaultCreateRoomNavigator import io.element.android.features.createroom.api.CreateRoomEntryPoint -import io.element.android.features.createroom.impl.joinbyaddress.JoinRoomByAddressNode -import io.element.android.features.createroom.impl.root.CreateRoomRootNode +import io.element.android.features.createroom.impl.addpeople.AddPeopleNode +import io.element.android.features.createroom.impl.configureroom.ConfigureRoomNode import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode -import io.element.android.libraries.architecture.OverlayView import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.core.RoomId import kotlinx.parcelize.Parcelize @ContributesNode(SessionScope::class) @@ -38,53 +35,48 @@ class CreateRoomFlowNode @AssistedInject constructor( @Assisted plugins: List, ) : BaseFlowNode( backstack = BackStack( - initialElement = NavTarget.Root, + initialElement = NavTarget.ConfigureRoom, savedStateMap = buildContext.savedStateMap, ), buildContext = buildContext, plugins = plugins ) { - sealed interface NavTarget : Parcelable { - @Parcelize - data object Root : NavTarget - - @Parcelize - data object NewRoom : NavTarget - - @Parcelize - data object JoinByAddress : NavTarget + private fun onRoomCreated(roomId: RoomId) { + plugins().forEach { it.onRoomCreated(roomId) } } - private val navigator = DefaultCreateRoomNavigator( - backstack = backstack, - overlay = overlay, - openRoom = { roomIdOrAlias, viaServers -> - plugins().forEach { it.onOpenRoom(roomIdOrAlias, viaServers) } - }, - openRoomDirectory = { - plugins().forEach { it.onOpenRoomDirectory() } - } - ) - override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { return when (navTarget) { - NavTarget.Root -> { - createNode(buildContext = buildContext, plugins = listOf(navigator)) + NavTarget.ConfigureRoom -> { + val callback = object : ConfigureRoomNode.Callback { + override fun onCreateRoomSuccess(roomId: RoomId) { + backstack.replace(NavTarget.AddPeople(roomId)) + } + } + createNode(buildContext, plugins = listOf(callback)) } - NavTarget.NewRoom -> { - createNode(buildContext = buildContext, plugins = listOf(navigator)) - } - NavTarget.JoinByAddress -> { - createNode(buildContext = buildContext, plugins = listOf(navigator)) + is NavTarget.AddPeople -> { + val inputs = AddPeopleNode.Inputs(navTarget.roomId) + val callback: AddPeopleNode.Callback = object : AddPeopleNode.Callback { + override fun onFinish() { + onRoomCreated(navTarget.roomId) + } + } + createNode(buildContext, plugins = listOf(inputs, callback)) } } } @Composable override fun View(modifier: Modifier) { - Box(modifier = modifier) { - BackstackView() - OverlayView(transitionHandler = remember { JumpToEndTransitionHandler() }) - } + BackstackView() + } + + sealed interface NavTarget : Parcelable { + @Parcelize + data object ConfigureRoom : NavTarget + + @Parcelize + data class AddPeople(val roomId: RoomId) : NavTarget } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt index 161d67e817..b9dfb20960 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023, 2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. @@ -13,10 +13,10 @@ import com.bumble.appyx.core.plugin.Plugin import com.squareup.anvil.annotations.ContributesBinding import io.element.android.features.createroom.api.CreateRoomEntryPoint import io.element.android.libraries.architecture.createNode -import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.SessionScope import javax.inject.Inject -@ContributesBinding(AppScope::class) +@ContributesBinding(SessionScope::class) class DefaultCreateRoomEntryPoint @Inject constructor() : CreateRoomEntryPoint { override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): CreateRoomEntryPoint.NodeBuilder { val plugins = ArrayList() diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt index ba9eb82073..3fc9cd7d81 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023, 2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. @@ -16,30 +16,46 @@ import com.bumble.appyx.core.plugin.plugins import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.createroom.impl.di.CreateRoomScope +import io.element.android.features.invitepeople.api.InvitePeoplePresenter +import io.element.android.features.invitepeople.api.InvitePeopleRenderer +import io.element.android.libraries.architecture.NodeInputs +import io.element.android.libraries.architecture.inputs +import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.core.RoomId -@ContributesNode(CreateRoomScope::class) +@ContributesNode(SessionScope::class) class AddPeopleNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, - private val presenter: AddPeoplePresenter, + invitePeoplePresenterFactory: InvitePeoplePresenter.Factory, + private val invitePeopleRenderer: InvitePeopleRenderer, ) : Node(buildContext, plugins = plugins) { + data class Inputs( + val roomId: RoomId, + ) : NodeInputs + interface Callback : Plugin { - fun onContinue() + fun onFinish() } - private fun onContinue() { - plugins().forEach { it.onContinue() } + private fun onFinish() { + plugins().forEach { it.onFinish() } } + private val roomId = inputs().roomId + private val invitePeoplePresenter = invitePeoplePresenterFactory.create( + joinedRoom = null, + roomId = roomId, + ) + @Composable override fun View(modifier: Modifier) { - val state = presenter.present() + val state = invitePeoplePresenter.present() AddPeopleView( state = state, - modifier = modifier, - onBackClick = this::navigateUp, - onNextClick = this::onContinue, - ) + onFinish = ::onFinish, + ) { + invitePeopleRenderer.Render(state, Modifier) + } } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeoplePresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeoplePresenter.kt deleted file mode 100644 index e050a0738e..0000000000 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeoplePresenter.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2023, 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.features.createroom.impl.addpeople - -import androidx.compose.runtime.Composable -import io.element.android.features.createroom.impl.CreateRoomDataStore -import io.element.android.features.createroom.impl.userlist.SelectionMode -import io.element.android.features.createroom.impl.userlist.UserListPresenter -import io.element.android.features.createroom.impl.userlist.UserListPresenterArgs -import io.element.android.features.createroom.impl.userlist.UserListState -import io.element.android.libraries.architecture.Presenter -import io.element.android.libraries.usersearch.api.UserRepository -import javax.inject.Inject - -class AddPeoplePresenter @Inject constructor( - userListPresenterFactory: UserListPresenter.Factory, - userRepository: UserRepository, - dataStore: CreateRoomDataStore, -) : Presenter { - private val userListPresenter = userListPresenterFactory.create( - UserListPresenterArgs( - selectionMode = SelectionMode.Multiple, - ), - userRepository, - dataStore.selectedUserListDataStore, - ) - - @Composable - override fun present(): UserListState { - return userListPresenter.present() - } -} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleUserListStateProvider.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleUserListStateProvider.kt deleted file mode 100644 index 9e0ddd04c8..0000000000 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleUserListStateProvider.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2023, 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.features.createroom.impl.addpeople - -import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.features.createroom.impl.userlist.SelectionMode -import io.element.android.features.createroom.impl.userlist.UserListState -import io.element.android.features.createroom.impl.userlist.aRecentDirectRoomList -import io.element.android.features.createroom.impl.userlist.aUserListState -import io.element.android.libraries.designsystem.theme.components.SearchBarResultState -import io.element.android.libraries.matrix.ui.components.aMatrixUserList -import io.element.android.libraries.usersearch.api.UserSearchResult -import kotlinx.collections.immutable.toImmutableList - -open class AddPeopleUserListStateProvider : PreviewParameterProvider { - override val values: Sequence - get() = sequenceOf( - aUserListState(), - aUserListState( - searchResults = SearchBarResultState.Results(aMatrixUserList().toImmutableList()), - selectedUsers = aMatrixUserList().toImmutableList(), - isSearchActive = false, - selectionMode = SelectionMode.Multiple, - ), - aUserListState( - searchResults = SearchBarResultState.Results( - aMatrixUserList() - .mapIndexed { index, matrixUser -> - UserSearchResult(matrixUser, index % 2 == 0) - } - .toImmutableList() - ), - selectedUsers = aMatrixUserList().toImmutableList(), - isSearchActive = true, - selectionMode = SelectionMode.Multiple, - ), - aUserListState( - recentDirectRooms = aRecentDirectRoomList(), - ), - ) -} 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 d39ac4d250..1c9a5f84d3 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 @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. @@ -7,77 +7,68 @@ package io.element.android.features.createroom.impl.addpeople -import androidx.compose.foundation.layout.consumeWindowInsets -import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.unit.dp import io.element.android.features.createroom.impl.R -import io.element.android.features.createroom.impl.components.UserListView -import io.element.android.features.createroom.impl.userlist.UserListEvents -import io.element.android.features.createroom.impl.userlist.UserListState -import io.element.android.libraries.designsystem.components.button.BackButton +import io.element.android.features.invitepeople.api.InvitePeopleEvents +import io.element.android.features.invitepeople.api.InvitePeopleState +import io.element.android.features.invitepeople.api.InvitePeopleStateProvider +import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight -import io.element.android.libraries.designsystem.theme.components.Scaffold +import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.ui.strings.CommonStrings @Composable fun AddPeopleView( - state: UserListState, - onBackClick: () -> Unit, - onNextClick: () -> Unit, + state: InvitePeopleState, + onFinish: () -> Unit, modifier: Modifier = Modifier, + invitePeopleView: @Composable () -> Unit, ) { - Scaffold( + HeaderFooterPage( modifier = modifier, + contentPadding = PaddingValues(0.dp), topBar = { - AddPeopleViewTopBar( - hasSelectedUsers = state.selectedUsers.isNotEmpty(), - onBackClick = { - if (state.isSearchActive) { - state.eventSink(UserListEvents.OnSearchActiveChanged(false)) - } else { - onBackClick() - } + AddPeopleTopBar(onSkipClick = onFinish) + }, + footer = { + Button( + text = stringResource(CommonStrings.action_finish), + onClick = { + state.eventSink(InvitePeopleEvents.SendInvites) + onFinish() }, - onNextClick = onNextClick, + enabled = state.canInvite, + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 16.dp) ) - } - ) { padding -> - UserListView( - modifier = Modifier - .fillMaxSize() - .padding(padding) - .consumeWindowInsets(padding), - state = state, - showBackButton = false, - onSelectUser = {}, - onDeselectUser = {}, - ) - } + }, + content = invitePeopleView + ) } @OptIn(ExperimentalMaterial3Api::class) @Composable -private fun AddPeopleViewTopBar( - hasSelectedUsers: Boolean, - onBackClick: () -> Unit, - onNextClick: () -> Unit, +private fun AddPeopleTopBar( + onSkipClick: () -> Unit, ) { TopAppBar( - titleStr = stringResource(id = R.string.screen_create_room_add_people_title), - navigationIcon = { BackButton(onClick = onBackClick) }, + titleStr = stringResource(R.string.screen_create_room_add_people_title), actions = { - val textActionResId = if (hasSelectedUsers) CommonStrings.action_next else CommonStrings.action_skip TextButton( - text = stringResource(id = textActionResId), - onClick = onNextClick, + text = stringResource(CommonStrings.action_skip), + onClick = onSkipClick, ) } ) @@ -85,10 +76,10 @@ private fun AddPeopleViewTopBar( @PreviewsDayNight @Composable -internal fun AddPeopleViewPreview(@PreviewParameter(AddPeopleUserListStateProvider::class) state: UserListState) = ElementPreview { +internal fun AddPeopleViewPreview(@PreviewParameter(InvitePeopleStateProvider::class) state: InvitePeopleState) = ElementPreview { AddPeopleView( state = state, - onBackClick = {}, - onNextClick = {}, + invitePeopleView = {}, + onFinish = {}, ) } 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 6885123f63..cd5470bc24 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 @@ -7,7 +7,6 @@ package io.element.android.features.createroom.impl.configureroom -import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.ui.media.AvatarAction sealed interface ConfigureRoomEvents { @@ -16,7 +15,6 @@ sealed interface ConfigureRoomEvents { data class RoomVisibilityChanged(val visibilityItem: RoomVisibilityItem) : ConfigureRoomEvents data class RoomAccessChanged(val roomAccess: RoomAccessItem) : ConfigureRoomEvents data class RoomAddressChanged(val roomAddress: String) : ConfigureRoomEvents - data class RemoveUserFromSelection(val matrixUser: MatrixUser) : ConfigureRoomEvents data object CreateRoom : ConfigureRoomEvents data class HandleAvatarAction(val action: AvatarAction) : ConfigureRoomEvents data object CancelCreateRoom : ConfigureRoomEvents diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt index e718825163..6927c51366 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt @@ -18,19 +18,20 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.createroom.CreateRoomNavigator -import io.element.android.features.createroom.impl.di.CreateRoomScope -import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias +import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.services.analytics.api.AnalyticsService -@ContributesNode(CreateRoomScope::class) +@ContributesNode(SessionScope::class) class ConfigureRoomNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val presenter: ConfigureRoomPresenter, private val analyticsService: AnalyticsService, ) : Node(buildContext, plugins = plugins) { - private val navigator = plugins().first() + interface Callback : Plugin { + fun onCreateRoomSuccess(roomId: RoomId) + } init { lifecycle.subscribe( @@ -40,6 +41,10 @@ class ConfigureRoomNode @AssistedInject constructor( ) } + private fun onCreateRoomSuccess(roomId: RoomId) { + plugins().forEach { it.onCreateRoomSuccess(roomId) } + } + @Composable override fun View(modifier: Modifier) { val state = presenter.present() @@ -47,9 +52,7 @@ class ConfigureRoomNode @AssistedInject constructor( state = state, modifier = modifier, onBackClick = this::navigateUp, - onCreateRoomSuccess = { - navigator.onOpenRoom(roomIdOrAlias = it.toRoomIdOrAlias(), serverNames = emptyList()) - }, + onCreateRoomSuccess = ::onCreateRoomSuccess, ) } } 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 a3e8f67edf..397ae74186 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 @@ -18,8 +18,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import im.vector.app.features.analytics.plan.CreatedRoom -import io.element.android.features.createroom.impl.CreateRoomConfig -import io.element.android.features.createroom.impl.CreateRoomDataStore import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState @@ -50,7 +48,7 @@ import javax.inject.Inject import kotlin.jvm.optionals.getOrDefault class ConfigureRoomPresenter @Inject constructor( - private val dataStore: CreateRoomDataStore, + private val dataStore: CreateRoomConfigStore, private val matrixClient: MatrixClient, private val mediaPickerProvider: PickerProvider, private val mediaPreProcessor: MediaPreProcessor, @@ -66,7 +64,7 @@ class ConfigureRoomPresenter @Inject constructor( @Composable override fun present(): ConfigureRoomState { val cameraPermissionState = cameraPermissionPresenter.present() - val createRoomConfig by dataStore.createRoomConfigWithInvites.collectAsState(CreateRoomConfig()) + val createRoomConfig by dataStore.getCreateRoomConfigFlow().collectAsState(CreateRoomConfig()) val homeserverName = remember { matrixClient.userIdServerName() } val isKnockFeatureEnabled by remember { featureFlagService.isFeatureEnabledFlow(FeatureFlags.Knock) @@ -121,7 +119,6 @@ class ConfigureRoomPresenter @Inject constructor( is ConfigureRoomEvents.RoomNameChanged -> dataStore.setRoomName(event.name) is ConfigureRoomEvents.TopicChanged -> dataStore.setTopic(event.topic) is ConfigureRoomEvents.RoomVisibilityChanged -> dataStore.setRoomVisibility(event.visibilityItem) - is ConfigureRoomEvents.RemoveUserFromSelection -> dataStore.selectedUserListDataStore.removeUserFromSelection(event.matrixUser) is ConfigureRoomEvents.RoomAccessChanged -> dataStore.setRoomAccess(event.roomAccess) is ConfigureRoomEvents.RoomAddressChanged -> dataStore.setRoomAddress(event.roomAddress) is ConfigureRoomEvents.CreateRoom -> createRoom(createRoomConfig) 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 6651d16604..90022a9204 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 @@ -7,7 +7,6 @@ package io.element.android.features.createroom.impl.configureroom -import io.element.android.features.createroom.impl.CreateRoomConfig import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.ui.media.AvatarAction 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 71568dbbc7..7db8744408 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 @@ -8,7 +8,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.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.ui.components.aMatrixUserList 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 f639704890..8c56607a22 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 @@ -12,7 +12,6 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.consumeWindowInsets @@ -58,7 +57,6 @@ import io.element.android.libraries.designsystem.theme.components.TextField import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.ui.components.AvatarActionBottomSheet -import io.element.android.libraries.matrix.ui.components.SelectedUsersRowList import io.element.android.libraries.matrix.ui.components.UnsavedAvatar import io.element.android.libraries.matrix.ui.room.address.RoomAddressField import io.element.android.libraries.permissions.api.PermissionsView @@ -112,16 +110,6 @@ fun ConfigureRoomView( topic = state.config.topic.orEmpty(), onTopicChange = { state.eventSink(ConfigureRoomEvents.TopicChanged(it)) }, ) - if (state.config.invites.isNotEmpty()) { - SelectedUsersRowList( - contentPadding = PaddingValues(horizontal = 24.dp), - selectedUsers = state.config.invites, - onUserRemove = { - focusManager.clearFocus() - state.eventSink(ConfigureRoomEvents.RemoveUserFromSelection(it)) - }, - ) - } RoomVisibilityOptions( selected = when (state.config.roomVisibility) { is RoomVisibilityState.Private -> RoomVisibilityItem.Private 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/configureroom/CreateRoomConfig.kt similarity index 82% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomConfig.kt rename to features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfig.kt index 4cfa6158b8..9ec71f5b76 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/configureroom/CreateRoomConfig.kt @@ -5,10 +5,9 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl +package io.element.android.features.createroom.impl.configureroom import android.net.Uri -import io.element.android.features.createroom.impl.configureroom.RoomVisibilityState import io.element.android.libraries.matrix.api.user.MatrixUser import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf 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/configureroom/CreateRoomConfigStore.kt similarity index 78% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt rename to features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfigStore.kt index 29b1525f51..bee9b686d6 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/configureroom/CreateRoomConfigStore.kt @@ -5,45 +5,29 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl +package io.element.android.features.createroom.impl.configureroom import android.net.Uri -import io.element.android.features.createroom.impl.configureroom.RoomAccess -import io.element.android.features.createroom.impl.configureroom.RoomAccessItem -import io.element.android.features.createroom.impl.configureroom.RoomAddress -import io.element.android.features.createroom.impl.configureroom.RoomVisibilityItem -import io.element.android.features.createroom.impl.configureroom.RoomVisibilityState -import io.element.android.features.createroom.impl.di.CreateRoomScope -import io.element.android.features.createroom.impl.userlist.UserListDataStore import io.element.android.libraries.androidutils.file.safeDelete -import io.element.android.libraries.di.SingleIn import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper -import kotlinx.collections.immutable.toImmutableList -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.getAndUpdate import java.io.File import javax.inject.Inject -@SingleIn(CreateRoomScope::class) -class CreateRoomDataStore @Inject constructor( - val selectedUserListDataStore: UserListDataStore, +class CreateRoomConfigStore @Inject constructor( private val roomAliasHelper: RoomAliasHelper, ) { private val createRoomConfigFlow: MutableStateFlow = MutableStateFlow(CreateRoomConfig()) + private var cachedAvatarUri: Uri? = null set(value) { field?.path?.let { File(it) }?.safeDelete() field = value } - val createRoomConfigWithInvites: Flow = combine( - selectedUserListDataStore.selectedUsers, - createRoomConfigFlow, - ) { selectedUsers, config -> - config.copy(invites = selectedUsers.toImmutableList()) - } + fun getCreateRoomConfigFlow(): StateFlow = createRoomConfigFlow fun setRoomName(roomName: String) { createRoomConfigFlow.getAndUpdate { config -> diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/di/CreateRoomComponent.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/di/CreateRoomComponent.kt deleted file mode 100644 index b47b8c30e5..0000000000 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/di/CreateRoomComponent.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2023, 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.features.createroom.impl.di - -import com.squareup.anvil.annotations.ContributesTo -import com.squareup.anvil.annotations.MergeSubcomponent -import io.element.android.libraries.architecture.NodeFactoriesBindings -import io.element.android.libraries.di.SessionScope -import io.element.android.libraries.di.SingleIn - -@SingleIn(CreateRoomScope::class) -@MergeSubcomponent(CreateRoomScope::class) -interface CreateRoomComponent : NodeFactoriesBindings { - @MergeSubcomponent.Builder - interface Builder { - fun build(): CreateRoomComponent - } - - @ContributesTo(SessionScope::class) - interface ParentBindings { - fun createRoomComponentBuilder(): Builder - } -} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/di/CreateRoomScope.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/di/CreateRoomScope.kt deleted file mode 100644 index b0a011424a..0000000000 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/di/CreateRoomScope.kt +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright 2023, 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.features.createroom.impl.di - -abstract class CreateRoomScope private constructor() diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootEvents.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootEvents.kt deleted file mode 100644 index bc3c4a39b9..0000000000 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootEvents.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2023, 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.features.createroom.impl.root - -import io.element.android.libraries.matrix.api.user.MatrixUser - -sealed interface CreateRoomRootEvents { - data class StartDM(val matrixUser: MatrixUser) : CreateRoomRootEvents - data object CancelStartDM : CreateRoomRootEvents -} diff --git a/features/createroom/impl/src/main/res/values-be/translations.xml b/features/createroom/impl/src/main/res/values-be/translations.xml index 8acb990b02..f5d6a234e2 100644 --- a/features/createroom/impl/src/main/res/values-be/translations.xml +++ b/features/createroom/impl/src/main/res/values-be/translations.xml @@ -14,6 +14,4 @@ "Назва пакоя" "Стварыце пакой" "Тэма (неабавязкова)" - "Каталог пакояў" - "Пры спробе пачаць чат адбылася памылка" diff --git a/features/createroom/impl/src/main/res/values-bg/translations.xml b/features/createroom/impl/src/main/res/values-bg/translations.xml index fa6dae371c..249058b7af 100644 --- a/features/createroom/impl/src/main/res/values-bg/translations.xml +++ b/features/createroom/impl/src/main/res/values-bg/translations.xml @@ -15,9 +15,4 @@ "Видимост на стаята" "Създаване на стая" "Тема за разговор (незадължително)" - "Присъединяване към стая по адрес" - "Не е валиден адрес" - "Въведете…" - "Стаята не е намерена" - "напр. #room-name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-cs/translations.xml b/features/createroom/impl/src/main/res/values-cs/translations.xml index 53592e0db0..e19cfbcf91 100644 --- a/features/createroom/impl/src/main/res/values-cs/translations.xml +++ b/features/createroom/impl/src/main/res/values-cs/translations.xml @@ -19,12 +19,4 @@ To můžete kdykoli změnit v nastavení místnosti." "Viditelnost místnosti" "Vytvořit místnost" "Téma (nepovinné)" - "Adresář místností" - "Při pokusu o zahájení chatu došlo k chybě" - "Vstoupit do místnosti pomocí adresy" - "Neplatná adresa" - "Zadejte…" - "Odpovídající místnost nalezena" - "Místnost nebyla nalezena" - "např. #room-name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-cy/translations.xml b/features/createroom/impl/src/main/res/values-cy/translations.xml index a3a9e30e35..52168014bf 100644 --- a/features/createroom/impl/src/main/res/values-cy/translations.xml +++ b/features/createroom/impl/src/main/res/values-cy/translations.xml @@ -19,12 +19,4 @@ Gallwch newid hyn unrhyw bryd yng ngosodiadau ystafell." "Gwelededd yr ystafell" "Creu ystafell" "Pwnc (dewisol)" - "Cyfeiriadur ystafelloedd" - "Digwyddodd gwall wrth geisio cychwyn sgwrs" - "Ymuno â\'r ystafell yn ôl cyfeiriad" - "Ddim yn gyfeiriad dilys" - "Ewch i mewn…" - "Cafwyd hyd i ystafell gyfatebol" - "Heb ganfod yr ystafell" - "e.e. #enw-ystafell:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-da/translations.xml b/features/createroom/impl/src/main/res/values-da/translations.xml index c9c182b474..a8f66f60db 100644 --- a/features/createroom/impl/src/main/res/values-da/translations.xml +++ b/features/createroom/impl/src/main/res/values-da/translations.xml @@ -19,12 +19,4 @@ Du kan ændre dette når som helst i rummets indstillinger." "Rummets synlighed" "Opret et rum" "Emne (valgfrit)" - "Register over rum" - "Der opstod en fejl under forsøget på at starte en samtale" - "Tilslut dig rummet med adressen" - "Ikke en gyldig adresse" - "Indtast…" - "Matchende rum fundet" - "Rum ikke fundet" - "f.eks. #rummets-navn:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-de/translations.xml b/features/createroom/impl/src/main/res/values-de/translations.xml index 90438aa38c..213d10ae7a 100644 --- a/features/createroom/impl/src/main/res/values-de/translations.xml +++ b/features/createroom/impl/src/main/res/values-de/translations.xml @@ -19,12 +19,4 @@ Sie können dies aber jederzeit in den Chatroomeinstellungen ändern." " Sichtbarkeit des Chatrooms" "Raum erstellen" "Thema (optional)" - "Raum-Verzeichnis" - "Beim Versuch, einen Chat zu starten, ist ein Fehler aufgetreten" - "Raum per Adresse betreten" - "Keine gültige Adresse" - "Eintreten…" - "Passender Raum gefunden" - "Raum nicht gefunden" - "z. B. #room -name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-el/translations.xml b/features/createroom/impl/src/main/res/values-el/translations.xml index c036b43a05..a3084a4e70 100644 --- a/features/createroom/impl/src/main/res/values-el/translations.xml +++ b/features/createroom/impl/src/main/res/values-el/translations.xml @@ -19,12 +19,4 @@ "Ορατότητα αίθουσας" "Δημιουργία αίθουσας" "Θέμα (προαιρετικό)" - "Κατάλογος αιθουσών" - "Παρουσιάστηκε σφάλμα κατά την προσπάθεια έναρξης μιας συνομιλίας" - "Συμμετοχή σε αίθουσα μέσω διεύθυνσης" - "Μη έγκυρη διεύθυνση" - "Εισάγετε…" - "Βρέθηκε η αντίστοιχη αίθουσα" - "Η αίθουσα δεν βρέθηκε" - "π.χ. #όνομα-αίθουσας:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-es/translations.xml b/features/createroom/impl/src/main/res/values-es/translations.xml index c11f08fc14..521f761174 100644 --- a/features/createroom/impl/src/main/res/values-es/translations.xml +++ b/features/createroom/impl/src/main/res/values-es/translations.xml @@ -19,12 +19,4 @@ Puedes cambiar esto en cualquier momento en los ajustes de la sala." "Visibilidad de la sala" "Crear una sala" "Tema (opcional)" - "Directorio de salas" - "Se ha producido un error al intentar iniciar un chat" - "Unirse a una sala por su dirección" - "Dirección no válida" - "Introducir…" - "Sala encontrada" - "No se encontró la sala" - "p. ej., #nombre-de-la-sala:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-et/translations.xml b/features/createroom/impl/src/main/res/values-et/translations.xml index 57a26106b3..6a1d9dc58a 100644 --- a/features/createroom/impl/src/main/res/values-et/translations.xml +++ b/features/createroom/impl/src/main/res/values-et/translations.xml @@ -19,12 +19,4 @@ Sa võid seda jututoa seadistustest alati muuta." "Jututoa nähtavus" "Loo jututuba" "Teema (kui soovid lisada)" - "Jututubade kataloog" - "Vestluse alustamisel tekkis viga" - "Liitu jututoaga aadressi alusel" - "See pole kehtiv aadress" - "Sisene…" - "Leidsime vastava jututoa" - "Jututuba ei leidu" - "nt. #jututoa-nimi:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-eu/translations.xml b/features/createroom/impl/src/main/res/values-eu/translations.xml index 43f67e429c..537aa495a5 100644 --- a/features/createroom/impl/src/main/res/values-eu/translations.xml +++ b/features/createroom/impl/src/main/res/values-eu/translations.xml @@ -16,8 +16,4 @@ Gelaren ezarpenetan aldatu dezakezu hobespena." "Gelaren ikusgarritasuna" "Sortu gela" "Mintzagaia (aukerakoa)" - "Gelen direktorioa" - "Errorea gertatu da txata hasten saiatzean" - "Sartu…" - "Ez da gela aurkitu" diff --git a/features/createroom/impl/src/main/res/values-fa/translations.xml b/features/createroom/impl/src/main/res/values-fa/translations.xml index 03bc5c3f58..09869c76f6 100644 --- a/features/createroom/impl/src/main/res/values-fa/translations.xml +++ b/features/createroom/impl/src/main/res/values-fa/translations.xml @@ -17,12 +17,4 @@ "نمایانی اتاق" "ایجاد اتاق" "موضوع (اختیاری)" - "فهرست اتاق‌ها" - "هنگام تلاش برای شروع چت خطایی روی داد" - "پیوستن به اتاق با نشانی" - "نشانی معتبری نیست" - "ورود…" - "اتاق مطابق پیدا شد" - "اتاق پیدا نشد" - "نمونه: ‪#room-name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-fi/translations.xml b/features/createroom/impl/src/main/res/values-fi/translations.xml index cdb6d04d59..31589ab997 100644 --- a/features/createroom/impl/src/main/res/values-fi/translations.xml +++ b/features/createroom/impl/src/main/res/values-fi/translations.xml @@ -19,12 +19,4 @@ Voit muuttaa tämän milloin tahansa huoneen asetuksista." "Huoneen näkyvyys" "Luo huone" "Aihe (valinnainen)" - "Huoneluettelo" - "Keskustelun aloituksessa tapahtui virhe" - "Liity huoneeseen osoitteella" - "Osoite ei ole kelvollinen" - "Syötä…" - "Täsmäävä huone löytyi" - "Huonetta ei löytynyt" - "esim. #huoneen-nimi:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-fr/translations.xml b/features/createroom/impl/src/main/res/values-fr/translations.xml index 3f9e01dc85..afbdc919ba 100644 --- a/features/createroom/impl/src/main/res/values-fr/translations.xml +++ b/features/createroom/impl/src/main/res/values-fr/translations.xml @@ -19,12 +19,4 @@ Vous pouvez modifier cela à tout moment dans les paramètres du salon.""Visibilité du salon" "Créer un salon" "Sujet (facultatif)" - "Annuaire des salons" - "Une erreur s’est produite lors de la tentative de création de la discussion" - "Saisir une adresse de salon" - "Ce n’est pas une adresse valide" - "Saisir…" - "Ce salon existe" - "Salon non trouvé" - "ex: #nom-du-salon:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-hu/translations.xml b/features/createroom/impl/src/main/res/values-hu/translations.xml index 1e4a721279..8833afcdec 100644 --- a/features/createroom/impl/src/main/res/values-hu/translations.xml +++ b/features/createroom/impl/src/main/res/values-hu/translations.xml @@ -19,12 +19,4 @@ Ezt bármikor módosíthatja a szobabeállításokban." "Szoba láthatósága" "Szoba létrehozása" "Téma (nem kötelező)" - "Szobakatalógus" - "Hiba történt a csevegés indításakor" - "Csatlakozás a szobához cím szerint" - "Nem érvényes cím" - "Írja be…" - "Megfelelő szoba található" - "Szoba nem található" - "pl. #szoba-neve:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-in/translations.xml b/features/createroom/impl/src/main/res/values-in/translations.xml index 65f135e617..219f621068 100644 --- a/features/createroom/impl/src/main/res/values-in/translations.xml +++ b/features/createroom/impl/src/main/res/values-in/translations.xml @@ -19,12 +19,4 @@ Anda dapat mengubah ini kapan pun dalam pengaturan ruangan." "Keterlihatan ruangan" "Buat ruangan" "Topik (opsional)" - "Direktori ruangan" - "Terjadi kesalahan saat mencoba memulai obrolan" - "Bergabung dalam ruangan berdasarkan alamat" - "Bukan alamat yang valid" - "Masuk…" - "Ruangan yang cocok ditemukan" - "Ruangan tidak ditemukan" - "mis. #nama-ruangan:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-it/translations.xml b/features/createroom/impl/src/main/res/values-it/translations.xml index 701ebc967f..741b88b763 100644 --- a/features/createroom/impl/src/main/res/values-it/translations.xml +++ b/features/createroom/impl/src/main/res/values-it/translations.xml @@ -19,12 +19,4 @@ Puoi modificarlo in qualsiasi momento nelle impostazioni della stanza." "Visibilità della stanza" "Crea una stanza" "Argomento (facoltativo)" - "Elenco delle stanze" - "Si è verificato un errore durante il tentativo di avviare una chat" - "Accedi alla stanza tramite indirizzo" - "Indirizzo non valido" - "Inserisci…" - "Stanza trovata" - "Stanza non trovata" - "ad esempio #room -name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-ka/translations.xml b/features/createroom/impl/src/main/res/values-ka/translations.xml index bb4a430320..20c7af40de 100644 --- a/features/createroom/impl/src/main/res/values-ka/translations.xml +++ b/features/createroom/impl/src/main/res/values-ka/translations.xml @@ -10,6 +10,4 @@ "ოთახის სახელი" "ოთახის შექმნა" "თემა (სურვილისამებრ)" - "ოთახის კატალოგი" - "ჩატის დაწყების მცდელობისას შეცდომა მოხდა" diff --git a/features/createroom/impl/src/main/res/values-lt/translations.xml b/features/createroom/impl/src/main/res/values-lt/translations.xml index 2f7a4438ea..2fb7b3eb5c 100644 --- a/features/createroom/impl/src/main/res/values-lt/translations.xml +++ b/features/createroom/impl/src/main/res/values-lt/translations.xml @@ -10,5 +10,4 @@ Tai galite bet kada pakeisti kambario nustatymuose." "Kambario pavadinimas" "Kurti kambarį" "Tema (nebūtina)" - "Bandant pradėti pokalbį įvyko klaida" diff --git a/features/createroom/impl/src/main/res/values-nb/translations.xml b/features/createroom/impl/src/main/res/values-nb/translations.xml index 9266993fd4..e6021cf5ac 100644 --- a/features/createroom/impl/src/main/res/values-nb/translations.xml +++ b/features/createroom/impl/src/main/res/values-nb/translations.xml @@ -19,12 +19,4 @@ Du kan endre dette når som helst i rominnstillingene." "Romsynlighet" "Opprett et rom" "Emne (valgfritt)" - "Romkatalog" - "Det oppstod en feil når du prøvde å starte en chat" - "Bli med i rommet med adresse" - "Ikke en gyldig adresse" - "Gå inn…" - "Matchende rom funnet" - "Rom ikke funnet" - "f.eks. #rom-navn:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-nl/translations.xml b/features/createroom/impl/src/main/res/values-nl/translations.xml index 29d070a263..5142148171 100644 --- a/features/createroom/impl/src/main/res/values-nl/translations.xml +++ b/features/createroom/impl/src/main/res/values-nl/translations.xml @@ -16,6 +16,4 @@ Je kunt dit op elk gewenst moment wijzigen in de kamerinstellingen." "Naam van de kamer" "Creëer een kamer" "Onderwerp (optioneel)" - "Kamergids" - "Er is een fout opgetreden bij het starten van een chat" diff --git a/features/createroom/impl/src/main/res/values-pl/translations.xml b/features/createroom/impl/src/main/res/values-pl/translations.xml index 3ed917b7bb..446644b622 100644 --- a/features/createroom/impl/src/main/res/values-pl/translations.xml +++ b/features/createroom/impl/src/main/res/values-pl/translations.xml @@ -19,12 +19,4 @@ Możesz to zmienić w ustawieniach pokoju." "Widoczność pomieszczenia" "Utwórz pokój" "Temat (opcjonalnie)" - "Katalog pokoi" - "Wystąpił błąd podczas próby rozpoczęcia czatu" - "Dołącz do pokoju za pomocą adresu" - "Nieprawidłowy adres" - "Wprowadź…" - "Znaleziono pasujący pokój" - "Nie znaleziono pokoju" - "np. #room-name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-pt-rBR/translations.xml b/features/createroom/impl/src/main/res/values-pt-rBR/translations.xml index 52c9f569af..1b1e9f2d1b 100644 --- a/features/createroom/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/createroom/impl/src/main/res/values-pt-rBR/translations.xml @@ -19,12 +19,4 @@ Você pode mudar isso a qualquer momento nas configurações da sala." "Visibilidade da sala" "Criar uma sala" "Tópico (opcional)" - "Diretório de salas" - "Ocorreu um erro ao tentar iniciar um chat" - "Entrar na sala pelo endereço" - "Não é um endereço válido" - "Entrar…" - "Foi encontrada uma sala correspondente" - "Sala não encontrada" - "Por exemplo, #nome-da-sala:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-pt/translations.xml b/features/createroom/impl/src/main/res/values-pt/translations.xml index 5e5f5fc9c3..1524914bb2 100644 --- a/features/createroom/impl/src/main/res/values-pt/translations.xml +++ b/features/createroom/impl/src/main/res/values-pt/translations.xml @@ -19,12 +19,4 @@ Pode alterar esta opção nas definições da sala." "Visibilidade da sala" "Criar uma sala" "Descrição (opcional)" - "Diretório de salas" - "Ocorreu um erro ao tentar iniciar uma conversa" - "Entrar na sala pelo endereço" - "Não é um endereço válido" - "Entrar…" - "Sala correspondente encontrado" - "Sala não encontrada" - "por exemplo, #sala:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-ro/translations.xml b/features/createroom/impl/src/main/res/values-ro/translations.xml index 8d9e74b530..a5ea4fbb85 100644 --- a/features/createroom/impl/src/main/res/values-ro/translations.xml +++ b/features/createroom/impl/src/main/res/values-ro/translations.xml @@ -17,6 +17,4 @@ Puteți modifica acest lucru oricând în setări." "Numele camerei" "Creați o cameră" "Subiect (opțional)" - "Director de camere" - "A apărut o eroare la încercarea începerii conversației" diff --git a/features/createroom/impl/src/main/res/values-ru/translations.xml b/features/createroom/impl/src/main/res/values-ru/translations.xml index 6344491248..e871673114 100644 --- a/features/createroom/impl/src/main/res/values-ru/translations.xml +++ b/features/createroom/impl/src/main/res/values-ru/translations.xml @@ -19,12 +19,4 @@ "Видимость комнаты" "Создать комнату" "Тема (необязательно)" - "Каталог комнат" - "Произошла ошибка при запуске чата" - "Присоединиться к комнате по адресу" - "Недействительный адрес" - "Ввести…" - "Соответствующая комната найдена" - "Комната не найдена" - "прим. #room-name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-sk/translations.xml b/features/createroom/impl/src/main/res/values-sk/translations.xml index eaf6c2f19c..7b6d89b2e1 100644 --- a/features/createroom/impl/src/main/res/values-sk/translations.xml +++ b/features/createroom/impl/src/main/res/values-sk/translations.xml @@ -19,12 +19,4 @@ Môžete to kedykoľvek zmeniť v nastaveniach miestnosti." "Viditeľnosť miestnosti" "Vytvoriť miestnosť" "Téma (voliteľné)" - "Adresár miestností" - "Pri pokuse o spustenie konverzácie sa vyskytla chyba" - "Pripojte sa do miestnosti podľa adresy" - "Neplatná adresa" - "Zadajte…" - "Nájdená zodpovedajúca miestnosť" - "Miestnosť sa nenašla" - "napr. #nazov-miestnosti:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-sv/translations.xml b/features/createroom/impl/src/main/res/values-sv/translations.xml index 316c9cc32e..8cd01ebd0e 100644 --- a/features/createroom/impl/src/main/res/values-sv/translations.xml +++ b/features/createroom/impl/src/main/res/values-sv/translations.xml @@ -19,12 +19,4 @@ Du kan ändra detta när som helst i rumsinställningarna." "Rumssynlighet" "Skapa ett rum" "Ämne (valfritt)" - "Rumskatalog" - "Ett fel uppstod när du försökte starta en chatt" - "Gå med i rum med adress" - "Inte en giltig adress" - "Ange …" - "Matchande rum hittades" - "Rummet hittades inte" - "t.ex. #rumsnamn:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-tr/translations.xml b/features/createroom/impl/src/main/res/values-tr/translations.xml index c8e3136517..d97139c973 100644 --- a/features/createroom/impl/src/main/res/values-tr/translations.xml +++ b/features/createroom/impl/src/main/res/values-tr/translations.xml @@ -19,6 +19,4 @@ Bunu istediğiniz zaman oda ayarlarından değiştirebilirsiniz." "Oda görünürlüğü" "Bir oda oluştur" "Konu (isteğe bağlı)" - "Oda dizini" - "Sohbet başlatmaya çalışırken bir hata oluştu" diff --git a/features/createroom/impl/src/main/res/values-uk/translations.xml b/features/createroom/impl/src/main/res/values-uk/translations.xml index a43172fb8b..047b4dd9d2 100644 --- a/features/createroom/impl/src/main/res/values-uk/translations.xml +++ b/features/createroom/impl/src/main/res/values-uk/translations.xml @@ -19,12 +19,4 @@ "Видимість кімнати" "Створити кімнату" "Тема (необов\'язково)" - "Каталог кімнат" - "Під час спроби почати бесіду сталася помилка" - "Приєднатися до кімнати за адресою" - "Недійсна адреса" - "Введіть…" - "Знайдено відповідну кімнату" - "Кімната не знайдена" - "наприклад, #room-name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-ur/translations.xml b/features/createroom/impl/src/main/res/values-ur/translations.xml index 6fe476462e..b68992085f 100644 --- a/features/createroom/impl/src/main/res/values-ur/translations.xml +++ b/features/createroom/impl/src/main/res/values-ur/translations.xml @@ -11,6 +11,4 @@ "کمرے کا نام" "ایک کمرہ بنائیں" "موضوع (اختیاری)" - "کمرے کا راہنامچہ" - "گفتگو شروع کرنے کی کوشش کرتے وقت ایک خرابی واقع ہوگئی" diff --git a/features/createroom/impl/src/main/res/values-uz/translations.xml b/features/createroom/impl/src/main/res/values-uz/translations.xml index e3bc9de528..c33e89be28 100644 --- a/features/createroom/impl/src/main/res/values-uz/translations.xml +++ b/features/createroom/impl/src/main/res/values-uz/translations.xml @@ -9,5 +9,4 @@ "Xona nomi" "Xonani yaratish" "Mavzu (ixtiyoriy)" - "Suhbatni boshlashda xatolik yuz berdi" diff --git a/features/createroom/impl/src/main/res/values-zh-rTW/translations.xml b/features/createroom/impl/src/main/res/values-zh-rTW/translations.xml index 0d67c883c7..476f9cff7e 100644 --- a/features/createroom/impl/src/main/res/values-zh-rTW/translations.xml +++ b/features/createroom/impl/src/main/res/values-zh-rTW/translations.xml @@ -19,12 +19,4 @@ "聊天室能見度" "建立聊天室" "主題(非必填)" - "聊天室目錄" - "嘗試開始聊天時發生錯誤" - "按地址加入聊天室" - "不是有效的位址" - "輸入……" - "找到相符的聊天室" - "找不到聊天室" - "例如 #room-name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-zh/translations.xml b/features/createroom/impl/src/main/res/values-zh/translations.xml index 24d7df7f35..d20e34801d 100644 --- a/features/createroom/impl/src/main/res/values-zh/translations.xml +++ b/features/createroom/impl/src/main/res/values-zh/translations.xml @@ -19,6 +19,4 @@ "房间可见性" "创建聊天室" "主题(可选)" - "聊天室目录" - "在开始聊天时发生了错误" diff --git a/features/createroom/impl/src/main/res/values/localazy.xml b/features/createroom/impl/src/main/res/values/localazy.xml index d011a1d87b..fa9a1cb276 100644 --- a/features/createroom/impl/src/main/res/values/localazy.xml +++ b/features/createroom/impl/src/main/res/values/localazy.xml @@ -19,12 +19,4 @@ You can change this anytime in room settings." "Room visibility" "Create a room" "Topic (optional)" - "Room directory" - "An error occurred when trying to start a chat" - "Join room by address" - "Not a valid address" - "Enter…" - "Matching room found" - "Room not found" - "e.g. #room-name:matrix.org" diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeoplePresenterTest.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeoplePresenterTest.kt deleted file mode 100644 index acb381dadc..0000000000 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeoplePresenterTest.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2023, 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.features.createroom.impl.addpeople - -import app.cash.molecule.RecompositionMode -import app.cash.molecule.moleculeFlow -import app.cash.turbine.test -import com.google.common.truth.Truth.assertThat -import io.element.android.features.createroom.impl.CreateRoomDataStore -import io.element.android.features.createroom.impl.userlist.FakeUserListPresenterFactory -import io.element.android.features.createroom.impl.userlist.UserListDataStore -import io.element.android.libraries.matrix.test.room.alias.FakeRoomAliasHelper -import io.element.android.libraries.usersearch.test.FakeUserRepository -import io.element.android.tests.testutils.WarmUpRule -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Rule -import org.junit.Test - -class AddPeoplePresenterTest { - @get:Rule - val warmUpRule = WarmUpRule() - - private lateinit var presenter: AddPeoplePresenter - - @Before - fun setup() { - presenter = AddPeoplePresenter( - FakeUserListPresenterFactory(), - FakeUserRepository(), - CreateRoomDataStore(UserListDataStore(), FakeRoomAliasHelper()) - ) - } - - @Test - fun `present - initial state`() = runTest { - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { - // TODO This doesn't actually test anything... - val initialState = awaitItem() - assertThat(initialState) - } - } -} diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleViewTest.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleViewTest.kt deleted file mode 100644 index c18abf0daa..0000000000 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleViewTest.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.features.createroom.impl.addpeople - -import androidx.activity.ComponentActivity -import androidx.compose.ui.test.junit4.AndroidComposeTestRule -import androidx.compose.ui.test.junit4.createAndroidComposeRule -import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.element.android.features.createroom.impl.userlist.UserListEvents -import io.element.android.features.createroom.impl.userlist.UserListState -import io.element.android.features.createroom.impl.userlist.aUserListState -import io.element.android.libraries.ui.strings.CommonStrings -import io.element.android.tests.testutils.EnsureNeverCalled -import io.element.android.tests.testutils.EventsRecorder -import io.element.android.tests.testutils.clickOn -import io.element.android.tests.testutils.ensureCalledOnce -import io.element.android.tests.testutils.pressBack -import org.junit.Rule -import org.junit.Test -import org.junit.rules.TestRule -import org.junit.runner.RunWith - -@RunWith(AndroidJUnit4::class) -class AddPeopleViewTest { - @get:Rule - val rule = createAndroidComposeRule() - - @Test - fun `clicking on back invokes the expected callback`() { - val eventsRecorder = EventsRecorder() - ensureCalledOnce { - rule.setAddPeopleView( - aUserListState( - eventSink = eventsRecorder, - ), - onBackClick = it - ) - rule.pressBack() - } - eventsRecorder.assertSingle(UserListEvents.UpdateSearchQuery("")) - } - - @Test - fun `clicking on back during search emits the expected Event`() { - val eventsRecorder = EventsRecorder() - rule.setAddPeopleView( - aUserListState( - isSearchActive = true, - eventSink = eventsRecorder, - ), - ) - rule.pressBack() - eventsRecorder.assertSingle(UserListEvents.OnSearchActiveChanged(false)) - } - - @Test - fun `clicking on skip invokes the expected callback`() { - val eventsRecorder = EventsRecorder() - ensureCalledOnce { - rule.setAddPeopleView( - aUserListState( - eventSink = eventsRecorder, - ), - onNextClick = it - ) - rule.clickOn(CommonStrings.action_skip) - } - eventsRecorder.assertSingle(UserListEvents.UpdateSearchQuery("")) - } -} - -private fun AndroidComposeTestRule.setAddPeopleView( - state: UserListState, - onBackClick: () -> Unit = EnsureNeverCalled(), - onNextClick: () -> Unit = EnsureNeverCalled(), -) { - setContent { - AddPeopleView( - state = state, - onBackClick = onBackClick, - onNextClick = onNextClick, - ) - } -} diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureBaseRoomPresenterTest.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterTest.kt similarity index 90% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureBaseRoomPresenterTest.kt rename to features/createroom/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterTest.kt index 8c8ba7ca58..635a2b330e 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureBaseRoomPresenterTest.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterTest.kt @@ -5,15 +5,21 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.configureroom +package io.element.android.features.startchat.impl.configureroom import android.net.Uri import app.cash.turbine.TurbineTestContext import com.google.common.truth.Truth.assertThat import im.vector.app.features.analytics.plan.CreatedRoom -import io.element.android.features.createroom.impl.CreateRoomConfig -import io.element.android.features.createroom.impl.CreateRoomDataStore -import io.element.android.features.createroom.impl.userlist.UserListDataStore +import io.element.android.features.createroom.impl.configureroom.ConfigureRoomEvents +import io.element.android.features.createroom.impl.configureroom.ConfigureRoomPresenter +import io.element.android.features.createroom.impl.configureroom.ConfigureRoomState +import io.element.android.features.createroom.impl.configureroom.CreateRoomConfig +import io.element.android.features.createroom.impl.configureroom.CreateRoomConfigStore +import io.element.android.features.createroom.impl.configureroom.RoomAccess +import io.element.android.features.createroom.impl.configureroom.RoomAddress +import io.element.android.features.createroom.impl.configureroom.RoomVisibilityItem +import io.element.android.features.createroom.impl.configureroom.RoomVisibilityState import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService @@ -28,7 +34,6 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.room.alias.FakeRoomAliasHelper -import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.media.AvatarAction import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity import io.element.android.libraries.mediapickers.api.PickerProvider @@ -48,8 +53,6 @@ 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.advanceUntilIdle import kotlinx.coroutines.test.runTest @@ -67,7 +70,7 @@ private const val AN_URI_FROM_CAMERA_2 = "content://uri_from_camera_2" private const val AN_URI_FROM_GALLERY = "content://uri_from_gallery" @RunWith(RobolectricTestRunner::class) -class ConfigureBaseRoomPresenterTest { +class ConfigureRoomPresenterTest { @get:Rule val warmUpRule = WarmUpRule() @@ -124,12 +127,11 @@ class ConfigureBaseRoomPresenterTest { @Test fun `present - state is updated when fields are changed`() = runTest { - val userListDataStore = UserListDataStore() val pickerProvider = FakePickerProvider() val permissionsPresenter = FakePermissionsPresenter() val roomAliasHelper = FakeRoomAliasHelper() val presenter = createConfigureRoomPresenter( - createRoomDataStore = CreateRoomDataStore(userListDataStore, roomAliasHelper), + dataStore = CreateRoomConfigStore(roomAliasHelper), pickerProvider = pickerProvider, permissionsPresenter = permissionsPresenter, ) @@ -137,20 +139,9 @@ class ConfigureBaseRoomPresenterTest { val initialState = initialState() var expectedConfig = CreateRoomConfig() assertThat(initialState.config).isEqualTo(expectedConfig) - - // Select User - val selectedUser1 = aMatrixUser() - val selectedUser2 = aMatrixUser("@id_of_bob:server.org", "Bob") - userListDataStore.selectUser(selectedUser1) - skipItems(1) - userListDataStore.selectUser(selectedUser2) - var newState = awaitItem() - expectedConfig = expectedConfig.copy(invites = persistentListOf(selectedUser1, selectedUser2)) - assertThat(newState.config).isEqualTo(expectedConfig) - // Room name initialState.eventSink(ConfigureRoomEvents.RoomNameChanged(A_ROOM_NAME)) - newState = awaitItem() + var newState = awaitItem() expectedConfig = expectedConfig.copy(roomName = A_ROOM_NAME) assertThat(newState.config).isEqualTo(expectedConfig) @@ -206,12 +197,6 @@ class ConfigureBaseRoomPresenterTest { ) ) assertThat(newState.config).isEqualTo(expectedConfig) - - // Remove user - newState.eventSink(ConfigureRoomEvents.RemoveUserFromSelection(selectedUser1)) - newState = awaitItem() - expectedConfig = expectedConfig.copy(invites = expectedConfig.invites.minus(selectedUser1).toImmutableList()) - assertThat(newState.config).isEqualTo(expectedConfig) } } @@ -263,16 +248,16 @@ class ConfigureBaseRoomPresenterTest { val matrixClient = createMatrixClient() val analyticsService = FakeAnalyticsService() val mediaPreProcessor = FakeMediaPreProcessor() - val createRoomDataStore = CreateRoomDataStore(UserListDataStore(), FakeRoomAliasHelper()) + val dataStore = CreateRoomConfigStore(FakeRoomAliasHelper()) val presenter = createConfigureRoomPresenter( - createRoomDataStore = createRoomDataStore, + dataStore = dataStore, mediaPreProcessor = mediaPreProcessor, matrixClient = matrixClient, analyticsService = analyticsService ) presenter.test { val initialState = initialState() - createRoomDataStore.setAvatarUri(Uri.parse(AN_URI_FROM_GALLERY)) + dataStore.setAvatarUri(Uri.parse(AN_URI_FROM_GALLERY)) skipItems(1) mediaPreProcessor.givenResult(Result.success(MediaUploadInfo.Image(mockk(), mockk(), mockk()))) matrixClient.givenUploadMediaResult(Result.failure(AN_EXCEPTION)) @@ -405,7 +390,7 @@ class ConfigureBaseRoomPresenterTest { private fun createConfigureRoomPresenter( roomAliasHelper: RoomAliasHelper = FakeRoomAliasHelper(), - createRoomDataStore: CreateRoomDataStore = CreateRoomDataStore(UserListDataStore(), roomAliasHelper), + dataStore: CreateRoomConfigStore = CreateRoomConfigStore(roomAliasHelper), matrixClient: MatrixClient = createMatrixClient(), pickerProvider: PickerProvider = FakePickerProvider(), mediaPreProcessor: MediaPreProcessor = FakeMediaPreProcessor(), @@ -414,7 +399,7 @@ class ConfigureBaseRoomPresenterTest { isKnockFeatureEnabled: Boolean = true, mediaOptimizationConfigProvider: FakeMediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(), ) = ConfigureRoomPresenter( - dataStore = createRoomDataStore, + dataStore = dataStore, matrixClient = matrixClient, mediaPickerProvider = pickerProvider, mediaPreProcessor = mediaPreProcessor, diff --git a/features/home/api/src/main/kotlin/io/element/android/features/home/api/HomeEntryPoint.kt b/features/home/api/src/main/kotlin/io/element/android/features/home/api/HomeEntryPoint.kt index 0f6ee581bb..88b55d4e02 100644 --- a/features/home/api/src/main/kotlin/io/element/android/features/home/api/HomeEntryPoint.kt +++ b/features/home/api/src/main/kotlin/io/element/android/features/home/api/HomeEntryPoint.kt @@ -22,7 +22,7 @@ interface HomeEntryPoint : FeatureEntryPoint { interface Callback : Plugin { fun onRoomClick(roomId: RoomId) - fun onCreateRoomClick() + fun onStartChatClick() fun onSettingsClick() fun onSetUpRecoveryClick() fun onSessionConfirmRecoveryKeyClick() diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeFlowNode.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeFlowNode.kt index 54c58d7387..d08abb6891 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeFlowNode.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeFlowNode.kt @@ -120,8 +120,8 @@ class HomeFlowNode @AssistedInject constructor( plugins().forEach { it.onSettingsClick() } } - private fun onCreateRoomClick() { - plugins().forEach { it.onCreateRoomClick() } + private fun onStartChatClick() { + plugins().forEach { it.onStartChatClick() } } private fun onSetUpRecoveryClick() { @@ -171,7 +171,7 @@ class HomeFlowNode @AssistedInject constructor( homeState = state, onRoomClick = this::onRoomClick, onSettingsClick = this::onOpenSettings, - onCreateRoomClick = this::onCreateRoomClick, + onStartChatClick = this::onStartChatClick, onSetUpRecoveryClick = this::onSetUpRecoveryClick, onConfirmRecoveryKeyClick = this::onSessionConfirmRecoveryKeyClick, onRoomSettingsClick = this::onRoomSettingsClick, diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt index c2ef2e4bc5..c0e999e7f5 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt @@ -72,7 +72,7 @@ fun HomeView( onSettingsClick: () -> Unit, onSetUpRecoveryClick: () -> Unit, onConfirmRecoveryKeyClick: () -> Unit, - onCreateRoomClick: () -> Unit, + onStartChatClick: () -> Unit, onRoomSettingsClick: (roomId: RoomId) -> Unit, onMenuActionClick: (RoomListMenuAction) -> Unit, onReportRoomClick: (roomId: RoomId) -> Unit, @@ -116,7 +116,7 @@ fun HomeView( onConfirmRecoveryKeyClick = onConfirmRecoveryKeyClick, onRoomClick = { if (firstThrottler.canHandle()) onRoomClick(it) }, onOpenSettings = { if (firstThrottler.canHandle()) onSettingsClick() }, - onCreateRoomClick = { if (firstThrottler.canHandle()) onCreateRoomClick() }, + onStartChatClick = { if (firstThrottler.canHandle()) onStartChatClick() }, onMenuActionClick = onMenuActionClick, modifier = Modifier.padding(top = topPadding), ) @@ -145,7 +145,7 @@ private fun HomeScaffold( onConfirmRecoveryKeyClick: () -> Unit, onRoomClick: (RoomId) -> Unit, onOpenSettings: () -> Unit, - onCreateRoomClick: () -> Unit, + onStartChatClick: () -> Unit, onMenuActionClick: (RoomListMenuAction) -> Unit, modifier: Modifier = Modifier, ) { @@ -236,7 +236,7 @@ private fun HomeScaffold( onSetUpRecoveryClick = onSetUpRecoveryClick, onConfirmRecoveryKeyClick = onConfirmRecoveryKeyClick, onRoomClick = ::onRoomClick, - onCreateRoomClick = onCreateRoomClick, + onCreateRoomClick = onStartChatClick, contentPadding = PaddingValues( // FAB height is 56dp, bottom padding is 16dp, we add 8dp as extra margin -> 56+16+8 = 80, // and include provided bottom padding @@ -280,7 +280,7 @@ private fun HomeScaffold( floatingActionButton = { if (state.displayActions) { FloatingActionButton( - onClick = onCreateRoomClick, + onClick = onStartChatClick, ) { Icon( imageVector = CompoundIcons.Plus(), @@ -304,7 +304,7 @@ internal fun HomeViewPreview(@PreviewParameter(HomeStateProvider::class) state: onSettingsClick = {}, onSetUpRecoveryClick = {}, onConfirmRecoveryKeyClick = {}, - onCreateRoomClick = {}, + onStartChatClick = {}, onRoomSettingsClick = {}, onReportRoomClick = {}, onMenuActionClick = {}, diff --git a/features/home/impl/src/main/res/values/localazy.xml b/features/home/impl/src/main/res/values/localazy.xml index 4918260281..e6e09b5e47 100644 --- a/features/home/impl/src/main/res/values/localazy.xml +++ b/features/home/impl/src/main/res/values/localazy.xml @@ -33,6 +33,7 @@ For now, you can deselect filters in order to see your other chats" "Invites" "You don\'t have any pending invites." "Low Priority" + "You don’t have any low priority chats yet" "You can deselect filters in order to see your other chats" "You don’t have chats for this selection" "People" diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListViewTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListViewTest.kt index e29b2cf580..4fcbcd170b 100644 --- a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListViewTest.kt +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListViewTest.kt @@ -284,7 +284,7 @@ private fun AndroidComposeTestRule.setRoomL onSettingsClick = onSettingsClick, onSetUpRecoveryClick = onSetUpRecoveryClick, onConfirmRecoveryKeyClick = onConfirmRecoveryKeyClick, - onCreateRoomClick = onCreateRoomClick, + onStartChatClick = onCreateRoomClick, onRoomSettingsClick = onRoomSettingsClick, onMenuActionClick = onMenuActionClick, onDeclineInviteAndBlockUser = onDeclineInviteAndBlockUser, diff --git a/features/invitepeople/api/build.gradle.kts b/features/invitepeople/api/build.gradle.kts new file mode 100644 index 0000000000..3cbd83724a --- /dev/null +++ b/features/invitepeople/api/build.gradle.kts @@ -0,0 +1,18 @@ +/* + * Copyright 2023, 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ +plugins { + id("io.element.android-compose-library") +} + +android { + namespace = "io.element.android.features.invitepeople.api" +} + +dependencies { + implementation(projects.libraries.architecture) + implementation(projects.libraries.matrix.api) +} diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleEvents.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleEvents.kt new file mode 100644 index 0000000000..0ab097462b --- /dev/null +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleEvents.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.invitepeople.api + +interface InvitePeopleEvents { + data object SendInvites : InvitePeopleEvents + data object CloseSearch : InvitePeopleEvents +} diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt new file mode 100644 index 0000000000..46903bfb18 --- /dev/null +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.invitepeople.api + +import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.room.JoinedRoom + +interface InvitePeoplePresenter : Presenter { + interface Factory { + fun create( + joinedRoom: JoinedRoom?, + roomId: RoomId, + ): InvitePeoplePresenter + } +} diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt new file mode 100644 index 0000000000..30144a11d1 --- /dev/null +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.invitepeople.api + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +interface InvitePeopleRenderer { + @Composable + fun Render( + state: InvitePeopleState, + modifier: Modifier, + ) +} diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt new file mode 100644 index 0000000000..db8b9ffbd2 --- /dev/null +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.invitepeople.api + +interface InvitePeopleState { + val canInvite: Boolean + val isSearchActive: Boolean + val eventSink: (InvitePeopleEvents) -> Unit +} diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleStateProvider.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleStateProvider.kt new file mode 100644 index 0000000000..b69ad7c225 --- /dev/null +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleStateProvider.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.invitepeople.api + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider + +class InvitePeopleStateProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + aPreviewInvitePeopleState(), + aPreviewInvitePeopleState(canInvite = true), + aPreviewInvitePeopleState(isSearchActive = true) + ) +} + +private data class PreviewInvitePeopleState( + override val canInvite: Boolean, + override val isSearchActive: Boolean, + override val eventSink: (InvitePeopleEvents) -> Unit, +) : InvitePeopleState + +private fun aPreviewInvitePeopleState( + canInvite: Boolean = false, + isSearchActive: Boolean = false, + eventSink: (InvitePeopleEvents) -> Unit = {}, +) = PreviewInvitePeopleState( + canInvite = canInvite, + isSearchActive = isSearchActive, + eventSink = eventSink +) diff --git a/features/invitepeople/impl/build.gradle.kts b/features/invitepeople/impl/build.gradle.kts new file mode 100644 index 0000000000..bdb1c6942e --- /dev/null +++ b/features/invitepeople/impl/build.gradle.kts @@ -0,0 +1,53 @@ +import extension.setupAnvil + +/* + * Copyright 2022-2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +plugins { + id("io.element.android-compose-library") + id("kotlin-parcelize") +} + +android { + namespace = "io.element.android.features.invitepeople.impl" + + testOptions { + unitTests { + isIncludeAndroidResources = true + } + } +} + +setupAnvil() + +dependencies { + implementation(projects.libraries.core) + implementation(projects.libraries.architecture) + implementation(projects.libraries.matrix.api) + implementation(projects.libraries.matrixui) + implementation(projects.libraries.designsystem) + implementation(projects.libraries.uiStrings) + implementation(projects.libraries.androidutils) + implementation(projects.libraries.usersearch.impl) + implementation(libs.coil.compose) + implementation(projects.services.apperror.api) + api(projects.features.invitepeople.api) + + testImplementation(libs.test.junit) + testImplementation(libs.test.mockk) + testImplementation(libs.coroutines.test) + testImplementation(libs.molecule.runtime) + testImplementation(libs.test.truth) + testImplementation(libs.test.turbine) + testImplementation(libs.test.robolectric) + testImplementation(projects.libraries.matrix.test) + testImplementation(projects.libraries.usersearch.test) + testImplementation(projects.services.apperror.test) + testImplementation(projects.tests.testutils) + testImplementation(libs.androidx.compose.ui.test.junit) + testReleaseImplementation(libs.androidx.compose.ui.test.manifest) +} diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleEvents.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleEvents.kt new file mode 100644 index 0000000000..984eefbc77 --- /dev/null +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleEvents.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2023, 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.invitepeople.impl + +import io.element.android.features.invitepeople.api.InvitePeopleEvents +import io.element.android.libraries.matrix.api.user.MatrixUser + +sealed interface DefaultInvitePeopleEvents : InvitePeopleEvents { + data class ToggleUser(val user: MatrixUser) : DefaultInvitePeopleEvents + data class UpdateSearchQuery(val query: String) : DefaultInvitePeopleEvents + data class OnSearchActiveChanged(val active: Boolean) : DefaultInvitePeopleEvents +} diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenter.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt similarity index 57% rename from features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenter.kt rename to features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt index ed5d13f70b..8961e1157f 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenter.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt @@ -5,50 +5,88 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.roomdetails.impl.invite +package io.element.android.features.invitepeople.impl import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import io.element.android.features.roomdetails.impl.members.RoomMemberListDataSource +import com.squareup.anvil.annotations.ContributesBinding +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import io.element.android.features.invitepeople.api.InvitePeopleEvents +import io.element.android.features.invitepeople.api.InvitePeoplePresenter +import io.element.android.features.invitepeople.api.InvitePeopleState import io.element.android.libraries.architecture.AsyncData -import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.architecture.map import io.element.android.libraries.architecture.runCatchingUpdatingState import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.designsystem.theme.components.SearchBarResultState +import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.di.annotations.SessionCoroutineScope +import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomMembershipState +import io.element.android.libraries.matrix.api.room.filterMembers import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.usersearch.api.UserRepository +import io.element.android.services.apperror.api.AppErrorStateService import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import javax.inject.Inject -class RoomInviteMembersPresenter @Inject constructor( +class DefaultInvitePeoplePresenter @AssistedInject constructor( + @Assisted private val joinedRoom: JoinedRoom?, + @Assisted private val roomId: RoomId, private val userRepository: UserRepository, - private val roomMemberListDataSource: RoomMemberListDataSource, private val coroutineDispatchers: CoroutineDispatchers, -) : Presenter { + @SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope, + private val appErrorStateService: AppErrorStateService, + private val matrixClient: MatrixClient, +) : InvitePeoplePresenter { + @AssistedFactory + @ContributesBinding(SessionScope::class) + interface Factory : InvitePeoplePresenter.Factory { + override fun create(joinedRoom: JoinedRoom?, roomId: RoomId): DefaultInvitePeoplePresenter + } + @Composable - override fun present(): RoomInviteMembersState { + override fun present(): InvitePeopleState { val roomMembers = remember { mutableStateOf>>(AsyncData.Loading()) } val selectedUsers = remember { mutableStateOf>(persistentListOf()) } val searchResults = remember { mutableStateOf>>(SearchBarResultState.Initial()) } var searchQuery by rememberSaveable { mutableStateOf("") } var searchActive by rememberSaveable { mutableStateOf(false) } val showSearchLoader = rememberSaveable { mutableStateOf(false) } + val room by produceState(if (joinedRoom != null) AsyncData.Success(joinedRoom) else AsyncData.Loading()) { + if (joinedRoom == null) { + val result = matrixClient.getJoinedRoom(roomId) + value = if (result == null) { + AsyncData.Failure(Exception("Room not found")) + } else { + AsyncData.Success(result) + } + } + } - LaunchedEffect(Unit) { - fetchMembers(roomMembers) + LaunchedEffect(room.isSuccess()) { + room.dataOrNull()?.let { + fetchMembers(it, roomMembers) + } } LaunchedEffect(searchQuery, roomMembers) { performSearch( @@ -60,33 +98,61 @@ class RoomInviteMembersPresenter @Inject constructor( ) } - return RoomInviteMembersState( + fun handleEvents(event: InvitePeopleEvents) { + when (event) { + is DefaultInvitePeopleEvents.OnSearchActiveChanged -> { + searchActive = event.active + searchQuery = "" + } + + is DefaultInvitePeopleEvents.UpdateSearchQuery -> { + searchQuery = event.query + } + + is DefaultInvitePeopleEvents.ToggleUser -> { + selectedUsers.toggleUser(event.user) + searchResults.toggleUser(event.user) + } + is InvitePeopleEvents.SendInvites -> { + room.dataOrNull()?.let { + sessionCoroutineScope.sendInvites(it, selectedUsers.value) + } + } + is InvitePeopleEvents.CloseSearch -> { + searchActive = false + searchQuery = "" + } + } + } + + return DefaultInvitePeopleState( + room = room.map { }, canInvite = selectedUsers.value.isNotEmpty(), selectedUsers = selectedUsers.value, searchQuery = searchQuery, isSearchActive = searchActive, searchResults = searchResults.value, showSearchLoader = showSearchLoader.value, - eventSink = { - when (it) { - is RoomInviteMembersEvents.OnSearchActiveChanged -> { - searchActive = it.active - searchQuery = "" - } - - is RoomInviteMembersEvents.UpdateSearchQuery -> { - searchQuery = it.query - } - - is RoomInviteMembersEvents.ToggleUser -> { - selectedUsers.toggleUser(it.user) - searchResults.toggleUser(it.user) - } - } - } + eventSink = ::handleEvents, ) } + private fun CoroutineScope.sendInvites( + room: JoinedRoom, + selectedUsers: List, + ) = launch { + val anyInviteFailed = selectedUsers + .map { room.inviteUserById(it.userId) } + .any { it.isFailure } + + if (anyInviteFailed) { + appErrorStateService.showError( + titleRes = CommonStrings.common_unable_to_invite_title, + bodyRes = CommonStrings.common_unable_to_invite_message, + ) + } + } + @JvmName("toggleUserInSelectedUsers") private fun MutableState>.toggleUser(user: MatrixUser) { value = if (value.contains(user)) { @@ -134,7 +200,7 @@ class RoomInviteMembersPresenter @Inject constructor( val isInvited = existingMembership == RoomMembershipState.INVITE InvitableUser( matrixUser = result.matrixUser, - isSelected = selectedUsers.value.contains(result.matrixUser) || isJoined || isInvited, + isSelected = selectedUsers.value.contains(result.matrixUser), isAlreadyJoined = isJoined, isAlreadyInvited = isInvited, isUnresolved = result.isUnresolved, @@ -144,11 +210,12 @@ class RoomInviteMembersPresenter @Inject constructor( }.launchIn(this) } - private suspend fun fetchMembers(roomMembers: MutableState>>) { + private suspend fun fetchMembers( + room: JoinedRoom, + roomMembers: MutableState>> + ) { suspend { - withContext(coroutineDispatchers.io) { - roomMemberListDataSource.search("").toImmutableList() - } + room.filterMembers("", coroutineDispatchers.io).toImmutableList() }.runCatchingUpdatingState(roomMembers) } } diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleRenderer.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleRenderer.kt new file mode 100644 index 0000000000..8207e75fd5 --- /dev/null +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleRenderer.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.invitepeople.impl + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.features.invitepeople.api.InvitePeopleRenderer +import io.element.android.features.invitepeople.api.InvitePeopleState +import io.element.android.libraries.di.SessionScope +import javax.inject.Inject + +@ContributesBinding(SessionScope::class) +class DefaultInvitePeopleRenderer @Inject constructor() : InvitePeopleRenderer { + @Composable + override fun Render(state: InvitePeopleState, modifier: Modifier) { + if (state is DefaultInvitePeopleState) { + InvitePeopleView( + state = state, + modifier = modifier + ) + } else { + error("Unsupported state type: ${state::javaClass}") + } + } +} diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersState.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt similarity index 51% rename from features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersState.kt rename to features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt index c7927247ef..77ba8aad05 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersState.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt @@ -1,30 +1,26 @@ /* - * Copyright 2023, 2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.roomdetails.impl.invite +package io.element.android.features.invitepeople.impl +import io.element.android.features.invitepeople.api.InvitePeopleEvents +import io.element.android.features.invitepeople.api.InvitePeopleState +import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.user.MatrixUser import kotlinx.collections.immutable.ImmutableList -data class RoomInviteMembersState( - val canInvite: Boolean, +data class DefaultInvitePeopleState( + val room: AsyncData, + override val canInvite: Boolean, val searchQuery: String, val showSearchLoader: Boolean, val searchResults: SearchBarResultState>, val selectedUsers: ImmutableList, - val isSearchActive: Boolean, - val eventSink: (RoomInviteMembersEvents) -> Unit, -) - -data class InvitableUser( - val matrixUser: MatrixUser, - val isSelected: Boolean = false, - val isAlreadyJoined: Boolean = false, - val isAlreadyInvited: Boolean = false, - val isUnresolved: Boolean = false, -) + override val isSearchActive: Boolean, + override val eventSink: (InvitePeopleEvents) -> Unit +) : InvitePeopleState diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersStateProvider.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt similarity index 50% rename from features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersStateProvider.kt rename to features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt index 7675880f37..980d32e7fb 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersStateProvider.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt @@ -5,9 +5,10 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.roomdetails.impl.invite +package io.element.android.features.invitepeople.impl import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUser @@ -16,15 +17,15 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList -internal class RoomInviteMembersStateProvider : PreviewParameterProvider { - override val values: Sequence +internal class DefaultInvitePeopleStateProvider : PreviewParameterProvider { + override val values: Sequence get() = sequenceOf( - aRoomInviteMembersState(), - aRoomInviteMembersState(canInvite = true, selectedUsers = aMatrixUserList().toImmutableList()), - aRoomInviteMembersState(isSearchActive = true, searchQuery = "some query"), - aRoomInviteMembersState(isSearchActive = true, searchQuery = "some query", selectedUsers = aMatrixUserList().toImmutableList()), - aRoomInviteMembersState(isSearchActive = true, searchQuery = "some query", searchResults = SearchBarResultState.NoResultsFound()), - aRoomInviteMembersState( + aDefaultInvitePeopleState(), + aDefaultInvitePeopleState(canInvite = true, selectedUsers = aMatrixUserList().toImmutableList()), + aDefaultInvitePeopleState(isSearchActive = true, searchQuery = "some query"), + aDefaultInvitePeopleState(isSearchActive = true, searchQuery = "some query", selectedUsers = aMatrixUserList().toImmutableList()), + aDefaultInvitePeopleState(isSearchActive = true, searchQuery = "some query", searchResults = SearchBarResultState.NoResultsFound()), + aDefaultInvitePeopleState( isSearchActive = true, canInvite = true, searchQuery = "some query", @@ -33,15 +34,15 @@ internal class RoomInviteMembersStateProvider : PreviewParameterProvider = AsyncData.Success(Unit), canInvite: Boolean = false, searchQuery: String = "", searchResults: SearchBarResultState> = SearchBarResultState.Initial(), selectedUsers: ImmutableList = persistentListOf(), isSearchActive: Boolean = false, showSearchLoader: Boolean = false, -): RoomInviteMembersState { - return RoomInviteMembersState( +): DefaultInvitePeopleState { + return DefaultInvitePeopleState( + room = room, canInvite = canInvite, searchQuery = searchQuery, searchResults = searchResults, diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitableUser.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitableUser.kt new file mode 100644 index 0000000000..7dfd6a0f36 --- /dev/null +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitableUser.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.invitepeople.impl + +import io.element.android.libraries.matrix.api.user.MatrixUser + +data class InvitableUser( + val matrixUser: MatrixUser, + val isSelected: Boolean, + val isAlreadyJoined: Boolean, + val isAlreadyInvited: Boolean, + val isUnresolved: Boolean, +) diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt new file mode 100644 index 0000000000..f2382fb170 --- /dev/null +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt @@ -0,0 +1,210 @@ +/* + * Copyright 2023, 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.invitepeople.impl + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.unit.dp +import io.element.android.compound.theme.ElementTheme +import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.designsystem.components.async.AsyncFailure +import io.element.android.libraries.designsystem.components.async.AsyncLoading +import io.element.android.libraries.designsystem.components.avatar.AvatarSize +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.components.HorizontalDivider +import io.element.android.libraries.designsystem.theme.components.SearchBar +import io.element.android.libraries.designsystem.theme.components.SearchBarResultState +import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.matrix.ui.components.CheckableUserRow +import io.element.android.libraries.matrix.ui.components.CheckableUserRowData +import io.element.android.libraries.matrix.ui.components.SelectedUsersRowList +import io.element.android.libraries.matrix.ui.model.getAvatarData +import io.element.android.libraries.matrix.ui.model.getBestName +import io.element.android.libraries.ui.strings.CommonStrings +import kotlinx.collections.immutable.ImmutableList + +@Composable +fun InvitePeopleView( + state: DefaultInvitePeopleState, + modifier: Modifier = Modifier, +) { + when (state.room) { + is AsyncData.Failure -> InvitePeopleViewError(state.room.error, modifier) + AsyncData.Uninitialized, + is AsyncData.Loading, + is AsyncData.Success -> InvitePeopleContentView(state, modifier) + } +} + +@Composable +private fun InvitePeopleViewError( + error: Throwable, + modifier: Modifier = Modifier, +) { + Box( + modifier = modifier.fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + AsyncFailure( + throwable = error, + onRetry = null, + modifier = Modifier.padding(horizontal = 16.dp), + ) + } +} + +@Composable +private fun InvitePeopleContentView( + state: DefaultInvitePeopleState, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier.fillMaxSize(), + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + InvitePeopleSearchBar( + modifier = Modifier.fillMaxWidth(), + query = state.searchQuery, + showLoader = state.showSearchLoader, + selectedUsers = state.selectedUsers, + state = state.searchResults, + active = state.isSearchActive, + onActiveChange = { + state.eventSink( + DefaultInvitePeopleEvents.OnSearchActiveChanged( + it + ) + ) + }, + onTextChange = { state.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery(it)) }, + onToggleUser = { state.eventSink(DefaultInvitePeopleEvents.ToggleUser(it)) }, + ) + + if (!state.isSearchActive) { + SelectedUsersRowList( + modifier = Modifier.fillMaxWidth(), + selectedUsers = state.selectedUsers, + autoScroll = true, + onUserRemove = { state.eventSink(DefaultInvitePeopleEvents.ToggleUser(it)) }, + contentPadding = PaddingValues(16.dp), + ) + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun InvitePeopleSearchBar( + query: String, + state: SearchBarResultState>, + showLoader: Boolean, + selectedUsers: ImmutableList, + active: Boolean, + onActiveChange: (Boolean) -> Unit, + onTextChange: (String) -> Unit, + onToggleUser: (MatrixUser) -> Unit, + modifier: Modifier = Modifier, + placeHolderTitle: String = stringResource(CommonStrings.common_search_for_someone), +) { + SearchBar( + query = query, + onQueryChange = onTextChange, + active = active, + onActiveChange = onActiveChange, + modifier = modifier, + placeHolderTitle = placeHolderTitle, + contentPrefix = { + if (selectedUsers.isNotEmpty()) { + SelectedUsersRowList( + modifier = Modifier.fillMaxWidth(), + selectedUsers = selectedUsers, + autoScroll = true, + onUserRemove = onToggleUser, + contentPadding = PaddingValues(16.dp), + ) + } + }, + showBackButton = false, + resultState = state, + contentSuffix = { + if (showLoader) { + AsyncLoading() + } + }, + resultHandler = { results -> + Text( + text = stringResource(id = CommonStrings.common_search_results), + style = ElementTheme.typography.fontBodyLgMedium, + modifier = Modifier + .fillMaxWidth() + .padding(start = 16.dp, top = 12.dp, end = 16.dp, bottom = 8.dp) + ) + + LazyColumn { + itemsIndexed(results) { index, invitableUser -> + val invitedOrJoined = invitableUser.isAlreadyInvited || invitableUser.isAlreadyJoined + val isUnresolved = invitableUser.isUnresolved && !invitedOrJoined + val enabled = isUnresolved || !invitedOrJoined + val data = if (isUnresolved) { + CheckableUserRowData.Unresolved( + avatarData = invitableUser.matrixUser.getAvatarData(AvatarSize.UserListItem), + id = invitableUser.matrixUser.userId.value, + ) + } else { + CheckableUserRowData.Resolved( + avatarData = invitableUser.matrixUser.getAvatarData(AvatarSize.UserListItem), + name = invitableUser.matrixUser.getBestName(), + subtext = when { + // If they're already invited or joined we show that information + invitableUser.isAlreadyJoined -> stringResource(R.string.screen_invite_users_already_a_member) + invitableUser.isAlreadyInvited -> stringResource(R.string.screen_invite_users_already_invited) + // Otherwise show the ID, unless that's already used for their name + invitableUser.matrixUser.displayName.isNullOrEmpty() + .not() -> invitableUser.matrixUser.userId.value + else -> null + } + ) + } + CheckableUserRow( + checked = invitableUser.isSelected || invitedOrJoined, + enabled = enabled, + data = data, + onCheckedChange = { onToggleUser(invitableUser.matrixUser) }, + modifier = Modifier.fillMaxWidth() + ) + + if (index < results.lastIndex) { + HorizontalDivider() + } + } + } + }, + ) +} + +@PreviewsDayNight +@Composable +internal fun InvitePeopleViewPreview(@PreviewParameter(DefaultInvitePeopleStateProvider::class) state: DefaultInvitePeopleState) = + ElementPreview { + InvitePeopleView(state = state) + } diff --git a/features/invitepeople/impl/src/main/res/values-be/translations.xml b/features/invitepeople/impl/src/main/res/values-be/translations.xml new file mode 100644 index 0000000000..7125d8b2e6 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-be/translations.xml @@ -0,0 +1,5 @@ + + + "Ужо ўдзельнік" + "Ужо запрасілі" + diff --git a/features/invitepeople/impl/src/main/res/values-bg/translations.xml b/features/invitepeople/impl/src/main/res/values-bg/translations.xml new file mode 100644 index 0000000000..f585980920 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-bg/translations.xml @@ -0,0 +1,5 @@ + + + "Вече е член" + "Вече е бил поканен" + diff --git a/features/invitepeople/impl/src/main/res/values-cs/translations.xml b/features/invitepeople/impl/src/main/res/values-cs/translations.xml new file mode 100644 index 0000000000..fa5b3aa9a9 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-cs/translations.xml @@ -0,0 +1,5 @@ + + + "Již členem" + "Již pozván(a)" + diff --git a/features/invitepeople/impl/src/main/res/values-cy/translations.xml b/features/invitepeople/impl/src/main/res/values-cy/translations.xml new file mode 100644 index 0000000000..c58df3c541 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-cy/translations.xml @@ -0,0 +1,5 @@ + + + "Eisoes yn aelod" + "Wedi gwahodd yn barod" + diff --git a/features/invitepeople/impl/src/main/res/values-da/translations.xml b/features/invitepeople/impl/src/main/res/values-da/translations.xml new file mode 100644 index 0000000000..fbb1814e9f --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-da/translations.xml @@ -0,0 +1,5 @@ + + + "Allerede medlem" + "Allerede inviteret" + diff --git a/features/invitepeople/impl/src/main/res/values-de/translations.xml b/features/invitepeople/impl/src/main/res/values-de/translations.xml new file mode 100644 index 0000000000..182d9f289a --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-de/translations.xml @@ -0,0 +1,5 @@ + + + "Bereits Mitglied" + "Bereits eingeladen" + diff --git a/features/invitepeople/impl/src/main/res/values-el/translations.xml b/features/invitepeople/impl/src/main/res/values-el/translations.xml new file mode 100644 index 0000000000..3e3c1fd5d2 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-el/translations.xml @@ -0,0 +1,5 @@ + + + "Ήδη μέλος" + "Ήδη προσκεκλημένος" + diff --git a/features/invitepeople/impl/src/main/res/values-es/translations.xml b/features/invitepeople/impl/src/main/res/values-es/translations.xml new file mode 100644 index 0000000000..e62bb211e5 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-es/translations.xml @@ -0,0 +1,5 @@ + + + "Ya eres miembro" + "Ya estás invitado" + diff --git a/features/invitepeople/impl/src/main/res/values-et/translations.xml b/features/invitepeople/impl/src/main/res/values-et/translations.xml new file mode 100644 index 0000000000..44484d23c3 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-et/translations.xml @@ -0,0 +1,5 @@ + + + "Sa juba oled jututoa liige" + "Sa juba oled kutse saanud" + diff --git a/features/invitepeople/impl/src/main/res/values-eu/translations.xml b/features/invitepeople/impl/src/main/res/values-eu/translations.xml new file mode 100644 index 0000000000..a6aedd89cd --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-eu/translations.xml @@ -0,0 +1,5 @@ + + + "Kidea da dagoeneko" + "Lehendik ere gonbidatuta" + diff --git a/features/invitepeople/impl/src/main/res/values-fa/translations.xml b/features/invitepeople/impl/src/main/res/values-fa/translations.xml new file mode 100644 index 0000000000..544f01b8c8 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-fa/translations.xml @@ -0,0 +1,5 @@ + + + "از پیش عضو است" + "از پیش دعوت شده" + diff --git a/features/invitepeople/impl/src/main/res/values-fi/translations.xml b/features/invitepeople/impl/src/main/res/values-fi/translations.xml new file mode 100644 index 0000000000..e347919719 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-fi/translations.xml @@ -0,0 +1,5 @@ + + + "On jo jäsen" + "On jo kutsuttu" + diff --git a/features/invitepeople/impl/src/main/res/values-fr/translations.xml b/features/invitepeople/impl/src/main/res/values-fr/translations.xml new file mode 100644 index 0000000000..dcc16f58cf --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-fr/translations.xml @@ -0,0 +1,5 @@ + + + "Déjà membre" + "Déjà invité(e)" + diff --git a/features/invitepeople/impl/src/main/res/values-hu/translations.xml b/features/invitepeople/impl/src/main/res/values-hu/translations.xml new file mode 100644 index 0000000000..16f35b018c --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-hu/translations.xml @@ -0,0 +1,5 @@ + + + "Már tag" + "Már meghívták" + diff --git a/features/invitepeople/impl/src/main/res/values-in/translations.xml b/features/invitepeople/impl/src/main/res/values-in/translations.xml new file mode 100644 index 0000000000..e112033a06 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-in/translations.xml @@ -0,0 +1,5 @@ + + + "Sudah menjadi anggota" + "Sudah diundang" + diff --git a/features/invitepeople/impl/src/main/res/values-it/translations.xml b/features/invitepeople/impl/src/main/res/values-it/translations.xml new file mode 100644 index 0000000000..979e42de1b --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-it/translations.xml @@ -0,0 +1,5 @@ + + + "Già membro" + "Già invitato" + diff --git a/features/invitepeople/impl/src/main/res/values-ka/translations.xml b/features/invitepeople/impl/src/main/res/values-ka/translations.xml new file mode 100644 index 0000000000..3a34c2edac --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-ka/translations.xml @@ -0,0 +1,5 @@ + + + "უკვე წევრია" + "უკვე მოწვეულია" + diff --git a/features/invitepeople/impl/src/main/res/values-lt/translations.xml b/features/invitepeople/impl/src/main/res/values-lt/translations.xml new file mode 100644 index 0000000000..59c15290a1 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-lt/translations.xml @@ -0,0 +1,5 @@ + + + "Jau narys" + "Jau pakviestas" + diff --git a/features/invitepeople/impl/src/main/res/values-nb/translations.xml b/features/invitepeople/impl/src/main/res/values-nb/translations.xml new file mode 100644 index 0000000000..617b9271d5 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-nb/translations.xml @@ -0,0 +1,5 @@ + + + "Allerede medlem" + "Allerede invitert" + diff --git a/features/invitepeople/impl/src/main/res/values-nl/translations.xml b/features/invitepeople/impl/src/main/res/values-nl/translations.xml new file mode 100644 index 0000000000..b978dcd9cc --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-nl/translations.xml @@ -0,0 +1,5 @@ + + + "Reeds lid" + "Reeds uitgenodigd" + diff --git a/features/invitepeople/impl/src/main/res/values-pl/translations.xml b/features/invitepeople/impl/src/main/res/values-pl/translations.xml new file mode 100644 index 0000000000..bfd537bb4b --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-pl/translations.xml @@ -0,0 +1,5 @@ + + + "Jest już członkiem" + "Już zaproszony" + diff --git a/features/invitepeople/impl/src/main/res/values-pt-rBR/translations.xml b/features/invitepeople/impl/src/main/res/values-pt-rBR/translations.xml new file mode 100644 index 0000000000..7ad049843b --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-pt-rBR/translations.xml @@ -0,0 +1,5 @@ + + + "Já é membro" + "Já foi convidado" + diff --git a/features/invitepeople/impl/src/main/res/values-pt/translations.xml b/features/invitepeople/impl/src/main/res/values-pt/translations.xml new file mode 100644 index 0000000000..a953d11f67 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-pt/translations.xml @@ -0,0 +1,5 @@ + + + "Já é participante" + "Já foi convidado" + diff --git a/features/invitepeople/impl/src/main/res/values-ro/translations.xml b/features/invitepeople/impl/src/main/res/values-ro/translations.xml new file mode 100644 index 0000000000..f03be4b263 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-ro/translations.xml @@ -0,0 +1,5 @@ + + + "Deja membru" + "Deja invitat" + diff --git a/features/invitepeople/impl/src/main/res/values-ru/translations.xml b/features/invitepeople/impl/src/main/res/values-ru/translations.xml new file mode 100644 index 0000000000..0ae8eb792c --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-ru/translations.xml @@ -0,0 +1,5 @@ + + + "Уже зарегистрирован" + "Уже приглашены" + diff --git a/features/invitepeople/impl/src/main/res/values-sk/translations.xml b/features/invitepeople/impl/src/main/res/values-sk/translations.xml new file mode 100644 index 0000000000..68e34b0ada --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-sk/translations.xml @@ -0,0 +1,5 @@ + + + "Už ste členom" + "Už ste pozvaní" + diff --git a/features/invitepeople/impl/src/main/res/values-sv/translations.xml b/features/invitepeople/impl/src/main/res/values-sv/translations.xml new file mode 100644 index 0000000000..fd670c9c1a --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-sv/translations.xml @@ -0,0 +1,5 @@ + + + "Redan medlem" + "Redan inbjuden" + diff --git a/features/invitepeople/impl/src/main/res/values-tr/translations.xml b/features/invitepeople/impl/src/main/res/values-tr/translations.xml new file mode 100644 index 0000000000..427a7f3f10 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-tr/translations.xml @@ -0,0 +1,5 @@ + + + "Zaten üye" + "Zaten davet edildi" + diff --git a/features/invitepeople/impl/src/main/res/values-uk/translations.xml b/features/invitepeople/impl/src/main/res/values-uk/translations.xml new file mode 100644 index 0000000000..da3ac9fe5b --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-uk/translations.xml @@ -0,0 +1,5 @@ + + + "Уже учасник" + "Уже запрошені" + diff --git a/features/invitepeople/impl/src/main/res/values-ur/translations.xml b/features/invitepeople/impl/src/main/res/values-ur/translations.xml new file mode 100644 index 0000000000..06e8cee414 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-ur/translations.xml @@ -0,0 +1,5 @@ + + + "پہلے سے ہی رکن" + "پہلے سے مدعو شدہ" + diff --git a/features/invitepeople/impl/src/main/res/values-uz/translations.xml b/features/invitepeople/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..445a62d318 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,5 @@ + + + "Allaqachon a\'zo" + "Allaqachon taklif qilingan" + diff --git a/features/invitepeople/impl/src/main/res/values-zh-rTW/translations.xml b/features/invitepeople/impl/src/main/res/values-zh-rTW/translations.xml new file mode 100644 index 0000000000..c8117ec283 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-zh-rTW/translations.xml @@ -0,0 +1,5 @@ + + + "已是成員" + "已邀請" + diff --git a/features/invitepeople/impl/src/main/res/values-zh/translations.xml b/features/invitepeople/impl/src/main/res/values-zh/translations.xml new file mode 100644 index 0000000000..b1e0e953f8 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-zh/translations.xml @@ -0,0 +1,5 @@ + + + "已经是成员" + "已邀请" + diff --git a/features/invitepeople/impl/src/main/res/values/localazy.xml b/features/invitepeople/impl/src/main/res/values/localazy.xml new file mode 100644 index 0000000000..d89ae92e75 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values/localazy.xml @@ -0,0 +1,5 @@ + + + "Already a member" + "Already invited" + diff --git a/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt b/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt new file mode 100644 index 0000000000..1e438fab8e --- /dev/null +++ b/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt @@ -0,0 +1,547 @@ +/* + * Copyright 2023, 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.invitepeople.impl + +import app.cash.turbine.ReceiveTurbine +import com.google.common.truth.Truth.assertThat +import io.element.android.features.invitepeople.api.InvitePeopleEvents +import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.designsystem.theme.components.SearchBarResultState +import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.room.RoomMembersState +import io.element.android.libraries.matrix.api.room.RoomMembershipState +import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.matrix.test.AN_EXCEPTION +import io.element.android.libraries.matrix.test.A_ROOM_ID +import io.element.android.libraries.matrix.test.A_USER_ID +import io.element.android.libraries.matrix.test.A_USER_ID_2 +import io.element.android.libraries.matrix.test.FakeMatrixClient +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom +import io.element.android.libraries.matrix.test.room.aRoomMember +import io.element.android.libraries.matrix.test.room.aRoomMemberList +import io.element.android.libraries.matrix.ui.components.aMatrixUser +import io.element.android.libraries.matrix.ui.components.aMatrixUserList +import io.element.android.libraries.ui.strings.CommonStrings +import io.element.android.libraries.usersearch.api.UserRepository +import io.element.android.libraries.usersearch.api.UserSearchResult +import io.element.android.libraries.usersearch.api.UserSearchResultState +import io.element.android.libraries.usersearch.test.FakeUserRepository +import io.element.android.services.apperror.api.AppErrorStateService +import io.element.android.services.apperror.test.FakeAppErrorStateService +import io.element.android.tests.testutils.WarmUpRule +import io.element.android.tests.testutils.lambda.lambdaError +import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.lambda.value +import io.element.android.tests.testutils.test +import io.element.android.tests.testutils.testCoroutineDispatchers +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.coroutines.delay +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest +import org.junit.Rule +import org.junit.Test + +internal class DefaultInvitePeoplePresenterTest { + @get:Rule + val warmUpRule = WarmUpRule() + + @Test + fun `present - initial state has no results and no search`() = runTest { + val presenter = createDefaultInvitePeoplePresenter() + presenter.test { + val initialState = awaitItemAsDefault() + assertThat(initialState.room).isEqualTo(AsyncData.Success(Unit)) + assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) + assertThat(initialState.isSearchActive).isFalse() + assertThat(initialState.canInvite).isFalse() + assertThat(initialState.searchQuery).isEmpty() + + skipItems(1) + } + } + + @Test + fun `present - updates search active state`() = runTest { + val presenter = createDefaultInvitePeoplePresenter() + presenter.test { + val initialState = awaitItem() + skipItems(1) + + initialState.eventSink(DefaultInvitePeopleEvents.OnSearchActiveChanged(true)) + + val resultState = awaitItem() + assertThat(resultState.isSearchActive).isTrue() + resultState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query")) + assertThat(awaitItemAsDefault().searchQuery).isEqualTo("some query") + resultState.eventSink(InvitePeopleEvents.CloseSearch) + skipItems(1) + awaitItemAsDefault().also { + assertThat(it.isSearchActive).isFalse() + assertThat(it.searchQuery).isEmpty() + } + } + } + + @Test + fun `present - performs search and handles empty result list`() = runTest { + val repository = FakeUserRepository() + val presenter = createDefaultInvitePeoplePresenter( + userRepository = repository, + coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) + ) + presenter.test { + val initialState = awaitItem() + initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query")) + assertThat(repository.providedQuery).isEqualTo("some query") + repository.emitState(UserSearchResultState(results = emptyList(), isSearching = true)) + skipItems(3) + awaitItemAsDefault().also { state -> + assertThat(state.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) + assertThat(state.showSearchLoader).isTrue() + } + repository.emitState(results = emptyList(), isSearching = false) + awaitItemAsDefault().also { state -> + assertThat(state.searchResults).isInstanceOf(SearchBarResultState.NoResultsFound::class.java) + assertThat(state.showSearchLoader).isFalse() + } + } + } + + @Test + fun `present - performs search and handles user results`() = runTest { + val repository = FakeUserRepository() + val presenter = createDefaultInvitePeoplePresenter( + userRepository = repository, + coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) + ) + presenter.test { + val initialState = awaitItem() + skipItems(1) + + initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query")) + skipItems(1) + + assertThat(repository.providedQuery).isEqualTo("some query") + repository.emitStateWithUsers(users = aMatrixUserList()) + skipItems(1) + + val resultState = awaitItemAsDefault() + assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) + + val expectedUsers = aMatrixUserList() + val users = resultState.searchResults.users() + expectedUsers.forEachIndexed { index, matrixUser -> + assertThat(users[index].matrixUser).isEqualTo(matrixUser) + // All users are joined or invited + if (users[index].isAlreadyInvited) { + assertThat(users[index].isAlreadyJoined).isFalse() + } else { + assertThat(users[index].isAlreadyJoined).isTrue() + } + assertThat(users[index].isSelected).isFalse() + } + } + } + + @Test + fun `present - performs search and handles membership state of existing users`() = runTest { + val userList = aMatrixUserList() + val joinedUser = userList[0] + val invitedUser = userList[1] + + val repository = FakeUserRepository() + val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) + val presenter = createDefaultInvitePeoplePresenter( + userRepository = repository, + roomMembersState = RoomMembersState.Ready( + persistentListOf( + aRoomMember( + userId = joinedUser.userId, + membership = RoomMembershipState.JOIN + ), + aRoomMember( + userId = invitedUser.userId, + membership = RoomMembershipState.INVITE + ), + ) + ), + coroutineDispatchers = coroutineDispatchers, + ) + presenter.test { + val initialState = awaitItem() + skipItems(1) + + initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query")) + skipItems(1) + + assertThat(repository.providedQuery).isEqualTo("some query") + repository.emitStateWithUsers(users = aMatrixUserList()) + skipItems(1) + + val resultState = awaitItemAsDefault() + assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) + + val users = resultState.searchResults.users() + + // The result that matches a user with JOINED membership is marked as such + val userWhoShouldBeJoined = users.find { it.matrixUser == joinedUser } + assertThat(userWhoShouldBeJoined).isNotNull() + assertThat(userWhoShouldBeJoined?.isAlreadyJoined).isTrue() + assertThat(userWhoShouldBeJoined?.isAlreadyInvited).isFalse() + + // The result that matches a user with INVITED membership is marked as such + val userWhoShouldBeInvited = users.find { it.matrixUser == invitedUser } + assertThat(userWhoShouldBeInvited).isNotNull() + assertThat(userWhoShouldBeInvited?.isAlreadyJoined).isFalse() + assertThat(userWhoShouldBeInvited?.isAlreadyInvited).isTrue() + + // All other users are neither joined nor invited + val otherUsers = users.minus(userWhoShouldBeInvited!!).minus(userWhoShouldBeJoined!!) + assertThat(otherUsers.none { it.isAlreadyInvited }).isTrue() + assertThat(otherUsers.none { it.isAlreadyJoined }).isTrue() + } + } + + @Test + fun `present - performs search and handles unresolved results`() = runTest { + val userList = aMatrixUserList() + val joinedUser = userList[0] + val invitedUser = userList[1] + + val repository = FakeUserRepository() + val presenter = createDefaultInvitePeoplePresenter( + userRepository = repository, + roomMembersState = + RoomMembersState.Ready( + persistentListOf( + aRoomMember( + userId = joinedUser.userId, + membership = RoomMembershipState.JOIN + ), + aRoomMember( + userId = invitedUser.userId, + membership = RoomMembershipState.INVITE + ), + ) + ), + coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) + ) + + presenter.test { + val initialState = awaitItem() + skipItems(1) + + initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query")) + skipItems(1) + + assertThat(repository.providedQuery).isEqualTo("some query") + + val unresolvedUser = + UserSearchResult(aMatrixUser(id = A_USER_ID.value), isUnresolved = true) + repository.emitState(listOf(unresolvedUser) + aMatrixUserList().map { + UserSearchResult( + it + ) + }) + skipItems(1) + + val resultState = awaitItemAsDefault() + assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) + + val users = resultState.searchResults.users() + + val userWhoShouldBeUnresolved = users.first() + assertThat(userWhoShouldBeUnresolved.isUnresolved).isTrue() + + // All other users are neither joined nor invited + val otherUsers = users.minus(userWhoShouldBeUnresolved) + assertThat(otherUsers.none { it.isUnresolved }).isTrue() + } + } + + @Test + fun `present - toggle users updates selected user state`() = runTest { + val repository = FakeUserRepository() + val presenter = createDefaultInvitePeoplePresenter( + userRepository = repository, + coroutineDispatchers = testCoroutineDispatchers() + ) + presenter.test { + val initialState = awaitItem() + skipItems(1) + + // When we toggle a user not in the list, they are added + initialState.eventSink(DefaultInvitePeopleEvents.ToggleUser(aMatrixUser())) + assertThat(awaitItemAsDefault().selectedUsers).containsExactly(aMatrixUser()) + + // Toggling a different user also adds them + initialState.eventSink(DefaultInvitePeopleEvents.ToggleUser(aMatrixUser(id = A_USER_ID_2.value))) + assertThat(awaitItemAsDefault().selectedUsers).containsExactly( + aMatrixUser(), + aMatrixUser(id = A_USER_ID_2.value) + ) + + // Toggling the first user removes them + initialState.eventSink(DefaultInvitePeopleEvents.ToggleUser(aMatrixUser())) + assertThat(awaitItemAsDefault().selectedUsers).containsExactly(aMatrixUser(id = A_USER_ID_2.value)) + } + } + + @Test + fun `present - selected users appear as such in search results`() = runTest { + val repository = FakeUserRepository() + val presenter = createDefaultInvitePeoplePresenter( + userRepository = repository, + coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) + ) + presenter.test { + val initialState = awaitItem() + skipItems(1) + + val selectedUser = aMatrixUser() + + initialState.eventSink(DefaultInvitePeopleEvents.ToggleUser(selectedUser)) + + initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query")) + skipItems(1) + + assertThat(repository.providedQuery).isEqualTo("some query") + repository.emitStateWithUsers(users = aMatrixUserList() + selectedUser) + skipItems(2) + + val resultState = awaitItemAsDefault() + assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) + + val users = resultState.searchResults.users() + + // The one user we have previously toggled is marked as selected + val shouldBeSelectedUser = users.find { it.matrixUser == selectedUser } + assertThat(shouldBeSelectedUser).isNotNull() + assertThat(shouldBeSelectedUser?.isSelected).isTrue() + + // And no others are + val allOtherUsers = users.minus(shouldBeSelectedUser!!) + assertThat(allOtherUsers.none { it.isSelected }).isTrue() + } + } + + @Test + fun `present - toggling a user updates existing search results`() = runTest { + val repository = FakeUserRepository() + val presenter = createDefaultInvitePeoplePresenter( + userRepository = repository, + coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) + ) + presenter.test { + val initialState = awaitItem() + skipItems(1) + + val selectedUser = aMatrixUser() + + // Given a query is made + initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query")) + skipItems(1) + + assertThat(repository.providedQuery).isEqualTo("some query") + repository.emitStateWithUsers(users = aMatrixUserList() + selectedUser) + skipItems(1) + awaitItemAsDefault().also { state -> + // selectedUser is not selected + assertThat(state.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) + val users = state.searchResults.users() + val shouldNotBeSelectedUser = users.find { it.matrixUser == selectedUser } + assertThat(shouldNotBeSelectedUser).isNotNull() + assertThat(shouldNotBeSelectedUser?.isSelected).isFalse() + } + + // And then a user is toggled + initialState.eventSink(DefaultInvitePeopleEvents.ToggleUser(selectedUser)) + skipItems(1) + val resultState = awaitItemAsDefault() + + // The results are updated... + assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) + val users = resultState.searchResults.users() + + // The one user we have now toggled is marked as selected + val shouldBeSelectedUser = users.find { it.matrixUser == selectedUser } + assertThat(shouldBeSelectedUser).isNotNull() + assertThat(shouldBeSelectedUser?.isSelected).isTrue() + + // And no others are + val allOtherUsers = users.minus(shouldBeSelectedUser!!) + assertThat(allOtherUsers.none { it.isSelected }).isTrue() + } + } + + @Test + fun `present - toggling a user and send invite success`() = runTest { + val repository = FakeUserRepository() + val inviteUserResult = lambdaRecorder> { userId: UserId -> + Result.success(Unit) + } + val presenter = createDefaultInvitePeoplePresenter( + userRepository = repository, + inviteUserResult = inviteUserResult, + coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) + ) + presenter.test { + val initialState = awaitItem() + skipItems(1) + val selectedUser = aMatrixUser() + repository.emitStateWithUsers(users = aMatrixUserList() + selectedUser) + skipItems(1) + // And then a user is toggled + initialState.eventSink(DefaultInvitePeopleEvents.ToggleUser(selectedUser)) + skipItems(1) + val resultState = awaitItemAsDefault() + // The results are updated... + assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) + // Send invites + initialState.eventSink(InvitePeopleEvents.SendInvites) + delay(1_000) + inviteUserResult.assertions().isCalledOnce().with( + value(selectedUser.userId) + ) + } + } + + @Test + fun `present - toggling a user and send invite error`() = runTest { + val repository = FakeUserRepository() + val inviteUserResult = lambdaRecorder> { _: UserId -> + Result.failure(AN_EXCEPTION) + } + val showErrorResResult = lambdaRecorder { _, _ -> } + val presenter = createDefaultInvitePeoplePresenter( + userRepository = repository, + inviteUserResult = inviteUserResult, + coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true), + appErrorStateService = FakeAppErrorStateService( + showErrorResResult = showErrorResResult, + ) + ) + presenter.test { + val initialState = awaitItem() + skipItems(1) + val selectedUser = aMatrixUser() + repository.emitStateWithUsers(users = aMatrixUserList() + selectedUser) + skipItems(1) + // And then a user is toggled + initialState.eventSink(DefaultInvitePeopleEvents.ToggleUser(selectedUser)) + skipItems(1) + val resultState = awaitItemAsDefault() + // The results are updated... + assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) + // Send invites + initialState.eventSink(InvitePeopleEvents.SendInvites) + delay(1_000) + inviteUserResult.assertions().isCalledOnce().with( + value(selectedUser.userId) + ) + showErrorResResult.assertions() + .isCalledOnce() + .with( + value(CommonStrings.common_unable_to_invite_title), + value(CommonStrings.common_unable_to_invite_message) + ) + } + } + + @Test + fun `present - when joinedRoom is not provided, it is retrieved on the MatrixClient`() = runTest { + val matrixClient = FakeMatrixClient().apply { + givenGetRoomResult(A_ROOM_ID, FakeJoinedRoom()) + } + val presenter = createDefaultInvitePeoplePresenter( + joinedRoom = null, + roomId = A_ROOM_ID, + matrixClient = matrixClient, + ) + presenter.test { + val initialState = awaitItemAsDefault() + assertThat(initialState.room.isLoading()).isTrue() + val finalState = awaitItemAsDefault() + assertThat(finalState.room).isEqualTo(AsyncData.Success(Unit)) + } + } + + @Test + fun `present - when joinedRoom is not provided, it is retrieved on the MatrixClient - error case`() = runTest { + val matrixClient = FakeMatrixClient() + val presenter = createDefaultInvitePeoplePresenter( + joinedRoom = null, + roomId = A_ROOM_ID, + matrixClient = matrixClient, + ) + presenter.test { + val initialState = awaitItemAsDefault() + assertThat(initialState.room.isLoading()).isTrue() + val finalState = awaitItemAsDefault() + assertThat(finalState.room.errorOrNull()?.message).isEqualTo("Room not found") + } + } + + private suspend fun FakeUserRepository.emitStateWithUsers( + users: List, + isSearching: Boolean = false + ) { + emitState( + results = users.map { UserSearchResult(it) }, + isSearching = isSearching, + ) + } + + private suspend fun FakeUserRepository.emitState( + results: List, + isSearching: Boolean = false + ) { + val state = UserSearchResultState( + results = results, + isSearching = isSearching + ) + emitState(state) + } + + private fun SearchBarResultState>.users() = + (this as? SearchBarResultState.Results>)?.results.orEmpty() +} + +private suspend fun ReceiveTurbine.awaitItemAsDefault(): DefaultInvitePeopleState { + return awaitItem() as DefaultInvitePeopleState +} + +fun TestScope.createDefaultInvitePeoplePresenter( + roomMembersState: RoomMembersState = RoomMembersState.Ready(aRoomMemberList()), + inviteUserResult: (UserId) -> Result = { lambdaError() }, + joinedRoom: JoinedRoom? = FakeJoinedRoom( + inviteUserResult = inviteUserResult, + ).apply { + givenRoomMembersState(roomMembersState) + }, + roomId: RoomId = A_ROOM_ID, + userRepository: UserRepository = FakeUserRepository(), + coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(), + appErrorStateService: AppErrorStateService = FakeAppErrorStateService(), + matrixClient: MatrixClient = FakeMatrixClient(), +): DefaultInvitePeoplePresenter { + return DefaultInvitePeoplePresenter( + joinedRoom = joinedRoom, + roomId = roomId, + userRepository = userRepository, + coroutineDispatchers = coroutineDispatchers, + sessionCoroutineScope = backgroundScope, + appErrorStateService = appErrorStateService, + matrixClient = matrixClient, + ) +} diff --git a/features/roomdetails/impl/build.gradle.kts b/features/roomdetails/impl/build.gradle.kts index ad45eda8fc..302ae7d8c6 100644 --- a/features/roomdetails/impl/build.gradle.kts +++ b/features/roomdetails/impl/build.gradle.kts @@ -44,7 +44,7 @@ dependencies { api(projects.services.apperror.api) implementation(libs.coil.compose) implementation(projects.features.call.api) - implementation(projects.features.createroom.api) + implementation(projects.features.startchat.api) implementation(projects.features.leaveroom.api) implementation(projects.features.userprofile.shared) implementation(projects.services.analytics.compose) @@ -56,6 +56,7 @@ dependencies { implementation(projects.features.reportroom.api) implementation(projects.features.roommembermoderation.api) implementation(projects.features.changeroommemberroles.api) + implementation(projects.features.invitepeople.api) testImplementation(libs.test.junit) testImplementation(libs.coroutines.test) @@ -72,7 +73,7 @@ dependencies { testImplementation(projects.libraries.usersearch.test) testImplementation(projects.libraries.featureflag.test) testImplementation(projects.tests.testutils) - testImplementation(projects.features.createroom.test) + testImplementation(projects.features.startchat.test) testImplementation(projects.services.analytics.test) testImplementation(libs.androidx.compose.ui.test.junit) testReleaseImplementation(libs.androidx.compose.ui.test.manifest) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersEvents.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersEvents.kt deleted file mode 100644 index a06ae82c49..0000000000 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersEvents.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2023, 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.features.roomdetails.impl.invite - -import io.element.android.libraries.matrix.api.user.MatrixUser - -sealed interface RoomInviteMembersEvents { - data class ToggleUser(val user: MatrixUser) : RoomInviteMembersEvents - data class UpdateSearchQuery(val query: String) : RoomInviteMembersEvents - data class OnSearchActiveChanged(val active: Boolean) : RoomInviteMembersEvents -} diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersNode.kt index ebfa3dcab8..dc269e7322 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersNode.kt @@ -9,7 +9,6 @@ package io.element.android.features.roomdetails.impl.invite import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import com.bumble.appyx.core.lifecycle.subscribe import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node @@ -18,28 +17,21 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.anvilannotations.ContributesNode -import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.features.invitepeople.api.InvitePeoplePresenter +import io.element.android.features.invitepeople.api.InvitePeopleRenderer import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.room.JoinedRoom -import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.services.analytics.api.AnalyticsService -import io.element.android.services.apperror.api.AppErrorStateService -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.launch @ContributesNode(RoomScope::class) class RoomInviteMembersNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, - coroutineDispatchers: CoroutineDispatchers, - private val room: JoinedRoom, - private val presenter: RoomInviteMembersPresenter, - private val appErrorStateService: AppErrorStateService, private val analyticsService: AnalyticsService, + private val invitePeopleRenderer: InvitePeopleRenderer, + room: JoinedRoom, + invitePeoplePresenterFactory: InvitePeoplePresenter.Factory, ) : Node(buildContext, plugins = plugins) { - private val coroutineScope = CoroutineScope(SupervisorJob() + coroutineDispatchers.io) - init { lifecycle.subscribe( onResume = { @@ -48,31 +40,21 @@ class RoomInviteMembersNode @AssistedInject constructor( ) } + private val invitePeoplePresenter = invitePeoplePresenterFactory.create( + joinedRoom = room, + roomId = room.roomId, + ) + @Composable override fun View(modifier: Modifier) { - val state = presenter.present() - val context = LocalContext.current.applicationContext - + val state = invitePeoplePresenter.present() RoomInviteMembersView( state = state, modifier = modifier, onBackClick = { navigateUp() }, - onSubmitClick = { users -> - navigateUp() - - coroutineScope.launch { - val anyInviteFailed = users - .map { room.inviteUserById(it.userId) } - .any { it.isFailure } - - if (anyInviteFailed) { - appErrorStateService.showError( - title = context.getString(CommonStrings.common_unable_to_invite_title), - body = context.getString(CommonStrings.common_unable_to_invite_message), - ) - } - } - } - ) + onDone = { navigateUp() } + ) { + invitePeopleRenderer.Render(state, Modifier) + } } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt index caae6ff16d..8bec90707f 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt @@ -7,49 +7,34 @@ package io.element.android.features.roomdetails.impl.invite -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.unit.dp -import io.element.android.compound.theme.ElementTheme +import io.element.android.features.invitepeople.api.InvitePeopleEvents +import io.element.android.features.invitepeople.api.InvitePeopleState +import io.element.android.features.invitepeople.api.InvitePeopleStateProvider import io.element.android.features.roomdetails.impl.R -import io.element.android.libraries.designsystem.components.async.AsyncLoading -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.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight -import io.element.android.libraries.designsystem.theme.components.HorizontalDivider 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.SearchBarResultState -import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.designsystem.theme.components.TopAppBar -import io.element.android.libraries.matrix.api.user.MatrixUser -import io.element.android.libraries.matrix.ui.components.CheckableUserRow -import io.element.android.libraries.matrix.ui.components.CheckableUserRowData -import io.element.android.libraries.matrix.ui.components.SelectedUsersRowList -import io.element.android.libraries.matrix.ui.model.getAvatarData -import io.element.android.libraries.matrix.ui.model.getBestName import io.element.android.libraries.ui.strings.CommonStrings -import kotlinx.collections.immutable.ImmutableList @Composable fun RoomInviteMembersView( - state: RoomInviteMembersState, + state: InvitePeopleState, onBackClick: () -> Unit, - onSubmitClick: (List) -> Unit, + onDone: () -> Unit, modifier: Modifier = Modifier, + invitePeopleView: @Composable () -> Unit, ) { Scaffold( modifier = modifier, @@ -57,44 +42,26 @@ fun RoomInviteMembersView( RoomInviteMembersTopBar( onBackClick = { if (state.isSearchActive) { - state.eventSink(RoomInviteMembersEvents.OnSearchActiveChanged(false)) + state.eventSink(InvitePeopleEvents.CloseSearch) } else { onBackClick() } }, - onSubmitClick = { onSubmitClick(state.selectedUsers) }, + onSubmitClick = { + state.eventSink(InvitePeopleEvents.SendInvites) + onDone() + }, canSend = state.canInvite, ) } ) { padding -> - Column( + Box( modifier = Modifier .fillMaxWidth() .padding(padding) .consumeWindowInsets(padding), - verticalArrangement = Arrangement.spacedBy(16.dp), ) { - RoomInviteMembersSearchBar( - modifier = Modifier.fillMaxWidth(), - query = state.searchQuery, - showLoader = state.showSearchLoader, - selectedUsers = state.selectedUsers, - state = state.searchResults, - active = state.isSearchActive, - onActiveChange = { state.eventSink(RoomInviteMembersEvents.OnSearchActiveChanged(it)) }, - onTextChange = { state.eventSink(RoomInviteMembersEvents.UpdateSearchQuery(it)) }, - onToggleUser = { state.eventSink(RoomInviteMembersEvents.ToggleUser(it)) }, - ) - - if (!state.isSearchActive) { - SelectedUsersRowList( - modifier = Modifier.fillMaxWidth(), - selectedUsers = state.selectedUsers, - autoScroll = true, - onUserRemove = { state.eventSink(RoomInviteMembersEvents.ToggleUser(it)) }, - contentPadding = PaddingValues(16.dp), - ) - } + invitePeopleView() } } } @@ -119,101 +86,13 @@ private fun RoomInviteMembersTopBar( ) } -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun RoomInviteMembersSearchBar( - query: String, - state: SearchBarResultState>, - showLoader: Boolean, - selectedUsers: ImmutableList, - active: Boolean, - onActiveChange: (Boolean) -> Unit, - onTextChange: (String) -> Unit, - onToggleUser: (MatrixUser) -> Unit, - modifier: Modifier = Modifier, - placeHolderTitle: String = stringResource(CommonStrings.common_search_for_someone), -) { - SearchBar( - query = query, - onQueryChange = onTextChange, - active = active, - onActiveChange = onActiveChange, - modifier = modifier, - placeHolderTitle = placeHolderTitle, - contentPrefix = { - if (selectedUsers.isNotEmpty()) { - SelectedUsersRowList( - modifier = Modifier.fillMaxWidth(), - selectedUsers = selectedUsers, - autoScroll = true, - onUserRemove = onToggleUser, - contentPadding = PaddingValues(16.dp), - ) - } - }, - showBackButton = false, - resultState = state, - contentSuffix = { - if (showLoader) { - AsyncLoading() - } - }, - resultHandler = { results -> - Text( - text = stringResource(id = CommonStrings.common_search_results), - style = ElementTheme.typography.fontBodyLgMedium, - modifier = Modifier - .fillMaxWidth() - .padding(start = 16.dp, top = 12.dp, end = 16.dp, bottom = 8.dp) - ) - - LazyColumn { - itemsIndexed(results) { index, invitableUser -> - val notInvitedOrJoined = !(invitableUser.isAlreadyInvited || invitableUser.isAlreadyJoined) - val isUnresolved = invitableUser.isUnresolved && notInvitedOrJoined - val enabled = isUnresolved || notInvitedOrJoined - val data = if (isUnresolved) { - CheckableUserRowData.Unresolved( - avatarData = invitableUser.matrixUser.getAvatarData(AvatarSize.UserListItem), - id = invitableUser.matrixUser.userId.value, - ) - } else { - CheckableUserRowData.Resolved( - avatarData = invitableUser.matrixUser.getAvatarData(AvatarSize.UserListItem), - name = invitableUser.matrixUser.getBestName(), - subtext = when { - // If they're already invited or joined we show that information - invitableUser.isAlreadyJoined -> stringResource(R.string.screen_room_details_already_a_member) - invitableUser.isAlreadyInvited -> stringResource(R.string.screen_room_details_already_invited) - // Otherwise show the ID, unless that's already used for their name - invitableUser.matrixUser.displayName.isNullOrEmpty().not() -> invitableUser.matrixUser.userId.value - else -> null - } - ) - } - CheckableUserRow( - checked = invitableUser.isSelected, - enabled = enabled, - data = data, - onCheckedChange = { onToggleUser(invitableUser.matrixUser) }, - modifier = Modifier.fillMaxWidth() - ) - - if (index < results.lastIndex) { - HorizontalDivider() - } - } - } - }, - ) -} - @PreviewsDayNight @Composable -internal fun RoomInviteMembersViewPreview(@PreviewParameter(RoomInviteMembersStateProvider::class) state: RoomInviteMembersState) = ElementPreview { +internal fun RoomInviteMembersViewPreview(@PreviewParameter(InvitePeopleStateProvider::class) state: InvitePeopleState) = ElementPreview { RoomInviteMembersView( state = state, + invitePeopleView = {}, onBackClick = {}, - onSubmitClick = {}, + onDone = {}, ) } diff --git a/features/roomdetails/impl/src/main/res/values-be/translations.xml b/features/roomdetails/impl/src/main/res/values-be/translations.xml index d50b3c5f6e..01c076fdb5 100644 --- a/features/roomdetails/impl/src/main/res/values-be/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-be/translations.xml @@ -33,8 +33,6 @@ "У вас ёсць незахаваныя змены." "Захаваць змены?" "Дадаць тэму" - "Ужо ўдзельнік" - "Ужо запрасілі" "Зашыфраваны" "Не зашыфраваны" "Публічны пакой" diff --git a/features/roomdetails/impl/src/main/res/values-bg/translations.xml b/features/roomdetails/impl/src/main/res/values-bg/translations.xml index 6f9c256742..fb01acb4fb 100644 --- a/features/roomdetails/impl/src/main/res/values-bg/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-bg/translations.xml @@ -22,8 +22,6 @@ "Модератори" "Членове" "Добавяне на тема" - "Вече е член" - "Вече е бил поканен" "С шифроване" "Без шифроване" "Общодостъпна стая" diff --git a/features/roomdetails/impl/src/main/res/values-cs/translations.xml b/features/roomdetails/impl/src/main/res/values-cs/translations.xml index 3bd037b1c0..d484486940 100644 --- a/features/roomdetails/impl/src/main/res/values-cs/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-cs/translations.xml @@ -35,8 +35,6 @@ "Máte neuložené změny." "Uložit změny?" "Přidat téma" - "Již členem" - "Již pozván(a)" "Šifrováno" "Není šifrováno" "Veřejná místnost" diff --git a/features/roomdetails/impl/src/main/res/values-cy/translations.xml b/features/roomdetails/impl/src/main/res/values-cy/translations.xml index ab0a8fa95d..80726aa1f8 100644 --- a/features/roomdetails/impl/src/main/res/values-cy/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-cy/translations.xml @@ -35,8 +35,6 @@ "Mae gennych newidiadau heb eu cadw." "Cadw\'r newidiadau?" "Ychwanegu pwnc" - "Eisoes yn aelod" - "Wedi gwahodd yn barod" "Wedi\'i amgryptio" "Heb ei amgryptio" "Ystafell gyhoeddus" diff --git a/features/roomdetails/impl/src/main/res/values-da/translations.xml b/features/roomdetails/impl/src/main/res/values-da/translations.xml index e989977145..a07d86be77 100644 --- a/features/roomdetails/impl/src/main/res/values-da/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-da/translations.xml @@ -39,8 +39,6 @@ "Du har ændringer, der ikke er gemt." "Gem ændringer?" "Tilføj emne" - "Allerede medlem" - "Allerede inviteret" "Krypteret" "Ikke krypteret" "Offentligt rum" diff --git a/features/roomdetails/impl/src/main/res/values-de/translations.xml b/features/roomdetails/impl/src/main/res/values-de/translations.xml index 2a2673beb1..714d36c38a 100644 --- a/features/roomdetails/impl/src/main/res/values-de/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-de/translations.xml @@ -35,8 +35,6 @@ "Sie haben ungespeicherte Änderungen." "Änderungen speichern?" "Thema hinzufügen" - "Bereits Mitglied" - "Bereits eingeladen" "Verschlüsselt" "Nicht verschlüsselt" "Öffentlicher Raum" diff --git a/features/roomdetails/impl/src/main/res/values-el/translations.xml b/features/roomdetails/impl/src/main/res/values-el/translations.xml index aed10ce24f..678dad15c9 100644 --- a/features/roomdetails/impl/src/main/res/values-el/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-el/translations.xml @@ -35,8 +35,6 @@ "Έχεις μη αποθηκευμένες αλλαγές." "Αποθήκευση αλλαγών;" "Προσθήκη θέματος" - "Ήδη μέλος" - "Ήδη προσκεκλημένος" "Κρυπτογραφημένο" "Μη κρυπτογραφημένο" "Δημόσια αίθουσα" diff --git a/features/roomdetails/impl/src/main/res/values-es/translations.xml b/features/roomdetails/impl/src/main/res/values-es/translations.xml index ffce0a6b76..96e31eb5c5 100644 --- a/features/roomdetails/impl/src/main/res/values-es/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-es/translations.xml @@ -35,8 +35,6 @@ "Tienes cambios sin guardar." "¿Guardar cambios?" "Añadir tema" - "Ya eres miembro" - "Ya estás invitado" "Cifrada" "No cifrada" "Sala pública" diff --git a/features/roomdetails/impl/src/main/res/values-et/translations.xml b/features/roomdetails/impl/src/main/res/values-et/translations.xml index efc6ee8e6d..98b0f3ee63 100644 --- a/features/roomdetails/impl/src/main/res/values-et/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-et/translations.xml @@ -39,8 +39,6 @@ "Sul on salvestamata muudatusi" "Kas salvestame muudatused?" "Lisa teema" - "Sa juba oled jututoa liige" - "Sa juba oled kutse saanud" "Krüptitud jututuba" "Krüptimata jututuba" "Avalik jututuba" diff --git a/features/roomdetails/impl/src/main/res/values-eu/translations.xml b/features/roomdetails/impl/src/main/res/values-eu/translations.xml index bd2a370942..4eb246d36f 100644 --- a/features/roomdetails/impl/src/main/res/values-eu/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-eu/translations.xml @@ -33,8 +33,6 @@ "Gorde gabeko aldaketak dituzu." "Aldaketak gorde?" "Gehitu hizketagaia" - "Kidea da dagoeneko" - "Lehendik ere gonbidatuta" "Zifratuta" "Zifratu gabe" "Gela publikoa" diff --git a/features/roomdetails/impl/src/main/res/values-fa/translations.xml b/features/roomdetails/impl/src/main/res/values-fa/translations.xml index 7941f60609..3f0c9b949e 100644 --- a/features/roomdetails/impl/src/main/res/values-fa/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-fa/translations.xml @@ -34,8 +34,6 @@ "تغییراتی ذخیره نشده دارید." "ذخیرهٔ تغییرات؟" "افزودن موضوع" - "از پیش عضو است" - "از پیش دعوت شده" "رمز شده" "رمزنگاری نشده" "اتاق عمومی" diff --git a/features/roomdetails/impl/src/main/res/values-fi/translations.xml b/features/roomdetails/impl/src/main/res/values-fi/translations.xml index 5906bd5986..04c1411e50 100644 --- a/features/roomdetails/impl/src/main/res/values-fi/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-fi/translations.xml @@ -39,8 +39,6 @@ "Sinulla on tallentamattomia muutoksia" "Tallenna muutokset?" "Lisää aihe" - "On jo jäsen" - "On jo kutsuttu" "Salattu" "Ei salattu" "Julkinen huone" diff --git a/features/roomdetails/impl/src/main/res/values-fr/translations.xml b/features/roomdetails/impl/src/main/res/values-fr/translations.xml index f5b876c9f7..066ce1ee0f 100644 --- a/features/roomdetails/impl/src/main/res/values-fr/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-fr/translations.xml @@ -39,8 +39,6 @@ "Vous avez des modifications non-enregistrées." "Enregistrer les changements ?" "Ajouter un sujet" - "Déjà membre" - "Déjà invité(e)" "Chiffré" "Non chiffré" "Salon public" diff --git a/features/roomdetails/impl/src/main/res/values-hu/translations.xml b/features/roomdetails/impl/src/main/res/values-hu/translations.xml index dfe25cf712..6e2484fc68 100644 --- a/features/roomdetails/impl/src/main/res/values-hu/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-hu/translations.xml @@ -39,8 +39,6 @@ "Mentetlen módosításai vannak." "Menti a módosításokat?" "Téma hozzáadása" - "Már tag" - "Már meghívták" "Titkosított" "Nem titkosított" "Nyilvános szoba" diff --git a/features/roomdetails/impl/src/main/res/values-in/translations.xml b/features/roomdetails/impl/src/main/res/values-in/translations.xml index 2143418fb0..49f44eb985 100644 --- a/features/roomdetails/impl/src/main/res/values-in/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-in/translations.xml @@ -35,8 +35,6 @@ "Anda memiliki perubahan yang belum disimpan." "Simpan perubahan?" "Tambahkan topik" - "Sudah menjadi anggota" - "Sudah diundang" "Terenkripsi" "Tidak terenkripsi" "Ruangan publik" diff --git a/features/roomdetails/impl/src/main/res/values-it/translations.xml b/features/roomdetails/impl/src/main/res/values-it/translations.xml index 54de5f5407..988a2edafd 100644 --- a/features/roomdetails/impl/src/main/res/values-it/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-it/translations.xml @@ -35,8 +35,6 @@ "Hai delle modifiche non salvate." "Salvare le modifiche?" "Aggiungi argomento" - "Già membro" - "Già invitato" "Cifrata" "Non cifrata" "Stanza pubblica" diff --git a/features/roomdetails/impl/src/main/res/values-ka/translations.xml b/features/roomdetails/impl/src/main/res/values-ka/translations.xml index 6a68985d87..1beb70d4dd 100644 --- a/features/roomdetails/impl/src/main/res/values-ka/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-ka/translations.xml @@ -32,8 +32,6 @@ "თქვენ გაქვთ შეუნახავი ცვლილებები" "შენახვა?" "თემის დამატება" - "უკვე წევრია" - "უკვე მოწვეულია" "ოთახის რედაქტირება" "უცნობი შეცდომა მოხდა. ინფორმაციის შეცვლა ვერ მოხერხდა." "ოთახის განახლება შეუძლებელია" diff --git a/features/roomdetails/impl/src/main/res/values-lt/translations.xml b/features/roomdetails/impl/src/main/res/values-lt/translations.xml index 18a908b2c0..1b3b44fdf2 100644 --- a/features/roomdetails/impl/src/main/res/values-lt/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-lt/translations.xml @@ -1,8 +1,6 @@ "Pridėti temą" - "Jau narys" - "Jau pakviestas" "Redaguoti kambarį" "Įvyko nežinoma klaida ir informacijos pakeisti nepavyko." "Nepavyko atnaujinti kambario" diff --git a/features/roomdetails/impl/src/main/res/values-nb/translations.xml b/features/roomdetails/impl/src/main/res/values-nb/translations.xml index a8f5d8d123..f964f142b5 100644 --- a/features/roomdetails/impl/src/main/res/values-nb/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-nb/translations.xml @@ -35,8 +35,6 @@ "Du har endringer som ikke er lagret." "Lagre endringer?" "Legg til emne" - "Allerede medlem" - "Allerede invitert" "Kryptert" "Ikke kryptert" "Offentlig rom" diff --git a/features/roomdetails/impl/src/main/res/values-nl/translations.xml b/features/roomdetails/impl/src/main/res/values-nl/translations.xml index 2b190fc4db..9b932f60fe 100644 --- a/features/roomdetails/impl/src/main/res/values-nl/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-nl/translations.xml @@ -33,8 +33,6 @@ "Je hebt niet-opgeslagen wijzigingen" "Wijzigingen opslaan?" "Onderwerp toevoegen" - "Reeds lid" - "Reeds uitgenodigd" "Versleuteld" "Niet versleuteld" "Openbare kamer" diff --git a/features/roomdetails/impl/src/main/res/values-pl/translations.xml b/features/roomdetails/impl/src/main/res/values-pl/translations.xml index c708ac220a..b9847c6cfd 100644 --- a/features/roomdetails/impl/src/main/res/values-pl/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-pl/translations.xml @@ -39,8 +39,6 @@ "Masz niezapisane zmiany." "Zapisać zmiany?" "Dodaj temat" - "Jest już członkiem" - "Już zaproszony" "Szyfrowany" "Nieszyfrowany" "Pokój publiczny" diff --git a/features/roomdetails/impl/src/main/res/values-pt-rBR/translations.xml b/features/roomdetails/impl/src/main/res/values-pt-rBR/translations.xml index 5561005e9b..bfe0b44af2 100644 --- a/features/roomdetails/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-pt-rBR/translations.xml @@ -35,8 +35,6 @@ "Você tem alterações não salvas." "Salvar alterações?" "Adicionar tópico" - "Já é membro" - "Já foi convidado" "Criptografado" "Não criptografado" "Sala pública" diff --git a/features/roomdetails/impl/src/main/res/values-pt/translations.xml b/features/roomdetails/impl/src/main/res/values-pt/translations.xml index 32d1bb8fc8..cba9ab5ac1 100644 --- a/features/roomdetails/impl/src/main/res/values-pt/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-pt/translations.xml @@ -39,8 +39,6 @@ "Tens alterações por guardar." "Guardar alterações?" "Adicionar descrição" - "Já é participante" - "Já foi convidado" "Cifrada" "Não cifrada" "Sala pública" diff --git a/features/roomdetails/impl/src/main/res/values-ro/translations.xml b/features/roomdetails/impl/src/main/res/values-ro/translations.xml index 622278dc64..b901be078e 100644 --- a/features/roomdetails/impl/src/main/res/values-ro/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-ro/translations.xml @@ -33,8 +33,6 @@ "Aveți modificări nesalvate." "Salvați modificările?" "Adăugare subiect" - "Deja membru" - "Deja invitat" "Criptat" "Necriptat" "Cameră publică" diff --git a/features/roomdetails/impl/src/main/res/values-ru/translations.xml b/features/roomdetails/impl/src/main/res/values-ru/translations.xml index 77d0b94eb3..e4c53ff30d 100644 --- a/features/roomdetails/impl/src/main/res/values-ru/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-ru/translations.xml @@ -35,8 +35,6 @@ "У вас есть несохраненные изменения." "Сохранить изменения?" "Добавить тему" - "Уже зарегистрирован" - "Уже приглашены" "Зашифровано" "Шифрования нет" "Общедоступная комната" diff --git a/features/roomdetails/impl/src/main/res/values-sk/translations.xml b/features/roomdetails/impl/src/main/res/values-sk/translations.xml index b8e9e0c30a..530455cbf2 100644 --- a/features/roomdetails/impl/src/main/res/values-sk/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-sk/translations.xml @@ -39,8 +39,6 @@ "Máte neuložené zmeny." "Uložiť zmeny?" "Pridať tému" - "Už ste členom" - "Už ste pozvaní" "Zašifrované" "Nešifrované" "Verejná miestnosť" diff --git a/features/roomdetails/impl/src/main/res/values-sv/translations.xml b/features/roomdetails/impl/src/main/res/values-sv/translations.xml index 12cec6d6ee..a3a9d4f144 100644 --- a/features/roomdetails/impl/src/main/res/values-sv/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-sv/translations.xml @@ -35,8 +35,6 @@ "Du har osparade ändringar." "Spara ändringar?" "Lägg till ämne" - "Redan medlem" - "Redan inbjuden" "Krypterat" "Inte krypterat" "Offentligt rum" diff --git a/features/roomdetails/impl/src/main/res/values-tr/translations.xml b/features/roomdetails/impl/src/main/res/values-tr/translations.xml index 67a8845821..92caaaf5eb 100644 --- a/features/roomdetails/impl/src/main/res/values-tr/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-tr/translations.xml @@ -35,8 +35,6 @@ "Kaydedilmemiş değişiklikleriniz var." "Değişiklikleri Kaydet?" "Konu ekle" - "Zaten üye" - "Zaten davet edildi" "Şifrelenmiş" "Şifrelenmemiş" "Herkese açık oda" diff --git a/features/roomdetails/impl/src/main/res/values-uk/translations.xml b/features/roomdetails/impl/src/main/res/values-uk/translations.xml index b3cac2e00a..7ef99d8430 100644 --- a/features/roomdetails/impl/src/main/res/values-uk/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-uk/translations.xml @@ -39,8 +39,6 @@ "У вас є не збережені зміни." "Зберегти зміни?" "Додати тему" - "Уже учасник" - "Уже запрошені" "Зашифровано" "Не зашифровано" "Загальнодоступна кімната" diff --git a/features/roomdetails/impl/src/main/res/values-ur/translations.xml b/features/roomdetails/impl/src/main/res/values-ur/translations.xml index 00c90107ac..12a8d964cb 100644 --- a/features/roomdetails/impl/src/main/res/values-ur/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-ur/translations.xml @@ -33,8 +33,6 @@ "آپکے پاس غیر محفوظ تبدیلیاں ہیں" "تبدیلیاں محفوظ کریں؟" "موضوع شامل کریں" - "پہلے سے ہی رکن" - "پہلے سے مدعو شدہ" "مرموز کردہ" "رموز کردہ نہیں" "عوامی کمرہ" diff --git a/features/roomdetails/impl/src/main/res/values-uz/translations.xml b/features/roomdetails/impl/src/main/res/values-uz/translations.xml index 030e0a91bd..e3d9418b43 100644 --- a/features/roomdetails/impl/src/main/res/values-uz/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-uz/translations.xml @@ -3,8 +3,6 @@ "Bildirishnoma sozlamalarini yangilashda xatolik yuz berdi." "Har kim" "Mavzu qo\'shish" - "Allaqachon a\'zo" - "Allaqachon taklif qilingan" "Xonani tahrirlash" "Nomaʼlum xatolik yuz berdi va maʼlumotni oʻzgartirib boʻlmadi." "Xonani yangilab bo‘lmadi" diff --git a/features/roomdetails/impl/src/main/res/values-zh-rTW/translations.xml b/features/roomdetails/impl/src/main/res/values-zh-rTW/translations.xml index ac32c3597b..5efcc0438a 100644 --- a/features/roomdetails/impl/src/main/res/values-zh-rTW/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-zh-rTW/translations.xml @@ -35,8 +35,6 @@ "您有尚未儲存的變更" "是否儲存變更?" "新增主題" - "已是成員" - "已邀請" "已加密" "未加密" "公開的聊天室" diff --git a/features/roomdetails/impl/src/main/res/values-zh/translations.xml b/features/roomdetails/impl/src/main/res/values-zh/translations.xml index 367741e4ef..7d5a9e330c 100644 --- a/features/roomdetails/impl/src/main/res/values-zh/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-zh/translations.xml @@ -35,8 +35,6 @@ "您有未保存的更改。" "保存更改?" "添加主题" - "已经是成员" - "已邀请" "加密的" "未加密的" "公共聊天室" diff --git a/features/roomdetails/impl/src/main/res/values/localazy.xml b/features/roomdetails/impl/src/main/res/values/localazy.xml index d0c389ded5..5dd185ec13 100644 --- a/features/roomdetails/impl/src/main/res/values/localazy.xml +++ b/features/roomdetails/impl/src/main/res/values/localazy.xml @@ -39,8 +39,6 @@ "You have unsaved changes." "Save changes?" "Add topic" - "Already a member" - "Already invited" "Encrypted" "Not encrypted" "Public room" diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt deleted file mode 100644 index 5aae0f5d3b..0000000000 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt +++ /dev/null @@ -1,408 +0,0 @@ -/* - * Copyright 2023, 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.features.roomdetails.impl.invite - -import app.cash.molecule.RecompositionMode -import app.cash.molecule.moleculeFlow -import app.cash.turbine.test -import com.google.common.truth.Truth.assertThat -import io.element.android.features.roomdetails.impl.aRoom -import io.element.android.features.roomdetails.impl.members.RoomMemberListDataSource -import io.element.android.features.roomdetails.impl.members.aRoomMember -import io.element.android.features.roomdetails.impl.members.aRoomMemberList -import io.element.android.libraries.core.coroutine.CoroutineDispatchers -import io.element.android.libraries.designsystem.theme.components.SearchBarResultState -import io.element.android.libraries.matrix.api.room.BaseRoom -import io.element.android.libraries.matrix.api.room.RoomMembersState -import io.element.android.libraries.matrix.api.room.RoomMembershipState -import io.element.android.libraries.matrix.api.user.MatrixUser -import io.element.android.libraries.matrix.test.A_USER_ID -import io.element.android.libraries.matrix.test.A_USER_ID_2 -import io.element.android.libraries.matrix.test.room.FakeBaseRoom -import io.element.android.libraries.matrix.ui.components.aMatrixUser -import io.element.android.libraries.matrix.ui.components.aMatrixUserList -import io.element.android.libraries.usersearch.api.UserSearchResult -import io.element.android.libraries.usersearch.api.UserSearchResultState -import io.element.android.libraries.usersearch.test.FakeUserRepository -import io.element.android.tests.testutils.WarmUpRule -import io.element.android.tests.testutils.consumeItemsUntilPredicate -import io.element.android.tests.testutils.testCoroutineDispatchers -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf -import kotlinx.coroutines.test.TestScope -import kotlinx.coroutines.test.runTest -import org.junit.Rule -import org.junit.Test - -internal class RoomInviteMembersPresenterTest { - @get:Rule - val warmUpRule = WarmUpRule() - - @Test - fun `present - initial state has no results and no search`() = runTest { - val presenter = RoomInviteMembersPresenter( - userRepository = FakeUserRepository(), - roomMemberListDataSource = createDataSource(FakeBaseRoom()), - coroutineDispatchers = testCoroutineDispatchers() - ) - - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { - val initialState = awaitItem() - - assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) - assertThat(initialState.isSearchActive).isFalse() - assertThat(initialState.canInvite).isFalse() - assertThat(initialState.searchQuery).isEmpty() - - skipItems(1) - } - } - - @Test - fun `present - updates search active state`() = runTest { - val presenter = RoomInviteMembersPresenter( - userRepository = FakeUserRepository(), - roomMemberListDataSource = createDataSource(FakeBaseRoom()), - coroutineDispatchers = testCoroutineDispatchers() - ) - - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { - val initialState = awaitItem() - skipItems(1) - - initialState.eventSink(RoomInviteMembersEvents.OnSearchActiveChanged(true)) - - val resultState = awaitItem() - assertThat(resultState.isSearchActive).isTrue() - } - } - - @Test - fun `present - performs search and handles empty result list`() = runTest { - val repository = FakeUserRepository() - val presenter = RoomInviteMembersPresenter( - userRepository = repository, - roomMemberListDataSource = createDataSource(FakeBaseRoom()), - coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) - ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { - val initialState = awaitItem() - initialState.eventSink(RoomInviteMembersEvents.UpdateSearchQuery("some query")) - assertThat(repository.providedQuery).isEqualTo("some query") - repository.emitState(UserSearchResultState(results = emptyList(), isSearching = true)) - consumeItemsUntilPredicate { it.showSearchLoader }.last().also { state -> - assertThat(state.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) - assertThat(state.showSearchLoader).isTrue() - } - repository.emitState(results = emptyList(), isSearching = false) - consumeItemsUntilPredicate { !it.showSearchLoader }.last().also { state -> - assertThat(state.searchResults).isInstanceOf(SearchBarResultState.NoResultsFound::class.java) - assertThat(state.showSearchLoader).isFalse() - } - } - } - - @Test - fun `present - performs search and handles user results`() = runTest { - val repository = FakeUserRepository() - val presenter = RoomInviteMembersPresenter( - userRepository = repository, - roomMemberListDataSource = createDataSource(FakeBaseRoom()), - coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) - ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { - val initialState = awaitItem() - skipItems(1) - - initialState.eventSink(RoomInviteMembersEvents.UpdateSearchQuery("some query")) - skipItems(1) - - assertThat(repository.providedQuery).isEqualTo("some query") - repository.emitStateWithUsers(users = aMatrixUserList()) - skipItems(1) - - val resultState = awaitItem() - assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) - - val expectedUsers = aMatrixUserList() - val users = resultState.searchResults.users() - expectedUsers.forEachIndexed { index, matrixUser -> - assertThat(users[index].matrixUser).isEqualTo(matrixUser) - assertThat(users[index].isAlreadyInvited).isFalse() - assertThat(users[index].isAlreadyJoined).isFalse() - assertThat(users[index].isSelected).isFalse() - } - } - } - - @Test - fun `present - performs search and handles membership state of existing users`() = runTest { - val userList = aMatrixUserList() - val joinedUser = userList[0] - val invitedUser = userList[1] - - val repository = FakeUserRepository() - val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) - val presenter = RoomInviteMembersPresenter( - userRepository = repository, - roomMemberListDataSource = createDataSource( - room = FakeBaseRoom().apply { - givenRoomMembersState( - RoomMembersState.Ready( - persistentListOf( - aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN), - aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE), - ) - ) - ) - }, - coroutineDispatchers = coroutineDispatchers, - ), - coroutineDispatchers = coroutineDispatchers - ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { - val initialState = awaitItem() - skipItems(1) - - initialState.eventSink(RoomInviteMembersEvents.UpdateSearchQuery("some query")) - skipItems(1) - - assertThat(repository.providedQuery).isEqualTo("some query") - repository.emitStateWithUsers(users = aMatrixUserList()) - skipItems(1) - - val resultState = awaitItem() - assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) - - val users = resultState.searchResults.users() - - // The result that matches a user with JOINED membership is marked as such - val userWhoShouldBeJoined = users.find { it.matrixUser == joinedUser } - assertThat(userWhoShouldBeJoined).isNotNull() - assertThat(userWhoShouldBeJoined?.isAlreadyJoined).isTrue() - assertThat(userWhoShouldBeJoined?.isAlreadyInvited).isFalse() - - // The result that matches a user with INVITED membership is marked as such - val userWhoShouldBeInvited = users.find { it.matrixUser == invitedUser } - assertThat(userWhoShouldBeInvited).isNotNull() - assertThat(userWhoShouldBeInvited?.isAlreadyJoined).isFalse() - assertThat(userWhoShouldBeInvited?.isAlreadyInvited).isTrue() - - // All other users are neither joined nor invited - val otherUsers = users.minus(userWhoShouldBeInvited!!).minus(userWhoShouldBeJoined!!) - assertThat(otherUsers.none { it.isAlreadyInvited }).isTrue() - assertThat(otherUsers.none { it.isAlreadyJoined }).isTrue() - } - } - - @Test - fun `present - performs search and handles unresolved results`() = runTest { - val userList = aMatrixUserList() - val joinedUser = userList[0] - val invitedUser = userList[1] - - val repository = FakeUserRepository() - val presenter = RoomInviteMembersPresenter( - userRepository = repository, - roomMemberListDataSource = createDataSource(FakeBaseRoom().apply { - givenRoomMembersState( - RoomMembersState.Ready( - persistentListOf( - aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN), - aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE), - ) - ) - ) - }), - coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) - ) - - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { - val initialState = awaitItem() - skipItems(1) - - initialState.eventSink(RoomInviteMembersEvents.UpdateSearchQuery("some query")) - skipItems(1) - - assertThat(repository.providedQuery).isEqualTo("some query") - - val unresolvedUser = UserSearchResult(aMatrixUser(id = A_USER_ID.value), isUnresolved = true) - repository.emitState(listOf(unresolvedUser) + aMatrixUserList().map { UserSearchResult(it) }) - skipItems(1) - - val resultState = awaitItem() - assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) - - val users = resultState.searchResults.users() - - val userWhoShouldBeUnresolved = users.first() - assertThat(userWhoShouldBeUnresolved.isUnresolved).isTrue() - - // All other users are neither joined nor invited - val otherUsers = users.minus(userWhoShouldBeUnresolved) - assertThat(otherUsers.none { it.isUnresolved }).isTrue() - } - } - - @Test - fun `present - toggle users updates selected user state`() = runTest { - val repository = FakeUserRepository() - val presenter = RoomInviteMembersPresenter( - userRepository = repository, - roomMemberListDataSource = createDataSource(), - coroutineDispatchers = testCoroutineDispatchers() - ) - - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { - val initialState = awaitItem() - skipItems(1) - - // When we toggle a user not in the list, they are added - initialState.eventSink(RoomInviteMembersEvents.ToggleUser(aMatrixUser())) - assertThat(awaitItem().selectedUsers).containsExactly(aMatrixUser()) - - // Toggling a different user also adds them - initialState.eventSink(RoomInviteMembersEvents.ToggleUser(aMatrixUser(id = A_USER_ID_2.value))) - assertThat(awaitItem().selectedUsers).containsExactly(aMatrixUser(), aMatrixUser(id = A_USER_ID_2.value)) - - // Toggling the first user removes them - initialState.eventSink(RoomInviteMembersEvents.ToggleUser(aMatrixUser())) - assertThat(awaitItem().selectedUsers).containsExactly(aMatrixUser(id = A_USER_ID_2.value)) - } - } - - @Test - fun `present - selected users appear as such in search results`() = runTest { - val repository = FakeUserRepository() - val presenter = RoomInviteMembersPresenter( - userRepository = repository, - roomMemberListDataSource = createDataSource(FakeBaseRoom()), - coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) - ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { - val initialState = awaitItem() - skipItems(1) - - val selectedUser = aMatrixUser() - - initialState.eventSink(RoomInviteMembersEvents.ToggleUser(selectedUser)) - - initialState.eventSink(RoomInviteMembersEvents.UpdateSearchQuery("some query")) - skipItems(1) - - assertThat(repository.providedQuery).isEqualTo("some query") - repository.emitStateWithUsers(users = aMatrixUserList() + selectedUser) - skipItems(2) - - val resultState = awaitItem() - assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) - - val users = resultState.searchResults.users() - - // The one user we have previously toggled is marked as selected - val shouldBeSelectedUser = users.find { it.matrixUser == selectedUser } - assertThat(shouldBeSelectedUser).isNotNull() - assertThat(shouldBeSelectedUser?.isSelected).isTrue() - - // And no others are - val allOtherUsers = users.minus(shouldBeSelectedUser!!) - assertThat(allOtherUsers.none { it.isSelected }).isTrue() - } - } - - @Test - fun `present - toggling a user updates existing search results`() = runTest { - val repository = FakeUserRepository() - val presenter = RoomInviteMembersPresenter( - userRepository = repository, - roomMemberListDataSource = createDataSource(FakeBaseRoom()), - coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) - ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { - val initialState = awaitItem() - skipItems(1) - - val selectedUser = aMatrixUser() - - // Given a query is made - initialState.eventSink(RoomInviteMembersEvents.UpdateSearchQuery("some query")) - skipItems(1) - - assertThat(repository.providedQuery).isEqualTo("some query") - repository.emitStateWithUsers(users = aMatrixUserList() + selectedUser) - skipItems(2) - - // And then a user is toggled - initialState.eventSink(RoomInviteMembersEvents.ToggleUser(selectedUser)) - skipItems(1) - val resultState = awaitItem() - - // The results are updated... - assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) - val users = resultState.searchResults.users() - - // The one user we have now toggled is marked as selected - val shouldBeSelectedUser = users.find { it.matrixUser == selectedUser } - assertThat(shouldBeSelectedUser).isNotNull() - assertThat(shouldBeSelectedUser?.isSelected).isTrue() - - // And no others are - val allOtherUsers = users.minus(shouldBeSelectedUser!!) - assertThat(allOtherUsers.none { it.isSelected }).isTrue() - } - } - - private suspend fun FakeUserRepository.emitStateWithUsers( - users: List, - isSearching: Boolean = false - ) { - emitState( - results = users.map { UserSearchResult(it) }, - isSearching = isSearching, - ) - } - - private suspend fun FakeUserRepository.emitState( - results: List, - isSearching: Boolean = false - ) { - val state = UserSearchResultState( - results = results, - isSearching = isSearching - ) - emitState(state) - } - - private fun TestScope.createDataSource( - room: BaseRoom = aRoom().apply { - givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) - }, - coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers() - ) = RoomMemberListDataSource(room, coroutineDispatchers) - - private fun SearchBarResultState>.users() = - (this as? SearchBarResultState.Results>)?.results.orEmpty() -} diff --git a/features/startchat/api/build.gradle.kts b/features/startchat/api/build.gradle.kts new file mode 100644 index 0000000000..77822f1a15 --- /dev/null +++ b/features/startchat/api/build.gradle.kts @@ -0,0 +1,18 @@ +/* + * Copyright 2023, 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ +plugins { + id("io.element.android-library") +} + +android { + namespace = "io.element.android.features.startchat.api" +} + +dependencies { + implementation(projects.libraries.architecture) + implementation(projects.libraries.matrix.api) +} diff --git a/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/ConfirmingStartDmWithMatrixUser.kt b/features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/ConfirmingStartDmWithMatrixUser.kt similarity index 89% rename from features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/ConfirmingStartDmWithMatrixUser.kt rename to features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/ConfirmingStartDmWithMatrixUser.kt index af19408324..192c32fee7 100644 --- a/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/ConfirmingStartDmWithMatrixUser.kt +++ b/features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/ConfirmingStartDmWithMatrixUser.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.api +package io.element.android.features.startchat.api import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.user.MatrixUser diff --git a/features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/StartChatEntryPoint.kt b/features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/StartChatEntryPoint.kt new file mode 100644 index 0000000000..17b9b902e2 --- /dev/null +++ b/features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/StartChatEntryPoint.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2023, 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.startchat.api + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import io.element.android.libraries.architecture.FeatureEntryPoint +import io.element.android.libraries.matrix.api.core.RoomIdOrAlias + +interface StartChatEntryPoint : FeatureEntryPoint { + fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder + interface NodeBuilder { + fun callback(callback: Callback): NodeBuilder + fun build(): Node + } + + interface Callback : Plugin { + fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias, serverNames: List) + fun onOpenRoomDirectory() + } +} diff --git a/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/StartDMAction.kt b/features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/StartDMAction.kt similarity index 95% rename from features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/StartDMAction.kt rename to features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/StartDMAction.kt index e64be9f923..b49a9fbdfd 100644 --- a/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/StartDMAction.kt +++ b/features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/StartDMAction.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.api +package io.element.android.features.startchat.api import androidx.compose.runtime.MutableState import io.element.android.libraries.architecture.AsyncAction diff --git a/features/startchat/impl/build.gradle.kts b/features/startchat/impl/build.gradle.kts new file mode 100644 index 0000000000..270c329a02 --- /dev/null +++ b/features/startchat/impl/build.gradle.kts @@ -0,0 +1,65 @@ +import extension.ComponentMergingStrategy +import extension.setupAnvil + +/* + * Copyright 2022-2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +plugins { + id("io.element.android-compose-library") + id("kotlin-parcelize") +} + +android { + namespace = "io.element.android.features.startchat.impl" + + testOptions { + unitTests { + isIncludeAndroidResources = true + } + } +} + +setupAnvil(componentMergingStrategy = ComponentMergingStrategy.KSP) + +dependencies { + implementation(projects.libraries.core) + implementation(projects.libraries.architecture) + implementation(projects.libraries.matrix.api) + implementation(projects.libraries.matrixui) + implementation(projects.libraries.designsystem) + implementation(projects.libraries.uiStrings) + implementation(projects.libraries.androidutils) + implementation(projects.libraries.deeplink) + implementation(projects.libraries.mediapickers.api) + implementation(projects.libraries.mediaupload.api) + implementation(projects.libraries.permissions.api) + implementation(projects.libraries.usersearch.impl) + implementation(projects.services.analytics.api) + implementation(libs.coil.compose) + implementation(projects.libraries.featureflag.api) + implementation(projects.features.createroom.api) + api(projects.features.startchat.api) + + testImplementation(libs.test.junit) + testImplementation(libs.test.mockk) + testImplementation(libs.coroutines.test) + testImplementation(libs.molecule.runtime) + testImplementation(libs.test.truth) + testImplementation(libs.test.turbine) + testImplementation(libs.test.robolectric) + testImplementation(projects.services.analytics.test) + testImplementation(projects.libraries.matrix.test) + testImplementation(projects.libraries.mediapickers.test) + testImplementation(projects.libraries.mediaupload.test) + testImplementation(projects.libraries.permissions.test) + testImplementation(projects.libraries.usersearch.test) + testImplementation(projects.features.startchat.test) + testImplementation(projects.libraries.featureflag.test) + testImplementation(projects.tests.testutils) + testImplementation(libs.androidx.compose.ui.test.junit) + testReleaseImplementation(libs.androidx.compose.ui.test.manifest) +} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/CreateRoomNavigator.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/StartChatNavigator.kt similarity index 86% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/CreateRoomNavigator.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/StartChatNavigator.kt index 69eac7d369..a45b4dddab 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/CreateRoomNavigator.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/StartChatNavigator.kt @@ -5,18 +5,18 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom +package io.element.android.features.startchat import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.navmodel.backstack.BackStack import com.bumble.appyx.navmodel.backstack.operation.push -import io.element.android.features.createroom.impl.CreateRoomFlowNode.NavTarget +import io.element.android.features.startchat.impl.StartChatFlowNode.NavTarget import io.element.android.libraries.architecture.overlay.Overlay import io.element.android.libraries.architecture.overlay.operation.hide import io.element.android.libraries.architecture.overlay.operation.show import io.element.android.libraries.matrix.api.core.RoomIdOrAlias -interface CreateRoomNavigator : Plugin { +interface StartChatNavigator : Plugin { fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias, serverNames: List) fun onCreateNewRoom() fun onShowJoinRoomByAddress() @@ -24,12 +24,12 @@ interface CreateRoomNavigator : Plugin { fun onOpenRoomDirectory() } -class DefaultCreateRoomNavigator( +class DefaultStartChatNavigator( private val backstack: BackStack, private val overlay: Overlay, private val openRoom: (RoomIdOrAlias, List) -> Unit, private val openRoomDirectory: () -> Unit, -) : CreateRoomNavigator { +) : StartChatNavigator { override fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias, serverNames: List) = openRoom(roomIdOrAlias, serverNames) override fun onOpenRoomDirectory() = openRoomDirectory() diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/DefaultStartChatEntryPoint.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/DefaultStartChatEntryPoint.kt new file mode 100644 index 0000000000..9f9073f1d7 --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/DefaultStartChatEntryPoint.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.startchat.impl + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.features.startchat.api.StartChatEntryPoint +import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.di.AppScope +import javax.inject.Inject + +@ContributesBinding(AppScope::class) +class DefaultStartChatEntryPoint @Inject constructor() : StartChatEntryPoint { + override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): StartChatEntryPoint.NodeBuilder { + val plugins = ArrayList() + + return object : StartChatEntryPoint.NodeBuilder { + override fun callback(callback: StartChatEntryPoint.Callback): StartChatEntryPoint.NodeBuilder { + plugins += callback + return this + } + + override fun build(): Node { + return parentNode.createNode(buildContext, plugins) + } + } + } +} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultStartDMAction.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/DefaultStartDMAction.kt similarity index 90% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultStartDMAction.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/DefaultStartDMAction.kt index c9b60786bd..b09c5ea174 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultStartDMAction.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/DefaultStartDMAction.kt @@ -5,13 +5,13 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl +package io.element.android.features.startchat.impl import androidx.compose.runtime.MutableState import com.squareup.anvil.annotations.ContributesBinding import im.vector.app.features.analytics.plan.CreatedRoom -import io.element.android.features.createroom.api.ConfirmingStartDmWithMatrixUser -import io.element.android.features.createroom.api.StartDMAction +import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser +import io.element.android.features.startchat.api.StartDMAction import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.MatrixClient diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/StartChatFlowNode.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/StartChatFlowNode.kt new file mode 100644 index 0000000000..a312b6fa84 --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/StartChatFlowNode.kt @@ -0,0 +1,101 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.startchat.impl + +import android.os.Parcelable +import androidx.compose.foundation.layout.Box +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.navigation.transition.JumpToEndTransitionHandler +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins +import com.bumble.appyx.navmodel.backstack.BackStack +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import io.element.android.anvilannotations.ContributesNode +import io.element.android.features.createroom.api.CreateRoomEntryPoint +import io.element.android.features.startchat.DefaultStartChatNavigator +import io.element.android.features.startchat.api.StartChatEntryPoint +import io.element.android.features.startchat.impl.joinbyaddress.JoinRoomByAddressNode +import io.element.android.features.startchat.impl.root.StartChatNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode +import io.element.android.libraries.architecture.OverlayView +import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias +import kotlinx.parcelize.Parcelize + +@ContributesNode(SessionScope::class) +class StartChatFlowNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, + private val createRoomEntryPoint: CreateRoomEntryPoint, +) : BaseFlowNode( + backstack = BackStack( + initialElement = NavTarget.Root, + savedStateMap = buildContext.savedStateMap, + ), + buildContext = buildContext, + plugins = plugins +) { + sealed interface NavTarget : Parcelable { + @Parcelize + data object Root : NavTarget + + @Parcelize + data object NewRoom : NavTarget + + @Parcelize + data object JoinByAddress : NavTarget + } + + private val navigator = DefaultStartChatNavigator( + backstack = backstack, + overlay = overlay, + openRoom = { roomIdOrAlias, viaServers -> + plugins().forEach { it.onOpenRoom(roomIdOrAlias, viaServers) } + }, + openRoomDirectory = { + plugins().forEach { it.onOpenRoomDirectory() } + } + ) + + override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { + return when (navTarget) { + NavTarget.Root -> { + createNode(buildContext = buildContext, plugins = listOf(navigator)) + } + NavTarget.NewRoom -> { + val callback = object : CreateRoomEntryPoint.Callback { + override fun onRoomCreated(roomId: RoomId) { + navigator.onOpenRoom(roomId.toRoomIdOrAlias(), emptyList()) + } + } + createRoomEntryPoint.nodeBuilder(parentNode = this, buildContext = buildContext) + .callback(callback) + .build() + } + NavTarget.JoinByAddress -> { + createNode(buildContext = buildContext, plugins = listOf(navigator)) + } + } + } + + @Composable + override fun View(modifier: Modifier) { + Box(modifier = modifier) { + BackstackView() + OverlayView(transitionHandler = remember { JumpToEndTransitionHandler() }) + } + } +} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchMultipleUsersResultItem.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchMultipleUsersResultItem.kt similarity index 98% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchMultipleUsersResultItem.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchMultipleUsersResultItem.kt index af12895fff..867ac9d918 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchMultipleUsersResultItem.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchMultipleUsersResultItem.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.components +package io.element.android.features.startchat.impl.components import androidx.compose.foundation.layout.Column import androidx.compose.runtime.Composable diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchSingleUserResultItem.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchSingleUserResultItem.kt similarity index 97% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchSingleUserResultItem.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchSingleUserResultItem.kt index eb922f1ae3..bd94d136af 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchSingleUserResultItem.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchSingleUserResultItem.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.components +package io.element.android.features.startchat.impl.components import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchUserBar.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchUserBar.kt similarity index 98% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchUserBar.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchUserBar.kt index 290c1aff0c..3d42c40067 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchUserBar.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchUserBar.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.components +package io.element.android.features.startchat.impl.components import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.Spring diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/UserListView.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/UserListView.kt similarity index 94% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/UserListView.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/UserListView.kt index a660480258..753bebec83 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/UserListView.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/UserListView.kt @@ -1,11 +1,11 @@ /* - * Copyright 2023, 2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.components +package io.element.android.features.startchat.impl.components import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -16,9 +16,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp -import io.element.android.features.createroom.impl.userlist.UserListEvents -import io.element.android.features.createroom.impl.userlist.UserListState -import io.element.android.features.createroom.impl.userlist.UserListStateProvider +import io.element.android.features.startchat.impl.userlist.UserListEvents +import io.element.android.features.startchat.impl.userlist.UserListState +import io.element.android.features.startchat.impl.userlist.UserListStateProvider import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressEvents.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressEvents.kt similarity index 86% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressEvents.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressEvents.kt index dbbcef56fa..648146fbd7 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressEvents.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressEvents.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.joinbyaddress +package io.element.android.features.startchat.impl.joinbyaddress sealed interface JoinRoomByAddressEvents { data object Dismiss : JoinRoomByAddressEvents diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressNode.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressNode.kt similarity index 85% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressNode.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressNode.kt index d6338ab43c..67dba8b46e 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressNode.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressNode.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.joinbyaddress +package io.element.android.features.startchat.impl.joinbyaddress import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -16,7 +16,7 @@ import com.bumble.appyx.core.plugin.plugins import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.createroom.CreateRoomNavigator +import io.element.android.features.startchat.StartChatNavigator import io.element.android.libraries.di.SessionScope @ContributesNode(SessionScope::class) @@ -25,7 +25,7 @@ class JoinRoomByAddressNode @AssistedInject constructor( @Assisted plugins: List, presenterFactory: JoinRoomByAddressPresenter.Factory, ) : Node(buildContext, plugins = plugins) { - private val navigator = plugins().first() + private val navigator = plugins().first() private val presenter = presenterFactory.create(navigator) @Composable diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressPresenter.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressPresenter.kt similarity index 95% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressPresenter.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressPresenter.kt index cf4788cbbf..4e1f9f9ab0 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressPresenter.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressPresenter.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.joinbyaddress +package io.element.android.features.startchat.impl.joinbyaddress import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -18,7 +18,7 @@ import androidx.compose.runtime.setValue import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import io.element.android.features.createroom.CreateRoomNavigator +import io.element.android.features.startchat.StartChatNavigator import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.data.tryOrNull import io.element.android.libraries.matrix.api.MatrixClient @@ -32,13 +32,13 @@ import kotlin.time.Duration.Companion.seconds private const val ADDRESS_RESOLVE_TIMEOUT_IN_SECONDS = 10 class JoinRoomByAddressPresenter @AssistedInject constructor( - @Assisted private val navigator: CreateRoomNavigator, + @Assisted private val navigator: StartChatNavigator, private val client: MatrixClient, private val roomAliasHelper: RoomAliasHelper, ) : Presenter { @AssistedFactory interface Factory { - fun create(navigator: CreateRoomNavigator): JoinRoomByAddressPresenter + fun create(navigator: StartChatNavigator): JoinRoomByAddressPresenter } @Composable diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressState.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressState.kt similarity index 92% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressState.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressState.kt index 11791181e1..84b01ac263 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressState.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressState.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.joinbyaddress +package io.element.android.features.startchat.impl.joinbyaddress import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressStateProvider.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressStateProvider.kt similarity index 95% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressStateProvider.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressStateProvider.kt index 6281a8e8e3..847ca78837 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressStateProvider.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressStateProvider.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.joinbyaddress +package io.element.android.features.startchat.impl.joinbyaddress import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.matrix.api.core.RoomId diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressView.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressView.kt similarity index 97% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressView.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressView.kt index c256f5140c..2d34dcc1cf 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressView.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressView.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.joinbyaddress +package io.element.android.features.startchat.impl.joinbyaddress import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -29,7 +29,7 @@ import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp -import io.element.android.features.createroom.impl.R +import io.element.android.features.startchat.impl.R import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatEvents.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatEvents.kt new file mode 100644 index 0000000000..6ea72d8b05 --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatEvents.kt @@ -0,0 +1,15 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.startchat.impl.root + +import io.element.android.libraries.matrix.api.user.MatrixUser + +sealed interface StartChatEvents { + data class StartDM(val matrixUser: MatrixUser) : StartChatEvents + data object CancelStartDM : StartChatEvents +} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootNode.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatNode.kt similarity index 85% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootNode.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatNode.kt index f76a5d5c61..f42b7da7cc 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootNode.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatNode.kt @@ -1,11 +1,11 @@ /* - * Copyright 2023, 2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.root +package io.element.android.features.startchat.impl.root import android.app.Activity import androidx.activity.compose.LocalActivity @@ -20,21 +20,21 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.createroom.CreateRoomNavigator +import io.element.android.features.startchat.StartChatNavigator import io.element.android.libraries.deeplink.usecase.InviteFriendsUseCase import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias import io.element.android.services.analytics.api.AnalyticsService @ContributesNode(SessionScope::class) -class CreateRoomRootNode @AssistedInject constructor( +class StartChatNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, - private val presenter: CreateRoomRootPresenter, + private val presenter: StartChatPresenter, private val analyticsService: AnalyticsService, private val inviteFriendsUseCase: InviteFriendsUseCase, ) : Node(buildContext, plugins = plugins) { - private val navigator = plugins().first() + private val navigator = plugins().first() init { lifecycle.subscribe( @@ -46,7 +46,7 @@ class CreateRoomRootNode @AssistedInject constructor( override fun View(modifier: Modifier) { val state = presenter.present() val activity = requireNotNull(LocalActivity.current) - CreateRoomRootView( + StartChatView( state = state, modifier = modifier, onCloseClick = this::navigateUp, diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenter.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenter.kt similarity index 73% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenter.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenter.kt index ea8be45e6b..9f7bea5c68 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenter.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenter.kt @@ -1,11 +1,11 @@ /* - * Copyright 2023, 2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.root +package io.element.android.features.startchat.impl.root import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -14,11 +14,11 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import io.element.android.features.createroom.api.StartDMAction -import io.element.android.features.createroom.impl.userlist.SelectionMode -import io.element.android.features.createroom.impl.userlist.UserListDataStore -import io.element.android.features.createroom.impl.userlist.UserListPresenter -import io.element.android.features.createroom.impl.userlist.UserListPresenterArgs +import io.element.android.features.startchat.api.StartDMAction +import io.element.android.features.startchat.impl.userlist.SelectionMode +import io.element.android.features.startchat.impl.userlist.UserListDataStore +import io.element.android.features.startchat.impl.userlist.UserListPresenter +import io.element.android.features.startchat.impl.userlist.UserListPresenterArgs import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.meta.BuildMeta @@ -29,14 +29,14 @@ import io.element.android.libraries.usersearch.api.UserRepository import kotlinx.coroutines.launch import javax.inject.Inject -class CreateRoomRootPresenter @Inject constructor( +class StartChatPresenter @Inject constructor( presenterFactory: UserListPresenter.Factory, userRepository: UserRepository, userListDataStore: UserListDataStore, private val startDMAction: StartDMAction, private val buildMeta: BuildMeta, private val featureFlagService: FeatureFlagService, -) : Presenter { +) : Presenter { private val presenter = presenterFactory.create( UserListPresenterArgs( selectionMode = SelectionMode.Single, @@ -46,7 +46,7 @@ class CreateRoomRootPresenter @Inject constructor( ) @Composable - override fun present(): CreateRoomRootState { + override fun present(): StartChatState { val userListState = presenter.present() val localCoroutineScope = rememberCoroutineScope() @@ -56,20 +56,20 @@ class CreateRoomRootPresenter @Inject constructor( featureFlagService.isFeatureEnabledFlow(FeatureFlags.RoomDirectorySearch) }.collectAsState(initial = false) - fun handleEvents(event: CreateRoomRootEvents) { + fun handleEvents(event: StartChatEvents) { when (event) { - is CreateRoomRootEvents.StartDM -> localCoroutineScope.launch { + is StartChatEvents.StartDM -> localCoroutineScope.launch { startDMAction.execute( matrixUser = event.matrixUser, createIfDmDoesNotExist = startDmActionState.value is AsyncAction.Confirming, actionState = startDmActionState, ) } - CreateRoomRootEvents.CancelStartDM -> startDmActionState.value = AsyncAction.Uninitialized + StartChatEvents.CancelStartDM -> startDmActionState.value = AsyncAction.Uninitialized } } - return CreateRoomRootState( + return StartChatState( applicationName = buildMeta.applicationName, userListState = userListState, startDmAction = startDmActionState.value, diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootState.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatState.kt similarity index 63% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootState.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatState.kt index 7a6d651db3..724d6e5e88 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootState.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatState.kt @@ -1,20 +1,20 @@ /* - * Copyright 2023, 2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.root +package io.element.android.features.startchat.impl.root -import io.element.android.features.createroom.impl.userlist.UserListState +import io.element.android.features.startchat.impl.userlist.UserListState import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.core.RoomId -data class CreateRoomRootState( +data class StartChatState( val applicationName: String, val userListState: UserListState, val startDmAction: AsyncAction, val isRoomDirectorySearchEnabled: Boolean, - val eventSink: (CreateRoomRootEvents) -> Unit, + val eventSink: (StartChatEvents) -> Unit, ) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootStateProvider.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatStateProvider.kt similarity index 80% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootStateProvider.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatStateProvider.kt index 9f2d59e3b6..6b5113cc94 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootStateProvider.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatStateProvider.kt @@ -1,17 +1,17 @@ /* - * Copyright 2023, 2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.root +package io.element.android.features.startchat.impl.root import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.features.createroom.api.ConfirmingStartDmWithMatrixUser -import io.element.android.features.createroom.impl.userlist.UserListState -import io.element.android.features.createroom.impl.userlist.aRecentDirectRoomList -import io.element.android.features.createroom.impl.userlist.aUserListState +import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser +import io.element.android.features.startchat.impl.userlist.UserListState +import io.element.android.features.startchat.impl.userlist.aRecentDirectRoomList +import io.element.android.features.startchat.impl.userlist.aUserListState import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.core.RoomId @@ -19,8 +19,8 @@ import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.usersearch.api.UserSearchResult import kotlinx.collections.immutable.persistentListOf -open class CreateRoomRootStateProvider : PreviewParameterProvider { - override val values: Sequence +open class StartChatStateProvider : PreviewParameterProvider { + override val values: Sequence get() = sequenceOf( aCreateRoomRootState(), aCreateRoomRootState( @@ -64,8 +64,8 @@ fun aCreateRoomRootState( userListState: UserListState = aUserListState(), startDmAction: AsyncAction = AsyncAction.Uninitialized, isRoomDirectorySearchEnabled: Boolean = false, - eventSink: (CreateRoomRootEvents) -> Unit = {}, -) = CreateRoomRootState( + eventSink: (StartChatEvents) -> Unit = {}, +) = StartChatState( applicationName = applicationName, userListState = userListState, startDmAction = startDmAction, diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatView.kt similarity index 89% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatView.kt index 248d331985..ebde080f75 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatView.kt @@ -1,11 +1,11 @@ /* - * Copyright 2023, 2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.root +package io.element.android.features.startchat.impl.root import androidx.annotation.DrawableRes import androidx.compose.foundation.clickable @@ -27,9 +27,9 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons -import io.element.android.features.createroom.api.ConfirmingStartDmWithMatrixUser -import io.element.android.features.createroom.impl.R -import io.element.android.features.createroom.impl.components.UserListView +import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser +import io.element.android.features.startchat.impl.R +import io.element.android.features.startchat.impl.components.UserListView import io.element.android.libraries.designsystem.components.async.AsyncActionView import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults import io.element.android.libraries.designsystem.components.button.BackButton @@ -48,8 +48,8 @@ import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.collections.immutable.persistentListOf @Composable -fun CreateRoomRootView( - state: CreateRoomRootState, +fun StartChatView( + state: StartChatState, onCloseClick: () -> Unit, onNewRoomClick: () -> Unit, onOpenDM: (RoomId) -> Unit, @@ -80,7 +80,7 @@ fun CreateRoomRootView( recentDirectRooms = persistentListOf(), ), onSelectUser = { - state.eventSink(CreateRoomRootEvents.StartDM(it)) + state.eventSink(StartChatEvents.StartDM(it)) }, onDeselectUser = { }, ) @@ -109,20 +109,20 @@ fun CreateRoomRootView( errorMessage = { stringResource(R.string.screen_start_chat_error_starting_chat) }, onRetry = { state.userListState.selectedUsers.firstOrNull() - ?.let { state.eventSink(CreateRoomRootEvents.StartDM(it)) } + ?.let { state.eventSink(StartChatEvents.StartDM(it)) } // Cancel start DM if there is no more selected user (should not happen) - ?: state.eventSink(CreateRoomRootEvents.CancelStartDM) + ?: state.eventSink(StartChatEvents.CancelStartDM) }, - onErrorDismiss = { state.eventSink(CreateRoomRootEvents.CancelStartDM) }, + onErrorDismiss = { state.eventSink(StartChatEvents.CancelStartDM) }, confirmationDialog = { data -> if (data is ConfirmingStartDmWithMatrixUser) { CreateDmConfirmationBottomSheet( matrixUser = data.matrixUser, onSendInvite = { - state.eventSink(CreateRoomRootEvents.StartDM(data.matrixUser)) + state.eventSink(StartChatEvents.StartDM(data.matrixUser)) }, onDismiss = { - state.eventSink(CreateRoomRootEvents.CancelStartDM) + state.eventSink(StartChatEvents.CancelStartDM) }, ) } @@ -148,7 +148,7 @@ private fun CreateRoomRootViewTopBar( @Composable private fun CreateRoomActionButtonsList( - state: CreateRoomRootState, + state: StartChatState, onNewRoomClick: () -> Unit, onInvitePeopleClick: () -> Unit, onJoinByAddressClick: () -> Unit, @@ -239,9 +239,9 @@ private fun CreateRoomActionButton( @PreviewsDayNight @Composable -internal fun CreateRoomRootViewPreview(@PreviewParameter(CreateRoomRootStateProvider::class) state: CreateRoomRootState) = +internal fun StartChatViewPreview(@PreviewParameter(StartChatStateProvider::class) state: StartChatState) = ElementPreview { - CreateRoomRootView( + StartChatView( state = state, onCloseClick = {}, onNewRoomClick = {}, diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenter.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/DefaultUserListPresenter.kt similarity index 98% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenter.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/DefaultUserListPresenter.kt index 32d5767cc6..c964b18441 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenter.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/DefaultUserListPresenter.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListDataStore.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListDataStore.kt similarity index 93% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListDataStore.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListDataStore.kt index a500e3a05f..64048d7e86 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListDataStore.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListDataStore.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import io.element.android.libraries.matrix.api.user.MatrixUser import kotlinx.coroutines.flow.MutableStateFlow diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListEvents.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListEvents.kt similarity index 90% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListEvents.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListEvents.kt index 45b40597da..794b2c18af 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListEvents.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListEvents.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import io.element.android.libraries.matrix.api.user.MatrixUser diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListPresenter.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListPresenter.kt similarity index 90% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListPresenter.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListPresenter.kt index 38f45d202f..a07b39a1e7 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListPresenter.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListPresenter.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.usersearch.api.UserRepository diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListPresenterArgs.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListPresenterArgs.kt similarity index 84% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListPresenterArgs.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListPresenterArgs.kt index 85cc58e995..d7e6a727f8 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListPresenterArgs.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListPresenterArgs.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist data class UserListPresenterArgs( val selectionMode: SelectionMode, diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListState.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListState.kt similarity index 94% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListState.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListState.kt index bed3ac7f63..2186bcb57a 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListState.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListState.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.room.recent.RecentDirectRoom diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListStateProvider.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListStateProvider.kt similarity index 98% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListStateProvider.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListStateProvider.kt index 3b5918abc5..65b4efdadb 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListStateProvider.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListStateProvider.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.designsystem.theme.components.SearchBarResultState diff --git a/features/startchat/impl/src/main/res/values-be/translations.xml b/features/startchat/impl/src/main/res/values-be/translations.xml new file mode 100644 index 0000000000..106159a00d --- /dev/null +++ b/features/startchat/impl/src/main/res/values-be/translations.xml @@ -0,0 +1,6 @@ + + + "Новы пакой" + "Каталог пакояў" + "Пры спробе пачаць чат адбылася памылка" + diff --git a/features/startchat/impl/src/main/res/values-bg/translations.xml b/features/startchat/impl/src/main/res/values-bg/translations.xml new file mode 100644 index 0000000000..21ad117fb6 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-bg/translations.xml @@ -0,0 +1,9 @@ + + + "Нова стая" + "Присъединяване към стая по адрес" + "Не е валиден адрес" + "Въведете…" + "Стаята не е намерена" + "напр. #room-name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-cs/translations.xml b/features/startchat/impl/src/main/res/values-cs/translations.xml new file mode 100644 index 0000000000..b89f27fb9e --- /dev/null +++ b/features/startchat/impl/src/main/res/values-cs/translations.xml @@ -0,0 +1,12 @@ + + + "Nová místnost" + "Adresář místností" + "Při pokusu o zahájení chatu došlo k chybě" + "Vstoupit do místnosti pomocí adresy" + "Neplatná adresa" + "Zadejte…" + "Odpovídající místnost nalezena" + "Místnost nebyla nalezena" + "např. #room-name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-cy/translations.xml b/features/startchat/impl/src/main/res/values-cy/translations.xml new file mode 100644 index 0000000000..47faa4c5c9 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-cy/translations.xml @@ -0,0 +1,12 @@ + + + "Ystafell newydd" + "Cyfeiriadur ystafelloedd" + "Digwyddodd gwall wrth geisio cychwyn sgwrs" + "Ymuno â\'r ystafell yn ôl cyfeiriad" + "Ddim yn gyfeiriad dilys" + "Ewch i mewn…" + "Cafwyd hyd i ystafell gyfatebol" + "Heb ganfod yr ystafell" + "e.e. #enw-ystafell:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-da/translations.xml b/features/startchat/impl/src/main/res/values-da/translations.xml new file mode 100644 index 0000000000..89092045f5 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-da/translations.xml @@ -0,0 +1,12 @@ + + + "Nyt rum" + "Register over rum" + "Der opstod en fejl under forsøget på at starte en samtale" + "Tilslut dig rummet med adressen" + "Ikke en gyldig adresse" + "Indtast…" + "Matchende rum fundet" + "Rum ikke fundet" + "f.eks. #rummets-navn:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-de/translations.xml b/features/startchat/impl/src/main/res/values-de/translations.xml new file mode 100644 index 0000000000..dff0a6fdea --- /dev/null +++ b/features/startchat/impl/src/main/res/values-de/translations.xml @@ -0,0 +1,12 @@ + + + "Neuer Raum" + "Raum-Verzeichnis" + "Beim Versuch, einen Chat zu starten, ist ein Fehler aufgetreten" + "Raum per Adresse betreten" + "Keine gültige Adresse" + "Eintreten…" + "Passender Raum gefunden" + "Raum nicht gefunden" + "z. B. #room -name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-el/translations.xml b/features/startchat/impl/src/main/res/values-el/translations.xml new file mode 100644 index 0000000000..19e6250d12 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-el/translations.xml @@ -0,0 +1,12 @@ + + + "Νέα αίθουσα" + "Κατάλογος αιθουσών" + "Παρουσιάστηκε σφάλμα κατά την προσπάθεια έναρξης μιας συνομιλίας" + "Συμμετοχή σε αίθουσα μέσω διεύθυνσης" + "Μη έγκυρη διεύθυνση" + "Εισάγετε…" + "Βρέθηκε η αντίστοιχη αίθουσα" + "Η αίθουσα δεν βρέθηκε" + "π.χ. #όνομα-αίθουσας:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-es/translations.xml b/features/startchat/impl/src/main/res/values-es/translations.xml new file mode 100644 index 0000000000..64a9f02a17 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-es/translations.xml @@ -0,0 +1,12 @@ + + + "Nueva sala" + "Directorio de salas" + "Se ha producido un error al intentar iniciar un chat" + "Unirse a una sala por su dirección" + "Dirección no válida" + "Introducir…" + "Sala encontrada" + "No se encontró la sala" + "p. ej., #nombre-de-la-sala:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-et/translations.xml b/features/startchat/impl/src/main/res/values-et/translations.xml new file mode 100644 index 0000000000..65459475a8 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-et/translations.xml @@ -0,0 +1,12 @@ + + + "Uus jututuba" + "Jututubade kataloog" + "Vestluse alustamisel tekkis viga" + "Liitu jututoaga aadressi alusel" + "See pole kehtiv aadress" + "Sisene…" + "Leidsime vastava jututoa" + "Jututuba ei leidu" + "nt. #jututoa-nimi:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-eu/translations.xml b/features/startchat/impl/src/main/res/values-eu/translations.xml new file mode 100644 index 0000000000..403db09c9d --- /dev/null +++ b/features/startchat/impl/src/main/res/values-eu/translations.xml @@ -0,0 +1,9 @@ + + + "Gela berria" + "Gelen direktorioa" + "Errorea gertatu da txata hasten saiatzean" + "Ez da baliozko helbidea" + "Sartu…" + "Ez da gela aurkitu" + diff --git a/features/startchat/impl/src/main/res/values-fa/translations.xml b/features/startchat/impl/src/main/res/values-fa/translations.xml new file mode 100644 index 0000000000..7cb1e1baee --- /dev/null +++ b/features/startchat/impl/src/main/res/values-fa/translations.xml @@ -0,0 +1,12 @@ + + + "اتاق جدید" + "فهرست اتاق‌ها" + "هنگام تلاش برای شروع چت خطایی روی داد" + "پیوستن به اتاق با نشانی" + "نشانی معتبری نیست" + "ورود…" + "اتاق مطابق پیدا شد" + "اتاق پیدا نشد" + "نمونه: ‪#room-name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-fi/translations.xml b/features/startchat/impl/src/main/res/values-fi/translations.xml new file mode 100644 index 0000000000..13659571c8 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-fi/translations.xml @@ -0,0 +1,12 @@ + + + "Uusi huone" + "Huoneluettelo" + "Keskustelun aloituksessa tapahtui virhe" + "Liity huoneeseen osoitteella" + "Osoite ei ole kelvollinen" + "Syötä…" + "Täsmäävä huone löytyi" + "Huonetta ei löytynyt" + "esim. #huoneen-nimi:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-fr/translations.xml b/features/startchat/impl/src/main/res/values-fr/translations.xml new file mode 100644 index 0000000000..9aaebd018f --- /dev/null +++ b/features/startchat/impl/src/main/res/values-fr/translations.xml @@ -0,0 +1,12 @@ + + + "Nouveau salon" + "Annuaire des salons" + "Une erreur s’est produite lors de la tentative de création de la discussion" + "Saisir une adresse de salon" + "Ce n’est pas une adresse valide" + "Saisir…" + "Ce salon existe" + "Salon non trouvé" + "ex: #nom-du-salon:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-hu/translations.xml b/features/startchat/impl/src/main/res/values-hu/translations.xml new file mode 100644 index 0000000000..014f7baaac --- /dev/null +++ b/features/startchat/impl/src/main/res/values-hu/translations.xml @@ -0,0 +1,12 @@ + + + "Új szoba" + "Szobakatalógus" + "Hiba történt a csevegés indításakor" + "Csatlakozás a szobához cím szerint" + "Nem érvényes cím" + "Írja be…" + "Megfelelő szoba található" + "Szoba nem található" + "pl. #szoba-neve:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-in/translations.xml b/features/startchat/impl/src/main/res/values-in/translations.xml new file mode 100644 index 0000000000..5f796bb8da --- /dev/null +++ b/features/startchat/impl/src/main/res/values-in/translations.xml @@ -0,0 +1,12 @@ + + + "Ruangan baru" + "Direktori ruangan" + "Terjadi kesalahan saat mencoba memulai obrolan" + "Bergabung dalam ruangan berdasarkan alamat" + "Bukan alamat yang valid" + "Masuk…" + "Ruangan yang cocok ditemukan" + "Ruangan tidak ditemukan" + "mis. #nama-ruangan:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-it/translations.xml b/features/startchat/impl/src/main/res/values-it/translations.xml new file mode 100644 index 0000000000..94818d7ab1 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-it/translations.xml @@ -0,0 +1,12 @@ + + + "Nuova stanza" + "Elenco delle stanze" + "Si è verificato un errore durante il tentativo di avviare una chat" + "Accedi alla stanza tramite indirizzo" + "Indirizzo non valido" + "Inserisci…" + "Stanza trovata" + "Stanza non trovata" + "ad esempio #room -name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-ka/translations.xml b/features/startchat/impl/src/main/res/values-ka/translations.xml new file mode 100644 index 0000000000..c5ccd79305 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-ka/translations.xml @@ -0,0 +1,6 @@ + + + "ახალი ოთახი" + "ოთახის კატალოგი" + "ჩატის დაწყების მცდელობისას შეცდომა მოხდა" + diff --git a/features/startchat/impl/src/main/res/values-lt/translations.xml b/features/startchat/impl/src/main/res/values-lt/translations.xml new file mode 100644 index 0000000000..699e0703f1 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-lt/translations.xml @@ -0,0 +1,5 @@ + + + "Naujas kambarys" + "Bandant pradėti pokalbį įvyko klaida" + diff --git a/features/startchat/impl/src/main/res/values-nb/translations.xml b/features/startchat/impl/src/main/res/values-nb/translations.xml new file mode 100644 index 0000000000..ffd8fe9cfc --- /dev/null +++ b/features/startchat/impl/src/main/res/values-nb/translations.xml @@ -0,0 +1,12 @@ + + + "Nytt rom" + "Romkatalog" + "Det oppstod en feil når du prøvde å starte en chat" + "Bli med i rommet med adresse" + "Ikke en gyldig adresse" + "Gå inn…" + "Matchende rom funnet" + "Rom ikke funnet" + "f.eks. #rom-navn:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-nl/translations.xml b/features/startchat/impl/src/main/res/values-nl/translations.xml new file mode 100644 index 0000000000..244ffddba3 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-nl/translations.xml @@ -0,0 +1,6 @@ + + + "Nieuwe kamer" + "Kamergids" + "Er is een fout opgetreden bij het starten van een chat" + diff --git a/features/startchat/impl/src/main/res/values-pl/translations.xml b/features/startchat/impl/src/main/res/values-pl/translations.xml new file mode 100644 index 0000000000..fe6b4a2c8d --- /dev/null +++ b/features/startchat/impl/src/main/res/values-pl/translations.xml @@ -0,0 +1,12 @@ + + + "Nowy pokój" + "Katalog pokoi" + "Wystąpił błąd podczas próby rozpoczęcia czatu" + "Dołącz do pokoju za pomocą adresu" + "Nieprawidłowy adres" + "Wprowadź…" + "Znaleziono pasujący pokój" + "Nie znaleziono pokoju" + "np. #room-name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-pt-rBR/translations.xml b/features/startchat/impl/src/main/res/values-pt-rBR/translations.xml new file mode 100644 index 0000000000..f17991c56b --- /dev/null +++ b/features/startchat/impl/src/main/res/values-pt-rBR/translations.xml @@ -0,0 +1,12 @@ + + + "Nova sala" + "Diretório de salas" + "Ocorreu um erro ao tentar iniciar um chat" + "Entrar na sala pelo endereço" + "Não é um endereço válido" + "Entrar…" + "Foi encontrada uma sala correspondente" + "Sala não encontrada" + "Por exemplo, #nome-da-sala:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-pt/translations.xml b/features/startchat/impl/src/main/res/values-pt/translations.xml new file mode 100644 index 0000000000..3efcbf7640 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-pt/translations.xml @@ -0,0 +1,12 @@ + + + "Nova sala" + "Diretório de salas" + "Ocorreu um erro ao tentar iniciar uma conversa" + "Entrar na sala pelo endereço" + "Não é um endereço válido" + "Entrar…" + "Sala correspondente encontrado" + "Sala não encontrada" + "por exemplo, #sala:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-ro/translations.xml b/features/startchat/impl/src/main/res/values-ro/translations.xml new file mode 100644 index 0000000000..d306d83aab --- /dev/null +++ b/features/startchat/impl/src/main/res/values-ro/translations.xml @@ -0,0 +1,6 @@ + + + "Cameră nouă" + "Director de camere" + "A apărut o eroare la încercarea începerii conversației" + diff --git a/features/startchat/impl/src/main/res/values-ru/translations.xml b/features/startchat/impl/src/main/res/values-ru/translations.xml new file mode 100644 index 0000000000..6d676d3c76 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-ru/translations.xml @@ -0,0 +1,12 @@ + + + "Создать новую комнату" + "Каталог комнат" + "Произошла ошибка при запуске чата" + "Присоединиться к комнате по адресу" + "Недействительный адрес" + "Ввести…" + "Соответствующая комната найдена" + "Комната не найдена" + "прим. #room-name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-sk/translations.xml b/features/startchat/impl/src/main/res/values-sk/translations.xml new file mode 100644 index 0000000000..16a1548765 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-sk/translations.xml @@ -0,0 +1,12 @@ + + + "Nová miestnosť" + "Adresár miestností" + "Pri pokuse o spustenie konverzácie sa vyskytla chyba" + "Pripojte sa do miestnosti podľa adresy" + "Neplatná adresa" + "Zadajte…" + "Nájdená zodpovedajúca miestnosť" + "Miestnosť sa nenašla" + "napr. #nazov-miestnosti:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-sv/translations.xml b/features/startchat/impl/src/main/res/values-sv/translations.xml new file mode 100644 index 0000000000..21cfb470b1 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-sv/translations.xml @@ -0,0 +1,12 @@ + + + "Nytt rum" + "Rumskatalog" + "Ett fel uppstod när du försökte starta en chatt" + "Gå med i rum med adress" + "Inte en giltig adress" + "Ange …" + "Matchande rum hittades" + "Rummet hittades inte" + "t.ex. #rumsnamn:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-tr/translations.xml b/features/startchat/impl/src/main/res/values-tr/translations.xml new file mode 100644 index 0000000000..581996500d --- /dev/null +++ b/features/startchat/impl/src/main/res/values-tr/translations.xml @@ -0,0 +1,6 @@ + + + "Yeni oda" + "Oda dizini" + "Sohbet başlatmaya çalışırken bir hata oluştu" + diff --git a/features/startchat/impl/src/main/res/values-uk/translations.xml b/features/startchat/impl/src/main/res/values-uk/translations.xml new file mode 100644 index 0000000000..3c2b09939c --- /dev/null +++ b/features/startchat/impl/src/main/res/values-uk/translations.xml @@ -0,0 +1,12 @@ + + + "Нова кімната" + "Каталог кімнат" + "Під час спроби почати бесіду сталася помилка" + "Приєднатися до кімнати за адресою" + "Недійсна адреса" + "Введіть…" + "Знайдено відповідну кімнату" + "Кімната не знайдена" + "наприклад, #room-name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-ur/translations.xml b/features/startchat/impl/src/main/res/values-ur/translations.xml new file mode 100644 index 0000000000..394f6aa817 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-ur/translations.xml @@ -0,0 +1,6 @@ + + + "نیا کمرہ" + "کمرے کا راہنامچہ" + "گفتگو شروع کرنے کی کوشش کرتے وقت ایک خرابی واقع ہوگئی" + diff --git a/features/startchat/impl/src/main/res/values-uz/translations.xml b/features/startchat/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..6f68899a3b --- /dev/null +++ b/features/startchat/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,5 @@ + + + "Yangi xona" + "Suhbatni boshlashda xatolik yuz berdi" + diff --git a/features/startchat/impl/src/main/res/values-zh-rTW/translations.xml b/features/startchat/impl/src/main/res/values-zh-rTW/translations.xml new file mode 100644 index 0000000000..c6dcd50008 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-zh-rTW/translations.xml @@ -0,0 +1,12 @@ + + + "建立聊天室" + "聊天室目錄" + "嘗試開始聊天時發生錯誤" + "按地址加入聊天室" + "不是有效的位址" + "輸入……" + "找到相符的聊天室" + "找不到聊天室" + "例如 #room-name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-zh/translations.xml b/features/startchat/impl/src/main/res/values-zh/translations.xml new file mode 100644 index 0000000000..f5f6681073 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-zh/translations.xml @@ -0,0 +1,6 @@ + + + "新聊天室" + "聊天室目录" + "在开始聊天时发生了错误" + diff --git a/features/startchat/impl/src/main/res/values/localazy.xml b/features/startchat/impl/src/main/res/values/localazy.xml new file mode 100644 index 0000000000..48b6449263 --- /dev/null +++ b/features/startchat/impl/src/main/res/values/localazy.xml @@ -0,0 +1,12 @@ + + + "New room" + "Room directory" + "An error occurred when trying to start a chat" + "Join room by address" + "Not a valid address" + "Enter…" + "Matching room found" + "Room not found" + "e.g. #room-name:matrix.org" + diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/DefaultStartDMActionTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/DefaultStartDMActionTest.kt similarity index 97% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/DefaultStartDMActionTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/DefaultStartDMActionTest.kt index ef6b3b9517..fa6e140c3a 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/DefaultStartDMActionTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/DefaultStartDMActionTest.kt @@ -5,12 +5,12 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl +package io.element.android.features.startchat.impl import androidx.compose.runtime.mutableStateOf import com.google.common.truth.Truth.assertThat import im.vector.app.features.analytics.plan.CreatedRoom -import io.element.android.features.createroom.api.ConfirmingStartDmWithMatrixUser +import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/FakeCreateRoomNavigator.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/FakeStartChatNavigator.kt similarity index 86% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/FakeCreateRoomNavigator.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/FakeStartChatNavigator.kt index 28dcdd409d..9de00e0a4c 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/FakeCreateRoomNavigator.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/FakeStartChatNavigator.kt @@ -5,18 +5,18 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl +package io.element.android.features.startchat.impl -import io.element.android.features.createroom.CreateRoomNavigator +import io.element.android.features.startchat.StartChatNavigator import io.element.android.libraries.matrix.api.core.RoomIdOrAlias -class FakeCreateRoomNavigator( +class FakeStartChatNavigator( private val openRoomLambda: (roomIdOrAlias: RoomIdOrAlias, serverNames: List) -> Unit = { _, _ -> }, private val createNewRoomLambda: () -> Unit = {}, private val showJoinRoomByAddressLambda: () -> Unit = {}, private val dismissJoinRoomByAddressLambda: () -> Unit = {}, private val openRoomDirectoryLambda: () -> Unit = {}, -) : CreateRoomNavigator { +) : StartChatNavigator { override fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias, serverNames: List) { openRoomLambda(roomIdOrAlias, serverNames) } diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt similarity index 93% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt index 10cca20fa3..bd40b92d57 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt @@ -5,11 +5,11 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.joinbyaddress +package io.element.android.features.startchat.impl.joinbyaddress import com.google.common.truth.Truth.assertThat -import io.element.android.features.createroom.CreateRoomNavigator -import io.element.android.features.createroom.impl.FakeCreateRoomNavigator +import io.element.android.features.startchat.StartChatNavigator +import io.element.android.features.startchat.impl.FakeStartChatNavigator import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomIdOrAlias import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper @@ -61,7 +61,7 @@ class JoinBaseRoomByAddressPresenterTest { fun `present - room found`() = runTest { val openRoomLambda = lambdaRecorder, Unit> { _, _ -> } val dismissJoinRoomByAddressLambda = lambdaRecorder { } - val navigator = FakeCreateRoomNavigator( + val navigator = FakeStartChatNavigator( openRoomLambda = openRoomLambda, dismissJoinRoomByAddressLambda = dismissJoinRoomByAddressLambda ) @@ -114,7 +114,7 @@ class JoinBaseRoomByAddressPresenterTest { @Test fun `present - dismiss`() = runTest { val dismissJoinRoomByAddressLambda = lambdaRecorder { } - val navigator = FakeCreateRoomNavigator( + val navigator = FakeStartChatNavigator( dismissJoinRoomByAddressLambda = dismissJoinRoomByAddressLambda ) val presenter = createJoinRoomByAddressPresenter(navigator = navigator) @@ -127,7 +127,7 @@ class JoinBaseRoomByAddressPresenterTest { } private fun createJoinRoomByAddressPresenter( - navigator: CreateRoomNavigator = FakeCreateRoomNavigator(), + navigator: StartChatNavigator = FakeStartChatNavigator(), matrixClient: MatrixClient = FakeMatrixClient(), roomAliasHelper: RoomAliasHelper = FakeRoomAliasHelper(), ): JoinRoomByAddressPresenter { diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt similarity index 94% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt index b2e75c9f5a..4de9bd1470 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.joinbyaddress +package io.element.android.features.startchat.impl.joinbyaddress import androidx.activity.ComponentActivity import androidx.compose.ui.test.junit4.AndroidComposeTestRule @@ -13,7 +13,7 @@ import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performTextInput import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.element.android.features.createroom.impl.R +import io.element.android.features.startchat.impl.R import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootPresenterTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt similarity index 83% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootPresenterTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt index d2d9959e2a..59a8838c6b 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootPresenterTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt @@ -1,23 +1,23 @@ /* - * Copyright 2023, 2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.root +package io.element.android.features.startchat.impl.root import androidx.compose.runtime.MutableState import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.features.createroom.api.ConfirmingStartDmWithMatrixUser -import io.element.android.features.createroom.api.StartDMAction -import io.element.android.features.createroom.impl.userlist.FakeUserListPresenter -import io.element.android.features.createroom.impl.userlist.FakeUserListPresenterFactory -import io.element.android.features.createroom.impl.userlist.UserListDataStore -import io.element.android.features.createroom.test.FakeStartDMAction +import io.element.android.features.invitepeople.test.FakeStartDMAction +import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser +import io.element.android.features.startchat.api.StartDMAction +import io.element.android.features.startchat.impl.userlist.FakeUserListPresenter +import io.element.android.features.startchat.impl.userlist.FakeUserListPresenterFactory +import io.element.android.features.startchat.impl.userlist.UserListDataStore import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService @@ -36,7 +36,7 @@ import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -class CreateBaseRoomRootPresenterTest { +class StartChatPresenterTest { @get:Rule val warmUpRule = WarmUpRule() @@ -47,7 +47,7 @@ class CreateBaseRoomRootPresenterTest { actionState.value = startDMFailureResult } val startDMAction = FakeStartDMAction(executeResult = executeResult) - val presenter = createCreateRoomRootPresenter(startDMAction) + val presenter = createStartChatPresenter(startDMAction) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -58,7 +58,7 @@ class CreateBaseRoomRootPresenterTest { assertThat(initialState.userListState.isSearchActive).isFalse() assertThat(initialState.userListState.isMultiSelectionEnabled).isFalse() val matrixUser = MatrixUser(UserId("@name:domain")) - initialState.eventSink(CreateRoomRootEvents.StartDM(matrixUser)) + initialState.eventSink(StartChatEvents.StartDM(matrixUser)) awaitItem().also { state -> assertThat(state.startDmAction).isEqualTo(startDMFailureResult) executeResult.assertions().isCalledOnce().with( @@ -66,7 +66,7 @@ class CreateBaseRoomRootPresenterTest { value(false), any(), ) - state.eventSink(CreateRoomRootEvents.CancelStartDM) + state.eventSink(StartChatEvents.CancelStartDM) } awaitItem().also { state -> assertThat(state.startDmAction.isUninitialized()).isTrue() @@ -81,7 +81,7 @@ class CreateBaseRoomRootPresenterTest { actionState.value = startDMSuccessResult } val startDMAction = FakeStartDMAction(executeResult = executeResult) - val presenter = createCreateRoomRootPresenter(startDMAction) + val presenter = createStartChatPresenter(startDMAction) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -92,7 +92,7 @@ class CreateBaseRoomRootPresenterTest { assertThat(initialState.userListState.isSearchActive).isFalse() assertThat(initialState.userListState.isMultiSelectionEnabled).isFalse() val matrixUser = MatrixUser(UserId("@name:domain")) - initialState.eventSink(CreateRoomRootEvents.StartDM(matrixUser)) + initialState.eventSink(StartChatEvents.StartDM(matrixUser)) awaitItem().also { state -> assertThat(state.startDmAction).isEqualTo(startDMSuccessResult) executeResult.assertions().isCalledOnce().with( @@ -112,13 +112,13 @@ class CreateBaseRoomRootPresenterTest { actionState.value = startDMConfirmationResult } val startDMAction = FakeStartDMAction(executeResult = executeResult) - val presenter = createCreateRoomRootPresenter(startDMAction) + val presenter = createStartChatPresenter(startDMAction) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { val initialState = awaitItem() assertThat(initialState.startDmAction).isInstanceOf(AsyncAction.Uninitialized::class.java) - initialState.eventSink(CreateRoomRootEvents.StartDM(matrixUser)) + initialState.eventSink(StartChatEvents.StartDM(matrixUser)) val confirmingState = awaitItem() assertThat(confirmingState.startDmAction).isEqualTo(startDMConfirmationResult) executeResult.assertions().isCalledOnce().with( @@ -127,7 +127,7 @@ class CreateBaseRoomRootPresenterTest { any(), ) // Cancelling should not create the DM - confirmingState.eventSink(CreateRoomRootEvents.CancelStartDM) + confirmingState.eventSink(StartChatEvents.CancelStartDM) val finalState = awaitItem() assertThat(finalState.startDmAction.isUninitialized()).isTrue() executeResult.assertions().isCalledExactly(1) @@ -142,13 +142,13 @@ class CreateBaseRoomRootPresenterTest { actionState.value = startDMConfirmationResult } val startDMAction = FakeStartDMAction(executeResult = executeResult) - val presenter = createCreateRoomRootPresenter(startDMAction) + val presenter = createStartChatPresenter(startDMAction) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { val initialState = awaitItem() assertThat(initialState.startDmAction).isInstanceOf(AsyncAction.Uninitialized::class.java) - initialState.eventSink(CreateRoomRootEvents.StartDM(matrixUser)) + initialState.eventSink(StartChatEvents.StartDM(matrixUser)) val confirmingState = awaitItem() assertThat(confirmingState.startDmAction).isEqualTo(startDMConfirmationResult) executeResult.assertions().isCalledOnce().with( @@ -157,7 +157,7 @@ class CreateBaseRoomRootPresenterTest { any(), ) // Start DM again should invoke the action with createIfDmDoesNotExist = true - confirmingState.eventSink(CreateRoomRootEvents.StartDM(matrixUser)) + confirmingState.eventSink(StartChatEvents.StartDM(matrixUser)) executeResult.assertions().isCalledExactly(2).withSequence( listOf(value(matrixUser), value(false), any()), listOf(value(matrixUser), value(true), any()), @@ -167,7 +167,7 @@ class CreateBaseRoomRootPresenterTest { @Test fun `present - room directory search`() = runTest { - val presenter = createCreateRoomRootPresenter(isRoomDirectorySearchEnabled = true) + val presenter = createStartChatPresenter(isRoomDirectorySearchEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -178,16 +178,16 @@ class CreateBaseRoomRootPresenterTest { } } - private fun createCreateRoomRootPresenter( + private fun createStartChatPresenter( startDMAction: StartDMAction = FakeStartDMAction(), isRoomDirectorySearchEnabled: Boolean = false, - ): CreateRoomRootPresenter { + ): StartChatPresenter { val featureFlagService = FakeFeatureFlagService( initialState = mapOf( FeatureFlags.RoomDirectorySearch.key to isRoomDirectorySearchEnabled, ), ) - return CreateRoomRootPresenter( + return StartChatPresenter( presenterFactory = FakeUserListPresenterFactory(FakeUserListPresenter()), userRepository = FakeUserRepository(), userListDataStore = UserListDataStore(), diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootViewTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatViewTest.kt similarity index 80% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootViewTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatViewTest.kt index 9104b2dfb2..dc213446a0 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootViewTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatViewTest.kt @@ -1,11 +1,11 @@ /* - * Copyright 2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.root +package io.element.android.features.startchat.impl.root import androidx.activity.ComponentActivity import androidx.compose.ui.test.junit4.AndroidComposeTestRule @@ -13,9 +13,9 @@ import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.element.android.features.createroom.impl.R -import io.element.android.features.createroom.impl.userlist.aRecentDirectRoomList -import io.element.android.features.createroom.impl.userlist.aUserListState +import io.element.android.features.startchat.impl.R +import io.element.android.features.startchat.impl.userlist.aRecentDirectRoomList +import io.element.android.features.startchat.impl.userlist.aUserListState import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.ui.model.getBestName import io.element.android.libraries.ui.strings.CommonStrings @@ -33,15 +33,15 @@ import org.junit.runner.RunWith import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) -class CreateBaseRoomRootViewTest { +class StartChatViewTest { @get:Rule val rule = createAndroidComposeRule() @Test fun `clicking on back invokes the expected callback`() { - val eventsRecorder = EventsRecorder(expectEvents = false) + val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { - rule.setCreateRoomRootView( + rule.setStartChatView( aCreateRoomRootState( eventSink = eventsRecorder, ), @@ -53,9 +53,9 @@ class CreateBaseRoomRootViewTest { @Test fun `clicking on New room invokes the expected callback`() { - val eventsRecorder = EventsRecorder(expectEvents = false) + val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { - rule.setCreateRoomRootView( + rule.setStartChatView( aCreateRoomRootState( eventSink = eventsRecorder, ), @@ -68,9 +68,9 @@ class CreateBaseRoomRootViewTest { @Config(qualifiers = "h1024dp") @Test fun `clicking on Invite people invokes the expected callback`() { - val eventsRecorder = EventsRecorder(expectEvents = false) + val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { - rule.setCreateRoomRootView( + rule.setStartChatView( aCreateRoomRootState( applicationName = "test", eventSink = eventsRecorder, @@ -87,9 +87,9 @@ class CreateBaseRoomRootViewTest { fun `clicking on a user suggestion invokes the expected callback`() { val recentDirectRoomList = aRecentDirectRoomList() val firstRoom = recentDirectRoomList[0] - val eventsRecorder = EventsRecorder(expectEvents = false) + val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnceWithParam(firstRoom.roomId) { - rule.setCreateRoomRootView( + rule.setStartChatView( aCreateRoomRootState( userListState = aUserListState( recentDirectRooms = recentDirectRoomList @@ -105,9 +105,9 @@ class CreateBaseRoomRootViewTest { @Config(qualifiers = "h1024dp") @Test fun `clicking on Join room by address invokes the expected callback`() { - val eventsRecorder = EventsRecorder(expectEvents = false) + val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { - rule.setCreateRoomRootView( + rule.setStartChatView( aCreateRoomRootState( eventSink = eventsRecorder, ), @@ -119,9 +119,9 @@ class CreateBaseRoomRootViewTest { @Test fun `clicking on room directory invokes the expected callback`() { - val eventsRecorder = EventsRecorder(expectEvents = false) + val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { - rule.setCreateRoomRootView( + rule.setStartChatView( aCreateRoomRootState( eventSink = eventsRecorder, isRoomDirectorySearchEnabled = true @@ -133,8 +133,8 @@ class CreateBaseRoomRootViewTest { } } -private fun AndroidComposeTestRule.setCreateRoomRootView( - state: CreateRoomRootState, +private fun AndroidComposeTestRule.setStartChatView( + state: StartChatState, onCloseClick: () -> Unit = EnsureNeverCalled(), onNewRoomClick: () -> Unit = EnsureNeverCalled(), onOpenDM: (RoomId) -> Unit = EnsureNeverCalledWithParam(), @@ -143,7 +143,7 @@ private fun AndroidComposeTestRule.setCreat onRoomDirectorySearchClick: () -> Unit = EnsureNeverCalled(), ) { setContent { - CreateRoomRootView( + StartChatView( state = state, onCloseClick = onCloseClick, onNewRoomClick = onNewRoomClick, diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenterTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/DefaultUserListPresenterTest.kt similarity index 99% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenterTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/DefaultUserListPresenterTest.kt index ac793a247f..50bbc425c2 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenterTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/DefaultUserListPresenterTest.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/FakeUserListPresenter.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/FakeUserListPresenter.kt similarity index 89% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/FakeUserListPresenter.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/FakeUserListPresenter.kt index a0768ffda8..84c4fd9d67 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/FakeUserListPresenter.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/FakeUserListPresenter.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import androidx.compose.runtime.Composable diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/FakeUserListPresenterFactory.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/FakeUserListPresenterFactory.kt similarity index 91% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/FakeUserListPresenterFactory.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/FakeUserListPresenterFactory.kt index 123a013670..8e80626e86 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/FakeUserListPresenterFactory.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/FakeUserListPresenterFactory.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import io.element.android.libraries.usersearch.api.UserRepository diff --git a/features/createroom/test/build.gradle.kts b/features/startchat/test/build.gradle.kts similarity index 83% rename from features/createroom/test/build.gradle.kts rename to features/startchat/test/build.gradle.kts index b7df0caab6..96b05a80fa 100644 --- a/features/createroom/test/build.gradle.kts +++ b/features/startchat/test/build.gradle.kts @@ -10,7 +10,7 @@ plugins { } android { - namespace = "io.element.android.features.createroom.test" + namespace = "io.element.android.features.invitepeople.test" } dependencies { @@ -19,5 +19,5 @@ dependencies { implementation(projects.libraries.matrix.test) implementation(projects.libraries.architecture) implementation(projects.tests.testutils) - api(projects.features.createroom.api) + api(projects.features.startchat.api) } diff --git a/features/createroom/test/src/main/kotlin/io/element/android/features/createroom/test/FakeStartDMAction.kt b/features/startchat/test/src/main/kotlin/io/element/android/features/invitepeople/test/FakeStartDMAction.kt similarity index 88% rename from features/createroom/test/src/main/kotlin/io/element/android/features/createroom/test/FakeStartDMAction.kt rename to features/startchat/test/src/main/kotlin/io/element/android/features/invitepeople/test/FakeStartDMAction.kt index 90e2ecf1c1..d7ab63d0e3 100644 --- a/features/createroom/test/src/main/kotlin/io/element/android/features/createroom/test/FakeStartDMAction.kt +++ b/features/startchat/test/src/main/kotlin/io/element/android/features/invitepeople/test/FakeStartDMAction.kt @@ -5,10 +5,10 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.test +package io.element.android.features.invitepeople.test import androidx.compose.runtime.MutableState -import io.element.android.features.createroom.api.StartDMAction +import io.element.android.features.startchat.api.StartDMAction import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.user.MatrixUser diff --git a/features/userprofile/impl/build.gradle.kts b/features/userprofile/impl/build.gradle.kts index 4242efcb98..7bcebae565 100644 --- a/features/userprofile/impl/build.gradle.kts +++ b/features/userprofile/impl/build.gradle.kts @@ -38,7 +38,7 @@ dependencies { api(projects.features.userprofile.api) api(projects.features.userprofile.shared) implementation(libs.coil.compose) - implementation(projects.features.createroom.api) + implementation(projects.features.startchat.api) implementation(projects.services.analytics.api) testImplementation(libs.test.junit) @@ -49,7 +49,7 @@ dependencies { testImplementation(libs.test.mockk) testImplementation(libs.test.robolectric) testImplementation(projects.libraries.matrix.test) - testImplementation(projects.features.createroom.test) + testImplementation(projects.features.startchat.test) testImplementation(projects.features.enterprise.test) testImplementation(projects.tests.testutils) testImplementation(libs.androidx.compose.ui.test.junit) diff --git a/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/root/UserProfilePresenter.kt b/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/root/UserProfilePresenter.kt index 4de79b8375..b7fae6082b 100644 --- a/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/root/UserProfilePresenter.kt +++ b/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/root/UserProfilePresenter.kt @@ -20,8 +20,8 @@ import androidx.compose.runtime.setValue import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import io.element.android.features.createroom.api.StartDMAction import io.element.android.features.enterprise.api.SessionEnterpriseService +import io.element.android.features.startchat.api.StartDMAction import io.element.android.features.userprofile.api.UserProfileEvents import io.element.android.features.userprofile.api.UserProfileState import io.element.android.features.userprofile.api.UserProfileState.ConfirmationDialog diff --git a/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/UserProfilePresenterTest.kt b/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/UserProfilePresenterTest.kt index 2ce7f99c2c..dd937b067a 100644 --- a/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/UserProfilePresenterTest.kt +++ b/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/UserProfilePresenterTest.kt @@ -13,10 +13,10 @@ import app.cash.molecule.moleculeFlow import app.cash.turbine.ReceiveTurbine import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.features.createroom.api.ConfirmingStartDmWithMatrixUser -import io.element.android.features.createroom.api.StartDMAction -import io.element.android.features.createroom.test.FakeStartDMAction import io.element.android.features.enterprise.test.FakeSessionEnterpriseService +import io.element.android.features.invitepeople.test.FakeStartDMAction +import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser +import io.element.android.features.startchat.api.StartDMAction import io.element.android.features.userprofile.api.UserProfileEvents import io.element.android.features.userprofile.api.UserProfileState import io.element.android.features.userprofile.api.UserProfileVerificationState diff --git a/features/userprofile/shared/build.gradle.kts b/features/userprofile/shared/build.gradle.kts index 0b14ce63f2..53e8e9dee2 100644 --- a/features/userprofile/shared/build.gradle.kts +++ b/features/userprofile/shared/build.gradle.kts @@ -39,7 +39,7 @@ dependencies { api(projects.features.userprofile.api) api(projects.services.apperror.api) implementation(libs.coil.compose) - implementation(projects.features.createroom.api) + implementation(projects.features.startchat.api) implementation(projects.services.analytics.api) testImplementation(libs.test.junit) diff --git a/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/UserProfileStateProvider.kt b/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/UserProfileStateProvider.kt index 7a5cc53239..25cb8a5df6 100644 --- a/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/UserProfileStateProvider.kt +++ b/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/UserProfileStateProvider.kt @@ -8,7 +8,7 @@ package io.element.android.features.userprofile.shared import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.features.createroom.api.ConfirmingStartDmWithMatrixUser +import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser import io.element.android.features.userprofile.api.UserProfileEvents import io.element.android.features.userprofile.api.UserProfileState import io.element.android.features.userprofile.api.UserProfileVerificationState diff --git a/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/UserProfileView.kt b/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/UserProfileView.kt index a43478e466..f39cbfaf73 100644 --- a/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/UserProfileView.kt +++ b/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/UserProfileView.kt @@ -21,7 +21,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.compound.tokens.generated.CompoundIcons -import io.element.android.features.createroom.api.ConfirmingStartDmWithMatrixUser +import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser import io.element.android.features.userprofile.api.UserProfileEvents import io.element.android.features.userprofile.api.UserProfileState import io.element.android.features.userprofile.api.UserProfileVerificationState diff --git a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/AsyncData.kt b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/AsyncData.kt index b7f22cbe23..7085db62f3 100644 --- a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/AsyncData.kt +++ b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/AsyncData.kt @@ -160,3 +160,17 @@ suspend inline fun runUpdatingState( } ) } + +inline fun AsyncData.map( + transform: (T?) -> R, +): AsyncData { + return when (this) { + is AsyncData.Failure -> AsyncData.Failure( + error = error, + prevData = transform(prevData) + ) + is AsyncData.Loading -> AsyncData.Loading(transform(prevData)) + is AsyncData.Success -> AsyncData.Success(transform(data)) + AsyncData.Uninitialized -> AsyncData.Uninitialized + } +} diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/StringProvider.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/StringProvider.kt deleted file mode 100644 index 74c11e58c0..0000000000 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/StringProvider.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2023, 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.designsystem.utils - -import androidx.compose.ui.tooling.preview.PreviewParameterProvider - -open class StringProvider(val strings: List) : PreviewParameterProvider { - override val values: Sequence - get() = strings.asSequence() -} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/FilterRoomMembers.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/FilterRoomMembers.kt new file mode 100644 index 0000000000..a1c4f0bf01 --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/FilterRoomMembers.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.api.room + +import io.element.android.libraries.core.bool.orFalse +import kotlinx.coroutines.withContext +import kotlin.coroutines.CoroutineContext + +/** + * Method to filter members by userId or displayName. + * It does filter through the already known members, it doesn't perform additional requests. + */ +suspend fun BaseRoom.filterMembers(query: String, coroutineContext: CoroutineContext): List = withContext(coroutineContext) { + val roomMembersState = membersStateFlow.value + val activeRoomMembers = roomMembersState.roomMembers() + ?.filter { it.membership.isActive() } + .orEmpty() + val filteredMembers = if (query.isBlank()) { + activeRoomMembers + } else { + activeRoomMembers.filter { member -> + member.userId.value.contains(query, ignoreCase = true) || + member.displayName?.contains(query, ignoreCase = true).orFalse() + } + } + filteredMembers +} diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index ec29d79f19..242e7b67fa 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -88,6 +88,7 @@ "Enable" "End poll" "Enter PIN" + "Finish" "Forgot password?" "Forward" "Go back" @@ -301,6 +302,7 @@ Reason: %1$s." "Signing out" "Something went wrong" "We encountered an issue. Please try again." + "Space" "%1$d Space" "%1$d Spaces" diff --git a/services/apperror/api/src/main/kotlin/io/element/android/services/apperror/api/AppErrorStateService.kt b/services/apperror/api/src/main/kotlin/io/element/android/services/apperror/api/AppErrorStateService.kt index 45031fdf33..8070673804 100644 --- a/services/apperror/api/src/main/kotlin/io/element/android/services/apperror/api/AppErrorStateService.kt +++ b/services/apperror/api/src/main/kotlin/io/element/android/services/apperror/api/AppErrorStateService.kt @@ -7,10 +7,13 @@ package io.element.android.services.apperror.api +import androidx.annotation.StringRes import kotlinx.coroutines.flow.StateFlow interface AppErrorStateService { val appErrorStateFlow: StateFlow fun showError(title: String, body: String) + + fun showError(@StringRes titleRes: Int, @StringRes bodyRes: Int) } diff --git a/services/apperror/impl/build.gradle.kts b/services/apperror/impl/build.gradle.kts index a3d17a14cd..01163d240c 100644 --- a/services/apperror/impl/build.gradle.kts +++ b/services/apperror/impl/build.gradle.kts @@ -23,6 +23,7 @@ dependencies { implementation(projects.libraries.di) implementation(projects.libraries.designsystem) implementation(projects.libraries.uiStrings) + implementation(projects.services.toolbox.api) implementation(projects.anvilannotations) implementation(libs.coroutines.core) @@ -34,4 +35,5 @@ dependencies { testImplementation(libs.coroutines.test) testImplementation(libs.test.turbine) testImplementation(libs.test.truth) + testImplementation(projects.services.toolbox.test) } diff --git a/services/apperror/impl/src/main/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateService.kt b/services/apperror/impl/src/main/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateService.kt index 7341028784..9f9ede50ee 100644 --- a/services/apperror/impl/src/main/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateService.kt +++ b/services/apperror/impl/src/main/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateService.kt @@ -12,13 +12,16 @@ import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.SingleIn import io.element.android.services.apperror.api.AppErrorState import io.element.android.services.apperror.api.AppErrorStateService +import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import javax.inject.Inject @ContributesBinding(AppScope::class) @SingleIn(AppScope::class) -class DefaultAppErrorStateService @Inject constructor() : AppErrorStateService { +class DefaultAppErrorStateService @Inject constructor( + private val stringProvider: StringProvider, +) : AppErrorStateService { private val currentAppErrorState = MutableStateFlow(AppErrorState.NoError) override val appErrorStateFlow: StateFlow = currentAppErrorState @@ -31,4 +34,10 @@ class DefaultAppErrorStateService @Inject constructor() : AppErrorStateService { }, ) } + + override fun showError(titleRes: Int, bodyRes: Int) { + val title = stringProvider.getString(titleRes) + val body = stringProvider.getString(bodyRes) + showError(title, body) + } } diff --git a/services/apperror/impl/src/test/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateServiceTest.kt b/services/apperror/impl/src/test/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateServiceTest.kt index 86f918c264..6eb26c9c50 100644 --- a/services/apperror/impl/src/test/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateServiceTest.kt +++ b/services/apperror/impl/src/test/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateServiceTest.kt @@ -10,14 +10,14 @@ package io.element.android.services.apperror.impl import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.services.apperror.api.AppErrorState +import io.element.android.services.toolbox.test.strings.FakeStringProvider import kotlinx.coroutines.test.runTest import org.junit.Test internal class DefaultAppErrorStateServiceTest { @Test fun `initial value is no error`() = runTest { - val service = DefaultAppErrorStateService() - + val service = createDefaultAppErrorStateService() service.appErrorStateFlow.test { val state = awaitItem() assertThat(state).isInstanceOf(AppErrorState.NoError::class.java) @@ -26,8 +26,7 @@ internal class DefaultAppErrorStateServiceTest { @Test fun `showError - emits value`() = runTest { - val service = DefaultAppErrorStateService() - + val service = createDefaultAppErrorStateService() service.appErrorStateFlow.test { skipItems(1) @@ -42,9 +41,22 @@ internal class DefaultAppErrorStateServiceTest { } @Test - fun `dismiss - clears value`() = runTest { - val service = DefaultAppErrorStateService() + fun `showError - emits value from ids`() = runTest { + val service = createDefaultAppErrorStateService() + service.appErrorStateFlow.test { + skipItems(1) + service.showError(1, 2) + val state = awaitItem() + assertThat(state).isInstanceOf(AppErrorState.Error::class.java) + val errorState = state as AppErrorState.Error + assertThat(errorState.title).isEqualTo("A string") + assertThat(errorState.body).isEqualTo("A string") + } + } + @Test + fun `dismiss - clears value`() = runTest { + val service = createDefaultAppErrorStateService() service.appErrorStateFlow.test { skipItems(1) @@ -58,4 +70,8 @@ internal class DefaultAppErrorStateServiceTest { assertThat(awaitItem()).isInstanceOf(AppErrorState.NoError::class.java) } } + + private fun createDefaultAppErrorStateService() = DefaultAppErrorStateService( + stringProvider = FakeStringProvider(), + ) } diff --git a/services/apperror/test/build.gradle.kts b/services/apperror/test/build.gradle.kts new file mode 100644 index 0000000000..c8ac902784 --- /dev/null +++ b/services/apperror/test/build.gradle.kts @@ -0,0 +1,20 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +plugins { + id("io.element.android-library") +} + +android { + namespace = "io.element.android.services.apperror.test" +} + +dependencies { + implementation(libs.coroutines.core) + implementation(projects.services.apperror.api) + implementation(projects.tests.testutils) +} diff --git a/services/apperror/test/src/main/kotlin/io/element/android/services/apperror/test/FakeAppErrorStateService.kt b/services/apperror/test/src/main/kotlin/io/element/android/services/apperror/test/FakeAppErrorStateService.kt new file mode 100644 index 0000000000..0783d08e02 --- /dev/null +++ b/services/apperror/test/src/main/kotlin/io/element/android/services/apperror/test/FakeAppErrorStateService.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.services.apperror.test + +import io.element.android.services.apperror.api.AppErrorState +import io.element.android.services.apperror.api.AppErrorStateService +import io.element.android.tests.testutils.lambda.lambdaError +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +class FakeAppErrorStateService( + initialState: AppErrorState = AppErrorState.NoError, + private val showErrorResult: (String, String) -> Unit = { _, _ -> lambdaError() }, + private val showErrorResResult: (Int, Int) -> Unit = { _, _ -> lambdaError() } +) : AppErrorStateService { + private val mutableAppErrorStateFlow = MutableStateFlow(initialState) + override val appErrorStateFlow: StateFlow = mutableAppErrorStateFlow.asStateFlow() + + override fun showError(title: String, body: String) { + showErrorResult(title, body) + } + + override fun showError(titleRes: Int, bodyRes: Int) { + showErrorResResult(titleRes, bodyRes) + } + + fun setAppErrorState(state: AppErrorState) { + mutableAppErrorStateFlow.value = state + } +} diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_0_en.png index 1360f07fe2..338eb8d3f6 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e7f6f2d2302e958ec4c85a5856839f5ed430ff9bf1048a8427b8b589cbc3f8ce -size 13665 +oid sha256:7415b3286707130c0218a8d1e82a9d9c61c8eec8df346653dd67626d0dd7709c +size 10038 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_1_en.png index f5ba7efcf3..a17b156fbf 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f315821d7f65b36f1237ffc4a7fc4e8d6ca1f00cc5452322495f057a9244dd20 -size 24704 +oid sha256:efe665c1419f9674e74b04dd066adf042cd421fd3e18a8cbc1f2ed80a0977e07 +size 10340 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_2_en.png index 873b524941..338eb8d3f6 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9a04777e27af3dc8068f97e64c6312af53f416353b8b886f89368e83458d48b0 -size 77516 +oid sha256:7415b3286707130c0218a8d1e82a9d9c61c8eec8df346653dd67626d0dd7709c +size 10038 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_3_en.png deleted file mode 100644 index 0c7800bb11..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_3_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:72216dbc7378b0745abc76a364258254cd7b7af56e47083799fb85e9f9d181f7 -size 41977 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_0_en.png index 8207f06398..5bd1590652 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b235755e1122103b52cb68a2ddef230ecfe3d61cac802d1fd633cf3bc37dbb0 -size 12880 +oid sha256:39c67413ca997982b0fcd32831ccedee1d7a0763619784b8758b194df6c7ff81 +size 9639 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_1_en.png index 479aaeb6c6..5cfffac707 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b46150ff515da137e4b2a57c7f0739b700c984f08c5ac01b9804638e53b661d7 -size 24865 +oid sha256:d8b6fae4f9fa5be0bbad9855ce80b53206748970d1ea1f9473eaa476afa39bcc +size 9936 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_2_en.png index f9fc27e0c0..5bd1590652 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:04c62992c4744efc672861adbd0635a25616f060b66824ac0ad9c9ca89922462 -size 77954 +oid sha256:39c67413ca997982b0fcd32831ccedee1d7a0763619784b8758b194df6c7ff81 +size 9639 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_3_en.png deleted file mode 100644 index 52779bf8fd..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_3_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:be7cfa925e024d94d72b17408fe3487007b6daee2c4dc728960f56af1351f644 -size 42100 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en.png index 6ba325fefe..933f4d0185 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0c797770fae796712a4db1d9d4084ebef2211548a33c49178d015658ebc502a6 -size 42823 +oid sha256:e7a0b233fa704f80e06b4e5ed3b787722545e30b0adf3729b1618785169c8511 +size 35832 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en.png index 7e0c631982..867eb9e084 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:45b66b5de32c34fde5ab5997e4ee7bc7fce64c9846220a6cb98acb462b3f79d8 -size 59051 +oid sha256:dc153a3db10441cb166f2cf1d767f59bd77f4b45ff3f6a2dce02324f265626b1 +size 56368 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en.png index c2c2dd1d1d..0d444e8f35 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8b846ef4e88898937c13d1a8e4a25d0ac1a5673e2906cca4369453fbd45b8dfa -size 43458 +oid sha256:686dd48e4b76b6f5bc06c8b2751b981a5a53dfba9821a138d2c64a9a9aacdd3c +size 36979 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en.png index 372d0db1bf..661406ac93 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fcd04f11078a2b5727a65b758b8425dddc49b28a11ef0cb61f35ad7f11ab90c9 -size 60231 +oid sha256:6c24eec8e26ba06ddb216e3d5335a139f947d9ff576dc8737af0bb713e0d68a1 +size 58216 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_0_en.png new file mode 100644 index 0000000000..31d8d6d6ee --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aae19b03efb483fd312e5cf4b02e000af86941ce5c8e3472fe2410bc67178519 +size 9122 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_1_en.png new file mode 100644 index 0000000000..dec7a7732f --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1fcdfe7d1492b536b3604747ede049e24f48b75977eb3858e27a837b5b4ec6da +size 20550 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_2_en.png new file mode 100644 index 0000000000..bff2174041 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8a40987c3fb50529128eee026fa9b21495bacac58bdf20a01a39fb24ea462f4c +size 6676 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_3_en.png new file mode 100644 index 0000000000..5399d37415 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_3_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:84b3f9bbf73e600f1e860a42c26cc4a9f5be45acae551a90a2e19084dcf5d157 +size 18031 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_4_en.png new file mode 100644 index 0000000000..09335740e8 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_4_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1ee1be1b069192b7e155139af4e3dba97fc21373d3e49d31be41f6263b733800 +size 8626 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_5_en.png new file mode 100644 index 0000000000..353f884e3e --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_5_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f050b90caaf47a772c72d805955b657de1f7fe544e8a45952b4f9592e54ee5d6 +size 38336 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_6_en.png new file mode 100644 index 0000000000..76b5bab350 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_6_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5996283d500a3b9eb525584865ba868dda5d688c8f757399e5b907c6aa1ea70e +size 33128 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_7_en.png new file mode 100644 index 0000000000..1be07da870 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_7_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f301d1266f98ec60c8abdb508884d44d3eb5b607654e0158b693779e5a8b6ca6 +size 25626 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_8_en.png new file mode 100644 index 0000000000..7e1dc6ec2d --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_8_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:805f7e08c25821528d2748ffa2b4edeaf21d0ee2a1d833693e36e51fafe0f92b +size 6607 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_0_en.png new file mode 100644 index 0000000000..d42ab638fa --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:31143646f33a013c30bc4e1cfd6e66beb8af100521dfd9dc599a94be8e6f415c +size 8535 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_1_en.png new file mode 100644 index 0000000000..aca93cea12 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50474e918e38f3f14e57ac6c069bf414f99050083d3796e100ac683309db74c0 +size 20917 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_2_en.png new file mode 100644 index 0000000000..d4004dd81d --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5d2fae553f7775986fe0c50adcbb581eabe7ebf2f82d39e1fef3d6ecc4e3c288 +size 6511 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_3_en.png new file mode 100644 index 0000000000..68ddb5c685 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_3_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ee5daee317f00723321e2b4aa0f8be015cacb9ab22e36ba74238a8063766aab5 +size 18713 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_4_en.png new file mode 100644 index 0000000000..0553656788 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_4_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fe4889333bc96358fb3121bdeb54d3d4d75eba234d318462da3985ee75cf8ed2 +size 8420 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_5_en.png new file mode 100644 index 0000000000..c3d5eebc49 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_5_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1bfd83f8bcf688f73edeeed7d085f706dc81fe7c5b608a46c55f320a0772cc14 +size 39183 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_6_en.png new file mode 100644 index 0000000000..89d64ec951 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_6_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1318a5b1a3f17f6e4e867eea5615909c9c54c13f55caeff5beb97f8251c62138 +size 33225 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_7_en.png new file mode 100644 index 0000000000..55ea3aaf4c --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_7_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0ea5406893f8d4eb3ba729233fee5271c5de3d10b57cae9dd6d8cb973da04378 +size 25211 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_8_en.png new file mode 100644 index 0000000000..03b52521f9 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_8_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:65fde13bab6f3561319892c242c361fbd15874251670f5db3155ef75c3ba4cdb +size 6529 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en.png index 6102c1316d..4149be807b 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cb145968deaf61c3c94c5094624a1024e796698fc7b62801f852fd4db4483de6 -size 13741 +oid sha256:611314345ea0f68062800755783e790ad452adec1f1dd01fcae1eec4cc5322fc +size 8188 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en.png index 8a3e9fced6..39ff3000da 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:66f4f90864984ed917ff55916b62a825ab05915de3b7e7fc9be22b4bcb7c3ef1 -size 24702 +oid sha256:86a07a08b2bd2b6672da54bec6183ccdc860740a24cf43e88d3e40c0b50138ed +size 8110 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en.png index c042e2b852..4149be807b 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2df17818a5c948856cd4892f56e321b3f5f72353d0d05b0104c13115a1538c92 -size 11160 +oid sha256:611314345ea0f68062800755783e790ad452adec1f1dd01fcae1eec4cc5322fc +size 8188 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en.png deleted file mode 100644 index af42e49989..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c9b9ae8410f882587f286684da3d92fde0de1c5f9a42dcc4819e690c3fc997ba -size 22454 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_4_en.png deleted file mode 100644 index 528b5ad450..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_4_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c69900f653154c27dea219139c66337783e3ed1a04d1520c18c4271430a1910b -size 13111 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_5_en.png deleted file mode 100644 index 7db6382d79..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_5_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:022d3375146f9fc4d68b5342a725492e5e3899565518110ee0a5c25687b46764 -size 42527 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_6_en.png deleted file mode 100644 index b9cdf531f8..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_6_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0e13b174b62b089cf1275d5bbf7ca59bbcb0c8afe416d0dbc8bc92c6267b7379 -size 37547 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_7_en.png deleted file mode 100644 index 4097a7998a..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_7_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5f46810124f978b267deb9b6418b740ae845bd53529cda4de688e2d09cea1010 -size 29699 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en.png index f13c0ff5ff..b27727ee2b 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b385467c9bf74c9abc478d3cc2b20f73abd2da65f71a75d8f86e9e8635b86af1 -size 12919 +oid sha256:7ba9d3cb9a5a601b28ad9ff508c3179921cf26fcee86194c582092b1d7bf79d3 +size 7992 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en.png index 9832cb4eb2..3f5cacc2d0 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:44264663827df1a99b190ec02edddac80d6b95a65f98a4abc4e8cf7a1141b793 -size 24841 +oid sha256:6cb292850354b8b6ba5ca36334d1664dccd617e7a6b9b55ecf3ac7d1b9729d90 +size 7872 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en.png index c9c0170659..b27727ee2b 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:77a5df48748a583eb76d1fd9ddfc334f16d8b327f31edde679a548ada59f4488 -size 10772 +oid sha256:7ba9d3cb9a5a601b28ad9ff508c3179921cf26fcee86194c582092b1d7bf79d3 +size 7992 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en.png deleted file mode 100644 index e49a38e82e..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:40eb69cf8c757555304edccca2e1b57d378e0cf9f4a8c42b275287d0f44a7f18 -size 22877 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_4_en.png deleted file mode 100644 index 8c0a4c43a0..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_4_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2c54621eb62e69ea15b707a75a1a579836730ab321c67e16535a56da0b972ed3 -size 12689 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_5_en.png deleted file mode 100644 index 3645708432..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_5_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:25eb2a710631f8297160e6a8e51102f454db559d7c56b8b14a33e2bbfb5a4173 -size 43159 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_6_en.png deleted file mode 100644 index 136e28cb23..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_6_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b5d429e01ef00018de091809af63edc12827362fe82498bca5c85b85a0e6fd6a -size 37451 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_7_en.png deleted file mode 100644 index ad4dd4a0a0..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_7_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4e1e57cfdee3e3f45024b9b9bafa5ea9eade19ab4b9ff48f2acd76245d5cc026 -size 29011 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_SearchMultipleUsersResultItem_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_SearchMultipleUsersResultItem_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_SearchMultipleUsersResultItem_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_SearchMultipleUsersResultItem_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_SearchSingleUserResultItem_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_SearchSingleUserResultItem_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_SearchSingleUserResultItem_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_SearchSingleUserResultItem_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_0_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_1_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_1_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_1_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_2_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_2_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_2_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_3_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_3_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_3_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_4_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_4_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_4_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_5_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_5_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_5_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_6_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_6_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_6_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_7_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_7_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_7_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_8_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_8_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_8_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_9_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_9_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_9_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_0_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_1_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_1_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_1_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_2_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_2_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_2_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_3_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_3_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_3_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_4_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_4_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_4_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_5_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_5_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_5_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_6_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_6_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_6_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_7_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_7_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_7_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_8_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_8_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_8_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_9_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_9_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_9_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_0_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_1_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_1_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_1_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_2_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_2_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_2_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_3_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_3_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_3_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_4_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_4_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_4_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_5_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_5_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_5_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_0_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_1_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_1_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_1_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_2_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_2_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_2_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_3_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_3_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_3_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_4_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_4_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_4_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_5_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_5_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_5_en.png diff --git a/tools/localazy/config.json b/tools/localazy/config.json index 1f0d291d0b..0aac7e51af 100644 --- a/tools/localazy/config.json +++ b/tools/localazy/config.json @@ -59,10 +59,16 @@ "name" : ":features:createroom:impl", "includeRegex" : [ "screen_create_room_.*", - "screen\\.create_room\\..*", + "screen\\.create_room\\..*" + ] + }, + { + "name" : ":features:startchat:impl", + "includeRegex" : [ "screen_start_chat_.*", "screen\\.start_chat\\..*", - "screen_room_directory_search_title*" + "screen_room_directory_search_title", + "screen_create_room_action_create_room" ] }, { @@ -201,6 +207,12 @@ "screen_room_member_details_.*" ] }, + { + "name" : ":features:invitepeople:impl", + "includeRegex" : [ + "screen\\.invite_users\\..*" + ] + }, { "name" : ":features:messages:impl", "includeRegex" : [