Merge pull request #324 from vector-im/feature/fre/create_room
Handle create room action
This commit is contained in:
@@ -199,7 +199,7 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||
}
|
||||
NavTarget.CreateRoom -> {
|
||||
val callback = object : CreateRoomEntryPoint.Callback {
|
||||
override fun onOpenRoom(roomId: RoomId) {
|
||||
override fun onSuccess(roomId: RoomId) {
|
||||
backstack.replace(NavTarget.Room(roomId))
|
||||
}
|
||||
}
|
||||
|
||||
1
changelog.d/111.feature
Normal file
1
changelog.d/111.feature
Normal file
@@ -0,0 +1 @@
|
||||
[Create and join rooms] Create a room and show it
|
||||
@@ -31,6 +31,6 @@ interface CreateRoomEntryPoint : FeatureEntryPoint {
|
||||
}
|
||||
|
||||
interface Callback : Plugin {
|
||||
fun onOpenRoom(roomId: RoomId)
|
||||
fun onSuccess(roomId: RoomId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,10 +76,10 @@ class ConfigureRoomFlowNode @AssistedInject constructor(
|
||||
backstack.push(NavTarget.ConfigureRoom)
|
||||
}
|
||||
}
|
||||
createNode<AddPeopleNode>(context = buildContext, plugins = listOf(callback))
|
||||
createNode<AddPeopleNode>(context = buildContext, plugins = plugins.plus(callback))
|
||||
}
|
||||
NavTarget.ConfigureRoom -> {
|
||||
createNode<ConfigureRoomNode>(context = buildContext)
|
||||
createNode<ConfigureRoomNode>(context = buildContext, plugins = plugins)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ 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.createroom.impl.configureroom.ConfigureRoomNode
|
||||
import io.element.android.features.createroom.impl.root.CreateRoomRootNode
|
||||
import io.element.android.libraries.architecture.BackstackNode
|
||||
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
||||
@@ -67,14 +68,19 @@ class CreateRoomFlowNode @AssistedInject constructor(
|
||||
backstack.push(NavTarget.NewRoom)
|
||||
}
|
||||
|
||||
override fun onOpenRoom(roomId: RoomId) {
|
||||
plugins<CreateRoomEntryPoint.Callback>().forEach { it.onOpenRoom(roomId) }
|
||||
override fun onStartChatSuccess(roomId: RoomId) {
|
||||
plugins<CreateRoomEntryPoint.Callback>().forEach { it.onSuccess(roomId) }
|
||||
}
|
||||
}
|
||||
createNode<CreateRoomRootNode>(context = buildContext, plugins = listOf(callback))
|
||||
}
|
||||
NavTarget.NewRoom -> {
|
||||
createNode<ConfigureRoomFlowNode>(context = buildContext, plugins = emptyList())
|
||||
val callback = object : ConfigureRoomNode.Callback {
|
||||
override fun onCreateRoomSuccess(roomId: RoomId) {
|
||||
plugins<CreateRoomEntryPoint.Callback>().forEach { it.onSuccess(roomId) }
|
||||
}
|
||||
}
|
||||
createNode<ConfigureRoomFlowNode>(context = buildContext, plugins = listOf(callback))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import android.net.Uri
|
||||
import io.element.android.features.createroom.impl.CreateRoomConfig
|
||||
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
||||
|
||||
sealed interface ConfigureRoomEvents {
|
||||
@@ -25,5 +26,6 @@ sealed interface ConfigureRoomEvents {
|
||||
data class AvatarUriChanged(val uri: Uri?) : ConfigureRoomEvents
|
||||
data class RoomPrivacyChanged(val privacy: RoomPrivacy?) : ConfigureRoomEvents
|
||||
data class RemoveFromSelection(val matrixUser: MatrixUser) : ConfigureRoomEvents
|
||||
object CreateRoom : ConfigureRoomEvents
|
||||
data class CreateRoom(val config: CreateRoomConfig) : ConfigureRoomEvents
|
||||
object CancelCreateRoom : ConfigureRoomEvents
|
||||
}
|
||||
|
||||
@@ -21,10 +21,12 @@ 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 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.libraries.matrix.api.core.RoomId
|
||||
|
||||
@ContributesNode(CreateRoomScope::class)
|
||||
class ConfigureRoomNode @AssistedInject constructor(
|
||||
@@ -33,13 +35,24 @@ class ConfigureRoomNode @AssistedInject constructor(
|
||||
private val presenter: ConfigureRoomPresenter,
|
||||
) : Node(buildContext, plugins = plugins) {
|
||||
|
||||
interface Callback : Plugin {
|
||||
fun onCreateRoomSuccess(roomId: RoomId)
|
||||
}
|
||||
|
||||
private val callback = object : Callback {
|
||||
override fun onCreateRoomSuccess(roomId: RoomId) {
|
||||
plugins<Callback>().forEach { it.onCreateRoomSuccess(roomId) }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
val state = presenter.present()
|
||||
ConfigureRoomView(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
onBackPressed = { navigateUp() } // TODO we should keep in memory the current view state
|
||||
onBackPressed = this::navigateUp,
|
||||
onRoomCreated = callback::onCreateRoomSuccess
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,17 +17,30 @@
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
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.impl.CreateRoomConfig
|
||||
import io.element.android.features.createroom.impl.CreateRoomDataStore
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.execute
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
|
||||
import io.element.android.libraries.matrix.api.createroom.RoomPreset
|
||||
import io.element.android.libraries.matrix.api.createroom.RoomVisibility
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class ConfigureRoomPresenter @Inject constructor(
|
||||
private val dataStore: CreateRoomDataStore,
|
||||
private val matrixClient: MatrixClient,
|
||||
) : Presenter<ConfigureRoomState> {
|
||||
|
||||
@Composable
|
||||
@@ -39,6 +52,14 @@ class ConfigureRoomPresenter @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
val localCoroutineScope = rememberCoroutineScope()
|
||||
val createRoomAction: MutableState<Async<RoomId>> = remember { mutableStateOf(Async.Uninitialized) }
|
||||
|
||||
fun createRoom(config: CreateRoomConfig) {
|
||||
createRoomAction.value = Async.Uninitialized
|
||||
localCoroutineScope.createRoom(config, createRoomAction)
|
||||
}
|
||||
|
||||
fun handleEvents(event: ConfigureRoomEvents) {
|
||||
when (event) {
|
||||
is ConfigureRoomEvents.AvatarUriChanged -> dataStore.setAvatarUrl(event.uri?.toString())
|
||||
@@ -46,14 +67,32 @@ class ConfigureRoomPresenter @Inject constructor(
|
||||
is ConfigureRoomEvents.TopicChanged -> dataStore.setTopic(event.topic)
|
||||
is ConfigureRoomEvents.RoomPrivacyChanged -> dataStore.setPrivacy(event.privacy)
|
||||
is ConfigureRoomEvents.RemoveFromSelection -> dataStore.selectedUserListDataStore.removeUserFromSelection(event.matrixUser)
|
||||
ConfigureRoomEvents.CreateRoom -> Unit // TODO
|
||||
is ConfigureRoomEvents.CreateRoom -> createRoom(event.config)
|
||||
ConfigureRoomEvents.CancelCreateRoom -> createRoomAction.value = Async.Uninitialized
|
||||
}
|
||||
}
|
||||
|
||||
return ConfigureRoomState(
|
||||
createRoomConfig.value,
|
||||
config = createRoomConfig.value,
|
||||
isCreateButtonEnabled = isCreateButtonEnabled,
|
||||
createRoomAction = createRoomAction.value,
|
||||
eventSink = ::handleEvents,
|
||||
)
|
||||
}
|
||||
|
||||
private fun CoroutineScope.createRoom(config: CreateRoomConfig, createRoomAction: MutableState<Async<RoomId>>) = launch {
|
||||
suspend {
|
||||
val params = CreateRoomParameters(
|
||||
name = config.roomName,
|
||||
topic = config.topic,
|
||||
isEncrypted = config.privacy == RoomPrivacy.Private,
|
||||
isDirect = false,
|
||||
visibility = if (config.privacy == RoomPrivacy.Public) RoomVisibility.PUBLIC else RoomVisibility.PRIVATE,
|
||||
preset = if (config.privacy == RoomPrivacy.Public) RoomPreset.PUBLIC_CHAT else RoomPreset.PRIVATE_CHAT,
|
||||
invite = config.invites.map { it.id },
|
||||
avatar = config.avatarUrl,
|
||||
)
|
||||
matrixClient.createRoom(params).getOrThrow()
|
||||
}.execute(createRoomAction)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,12 @@
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import io.element.android.features.createroom.impl.CreateRoomConfig
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
||||
data class ConfigureRoomState(
|
||||
val config: CreateRoomConfig,
|
||||
val isCreateButtonEnabled: Boolean,
|
||||
val createRoomAction: Async<RoomId>,
|
||||
val eventSink: (ConfigureRoomEvents) -> Unit
|
||||
)
|
||||
|
||||
@@ -19,6 +19,7 @@ package io.element.android.features.createroom.impl.configureroom
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.features.createroom.impl.CreateRoomConfig
|
||||
import io.element.android.features.userlist.api.aListOfSelectedUsers
|
||||
import io.element.android.libraries.architecture.Async
|
||||
|
||||
open class ConfigureRoomStateProvider : PreviewParameterProvider<ConfigureRoomState> {
|
||||
override val values: Sequence<ConfigureRoomState>
|
||||
@@ -39,5 +40,6 @@ open class ConfigureRoomStateProvider : PreviewParameterProvider<ConfigureRoomSt
|
||||
fun aConfigureRoomState() = ConfigureRoomState(
|
||||
config = CreateRoomConfig(),
|
||||
isCreateButtonEnabled = false,
|
||||
createRoomAction = Async.Uninitialized,
|
||||
eventSink = {}
|
||||
)
|
||||
|
||||
@@ -29,6 +29,7 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.selection.selectableGroup
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
@@ -44,13 +45,17 @@ import io.element.android.features.createroom.impl.components.Avatar
|
||||
import io.element.android.features.createroom.impl.components.LabelledTextField
|
||||
import io.element.android.features.createroom.impl.components.RoomPrivacyOption
|
||||
import io.element.android.features.userlist.api.components.SelectedUsersList
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.designsystem.components.ProgressDialog
|
||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||
import io.element.android.libraries.designsystem.components.dialogs.RetryDialog
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.CenterAlignedTopAppBar
|
||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.theme.components.TextButton
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.ui.strings.R as StringR
|
||||
|
||||
@Composable
|
||||
@@ -58,7 +63,14 @@ fun ConfigureRoomView(
|
||||
state: ConfigureRoomState,
|
||||
modifier: Modifier = Modifier,
|
||||
onBackPressed: () -> Unit = {},
|
||||
onRoomCreated: (RoomId) -> Unit = {},
|
||||
) {
|
||||
if (state.createRoomAction is Async.Success) {
|
||||
LaunchedEffect(state.createRoomAction) {
|
||||
onRoomCreated(state.createRoomAction.state)
|
||||
}
|
||||
}
|
||||
|
||||
val context = LocalContext.current
|
||||
Scaffold(
|
||||
modifier = modifier,
|
||||
@@ -67,8 +79,7 @@ fun ConfigureRoomView(
|
||||
isNextActionEnabled = state.isCreateButtonEnabled,
|
||||
onBackPressed = onBackPressed,
|
||||
onNextPressed = {
|
||||
// state.eventSink(ConfigureRoomEvents.CreateRoom)
|
||||
Toast.makeText(context, "not implemented yet", Toast.LENGTH_SHORT).show()
|
||||
state.eventSink(ConfigureRoomEvents.CreateRoom(state.config))
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -102,6 +113,20 @@ fun ConfigureRoomView(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
when (state.createRoomAction) {
|
||||
is Async.Loading -> {
|
||||
ProgressDialog(text = stringResource(StringR.string.common_creating_room))
|
||||
}
|
||||
is Async.Failure -> {
|
||||
RetryDialog(
|
||||
content = stringResource(R.string.screen_create_room_error_creating_room),
|
||||
onDismiss = { state.eventSink(ConfigureRoomEvents.CancelCreateRoom) },
|
||||
onRetry = { state.eventSink(ConfigureRoomEvents.CreateRoom(state.config)) },
|
||||
)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -37,7 +37,7 @@ class CreateRoomRootNode @AssistedInject constructor(
|
||||
|
||||
interface Callback : Plugin {
|
||||
fun onCreateNewRoom()
|
||||
fun onOpenRoom(roomId: RoomId)
|
||||
fun onStartChatSuccess(roomId: RoomId)
|
||||
}
|
||||
|
||||
private val callback = object : Callback {
|
||||
@@ -45,8 +45,8 @@ class CreateRoomRootNode @AssistedInject constructor(
|
||||
plugins<Callback>().forEach { it.onCreateNewRoom() }
|
||||
}
|
||||
|
||||
override fun onOpenRoom(roomId: RoomId) {
|
||||
plugins<Callback>().forEach { it.onOpenRoom(roomId) }
|
||||
override fun onStartChatSuccess(roomId: RoomId) {
|
||||
plugins<Callback>().forEach { it.onStartChatSuccess(roomId) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ class CreateRoomRootNode @AssistedInject constructor(
|
||||
modifier = modifier,
|
||||
onClosePressed = this::navigateUp,
|
||||
onNewRoomClicked = callback::onCreateNewRoom,
|
||||
onOpenDM = callback::onOpenRoom,
|
||||
onOpenDM = callback::onStartChatSuccess,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<string name="screen_create_room_action_create_room">"New room"</string>
|
||||
<string name="screen_create_room_action_invite_people">"Invite people"</string>
|
||||
<string name="screen_create_room_add_people_title">"Add people"</string>
|
||||
<string name="screen_create_room_error_creating_room">"An error occurred when creating the room"</string>
|
||||
<string name="screen_create_room_private_option_description">"Messages in this room are encrypted. Encryption can’t be disabled afterwards."</string>
|
||||
<string name="screen_create_room_private_option_title">"Private room (invite only)"</string>
|
||||
<string name="screen_create_room_public_option_description">"Messages are not encrypted and anyone can read them. You can enable encryption at a later date."</string>
|
||||
|
||||
@@ -26,9 +26,13 @@ import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.createroom.impl.CreateRoomConfig
|
||||
import io.element.android.features.createroom.impl.CreateRoomDataStore
|
||||
import io.element.android.features.userlist.api.UserListDataStore
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
|
||||
import io.element.android.libraries.matrix.test.A_MESSAGE
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
||||
import io.element.android.libraries.matrix.test.A_THROWABLE
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
@@ -44,11 +48,16 @@ class ConfigureRoomPresenterTests {
|
||||
|
||||
private lateinit var presenter: ConfigureRoomPresenter
|
||||
private lateinit var userListDataStore: UserListDataStore
|
||||
private lateinit var fakeMatrixClient: FakeMatrixClient
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
fakeMatrixClient = FakeMatrixClient()
|
||||
userListDataStore = UserListDataStore()
|
||||
presenter = ConfigureRoomPresenter(CreateRoomDataStore(userListDataStore))
|
||||
presenter = ConfigureRoomPresenter(
|
||||
dataStore = CreateRoomDataStore(userListDataStore),
|
||||
matrixClient = fakeMatrixClient
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -149,5 +158,54 @@ class ConfigureRoomPresenterTests {
|
||||
assertThat(newState.config).isEqualTo(expectedConfig)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - trigger create room action`() = runTest {
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
val createRoomResult = Result.success(RoomId("!createRoomResult"))
|
||||
|
||||
fakeMatrixClient.givenCreateRoomResult(createRoomResult)
|
||||
|
||||
initialState.eventSink(ConfigureRoomEvents.CreateRoom(initialState.config))
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Loading::class.java)
|
||||
val stateAfterCreateRoom = awaitItem()
|
||||
assertThat(stateAfterCreateRoom.createRoomAction).isInstanceOf(Async.Success::class.java)
|
||||
assertThat(stateAfterCreateRoom.createRoomAction.dataOrNull()).isEqualTo(createRoomResult.getOrNull())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - trigger retry and cancel actions`() = runTest {
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
val createRoomResult = Result.failure<RoomId>(A_THROWABLE)
|
||||
|
||||
fakeMatrixClient.givenCreateRoomResult(createRoomResult)
|
||||
|
||||
// Create
|
||||
initialState.eventSink(ConfigureRoomEvents.CreateRoom(initialState.config))
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Loading::class.java)
|
||||
val stateAfterCreateRoom = awaitItem()
|
||||
assertThat(stateAfterCreateRoom.createRoomAction).isInstanceOf(Async.Failure::class.java)
|
||||
assertThat((stateAfterCreateRoom.createRoomAction as? Async.Failure)?.error).isEqualTo(createRoomResult.exceptionOrNull())
|
||||
|
||||
// Retry
|
||||
stateAfterCreateRoom.eventSink(ConfigureRoomEvents.CreateRoom(initialState.config))
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Uninitialized::class.java)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Loading::class.java)
|
||||
val stateAfterRetry = awaitItem()
|
||||
assertThat(stateAfterRetry.createRoomAction).isInstanceOf(Async.Failure::class.java)
|
||||
assertThat((stateAfterRetry.createRoomAction as? Async.Failure)?.error).isEqualTo(createRoomResult.exceptionOrNull())
|
||||
|
||||
// Cancel
|
||||
stateAfterRetry.eventSink(ConfigureRoomEvents.CancelCreateRoom)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Uninitialized::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
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.core.asRoomId
|
||||
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
|
||||
import io.element.android.libraries.matrix.api.createroom.RoomPreset
|
||||
import io.element.android.libraries.matrix.api.createroom.RoomVisibility
|
||||
@@ -40,9 +41,12 @@ import io.element.android.libraries.matrix.impl.verification.RustSessionVerifica
|
||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import org.matrix.rustcomponents.sdk.Client
|
||||
import org.matrix.rustcomponents.sdk.ClientDelegate
|
||||
import org.matrix.rustcomponents.sdk.RequiredState
|
||||
@@ -180,43 +184,44 @@ class RustMatrixClient constructor(
|
||||
|
||||
override suspend fun createRoom(createRoomParams: CreateRoomParameters): Result<RoomId> = withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
val roomId = client.createRoom(
|
||||
RustCreateRoomParameters(
|
||||
name = createRoomParams.name,
|
||||
topic = createRoomParams.topic,
|
||||
isEncrypted = createRoomParams.isEncrypted,
|
||||
isDirect = createRoomParams.isDirect,
|
||||
visibility = when (createRoomParams.visibility) {
|
||||
RoomVisibility.PUBLIC -> RustRoomVisibility.PUBLIC
|
||||
RoomVisibility.PRIVATE -> RustRoomVisibility.PRIVATE
|
||||
},
|
||||
preset = when (createRoomParams.preset) {
|
||||
RoomPreset.PRIVATE_CHAT -> RustRoomPreset.PRIVATE_CHAT
|
||||
RoomPreset.PUBLIC_CHAT -> RustRoomPreset.PUBLIC_CHAT
|
||||
RoomPreset.TRUSTED_PRIVATE_CHAT -> RustRoomPreset.TRUSTED_PRIVATE_CHAT
|
||||
},
|
||||
invite = createRoomParams.invite?.map { it.value },
|
||||
avatar = createRoomParams.avatar,
|
||||
)
|
||||
val rustParams = RustCreateRoomParameters(
|
||||
name = createRoomParams.name,
|
||||
topic = createRoomParams.topic,
|
||||
isEncrypted = createRoomParams.isEncrypted,
|
||||
isDirect = createRoomParams.isDirect,
|
||||
visibility = when (createRoomParams.visibility) {
|
||||
RoomVisibility.PUBLIC -> RustRoomVisibility.PUBLIC
|
||||
RoomVisibility.PRIVATE -> RustRoomVisibility.PRIVATE
|
||||
},
|
||||
preset = when (createRoomParams.preset) {
|
||||
RoomPreset.PRIVATE_CHAT -> RustRoomPreset.PRIVATE_CHAT
|
||||
RoomPreset.PUBLIC_CHAT -> RustRoomPreset.PUBLIC_CHAT
|
||||
RoomPreset.TRUSTED_PRIVATE_CHAT -> RustRoomPreset.TRUSTED_PRIVATE_CHAT
|
||||
},
|
||||
invite = createRoomParams.invite?.map { it.value },
|
||||
avatar = createRoomParams.avatar,
|
||||
)
|
||||
RoomId(roomId)
|
||||
val roomId = client.createRoom(rustParams).asRoomId()
|
||||
|
||||
// Wait to receive the room back from the sync
|
||||
withTimeout(30_000L) {
|
||||
slidingSyncObserverProxy.updateSummaryFlow.filter { roomId.value in it.rooms }.first()
|
||||
}
|
||||
|
||||
roomId
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun createDM(userId: UserId): Result<RoomId> = withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
val roomId = client.createRoom(
|
||||
RustCreateRoomParameters(
|
||||
name = null,
|
||||
isEncrypted = true,
|
||||
isDirect = true,
|
||||
visibility = RustRoomVisibility.PRIVATE,
|
||||
preset = RustRoomPreset.TRUSTED_PRIVATE_CHAT,
|
||||
invite = listOf(userId.value),
|
||||
)
|
||||
)
|
||||
RoomId(roomId)
|
||||
}
|
||||
override suspend fun createDM(userId: UserId): Result<RoomId> {
|
||||
val createRoomParams = CreateRoomParameters(
|
||||
name = null,
|
||||
isEncrypted = true,
|
||||
isDirect = true,
|
||||
visibility = RoomVisibility.PRIVATE,
|
||||
preset = RoomPreset.TRUSTED_PRIVATE_CHAT,
|
||||
invite = listOf(userId)
|
||||
)
|
||||
return createRoom(createRoomParams)
|
||||
}
|
||||
|
||||
override fun mediaResolver(): MediaResolver = mediaResolver
|
||||
@@ -321,3 +326,4 @@ class RustMatrixClient constructor(
|
||||
return sessionDirectory.deleteRecursively()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ class FakeMatrixClient(
|
||||
private val notificationService: FakeNotificationService = FakeNotificationService(),
|
||||
) : MatrixClient {
|
||||
|
||||
private var createRoomResult: Result<RoomId> = Result.success(A_ROOM_ID)
|
||||
private var createDmResult: Result<RoomId> = Result.success(A_ROOM_ID)
|
||||
private var createDmFailure: Throwable? = null
|
||||
private var findDmResult: MatrixRoom? = FakeMatrixRoom()
|
||||
@@ -61,7 +62,7 @@ class FakeMatrixClient(
|
||||
|
||||
override suspend fun createRoom(createRoomParams: CreateRoomParameters): Result<RoomId> {
|
||||
delay(100)
|
||||
return Result.success(A_ROOM_ID)
|
||||
return createRoomResult
|
||||
}
|
||||
|
||||
override suspend fun createDM(userId: UserId): Result<RoomId> {
|
||||
@@ -119,6 +120,10 @@ class FakeMatrixClient(
|
||||
logoutFailure = failure
|
||||
}
|
||||
|
||||
fun givenCreateRoomResult(result: Result<RoomId>) {
|
||||
createRoomResult = result
|
||||
}
|
||||
|
||||
fun givenCreateDmResult(result: Result<RoomId>) {
|
||||
createDmResult = result
|
||||
}
|
||||
|
||||
@@ -121,60 +121,15 @@
|
||||
<string name="leave_room_alert_private_subtitle">"Are you sure that you want to leave this room? This room is not public and you will not be able to rejoin without an invite."</string>
|
||||
<string name="leave_room_alert_subtitle">"Are you sure that you want to leave the room?"</string>
|
||||
<string name="login_initial_device_name_android">"%1$s Android"</string>
|
||||
<string name="notification_channel_call">"Call"</string>
|
||||
<string name="notification_channel_listening_for_events">"Listening for events"</string>
|
||||
<string name="notification_channel_noisy">"Noisy notifications"</string>
|
||||
<string name="notification_channel_silent">"Silent notifications"</string>
|
||||
<string name="notification_inline_reply_failed">"** Failed to send - please open room"</string>
|
||||
<string name="notification_invitation_action_join">"Join"</string>
|
||||
<string name="notification_invitation_action_reject">"Reject"</string>
|
||||
<string name="notification_new_messages">"New Messages"</string>
|
||||
<string name="notification_room_action_mark_as_read">"Mark as read"</string>
|
||||
<string name="notification_room_action_quick_reply">"Quick reply"</string>
|
||||
<string name="notification_sender_me">"Me"</string>
|
||||
<string name="notification_test_push_notification_content">"You are viewing the notification! Click me!"</string>
|
||||
<string name="notification_ticker_text_dm">"%1$s: %2$s"</string>
|
||||
<string name="notification_ticker_text_group">"%1$s: %2$s %3$s"</string>
|
||||
<string name="notification_unread_notified_messages_and_invitation">"%1$s and %2$s"</string>
|
||||
<string name="notification_unread_notified_messages_in_room">"%1$s in %2$s"</string>
|
||||
<string name="notification_unread_notified_messages_in_room_and_invitation">"%1$s in %2$s and %3$s"</string>
|
||||
<plurals name="common_member_count">
|
||||
<item quantity="one">"%1$d member"</item>
|
||||
<item quantity="other">"%1$d members"</item>
|
||||
</plurals>
|
||||
<plurals name="notification_compat_summary_line_for_room">
|
||||
<item quantity="one">"%1$s: %2$d message"</item>
|
||||
<item quantity="other">"%1$s: %2$d messages"</item>
|
||||
</plurals>
|
||||
<plurals name="notification_compat_summary_title">
|
||||
<item quantity="one">"%d notification"</item>
|
||||
<item quantity="other">"%d notifications"</item>
|
||||
</plurals>
|
||||
<plurals name="notification_invitations">
|
||||
<item quantity="one">"%d invitation"</item>
|
||||
<item quantity="other">"%d invitations"</item>
|
||||
</plurals>
|
||||
<plurals name="notification_new_messages_for_room">
|
||||
<item quantity="one">"%d new message"</item>
|
||||
<item quantity="other">"%d new messages"</item>
|
||||
</plurals>
|
||||
<plurals name="notification_unread_notified_messages">
|
||||
<item quantity="one">"%d unread notified message"</item>
|
||||
<item quantity="other">"%d unread notified messages"</item>
|
||||
</plurals>
|
||||
<plurals name="notification_unread_notified_messages_in_room_rooms">
|
||||
<item quantity="one">"%d room"</item>
|
||||
<item quantity="other">"%d rooms"</item>
|
||||
</plurals>
|
||||
<plurals name="room_timeline_state_changes">
|
||||
<item quantity="one">"%1$d room change"</item>
|
||||
<item quantity="other">"%1$d room changes"</item>
|
||||
</plurals>
|
||||
<string name="preference_rageshake">"Rageshake to report bug"</string>
|
||||
<string name="push_choose_distributor_dialog_title_android">"Choose how to receive notifications"</string>
|
||||
<string name="push_distributor_background_sync_android">"Background synchronization"</string>
|
||||
<string name="push_distributor_firebase_android">"Google Services"</string>
|
||||
<string name="push_no_valid_google_play_services_apk_android">"No valid Google Play Services found. Notifications may not work properly."</string>
|
||||
<string name="rageshake_dialog_content">"You seem to be shaking the phone in frustration. Would you like to open the bug report screen?"</string>
|
||||
<string name="report_content_explanation">"This message will be reported to your homeserver’s administrator. They will not be able to read any encrypted messages."</string>
|
||||
<string name="report_content_hint">"Reason for reporting this content"</string>
|
||||
|
||||
Reference in New Issue
Block a user