Add an empty state for the space screen if the user can modify its graph (#6064)
* Add an empty state for the space screen if the user can modify its graph. It adds a new 'create room' button that allows you to open the create room screen with some preset values. * When computing the editable spaces in `ConfigureRoomPresenter`, also set up the initial selected parent space if possible * Use `Builder` pattern for `CreateRoomEntryPoint` * Update screenshots --------- Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
parent
fc8afab1bb
commit
6a9d084a50
31 changed files with 248 additions and 111 deletions
|
|
@ -484,7 +484,10 @@ class LoggedInFlowNode(
|
|||
backstack.replace(NavTarget.Room(roomIdOrAlias = RoomIdOrAlias.Id(roomId), serverNames = emptyList()))
|
||||
}
|
||||
}
|
||||
createRoomEntryPoint.createNode(isSpace = true, parentNode = this, buildContext = buildContext, callback = callback)
|
||||
createRoomEntryPoint
|
||||
.builder(parentNode = this, buildContext = buildContext, callback = callback)
|
||||
.setIsSpace(true)
|
||||
.build()
|
||||
}
|
||||
is NavTarget.SecureBackup -> {
|
||||
secureBackupEntryPoint.createNode(
|
||||
|
|
|
|||
|
|
@ -15,12 +15,13 @@ import io.element.android.libraries.architecture.FeatureEntryPoint
|
|||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
||||
interface CreateRoomEntryPoint : FeatureEntryPoint {
|
||||
fun createNode(
|
||||
isSpace: Boolean,
|
||||
parentNode: Node,
|
||||
buildContext: BuildContext,
|
||||
callback: Callback,
|
||||
): Node
|
||||
interface Builder {
|
||||
fun setIsSpace(isSpace: Boolean): Builder
|
||||
fun setParentSpace(parentSpaceId: RoomId): Builder
|
||||
fun build(): Node
|
||||
}
|
||||
|
||||
fun builder(parentNode: Node, buildContext: BuildContext, callback: Callback): Builder
|
||||
|
||||
interface Callback : Plugin {
|
||||
fun onRoomCreated(roomId: RoomId)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class CreateRoomFlowNode(
|
|||
@Assisted plugins: List<Plugin>,
|
||||
) : BaseFlowNode<CreateRoomFlowNode.NavTarget>(
|
||||
backstack = BackStack(
|
||||
initialElement = NavTarget.ConfigureRoom(isSpace = plugins.filterIsInstance<Inputs>().first().isSpace),
|
||||
initialElement = initialElementFromInputs(plugins.filterIsInstance<Inputs>().first()),
|
||||
savedStateMap = buildContext.savedStateMap,
|
||||
),
|
||||
buildContext = buildContext,
|
||||
|
|
@ -46,7 +46,8 @@ class CreateRoomFlowNode(
|
|||
) {
|
||||
@Parcelize
|
||||
data class Inputs(
|
||||
val isSpace: Boolean
|
||||
val isSpace: Boolean,
|
||||
val parentSpaceId: RoomId?,
|
||||
) : NodeInputs, Parcelable
|
||||
|
||||
private val callback: CreateRoomEntryPoint.Callback = callback()
|
||||
|
|
@ -54,7 +55,7 @@ class CreateRoomFlowNode(
|
|||
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
||||
return when (navTarget) {
|
||||
is NavTarget.ConfigureRoom -> {
|
||||
val inputs = ConfigureRoomNode.Inputs(isSpace = navTarget.isSpace)
|
||||
val inputs = ConfigureRoomNode.Inputs(isSpace = navTarget.isSpace, parentSpaceId = navTarget.parentSpaceId)
|
||||
val callback = object : ConfigureRoomNode.Callback {
|
||||
override fun onCreateRoomSuccess(roomId: RoomId) {
|
||||
backstack.replace(NavTarget.AddPeople(roomId))
|
||||
|
|
@ -81,9 +82,14 @@ class CreateRoomFlowNode(
|
|||
|
||||
sealed interface NavTarget : Parcelable {
|
||||
@Parcelize
|
||||
data class ConfigureRoom(val isSpace: Boolean) : NavTarget
|
||||
data class ConfigureRoom(val isSpace: Boolean, val parentSpaceId: RoomId?) : NavTarget
|
||||
|
||||
@Parcelize
|
||||
data class AddPeople(val roomId: RoomId) : NavTarget
|
||||
}
|
||||
}
|
||||
|
||||
private fun initialElementFromInputs(inputs: CreateRoomFlowNode.Inputs) = CreateRoomFlowNode.NavTarget.ConfigureRoom(
|
||||
isSpace = inputs.isSpace,
|
||||
parentSpaceId = inputs.parentSpaceId,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -14,16 +14,35 @@ import dev.zacsweers.metro.ContributesBinding
|
|||
import io.element.android.features.createroom.api.CreateRoomEntryPoint
|
||||
import io.element.android.libraries.architecture.createNode
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
||||
@ContributesBinding(SessionScope::class)
|
||||
class DefaultCreateRoomEntryPoint : CreateRoomEntryPoint {
|
||||
override fun createNode(
|
||||
isSpace: Boolean,
|
||||
parentNode: Node,
|
||||
buildContext: BuildContext,
|
||||
callback: CreateRoomEntryPoint.Callback,
|
||||
): Node {
|
||||
val inputs = CreateRoomFlowNode.Inputs(isSpace)
|
||||
class Builder(
|
||||
private val parentNode: Node,
|
||||
private val buildContext: BuildContext,
|
||||
private val callback: CreateRoomEntryPoint.Callback,
|
||||
) : CreateRoomEntryPoint.Builder {
|
||||
private var isSpace = false
|
||||
private var parentSpaceId: RoomId? = null
|
||||
|
||||
override fun setIsSpace(isSpace: Boolean): Builder {
|
||||
this.isSpace = isSpace
|
||||
return this
|
||||
}
|
||||
|
||||
override fun setParentSpace(parentSpaceId: RoomId): Builder {
|
||||
this.parentSpaceId = parentSpaceId
|
||||
return this
|
||||
}
|
||||
|
||||
override fun build(): Node {
|
||||
val inputs = CreateRoomFlowNode.Inputs(isSpace = isSpace, parentSpaceId = parentSpaceId)
|
||||
return parentNode.createNode<CreateRoomFlowNode>(buildContext, listOf(inputs, callback))
|
||||
}
|
||||
}
|
||||
|
||||
override fun builder(parentNode: Node, buildContext: BuildContext, callback: CreateRoomEntryPoint.Callback): CreateRoomEntryPoint.Builder {
|
||||
return Builder(parentNode, buildContext, callback)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,11 +42,12 @@ class ConfigureRoomNode(
|
|||
@Parcelize
|
||||
data class Inputs(
|
||||
val isSpace: Boolean,
|
||||
val parentSpaceId: RoomId?,
|
||||
) : NodeInputs, Parcelable
|
||||
|
||||
private val inputs = inputs<Inputs>()
|
||||
|
||||
private val presenter = presenterFactory.create(inputs.isSpace)
|
||||
private val presenter = presenterFactory.create(inputs.isSpace, inputs.parentSpaceId)
|
||||
|
||||
init {
|
||||
lifecycle.subscribe(
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ import kotlin.time.Duration.Companion.seconds
|
|||
@AssistedInject
|
||||
class ConfigureRoomPresenter(
|
||||
@Assisted private val isSpace: Boolean,
|
||||
@Assisted private val initialParentSpaceId: RoomId?,
|
||||
private val dataStore: CreateRoomConfigStore,
|
||||
private val matrixClient: MatrixClient,
|
||||
private val mediaPickerProvider: PickerProvider,
|
||||
|
|
@ -75,7 +76,7 @@ class ConfigureRoomPresenter(
|
|||
) : Presenter<ConfigureRoomState> {
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(isSpace: Boolean): ConfigureRoomPresenter
|
||||
fun create(isSpace: Boolean, parentSpaceId: RoomId?): ConfigureRoomPresenter
|
||||
}
|
||||
|
||||
private val cameraPermissionPresenter: PermissionsPresenter = permissionsPresenterFactory.create(android.Manifest.permission.CAMERA)
|
||||
|
|
@ -122,6 +123,9 @@ class ConfigureRoomPresenter(
|
|||
} else {
|
||||
persistentListOf()
|
||||
}
|
||||
|
||||
val parentSpace = spaces.find { it.roomId == initialParentSpaceId }
|
||||
parentSpace?.let { dataStore.setParentSpace(it) }
|
||||
}
|
||||
|
||||
LaunchedEffect(cameraPermissionState.permissionGranted) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
<string name="screen_create_room_name_placeholder">"Add name…"</string>
|
||||
<string name="screen_create_room_new_room_title">"New room"</string>
|
||||
<string name="screen_create_room_new_space_title">"New space"</string>
|
||||
<string name="screen_create_room_parent_space_home_description">"(no space)"</string>
|
||||
<string name="screen_create_room_parent_space_home_title">"Home"</string>
|
||||
<string name="screen_create_room_private_option_description">"Only people invited can join."</string>
|
||||
<string name="screen_create_room_private_option_title">"Private"</string>
|
||||
<string name="screen_create_room_public_option_description">"Anyone can find this room.
|
||||
|
|
|
|||
|
|
@ -532,6 +532,7 @@ class ConfigureRoomPresenterTest {
|
|||
|
||||
private fun createConfigureRoomPresenter(
|
||||
isSpace: Boolean = false,
|
||||
initialParenSpaceId: RoomId? = null,
|
||||
roomAliasHelper: RoomAliasHelper = FakeRoomAliasHelper(),
|
||||
dataStore: CreateRoomConfigStore = CreateRoomConfigStore(roomAliasHelper),
|
||||
matrixClient: MatrixClient = createMatrixClient(),
|
||||
|
|
@ -543,6 +544,7 @@ class ConfigureRoomPresenterTest {
|
|||
mediaOptimizationConfigProvider: FakeMediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(),
|
||||
) = ConfigureRoomPresenter(
|
||||
isSpace = isSpace,
|
||||
initialParentSpaceId = initialParenSpaceId,
|
||||
dataStore = dataStore,
|
||||
matrixClient = matrixClient,
|
||||
mediaPickerProvider = pickerProvider,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
|
|||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.createroom.api.CreateRoomEntryPoint
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
import io.element.android.tests.testutils.node.TestParentNode
|
||||
import org.junit.Rule
|
||||
|
|
@ -36,15 +37,16 @@ class DefaultCreateRoomEntryPointTest {
|
|||
plugins = plugins,
|
||||
)
|
||||
}
|
||||
val buildContext = BuildContext.root(null)
|
||||
|
||||
val callback = object : CreateRoomEntryPoint.Callback {
|
||||
override fun onRoomCreated(roomId: RoomId) = lambdaError()
|
||||
}
|
||||
val result = entryPoint.createNode(
|
||||
isSpace = false,
|
||||
parentNode = parentNode,
|
||||
buildContext = BuildContext.root(null),
|
||||
callback = callback,
|
||||
)
|
||||
val result = entryPoint
|
||||
.builder(parentNode, buildContext, callback)
|
||||
.setIsSpace(true)
|
||||
.setParentSpace(A_ROOM_ID)
|
||||
.build()
|
||||
assertThat(result.plugins).contains(callback)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,5 +16,6 @@ android {
|
|||
dependencies {
|
||||
implementation(projects.features.createroom.api)
|
||||
implementation(projects.libraries.architecture)
|
||||
implementation(projects.libraries.matrix.api)
|
||||
implementation(projects.tests.testutils)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,13 +10,19 @@ package io.element.android.features.createroom.api
|
|||
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
|
||||
class FakeCreateRoomEntryPoint : CreateRoomEntryPoint {
|
||||
override fun createNode(
|
||||
isSpace: Boolean,
|
||||
class Builder : CreateRoomEntryPoint.Builder {
|
||||
override fun setIsSpace(isSpace: Boolean): Builder = this
|
||||
override fun setParentSpace(parentSpaceId: RoomId): Builder = this
|
||||
override fun build(): Node = lambdaError()
|
||||
}
|
||||
|
||||
override fun builder(
|
||||
parentNode: Node,
|
||||
buildContext: BuildContext,
|
||||
callback: CreateRoomEntryPoint.Callback,
|
||||
): Node = lambdaError()
|
||||
): Builder = lambdaError()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ dependencies {
|
|||
implementation(projects.services.analytics.api)
|
||||
implementation(libs.coil.compose)
|
||||
implementation(projects.libraries.featureflag.api)
|
||||
implementation(projects.features.createroom.api)
|
||||
implementation(projects.features.invite.api)
|
||||
implementation(projects.libraries.previewutils)
|
||||
implementation(projects.features.securityandprivacy.api)
|
||||
|
|
@ -49,5 +50,6 @@ dependencies {
|
|||
testImplementation(projects.services.analytics.test)
|
||||
testImplementation(projects.libraries.matrix.test)
|
||||
testImplementation(projects.libraries.featureflag.test)
|
||||
testImplementation(projects.features.createroom.test)
|
||||
testImplementation(projects.features.invite.test)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import com.bumble.appyx.navmodel.backstack.operation.push
|
|||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.features.createroom.api.CreateRoomEntryPoint
|
||||
import io.element.android.features.space.api.SpaceEntryPoint
|
||||
import io.element.android.features.space.impl.addroom.AddRoomToSpaceNode
|
||||
import io.element.android.features.space.impl.di.SpaceFlowGraph
|
||||
|
|
@ -49,6 +50,7 @@ class SpaceFlowNode(
|
|||
room: JoinedRoom,
|
||||
spaceService: SpaceService,
|
||||
graphFactory: SpaceFlowGraph.Factory,
|
||||
private val createRoomEntryPoint: CreateRoomEntryPoint,
|
||||
) : BaseFlowNode<SpaceFlowNode.NavTarget>(
|
||||
backstack = BackStack(
|
||||
initialElement = NavTarget.Root,
|
||||
|
|
@ -71,6 +73,9 @@ class SpaceFlowNode(
|
|||
@Parcelize
|
||||
data object Leave : NavTarget
|
||||
|
||||
@Parcelize
|
||||
data object CreateRoom : NavTarget
|
||||
|
||||
@Parcelize
|
||||
data object AddRoom : NavTarget
|
||||
}
|
||||
|
|
@ -116,6 +121,10 @@ class SpaceFlowNode(
|
|||
backstack.push(NavTarget.Leave)
|
||||
}
|
||||
|
||||
override fun onCreateRoom() {
|
||||
backstack.push(NavTarget.CreateRoom)
|
||||
}
|
||||
|
||||
override fun navigateToAddRoom() {
|
||||
backstack.push(NavTarget.AddRoom)
|
||||
}
|
||||
|
|
@ -140,6 +149,21 @@ class SpaceFlowNode(
|
|||
}
|
||||
createNode<SpaceSettingsFlowNode>(buildContext, listOf(callback))
|
||||
}
|
||||
is NavTarget.CreateRoom -> {
|
||||
val callback = object : CreateRoomEntryPoint.Callback {
|
||||
override fun onRoomCreated(roomId: RoomId) {
|
||||
callback.navigateToRoom(roomId, emptyList())
|
||||
}
|
||||
}
|
||||
createRoomEntryPoint
|
||||
.builder(
|
||||
parentNode = this,
|
||||
buildContext = buildContext,
|
||||
callback = callback,
|
||||
)
|
||||
.setParentSpace(spaceRoomList.roomId)
|
||||
.build()
|
||||
}
|
||||
NavTarget.AddRoom -> {
|
||||
val callback = object : AddRoomToSpaceNode.Callback {
|
||||
override fun onFinish() {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ class SpaceNode(
|
|||
fun navigateToRoomMemberList()
|
||||
fun startLeaveSpaceFlow()
|
||||
fun navigateToAddRoom()
|
||||
|
||||
fun onCreateRoom()
|
||||
}
|
||||
|
||||
private val callback: Callback = callback()
|
||||
|
|
@ -105,6 +107,7 @@ class SpaceNode(
|
|||
modifier = Modifier
|
||||
)
|
||||
},
|
||||
onCreateRoomClick = callback::onCreateRoom,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ open class SpaceStateProvider : PreviewParameterProvider<SpaceState> {
|
|||
spaceInfo = aSpaceInfo(),
|
||||
children = aListOfSpaceRooms(),
|
||||
joiningRooms = setOf(RoomId("!spaceId0:example.com")),
|
||||
hasMoreToLoad = false
|
||||
hasMoreToLoad = true,
|
||||
),
|
||||
aSpaceState(
|
||||
topicViewerState = TopicViewerState.Shown(topic = "Space description goes here." + LoremIpsum(20).values.first()),
|
||||
|
|
@ -71,7 +71,7 @@ fun aSpaceState(
|
|||
joiningRooms: Set<RoomId> = emptySet(),
|
||||
joinActions: Map<RoomId, AsyncAction<Unit>> = joiningRooms.associateWith { AsyncAction.Loading },
|
||||
hideInvitesAvatar: Boolean = false,
|
||||
hasMoreToLoad: Boolean = true,
|
||||
hasMoreToLoad: Boolean = false,
|
||||
acceptDeclineInviteState: AcceptDeclineInviteState = anAcceptDeclineInviteState(),
|
||||
topicViewerState: TopicViewerState = TopicViewerState.Hidden,
|
||||
canAccessSpaceSettings: Boolean = true,
|
||||
|
|
|
|||
|
|
@ -50,7 +50,9 @@ import io.element.android.compound.theme.ElementTheme
|
|||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.features.space.impl.R
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.InviteButtonsRowMolecule
|
||||
import io.element.android.libraries.designsystem.components.BigIcon
|
||||
import io.element.android.libraries.designsystem.components.ClickableLinkText
|
||||
import io.element.android.libraries.designsystem.components.SimpleModalBottomSheet
|
||||
import io.element.android.libraries.designsystem.components.async.AsyncActionView
|
||||
|
|
@ -65,6 +67,7 @@ import io.element.android.libraries.designsystem.components.button.BackButton
|
|||
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||
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
|
||||
import io.element.android.libraries.designsystem.theme.components.Checkbox
|
||||
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||
import io.element.android.libraries.designsystem.theme.components.DropdownMenu
|
||||
|
|
@ -72,6 +75,7 @@ import io.element.android.libraries.designsystem.theme.components.DropdownMenuIt
|
|||
import io.element.android.libraries.designsystem.theme.components.HorizontalDivider
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||
import io.element.android.libraries.designsystem.theme.components.IconSource
|
||||
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
|
||||
|
|
@ -98,6 +102,7 @@ fun SpaceView(
|
|||
onLeaveSpaceClick: () -> Unit,
|
||||
onSettingsClick: () -> Unit,
|
||||
onViewMembersClick: () -> Unit,
|
||||
onCreateRoomClick: () -> Unit,
|
||||
onAddRoomClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
acceptDeclineInviteView: @Composable () -> Unit,
|
||||
|
|
@ -161,7 +166,8 @@ fun SpaceView(
|
|||
},
|
||||
onTopicClick = { topic ->
|
||||
state.eventSink(SpaceEvents.ShowTopicViewer(topic))
|
||||
}
|
||||
},
|
||||
onCreateRoomClick = onCreateRoomClick,
|
||||
)
|
||||
JoinFailuresEffect(
|
||||
hasAnyFailure = state.hasAnyJoinFailures,
|
||||
|
|
@ -234,6 +240,7 @@ private fun SpaceViewContent(
|
|||
state: SpaceState,
|
||||
onRoomClick: (spaceRoom: SpaceRoom) -> Unit,
|
||||
onTopicClick: (String) -> Unit,
|
||||
onCreateRoomClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
LazyColumn(modifier.fillMaxSize()) {
|
||||
|
|
@ -259,6 +266,12 @@ private fun SpaceViewContent(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state.children.isEmpty() && state.canEditSpaceGraph && !state.hasMoreToLoad) {
|
||||
item {
|
||||
EmptySpaceView(onCreateRoomClick = onCreateRoomClick)
|
||||
}
|
||||
} else {
|
||||
itemsIndexed(
|
||||
items = state.children,
|
||||
key = { _, spaceRoom -> spaceRoom.roomId }
|
||||
|
|
@ -306,12 +319,35 @@ private fun SpaceViewContent(
|
|||
HorizontalDivider()
|
||||
}
|
||||
}
|
||||
|
||||
if (state.hasMoreToLoad) {
|
||||
item {
|
||||
LoadingMoreIndicator(eventSink = state.eventSink)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EmptySpaceView(onCreateRoomClick: () -> Unit) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.padding(bottom = 24.dp),
|
||||
) {
|
||||
IconTitleSubtitleMolecule(
|
||||
title = stringResource(R.string.screen_space_empty_state_title),
|
||||
subTitle = null,
|
||||
iconStyle = BigIcon.Style.Default(CompoundIcons.Room()),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.padding(top = 40.dp, start = 24.dp, end = 24.dp, bottom = 24.dp),
|
||||
)
|
||||
Button(
|
||||
text = stringResource(R.string.screen_space_add_room_action),
|
||||
leadingIcon = IconSource.Vector(CompoundIcons.Plus()),
|
||||
onClick = onCreateRoomClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
@ -611,6 +647,7 @@ internal fun SpaceViewPreview(
|
|||
acceptDeclineInviteView = {},
|
||||
onSettingsClick = {},
|
||||
onViewMembersClick = {},
|
||||
onCreateRoomClick = {},
|
||||
onAddRoomClick = {},
|
||||
onBackClick = {},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
|||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.createroom.api.FakeCreateRoomEntryPoint
|
||||
import io.element.android.features.space.api.SpaceEntryPoint
|
||||
import io.element.android.features.space.impl.di.FakeSpaceFlowGraph
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
|
@ -43,7 +44,8 @@ class DefaultSpaceEntryPointTest {
|
|||
spaceRoomListResult = { _: RoomId -> FakeSpaceRoomList(A_ROOM_ID) }
|
||||
),
|
||||
room = FakeJoinedRoom(),
|
||||
graphFactory = FakeSpaceFlowGraph.Factory
|
||||
graphFactory = FakeSpaceFlowGraph.Factory,
|
||||
createRoomEntryPoint = FakeCreateRoomEntryPoint(),
|
||||
)
|
||||
}
|
||||
val callback = object : SpaceEntryPoint.Callback {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ 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.space.impl.R
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
|
||||
|
|
@ -30,6 +31,7 @@ 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.ensureCalledOnceWithParam
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.pressBack
|
||||
import io.element.android.tests.testutils.pressBackKey
|
||||
import org.junit.Rule
|
||||
|
|
@ -200,6 +202,22 @@ class SpaceViewTest {
|
|||
rule.clickOn(CommonStrings.action_remove, inDialog = true)
|
||||
eventsRecorder.assertSingle(SpaceEvents.ConfirmRoomRemoval)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking create room button calls the expected callback`() {
|
||||
val onCreateRoomClick = lambdaRecorder<Unit> { }
|
||||
rule.setSpaceView(
|
||||
aSpaceState(
|
||||
children = emptyList(),
|
||||
hasMoreToLoad = false,
|
||||
isManageMode = true,
|
||||
canManageRooms = true,
|
||||
),
|
||||
onCreateRoomClick = onCreateRoomClick,
|
||||
)
|
||||
rule.clickOn(R.string.screen_space_add_room_action)
|
||||
onCreateRoomClick.assertions().isCalledOnce()
|
||||
}
|
||||
}
|
||||
|
||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setSpaceView(
|
||||
|
|
@ -210,6 +228,7 @@ private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setSpace
|
|||
onLeaveSpaceClick: () -> Unit = EnsureNeverCalled(),
|
||||
onSettingsClick: () -> Unit = EnsureNeverCalled(),
|
||||
onViewMembersClick: () -> Unit = EnsureNeverCalled(),
|
||||
onCreateRoomClick: () -> Unit = EnsureNeverCalled(),
|
||||
onAddRoomClick: () -> Unit = EnsureNeverCalled(),
|
||||
acceptDeclineInviteView: @Composable () -> Unit = {},
|
||||
) {
|
||||
|
|
@ -224,6 +243,7 @@ private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setSpace
|
|||
onViewMembersClick = onViewMembersClick,
|
||||
onAddRoomClick = onAddRoomClick,
|
||||
acceptDeclineInviteView = acceptDeclineInviteView,
|
||||
onCreateRoomClick = onCreateRoomClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,12 +80,14 @@ class StartChatFlowNode(
|
|||
navigator.onRoomCreated(roomId.toRoomIdOrAlias(), emptyList())
|
||||
}
|
||||
}
|
||||
createRoomEntryPoint.createNode(
|
||||
isSpace = false,
|
||||
createRoomEntryPoint
|
||||
.builder(
|
||||
parentNode = this,
|
||||
buildContext = buildContext,
|
||||
callback = callback,
|
||||
)
|
||||
.setIsSpace(false)
|
||||
.build()
|
||||
}
|
||||
NavTarget.JoinByAddress -> {
|
||||
createNode<JoinRoomByAddressNode>(buildContext = buildContext, plugins = listOf(navigator))
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e59a9e2ae6ef36f28e61534b5639314cc840953df51bb1660e77e8d565865357
|
||||
size 32998
|
||||
oid sha256:6444cece1e3f5dfc94591380837fb8aa8caecdc4a87881485278c036accf2007
|
||||
size 40411
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b854ce2b0618ebcbc88eff9952d6869bceeb8b43f9eccb8f8e5feef225e0a4c2
|
||||
size 33181
|
||||
oid sha256:70e98028aafc62aeb86e69db82dce9b9bb0250d47339a81e8e832a0600d21217
|
||||
size 40588
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e1cf063ee5c9fbc50a53445050780ba239d4fb0fd1e9903a578eab8dd3bfc257
|
||||
size 33496
|
||||
oid sha256:a6a950c626b57f2624ce8929f61dfa2fcdc25036e0b3ebb5ec87a00e7531aea8
|
||||
size 40898
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:525059397001897f705630b8ac5a661439a502f2e623fdca252f9e86f97133e4
|
||||
size 58181
|
||||
oid sha256:778488da7192f2c3f98367d9d424783a42343a4bff8b7616f6175952526a8d30
|
||||
size 57766
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:59af097a2152b235c7df83aa76eea880ceef65edebebecb86f00745ec39712f4
|
||||
size 35937
|
||||
oid sha256:dbe04b9b4274183626f94d7014df9fc6462114226670161ffa3bb94b214b027e
|
||||
size 34283
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a5151bbd3effcd6a46724a0cfb13730e845a3b8ba489826146c76d0a797403e0
|
||||
size 36502
|
||||
oid sha256:b86c4e7011f15079e01e7aa8e8c26b94cffb4ef451b3374d3834641336d3d036
|
||||
size 34853
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:47c8bdf4d153ecebe749ae3cacfe4c9a1c59ac836106fb0903dca80305aedac2
|
||||
size 32412
|
||||
oid sha256:9b221b06e7533c21ed4393f388630c7119a1e7087b3a33de6c2cf498b01bbe65
|
||||
size 39544
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:33917297cb1c6d38e5b955757de50f4ff6b73844bb87e8e88d0885daa01b266b
|
||||
size 32556
|
||||
oid sha256:dd9b3d59af7fc710b7ef8f16ed961086693aa685de93658e2df85e3edbd7f787
|
||||
size 39689
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:930f763051533ea3aa4032e483e15e0c1ccb1d213d2e59bebe7f934517b500ba
|
||||
size 32868
|
||||
oid sha256:db27594444024da1818bbb089fac602b0937ad786072ad3542aa822e5a29c8c4
|
||||
size 40008
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:dd673c2cf628285836848a732d3972a17421a2394464a3a77e7a49e4c5a862f1
|
||||
size 56636
|
||||
oid sha256:21ec87536d892719f5343c0aacde2ed4be1a7d0987eff72675b03b4be5038f78
|
||||
size 56278
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b459fa8aa195dcf85995ac51c2f079e9d2505efede138bcef94c0a5049e1f271
|
||||
size 35266
|
||||
oid sha256:8c01095702c3ab147349f9b60729b534ec1763bc5c04e43b6d571a52a115e10a
|
||||
size 33634
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:36fd123fcff07169723857c99e4e375fe9bbb8193b2a6e97508343ea025d5787
|
||||
size 35782
|
||||
oid sha256:ae1a096a6de24c2c6517455cd632291ad9d3d45e16df02fa75c33f278e44b26e
|
||||
size 34149
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue