feat(join by alias) : introduce the JoinRoomByAddress
This commit is contained in:
parent
12c0465d2a
commit
f1c5fa53e8
10 changed files with 355 additions and 1 deletions
|
|
@ -19,10 +19,13 @@ import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
||||||
interface CreateRoomNavigator : Plugin {
|
interface CreateRoomNavigator : Plugin {
|
||||||
fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias)
|
fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias)
|
||||||
fun onCreateNewRoom()
|
fun onCreateNewRoom()
|
||||||
|
fun onShowJoinRoomByAddress()
|
||||||
|
fun onDismissJoinRoomByAddress()
|
||||||
}
|
}
|
||||||
|
|
||||||
class DefaultCreateRoomNavigator(
|
class DefaultCreateRoomNavigator(
|
||||||
private val backstack: BackStack<NavTarget>,
|
private val backstack: BackStack<NavTarget>,
|
||||||
|
private val overlay: Overlay<NavTarget>,
|
||||||
private val openRoom: (RoomIdOrAlias) -> Unit,
|
private val openRoom: (RoomIdOrAlias) -> Unit,
|
||||||
) : CreateRoomNavigator {
|
) : CreateRoomNavigator {
|
||||||
|
|
||||||
|
|
@ -32,4 +35,11 @@ class DefaultCreateRoomNavigator(
|
||||||
backstack.push(NavTarget.NewRoom)
|
backstack.push(NavTarget.NewRoom)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onShowJoinRoomByAddress() {
|
||||||
|
overlay.show(NavTarget.JoinByAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDismissJoinRoomByAddress() {
|
||||||
|
overlay.hide()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
package io.element.android.features.createroom.impl
|
package io.element.android.features.createroom.impl
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -22,9 +23,11 @@ import dagger.assisted.AssistedInject
|
||||||
import io.element.android.anvilannotations.ContributesNode
|
import io.element.android.anvilannotations.ContributesNode
|
||||||
import io.element.android.features.createroom.DefaultCreateRoomNavigator
|
import io.element.android.features.createroom.DefaultCreateRoomNavigator
|
||||||
import io.element.android.features.createroom.api.CreateRoomEntryPoint
|
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.root.CreateRoomRootNode
|
||||||
import io.element.android.libraries.architecture.BackstackView
|
import io.element.android.libraries.architecture.BackstackView
|
||||||
import io.element.android.libraries.architecture.BaseFlowNode
|
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.architecture.createNode
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
|
@ -50,10 +53,13 @@ class CreateRoomFlowNode @AssistedInject constructor(
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data object NewRoom : NavTarget
|
data object NewRoom : NavTarget
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data object JoinByAddress : NavTarget
|
||||||
}
|
}
|
||||||
|
|
||||||
private val navigator = DefaultCreateRoomNavigator(
|
private val navigator = DefaultCreateRoomNavigator(
|
||||||
backstack = backstack,
|
backstack = backstack,
|
||||||
|
overlay = overlay,
|
||||||
openRoom = { roomIdOrAlias ->
|
openRoom = { roomIdOrAlias ->
|
||||||
plugins<CreateRoomEntryPoint.Callback>().forEach { it.onOpenRoom(roomIdOrAlias) }
|
plugins<CreateRoomEntryPoint.Callback>().forEach { it.onOpenRoom(roomIdOrAlias) }
|
||||||
}
|
}
|
||||||
|
|
@ -67,11 +73,17 @@ class CreateRoomFlowNode @AssistedInject constructor(
|
||||||
NavTarget.NewRoom -> {
|
NavTarget.NewRoom -> {
|
||||||
createNode<ConfigureRoomFlowNode>(buildContext = buildContext, plugins = listOf(navigator))
|
createNode<ConfigureRoomFlowNode>(buildContext = buildContext, plugins = listOf(navigator))
|
||||||
}
|
}
|
||||||
|
NavTarget.JoinByAddress -> {
|
||||||
|
createNode<JoinRoomByAddressNode>(buildContext = buildContext, plugins = listOf(navigator))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun View(modifier: Modifier) {
|
override fun View(modifier: Modifier) {
|
||||||
BackstackView()
|
Box(modifier = modifier) {
|
||||||
|
BackstackView()
|
||||||
|
OverlayView(transitionHandler = remember { JumpToEndTransitionHandler() })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.createroom.impl.joinbyaddress
|
||||||
|
|
||||||
|
sealed interface JoinRoomByAddressEvents {
|
||||||
|
data object Dismiss : JoinRoomByAddressEvents
|
||||||
|
data object Continue: JoinRoomByAddressEvents
|
||||||
|
data class UpdateAddress(val address: String) : JoinRoomByAddressEvents
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* 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.joinbyaddress
|
||||||
|
|
||||||
|
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 dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import io.element.android.anvilannotations.ContributesNode
|
||||||
|
import io.element.android.features.createroom.CreateRoomNavigator
|
||||||
|
import io.element.android.libraries.di.SessionScope
|
||||||
|
|
||||||
|
@ContributesNode(SessionScope::class)
|
||||||
|
class JoinRoomByAddressNode @AssistedInject constructor(
|
||||||
|
@Assisted buildContext: BuildContext,
|
||||||
|
@Assisted plugins: List<Plugin>,
|
||||||
|
presenterFactory: JoinRoomByAddressPresenter.Factory,
|
||||||
|
) : Node(buildContext, plugins = plugins) {
|
||||||
|
|
||||||
|
private val navigator = plugins<CreateRoomNavigator>().first()
|
||||||
|
private val presenter = presenterFactory.create(navigator)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun View(modifier: Modifier) {
|
||||||
|
val state = presenter.present()
|
||||||
|
JoinRoomByAddressView(
|
||||||
|
state = state,
|
||||||
|
modifier = modifier
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* 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.joinbyaddress
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberUpdatedState
|
||||||
|
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.libraries.architecture.Presenter
|
||||||
|
import io.element.android.libraries.core.data.tryOrNull
|
||||||
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
|
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||||
|
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
||||||
|
import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
|
class JoinRoomByAddressPresenter @AssistedInject constructor(
|
||||||
|
@Assisted private val navigator: CreateRoomNavigator,
|
||||||
|
private val client: MatrixClient,
|
||||||
|
private val roomAliasHelper: RoomAliasHelper,
|
||||||
|
) : Presenter<JoinRoomByAddressState> {
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface Factory {
|
||||||
|
fun create(navigator: CreateRoomNavigator): JoinRoomByAddressPresenter
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun present(): JoinRoomByAddressState {
|
||||||
|
var address by remember { mutableStateOf("") }
|
||||||
|
var addressState by remember { mutableStateOf<RoomAddressState>(RoomAddressState.Unknown) }
|
||||||
|
|
||||||
|
fun handleEvents(event: JoinRoomByAddressEvents) {
|
||||||
|
when (event) {
|
||||||
|
JoinRoomByAddressEvents.Continue -> {
|
||||||
|
navigator.onDismissJoinRoomByAddress()
|
||||||
|
navigator.onOpenRoom(RoomIdOrAlias.Alias(RoomAlias(address)))
|
||||||
|
}
|
||||||
|
JoinRoomByAddressEvents.Dismiss -> navigator.onDismissJoinRoomByAddress()
|
||||||
|
is JoinRoomByAddressEvents.UpdateAddress -> {
|
||||||
|
address = event.address.trim()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomAddressStateEffect(
|
||||||
|
fullAddress = address,
|
||||||
|
onRoomAddressStateChange = { addressState = it }
|
||||||
|
)
|
||||||
|
|
||||||
|
return JoinRoomByAddressState(
|
||||||
|
address = address,
|
||||||
|
addressState = addressState,
|
||||||
|
eventSink = ::handleEvents
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun RoomAddressStateEffect(
|
||||||
|
fullAddress: String,
|
||||||
|
onRoomAddressStateChange: (RoomAddressState) -> Unit,
|
||||||
|
) {
|
||||||
|
val onChange by rememberUpdatedState(onRoomAddressStateChange)
|
||||||
|
LaunchedEffect(fullAddress) {
|
||||||
|
if (fullAddress.isEmpty()) {
|
||||||
|
onChange(RoomAddressState.Unknown)
|
||||||
|
return@LaunchedEffect
|
||||||
|
}
|
||||||
|
// debounce the room address validation
|
||||||
|
delay(300)
|
||||||
|
val roomAlias = tryOrNull { RoomAlias(fullAddress) }
|
||||||
|
if (roomAlias == null || !roomAliasHelper.isRoomAliasValid(roomAlias)) {
|
||||||
|
onChange(RoomAddressState.Invalid)
|
||||||
|
} else {
|
||||||
|
onChange(RoomAddressState.Valid(matchingRoomFound = false))
|
||||||
|
client.resolveRoomAlias(roomAlias)
|
||||||
|
.onSuccess { resolved ->
|
||||||
|
onChange(RoomAddressState.Valid(matchingRoomFound = resolved.isPresent))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* 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.joinbyaddress
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
|
||||||
|
data class JoinRoomByAddressState(
|
||||||
|
val address: String,
|
||||||
|
val addressState: RoomAddressState,
|
||||||
|
val eventSink: (JoinRoomByAddressEvents) -> Unit
|
||||||
|
)
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
sealed interface RoomAddressState {
|
||||||
|
data object Unknown : RoomAddressState
|
||||||
|
data object Invalid : RoomAddressState
|
||||||
|
data class Valid(val matchingRoomFound: Boolean) : RoomAddressState
|
||||||
|
}
|
||||||
|
|
@ -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.createroom.impl.joinbyaddress
|
||||||
|
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
|
|
||||||
|
open class JoinRoomByAddressStateProvider : PreviewParameterProvider<JoinRoomByAddressState> {
|
||||||
|
override val values: Sequence<JoinRoomByAddressState>
|
||||||
|
get() = sequenceOf(
|
||||||
|
aJoinRoomByAddressState(),
|
||||||
|
aJoinRoomByAddressState("#room-"),
|
||||||
|
aJoinRoomByAddressState("#room-", addressState = RoomAddressState.Invalid),
|
||||||
|
aJoinRoomByAddressState("#room-name:matrix.org", addressState = RoomAddressState.Valid(true)),
|
||||||
|
aJoinRoomByAddressState("#room-name-here:matrix.org", addressState = RoomAddressState.Valid(false)),
|
||||||
|
// Add other states here
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun aJoinRoomByAddressState(
|
||||||
|
address: String = "",
|
||||||
|
addressState: RoomAddressState = RoomAddressState.Unknown,
|
||||||
|
) = JoinRoomByAddressState(
|
||||||
|
address = address,
|
||||||
|
addressState = addressState,
|
||||||
|
eventSink = {}
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* 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.joinbyaddress
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
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.ModalBottomSheet
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.TextField
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun JoinRoomByAddressView(
|
||||||
|
state: JoinRoomByAddressState,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||||
|
ModalBottomSheet(
|
||||||
|
modifier = modifier,
|
||||||
|
sheetState = sheetState,
|
||||||
|
onDismissRequest = {
|
||||||
|
state.eventSink(JoinRoomByAddressEvents.Dismiss)
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(all = 16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
RoomAddressField(
|
||||||
|
address = state.address,
|
||||||
|
addressState = state.addressState,
|
||||||
|
requestFocus = sheetState.isVisible,
|
||||||
|
onAddressChange = {
|
||||||
|
state.eventSink(JoinRoomByAddressEvents.UpdateAddress(it))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
Button(
|
||||||
|
text = stringResource(CommonStrings.action_continue),
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
enabled = state.addressState is RoomAddressState.Valid,
|
||||||
|
onClick = {
|
||||||
|
state.eventSink(JoinRoomByAddressEvents.Continue)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun RoomAddressField(
|
||||||
|
address: String,
|
||||||
|
addressState: RoomAddressState,
|
||||||
|
requestFocus: Boolean,
|
||||||
|
onAddressChange: (String) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
val focusRequester = remember { FocusRequester() }
|
||||||
|
if (requestFocus) {
|
||||||
|
LaunchedEffect(Unit) { focusRequester.requestFocus() }
|
||||||
|
}
|
||||||
|
TextField(
|
||||||
|
modifier = modifier.focusRequester(focusRequester),
|
||||||
|
value = address,
|
||||||
|
label = "Join room by address",
|
||||||
|
placeholder = "Enter...",
|
||||||
|
supportingText = when (addressState) {
|
||||||
|
RoomAddressState.Invalid -> "Not a valid address"
|
||||||
|
RoomAddressState.Unknown -> "e.g. #room-name:matrix.org"
|
||||||
|
is RoomAddressState.Valid -> if (addressState.matchingRoomFound) {
|
||||||
|
"Matching room found"
|
||||||
|
} else {
|
||||||
|
"e.g. #room-name:matrix.org"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isError = addressState is RoomAddressState.Invalid,
|
||||||
|
onValueChange = onAddressChange,
|
||||||
|
singleLine = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreviewsDayNight
|
||||||
|
@Composable
|
||||||
|
internal fun JoinRoomByAddressViewPreview(
|
||||||
|
@PreviewParameter(JoinRoomByAddressStateProvider::class) state: JoinRoomByAddressState
|
||||||
|
) = ElementPreview {
|
||||||
|
JoinRoomByAddressView(state = state)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -55,6 +55,7 @@ class CreateRoomRootNode @AssistedInject constructor(
|
||||||
onOpenDM = {
|
onOpenDM = {
|
||||||
navigator.onOpenRoom(it.toRoomIdOrAlias())
|
navigator.onOpenRoom(it.toRoomIdOrAlias())
|
||||||
},
|
},
|
||||||
|
onJoinByAddressClick = navigator::onShowJoinRoomByAddress,
|
||||||
onInviteFriendsClick = { invitePeople(activity) }
|
onInviteFriendsClick = { invitePeople(activity) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ fun CreateRoomRootView(
|
||||||
onNewRoomClick: () -> Unit,
|
onNewRoomClick: () -> Unit,
|
||||||
onOpenDM: (RoomId) -> Unit,
|
onOpenDM: (RoomId) -> Unit,
|
||||||
onInviteFriendsClick: () -> Unit,
|
onInviteFriendsClick: () -> Unit,
|
||||||
|
onJoinByAddressClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
|
@ -89,6 +90,7 @@ fun CreateRoomRootView(
|
||||||
state = state,
|
state = state,
|
||||||
onNewRoomClick = onNewRoomClick,
|
onNewRoomClick = onNewRoomClick,
|
||||||
onInvitePeopleClick = onInviteFriendsClick,
|
onInvitePeopleClick = onInviteFriendsClick,
|
||||||
|
onJoinByAddressClick = onJoinByAddressClick,
|
||||||
onDmClick = onOpenDM,
|
onDmClick = onOpenDM,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -153,6 +155,7 @@ private fun CreateRoomActionButtonsList(
|
||||||
state: CreateRoomRootState,
|
state: CreateRoomRootState,
|
||||||
onNewRoomClick: () -> Unit,
|
onNewRoomClick: () -> Unit,
|
||||||
onInvitePeopleClick: () -> Unit,
|
onInvitePeopleClick: () -> Unit,
|
||||||
|
onJoinByAddressClick: () -> Unit,
|
||||||
onDmClick: (RoomId) -> Unit,
|
onDmClick: (RoomId) -> Unit,
|
||||||
) {
|
) {
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
|
|
@ -170,6 +173,13 @@ private fun CreateRoomActionButtonsList(
|
||||||
onClick = onInvitePeopleClick,
|
onClick = onInvitePeopleClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
item {
|
||||||
|
CreateRoomActionButton(
|
||||||
|
iconRes = CompoundDrawables.ic_compound_mention,
|
||||||
|
text = "Join room by address",
|
||||||
|
onClick = onJoinByAddressClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
if (state.userListState.recentDirectRooms.isNotEmpty()) {
|
if (state.userListState.recentDirectRooms.isNotEmpty()) {
|
||||||
item {
|
item {
|
||||||
ListSectionHeader(
|
ListSectionHeader(
|
||||||
|
|
@ -230,6 +240,7 @@ internal fun CreateRoomRootViewPreview(@PreviewParameter(CreateRoomRootStateProv
|
||||||
onCloseClick = {},
|
onCloseClick = {},
|
||||||
onNewRoomClick = {},
|
onNewRoomClick = {},
|
||||||
onOpenDM = {},
|
onOpenDM = {},
|
||||||
|
onJoinByAddressClick = {},
|
||||||
onInviteFriendsClick = {},
|
onInviteFriendsClick = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue