Alias permalink navigation - WIP
This commit is contained in:
parent
a602849ec5
commit
c1188ebb2d
12 changed files with 137 additions and 68 deletions
|
|
@ -66,6 +66,8 @@ import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.MAIN_SPACE
|
import io.element.android.libraries.matrix.api.core.MAIN_SPACE
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
||||||
|
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||||
import io.element.android.libraries.matrix.api.sync.SyncState
|
import io.element.android.libraries.matrix.api.sync.SyncState
|
||||||
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
||||||
|
|
@ -190,7 +192,7 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class Room(
|
data class Room(
|
||||||
val roomId: RoomId,
|
val roomIdOrAlias: RoomIdOrAlias,
|
||||||
val roomDescription: RoomDescription? = null,
|
val roomDescription: RoomDescription? = null,
|
||||||
val initialElement: RoomNavigationTarget = RoomNavigationTarget.Messages(null)
|
val initialElement: RoomNavigationTarget = RoomNavigationTarget.Messages(null)
|
||||||
) : NavTarget
|
) : NavTarget
|
||||||
|
|
@ -229,7 +231,7 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||||
NavTarget.RoomList -> {
|
NavTarget.RoomList -> {
|
||||||
val callback = object : RoomListEntryPoint.Callback {
|
val callback = object : RoomListEntryPoint.Callback {
|
||||||
override fun onRoomClicked(roomId: RoomId) {
|
override fun onRoomClicked(roomId: RoomId) {
|
||||||
backstack.push(NavTarget.Room(roomId))
|
backstack.push(NavTarget.Room(roomId.toRoomIdOrAlias()))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSettingsClicked() {
|
override fun onSettingsClicked() {
|
||||||
|
|
@ -245,7 +247,7 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRoomSettingsClicked(roomId: RoomId) {
|
override fun onRoomSettingsClicked(roomId: RoomId) {
|
||||||
backstack.push(NavTarget.Room(roomId, initialElement = RoomNavigationTarget.Details))
|
backstack.push(NavTarget.Room(roomId.toRoomIdOrAlias(), initialElement = RoomNavigationTarget.Details))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onReportBugClicked() {
|
override fun onReportBugClicked() {
|
||||||
|
|
@ -264,7 +266,7 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||||
is NavTarget.Room -> {
|
is NavTarget.Room -> {
|
||||||
val callback = object : JoinedRoomLoadedFlowNode.Callback {
|
val callback = object : JoinedRoomLoadedFlowNode.Callback {
|
||||||
override fun onOpenRoom(roomId: RoomId) {
|
override fun onOpenRoom(roomId: RoomId) {
|
||||||
backstack.push(NavTarget.Room(roomId))
|
backstack.push(NavTarget.Room(roomId.toRoomIdOrAlias()))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onForwardedToSingleRoom(roomId: RoomId) {
|
override fun onForwardedToSingleRoom(roomId: RoomId) {
|
||||||
|
|
@ -279,20 +281,23 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||||
Timber.e("User link clicked: ${data.userId}. TODO Add a user profile screen")
|
Timber.e("User link clicked: ${data.userId}. TODO Add a user profile screen")
|
||||||
}
|
}
|
||||||
is PermalinkData.RoomIdLink -> {
|
is PermalinkData.RoomIdLink -> {
|
||||||
backstack.push(NavTarget.Room(data.roomId))
|
backstack.push(NavTarget.Room(data.roomId.toRoomIdOrAlias()))
|
||||||
}
|
}
|
||||||
is PermalinkData.RoomAliasLink -> {
|
is PermalinkData.RoomAliasLink -> {
|
||||||
// FIXME Implement room alias navigation
|
backstack.push(NavTarget.Room(data.roomAlias.toRoomIdOrAlias()))
|
||||||
Timber.e("Room alias link clicked: ${data.roomAlias}. TODO Handle a room alias navigation")
|
|
||||||
}
|
}
|
||||||
is PermalinkData.EventIdAliasLink -> {
|
is PermalinkData.EventIdAliasLink -> {
|
||||||
// FIXME Implement event alias navigation
|
backstack.push(
|
||||||
Timber.e("Event with room alias link clicked: ${data.eventId}. TODO Handle an event with room alias navigation")
|
NavTarget.Room(
|
||||||
|
data.roomAlias.toRoomIdOrAlias(),
|
||||||
|
initialElement = RoomNavigationTarget.Messages(data.eventId)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is PermalinkData.EventIdLink -> {
|
is PermalinkData.EventIdLink -> {
|
||||||
backstack.push(
|
backstack.push(
|
||||||
NavTarget.Room(
|
NavTarget.Room(
|
||||||
data.roomId,
|
data.roomId.toRoomIdOrAlias(),
|
||||||
initialElement = RoomNavigationTarget.Messages(data.eventId)
|
initialElement = RoomNavigationTarget.Messages(data.eventId)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -310,7 +315,7 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val inputs = RoomFlowNode.Inputs(
|
val inputs = RoomFlowNode.Inputs(
|
||||||
roomId = navTarget.roomId,
|
roomIdOrAlias = navTarget.roomIdOrAlias,
|
||||||
roomDescription = Optional.ofNullable(navTarget.roomDescription),
|
roomDescription = Optional.ofNullable(navTarget.roomDescription),
|
||||||
initialElement = navTarget.initialElement
|
initialElement = navTarget.initialElement
|
||||||
)
|
)
|
||||||
|
|
@ -327,7 +332,7 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOpenRoomNotificationSettings(roomId: RoomId) {
|
override fun onOpenRoomNotificationSettings(roomId: RoomId) {
|
||||||
backstack.push(NavTarget.Room(roomId, initialElement = RoomNavigationTarget.NotificationSettings))
|
backstack.push(NavTarget.Room(roomId.toRoomIdOrAlias(), initialElement = RoomNavigationTarget.NotificationSettings))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val inputs = PreferencesEntryPoint.Params(navTarget.initialElement)
|
val inputs = PreferencesEntryPoint.Params(navTarget.initialElement)
|
||||||
|
|
@ -339,7 +344,7 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||||
NavTarget.CreateRoom -> {
|
NavTarget.CreateRoom -> {
|
||||||
val callback = object : CreateRoomEntryPoint.Callback {
|
val callback = object : CreateRoomEntryPoint.Callback {
|
||||||
override fun onSuccess(roomId: RoomId) {
|
override fun onSuccess(roomId: RoomId) {
|
||||||
backstack.replace(NavTarget.Room(roomId))
|
backstack.replace(NavTarget.Room(roomId.toRoomIdOrAlias()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -366,11 +371,11 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||||
roomDirectoryEntryPoint.nodeBuilder(this, buildContext)
|
roomDirectoryEntryPoint.nodeBuilder(this, buildContext)
|
||||||
.callback(object : RoomDirectoryEntryPoint.Callback {
|
.callback(object : RoomDirectoryEntryPoint.Callback {
|
||||||
override fun onRoomJoined(roomId: RoomId) {
|
override fun onRoomJoined(roomId: RoomId) {
|
||||||
backstack.push(NavTarget.Room(roomId))
|
backstack.push(NavTarget.Room(roomId.toRoomIdOrAlias()))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResultClicked(roomDescription: RoomDescription) {
|
override fun onResultClicked(roomDescription: RoomDescription) {
|
||||||
backstack.push(NavTarget.Room(roomDescription.roomId, roomDescription))
|
backstack.push(NavTarget.Room(roomDescription.roomId.toRoomIdOrAlias(), roomDescription))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.build()
|
.build()
|
||||||
|
|
@ -389,7 +394,7 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||||
if (!canShowRoomList()) return
|
if (!canShowRoomList()) return
|
||||||
attachChild<RoomFlowNode> {
|
attachChild<RoomFlowNode> {
|
||||||
backstack.singleTop(NavTarget.RoomList)
|
backstack.singleTop(NavTarget.RoomList)
|
||||||
backstack.push(NavTarget.Room(roomId))
|
backstack.push(NavTarget.Room(roomId.toRoomIdOrAlias()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,10 @@ import io.element.android.libraries.designsystem.theme.components.CircularProgre
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
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.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
||||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
@ -73,7 +75,7 @@ class RoomFlowNode @AssistedInject constructor(
|
||||||
plugins = plugins
|
plugins = plugins
|
||||||
) {
|
) {
|
||||||
data class Inputs(
|
data class Inputs(
|
||||||
val roomId: RoomId,
|
val roomIdOrAlias: RoomIdOrAlias,
|
||||||
val roomDescription: Optional<RoomDescription>,
|
val roomDescription: Optional<RoomDescription>,
|
||||||
val initialElement: RoomNavigationTarget = RoomNavigationTarget.Messages(),
|
val initialElement: RoomNavigationTarget = RoomNavigationTarget.Messages(),
|
||||||
) : NodeInputs
|
) : NodeInputs
|
||||||
|
|
@ -88,42 +90,45 @@ class RoomFlowNode @AssistedInject constructor(
|
||||||
data object JoinRoom : NavTarget
|
data object JoinRoom : NavTarget
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data object JoinedRoom : NavTarget
|
data class JoinedRoom(val roomId: RoomId) : NavTarget
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var roomMembershipJob: Job? = null
|
||||||
|
|
||||||
override fun onBuilt() {
|
override fun onBuilt() {
|
||||||
super.onBuilt()
|
super.onBuilt()
|
||||||
client.getRoomInfoFlow(
|
client.getRoomInfoFlow(
|
||||||
inputs.roomId
|
inputs.roomIdOrAlias
|
||||||
).onEach { roomInfo ->
|
).onEach { roomInfo ->
|
||||||
Timber.d("Room membership: ${roomInfo.map { it.currentUserMembership }}")
|
Timber.d("Room membership: ${roomInfo.map { it.currentUserMembership }}")
|
||||||
if (roomInfo.getOrNull()?.currentUserMembership == CurrentUserMembership.JOINED) {
|
val info = roomInfo.getOrNull()
|
||||||
backstack.newRoot(NavTarget.JoinedRoom)
|
if (info?.currentUserMembership == CurrentUserMembership.JOINED) {
|
||||||
|
backstack.newRoot(NavTarget.JoinedRoom(info.id))
|
||||||
|
// When leaving the room from this session only, navigate up.
|
||||||
|
roomMembershipJob?.cancel()
|
||||||
|
roomMembershipJob = roomMembershipObserver.updates
|
||||||
|
.filter { update -> update.roomId == info.id && !update.isUserInRoom }
|
||||||
|
.onEach {
|
||||||
|
navigateUp()
|
||||||
|
}
|
||||||
|
.launchIn(lifecycleScope)
|
||||||
} else {
|
} else {
|
||||||
backstack.newRoot(NavTarget.JoinRoom)
|
backstack.newRoot(NavTarget.JoinRoom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
|
|
||||||
// When leaving the room from this session only, navigate up.
|
|
||||||
roomMembershipObserver.updates
|
|
||||||
.filter { update -> update.roomId == inputs.roomId && !update.isUserInRoom }
|
|
||||||
.onEach {
|
|
||||||
navigateUp()
|
|
||||||
}
|
|
||||||
.launchIn(lifecycleScope)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
||||||
return when (navTarget) {
|
return when (navTarget) {
|
||||||
NavTarget.Loading -> loadingNode(buildContext)
|
NavTarget.Loading -> loadingNode(buildContext)
|
||||||
NavTarget.JoinRoom -> {
|
NavTarget.JoinRoom -> {
|
||||||
val inputs = JoinRoomEntryPoint.Inputs(inputs.roomId, roomDescription = inputs.roomDescription)
|
val inputs = JoinRoomEntryPoint.Inputs(inputs.roomIdOrAlias, roomDescription = inputs.roomDescription)
|
||||||
joinRoomEntryPoint.createNode(this, buildContext, inputs)
|
joinRoomEntryPoint.createNode(this, buildContext, inputs)
|
||||||
}
|
}
|
||||||
NavTarget.JoinedRoom -> {
|
is NavTarget.JoinedRoom -> {
|
||||||
val roomFlowNodeCallback = plugins<JoinedRoomLoadedFlowNode.Callback>()
|
val roomFlowNodeCallback = plugins<JoinedRoomLoadedFlowNode.Callback>()
|
||||||
val inputs = JoinedRoomFlowNode.Inputs(inputs.roomId, initialElement = inputs.initialElement)
|
val inputs = JoinedRoomFlowNode.Inputs(navTarget.roomId, initialElement = inputs.initialElement)
|
||||||
createNode<JoinedRoomFlowNode>(buildContext, plugins = listOf(inputs) + roomFlowNodeCallback)
|
createNode<JoinedRoomFlowNode>(buildContext, plugins = listOf(inputs) + roomFlowNodeCallback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,14 +21,14 @@ import com.bumble.appyx.core.node.Node
|
||||||
import io.element.android.features.roomdirectory.api.RoomDescription
|
import io.element.android.features.roomdirectory.api.RoomDescription
|
||||||
import io.element.android.libraries.architecture.FeatureEntryPoint
|
import io.element.android.libraries.architecture.FeatureEntryPoint
|
||||||
import io.element.android.libraries.architecture.NodeInputs
|
import io.element.android.libraries.architecture.NodeInputs
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
||||||
import java.util.Optional
|
import java.util.Optional
|
||||||
|
|
||||||
interface JoinRoomEntryPoint : FeatureEntryPoint {
|
interface JoinRoomEntryPoint : FeatureEntryPoint {
|
||||||
fun createNode(parentNode: Node, buildContext: BuildContext, inputs: Inputs): Node
|
fun createNode(parentNode: Node, buildContext: BuildContext, inputs: Inputs): Node
|
||||||
|
|
||||||
data class Inputs(
|
data class Inputs(
|
||||||
val roomId: RoomId,
|
val roomIdOrAlias: RoomIdOrAlias,
|
||||||
val roomDescription: Optional<RoomDescription>,
|
val roomDescription: Optional<RoomDescription>,
|
||||||
) : NodeInputs
|
) : NodeInputs
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ class JoinRoomNode @AssistedInject constructor(
|
||||||
private val acceptDeclineInviteView: AcceptDeclineInviteView,
|
private val acceptDeclineInviteView: AcceptDeclineInviteView,
|
||||||
) : Node(buildContext, plugins = plugins) {
|
) : Node(buildContext, plugins = plugins) {
|
||||||
private val inputs: JoinRoomEntryPoint.Inputs = inputs()
|
private val inputs: JoinRoomEntryPoint.Inputs = inputs()
|
||||||
private val presenter = presenterFactory.create(inputs.roomId, inputs.roomDescription)
|
private val presenter = presenterFactory.create(inputs.roomIdOrAlias, inputs.roomDescription)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun View(modifier: Modifier) {
|
override fun View(modifier: Modifier) {
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import io.element.android.features.invite.api.response.InviteData
|
||||||
import io.element.android.features.roomdirectory.api.RoomDescription
|
import io.element.android.features.roomdirectory.api.RoomDescription
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
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.RoomIdOrAlias
|
||||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||||
import io.element.android.libraries.matrix.api.room.preview.RoomPreview
|
import io.element.android.libraries.matrix.api.room.preview.RoomPreview
|
||||||
|
|
@ -38,20 +38,20 @@ import kotlinx.coroutines.launch
|
||||||
import java.util.Optional
|
import java.util.Optional
|
||||||
|
|
||||||
class JoinRoomPresenter @AssistedInject constructor(
|
class JoinRoomPresenter @AssistedInject constructor(
|
||||||
@Assisted private val roomId: RoomId,
|
@Assisted private val roomIdOrAlias: RoomIdOrAlias,
|
||||||
@Assisted private val roomDescription: Optional<RoomDescription>,
|
@Assisted private val roomDescription: Optional<RoomDescription>,
|
||||||
private val matrixClient: MatrixClient,
|
private val matrixClient: MatrixClient,
|
||||||
private val acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState>,
|
private val acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState>,
|
||||||
) : Presenter<JoinRoomState> {
|
) : Presenter<JoinRoomState> {
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(roomId: RoomId, roomDescription: Optional<RoomDescription>): JoinRoomPresenter
|
fun create(roomIdOrAlias: RoomIdOrAlias, roomDescription: Optional<RoomDescription>): JoinRoomPresenter
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): JoinRoomState {
|
override fun present(): JoinRoomState {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val roomInfo by matrixClient.getRoomInfoFlow(roomId).collectAsState(initial = Optional.empty())
|
val roomInfo by matrixClient.getRoomInfoFlow(roomIdOrAlias).collectAsState(initial = Optional.empty())
|
||||||
val contentState by produceState<ContentState>(initialValue = ContentState.Loading(roomId), key1 = roomInfo) {
|
val contentState by produceState<ContentState>(initialValue = ContentState.Loading(roomIdOrAlias), key1 = roomInfo) {
|
||||||
value = when {
|
value = when {
|
||||||
roomInfo.isPresent -> {
|
roomInfo.isPresent -> {
|
||||||
roomInfo.get().toContentState()
|
roomInfo.get().toContentState()
|
||||||
|
|
@ -61,12 +61,12 @@ class JoinRoomPresenter @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
val result = matrixClient.getRoomPreview(roomId.value)
|
val result = matrixClient.getRoomPreview(roomIdOrAlias)
|
||||||
value = result.getOrNull()
|
value = result.getOrNull()
|
||||||
?.toContentState()
|
?.toContentState()
|
||||||
?: ContentState.UnknownRoom(roomId)
|
?: ContentState.UnknownRoom(roomIdOrAlias)
|
||||||
}
|
}
|
||||||
ContentState.Loading(roomId)
|
ContentState.Loading(roomIdOrAlias)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ 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.avatar.AvatarSize
|
||||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class JoinRoomState(
|
data class JoinRoomState(
|
||||||
|
|
@ -36,8 +37,8 @@ data class JoinRoomState(
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface ContentState {
|
sealed interface ContentState {
|
||||||
data class Loading(val roomId: RoomId) : ContentState
|
data class Loading(val roomIdOrAlias: RoomIdOrAlias) : ContentState
|
||||||
data class UnknownRoom(val roomId: RoomId) : ContentState
|
data class UnknownRoom(val roomIdOrAlias: RoomIdOrAlias) : ContentState
|
||||||
data class Loaded(
|
data class Loaded(
|
||||||
val roomId: RoomId,
|
val roomId: RoomId,
|
||||||
val name: String?,
|
val name: String?,
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import io.element.android.features.invite.api.response.AcceptDeclineInviteState
|
||||||
import io.element.android.features.invite.api.response.anAcceptDeclineInviteState
|
import io.element.android.features.invite.api.response.anAcceptDeclineInviteState
|
||||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
||||||
|
|
||||||
open class JoinRoomStateProvider : PreviewParameterProvider<JoinRoomState> {
|
open class JoinRoomStateProvider : PreviewParameterProvider<JoinRoomState> {
|
||||||
override val values: Sequence<JoinRoomState>
|
override val values: Sequence<JoinRoomState>
|
||||||
|
|
@ -43,9 +44,9 @@ open class JoinRoomStateProvider : PreviewParameterProvider<JoinRoomState> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun anUnknownContentState(roomId: RoomId = A_ROOM_ID) = ContentState.UnknownRoom(roomId)
|
fun anUnknownContentState(roomId: RoomId = A_ROOM_ID) = ContentState.UnknownRoom(roomId.toRoomIdOrAlias())
|
||||||
|
|
||||||
fun aLoadingContentState(roomId: RoomId = A_ROOM_ID) = ContentState.Loading(roomId)
|
fun aLoadingContentState(roomId: RoomId = A_ROOM_ID) = ContentState.Loading(roomId.toRoomIdOrAlias())
|
||||||
|
|
||||||
fun aLoadedContentState(
|
fun aLoadedContentState(
|
||||||
roomId: RoomId = A_ROOM_ID,
|
roomId: RoomId = A_ROOM_ID,
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import io.element.android.features.roomdirectory.api.RoomDescription
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
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.RoomIdOrAlias
|
||||||
import java.util.Optional
|
import java.util.Optional
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
|
|
@ -37,9 +37,9 @@ object JoinRoomModule {
|
||||||
acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState>,
|
acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState>,
|
||||||
): JoinRoomPresenter.Factory {
|
): JoinRoomPresenter.Factory {
|
||||||
return object : JoinRoomPresenter.Factory {
|
return object : JoinRoomPresenter.Factory {
|
||||||
override fun create(roomId: RoomId, roomDescription: Optional<RoomDescription>): JoinRoomPresenter {
|
override fun create(roomIdOrAlias: RoomIdOrAlias, roomDescription: Optional<RoomDescription>): JoinRoomPresenter {
|
||||||
return JoinRoomPresenter(
|
return JoinRoomPresenter(
|
||||||
roomId = roomId,
|
roomIdOrAlias = roomIdOrAlias,
|
||||||
roomDescription = roomDescription,
|
roomDescription = roomDescription,
|
||||||
matrixClient = client,
|
matrixClient = client,
|
||||||
acceptDeclineInvitePresenter = acceptDeclineInvitePresenter,
|
acceptDeclineInvitePresenter = acceptDeclineInvitePresenter,
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package io.element.android.libraries.matrix.api
|
||||||
import io.element.android.libraries.matrix.api.core.ProgressCallback
|
import io.element.android.libraries.matrix.api.core.ProgressCallback
|
||||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
|
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
|
||||||
|
|
@ -94,12 +95,12 @@ interface MatrixClient : Closeable {
|
||||||
suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result<String?>
|
suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result<String?>
|
||||||
suspend fun uploadMedia(mimeType: String, data: ByteArray, progressCallback: ProgressCallback?): Result<String>
|
suspend fun uploadMedia(mimeType: String, data: ByteArray, progressCallback: ProgressCallback?): Result<String>
|
||||||
fun roomMembershipObserver(): RoomMembershipObserver
|
fun roomMembershipObserver(): RoomMembershipObserver
|
||||||
fun getRoomInfoFlow(roomId: RoomId): Flow<Optional<MatrixRoomInfo>>
|
fun getRoomInfoFlow(roomIdOrAlias: RoomIdOrAlias): Flow<Optional<MatrixRoomInfo>>
|
||||||
|
|
||||||
fun isMe(userId: UserId?) = userId == sessionId
|
fun isMe(userId: UserId?) = userId == sessionId
|
||||||
|
|
||||||
suspend fun trackRecentlyVisitedRoom(roomId: RoomId): Result<Unit>
|
suspend fun trackRecentlyVisitedRoom(roomId: RoomId): Result<Unit>
|
||||||
suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>>
|
suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>>
|
||||||
suspend fun resolveRoomAlias(roomAlias: RoomAlias): Result<RoomId>
|
suspend fun resolveRoomAlias(roomAlias: RoomAlias): Result<RoomId>
|
||||||
suspend fun getRoomPreview(roomIdOrAlias: String): Result<RoomPreview>
|
suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias): Result<RoomPreview>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* 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.libraries.matrix.api.core
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
sealed interface RoomIdOrAlias : Parcelable {
|
||||||
|
@Parcelize
|
||||||
|
@JvmInline
|
||||||
|
value class Id(val roomId: RoomId) : RoomIdOrAlias
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
@JvmInline
|
||||||
|
value class Alias(val roomAlias: RoomAlias) : RoomIdOrAlias
|
||||||
|
|
||||||
|
val identifier: String
|
||||||
|
get() = when (this) {
|
||||||
|
is Id -> roomId.value
|
||||||
|
is Alias -> roomAlias.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun RoomId.toRoomIdOrAlias() = RoomIdOrAlias.Id(this)
|
||||||
|
fun RoomAlias.toRoomIdOrAlias() = RoomIdOrAlias.Alias(this)
|
||||||
|
|
@ -25,6 +25,7 @@ import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.ProgressCallback
|
import io.element.android.libraries.matrix.api.core.ProgressCallback
|
||||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
|
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.RoomPreset
|
||||||
|
|
@ -469,9 +470,9 @@ class RustMatrixClient(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getRoomPreview(roomIdOrAlias: String): Result<RoomPreview> = withContext(sessionDispatcher) {
|
override suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias): Result<RoomPreview> = withContext(sessionDispatcher) {
|
||||||
runCatching {
|
runCatching {
|
||||||
client.getRoomPreview(roomIdOrAlias).let(RoomPreviewMapper::map)
|
client.getRoomPreview(roomIdOrAlias.identifier).let(RoomPreviewMapper::map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -561,18 +562,33 @@ class RustMatrixClient(
|
||||||
|
|
||||||
override fun roomMembershipObserver(): RoomMembershipObserver = roomMembershipObserver
|
override fun roomMembershipObserver(): RoomMembershipObserver = roomMembershipObserver
|
||||||
|
|
||||||
override fun getRoomInfoFlow(roomId: RoomId): Flow<Optional<MatrixRoomInfo>> {
|
override fun getRoomInfoFlow(roomIdOrAlias: RoomIdOrAlias): Flow<Optional<MatrixRoomInfo>> {
|
||||||
return flow {
|
return flow {
|
||||||
var room = getRoom(roomId)
|
val roomId = when (roomIdOrAlias) {
|
||||||
if (room == null) {
|
is RoomIdOrAlias.Alias -> {
|
||||||
emit(Optional.empty())
|
resolveRoomAlias(roomIdOrAlias.roomAlias)
|
||||||
awaitRoom(roomId, INFINITE)
|
.onFailure {
|
||||||
room = getRoom(roomId)
|
// TODO Get a way to emit an error
|
||||||
|
Timber.e("Unable to resolve room alias ${roomIdOrAlias.roomAlias}")
|
||||||
|
emit(Optional.empty())
|
||||||
|
return@flow
|
||||||
|
}
|
||||||
|
.getOrNull()
|
||||||
|
}
|
||||||
|
is RoomIdOrAlias.Id -> roomIdOrAlias.roomId
|
||||||
}
|
}
|
||||||
room?.use {
|
if (roomId != null) {
|
||||||
room.roomInfoFlow
|
var room = getRoom(roomId)
|
||||||
.map { roomInfo -> Optional.of(roomInfo) }
|
if (room == null) {
|
||||||
.collect(this)
|
emit(Optional.empty())
|
||||||
|
awaitRoom(roomId, INFINITE)
|
||||||
|
room = getRoom(roomId)
|
||||||
|
}
|
||||||
|
room?.use {
|
||||||
|
room.roomInfoFlow
|
||||||
|
.map { roomInfo -> Optional.of(roomInfo) }
|
||||||
|
.collect(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.distinctUntilChanged()
|
}.distinctUntilChanged()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.ProgressCallback
|
import io.element.android.libraries.matrix.api.core.ProgressCallback
|
||||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
|
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
|
||||||
|
|
@ -76,7 +77,7 @@ class FakeMatrixClient(
|
||||||
private val roomDirectoryService: RoomDirectoryService = FakeRoomDirectoryService(),
|
private val roomDirectoryService: RoomDirectoryService = FakeRoomDirectoryService(),
|
||||||
private val accountManagementUrlString: Result<String?> = Result.success(null),
|
private val accountManagementUrlString: Result<String?> = Result.success(null),
|
||||||
private val resolveRoomAliasResult: (RoomAlias) -> Result<RoomId> = { Result.success(A_ROOM_ID) },
|
private val resolveRoomAliasResult: (RoomAlias) -> Result<RoomId> = { Result.success(A_ROOM_ID) },
|
||||||
private val getRoomPreviewResult: (String) -> Result<RoomPreview> = { TODO("Not implemented") },
|
private val getRoomPreviewResult: (RoomIdOrAlias) -> Result<RoomPreview> = { TODO("Not implemented") },
|
||||||
) : MatrixClient {
|
) : MatrixClient {
|
||||||
var setDisplayNameCalled: Boolean = false
|
var setDisplayNameCalled: Boolean = false
|
||||||
private set
|
private set
|
||||||
|
|
@ -106,7 +107,7 @@ class FakeMatrixClient(
|
||||||
Result.success(it)
|
Result.success(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
var getRoomInfoFlowLambda = { _: RoomId ->
|
var getRoomInfoFlowLambda = { _: RoomIdOrAlias ->
|
||||||
flowOf<Optional<MatrixRoomInfo>>(Optional.empty())
|
flowOf<Optional<MatrixRoomInfo>>(Optional.empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -284,7 +285,7 @@ class FakeMatrixClient(
|
||||||
return resolveRoomAliasResult(roomAlias)
|
return resolveRoomAliasResult(roomAlias)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getRoomPreview(roomIdOrAlias: String): Result<RoomPreview> {
|
override suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias): Result<RoomPreview> {
|
||||||
return getRoomPreviewResult(roomIdOrAlias)
|
return getRoomPreviewResult(roomIdOrAlias)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -292,5 +293,5 @@ class FakeMatrixClient(
|
||||||
return Result.success(visitedRoomsId)
|
return Result.success(visitedRoomsId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getRoomInfoFlow(roomId: RoomId) = getRoomInfoFlowLambda(roomId)
|
override fun getRoomInfoFlow(roomIdOrAlias: RoomIdOrAlias) = getRoomInfoFlowLambda(roomIdOrAlias)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue