From e2578a29ed905ffe9095e663d51c325d96f14e9e Mon Sep 17 00:00:00 2001 From: Valere Date: Tue, 12 Jan 2021 11:40:09 +0100 Subject: [PATCH] Basic space join / use tmp msc id / db model update --- .../api/session/room/model/SpaceChildInfo.kt | 25 ++++ .../room/model/create/CreateRoomParams.kt | 3 +- .../sdk/api/session/space/SpaceSummary.kt | 3 +- .../session/space/model/SpaceChildContent.kt | 2 +- .../sdk/internal/database/RealmQueryLatch.kt | 2 + .../database/RealmSessionStoreMigration.kt | 11 +- .../database/mapper/SpaceSummaryMapper.kt | 9 +- .../database/model/SessionRealmModule.kt | 3 +- .../database/model/SpaceChildInfoEntity.kt | 38 ++++++ .../database/model/SpaceSummaryEntity.kt | 2 +- .../sdk/internal/session/room/RoomModule.kt | 5 + .../relationship/RoomRelationshipHelper.kt | 24 +++- .../room/summary/RoomSummaryUpdater.kt | 19 ++- .../session/space/DefaultSpaceService.kt | 35 +++--- .../internal/session/space/JoinSpaceTask.kt | 116 ++++++++++++++++++ .../session/space/peeking/SpacePeekResult.kt | 2 +- .../internal/session/sync/RoomSyncHandler.kt | 1 + vector/src/main/AndroidManifest.xml | 1 + .../im/vector/app/core/di/FragmentModule.kt | 2 +- .../app/features/home/HomeDrawerFragment.kt | 2 +- .../features/spaces/SpaceExploreActivity.kt | 73 +++++++++++ .../SpaceListFragment.kt | 10 +- .../SpaceSummaryController.kt | 10 +- .../{grouplist => spaces}/SpaceSummaryItem.kt | 2 +- .../features/spaces/SpacesListViewModel.kt | 13 +- .../explore/SpaceDirectoryController.kt | 53 ++++++++ .../spaces/explore/SpaceDirectoryFragment.kt | 35 ++++++ .../spaces/explore/SpaceDirectoryViewModel.kt | 101 +++++++++++++++ 28 files changed, 549 insertions(+), 53 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/SpaceChildInfo.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceChildInfoEntity.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/JoinSpaceTask.kt create mode 100644 vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt rename vector/src/main/java/im/vector/app/features/{grouplist => spaces}/SpaceListFragment.kt (91%) rename vector/src/main/java/im/vector/app/features/{grouplist => spaces}/SpaceSummaryController.kt (95%) rename vector/src/main/java/im/vector/app/features/{grouplist => spaces}/SpaceSummaryItem.kt (98%) create mode 100644 vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryController.kt create mode 100644 vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryFragment.kt create mode 100644 vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewModel.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/SpaceChildInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/SpaceChildInfo.kt new file mode 100644 index 0000000000..04f3310a77 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/SpaceChildInfo.kt @@ -0,0 +1,25 @@ +/* + * 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.api.session.room.model + +data class SpaceChildInfo( + val roomSummary: IRoomSummary?, + val present: Boolean, + val order: String?, + val autoJoin: Boolean, + val viaServers: List +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt index 6009649314..880854da58 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt @@ -21,7 +21,6 @@ import org.matrix.android.sdk.api.session.identity.ThreePid 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.RoomHistoryVisibility -import org.matrix.android.sdk.api.session.room.model.RoomType import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM // TODO Give a way to include other initial states @@ -112,7 +111,7 @@ open class CreateRoomParams { } } - var roomType: String? = RoomType.MESSAGING + var roomType: String? = null // RoomType.MESSAGING set(value) { field = value if (value != null) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceSummary.kt index d2be2f18f1..1473ed7a96 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceSummary.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceSummary.kt @@ -18,9 +18,10 @@ package org.matrix.android.sdk.api.session.space import org.matrix.android.sdk.api.session.room.model.IRoomSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo data class SpaceSummary( val spaceId: String, val roomSummary: RoomSummary, - val children: List + val children: List ) : IRoomSummary by roomSummary diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceChildContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceChildContent.kt index f7bd067c55..e31ff5af5c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceChildContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceChildContent.kt @@ -49,5 +49,5 @@ data class SpaceChildContent( * The default flag on a child listing allows a space admin to list the "default" sub-spaces and rooms in that space. * This means that when a user joins the parent space, they will automatically be joined to those default children. */ - @Json(name = "default") val default: Boolean? = true + @Json(name = "default") val default: Boolean? = false ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmQueryLatch.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmQueryLatch.kt index c9c797304a..04f47bfccd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmQueryLatch.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmQueryLatch.kt @@ -26,6 +26,7 @@ import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeout +import timber.log.Timber internal suspend fun awaitNotEmptyResult(realmConfiguration: RealmConfiguration, timeoutMillis: Long, @@ -40,6 +41,7 @@ internal suspend fun awaitNotEmptyResult(realmConfiguration: RealmConfigurat val listener = object : RealmChangeListener> { override fun onChange(it: RealmResults) { + Timber.v("## Space: $it") if (it.isNotEmpty()) { result.removeChangeListener(this) latch.complete(Unit) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt index 2c06a4e8f7..27b2b031e4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt @@ -29,9 +29,9 @@ import org.matrix.android.sdk.internal.database.model.PreviewUrlCacheEntityField import org.matrix.android.sdk.internal.database.model.RoomEntityFields import org.matrix.android.sdk.internal.database.model.RoomMembersLoadStatusType import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields - import org.matrix.android.sdk.internal.database.model.RoomTagEntityFields import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields +import org.matrix.android.sdk.internal.database.model.SpaceChildInfoEntityFields import org.matrix.android.sdk.internal.database.model.SpaceSummaryEntityFields import timber.log.Timber import javax.inject.Inject @@ -207,9 +207,16 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { obj.setString(RoomSummaryEntityFields.ROOM_TYPE, null) } + val spaceChildInfoSchema = realm.schema.create("SpaceChildInfoEntity") + ?.addField(SpaceChildInfoEntityFields.ORDER, String::class.java) + ?.addField(SpaceChildInfoEntityFields.PRESENT, Boolean::class.java) + ?.setNullable(SpaceChildInfoEntityFields.PRESENT, true) + ?.addRealmListField(SpaceChildInfoEntityFields.VIA_SERVERS.`$`, String::class.java) + ?.addRealmObjectField(SpaceChildInfoEntityFields.ROOM_SUMMARY_ENTITY.`$`, realm.schema.get("RoomSummaryEntity")!!) + realm.schema.create("SpaceSummaryEntity") ?.addField(SpaceSummaryEntityFields.SPACE_ID, String::class.java, FieldAttribute.PRIMARY_KEY) ?.addRealmObjectField(SpaceSummaryEntityFields.ROOM_SUMMARY_ENTITY.`$`, realm.schema.get("RoomSummaryEntity")!!) - ?.addRealmListField(SpaceSummaryEntityFields.CHILDREN.`$`, realm.schema.get("RoomSummaryEntity")!!) + ?.addRealmListField(SpaceSummaryEntityFields.CHILDREN.`$`, spaceChildInfoSchema!!) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/SpaceSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/SpaceSummaryMapper.kt index 9dee99d7fe..7128501a65 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/SpaceSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/SpaceSummaryMapper.kt @@ -16,6 +16,7 @@ package org.matrix.android.sdk.internal.database.mapper +import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo import org.matrix.android.sdk.api.session.space.SpaceSummary import org.matrix.android.sdk.internal.database.model.SpaceSummaryEntity import javax.inject.Inject @@ -27,7 +28,13 @@ internal class SpaceSummaryMapper @Inject constructor(private val roomSummaryMap spaceId = spaceSummaryEntity.spaceId, roomSummary = roomSummaryMapper.map(spaceSummaryEntity.roomSummaryEntity!!), children = spaceSummaryEntity.children.map { - roomSummaryMapper.map(it) + SpaceChildInfo( + roomSummary = it.roomSummaryEntity?.let { rs -> roomSummaryMapper.map(rs) }, + autoJoin = it.autoJoin ?: false, + present = it.present ?: false, + viaServers = it.viaServers.map { it }, + order = it.order + ) } ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt index 8c5bb8e990..76116be1a8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt @@ -62,6 +62,7 @@ import io.realm.annotations.RealmModule UserAccountDataEntity::class, ScalarTokenEntity::class, WellknownIntegrationManagerConfigEntity::class, - SpaceSummaryEntity::class + SpaceSummaryEntity::class, + SpaceChildInfoEntity::class ]) internal class SessionRealmModule diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceChildInfoEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceChildInfoEntity.kt new file mode 100644 index 0000000000..68667c55fc --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceChildInfoEntity.kt @@ -0,0 +1,38 @@ +/* + * 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.database.model + +import io.realm.RealmList +import io.realm.RealmObject + +/** + * Decorates room summary with space related information. + */ +internal open class SpaceChildInfoEntity( + var viaServers: RealmList = RealmList(), + // it's an active child of the space if and only if present is not null and true + var present: Boolean? = null, + // Use for alphabetic ordering of this child + var order: String? = null, + // If true, this child should be join when parent is joined + var autoJoin: Boolean? = null, + // link to the actual room (check type to see if it's a subspace) + var roomSummaryEntity: RoomSummaryEntity? = null +) : RealmObject() { + + companion object +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceSummaryEntity.kt index ca54655022..e63b5b9d55 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SpaceSummaryEntity.kt @@ -22,7 +22,7 @@ import io.realm.annotations.PrimaryKey internal open class SpaceSummaryEntity(@PrimaryKey var spaceId: String = "", var roomSummaryEntity: RoomSummaryEntity? = null, - var children: RealmList = RealmList() + var children: RealmList = RealmList() // TODO public / private .. and more ) : RealmObject() { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt index b7c4246eca..8cc7f41d5b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt @@ -90,7 +90,9 @@ import org.matrix.android.sdk.internal.session.room.typing.DefaultSendTypingTask import org.matrix.android.sdk.internal.session.room.typing.SendTypingTask import org.matrix.android.sdk.internal.session.room.uploads.DefaultGetUploadsTask import org.matrix.android.sdk.internal.session.room.uploads.GetUploadsTask +import org.matrix.android.sdk.internal.session.space.DefaultJoinSpaceTask import org.matrix.android.sdk.internal.session.space.DefaultSpaceService +import org.matrix.android.sdk.internal.session.space.JoinSpaceTask import org.matrix.android.sdk.internal.session.space.peeking.DefaultPeekSpaceTask import org.matrix.android.sdk.internal.session.space.peeking.PeekSpaceTask import retrofit2.Retrofit @@ -241,6 +243,9 @@ internal abstract class RoomModule { @Binds abstract fun bindPeekSpaceTask(task: DefaultPeekSpaceTask): PeekSpaceTask + @Binds + abstract fun bindJoinSpaceTask(task: DefaultJoinSpaceTask): JoinSpaceTask + @Binds abstract fun bindGetEventTask(task: DefaultGetEventTask): GetEventTask } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relationship/RoomRelationshipHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relationship/RoomRelationshipHelper.kt index b1bcfc7077..54b9a17c3c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relationship/RoomRelationshipHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relationship/RoomRelationshipHelper.kt @@ -23,6 +23,7 @@ import org.matrix.android.sdk.api.session.space.model.SpaceChildContent import org.matrix.android.sdk.internal.database.mapper.ContentMapper import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity import org.matrix.android.sdk.internal.database.query.whereType +import timber.log.Timber /** * Relationship between rooms and spaces @@ -38,13 +39,30 @@ internal class RoomRelationshipHelper(private val realm: Realm, private val roomId: String ) { - fun getDirectChildrenDescriptions(): List { + data class SpaceChildInfo( + val roomId: String, + val present: Boolean, + val order: String?, + val autoJoin: Boolean, + val viaServers: List + ) + + fun getDirectChildrenDescriptions(): List { return CurrentStateEventEntity.whereType(realm, roomId, EventType.STATE_SPACE_CHILD) .findAll() - .filter { ContentMapper.map(it.root?.content).toModel()?.present == true } +// .filter { ContentMapper.map(it.root?.content).toModel()?.present == true } .mapNotNull { // ContentMapper.map(it.root?.content).toModel() - it.stateKey + ContentMapper.map(it.root?.content).toModel()?.let { scc -> + Timber.d("## Space child desc state event $scc") + SpaceChildInfo( + roomId = it.stateKey, + present = scc.present ?: false, + order = scc.order, + autoJoin = scc.default ?: false, + viaServers = scc.via ?: emptyList() + ) + } } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt index 7b637cc9e9..11d0ffffde 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.session.room.summary import io.realm.Realm +import io.realm.kotlin.createObject import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel @@ -38,6 +39,7 @@ import org.matrix.android.sdk.internal.database.model.EventEntity import org.matrix.android.sdk.internal.database.model.EventEntityFields import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity +import org.matrix.android.sdk.internal.database.model.SpaceChildInfoEntity import org.matrix.android.sdk.internal.database.model.SpaceSummaryEntity import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.query.findAllInRoomWithSendStates @@ -162,13 +164,26 @@ internal class RoomSummaryUpdater @Inject constructor( } if (roomType == RoomType.SPACE) { - val spaceSummaryEntity = SpaceSummaryEntity.getOrCreate(realm, roomId) + Timber.v("## Space: Updating summary for Space $roomId membership: ${roomSummaryEntity.membership}") + val spaceSummaryEntity = SpaceSummaryEntity() + spaceSummaryEntity.spaceId = roomId spaceSummaryEntity.roomSummaryEntity = roomSummaryEntity spaceSummaryEntity.children.clear() spaceSummaryEntity.children.addAll( RoomRelationshipHelper(realm, roomId).getDirectChildrenDescriptions() - .map { RoomSummaryEntity.getOrCreate(realm, it) } + .map { + Timber.v("## Space: Updating summary for room $roomId with info $it") + realm.createObject().apply { + this.roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, it.roomId) + this.order = it.order + this.present = it.present + this.autoJoin = it.autoJoin + }.also { + Timber.v("## Space: Updating summary for room $roomId with children $it") + } + } ) + realm.insertOrUpdate(spaceSummaryEntity) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt index 4118d74604..973904cbd5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt @@ -42,6 +42,7 @@ internal class DefaultSpaceService @Inject constructor( @SessionDatabase private val monarchy: Monarchy, private val createRoomTask: CreateRoomTask, private val joinRoomTask: JoinRoomTask, + private val joinSpaceTask: JoinSpaceTask, private val markAllRoomsReadTask: MarkAllRoomsReadTask, private val updateBreadcrumbsTask: UpdateBreadcrumbsTask, private val roomIdByAliasTask: GetRoomIdByAliasTask, @@ -77,22 +78,24 @@ internal class DefaultSpaceService @Inject constructor( override suspend fun joinSpace(spaceIdOrAlias: String, reason: String?, viaServers: List, autoJoinChild: List): SpaceService.JoinSpaceResult { try { - joinRoomTask.execute(JoinRoomTask.Params(spaceIdOrAlias, reason, viaServers)) - val childJoinFailures = mutableMapOf() - autoJoinChild.forEach { info -> - // TODO what if the child is it self a subspace with some default children? - try { - joinRoomTask.execute(JoinRoomTask.Params(info.roomIdOrAlias, null, info.viaServers)) - } catch (failure: Throwable) { - // TODO, i could already be a member of this room, handle that as it should not be an error in this context - childJoinFailures[info.roomIdOrAlias] = failure - } - } - return if (childJoinFailures.isEmpty()) { - SpaceService.JoinSpaceResult.Success - } else { - SpaceService.JoinSpaceResult.PartialSuccess(childJoinFailures) - } + joinSpaceTask.execute(JoinSpaceTask.Params(spaceIdOrAlias, reason, viaServers)) + // TODO partial success + return SpaceService.JoinSpaceResult.Success +// val childJoinFailures = mutableMapOf() +// autoJoinChild.forEach { info -> +// // TODO what if the child is it self a subspace with some default children? +// try { +// joinRoomTask.execute(JoinRoomTask.Params(info.roomIdOrAlias, null, info.viaServers)) +// } catch (failure: Throwable) { +// // TODO, i could already be a member of this room, handle that as it should not be an error in this context +// childJoinFailures[info.roomIdOrAlias] = failure +// } +// } +// return if (childJoinFailures.isEmpty()) { +// SpaceService.JoinSpaceResult.Success +// } else { +// SpaceService.JoinSpaceResult.PartialSuccess(childJoinFailures) +// } } catch (throwable: Throwable) { return SpaceService.JoinSpaceResult.Fail(throwable) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/JoinSpaceTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/JoinSpaceTask.kt new file mode 100644 index 0000000000..66a695fc18 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/JoinSpaceTask.kt @@ -0,0 +1,116 @@ +/* + * 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 io.realm.RealmConfiguration +import kotlinx.coroutines.TimeoutCancellationException +import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure +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.internal.database.awaitNotEmptyResult +import org.matrix.android.sdk.internal.database.model.SpaceSummaryEntity +import org.matrix.android.sdk.internal.database.model.SpaceSummaryEntityFields +import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.session.room.RoomAPI +import org.matrix.android.sdk.internal.session.room.membership.joining.JoinRoomTask +import org.matrix.android.sdk.internal.task.Task +import timber.log.Timber +import java.util.concurrent.TimeUnit +import javax.inject.Inject + +internal interface JoinSpaceTask : Task { + data class Params( + val roomIdOrAlias: String, + val reason: String?, + val viaServers: List = emptyList() + ) +} + +internal class DefaultJoinSpaceTask @Inject constructor( + private val roomAPI: RoomAPI, + private val joinRoomTask: JoinRoomTask, + @SessionDatabase + private val realmConfiguration: RealmConfiguration, + private val spaceSummaryDataSource: SpaceSummaryDataSource, + private val eventBus: EventBus +) : JoinSpaceTask { + + override suspend fun execute(params: JoinSpaceTask.Params) { + Timber.v("## Space: > Joining root space ${params.roomIdOrAlias} ...") + joinRoomTask.execute(JoinRoomTask.Params( + params.roomIdOrAlias, + params.reason, + params.viaServers + )) + Timber.v("## Space: < Joining root space done for ${params.roomIdOrAlias}") + // we want to wait for sync result to check for auto join rooms + + Timber.v("## Space: > Wait for post joined sync ${params.roomIdOrAlias} ...") + try { + awaitNotEmptyResult(realmConfiguration, TimeUnit.MINUTES.toMillis(2L)) { realm -> + realm.where(SpaceSummaryEntity::class.java) + .apply { + if (params.roomIdOrAlias.startsWith("!")) { + equalTo(SpaceSummaryEntityFields.SPACE_ID, params.roomIdOrAlias) + } else { + equalTo(SpaceSummaryEntityFields.ROOM_SUMMARY_ENTITY.CANONICAL_ALIAS, params.roomIdOrAlias) + } + } + .equalTo(SpaceSummaryEntityFields.ROOM_SUMMARY_ENTITY.MEMBERSHIP_STR, Membership.JOIN.name) + } + } catch (exception: TimeoutCancellationException) { + Timber.w("## Space: > Error created with timeout") + throw CreateRoomFailure.CreatedWithTimeout + } + + Timber.v("## Space: > Sync done ...") + // after that i should have the children (? do i nead to paginate to get state) + val summary = spaceSummaryDataSource.getSpaceSummary(params.roomIdOrAlias) + Timber.v("## Space: Found space summary Name:[${summary?.roomSummary?.name}] children: ${summary?.children?.size}") + summary?.children?.forEach { + val childRoomSummary = it.roomSummary ?: return@forEach + Timber.v("## Space: Processing child :[${childRoomSummary.roomId}] present: ${it.present} autoJoin:${it.autoJoin}") + if (it.present && it.autoJoin) { + // I should try to join as well + if (childRoomSummary.roomType == RoomType.SPACE) { + } else { + try { + Timber.v("## Space: Joining room child ${childRoomSummary.roomId}") + joinRoomTask.execute(JoinRoomTask.Params( + roomIdOrAlias = childRoomSummary.roomId, + reason = "Auto-join parent space", + viaServers = it.viaServers + )) + } catch (failure: Throwable) { + // todo keep track for partial success + Timber.e("## Space: Failed to join room child ${childRoomSummary.roomId}") + } + } + } + } + } +} + +// try { +// awaitNotEmptyResult(realmConfiguration, TimeUnit.MINUTES.toMillis(1L)) { realm -> +// realm.where(RoomEntity::class.java) +// .equalTo(RoomEntityFields.ROOM_ID, roomId) +// } +// } catch (exception: TimeoutCancellationException) { +// throw CreateRoomFailure.CreatedWithTimeout +// } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/peeking/SpacePeekResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/peeking/SpacePeekResult.kt index 63eed2a6c2..a854dd25d3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/peeking/SpacePeekResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/peeking/SpacePeekResult.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 New Vector Ltd + * 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. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt index 2bb606e921..6859df1d37 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt @@ -212,6 +212,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle val ageLocalTs = event.unsignedData?.age?.let { syncLocalTimestampMillis - it } val eventEntity = event.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm, insertType) CurrentStateEventEntity.getOrCreate(realm, roomId, event.stateKey, event.type).apply { + Timber.v("## Space state event: $eventEntity") eventId = event.eventId root = eventEntity } diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 9a1f2e6dfd..e66a123773 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -273,6 +273,7 @@ + () { + + override fun getBinding(): ActivitySimpleBinding = ActivitySimpleBinding.inflate(layoutInflater) + // lateinit var sharedActionViewModel: SpacePreviewSharedActionViewModel + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) +// sharedActionViewModel = viewModelProvider.get(SpacePreviewSharedActionViewModel::class.java) +// sharedActionViewModel +// .observe() +// .subscribe { action -> +// when (action) { +// SpacePreviewSharedAction.DismissAction -> finish() +// SpacePreviewSharedAction.ShowModalLoading -> showWaitingView() +// SpacePreviewSharedAction.HideModalLoading -> hideWaitingView() +// is SpacePreviewSharedAction.ShowErrorMessage -> action.error?.let { showSnackbar(it) } +// } +// }.disposeOnDestroy() + + if (isFirstCreation()) { + val simpleName = SpaceDirectoryFragment::class.java.simpleName + val args = intent?.getParcelableExtra(MvRx.KEY_ARG) + if (supportFragmentManager.findFragmentByTag(simpleName) == null) { + supportFragmentManager.commitTransaction { + replace(R.id.simpleFragmentContainer, + SpacePreviewFragment::class.java, + Bundle().apply { this.putParcelable(MvRx.KEY_ARG, args) }, + simpleName + ) + } + } + } + } + + companion object { + fun newIntent(context: Context, spaceId: String): Intent { + return Intent(context, SpaceExploreActivity::class.java).apply { + putExtra(MvRx.KEY_ARG, SpaceDirectoryArgs(spaceId)) + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/grouplist/SpaceListFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt similarity index 91% rename from vector/src/main/java/im/vector/app/features/grouplist/SpaceListFragment.kt rename to vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt index 7091c0b86c..e14b920b2c 100644 --- a/vector/src/main/java/im/vector/app/features/grouplist/SpaceListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt @@ -1,21 +1,20 @@ /* - * Copyright 2019 New Vector Ltd + * 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 + * 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 im.vector.app.features.grouplist +package im.vector.app.features.spaces import android.os.Bundle import android.view.LayoutInflater @@ -33,9 +32,6 @@ import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.databinding.FragmentGroupListBinding import im.vector.app.features.home.HomeActivitySharedAction import im.vector.app.features.home.HomeSharedActionViewModel -import im.vector.app.features.spaces.SpaceListAction -import im.vector.app.features.spaces.SpaceListViewEvents -import im.vector.app.features.spaces.SpacesListViewModel import org.matrix.android.sdk.api.session.space.SpaceSummary import javax.inject.Inject diff --git a/vector/src/main/java/im/vector/app/features/grouplist/SpaceSummaryController.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceSummaryController.kt similarity index 95% rename from vector/src/main/java/im/vector/app/features/grouplist/SpaceSummaryController.kt rename to vector/src/main/java/im/vector/app/features/spaces/SpaceSummaryController.kt index dab2cbceae..29d48b4cd1 100644 --- a/vector/src/main/java/im/vector/app/features/grouplist/SpaceSummaryController.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceSummaryController.kt @@ -1,29 +1,28 @@ /* - * Copyright 2019 New Vector Ltd + * 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 + * 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 im.vector.app.features.grouplist +package im.vector.app.features.spaces import com.airbnb.epoxy.EpoxyController import im.vector.app.R import im.vector.app.core.resources.StringProvider import im.vector.app.core.ui.list.genericFooterItem import im.vector.app.core.ui.list.genericItemHeader +import im.vector.app.features.grouplist.homeSpaceSummaryItem import im.vector.app.features.home.AvatarRenderer -import im.vector.app.features.spaces.SpaceListViewState import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.space.SpaceSummary import org.matrix.android.sdk.api.util.toMatrixItem @@ -87,7 +86,6 @@ class SpaceSummaryController @Inject constructor( summaries .filter { it.roomSummary.membership == Membership.JOIN } .forEach { groupSummary -> - val isSelected = groupSummary.spaceId == selected?.spaceId if (groupSummary.spaceId == ALL_COMMUNITIES_GROUP_ID) { homeSpaceSummaryItem { diff --git a/vector/src/main/java/im/vector/app/features/grouplist/SpaceSummaryItem.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceSummaryItem.kt similarity index 98% rename from vector/src/main/java/im/vector/app/features/grouplist/SpaceSummaryItem.kt rename to vector/src/main/java/im/vector/app/features/spaces/SpaceSummaryItem.kt index 1a710b764c..525936deab 100644 --- a/vector/src/main/java/im/vector/app/features/grouplist/SpaceSummaryItem.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceSummaryItem.kt @@ -15,7 +15,7 @@ * */ -package im.vector.app.features.grouplist +package im.vector.app.features.spaces import android.widget.ImageView import android.widget.TextView diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpacesListViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/SpacesListViewModel.kt index f0d8ae30f7..bdc5c997f6 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpacesListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpacesListViewModel.kt @@ -31,14 +31,12 @@ import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModelAction import im.vector.app.core.resources.StringProvider import im.vector.app.features.grouplist.SelectedSpaceDataSource -import im.vector.app.features.grouplist.SpaceListFragment import io.reactivex.Observable import io.reactivex.functions.BiFunction import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.room.model.Membership 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.roomSummaryQueryParams import org.matrix.android.sdk.api.session.space.SpaceSummary import org.matrix.android.sdk.rx.rx @@ -117,9 +115,11 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp // PRIVATE METHODS ***************************************************************************** private fun handleSelectSpace(action: SpaceListAction.SelectSpace) = withState { state -> - - if (state.selectedSpace?.roomSummary?.membership == Membership.INVITE) { - _viewEvents.post(SpaceListViewEvents.OpenSpaceSummary(state.selectedSpace.roomSummary.roomId)) + // get uptodate version of the space + val summary = session.spaceService().getSpaceSummaries(roomSummaryQueryParams { roomId = QueryStringValue.Equals(action.spaceSummary.spaceId) }) + .firstOrNull() + if (summary?.roomSummary?.membership == Membership.INVITE) { + _viewEvents.post(SpaceListViewEvents.OpenSpaceSummary(summary.roomSummary.roomId)) // viewModelScope.launch(Dispatchers.IO) { // tryOrNull { session.spaceService().peekSpace(action.spaceSummary.spaceId) }.let { // Timber.d("PEEK RESULT/ $it") @@ -139,7 +139,8 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp val roomSummaryQueryParams = roomSummaryQueryParams() { memberships = listOf(Membership.JOIN, Membership.INVITE) displayName = QueryStringValue.IsNotEmpty - excludeType = listOf(RoomType.MESSAGING, null) + excludeType = listOf(/**RoomType.MESSAGING,$*/ + null) } Observable.combineLatest, List>( session diff --git a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryController.kt b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryController.kt new file mode 100644 index 0000000000..2c46607987 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryController.kt @@ -0,0 +1,53 @@ +/* + * 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 im.vector.app.features.spaces.explore + +import com.airbnb.epoxy.TypedEpoxyController +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Incomplete +import com.airbnb.mvrx.Success +import im.vector.app.core.epoxy.errorWithRetryItem +import im.vector.app.core.epoxy.loadingItem + +class SpaceDirectoryController : TypedEpoxyController() { + + override fun buildModels(data: SpaceDirectoryState?) { + when (data?.summary) { + is Success -> { +// val directories = roomDirectoryListCreator.computeDirectories(asyncThirdPartyProtocol()) +// +// directories.forEach { +// buildDirectory(it) +// } + } + is Incomplete -> { + loadingItem { + id("loading") + } + } + is Fail -> { + errorWithRetryItem { + id("error") +// text(errorFormatter.toHumanReadable(asyncThirdPartyProtocol.error)) +// listener { callback?.retry() } + } + } + else -> { + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryFragment.kt new file mode 100644 index 0000000000..6b67e20405 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryFragment.kt @@ -0,0 +1,35 @@ +/* + * 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 im.vector.app.features.spaces.explore + +import android.os.Parcelable +import android.view.LayoutInflater +import android.view.ViewGroup +import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentRoomDirectoryPickerBinding +import kotlinx.android.parcel.Parcelize + +@Parcelize +data class SpaceDirectoryArgs( + val spaceId: String +) : Parcelable + +class SpaceDirectoryFragment : VectorBaseFragment() { + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) = + FragmentRoomDirectoryPickerBinding.inflate(layoutInflater, container, false) +} diff --git a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewModel.kt new file mode 100644 index 0000000000..86baae0875 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewModel.kt @@ -0,0 +1,101 @@ +/* + * 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 im.vector.app.features.spaces.explore + +import androidx.lifecycle.viewModelScope +import com.airbnb.mvrx.ActivityViewModelContext +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.FragmentViewModelContext +import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.Uninitialized +import com.airbnb.mvrx.ViewModelContext +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject +import im.vector.app.core.platform.VectorViewEvents +import im.vector.app.core.platform.VectorViewModel +import im.vector.app.core.platform.VectorViewModelAction +import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.query.QueryStringValue +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams +import org.matrix.android.sdk.api.session.space.SpaceSummary +import org.matrix.android.sdk.api.util.Optional +import org.matrix.android.sdk.rx.rx +import org.matrix.android.sdk.rx.unwrap + +data class SpaceDirectoryState( + // The current filter + val spaceId: String, + val currentFilter: String = "", + val summary: Async = Uninitialized, + // True if more result are available server side + val hasMore: Boolean = false, + // Set of joined roomId / spaces, + val joinedRoomsIds: Set = emptySet() +) : MvRxState { + constructor(args: SpaceDirectoryArgs) : this(spaceId = args.spaceId) +} + +sealed class SpaceDirectoryViewAction : VectorViewModelAction + +sealed class SpaceDirectoryViewEvents : VectorViewEvents + +class SpaceDirectoryViewModel @AssistedInject constructor( + @Assisted initialState: SpaceDirectoryState, + private val session: Session +) : VectorViewModel(initialState) { + + @AssistedInject.Factory + interface Factory { + fun create(initialState: SpaceDirectoryState): SpaceDirectoryViewModel + } + + companion object : MvRxViewModelFactory { + override fun create(viewModelContext: ViewModelContext, state: SpaceDirectoryState): SpaceDirectoryViewModel? { + val factory = when (viewModelContext) { + is FragmentViewModelContext -> viewModelContext.fragment as? Factory + is ActivityViewModelContext -> viewModelContext.activity as? Factory + } + return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface") + } + } + + init { + val queryParams = roomSummaryQueryParams { + roomId = QueryStringValue.Equals(initialState.spaceId) + } + + viewModelScope.launch(Dispatchers.IO) { + session + .rx() + .liveSpaceSummaries(queryParams) + .observeOn(Schedulers.computation()) + .map { sum -> Optional.from(sum.firstOrNull()) } + .unwrap() + .execute { async -> + copy(summary = async) + } + } + } + + override fun handle(action: VectorViewModelAction) { + TODO("Not yet implemented") + } +}