Skip to content

Commit de16268

Browse files
authored
Merge pull request #5166 from element-hq/feature/fga/create_room_flow_rework
Create room flow rework
2 parents b05e8b7 + 58cc48c commit de16268

File tree

340 files changed

+2538
-1783
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

340 files changed

+2538
-1783
lines changed

.maestro/tests/roomList/createAndDeleteRoom.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@ appId: ${MAESTRO_APP_ID}
33
# Purpose: Test the creation and deletion of a room
44
- tapOn: "Create a new conversation or room"
55
- tapOn: "New room"
6-
- tapOn: "Search for someone"
7-
- inputText: ${MAESTRO_INVITEE1_MXID}
8-
- tapOn:
9-
text: ${MAESTRO_INVITEE1_MXID}
10-
index: 1
11-
- tapOn: "Next"
126
- tapOn: "e.g. your project name"
137
- inputText: "aRoomName"
148
- tapOn: "What is this room about?"
159
- inputText: "aRoomTopic"
1610
- tapOn: "Create"
1711
- takeScreenshot: build/maestro/320-createAndDeleteRoom
12+
- tapOn: "Search for someone"
13+
- inputText: ${MAESTRO_INVITEE1_MXID}
14+
- tapOn:
15+
text: ${MAESTRO_INVITEE1_MXID}
16+
index: 1
17+
- tapOn: "Finish"
1818
- tapOn: "aRoomName"
1919
- tapOn: "Invite"
2020
# assert there's 1 member and 1 invitee

appnav/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ dependencies {
6565
testImplementation(projects.features.rageshake.test)
6666
testImplementation(projects.services.appnavstate.test)
6767
testImplementation(projects.services.analytics.test)
68+
testImplementation(projects.services.toolbox.test)
6869
testImplementation(libs.test.appyx.junit)
6970
testImplementation(libs.test.arch.core)
7071
}

appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ import io.element.android.appnav.loggedin.SendQueues
4646
import io.element.android.appnav.room.RoomFlowNode
4747
import io.element.android.appnav.room.RoomNavigationTarget
4848
import io.element.android.appnav.room.joined.JoinedRoomLoadedFlowNode
49-
import io.element.android.features.createroom.api.CreateRoomEntryPoint
5049
import io.element.android.features.enterprise.api.SessionEnterpriseService
5150
import io.element.android.features.ftue.api.FtueEntryPoint
5251
import io.element.android.features.ftue.api.state.FtueService
@@ -60,6 +59,7 @@ import io.element.android.features.roomdirectory.api.RoomDescription
6059
import io.element.android.features.roomdirectory.api.RoomDirectoryEntryPoint
6160
import io.element.android.features.securebackup.api.SecureBackupEntryPoint
6261
import io.element.android.features.share.api.ShareEntryPoint
62+
import io.element.android.features.startchat.api.StartChatEntryPoint
6363
import io.element.android.features.userprofile.api.UserProfileEntryPoint
6464
import io.element.android.features.verifysession.api.IncomingVerificationEntryPoint
6565
import io.element.android.libraries.architecture.BackstackView
@@ -94,15 +94,6 @@ import java.time.Duration
9494
import java.time.Instant
9595
import java.util.Optional
9696
import java.util.UUID
97-
import kotlin.collections.List
98-
import kotlin.collections.any
99-
import kotlin.collections.emptyList
100-
import kotlin.collections.first
101-
import kotlin.collections.forEach
102-
import kotlin.collections.listOf
103-
import kotlin.collections.mapNotNull
104-
import kotlin.collections.plus
105-
import kotlin.collections.setOf
10697
import kotlin.time.Duration.Companion.minutes
10798
import kotlin.time.Duration.Companion.seconds
10899
import kotlin.time.toKotlinDuration
@@ -113,7 +104,7 @@ class LoggedInFlowNode @AssistedInject constructor(
113104
@Assisted plugins: List<Plugin>,
114105
private val homeEntryPoint: HomeEntryPoint,
115106
private val preferencesEntryPoint: PreferencesEntryPoint,
116-
private val createRoomEntryPoint: CreateRoomEntryPoint,
107+
private val startChatEntryPoint: StartChatEntryPoint,
117108
private val appNavigationStateService: AppNavigationStateService,
118109
private val secureBackupEntryPoint: SecureBackupEntryPoint,
119110
private val userProfileEntryPoint: UserProfileEntryPoint,
@@ -304,7 +295,7 @@ class LoggedInFlowNode @AssistedInject constructor(
304295
backstack.push(NavTarget.Settings())
305296
}
306297

307-
override fun onCreateRoomClick() {
298+
override fun onStartChatClick() {
308299
backstack.push(NavTarget.CreateRoom)
309300
}
310301

@@ -422,7 +413,7 @@ class LoggedInFlowNode @AssistedInject constructor(
422413
.build()
423414
}
424415
NavTarget.CreateRoom -> {
425-
val callback = object : CreateRoomEntryPoint.Callback {
416+
val callback = object : StartChatEntryPoint.Callback {
426417
override fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>) {
427418
backstack.replace(NavTarget.Room(roomIdOrAlias = roomIdOrAlias, serverNames = serverNames))
428419
}
@@ -432,7 +423,7 @@ class LoggedInFlowNode @AssistedInject constructor(
432423
}
433424
}
434425

435-
createRoomEntryPoint
426+
startChatEntryPoint
436427
.nodeBuilder(this, buildContext)
437428
.callback(callback)
438429
.build()

appnav/src/test/kotlin/io/element/android/appnav/RootPresenterTest.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import io.element.android.services.analytics.test.FakeAnalyticsService
1919
import io.element.android.services.apperror.api.AppErrorState
2020
import io.element.android.services.apperror.api.AppErrorStateService
2121
import io.element.android.services.apperror.impl.DefaultAppErrorStateService
22+
import io.element.android.services.toolbox.test.strings.FakeStringProvider
2223
import io.element.android.tests.testutils.WarmUpRule
2324
import kotlinx.coroutines.test.runTest
2425
import org.junit.Rule
@@ -42,7 +43,9 @@ class RootPresenterTest {
4243
@Test
4344
fun `present - passes app error state`() = runTest {
4445
val presenter = createRootPresenter(
45-
appErrorService = DefaultAppErrorStateService().apply {
46+
appErrorService = DefaultAppErrorStateService(
47+
stringProvider = FakeStringProvider(),
48+
).apply {
4649
showError("Bad news", "Something bad happened")
4750
}
4851
)
@@ -61,7 +64,9 @@ class RootPresenterTest {
6164
}
6265

6366
private fun createRootPresenter(
64-
appErrorService: AppErrorStateService = DefaultAppErrorStateService(),
67+
appErrorService: AppErrorStateService = DefaultAppErrorStateService(
68+
stringProvider = FakeStringProvider(),
69+
),
6570
): RootPresenter {
6671
return RootPresenter(
6772
crashDetectionPresenter = { aCrashDetectionState() },
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023, 2024 New Vector Ltd.
2+
* Copyright 2025 New Vector Ltd.
33
*
44
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
55
* Please see LICENSE files in the repository root for full details.
@@ -11,17 +11,17 @@ import com.bumble.appyx.core.modality.BuildContext
1111
import com.bumble.appyx.core.node.Node
1212
import com.bumble.appyx.core.plugin.Plugin
1313
import io.element.android.libraries.architecture.FeatureEntryPoint
14-
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
14+
import io.element.android.libraries.matrix.api.core.RoomId
1515

1616
interface CreateRoomEntryPoint : FeatureEntryPoint {
1717
fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder
18+
1819
interface NodeBuilder {
1920
fun callback(callback: Callback): NodeBuilder
2021
fun build(): Node
2122
}
2223

2324
interface Callback : Plugin {
24-
fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>)
25-
fun onOpenRoomDirectory()
25+
fun onRoomCreated(roomId: RoomId)
2626
}
2727
}

features/createroom/impl/build.gradle.kts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import extension.ComponentMergingStrategy
21
import extension.setupAnvil
32

43
/*
@@ -23,7 +22,7 @@ android {
2322
}
2423
}
2524

26-
setupAnvil(componentMergingStrategy = ComponentMergingStrategy.KSP)
25+
setupAnvil()
2726

2827
dependencies {
2928
implementation(projects.libraries.core)
@@ -41,6 +40,7 @@ dependencies {
4140
implementation(projects.services.analytics.api)
4241
implementation(libs.coil.compose)
4342
implementation(projects.libraries.featureflag.api)
43+
implementation(projects.features.invitepeople.api)
4444
api(projects.features.createroom.api)
4545

4646
testImplementation(libs.test.junit)
@@ -56,7 +56,7 @@ dependencies {
5656
testImplementation(projects.libraries.mediaupload.test)
5757
testImplementation(projects.libraries.permissions.test)
5858
testImplementation(projects.libraries.usersearch.test)
59-
testImplementation(projects.features.createroom.test)
59+
testImplementation(projects.features.startchat.test)
6060
testImplementation(projects.libraries.featureflag.test)
6161
testImplementation(projects.tests.testutils)
6262
testImplementation(libs.androidx.compose.ui.test.junit)

features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/ConfigureRoomFlowNode.kt

Lines changed: 0 additions & 83 deletions
This file was deleted.
Lines changed: 32 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023, 2024 New Vector Ltd.
2+
* Copyright 2025 New Vector Ltd.
33
*
44
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
55
* Please see LICENSE files in the repository root for full details.
@@ -8,28 +8,25 @@
88
package io.element.android.features.createroom.impl
99

1010
import android.os.Parcelable
11-
import androidx.compose.foundation.layout.Box
1211
import androidx.compose.runtime.Composable
13-
import androidx.compose.runtime.remember
1412
import androidx.compose.ui.Modifier
1513
import com.bumble.appyx.core.modality.BuildContext
16-
import com.bumble.appyx.core.navigation.transition.JumpToEndTransitionHandler
1714
import com.bumble.appyx.core.node.Node
1815
import com.bumble.appyx.core.plugin.Plugin
1916
import com.bumble.appyx.core.plugin.plugins
2017
import com.bumble.appyx.navmodel.backstack.BackStack
18+
import com.bumble.appyx.navmodel.backstack.operation.replace
2119
import dagger.assisted.Assisted
2220
import dagger.assisted.AssistedInject
2321
import io.element.android.anvilannotations.ContributesNode
24-
import io.element.android.features.createroom.DefaultCreateRoomNavigator
2522
import io.element.android.features.createroom.api.CreateRoomEntryPoint
26-
import io.element.android.features.createroom.impl.joinbyaddress.JoinRoomByAddressNode
27-
import io.element.android.features.createroom.impl.root.CreateRoomRootNode
23+
import io.element.android.features.createroom.impl.addpeople.AddPeopleNode
24+
import io.element.android.features.createroom.impl.configureroom.ConfigureRoomNode
2825
import io.element.android.libraries.architecture.BackstackView
2926
import io.element.android.libraries.architecture.BaseFlowNode
30-
import io.element.android.libraries.architecture.OverlayView
3127
import io.element.android.libraries.architecture.createNode
3228
import io.element.android.libraries.di.SessionScope
29+
import io.element.android.libraries.matrix.api.core.RoomId
3330
import kotlinx.parcelize.Parcelize
3431

3532
@ContributesNode(SessionScope::class)
@@ -38,53 +35,48 @@ class CreateRoomFlowNode @AssistedInject constructor(
3835
@Assisted plugins: List<Plugin>,
3936
) : BaseFlowNode<CreateRoomFlowNode.NavTarget>(
4037
backstack = BackStack(
41-
initialElement = NavTarget.Root,
38+
initialElement = NavTarget.ConfigureRoom,
4239
savedStateMap = buildContext.savedStateMap,
4340
),
4441
buildContext = buildContext,
4542
plugins = plugins
4643
) {
47-
sealed interface NavTarget : Parcelable {
48-
@Parcelize
49-
data object Root : NavTarget
50-
51-
@Parcelize
52-
data object NewRoom : NavTarget
53-
54-
@Parcelize
55-
data object JoinByAddress : NavTarget
44+
private fun onRoomCreated(roomId: RoomId) {
45+
plugins<CreateRoomEntryPoint.Callback>().forEach { it.onRoomCreated(roomId) }
5646
}
5747

58-
private val navigator = DefaultCreateRoomNavigator(
59-
backstack = backstack,
60-
overlay = overlay,
61-
openRoom = { roomIdOrAlias, viaServers ->
62-
plugins<CreateRoomEntryPoint.Callback>().forEach { it.onOpenRoom(roomIdOrAlias, viaServers) }
63-
},
64-
openRoomDirectory = {
65-
plugins<CreateRoomEntryPoint.Callback>().forEach { it.onOpenRoomDirectory() }
66-
}
67-
)
68-
6948
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
7049
return when (navTarget) {
71-
NavTarget.Root -> {
72-
createNode<CreateRoomRootNode>(buildContext = buildContext, plugins = listOf(navigator))
50+
NavTarget.ConfigureRoom -> {
51+
val callback = object : ConfigureRoomNode.Callback {
52+
override fun onCreateRoomSuccess(roomId: RoomId) {
53+
backstack.replace(NavTarget.AddPeople(roomId))
54+
}
55+
}
56+
createNode<ConfigureRoomNode>(buildContext, plugins = listOf(callback))
7357
}
74-
NavTarget.NewRoom -> {
75-
createNode<ConfigureRoomFlowNode>(buildContext = buildContext, plugins = listOf(navigator))
76-
}
77-
NavTarget.JoinByAddress -> {
78-
createNode<JoinRoomByAddressNode>(buildContext = buildContext, plugins = listOf(navigator))
58+
is NavTarget.AddPeople -> {
59+
val inputs = AddPeopleNode.Inputs(navTarget.roomId)
60+
val callback: AddPeopleNode.Callback = object : AddPeopleNode.Callback {
61+
override fun onFinish() {
62+
onRoomCreated(navTarget.roomId)
63+
}
64+
}
65+
createNode<AddPeopleNode>(buildContext, plugins = listOf(inputs, callback))
7966
}
8067
}
8168
}
8269

8370
@Composable
8471
override fun View(modifier: Modifier) {
85-
Box(modifier = modifier) {
86-
BackstackView()
87-
OverlayView(transitionHandler = remember { JumpToEndTransitionHandler() })
88-
}
72+
BackstackView()
73+
}
74+
75+
sealed interface NavTarget : Parcelable {
76+
@Parcelize
77+
data object ConfigureRoom : NavTarget
78+
79+
@Parcelize
80+
data class AddPeople(val roomId: RoomId) : NavTarget
8981
}
9082
}

0 commit comments

Comments
 (0)