Merge remote-tracking branch 'origin/develop' into

feature/fre/start_chat_with_matrix_id
This commit is contained in:
Florian Renaud 2023-04-05 10:16:33 +02:00
commit eef1eea2a8
68 changed files with 1157 additions and 187 deletions

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.createroom.impl
import io.element.android.features.userlist.api.MatrixUserDataSource
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.ui.model.MatrixUser
import javax.inject.Inject
// TODO this is empty as we currently don't have an endpoint to perform user search
class AllMatrixUsersDataSource @Inject constructor() : MatrixUserDataSource {
override suspend fun search(query: String): List<MatrixUser> {
return emptyList()
}
override suspend fun getProfile(userId: UserId): MatrixUser? {
return null
}
}

View file

@ -17,31 +17,38 @@
package io.element.android.features.createroom.impl.addpeople
import androidx.compose.runtime.Composable
import io.element.android.features.selectusers.api.SelectUsersPresenter
import io.element.android.features.selectusers.api.SelectUsersPresenterArgs
import io.element.android.features.selectusers.api.SelectionMode
import io.element.android.features.userlist.api.SelectionMode
import io.element.android.features.userlist.api.MatrixUserDataSource
import io.element.android.features.userlist.api.UserListPresenter
import io.element.android.features.userlist.api.UserListPresenterArgs
import io.element.android.libraries.architecture.Presenter
import javax.inject.Inject
import javax.inject.Named
class AddPeoplePresenter @Inject constructor(
private val selectUsersPresenterFactory: SelectUsersPresenter.Factory,
private val userListPresenterFactory: UserListPresenter.Factory,
@Named("AllUsers") private val matrixUserDataSource: MatrixUserDataSource,
) : Presenter<AddPeopleState> {
private val selectUsersPresenter by lazy {
selectUsersPresenterFactory.create(SelectUsersPresenterArgs(SelectionMode.Multiple))
private val userListPresenter by lazy {
userListPresenterFactory.create(
UserListPresenterArgs(selectionMode = SelectionMode.Multiple),
matrixUserDataSource,
)
}
@Composable
override fun present(): AddPeopleState {
val selectUsersState = selectUsersPresenter.present()
val userListState = userListPresenter.present()
fun handleEvents(event: AddPeopleEvents) {
// do nothing for now
}
return AddPeopleState(
selectUsersState = selectUsersState,
userListState = userListState,
eventSink = ::handleEvents,
)
}
}

View file

@ -16,9 +16,9 @@
package io.element.android.features.createroom.impl.addpeople
import io.element.android.features.selectusers.api.SelectUsersState
import io.element.android.features.userlist.api.UserListState
data class AddPeopleState(
val selectUsersState: SelectUsersState,
val userListState: UserListState,
val eventSink: (AddPeopleEvents) -> Unit,
)

View file

@ -17,22 +17,22 @@
package io.element.android.features.createroom.impl.addpeople
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.selectusers.api.SelectionMode
import io.element.android.features.selectusers.api.aListOfSelectedUsers
import io.element.android.features.selectusers.api.aSelectUsersState
import io.element.android.features.userlist.api.SelectionMode
import io.element.android.features.userlist.api.aListOfSelectedUsers
import io.element.android.features.userlist.api.aUserListState
open class AddPeopleStateProvider : PreviewParameterProvider<AddPeopleState> {
override val values: Sequence<AddPeopleState>
get() = sequenceOf(
aAddPeopleState(),
aAddPeopleState().copy(
selectUsersState = aSelectUsersState().copy(
userListState = aUserListState().copy(
selectedUsers = aListOfSelectedUsers(),
selectionMode = SelectionMode.Multiple,
)
),
aAddPeopleState().copy(
selectUsersState = aSelectUsersState().copy(
userListState = aUserListState().copy(
selectedUsers = aListOfSelectedUsers(),
isSearchActive = true,
selectionMode = SelectionMode.Multiple,
@ -42,6 +42,6 @@ open class AddPeopleStateProvider : PreviewParameterProvider<AddPeopleState> {
}
fun aAddPeopleState() = AddPeopleState(
selectUsersState = aSelectUsersState(),
userListState = aUserListState(),
eventSink = {}
)

View file

@ -29,8 +29,8 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import io.element.android.features.userlist.api.UserListView
import io.element.android.features.createroom.impl.R
import io.element.android.features.selectusers.api.SelectUsersView
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
@ -52,9 +52,9 @@ fun AddPeopleView(
Scaffold(
topBar = {
if (!state.selectUsersState.isSearchActive) {
if (!state.userListState.isSearchActive) {
AddPeopleViewTopBar(
hasSelectedUsers = state.selectUsersState.selectedUsers.isNotEmpty(),
hasSelectedUsers = state.userListState.selectedUsers.isNotEmpty(),
onBackPressed = onBackPressed,
onNextPressed = onNextPressed,
)
@ -66,9 +66,9 @@ fun AddPeopleView(
.fillMaxSize()
.padding(padding),
) {
SelectUsersView(
UserListView(
modifier = Modifier.fillMaxWidth(),
state = state.selectUsersState,
state = state.userListState,
)
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.createroom.impl.di
import com.squareup.anvil.annotations.ContributesTo
import dagger.Binds
import dagger.Module
import io.element.android.features.createroom.impl.AllMatrixUsersDataSource
import io.element.android.features.userlist.api.MatrixUserDataSource
import io.element.android.libraries.di.AppScope
import javax.inject.Named
@Module
@ContributesTo(AppScope::class)
interface CreateRoomModule {
@Binds
@Named("AllUsers")
fun bindAllUserListDataSource(dataSource: AllMatrixUsersDataSource): MatrixUserDataSource
}

View file

@ -21,9 +21,10 @@ import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import io.element.android.features.selectusers.api.SelectUsersPresenter
import io.element.android.features.selectusers.api.SelectUsersPresenterArgs
import io.element.android.features.selectusers.api.SelectionMode
import io.element.android.features.userlist.api.MatrixUserDataSource
import io.element.android.features.userlist.api.SelectionMode
import io.element.android.features.userlist.api.UserListPresenter
import io.element.android.features.userlist.api.UserListPresenterArgs
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.execute
@ -33,19 +34,24 @@ import io.element.android.libraries.matrix.ui.model.MatrixUser
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Named
class CreateRoomRootPresenter @Inject constructor(
private val presenterFactory: SelectUsersPresenter.Factory,
private val presenterFactory: UserListPresenter.Factory,
@Named("AllUsers") private val matrixUserDataSource: MatrixUserDataSource,
private val matrixClient: MatrixClient,
) : Presenter<CreateRoomRootState> {
private val presenter by lazy {
presenterFactory.create(SelectUsersPresenterArgs(SelectionMode.Single))
presenterFactory.create(
UserListPresenterArgs(selectionMode = SelectionMode.Single),
matrixUserDataSource,
)
}
@Composable
override fun present(): CreateRoomRootState {
val selectUsersState = presenter.present()
val userListState = presenter.present()
val localCoroutineScope = rememberCoroutineScope()
val startDmAction: MutableState<Async<RoomId>> = remember { mutableStateOf(Async.Uninitialized) }
@ -65,7 +71,7 @@ class CreateRoomRootPresenter @Inject constructor(
is CreateRoomRootEvents.StartDM -> startDm(event.matrixUser)
CreateRoomRootEvents.RetryStartDM -> {
startDmAction.value = Async.Uninitialized
selectUsersState.selectedUsers.firstOrNull()?.let { startDm(it) }
userListState.selectedUsers.firstOrNull()?.let { startDm(it) }
}
CreateRoomRootEvents.CancelStartDM -> startDmAction.value = Async.Uninitialized
CreateRoomRootEvents.InvitePeople -> Unit // Todo Handle invite people action
@ -73,7 +79,7 @@ class CreateRoomRootPresenter @Inject constructor(
}
return CreateRoomRootState(
selectUsersState = selectUsersState,
userListState = userListState,
startDmAction = startDmAction.value,
eventSink = ::handleEvents,
)

View file

@ -16,12 +16,12 @@
package io.element.android.features.createroom.impl.root
import io.element.android.features.selectusers.api.SelectUsersState
import io.element.android.features.userlist.api.UserListState
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.api.core.RoomId
data class CreateRoomRootState(
val selectUsersState: SelectUsersState,
val userListState: UserListState,
val startDmAction: Async<RoomId>,
val eventSink: (CreateRoomRootEvents) -> Unit,
)

View file

@ -17,7 +17,7 @@
package io.element.android.features.createroom.impl.root
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.selectusers.api.aSelectUsersState
import io.element.android.features.userlist.api.aUserListState
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.ui.components.aMatrixUser
import kotlinx.collections.immutable.persistentListOf
@ -28,8 +28,8 @@ open class CreateRoomRootStateProvider : PreviewParameterProvider<CreateRoomRoot
aCreateRoomRootState(),
aCreateRoomRootState().copy(
startDmAction = Async.Loading(),
selectUsersState = aMatrixUser().let {
aSelectUsersState().copy(
userListState = aMatrixUser().let {
aUserListState().copy(
searchQuery = it.id.value,
searchResults = persistentListOf(it),
selectedUsers = persistentListOf(it),
@ -39,8 +39,8 @@ open class CreateRoomRootStateProvider : PreviewParameterProvider<CreateRoomRoot
),
aCreateRoomRootState().copy(
startDmAction = Async.Failure(Throwable()),
selectUsersState = aMatrixUser().let {
aSelectUsersState().copy(
userListState = aMatrixUser().let {
aUserListState().copy(
searchQuery = it.id.value,
searchResults = persistentListOf(it),
selectedUsers = persistentListOf(it),
@ -54,5 +54,5 @@ open class CreateRoomRootStateProvider : PreviewParameterProvider<CreateRoomRoot
fun aCreateRoomRootState() = CreateRoomRootState(
eventSink = {},
startDmAction = Async.Uninitialized,
selectUsersState = aSelectUsersState(),
userListState = aUserListState(),
)

View file

@ -41,7 +41,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import io.element.android.features.createroom.impl.R
import io.element.android.features.selectusers.api.SelectUsersView
import io.element.android.features.userlist.api.UserListView
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.designsystem.components.ProgressDialog
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
@ -74,7 +74,7 @@ fun CreateRoomRootView(
Scaffold(
modifier = modifier.fillMaxWidth(),
topBar = {
if (!state.selectUsersState.isSearchActive) {
if (!state.userListState.isSearchActive) {
CreateRoomRootViewTopBar(onClosePressed = onClosePressed)
}
}
@ -84,9 +84,9 @@ fun CreateRoomRootView(
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
val context = LocalContext.current
SelectUsersView(
UserListView(
modifier = Modifier.fillMaxWidth(),
state = state.selectUsersState,
state = state.userListState,
onUserSelected = {
// Fixme disabled DM creation since it can break the account data which is not correctly synced
// uncomment to enable it again or move behind a feature flag
@ -95,7 +95,7 @@ fun CreateRoomRootView(
},
)
if (!state.selectUsersState.isSearchActive) {
if (!state.userListState.isSearchActive) {
CreateRoomActionButtonsList(
onNewRoomClicked = onNewRoomClicked,
onInvitePeopleClicked = { state.eventSink(CreateRoomRootEvents.InvitePeople) },

View file

@ -22,7 +22,8 @@ import app.cash.molecule.RecompositionClock
import app.cash.molecule.moleculeFlow
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.features.selectusers.test.FakeSelectUserPresenterFactory
import io.element.android.features.userlist.test.FakeMatrixUserDataSource
import io.element.android.features.userlist.test.FakeUserListPresenterFactory
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Before
@ -34,7 +35,7 @@ class AddPeoplePresenterTests {
@Before
fun setup() {
presenter = AddPeoplePresenter(FakeSelectUserPresenterFactory())
presenter = AddPeoplePresenter(FakeUserListPresenterFactory(), FakeMatrixUserDataSource())
}
@Test
@ -47,3 +48,4 @@ class AddPeoplePresenterTests {
}
}
}

View file

@ -22,10 +22,10 @@ import app.cash.molecule.RecompositionClock
import app.cash.molecule.moleculeFlow
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.features.selectusers.api.SelectUsersPresenter
import io.element.android.features.selectusers.api.SelectUsersPresenterArgs
import io.element.android.features.selectusers.api.aSelectUsersState
import io.element.android.features.selectusers.test.FakeSelectUserPresenter
import io.element.android.features.userlist.api.aUserListState
import io.element.android.features.userlist.test.FakeMatrixUserDataSource
import io.element.android.features.userlist.test.FakeUserListPresenter
import io.element.android.features.userlist.test.FakeUserListPresenterFactory
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId
@ -41,18 +41,17 @@ import org.junit.Test
class CreateRoomRootPresenterTests {
private lateinit var userListDataSource: FakeMatrixUserDataSource
private lateinit var presenter: CreateRoomRootPresenter
private lateinit var fakeSelectUsersPresenter: FakeSelectUserPresenter
private lateinit var fakeUserListPresenter: FakeUserListPresenter
private lateinit var fakeMatrixClient: FakeMatrixClient
@Before
fun setup() {
val factory = object : SelectUsersPresenter.Factory {
override fun create(args: SelectUsersPresenterArgs) = fakeSelectUsersPresenter
}
fakeSelectUsersPresenter = FakeSelectUserPresenter()
fakeUserListPresenter = FakeUserListPresenter()
fakeMatrixClient = FakeMatrixClient()
presenter = CreateRoomRootPresenter(factory, fakeMatrixClient)
userListDataSource = FakeMatrixUserDataSource()
presenter = CreateRoomRootPresenter(FakeUserListPresenterFactory(fakeUserListPresenter), userListDataSource, fakeMatrixClient)
}
@Test
@ -121,7 +120,7 @@ class CreateRoomRootPresenterTests {
val initialState = awaitItem()
val matrixUser = MatrixUser(UserId("@name:matrix.org"))
val createDmResult = Result.success(RoomId("!createDmResult"))
fakeSelectUsersPresenter.givenState(aSelectUsersState().copy(selectedUsers = persistentListOf(matrixUser)))
fakeUserListPresenter.givenState(aUserListState().copy(selectedUsers = persistentListOf(matrixUser)))
fakeMatrixClient.givenFindDmResult(null)
fakeMatrixClient.givenCreateDmError(A_THROWABLE)