ganfra
6 months ago
9 changed files with 583 additions and 30 deletions
@ -0,0 +1,23 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2024 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.appnav.room.join |
||||||
|
|
||||||
|
sealed interface JoinRoomEvents { |
||||||
|
data object JoinRoom: JoinRoomEvents |
||||||
|
data object AcceptInvite : JoinRoomEvents |
||||||
|
data object DeclineInvite : JoinRoomEvents |
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2024 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.appnav.room.join |
||||||
|
|
||||||
|
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 dagger.assisted.Assisted |
||||||
|
import dagger.assisted.AssistedInject |
||||||
|
import io.element.android.anvilannotations.ContributesNode |
||||||
|
import io.element.android.libraries.architecture.NodeInputs |
||||||
|
import io.element.android.libraries.architecture.inputs |
||||||
|
import io.element.android.libraries.di.SessionScope |
||||||
|
import io.element.android.libraries.matrix.api.core.RoomId |
||||||
|
|
||||||
|
@ContributesNode(SessionScope::class) |
||||||
|
class JoinRoomNode @AssistedInject constructor( |
||||||
|
@Assisted buildContext: BuildContext, |
||||||
|
@Assisted plugins: List<Plugin>, |
||||||
|
presenterFactory: JoinRoomPresenter.Factory, |
||||||
|
) : Node(buildContext, plugins = plugins) { |
||||||
|
|
||||||
|
data class Inputs( |
||||||
|
val roomId: RoomId, |
||||||
|
) : NodeInputs |
||||||
|
|
||||||
|
private val inputs: Inputs = inputs() |
||||||
|
private val presenter = presenterFactory.create(inputs.roomId) |
||||||
|
|
||||||
|
@Composable |
||||||
|
override fun View(modifier: Modifier) { |
||||||
|
val state = presenter.present() |
||||||
|
JoinRoomView( |
||||||
|
state = state, |
||||||
|
onBackPressed = ::navigateUp, |
||||||
|
modifier = modifier |
||||||
|
) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,104 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2024 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.appnav.room.join |
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable |
||||||
|
import androidx.compose.runtime.collectAsState |
||||||
|
import androidx.compose.runtime.getValue |
||||||
|
import androidx.compose.runtime.produceState |
||||||
|
import androidx.compose.runtime.rememberCoroutineScope |
||||||
|
import dagger.assisted.Assisted |
||||||
|
import dagger.assisted.AssistedInject |
||||||
|
import io.element.android.libraries.architecture.AsyncData |
||||||
|
import io.element.android.libraries.architecture.Presenter |
||||||
|
import io.element.android.libraries.matrix.api.MatrixClient |
||||||
|
import io.element.android.libraries.matrix.api.core.RoomId |
||||||
|
import io.element.android.libraries.matrix.api.room.CurrentUserMembership |
||||||
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService |
||||||
|
import kotlinx.coroutines.launch |
||||||
|
import java.util.Optional |
||||||
|
import kotlin.jvm.optionals.getOrNull |
||||||
|
|
||||||
|
class JoinRoomPresenter @AssistedInject constructor( |
||||||
|
@Assisted private val roomId: RoomId, |
||||||
|
private val matrixClient: MatrixClient, |
||||||
|
private val roomListService: RoomListService, |
||||||
|
) : Presenter<JoinRoomState> { |
||||||
|
|
||||||
|
interface Factory { |
||||||
|
fun create(roomId: RoomId): JoinRoomPresenter |
||||||
|
} |
||||||
|
|
||||||
|
@Composable |
||||||
|
override fun present(): JoinRoomState { |
||||||
|
val userMembership by roomListService.getUserMembershipForRoom(roomId).collectAsState(initial = Optional.empty()) |
||||||
|
val joinAuthorisationStatus = joinAuthorisationStatus(userMembership) |
||||||
|
val roomInfo by produceState<AsyncData<RoomInfo>>(initialValue = AsyncData.Uninitialized, key1 = userMembership) { |
||||||
|
when { |
||||||
|
userMembership.isPresent -> { |
||||||
|
val roomInfo = matrixClient.getRoom(roomId)?.let { |
||||||
|
RoomInfo( |
||||||
|
roomId = it.roomId, |
||||||
|
roomName = it.displayName, |
||||||
|
roomAlias = it.alias, |
||||||
|
memberCount = it.activeMemberCount, |
||||||
|
roomAvatarUrl = it.avatarUrl |
||||||
|
) |
||||||
|
} |
||||||
|
value = roomInfo?.let { AsyncData.Success(it) } ?: AsyncData.Failure(Exception("Failed to load room info")) |
||||||
|
} |
||||||
|
else -> { |
||||||
|
value = AsyncData.Uninitialized |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
val coroutineScope = rememberCoroutineScope() |
||||||
|
|
||||||
|
fun handleEvents(event: JoinRoomEvents) { |
||||||
|
when (event) { |
||||||
|
JoinRoomEvents.AcceptInvite, JoinRoomEvents.JoinRoom -> { |
||||||
|
coroutineScope.launch { |
||||||
|
matrixClient.joinRoom(roomId) |
||||||
|
} |
||||||
|
} |
||||||
|
JoinRoomEvents.DeclineInvite -> { |
||||||
|
coroutineScope.launch { |
||||||
|
matrixClient.getRoom(roomId)?.use { |
||||||
|
it.leave() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return JoinRoomState( |
||||||
|
roomInfo = roomInfo, |
||||||
|
joinAuthorisationStatus = joinAuthorisationStatus, |
||||||
|
currentAction = CurrentAction.None, |
||||||
|
eventSink = ::handleEvents |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
@Composable |
||||||
|
private fun joinAuthorisationStatus(userMembership: Optional<CurrentUserMembership>): JoinAuthorisationStatus { |
||||||
|
return when { |
||||||
|
userMembership.getOrNull() == CurrentUserMembership.INVITED -> return JoinAuthorisationStatus.IsInvited |
||||||
|
else -> JoinAuthorisationStatus.Unknown |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2024 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.appnav.room.join |
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable |
||||||
|
import io.element.android.libraries.architecture.AsyncData |
||||||
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData |
||||||
|
import io.element.android.libraries.designsystem.components.avatar.AvatarSize |
||||||
|
import io.element.android.libraries.matrix.api.core.RoomId |
||||||
|
|
||||||
|
@Immutable |
||||||
|
data class JoinRoomState( |
||||||
|
val roomInfo: AsyncData<RoomInfo>, |
||||||
|
val joinAuthorisationStatus: JoinAuthorisationStatus, |
||||||
|
val currentAction: CurrentAction, |
||||||
|
val eventSink: (JoinRoomEvents) -> Unit |
||||||
|
) |
||||||
|
|
||||||
|
data class RoomInfo( |
||||||
|
val roomId: RoomId, |
||||||
|
val roomName: String, |
||||||
|
val roomAlias: String?, |
||||||
|
val memberCount: Long?, |
||||||
|
val roomAvatarUrl: String?, |
||||||
|
) { |
||||||
|
fun avatarData(size: AvatarSize): AvatarData { |
||||||
|
return AvatarData( |
||||||
|
id = roomId.value, |
||||||
|
name = roomName, |
||||||
|
url = roomAvatarUrl, |
||||||
|
size = size, |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
enum class JoinAuthorisationStatus { |
||||||
|
IsInvited, |
||||||
|
CanKnock, |
||||||
|
CanJoin, |
||||||
|
Unknown, |
||||||
|
} |
||||||
|
|
||||||
|
sealed interface CurrentAction { |
||||||
|
data object None : CurrentAction |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2024 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.appnav.room.join |
||||||
|
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider |
||||||
|
import io.element.android.libraries.architecture.AsyncData |
||||||
|
import io.element.android.libraries.matrix.api.core.RoomId |
||||||
|
|
||||||
|
open class JoinRoomStateProvider : PreviewParameterProvider<JoinRoomState> { |
||||||
|
override val values: Sequence<JoinRoomState> |
||||||
|
get() = sequenceOf( |
||||||
|
aJoinRoomState( |
||||||
|
roomInfo = AsyncData.Uninitialized |
||||||
|
), |
||||||
|
aJoinRoomState( |
||||||
|
joinAuthorisationStatus = JoinAuthorisationStatus.CanJoin |
||||||
|
), |
||||||
|
aJoinRoomState( |
||||||
|
joinAuthorisationStatus = JoinAuthorisationStatus.CanKnock |
||||||
|
), |
||||||
|
aJoinRoomState( |
||||||
|
joinAuthorisationStatus = JoinAuthorisationStatus.IsInvited |
||||||
|
), |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
fun aJoinRoomState( |
||||||
|
roomInfo: AsyncData<RoomInfo> = AsyncData.Success( |
||||||
|
RoomInfo( |
||||||
|
roomId = RoomId("@exa:matrix.org"), |
||||||
|
roomName = "Element x android", |
||||||
|
roomAlias = "#exa:matrix.org", |
||||||
|
memberCount = null, |
||||||
|
roomAvatarUrl = null |
||||||
|
) |
||||||
|
), |
||||||
|
joinAuthorisationStatus: JoinAuthorisationStatus = JoinAuthorisationStatus.Unknown, |
||||||
|
currentAction: CurrentAction = CurrentAction.None, |
||||||
|
eventSink: (JoinRoomEvents) -> Unit = {} |
||||||
|
) = JoinRoomState( |
||||||
|
roomInfo = roomInfo, |
||||||
|
joinAuthorisationStatus = joinAuthorisationStatus, |
||||||
|
currentAction = currentAction, |
||||||
|
eventSink = eventSink |
||||||
|
) |
||||||
|
|
@ -0,0 +1,211 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2024 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.appnav.room.join |
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement |
||||||
|
import androidx.compose.foundation.layout.Column |
||||||
|
import androidx.compose.foundation.layout.Row |
||||||
|
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.foundation.layout.width |
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api |
||||||
|
import androidx.compose.runtime.Composable |
||||||
|
import androidx.compose.ui.Alignment |
||||||
|
import androidx.compose.ui.Modifier |
||||||
|
import androidx.compose.ui.res.stringResource |
||||||
|
import androidx.compose.ui.text.style.TextAlign |
||||||
|
import androidx.compose.ui.text.style.TextOverflow |
||||||
|
import androidx.compose.ui.tooling.preview.PreviewLightDark |
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameter |
||||||
|
import androidx.compose.ui.unit.dp |
||||||
|
import io.element.android.compound.theme.ElementTheme |
||||||
|
import io.element.android.libraries.architecture.AsyncData |
||||||
|
import io.element.android.libraries.designsystem.atomic.atoms.PlaceholderAtom |
||||||
|
import io.element.android.libraries.designsystem.atomic.molecules.ButtonRowMolecule |
||||||
|
import io.element.android.libraries.designsystem.atomic.molecules.IconTitlePlaceholdersRowMolecule |
||||||
|
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage |
||||||
|
import io.element.android.libraries.designsystem.components.avatar.Avatar |
||||||
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData |
||||||
|
import io.element.android.libraries.designsystem.components.avatar.AvatarSize |
||||||
|
import io.element.android.libraries.designsystem.components.button.BackButton |
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreview |
||||||
|
import io.element.android.libraries.designsystem.theme.components.Button |
||||||
|
import io.element.android.libraries.designsystem.theme.components.ButtonSize |
||||||
|
import io.element.android.libraries.designsystem.theme.components.OutlinedButton |
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text |
||||||
|
import io.element.android.libraries.designsystem.theme.components.TopAppBar |
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings |
||||||
|
|
||||||
|
@Composable |
||||||
|
fun JoinRoomView( |
||||||
|
state: JoinRoomState, |
||||||
|
onBackPressed: () -> Unit, |
||||||
|
modifier: Modifier = Modifier, |
||||||
|
) { |
||||||
|
HeaderFooterPage( |
||||||
|
modifier = modifier, |
||||||
|
topBar = { |
||||||
|
JoinRoomTopBar(asyncRoomInfo = state.roomInfo, onBackClicked = onBackPressed) |
||||||
|
}, |
||||||
|
content = { |
||||||
|
JoinRoomContent(state = state) |
||||||
|
}, |
||||||
|
footer = { |
||||||
|
JoinRoomFooter( |
||||||
|
joinAuthorisationStatus = state.joinAuthorisationStatus, |
||||||
|
onAcceptInvite = { |
||||||
|
state.eventSink(JoinRoomEvents.AcceptInvite) |
||||||
|
}, |
||||||
|
onDeclineInvite = { |
||||||
|
state.eventSink(JoinRoomEvents.DeclineInvite) |
||||||
|
}, |
||||||
|
onJoinRoom = { |
||||||
|
state.eventSink(JoinRoomEvents.JoinRoom) |
||||||
|
}, |
||||||
|
) |
||||||
|
} |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
@Composable |
||||||
|
private fun JoinRoomFooter( |
||||||
|
joinAuthorisationStatus: JoinAuthorisationStatus, |
||||||
|
onAcceptInvite: () -> Unit, |
||||||
|
onDeclineInvite: () -> Unit, |
||||||
|
onJoinRoom: () -> Unit, |
||||||
|
modifier: Modifier = Modifier, |
||||||
|
) { |
||||||
|
when (joinAuthorisationStatus) { |
||||||
|
JoinAuthorisationStatus.IsInvited -> { |
||||||
|
ButtonRowMolecule(modifier = modifier, horizontalArrangement = Arrangement.spacedBy(20.dp)) { |
||||||
|
OutlinedButton( |
||||||
|
text = stringResource(CommonStrings.action_decline), |
||||||
|
onClick = onDeclineInvite, |
||||||
|
modifier = Modifier.weight(1f), |
||||||
|
size = ButtonSize.Medium, |
||||||
|
) |
||||||
|
Button( |
||||||
|
text = stringResource(CommonStrings.action_accept), |
||||||
|
onClick = onAcceptInvite, |
||||||
|
modifier = Modifier.weight(1f), |
||||||
|
size = ButtonSize.Medium, |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
// TODO handle all cases properly |
||||||
|
else -> { |
||||||
|
Button( |
||||||
|
text = stringResource(CommonStrings.action_join), |
||||||
|
onClick = onJoinRoom, |
||||||
|
modifier = modifier.fillMaxWidth(), |
||||||
|
size = ButtonSize.Medium, |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Composable |
||||||
|
private fun JoinRoomContent( |
||||||
|
state: JoinRoomState, |
||||||
|
modifier: Modifier = Modifier, |
||||||
|
) { |
||||||
|
Column( |
||||||
|
modifier = modifier.padding(all = 16.dp), |
||||||
|
horizontalAlignment = Alignment.CenterHorizontally |
||||||
|
) { |
||||||
|
Spacer(modifier = Modifier.height(80.dp)) |
||||||
|
when (state.roomInfo) { |
||||||
|
is AsyncData.Success -> { |
||||||
|
val roomInfo = state.roomInfo.data |
||||||
|
Avatar(avatarData = roomInfo.avatarData(AvatarSize.RoomHeader)) |
||||||
|
} |
||||||
|
else -> { |
||||||
|
PlaceholderAtom(width = AvatarSize.RoomHeader.dp, height = AvatarSize.RoomHeader.dp) |
||||||
|
} |
||||||
|
} |
||||||
|
Spacer(modifier = Modifier.height(16.dp)) |
||||||
|
Text( |
||||||
|
text = "Preview is not available", |
||||||
|
style = ElementTheme.typography.fontHeadingMdBold, |
||||||
|
textAlign = TextAlign.Center, |
||||||
|
color = ElementTheme.colors.textPrimary, |
||||||
|
) |
||||||
|
Spacer(modifier = Modifier.height(8.dp)) |
||||||
|
Text( |
||||||
|
text = "You must be a member of this room to view the message history.", |
||||||
|
style = ElementTheme.typography.fontBodyMdRegular, |
||||||
|
textAlign = TextAlign.Center, |
||||||
|
color = ElementTheme.colors.textSecondary, |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class) |
||||||
|
@Composable |
||||||
|
private fun JoinRoomTopBar( |
||||||
|
asyncRoomInfo: AsyncData<RoomInfo>, |
||||||
|
onBackClicked: () -> Unit, |
||||||
|
) { |
||||||
|
TopAppBar( |
||||||
|
navigationIcon = { |
||||||
|
BackButton(onClick = onBackClicked) |
||||||
|
}, |
||||||
|
title = { |
||||||
|
when (asyncRoomInfo) { |
||||||
|
is AsyncData.Success -> { |
||||||
|
val roomInfo = asyncRoomInfo.data |
||||||
|
RoomAvatarAndNameRow(roomName = roomInfo.roomName, roomAvatar = roomInfo.avatarData(AvatarSize.TimelineRoom)) |
||||||
|
} |
||||||
|
else -> { |
||||||
|
IconTitlePlaceholdersRowMolecule(iconSize = AvatarSize.TimelineRoom.dp) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
@Composable |
||||||
|
private fun RoomAvatarAndNameRow( |
||||||
|
roomName: String, |
||||||
|
roomAvatar: AvatarData, |
||||||
|
modifier: Modifier = Modifier |
||||||
|
) { |
||||||
|
Row( |
||||||
|
modifier = modifier, |
||||||
|
verticalAlignment = Alignment.CenterVertically |
||||||
|
) { |
||||||
|
Avatar(roomAvatar) |
||||||
|
Spacer(modifier = Modifier.width(8.dp)) |
||||||
|
Text( |
||||||
|
text = roomName, |
||||||
|
style = ElementTheme.typography.fontBodyLgMedium, |
||||||
|
maxLines = 1, |
||||||
|
overflow = TextOverflow.Ellipsis |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@PreviewLightDark |
||||||
|
@Composable |
||||||
|
fun JoinRoomViewPreview(@PreviewParameter(JoinRoomStateProvider::class) state: JoinRoomState) = ElementPreview { |
||||||
|
JoinRoomView( |
||||||
|
state = state, |
||||||
|
onBackPressed = { } |
||||||
|
) |
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2024 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.appnav.room.join.di |
||||||
|
|
||||||
|
import com.squareup.anvil.annotations.ContributesTo |
||||||
|
import dagger.Module |
||||||
|
import dagger.Provides |
||||||
|
import io.element.android.appnav.room.join.JoinRoomPresenter |
||||||
|
import io.element.android.libraries.di.SessionScope |
||||||
|
import io.element.android.libraries.matrix.api.MatrixClient |
||||||
|
import io.element.android.libraries.matrix.api.core.RoomId |
||||||
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService |
||||||
|
|
||||||
|
@Module |
||||||
|
@ContributesTo(SessionScope::class) |
||||||
|
object JoinRoomModule { |
||||||
|
@Provides |
||||||
|
fun providesJoinRoomPresenterFactory( |
||||||
|
roomListService: RoomListService, |
||||||
|
client: MatrixClient, |
||||||
|
): JoinRoomPresenter.Factory { |
||||||
|
return object : JoinRoomPresenter.Factory { |
||||||
|
override fun create(roomId: RoomId): JoinRoomPresenter { |
||||||
|
return JoinRoomPresenter( |
||||||
|
roomId = roomId, |
||||||
|
matrixClient = client, |
||||||
|
roomListService = roomListService |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue