Support Space explore pagination
This commit is contained in:
parent
2982fdc626
commit
5297512f87
1
changelog.d/3693.feature
Normal file
1
changelog.d/3693.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
Space summary pagination
|
@ -27,7 +27,7 @@ data class SpaceChildInfo(
|
|||||||
val avatarUrl: String?,
|
val avatarUrl: String?,
|
||||||
val order: String?,
|
val order: String?,
|
||||||
val activeMemberCount: Int?,
|
val activeMemberCount: Int?,
|
||||||
val autoJoin: Boolean,
|
// val autoJoin: Boolean,
|
||||||
val viaServers: List<String>,
|
val viaServers: List<String>,
|
||||||
val parentRoomId: String?,
|
val parentRoomId: String?,
|
||||||
val suggested: Boolean?,
|
val suggested: Boolean?,
|
||||||
|
@ -36,7 +36,7 @@ interface Space {
|
|||||||
suspend fun addChildren(roomId: String,
|
suspend fun addChildren(roomId: String,
|
||||||
viaServers: List<String>?,
|
viaServers: List<String>?,
|
||||||
order: String?,
|
order: String?,
|
||||||
autoJoin: Boolean = false,
|
// autoJoin: Boolean = false,
|
||||||
suggested: Boolean? = false)
|
suggested: Boolean? = false)
|
||||||
|
|
||||||
fun getChildInfo(roomId: String): SpaceChildContent?
|
fun getChildInfo(roomId: String): SpaceChildContent?
|
||||||
@ -46,8 +46,8 @@ interface Space {
|
|||||||
@Throws
|
@Throws
|
||||||
suspend fun setChildrenOrder(roomId: String, order: String?)
|
suspend fun setChildrenOrder(roomId: String, order: String?)
|
||||||
|
|
||||||
@Throws
|
// @Throws
|
||||||
suspend fun setChildrenAutoJoin(roomId: String, autoJoin: Boolean)
|
// suspend fun setChildrenAutoJoin(roomId: String, autoJoin: Boolean)
|
||||||
|
|
||||||
@Throws
|
@Throws
|
||||||
suspend fun setChildrenSuggested(roomId: String, suggested: Boolean)
|
suspend fun setChildrenSuggested(roomId: String, suggested: Boolean)
|
||||||
|
@ -18,9 +18,10 @@ package org.matrix.android.sdk.api.session.space
|
|||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
|
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
import org.matrix.android.sdk.internal.session.space.SpaceHierarchySummary
|
||||||
import org.matrix.android.sdk.internal.session.space.peeking.SpacePeekResult
|
import org.matrix.android.sdk.internal.session.space.peeking.SpacePeekResult
|
||||||
|
|
||||||
typealias SpaceSummaryQueryParams = RoomSummaryQueryParams
|
typealias SpaceSummaryQueryParams = RoomSummaryQueryParams
|
||||||
@ -58,10 +59,18 @@ interface SpaceService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get's information of a space by querying the server
|
* Get's information of a space by querying the server
|
||||||
|
* @param suggestedOnly If true, return only child events and rooms where the m.space.child event has suggested: true.
|
||||||
|
* @param limit a client-defined limit to the maximum number of rooms to return per page. Must be a non-negative integer.
|
||||||
|
* @param maxDepth: Optional: The maximum depth in the tree (from the root room) to return.
|
||||||
|
* @param from: Optional. Pagination token given to retrieve the next set of rooms. Note that if a pagination token is provided,
|
||||||
|
* then the parameters given for suggested_only and max_depth must be the same.
|
||||||
*/
|
*/
|
||||||
suspend fun querySpaceChildren(spaceId: String,
|
suspend fun querySpaceChildren(spaceId: String,
|
||||||
suggestedOnly: Boolean? = null,
|
suggestedOnly: Boolean? = null,
|
||||||
autoJoinedOnly: Boolean? = null): Pair<RoomSummary, List<SpaceChildInfo>>
|
limit: Int? = null,
|
||||||
|
from: String? = null,
|
||||||
|
// when paginating, pass back the m.space.child state events
|
||||||
|
knownStateList: List<Event>? = null): SpaceHierarchySummary
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a live list of space summaries. This list is refreshed as soon as the data changes.
|
* Get a live list of space summaries. This list is refreshed as soon as the data changes.
|
||||||
|
@ -40,12 +40,12 @@ data class SpaceChildContent(
|
|||||||
* or consist of more than 50 characters, are forbidden and should be ignored if received.)
|
* or consist of more than 50 characters, are forbidden and should be ignored if received.)
|
||||||
*/
|
*/
|
||||||
@Json(name = "order") val order: String? = null,
|
@Json(name = "order") val order: String? = null,
|
||||||
/**
|
// /**
|
||||||
* The auto_join flag on a child listing allows a space admin to list the sub-spaces and rooms in that space which should
|
// * The auto_join flag on a child listing allows a space admin to list the sub-spaces and rooms in that space which should
|
||||||
* be automatically joined by members of that space.
|
// * be automatically joined by members of that space.
|
||||||
* (This is not a force-join, which are descoped for a future MSC; the user can subsequently part these room if they desire.)
|
// * (This is not a force-join, which are descoped for a future MSC; the user can subsequently part these room if they desire.)
|
||||||
*/
|
// */
|
||||||
@Json(name = "auto_join") val autoJoin: Boolean? = false,
|
// @Json(name = "auto_join") val autoJoin: Boolean? = false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If `suggested` is set to `true`, that indicates that the child should be advertised to
|
* If `suggested` is set to `true`, that indicates that the child should be advertised to
|
||||||
|
@ -88,7 +88,7 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa
|
|||||||
avatarUrl = it.childSummaryEntity?.avatarUrl,
|
avatarUrl = it.childSummaryEntity?.avatarUrl,
|
||||||
activeMemberCount = it.childSummaryEntity?.joinedMembersCount,
|
activeMemberCount = it.childSummaryEntity?.joinedMembersCount,
|
||||||
order = it.order,
|
order = it.order,
|
||||||
autoJoin = it.autoJoin ?: false,
|
// autoJoin = it.autoJoin ?: false,
|
||||||
viaServers = it.viaServers.toList(),
|
viaServers = it.viaServers.toList(),
|
||||||
parentRoomId = roomSummaryEntity.roomId,
|
parentRoomId = roomSummaryEntity.roomId,
|
||||||
suggested = it.suggested,
|
suggested = it.suggested,
|
||||||
|
@ -43,7 +43,7 @@ internal class RoomChildRelationInfo(
|
|||||||
data class SpaceChildInfo(
|
data class SpaceChildInfo(
|
||||||
val roomId: String,
|
val roomId: String,
|
||||||
val order: String?,
|
val order: String?,
|
||||||
val autoJoin: Boolean,
|
// val autoJoin: Boolean,
|
||||||
val viaServers: List<String>
|
val viaServers: List<String>
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ internal class RoomChildRelationInfo(
|
|||||||
SpaceChildInfo(
|
SpaceChildInfo(
|
||||||
roomId = it.stateKey,
|
roomId = it.stateKey,
|
||||||
order = scc.validOrder(),
|
order = scc.validOrder(),
|
||||||
autoJoin = scc.autoJoin ?: false,
|
// autoJoin = scc.autoJoin ?: false,
|
||||||
viaServers = via
|
viaServers = via
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,7 @@ internal class RoomSummaryUpdater @Inject constructor(
|
|||||||
this.childRoomId = child.roomId
|
this.childRoomId = child.roomId
|
||||||
this.childSummaryEntity = RoomSummaryEntity.where(realm, child.roomId).findFirst()
|
this.childSummaryEntity = RoomSummaryEntity.where(realm, child.roomId).findFirst()
|
||||||
this.order = child.order
|
this.order = child.order
|
||||||
this.autoJoin = child.autoJoin
|
// this.autoJoin = child.autoJoin
|
||||||
this.viaServers.addAll(child.viaServers)
|
this.viaServers.addAll(child.viaServers)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -51,7 +51,7 @@ internal class DefaultSpace(
|
|||||||
override suspend fun addChildren(roomId: String,
|
override suspend fun addChildren(roomId: String,
|
||||||
viaServers: List<String>?,
|
viaServers: List<String>?,
|
||||||
order: String?,
|
order: String?,
|
||||||
autoJoin: Boolean,
|
// autoJoin: Boolean,
|
||||||
suggested: Boolean?) {
|
suggested: Boolean?) {
|
||||||
// Find best via
|
// Find best via
|
||||||
val bestVia = viaServers
|
val bestVia = viaServers
|
||||||
@ -69,7 +69,6 @@ internal class DefaultSpace(
|
|||||||
stateKey = roomId,
|
stateKey = roomId,
|
||||||
body = SpaceChildContent(
|
body = SpaceChildContent(
|
||||||
via = bestVia,
|
via = bestVia,
|
||||||
autoJoin = autoJoin,
|
|
||||||
order = order,
|
order = order,
|
||||||
suggested = suggested
|
suggested = suggested
|
||||||
).toContent()
|
).toContent()
|
||||||
@ -90,7 +89,7 @@ internal class DefaultSpace(
|
|||||||
body = SpaceChildContent(
|
body = SpaceChildContent(
|
||||||
order = null,
|
order = null,
|
||||||
via = null,
|
via = null,
|
||||||
autoJoin = null,
|
// autoJoin = null,
|
||||||
suggested = null
|
suggested = null
|
||||||
).toContent()
|
).toContent()
|
||||||
)
|
)
|
||||||
@ -115,35 +114,35 @@ internal class DefaultSpace(
|
|||||||
body = SpaceChildContent(
|
body = SpaceChildContent(
|
||||||
order = order,
|
order = order,
|
||||||
via = existing.via,
|
via = existing.via,
|
||||||
autoJoin = existing.autoJoin,
|
// autoJoin = existing.autoJoin,
|
||||||
suggested = existing.suggested
|
suggested = existing.suggested
|
||||||
).toContent()
|
).toContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setChildrenAutoJoin(roomId: String, autoJoin: Boolean) {
|
// override suspend fun setChildrenAutoJoin(roomId: String, autoJoin: Boolean) {
|
||||||
val existing = room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId))
|
// val existing = room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId))
|
||||||
.firstOrNull()
|
// .firstOrNull()
|
||||||
?.content.toModel<SpaceChildContent>()
|
// ?.content.toModel<SpaceChildContent>()
|
||||||
?: throw IllegalArgumentException("$roomId is not a child of this space")
|
// ?: throw IllegalArgumentException("$roomId is not a child of this space")
|
||||||
|
//
|
||||||
if (existing.autoJoin == autoJoin) {
|
// if (existing.autoJoin == autoJoin) {
|
||||||
// nothing to do?
|
// // nothing to do?
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// edit state event and set via to null
|
// // edit state event and set via to null
|
||||||
room.sendStateEvent(
|
// room.sendStateEvent(
|
||||||
eventType = EventType.STATE_SPACE_CHILD,
|
// eventType = EventType.STATE_SPACE_CHILD,
|
||||||
stateKey = roomId,
|
// stateKey = roomId,
|
||||||
body = SpaceChildContent(
|
// body = SpaceChildContent(
|
||||||
order = existing.order,
|
// order = existing.order,
|
||||||
via = existing.via,
|
// via = existing.via,
|
||||||
autoJoin = autoJoin,
|
// autoJoin = autoJoin,
|
||||||
suggested = existing.suggested
|
// suggested = existing.suggested
|
||||||
).toContent()
|
// ).toContent()
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
|
||||||
override suspend fun setChildrenSuggested(roomId: String, suggested: Boolean) {
|
override suspend fun setChildrenSuggested(roomId: String, suggested: Boolean) {
|
||||||
val existing = room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId))
|
val existing = room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId))
|
||||||
@ -162,7 +161,7 @@ internal class DefaultSpace(
|
|||||||
body = SpaceChildContent(
|
body = SpaceChildContent(
|
||||||
order = existing.order,
|
order = existing.order,
|
||||||
via = existing.via,
|
via = existing.via,
|
||||||
autoJoin = existing.autoJoin,
|
// autoJoin = existing.autoJoin,
|
||||||
suggested = suggested
|
suggested = suggested
|
||||||
).toContent()
|
).toContent()
|
||||||
)
|
)
|
||||||
|
@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.space
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
@ -27,6 +28,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership
|
|||||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
|
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
|
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
|
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
|
||||||
@ -108,53 +110,65 @@ internal class DefaultSpaceService @Inject constructor(
|
|||||||
|
|
||||||
override suspend fun querySpaceChildren(spaceId: String,
|
override suspend fun querySpaceChildren(spaceId: String,
|
||||||
suggestedOnly: Boolean?,
|
suggestedOnly: Boolean?,
|
||||||
autoJoinedOnly: Boolean?): Pair<RoomSummary, List<SpaceChildInfo>> {
|
limit: Int?,
|
||||||
return resolveSpaceInfoTask.execute(ResolveSpaceInfoTask.Params.withId(spaceId, suggestedOnly, autoJoinedOnly)).let { response ->
|
from: String?,
|
||||||
|
knownStateList: List<Event>?): SpaceHierarchySummary {
|
||||||
|
return resolveSpaceInfoTask.execute(
|
||||||
|
ResolveSpaceInfoTask.Params(
|
||||||
|
spaceId = spaceId, limit = limit, maxDepth = 1, from = from, suggestedOnly = suggestedOnly
|
||||||
|
)
|
||||||
|
).let { response ->
|
||||||
val spaceDesc = response.rooms?.firstOrNull { it.roomId == spaceId }
|
val spaceDesc = response.rooms?.firstOrNull { it.roomId == spaceId }
|
||||||
Pair(
|
val root = RoomSummary(
|
||||||
first = RoomSummary(
|
roomId = spaceDesc?.roomId ?: spaceId,
|
||||||
roomId = spaceDesc?.roomId ?: spaceId,
|
roomType = spaceDesc?.roomType,
|
||||||
roomType = spaceDesc?.roomType,
|
name = spaceDesc?.name ?: "",
|
||||||
name = spaceDesc?.name ?: "",
|
displayName = spaceDesc?.name ?: "",
|
||||||
displayName = spaceDesc?.name ?: "",
|
topic = spaceDesc?.topic ?: "",
|
||||||
topic = spaceDesc?.topic ?: "",
|
joinedMembersCount = spaceDesc?.numJoinedMembers,
|
||||||
joinedMembersCount = spaceDesc?.numJoinedMembers,
|
avatarUrl = spaceDesc?.avatarUrl ?: "",
|
||||||
avatarUrl = spaceDesc?.avatarUrl ?: "",
|
encryptionEventTs = null,
|
||||||
encryptionEventTs = null,
|
typingUsers = emptyList(),
|
||||||
typingUsers = emptyList(),
|
isEncrypted = false,
|
||||||
isEncrypted = false,
|
flattenParentIds = emptyList(),
|
||||||
flattenParentIds = emptyList()
|
canonicalAlias = spaceDesc?.canonicalAlias,
|
||||||
),
|
joinRules = RoomJoinRules.PUBLIC.takeIf { spaceDesc?.worldReadable == true }
|
||||||
second = response.rooms
|
)
|
||||||
?.filter { it.roomId != spaceId }
|
val children = response.rooms
|
||||||
?.flatMap { childSummary ->
|
?.filter { it.roomId != spaceId }
|
||||||
response.events
|
?.flatMap { childSummary ->
|
||||||
?.filter { it.stateKey == childSummary.roomId && it.type == EventType.STATE_SPACE_CHILD }
|
(spaceDesc?.childrenState ?: knownStateList)
|
||||||
?.mapNotNull { childStateEv ->
|
?.filter { it.stateKey == childSummary.roomId && it.type == EventType.STATE_SPACE_CHILD }
|
||||||
// create a child entry for everytime this room is the child of a space
|
?.mapNotNull { childStateEv ->
|
||||||
// beware that a room could appear then twice in this list
|
// create a child entry for everytime this room is the child of a space
|
||||||
childStateEv.content.toModel<SpaceChildContent>()?.let { childStateEvContent ->
|
// beware that a room could appear then twice in this list
|
||||||
SpaceChildInfo(
|
childStateEv.content.toModel<SpaceChildContent>()?.let { childStateEvContent ->
|
||||||
childRoomId = childSummary.roomId,
|
SpaceChildInfo(
|
||||||
isKnown = true,
|
childRoomId = childSummary.roomId,
|
||||||
roomType = childSummary.roomType,
|
isKnown = true,
|
||||||
name = childSummary.name,
|
roomType = childSummary.roomType,
|
||||||
topic = childSummary.topic,
|
name = childSummary.name,
|
||||||
avatarUrl = childSummary.avatarUrl,
|
topic = childSummary.topic,
|
||||||
order = childStateEvContent.order,
|
avatarUrl = childSummary.avatarUrl,
|
||||||
autoJoin = childStateEvContent.autoJoin ?: false,
|
order = childStateEvContent.order,
|
||||||
viaServers = childStateEvContent.via.orEmpty(),
|
// autoJoin = childStateEvContent.autoJoin ?: false,
|
||||||
activeMemberCount = childSummary.numJoinedMembers,
|
viaServers = childStateEvContent.via.orEmpty(),
|
||||||
parentRoomId = childStateEv.roomId,
|
activeMemberCount = childSummary.numJoinedMembers,
|
||||||
suggested = childStateEvContent.suggested,
|
parentRoomId = childStateEv.roomId,
|
||||||
canonicalAlias = childSummary.canonicalAlias,
|
suggested = childStateEvContent.suggested,
|
||||||
aliases = childSummary.aliases,
|
canonicalAlias = childSummary.canonicalAlias,
|
||||||
worldReadable = childSummary.worldReadable
|
aliases = childSummary.aliases,
|
||||||
)
|
worldReadable = childSummary.worldReadable
|
||||||
}
|
)
|
||||||
}.orEmpty()
|
}
|
||||||
}
|
}.orEmpty()
|
||||||
.orEmpty()
|
}
|
||||||
|
.orEmpty()
|
||||||
|
SpaceHierarchySummary(
|
||||||
|
rootSummary = root,
|
||||||
|
children = children,
|
||||||
|
childrenState = spaceDesc?.childrenState.orEmpty(),
|
||||||
|
nextToken = response.nextBatch
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ package org.matrix.android.sdk.internal.session.space
|
|||||||
import io.realm.RealmConfiguration
|
import io.realm.RealmConfiguration
|
||||||
import kotlinx.coroutines.TimeoutCancellationException
|
import kotlinx.coroutines.TimeoutCancellationException
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
|
||||||
import org.matrix.android.sdk.api.session.space.JoinSpaceResult
|
import org.matrix.android.sdk.api.session.space.JoinSpaceResult
|
||||||
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
|
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
|
||||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
||||||
@ -84,39 +83,39 @@ internal class DefaultJoinSpaceTask @Inject constructor(
|
|||||||
// after that i should have the children (? do I need to paginate to get state)
|
// after that i should have the children (? do I need to paginate to get state)
|
||||||
val summary = roomSummaryDataSource.getSpaceSummary(params.roomIdOrAlias)
|
val summary = roomSummaryDataSource.getSpaceSummary(params.roomIdOrAlias)
|
||||||
Timber.v("## Space: Found space summary Name:[${summary?.name}] children: ${summary?.spaceChildren?.size}")
|
Timber.v("## Space: Found space summary Name:[${summary?.name}] children: ${summary?.spaceChildren?.size}")
|
||||||
summary?.spaceChildren?.forEach {
|
// summary?.spaceChildren?.forEach {
|
||||||
// val childRoomSummary = it.roomSummary ?: return@forEach
|
// val childRoomSummary = it.roomSummary ?: return@forEach
|
||||||
Timber.v("## Space: Processing child :[${it.childRoomId}] autoJoin:${it.autoJoin}")
|
// Timber.v("## Space: Processing child :[${it.childRoomId}] suggested:${it.suggested}")
|
||||||
if (it.autoJoin) {
|
// if (it.autoJoin) {
|
||||||
// I should try to join as well
|
// // I should try to join as well
|
||||||
if (it.roomType == RoomType.SPACE) {
|
// if (it.roomType == RoomType.SPACE) {
|
||||||
// recursively join auto-joined child of this space?
|
// // recursively join auto-joined child of this space?
|
||||||
when (val subspaceJoinResult = execute(JoinSpaceTask.Params(it.childRoomId, null, it.viaServers))) {
|
// when (val subspaceJoinResult = execute(JoinSpaceTask.Params(it.childRoomId, null, it.viaServers))) {
|
||||||
JoinSpaceResult.Success -> {
|
// JoinSpaceResult.Success -> {
|
||||||
// nop
|
// // nop
|
||||||
}
|
// }
|
||||||
is JoinSpaceResult.Fail -> {
|
// is JoinSpaceResult.Fail -> {
|
||||||
errors[it.childRoomId] = subspaceJoinResult.error
|
// errors[it.childRoomId] = subspaceJoinResult.error
|
||||||
}
|
// }
|
||||||
is JoinSpaceResult.PartialSuccess -> {
|
// is JoinSpaceResult.PartialSuccess -> {
|
||||||
errors.putAll(subspaceJoinResult.failedRooms)
|
// errors.putAll(subspaceJoinResult.failedRooms)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
try {
|
// try {
|
||||||
Timber.v("## Space: Joining room child ${it.childRoomId}")
|
// Timber.v("## Space: Joining room child ${it.childRoomId}")
|
||||||
joinRoomTask.execute(JoinRoomTask.Params(
|
// joinRoomTask.execute(JoinRoomTask.Params(
|
||||||
roomIdOrAlias = it.childRoomId,
|
// roomIdOrAlias = it.childRoomId,
|
||||||
reason = "Auto-join parent space",
|
// reason = "Auto-join parent space",
|
||||||
viaServers = it.viaServers
|
// viaServers = it.viaServers
|
||||||
))
|
// ))
|
||||||
} catch (failure: Throwable) {
|
// } catch (failure: Throwable) {
|
||||||
errors[it.childRoomId] = failure
|
// errors[it.childRoomId] = failure
|
||||||
Timber.e("## Space: Failed to join room child ${it.childRoomId}")
|
// Timber.e("## Space: Failed to join room child ${it.childRoomId}")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return if (errors.isEmpty()) {
|
return if (errors.isEmpty()) {
|
||||||
JoinSpaceResult.Success
|
JoinSpaceResult.Success
|
||||||
|
@ -24,23 +24,24 @@ import javax.inject.Inject
|
|||||||
internal interface ResolveSpaceInfoTask : Task<ResolveSpaceInfoTask.Params, SpacesResponse> {
|
internal interface ResolveSpaceInfoTask : Task<ResolveSpaceInfoTask.Params, SpacesResponse> {
|
||||||
data class Params(
|
data class Params(
|
||||||
val spaceId: String,
|
val spaceId: String,
|
||||||
val maxRoomPerSpace: Int?,
|
// val maxRoomPerSpace: Int?,
|
||||||
val limit: Int,
|
val limit: Int?,
|
||||||
val batchToken: String?,
|
val maxDepth: Int?,
|
||||||
val suggestedOnly: Boolean?,
|
val from: String?,
|
||||||
val autoJoinOnly: Boolean?
|
val suggestedOnly: Boolean?
|
||||||
|
// val autoJoinOnly: Boolean?
|
||||||
) {
|
) {
|
||||||
companion object {
|
// companion object {
|
||||||
fun withId(spaceId: String, suggestedOnly: Boolean?, autoJoinOnly: Boolean?) =
|
// fun withId(spaceId: String, suggestedOnly: Boolean?) =
|
||||||
Params(
|
// Params(
|
||||||
spaceId = spaceId,
|
// spaceId = spaceId,
|
||||||
maxRoomPerSpace = 10,
|
// // maxRoomPerSpace = 10,
|
||||||
limit = 20,
|
// limit = 20,
|
||||||
batchToken = null,
|
// from = null,
|
||||||
suggestedOnly = suggestedOnly,
|
// suggestedOnly = suggestedOnly
|
||||||
autoJoinOnly = autoJoinOnly
|
// // autoJoinOnly = autoJoinOnly
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,15 +50,13 @@ internal class DefaultResolveSpaceInfoTask @Inject constructor(
|
|||||||
private val globalErrorReceiver: GlobalErrorReceiver
|
private val globalErrorReceiver: GlobalErrorReceiver
|
||||||
) : ResolveSpaceInfoTask {
|
) : ResolveSpaceInfoTask {
|
||||||
override suspend fun execute(params: ResolveSpaceInfoTask.Params): SpacesResponse {
|
override suspend fun execute(params: ResolveSpaceInfoTask.Params): SpacesResponse {
|
||||||
val body = SpaceSummaryParams(
|
|
||||||
maxRoomPerSpace = params.maxRoomPerSpace,
|
|
||||||
limit = params.limit,
|
|
||||||
batch = params.batchToken ?: "",
|
|
||||||
autoJoinedOnly = params.autoJoinOnly,
|
|
||||||
suggestedOnly = params.suggestedOnly
|
|
||||||
)
|
|
||||||
return executeRequest(globalErrorReceiver) {
|
return executeRequest(globalErrorReceiver) {
|
||||||
spaceApi.getSpaces(params.spaceId, body)
|
spaceApi.getSpaceHierarchy(
|
||||||
|
spaceId = params.spaceId,
|
||||||
|
suggestedOnly = params.suggestedOnly,
|
||||||
|
limit = params.limit,
|
||||||
|
maxDepth = params.maxDepth,
|
||||||
|
from = params.from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
package org.matrix.android.sdk.internal.session.space
|
package org.matrix.android.sdk.internal.session.space
|
||||||
|
|
||||||
import org.matrix.android.sdk.internal.network.NetworkConstants
|
import org.matrix.android.sdk.internal.network.NetworkConstants
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.POST
|
|
||||||
import retrofit2.http.Path
|
import retrofit2.http.Path
|
||||||
|
import retrofit2.http.Query
|
||||||
|
|
||||||
internal interface SpaceApi {
|
internal interface SpaceApi {
|
||||||
|
|
||||||
@ -37,7 +37,23 @@ internal interface SpaceApi {
|
|||||||
* - MSC 2946 https://github.com/matrix-org/matrix-doc/blob/kegan/spaces-summary/proposals/2946-spaces-summary.md
|
* - MSC 2946 https://github.com/matrix-org/matrix-doc/blob/kegan/spaces-summary/proposals/2946-spaces-summary.md
|
||||||
* - https://hackmd.io/fNYh4tjUT5mQfR1uuRzWDA
|
* - https://hackmd.io/fNYh4tjUT5mQfR1uuRzWDA
|
||||||
*/
|
*/
|
||||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "org.matrix.msc2946/rooms/{roomId}/spaces")
|
// @POST(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "org.matrix.msc2946/rooms/{roomId}/spaces")
|
||||||
suspend fun getSpaces(@Path("roomId") spaceId: String,
|
// suspend fun getSpaces(@Path("roomId") spaceId: String,
|
||||||
@Body params: SpaceSummaryParams): SpacesResponse
|
// @Body params: SpaceSummaryParams): SpacesResponse
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param limit: Optional: a client-defined limit to the maximum number of rooms to return per page. Must be a non-negative integer.
|
||||||
|
* @param max_depth: Optional: The maximum depth in the tree (from the root room) to return.
|
||||||
|
* The deepest depth returned will not include children events. Defaults to no-limit. Must be a non-negative integer.
|
||||||
|
*
|
||||||
|
* @param from: Optional. Pagination token given to retrieve the next set of rooms.
|
||||||
|
* Note that if a pagination token is provided, then the parameters given for suggested_only and max_depth must be the same.
|
||||||
|
*/
|
||||||
|
@GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "org.matrix.msc2946/rooms/{roomId}/hierarchy")
|
||||||
|
suspend fun getSpaceHierarchy(
|
||||||
|
@Path("roomId") spaceId: String,
|
||||||
|
@Query("suggested_only") suggestedOnly: Boolean?,
|
||||||
|
@Query("limit") limit: Int?,
|
||||||
|
@Query("max_depth") maxDepth: Int?,
|
||||||
|
@Query("from") from: String?): SpacesResponse
|
||||||
}
|
}
|
||||||
|
@ -18,14 +18,21 @@ package org.matrix.android.sdk.internal.session.space
|
|||||||
|
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fields are the same as those returned by /publicRooms (see spec), with the addition of:
|
||||||
|
* room_type: the value of the m.type field from the room's m.room.create event, if any.
|
||||||
|
* children_state: The m.space.child events of the room. For each event, only the following fields are included1: type, state_key, content, room_id, sender, with the addition of:
|
||||||
|
* origin_server_ts: This is required for sorting of rooms as specified below.
|
||||||
|
*/
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
internal data class SpaceChildSummaryResponse(
|
internal data class SpaceChildSummaryResponse(
|
||||||
/**
|
// /**
|
||||||
* The total number of state events which point to or from this room (inbound/outbound edges).
|
// * The total number of state events which point to or from this room (inbound/outbound edges).
|
||||||
* This includes all m.space.child events in the room, in addition to m.room.parent events which point to this room as a parent.
|
// * This includes all m.space.child events in the room, in addition to m.room.parent events which point to this room as a parent.
|
||||||
*/
|
// */
|
||||||
@Json(name = "num_refs") val numRefs: Int? = null,
|
// @Json(name = "num_refs") val numRefs: Int? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The room type, which is m.space for subspaces.
|
* The room type, which is m.space for subspaces.
|
||||||
@ -33,6 +40,11 @@ internal data class SpaceChildSummaryResponse(
|
|||||||
*/
|
*/
|
||||||
@Json(name = "room_type") val roomType: String? = null,
|
@Json(name = "room_type") val roomType: String? = null,
|
||||||
|
|
||||||
|
/** The m.space.child events of the room. For each event, only the following fields are included:
|
||||||
|
* type, state_key, content, room_id, sender, with the addition of origin_server_ts: This is required for sorting of rooms as specified below.
|
||||||
|
*/
|
||||||
|
@Json(name = "children_state") val childrenState: List<Event>? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aliases of the room. May be empty.
|
* Aliases of the room. May be empty.
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 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 org.matrix.android.sdk.internal.session.space
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||||
|
|
||||||
|
data class SpaceHierarchySummary(
|
||||||
|
val rootSummary: RoomSummary,
|
||||||
|
val children: List<SpaceChildInfo>,
|
||||||
|
val childrenState: List<Event>,
|
||||||
|
val nextToken: String? = null
|
||||||
|
)
|
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
|
||||||
*
|
|
||||||
* 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 org.matrix.android.sdk.internal.session.space
|
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
|
||||||
import com.squareup.moshi.JsonClass
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
internal data class SpaceSummaryParams(
|
|
||||||
/** The maximum number of rooms/subspaces to return for a given space, if negative unbounded. default: -1 */
|
|
||||||
@Json(name = "max_rooms_per_space") val maxRoomPerSpace: Int?,
|
|
||||||
/** The maximum number of rooms/subspaces to return, server can override this, default: 100 */
|
|
||||||
@Json(name = "limit") val limit: Int?,
|
|
||||||
/** A token to use if this is a subsequent HTTP hit, default: "". */
|
|
||||||
@Json(name = "batch") val batch: String = "",
|
|
||||||
/** whether we should only return children with the "suggested" flag set. */
|
|
||||||
@Json(name = "suggested_only") val suggestedOnly: Boolean?,
|
|
||||||
/** whether we should only return children with the "suggested" flag set. */
|
|
||||||
@Json(name = "auto_join_only") val autoJoinedOnly: Boolean?
|
|
||||||
)
|
|
@ -18,14 +18,11 @@ package org.matrix.android.sdk.internal.session.space
|
|||||||
|
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
internal data class SpacesResponse(
|
internal data class SpacesResponse(
|
||||||
/** Its presence indicates that there are more results to return. */
|
/** Its presence indicates that there are more results to return. */
|
||||||
@Json(name = "next_batch") val nextBatch: String? = null,
|
@Json(name = "next_batch") val nextBatch: String? = null,
|
||||||
/** Rooms information like name/avatar/type ... */
|
/** Rooms information like name/avatar/type ... */
|
||||||
@Json(name = "rooms") val rooms: List<SpaceChildSummaryResponse>? = null,
|
@Json(name = "rooms") val rooms: List<SpaceChildSummaryResponse>? = null
|
||||||
/** These are the edges of the graph. The objects in the array are complete (or stripped?) m.room.parent or m.space.child events. */
|
|
||||||
@Json(name = "events") val events: List<Event>? = null
|
|
||||||
)
|
)
|
||||||
|
@ -103,7 +103,7 @@ internal class DefaultPeekSpaceTask @Inject constructor(
|
|||||||
// can't peek :/
|
// can't peek :/
|
||||||
spaceChildResults.add(
|
spaceChildResults.add(
|
||||||
SpaceChildPeekResult(
|
SpaceChildPeekResult(
|
||||||
childId, childPeek, entry.second?.autoJoin, entry.second?.order
|
childId, childPeek, entry.second?.order
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
// continue to next child
|
// continue to next child
|
||||||
@ -116,7 +116,7 @@ internal class DefaultPeekSpaceTask @Inject constructor(
|
|||||||
SpaceSubChildPeekResult(
|
SpaceSubChildPeekResult(
|
||||||
childId,
|
childId,
|
||||||
childPeek,
|
childPeek,
|
||||||
entry.second?.autoJoin,
|
// entry.second?.autoJoin,
|
||||||
entry.second?.order,
|
entry.second?.order,
|
||||||
peekChildren(childStateEvents, depth + 1, maxDepth)
|
peekChildren(childStateEvents, depth + 1, maxDepth)
|
||||||
)
|
)
|
||||||
@ -127,7 +127,7 @@ internal class DefaultPeekSpaceTask @Inject constructor(
|
|||||||
Timber.v("## SPACE_PEEK: room child $entry")
|
Timber.v("## SPACE_PEEK: room child $entry")
|
||||||
spaceChildResults.add(
|
spaceChildResults.add(
|
||||||
SpaceChildPeekResult(
|
SpaceChildPeekResult(
|
||||||
childId, childPeek, entry.second?.autoJoin, entry.second?.order
|
childId, childPeek, entry.second?.order
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -28,21 +28,21 @@ data class SpacePeekSummary(
|
|||||||
interface ISpaceChild {
|
interface ISpaceChild {
|
||||||
val id: String
|
val id: String
|
||||||
val roomPeekResult: PeekResult
|
val roomPeekResult: PeekResult
|
||||||
val default: Boolean?
|
// val default: Boolean?
|
||||||
val order: String?
|
val order: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
data class SpaceChildPeekResult(
|
data class SpaceChildPeekResult(
|
||||||
override val id: String,
|
override val id: String,
|
||||||
override val roomPeekResult: PeekResult,
|
override val roomPeekResult: PeekResult,
|
||||||
override val default: Boolean? = null,
|
// override val default: Boolean? = null,
|
||||||
override val order: String? = null
|
override val order: String? = null
|
||||||
) : ISpaceChild
|
) : ISpaceChild
|
||||||
|
|
||||||
data class SpaceSubChildPeekResult(
|
data class SpaceSubChildPeekResult(
|
||||||
override val id: String,
|
override val id: String,
|
||||||
override val roomPeekResult: PeekResult,
|
override val roomPeekResult: PeekResult,
|
||||||
override val default: Boolean?,
|
// override val default: Boolean?,
|
||||||
override val order: String?,
|
override val order: String?,
|
||||||
val children: List<ISpaceChild>
|
val children: List<ISpaceChild>
|
||||||
) : ISpaceChild
|
) : ISpaceChild
|
||||||
|
@ -80,7 +80,7 @@ class UpgradeRoomViewModelTask @Inject constructor(
|
|||||||
roomId = updatedRoomId,
|
roomId = updatedRoomId,
|
||||||
viaServers = currentInfo.via,
|
viaServers = currentInfo.via,
|
||||||
order = currentInfo.order,
|
order = currentInfo.order,
|
||||||
autoJoin = currentInfo.autoJoin ?: false,
|
// autoJoin = currentInfo.autoJoin ?: false,
|
||||||
suggested = currentInfo.suggested
|
suggested = currentInfo.suggested
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -230,8 +230,11 @@ class RoomListSectionBuilderSpace(
|
|||||||
Observable.just(emptyList())
|
Observable.just(emptyList())
|
||||||
} else {
|
} else {
|
||||||
liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
|
liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
|
||||||
val spaceSum = tryOrNull { session.spaceService().querySpaceChildren(selectedSpace.roomId, suggestedOnly = true) }
|
val spaceSum = tryOrNull {
|
||||||
val value = spaceSum?.second.orEmpty().distinctBy { it.childRoomId }
|
session.spaceService()
|
||||||
|
.querySpaceChildren(selectedSpace.roomId, suggestedOnly = true, null, null)
|
||||||
|
}
|
||||||
|
val value = spaceSum?.children.orEmpty().distinctBy { it.childRoomId }
|
||||||
// i need to check if it's already joined.
|
// i need to check if it's already joined.
|
||||||
val filtered = value.filter {
|
val filtered = value.filter {
|
||||||
session.getRoomSummary(it.childRoomId)?.membership?.isActive() != true
|
session.getRoomSummary(it.childRoomId)?.membership?.isActive() != true
|
||||||
|
@ -62,7 +62,7 @@ class SpaceCardRenderer @Inject constructor(
|
|||||||
inCard.matrixToAccessImage.isVisible = true
|
inCard.matrixToAccessImage.isVisible = true
|
||||||
inCard.matrixToAccessImage.setImageResource(R.drawable.ic_room_private)
|
inCard.matrixToAccessImage.setImageResource(R.drawable.ic_room_private)
|
||||||
}
|
}
|
||||||
val memberCount = spaceSummary.otherMemberIds.size
|
val memberCount = spaceSummary.joinedMembersCount?.let { it - 1 } ?: 0
|
||||||
if (memberCount != 0) {
|
if (memberCount != 0) {
|
||||||
inCard.matrixToMemberPills.isVisible = true
|
inCard.matrixToMemberPills.isVisible = true
|
||||||
inCard.spaceChildMemberCountText.text = stringProvider.getQuantityString(R.plurals.room_title_members, memberCount, memberCount)
|
inCard.spaceChildMemberCountText.text = stringProvider.getQuantityString(R.plurals.room_title_members, memberCount, memberCount)
|
||||||
|
@ -134,7 +134,7 @@ class CreateSpaceViewModelTask @Inject constructor(
|
|||||||
timeout.roomID
|
timeout.roomID
|
||||||
}
|
}
|
||||||
val via = session.sessionParams.homeServerHost?.let { listOf(it) } ?: emptyList()
|
val via = session.sessionParams.homeServerHost?.let { listOf(it) } ?: emptyList()
|
||||||
createdSpace!!.addChildren(roomId, via, null, autoJoin = false, suggested = true)
|
createdSpace!!.addChildren(roomId, via, null, suggested = true)
|
||||||
// set canonical
|
// set canonical
|
||||||
session.spaceService().setSpaceParent(
|
session.spaceService().setSpaceParent(
|
||||||
roomId,
|
roomId,
|
||||||
|
@ -18,8 +18,10 @@ package im.vector.app.features.spaces.explore
|
|||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import com.airbnb.epoxy.TypedEpoxyController
|
import com.airbnb.epoxy.TypedEpoxyController
|
||||||
|
import com.airbnb.epoxy.VisibilityState
|
||||||
import com.airbnb.mvrx.Fail
|
import com.airbnb.mvrx.Fail
|
||||||
import com.airbnb.mvrx.Incomplete
|
import com.airbnb.mvrx.Incomplete
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.ClickListener
|
import im.vector.app.core.epoxy.ClickListener
|
||||||
import im.vector.app.core.epoxy.errorWithRetryItem
|
import im.vector.app.core.epoxy.errorWithRetryItem
|
||||||
@ -54,13 +56,15 @@ class SpaceDirectoryController @Inject constructor(
|
|||||||
fun onRoomClick(spaceChildInfo: SpaceChildInfo)
|
fun onRoomClick(spaceChildInfo: SpaceChildInfo)
|
||||||
fun retry()
|
fun retry()
|
||||||
fun addExistingRooms(spaceId: String)
|
fun addExistingRooms(spaceId: String)
|
||||||
|
fun loadAdditionalItemsIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
var listener: InteractionListener? = null
|
var listener: InteractionListener? = null
|
||||||
|
|
||||||
override fun buildModels(data: SpaceDirectoryState?) {
|
override fun buildModels(data: SpaceDirectoryState?) {
|
||||||
val host = this
|
val host = this
|
||||||
val results = data?.spaceSummaryApiResult
|
val currentRootId = data?.hierarchyStack?.lastOrNull() ?: data?.spaceId ?: return
|
||||||
|
val results = data?.apiResults?.get(currentRootId)
|
||||||
|
|
||||||
if (results is Incomplete) {
|
if (results is Incomplete) {
|
||||||
loadingItem {
|
loadingItem {
|
||||||
@ -94,7 +98,9 @@ class SpaceDirectoryController @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val flattenChildInfo = results?.invoke()
|
val hierarchySummary = results?.invoke()
|
||||||
|
val flattenChildInfo = hierarchySummary
|
||||||
|
?.children
|
||||||
?.filter {
|
?.filter {
|
||||||
it.parentRoomId == (data.hierarchyStack.lastOrNull() ?: data.spaceId)
|
it.parentRoomId == (data.hierarchyStack.lastOrNull() ?: data.spaceId)
|
||||||
}
|
}
|
||||||
@ -132,6 +138,7 @@ class SpaceDirectoryController @Inject constructor(
|
|||||||
// if it's known use that matrixItem because it would have a better computed name
|
// if it's known use that matrixItem because it would have a better computed name
|
||||||
val matrixItem = data?.knownRoomSummaries?.find { it.roomId == info.childRoomId }?.toMatrixItem()
|
val matrixItem = data?.knownRoomSummaries?.find { it.roomId == info.childRoomId }?.toMatrixItem()
|
||||||
?: info.toMatrixItem()
|
?: info.toMatrixItem()
|
||||||
|
|
||||||
spaceChildInfoItem {
|
spaceChildInfoItem {
|
||||||
id(info.childRoomId)
|
id(info.childRoomId)
|
||||||
matrixItem(matrixItem)
|
matrixItem(matrixItem)
|
||||||
@ -162,6 +169,28 @@ class SpaceDirectoryController @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (hierarchySummary?.nextToken != null) {
|
||||||
|
val paginationStatus = data.paginationStatus[currentRootId] ?: Uninitialized
|
||||||
|
if (paginationStatus is Fail) {
|
||||||
|
errorWithRetryItem {
|
||||||
|
id("error_${currentRootId}_${hierarchySummary.nextToken}")
|
||||||
|
text(host.errorFormatter.toHumanReadable(paginationStatus.error))
|
||||||
|
listener { host.listener?.retry() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
loadingItem {
|
||||||
|
id("pagination_${currentRootId}_${hierarchySummary.nextToken}")
|
||||||
|
showLoader(true)
|
||||||
|
onVisibilityStateChanged { _, _, visibilityState ->
|
||||||
|
// Do something with the new visibility state
|
||||||
|
if (visibilityState == VisibilityState.VISIBLE) {
|
||||||
|
// we can trigger a seamless load of additional items
|
||||||
|
host.listener?.loadAdditionalItemsIfNeeded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.text.toSpannable
|
import androidx.core.text.toSpannable
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import com.airbnb.epoxy.EpoxyVisibilityTracker
|
||||||
import com.airbnb.mvrx.activityViewModel
|
import com.airbnb.mvrx.activityViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
@ -72,6 +73,7 @@ class SpaceDirectoryFragment @Inject constructor(
|
|||||||
FragmentSpaceDirectoryBinding.inflate(layoutInflater, container, false)
|
FragmentSpaceDirectoryBinding.inflate(layoutInflater, container, false)
|
||||||
|
|
||||||
private val viewModel by activityViewModel(SpaceDirectoryViewModel::class)
|
private val viewModel by activityViewModel(SpaceDirectoryViewModel::class)
|
||||||
|
private val epoxyVisibilityTracker = EpoxyVisibilityTracker()
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@ -84,6 +86,7 @@ class SpaceDirectoryFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
epoxyController.listener = this
|
epoxyController.listener = this
|
||||||
views.spaceDirectoryList.configureWith(epoxyController)
|
views.spaceDirectoryList.configureWith(epoxyController)
|
||||||
|
epoxyVisibilityTracker.attach(views.spaceDirectoryList)
|
||||||
|
|
||||||
viewModel.selectSubscribe(this, SpaceDirectoryState::canAddRooms) {
|
viewModel.selectSubscribe(this, SpaceDirectoryState::canAddRooms) {
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
@ -95,6 +98,7 @@ class SpaceDirectoryFragment @Inject constructor(
|
|||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
epoxyController.listener = null
|
epoxyController.listener = null
|
||||||
|
epoxyVisibilityTracker.detach(views.spaceDirectoryList)
|
||||||
views.spaceDirectoryList.cleanup()
|
views.spaceDirectoryList.cleanup()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
@ -102,21 +106,20 @@ class SpaceDirectoryFragment @Inject constructor(
|
|||||||
override fun invalidate() = withState(viewModel) { state ->
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
epoxyController.setData(state)
|
epoxyController.setData(state)
|
||||||
|
|
||||||
val currentParent = state.hierarchyStack.lastOrNull()?.let { currentParent ->
|
val currentParentId = state.hierarchyStack.lastOrNull()
|
||||||
state.spaceSummaryApiResult.invoke()?.firstOrNull { it.childRoomId == currentParent }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentParent == null) {
|
if (currentParentId == null) {
|
||||||
|
// it's the root
|
||||||
val title = getString(R.string.space_explore_activity_title)
|
val title = getString(R.string.space_explore_activity_title)
|
||||||
views.toolbar.title = title
|
views.toolbar.title = title
|
||||||
|
|
||||||
spaceCardRenderer.render(state.spaceSummary.invoke(), emptyList(), this, views.spaceCard)
|
|
||||||
} else {
|
} else {
|
||||||
val title = currentParent.name ?: currentParent.canonicalAlias ?: getString(R.string.space_explore_activity_title)
|
val title = state.currentRootSummary?.name
|
||||||
|
?: state.currentRootSummary?.canonicalAlias
|
||||||
|
?: getString(R.string.space_explore_activity_title)
|
||||||
views.toolbar.title = title
|
views.toolbar.title = title
|
||||||
|
|
||||||
spaceCardRenderer.render(currentParent, emptyList(), this, views.spaceCard)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spaceCardRenderer.render(state.currentRootSummary, emptyList(), this, views.spaceCard)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu) = withState(viewModel) { state ->
|
override fun onPrepareOptionsMenu(menu: Menu) = withState(viewModel) { state ->
|
||||||
@ -170,6 +173,10 @@ class SpaceDirectoryFragment @Inject constructor(
|
|||||||
addExistingRoomActivityResult.launch(SpaceManageActivity.newIntent(requireContext(), spaceId, ManageType.AddRooms))
|
addExistingRoomActivityResult.launch(SpaceManageActivity.newIntent(requireContext(), spaceId, ManageType.AddRooms))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun loadAdditionalItemsIfNeeded() {
|
||||||
|
viewModel.handle(SpaceDirectoryViewAction.LoadAdditionalItemsIfNeeded)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onUrlClicked(url: String, title: String): Boolean {
|
override fun onUrlClicked(url: String, title: String): Boolean {
|
||||||
permalinkHandler
|
permalinkHandler
|
||||||
.launch(requireActivity(), url, null)
|
.launch(requireActivity(), url, null)
|
||||||
@ -206,7 +213,5 @@ class SpaceDirectoryFragment @Inject constructor(
|
|||||||
// nothing?
|
// nothing?
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// override fun navigateToRoom(roomId: String) {
|
|
||||||
// viewModel.handle(SpaceDirectoryViewAction.NavigateToRoom(roomId))
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
@ -18,28 +18,27 @@ package im.vector.app.features.spaces.explore
|
|||||||
|
|
||||||
import com.airbnb.mvrx.Async
|
import com.airbnb.mvrx.Async
|
||||||
import com.airbnb.mvrx.MvRxState
|
import com.airbnb.mvrx.MvRxState
|
||||||
import com.airbnb.mvrx.Uninitialized
|
|
||||||
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||||
|
import org.matrix.android.sdk.internal.session.space.SpaceHierarchySummary
|
||||||
|
|
||||||
data class SpaceDirectoryState(
|
data class SpaceDirectoryState(
|
||||||
// The current filter
|
// The current filter
|
||||||
val spaceId: String,
|
val spaceId: String,
|
||||||
val currentFilter: String = "",
|
val currentFilter: String = "",
|
||||||
val spaceSummary: Async<RoomSummary> = Uninitialized,
|
val apiResults: Map<String, Async<SpaceHierarchySummary>> = emptyMap(),
|
||||||
val spaceSummaryApiResult: Async<List<SpaceChildInfo>> = Uninitialized,
|
val currentRootSummary: RoomSummary? = null,
|
||||||
val childList: List<SpaceChildInfo> = emptyList(),
|
val childList: List<SpaceChildInfo> = emptyList(),
|
||||||
val hierarchyStack: List<String> = emptyList(),
|
val hierarchyStack: List<String> = emptyList(),
|
||||||
// True if more result are available server side
|
|
||||||
val hasMore: Boolean = false,
|
|
||||||
// Set of joined roomId / spaces,
|
// Set of joined roomId / spaces,
|
||||||
val joinedRoomsIds: Set<String> = emptySet(),
|
val joinedRoomsIds: Set<String> = emptySet(),
|
||||||
// keys are room alias or roomId
|
// keys are room alias or roomId
|
||||||
val changeMembershipStates: Map<String, ChangeMembershipState> = emptyMap(),
|
val changeMembershipStates: Map<String, ChangeMembershipState> = emptyMap(),
|
||||||
val canAddRooms: Boolean = false,
|
val canAddRooms: Boolean = false,
|
||||||
// cached room summaries of known rooms
|
// cached room summaries of known rooms, we use it because computed room name would be better using it
|
||||||
val knownRoomSummaries : List<RoomSummary> = emptyList()
|
val knownRoomSummaries : List<RoomSummary> = emptyList(),
|
||||||
|
val paginationStatus: Map<String, Async<Unit>> = emptyMap()
|
||||||
) : MvRxState {
|
) : MvRxState {
|
||||||
constructor(args: SpaceDirectoryArgs) : this(
|
constructor(args: SpaceDirectoryArgs) : this(
|
||||||
spaceId = args.spaceId
|
spaceId = args.spaceId
|
||||||
|
@ -26,4 +26,5 @@ sealed class SpaceDirectoryViewAction : VectorViewModelAction {
|
|||||||
data class NavigateToRoom(val roomId: String) : SpaceDirectoryViewAction()
|
data class NavigateToRoom(val roomId: String) : SpaceDirectoryViewAction()
|
||||||
object HandleBack : SpaceDirectoryViewAction()
|
object HandleBack : SpaceDirectoryViewAction()
|
||||||
object Retry : SpaceDirectoryViewAction()
|
object Retry : SpaceDirectoryViewAction()
|
||||||
|
object LoadAdditionalItemsIfNeeded : SpaceDirectoryViewAction()
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import com.airbnb.mvrx.FragmentViewModelContext
|
|||||||
import com.airbnb.mvrx.Loading
|
import com.airbnb.mvrx.Loading
|
||||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
@ -34,6 +35,8 @@ import kotlinx.coroutines.launch
|
|||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||||
@ -67,11 +70,11 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
|
|||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
childList = spaceSum?.spaceChildren ?: emptyList(),
|
childList = spaceSum?.spaceChildren ?: emptyList(),
|
||||||
spaceSummary = spaceSum?.let { Success(spaceSum) } ?: Loading()
|
currentRootSummary = spaceSum
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshFromApi()
|
refreshFromApi(initialState.spaceId)
|
||||||
observeJoinedRooms()
|
observeJoinedRooms()
|
||||||
observeMembershipChanges()
|
observeMembershipChanges()
|
||||||
observePermissions()
|
observePermissions()
|
||||||
@ -93,29 +96,44 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
|
|||||||
.disposeOnClear()
|
.disposeOnClear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshFromApi() {
|
private fun refreshFromApi(rootId: String?) = withState { state ->
|
||||||
|
val spaceId = rootId ?: initialState.spaceId
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
spaceSummaryApiResult = Loading()
|
apiResults = state.apiResults.toMutableMap().apply {
|
||||||
|
this[spaceId] = Loading()
|
||||||
|
}.toMap()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
val cachedResults = state.apiResults.toMutableMap()
|
||||||
try {
|
try {
|
||||||
val query = session.spaceService().querySpaceChildren(initialState.spaceId)
|
val query = session.spaceService().querySpaceChildren(
|
||||||
val knownSummaries = query.second.mapNotNull {
|
spaceId,
|
||||||
|
limit = 10
|
||||||
|
)
|
||||||
|
val knownSummaries = query.children.mapNotNull {
|
||||||
session.getRoomSummary(it.childRoomId)
|
session.getRoomSummary(it.childRoomId)
|
||||||
?.takeIf { it.membership == Membership.JOIN } // only take if joined because it will be up to date (synced)
|
?.takeIf { it.membership == Membership.JOIN } // only take if joined because it will be up to date (synced)
|
||||||
}
|
}.distinctBy { it.roomId }
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
spaceSummaryApiResult = Success(query.second),
|
apiResults = cachedResults.apply {
|
||||||
knownRoomSummaries = knownSummaries
|
this[spaceId] = Success(query)
|
||||||
|
},
|
||||||
|
currentRootSummary = query.rootSummary,
|
||||||
|
paginationStatus = state.paginationStatus.toMutableMap().apply {
|
||||||
|
this[spaceId] = Uninitialized
|
||||||
|
}.toMap(),
|
||||||
|
knownRoomSummaries = (state.knownRoomSummaries + knownSummaries).distinctBy { it.roomId },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
spaceSummaryApiResult = Fail(failure)
|
apiResults = cachedResults.apply {
|
||||||
|
this[spaceId] = Fail(failure)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,39 +167,143 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
|
|||||||
|
|
||||||
override fun handle(action: SpaceDirectoryViewAction) {
|
override fun handle(action: SpaceDirectoryViewAction) {
|
||||||
when (action) {
|
when (action) {
|
||||||
is SpaceDirectoryViewAction.ExploreSubSpace -> {
|
is SpaceDirectoryViewAction.ExploreSubSpace -> {
|
||||||
setState {
|
handleExploreSubSpace(action)
|
||||||
copy(hierarchyStack = hierarchyStack + listOf(action.spaceChildInfo.childRoomId))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
SpaceDirectoryViewAction.HandleBack -> {
|
SpaceDirectoryViewAction.HandleBack -> {
|
||||||
withState {
|
handleBack()
|
||||||
if (it.hierarchyStack.isEmpty()) {
|
|
||||||
_viewEvents.post(SpaceDirectoryViewEvents.Dismiss)
|
|
||||||
} else {
|
|
||||||
setState {
|
|
||||||
copy(
|
|
||||||
hierarchyStack = hierarchyStack.dropLast(1)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
is SpaceDirectoryViewAction.JoinOrOpen -> {
|
is SpaceDirectoryViewAction.JoinOrOpen -> {
|
||||||
handleJoinOrOpen(action.spaceChildInfo)
|
handleJoinOrOpen(action.spaceChildInfo)
|
||||||
}
|
}
|
||||||
is SpaceDirectoryViewAction.NavigateToRoom -> {
|
is SpaceDirectoryViewAction.NavigateToRoom -> {
|
||||||
_viewEvents.post(SpaceDirectoryViewEvents.NavigateToRoom(action.roomId))
|
_viewEvents.post(SpaceDirectoryViewEvents.NavigateToRoom(action.roomId))
|
||||||
}
|
}
|
||||||
is SpaceDirectoryViewAction.ShowDetails -> {
|
is SpaceDirectoryViewAction.ShowDetails -> {
|
||||||
// This is temporary for now to at least display something for the space beta
|
// This is temporary for now to at least display something for the space beta
|
||||||
// It's not ideal as it's doing some peeking that is not needed.
|
// It's not ideal as it's doing some peeking that is not needed.
|
||||||
session.permalinkService().createRoomPermalink(action.spaceChildInfo.childRoomId)?.let {
|
session.permalinkService().createRoomPermalink(action.spaceChildInfo.childRoomId)?.let {
|
||||||
_viewEvents.post(SpaceDirectoryViewEvents.NavigateToMxToBottomSheet(it))
|
_viewEvents.post(SpaceDirectoryViewEvents.NavigateToMxToBottomSheet(it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SpaceDirectoryViewAction.Retry -> {
|
SpaceDirectoryViewAction.Retry -> {
|
||||||
refreshFromApi()
|
handleRetry()
|
||||||
|
}
|
||||||
|
SpaceDirectoryViewAction.LoadAdditionalItemsIfNeeded -> {
|
||||||
|
loadAdditionalItemsIfNeeded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleBack() = withState { state ->
|
||||||
|
if (state.hierarchyStack.isEmpty()) {
|
||||||
|
_viewEvents.post(SpaceDirectoryViewEvents.Dismiss)
|
||||||
|
} else {
|
||||||
|
val newStack = state.hierarchyStack.dropLast(1)
|
||||||
|
val newRootId = newStack.lastOrNull() ?: initialState.spaceId
|
||||||
|
val rootSummary = state.apiResults[newRootId]?.invoke()?.rootSummary
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
hierarchyStack = hierarchyStack.dropLast(1),
|
||||||
|
currentRootSummary = rootSummary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRetry() = withState { state ->
|
||||||
|
refreshFromApi(state.hierarchyStack.lastOrNull() ?: initialState.spaceId)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleExploreSubSpace(action: SpaceDirectoryViewAction.ExploreSubSpace) = withState { state ->
|
||||||
|
val newRootId = action.spaceChildInfo.childRoomId
|
||||||
|
val curSum = RoomSummary(
|
||||||
|
roomId = action.spaceChildInfo.childRoomId,
|
||||||
|
roomType = action.spaceChildInfo.roomType,
|
||||||
|
name = action.spaceChildInfo.name ?: "",
|
||||||
|
canonicalAlias = action.spaceChildInfo.canonicalAlias,
|
||||||
|
topic = action.spaceChildInfo.topic ?: "",
|
||||||
|
joinedMembersCount = action.spaceChildInfo.activeMemberCount,
|
||||||
|
avatarUrl = action.spaceChildInfo.avatarUrl ?: "",
|
||||||
|
isEncrypted = false,
|
||||||
|
joinRules = if (action.spaceChildInfo.worldReadable) RoomJoinRules.PUBLIC else RoomJoinRules.PRIVATE,
|
||||||
|
encryptionEventTs = 0,
|
||||||
|
typingUsers = emptyList()
|
||||||
|
)
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
hierarchyStack = hierarchyStack + listOf(newRootId),
|
||||||
|
currentRootSummary = curSum
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val shouldLoad = when (state.apiResults[newRootId]) {
|
||||||
|
Uninitialized -> true
|
||||||
|
is Loading -> false
|
||||||
|
is Success -> false
|
||||||
|
is Fail -> true
|
||||||
|
null -> true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldLoad) {
|
||||||
|
refreshFromApi(newRootId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadAdditionalItemsIfNeeded() = withState { state ->
|
||||||
|
val currentRootId = state.hierarchyStack.lastOrNull() ?: initialState.spaceId
|
||||||
|
val mutablePaginationStatus = state.paginationStatus.toMutableMap().apply {
|
||||||
|
if (this[currentRootId] == null) {
|
||||||
|
this[currentRootId] = Uninitialized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mutablePaginationStatus[currentRootId] is Loading) return@withState
|
||||||
|
|
||||||
|
setState {
|
||||||
|
copy(paginationStatus = mutablePaginationStatus.toMap())
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
val cachedResults = state.apiResults.toMutableMap()
|
||||||
|
try {
|
||||||
|
val currentResponse = cachedResults[currentRootId]?.invoke()
|
||||||
|
if (currentResponse == null) {
|
||||||
|
// nothing to paginate through...
|
||||||
|
setState {
|
||||||
|
copy(paginationStatus = mutablePaginationStatus.apply { this[currentRootId] = Uninitialized }.toMap())
|
||||||
|
}
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
val query = session.spaceService().querySpaceChildren(
|
||||||
|
currentRootId,
|
||||||
|
limit = 10,
|
||||||
|
from = currentResponse.nextToken,
|
||||||
|
knownStateList = currentResponse.childrenState
|
||||||
|
)
|
||||||
|
val knownSummaries = query.children.mapNotNull {
|
||||||
|
session.getRoomSummary(it.childRoomId)
|
||||||
|
?.takeIf { it.membership == Membership.JOIN } // only take if joined because it will be up to date (synced)
|
||||||
|
}.distinctBy { it.roomId }
|
||||||
|
|
||||||
|
cachedResults[currentRootId] = Success(
|
||||||
|
currentResponse.copy(
|
||||||
|
children = currentResponse.children + query.children,
|
||||||
|
nextToken = query.nextToken,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
apiResults = cachedResults.toMap(),
|
||||||
|
paginationStatus = mutablePaginationStatus.apply { this[currentRootId] = Success(Unit) }.toMap(),
|
||||||
|
knownRoomSummaries = (state.knownRoomSummaries + knownSummaries).distinctBy { it.roomId }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
paginationStatus = mutablePaginationStatus.apply { this[currentRootId] = Fail(failure) }.toMap()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ class SpaceManageRoomsViewModel @AssistedInject constructor(
|
|||||||
|
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
val apiResult = runCatchingToAsync {
|
val apiResult = runCatchingToAsync {
|
||||||
session.spaceService().querySpaceChildren(spaceId = initialState.spaceId).second
|
session.spaceService().querySpaceChildren(spaceId = initialState.spaceId).children
|
||||||
}
|
}
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
@ -131,8 +131,8 @@ class SpaceManageRoomsViewModel @AssistedInject constructor(
|
|||||||
roomId = info.childRoomId,
|
roomId = info.childRoomId,
|
||||||
viaServers = info.viaServers,
|
viaServers = info.viaServers,
|
||||||
order = info.order,
|
order = info.order,
|
||||||
suggested = suggested,
|
suggested = suggested
|
||||||
autoJoin = info.autoJoin
|
// autoJoin = info.autoJoin
|
||||||
)
|
)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
errorList.add(failure)
|
errorList.add(failure)
|
||||||
@ -156,7 +156,7 @@ class SpaceManageRoomsViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
val apiResult = runCatchingToAsync {
|
val apiResult = runCatchingToAsync {
|
||||||
session.spaceService().querySpaceChildren(spaceId = initialState.spaceId).second
|
session.spaceService().querySpaceChildren(spaceId = initialState.spaceId).children
|
||||||
}
|
}
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
|
@ -151,7 +151,7 @@ class SpacePreviewViewModel @AssistedInject constructor(
|
|||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
spaceInfo = Success(
|
spaceInfo = Success(
|
||||||
resolveResult.first.let {
|
resolveResult.rootSummary.let {
|
||||||
ChildInfo(
|
ChildInfo(
|
||||||
roomId = it.roomId,
|
roomId = it.roomId,
|
||||||
avatarUrl = it.avatarUrl,
|
avatarUrl = it.avatarUrl,
|
||||||
@ -165,7 +165,7 @@ class SpacePreviewViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
childInfoList = Success(
|
childInfoList = Success(
|
||||||
resolveResult.second.map {
|
resolveResult.children.map {
|
||||||
ChildInfo(
|
ChildInfo(
|
||||||
roomId = it.childRoomId,
|
roomId = it.childRoomId,
|
||||||
avatarUrl = it.avatarUrl,
|
avatarUrl = it.avatarUrl,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user