mirror of
https://github.com/element-hq/element-android
synced 2024-11-29 05:58:50 +03:00
legacy groups removal (#6268)
This commit is contained in:
parent
92801f625d
commit
c7b54b8d3d
90 changed files with 751 additions and 3039 deletions
1
changelog.d/5733.misc
Normal file
1
changelog.d/5733.misc
Normal file
|
@ -0,0 +1 @@
|
|||
Communities/Groups are removed completely
|
1
changelog.d/5733.sdk
Normal file
1
changelog.d/5733.sdk
Normal file
|
@ -0,0 +1 @@
|
|||
Communities/Groups are removed completely
|
|
@ -26,8 +26,6 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
|
|||
import org.matrix.android.sdk.api.session.crypto.crosssigning.PrivateKeysInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
import org.matrix.android.sdk.api.session.group.GroupSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import org.matrix.android.sdk.api.session.pushers.Pusher
|
||||
import org.matrix.android.sdk.api.session.room.RoomSortOrder
|
||||
|
@ -59,13 +57,6 @@ class FlowSession(private val session: Session) {
|
|||
}
|
||||
}
|
||||
|
||||
fun liveGroupSummaries(queryParams: GroupSummaryQueryParams): Flow<List<GroupSummary>> {
|
||||
return session.groupService().getGroupSummariesLive(queryParams).asFlow()
|
||||
.startWith(session.coroutineDispatchers.io) {
|
||||
session.groupService().getGroupSummaries(queryParams)
|
||||
}
|
||||
}
|
||||
|
||||
fun liveSpaceSummaries(queryParams: SpaceSummaryQueryParams): Flow<List<RoomSummary>> {
|
||||
return session.spaceService().getSpaceSummariesLive(queryParams).asFlow()
|
||||
.startWith(session.coroutineDispatchers.io) {
|
||||
|
|
|
@ -33,7 +33,6 @@ import org.matrix.android.sdk.api.session.crypto.CryptoService
|
|||
import org.matrix.android.sdk.api.session.events.EventService
|
||||
import org.matrix.android.sdk.api.session.file.ContentDownloadStateTracker
|
||||
import org.matrix.android.sdk.api.session.file.FileService
|
||||
import org.matrix.android.sdk.api.session.group.GroupService
|
||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
|
||||
import org.matrix.android.sdk.api.session.identity.IdentityService
|
||||
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
|
||||
|
@ -154,11 +153,6 @@ interface Session {
|
|||
*/
|
||||
fun roomDirectoryService(): RoomDirectoryService
|
||||
|
||||
/**
|
||||
* Returns the GroupService associated with the session.
|
||||
*/
|
||||
fun groupService(): GroupService
|
||||
|
||||
/**
|
||||
* Returns the UserService associated with the session.
|
||||
*/
|
||||
|
|
|
@ -1,31 +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.api.session.group
|
||||
|
||||
/**
|
||||
* This interface defines methods to interact within a group.
|
||||
*/
|
||||
interface Group {
|
||||
val groupId: String
|
||||
|
||||
/**
|
||||
* This methods allows you to refresh data about this group. It will be reflected on the GroupSummary.
|
||||
* The SDK also takes care of refreshing group data every hour.
|
||||
* @return a Cancelable to be able to cancel requests.
|
||||
*/
|
||||
suspend fun fetchGroupData()
|
||||
}
|
|
@ -1,51 +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.api.session.group
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
|
||||
/**
|
||||
* This interface defines methods to get groups. It's implemented at the session level.
|
||||
*/
|
||||
interface GroupService {
|
||||
/**
|
||||
* Get a group from a groupId.
|
||||
* @param groupId the groupId to look for.
|
||||
* @return the group with groupId or null
|
||||
*/
|
||||
fun getGroup(groupId: String): Group?
|
||||
|
||||
/**
|
||||
* Get a groupSummary from a groupId.
|
||||
* @param groupId the groupId to look for.
|
||||
* @return the groupSummary with groupId or null
|
||||
*/
|
||||
fun getGroupSummary(groupId: String): GroupSummary?
|
||||
|
||||
/**
|
||||
* Get a list of group summaries. This list is a snapshot of the data.
|
||||
* @return the list of [GroupSummary]
|
||||
*/
|
||||
fun getGroupSummaries(groupSummaryQueryParams: GroupSummaryQueryParams): List<GroupSummary>
|
||||
|
||||
/**
|
||||
* Get a live list of group summaries. This list is refreshed as soon as the data changes.
|
||||
* @return the [LiveData] of [GroupSummary]
|
||||
*/
|
||||
fun getGroupSummariesLive(groupSummaryQueryParams: GroupSummaryQueryParams): LiveData<List<GroupSummary>>
|
||||
}
|
|
@ -1,44 +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.api.session.group
|
||||
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
|
||||
fun groupSummaryQueryParams(init: (GroupSummaryQueryParams.Builder.() -> Unit) = {}): GroupSummaryQueryParams {
|
||||
return GroupSummaryQueryParams.Builder().apply(init).build()
|
||||
}
|
||||
|
||||
/**
|
||||
* This class can be used to filter group summaries.
|
||||
*/
|
||||
data class GroupSummaryQueryParams(
|
||||
val displayName: QueryStringValue,
|
||||
val memberships: List<Membership>
|
||||
) {
|
||||
|
||||
class Builder {
|
||||
|
||||
var displayName: QueryStringValue = QueryStringValue.IsNotEmpty
|
||||
var memberships: List<Membership> = Membership.all()
|
||||
|
||||
fun build() = GroupSummaryQueryParams(
|
||||
displayName = displayName,
|
||||
memberships = memberships
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,33 +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.api.session.group.model
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
|
||||
/**
|
||||
* This class holds some data of a group.
|
||||
* It can be retrieved through [org.matrix.android.sdk.api.session.group.GroupService]
|
||||
*/
|
||||
data class GroupSummary(
|
||||
val groupId: String,
|
||||
val membership: Membership,
|
||||
val displayName: String = "",
|
||||
val shortDescription: String = "",
|
||||
val avatarUrl: String = "",
|
||||
val roomIds: List<String> = emptyList(),
|
||||
val userIds: List<String> = emptyList()
|
||||
)
|
|
@ -54,7 +54,5 @@ sealed class PermalinkData {
|
|||
|
||||
data class UserLink(val userId: String) : PermalinkData()
|
||||
|
||||
data class GroupLink(val groupId: String) : PermalinkData()
|
||||
|
||||
data class FallbackLink(val uri: Uri) : PermalinkData()
|
||||
data class FallbackLink(val uri: Uri, val isLegacyGroupLink: Boolean = false) : PermalinkData()
|
||||
}
|
||||
|
|
|
@ -61,27 +61,29 @@ object PermalinkParser {
|
|||
val params = safeFragment
|
||||
.split(MatrixPatterns.SEP_REGEX)
|
||||
.filter { it.isNotEmpty() }
|
||||
.map { URLDecoder.decode(it, "UTF-8") }
|
||||
.take(2)
|
||||
|
||||
val decodedParams = params
|
||||
.map { URLDecoder.decode(it, "UTF-8") }
|
||||
|
||||
val identifier = params.getOrNull(0)
|
||||
val extraParameter = params.getOrNull(1)
|
||||
val decodedIdentifier = decodedParams.getOrNull(0)
|
||||
val extraParameter = decodedParams.getOrNull(1)
|
||||
return when {
|
||||
identifier.isNullOrEmpty() -> PermalinkData.FallbackLink(uri)
|
||||
MatrixPatterns.isUserId(identifier) -> PermalinkData.UserLink(userId = identifier)
|
||||
MatrixPatterns.isGroupId(identifier) -> PermalinkData.GroupLink(groupId = identifier)
|
||||
MatrixPatterns.isRoomId(identifier) -> {
|
||||
handleRoomIdCase(fragment, identifier, matrixToUri, extraParameter, viaQueryParameters)
|
||||
identifier.isNullOrEmpty() || decodedIdentifier.isNullOrEmpty() -> PermalinkData.FallbackLink(uri)
|
||||
MatrixPatterns.isUserId(decodedIdentifier) -> PermalinkData.UserLink(userId = decodedIdentifier)
|
||||
MatrixPatterns.isRoomId(decodedIdentifier) -> {
|
||||
handleRoomIdCase(fragment, decodedIdentifier, matrixToUri, extraParameter, viaQueryParameters)
|
||||
}
|
||||
MatrixPatterns.isRoomAlias(identifier) -> {
|
||||
MatrixPatterns.isRoomAlias(decodedIdentifier) -> {
|
||||
PermalinkData.RoomLink(
|
||||
roomIdOrAlias = identifier,
|
||||
roomIdOrAlias = decodedIdentifier,
|
||||
isRoomAlias = true,
|
||||
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
|
||||
viaParameters = viaQueryParameters
|
||||
)
|
||||
}
|
||||
else -> PermalinkData.FallbackLink(uri)
|
||||
else -> PermalinkData.FallbackLink(uri, MatrixPatterns.isGroupId(identifier))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -87,10 +87,6 @@ data class RoomSummaryQueryParams(
|
|||
* Used to filter room using the current space.
|
||||
*/
|
||||
val spaceFilter: SpaceFilter?,
|
||||
/**
|
||||
* Used to filter room using the current group.
|
||||
*/
|
||||
val activeGroupId: String? = null
|
||||
) {
|
||||
|
||||
/**
|
||||
|
@ -106,7 +102,6 @@ data class RoomSummaryQueryParams(
|
|||
var excludeType: List<String?>? = listOf(RoomType.SPACE)
|
||||
var includeType: List<String?>? = null
|
||||
var spaceFilter: SpaceFilter? = null
|
||||
var activeGroupId: String? = null
|
||||
|
||||
fun build() = RoomSummaryQueryParams(
|
||||
displayName = displayName,
|
||||
|
@ -117,7 +112,6 @@ data class RoomSummaryQueryParams(
|
|||
excludeType = excludeType,
|
||||
includeType = includeType,
|
||||
spaceFilter = spaceFilter,
|
||||
activeGroupId = activeGroupId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ enum class InitialSyncStep {
|
|||
ImportingAccount,
|
||||
ImportingAccountCrypto,
|
||||
ImportingAccountRoom,
|
||||
ImportingAccountGroups,
|
||||
ImportingAccountData,
|
||||
ImportingAccountJoinedRooms,
|
||||
ImportingAccountInvitedRooms,
|
||||
|
|
|
@ -1,33 +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.api.session.sync.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class GroupSyncProfile(
|
||||
/**
|
||||
* The name of the group, if any. May be nil.
|
||||
*/
|
||||
@Json(name = "name") val name: String? = null,
|
||||
|
||||
/**
|
||||
* The URL for the group's avatar. May be nil.
|
||||
*/
|
||||
@Json(name = "avatar_url") val avatarUrl: String? = null
|
||||
)
|
|
@ -1,38 +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.api.session.sync.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class GroupsSyncResponse(
|
||||
/**
|
||||
* Joined groups: An array of groups ids.
|
||||
*/
|
||||
@Json(name = "join") val join: Map<String, Any> = emptyMap(),
|
||||
|
||||
/**
|
||||
* Invitations. The groups that the user has been invited to: keys are groups ids.
|
||||
*/
|
||||
@Json(name = "invite") val invite: Map<String, InvitedGroupSync> = emptyMap(),
|
||||
|
||||
/**
|
||||
* Left groups. An array of groups ids: the groups that the user has left or been banned from.
|
||||
*/
|
||||
@Json(name = "leave") val leave: Map<String, Any> = emptyMap()
|
||||
)
|
|
@ -1,33 +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.api.session.sync.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class InvitedGroupSync(
|
||||
/**
|
||||
* The identifier of the inviter.
|
||||
*/
|
||||
@Json(name = "inviter") val inviter: String? = null,
|
||||
|
||||
/**
|
||||
* The group profile.
|
||||
*/
|
||||
@Json(name = "profile") val profile: GroupSyncProfile? = null
|
||||
)
|
|
@ -65,10 +65,4 @@ data class SyncResponse(
|
|||
*/
|
||||
@Json(name = "org.matrix.msc2732.device_unused_fallback_key_types")
|
||||
val deviceUnusedFallbackKeyTypes: List<String>? = null,
|
||||
|
||||
/**
|
||||
* List of groups.
|
||||
*/
|
||||
@Json(name = "groups") val groups: GroupsSyncResponse? = null
|
||||
|
||||
)
|
||||
|
|
|
@ -18,7 +18,6 @@ package org.matrix.android.sdk.api.util
|
|||
|
||||
import org.matrix.android.sdk.BuildConfig
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||
|
@ -113,19 +112,6 @@ sealed class MatrixItem(
|
|||
override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
|
||||
}
|
||||
|
||||
data class GroupItem(
|
||||
override val id: String,
|
||||
override val displayName: String? = null,
|
||||
override val avatarUrl: String? = null
|
||||
) :
|
||||
MatrixItem(id, displayName, avatarUrl) {
|
||||
init {
|
||||
if (BuildConfig.DEBUG) checkId()
|
||||
}
|
||||
|
||||
override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
|
||||
}
|
||||
|
||||
protected fun checkId() {
|
||||
if (!id.startsWith(getIdPrefix())) {
|
||||
error("Wrong usage of MatrixItem: check the id $id should start with ${getIdPrefix()}")
|
||||
|
@ -144,7 +130,6 @@ sealed class MatrixItem(
|
|||
is RoomItem,
|
||||
is EveryoneInRoomItem -> '!'
|
||||
is RoomAliasItem -> '#'
|
||||
is GroupItem -> '+'
|
||||
}
|
||||
|
||||
fun firstLetterOfDisplayName(): String {
|
||||
|
@ -196,8 +181,6 @@ sealed class MatrixItem(
|
|||
|
||||
fun User.toMatrixItem() = MatrixItem.UserItem(userId, displayName, avatarUrl)
|
||||
|
||||
fun GroupSummary.toMatrixItem() = MatrixItem.GroupItem(groupId, displayName, avatarUrl)
|
||||
|
||||
fun RoomSummary.toMatrixItem() = if (roomType == RoomType.SPACE) {
|
||||
MatrixItem.SpaceItem(roomId, displayName, avatarUrl)
|
||||
} else {
|
||||
|
|
|
@ -49,6 +49,7 @@ import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo028
|
|||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo029
|
||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo030
|
||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo031
|
||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo032
|
||||
import org.matrix.android.sdk.internal.util.Normalizer
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
@ -63,7 +64,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
|
|||
override fun equals(other: Any?) = other is RealmSessionStoreMigration
|
||||
override fun hashCode() = 1000
|
||||
|
||||
val schemaVersion = 31L
|
||||
val schemaVersion = 32L
|
||||
|
||||
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
||||
Timber.d("Migrating Realm Session from $oldVersion to $newVersion")
|
||||
|
@ -99,5 +100,6 @@ internal class RealmSessionStoreMigration @Inject constructor(
|
|||
if (oldVersion < 29) MigrateSessionTo029(realm).perform()
|
||||
if (oldVersion < 30) MigrateSessionTo030(realm).perform()
|
||||
if (oldVersion < 31) MigrateSessionTo031(realm).perform()
|
||||
if (oldVersion < 32) MigrateSessionTo032(realm).perform()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,39 +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.database.mapper
|
||||
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import org.matrix.android.sdk.internal.database.model.GroupSummaryEntity
|
||||
|
||||
internal object GroupSummaryMapper {
|
||||
|
||||
fun map(groupSummaryEntity: GroupSummaryEntity): GroupSummary {
|
||||
return GroupSummary(
|
||||
groupSummaryEntity.groupId,
|
||||
groupSummaryEntity.membership,
|
||||
groupSummaryEntity.displayName,
|
||||
groupSummaryEntity.shortDescription,
|
||||
groupSummaryEntity.avatarUrl,
|
||||
groupSummaryEntity.roomIds.toList(),
|
||||
groupSummaryEntity.userIds.toList()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun GroupSummaryEntity.asDomain(): GroupSummary {
|
||||
return GroupSummaryMapper.map(this)
|
||||
}
|
|
@ -49,7 +49,7 @@ internal class MigrateSessionTo010(realm: DynamicRealm) : RealmMigrator(realm, 1
|
|||
realm.schema.get("RoomSummaryEntity")
|
||||
?.addField(RoomSummaryEntityFields.ROOM_TYPE, String::class.java)
|
||||
?.addField(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, String::class.java)
|
||||
?.addField(RoomSummaryEntityFields.GROUP_IDS, String::class.java)
|
||||
?.addField("groupIds", String::class.java)
|
||||
?.transform { obj ->
|
||||
|
||||
val creationEvent = realm.where("CurrentStateEventEntity")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
* Copyright (c) 2022 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.
|
||||
|
@ -14,15 +14,15 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.session.group.model
|
||||
package org.matrix.android.sdk.internal.database.migration
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class GroupRooms(
|
||||
internal class MigrateSessionTo032(realm: DynamicRealm) : RealmMigrator(realm, 32) {
|
||||
|
||||
@Json(name = "total_room_count_estimate") val totalRoomCountEstimate: Int? = null,
|
||||
@Json(name = "chunk") val rooms: List<GroupRoom> = emptyList()
|
||||
|
||||
)
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.get("RoomSummaryEntity")
|
||||
?.removeField("groupIds")
|
||||
}
|
||||
}
|
|
@ -1,40 +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.database.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
|
||||
/**
|
||||
* This class is used to store group info (groupId and membership) from the sync response.
|
||||
* Then GetGroupDataTask is called regularly to fetch group information from the homeserver.
|
||||
*/
|
||||
internal open class GroupEntity(@PrimaryKey var groupId: String = "") :
|
||||
RealmObject() {
|
||||
|
||||
private var membershipStr: String = Membership.NONE.name
|
||||
var membership: Membership
|
||||
get() {
|
||||
return Membership.valueOf(membershipStr)
|
||||
}
|
||||
set(value) {
|
||||
membershipStr = value.name
|
||||
}
|
||||
|
||||
companion object
|
||||
}
|
|
@ -1,43 +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.database.model
|
||||
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
|
||||
internal open class GroupSummaryEntity(
|
||||
@PrimaryKey var groupId: String = "",
|
||||
var displayName: String = "",
|
||||
var shortDescription: String = "",
|
||||
var avatarUrl: String = "",
|
||||
var roomIds: RealmList<String> = RealmList(),
|
||||
var userIds: RealmList<String> = RealmList()
|
||||
) : RealmObject() {
|
||||
|
||||
private var membershipStr: String = Membership.NONE.name
|
||||
var membership: Membership
|
||||
get() {
|
||||
return Membership.valueOf(membershipStr)
|
||||
}
|
||||
set(value) {
|
||||
membershipStr = value.name
|
||||
}
|
||||
|
||||
companion object
|
||||
}
|
|
@ -240,11 +240,6 @@ internal open class RoomSummaryEntity(
|
|||
if (value != field) field = value
|
||||
}
|
||||
|
||||
var groupIds: String? = null
|
||||
set(value) {
|
||||
if (value != field) field = value
|
||||
}
|
||||
|
||||
@Index
|
||||
private var membershipStr: String = Membership.NONE.name
|
||||
|
||||
|
|
|
@ -32,8 +32,6 @@ import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntit
|
|||
EventInsertEntity::class,
|
||||
TimelineEventEntity::class,
|
||||
FilterEntity::class,
|
||||
GroupEntity::class,
|
||||
GroupSummaryEntity::class,
|
||||
ReadReceiptEntity::class,
|
||||
RoomEntity::class,
|
||||
RoomSummaryEntity::class,
|
||||
|
|
|
@ -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.database.query
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.internal.database.model.GroupEntity
|
||||
import org.matrix.android.sdk.internal.database.model.GroupEntityFields
|
||||
import org.matrix.android.sdk.internal.query.process
|
||||
|
||||
internal fun GroupEntity.Companion.where(realm: Realm, groupId: String): RealmQuery<GroupEntity> {
|
||||
return realm.where<GroupEntity>()
|
||||
.equalTo(GroupEntityFields.GROUP_ID, groupId)
|
||||
}
|
||||
|
||||
internal fun GroupEntity.Companion.where(realm: Realm, memberships: List<Membership>): RealmQuery<GroupEntity> {
|
||||
return realm.where<GroupEntity>().process(GroupEntityFields.MEMBERSHIP_STR, memberships)
|
||||
}
|
|
@ -1,41 +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.database.query
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.internal.database.model.GroupSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.model.GroupSummaryEntityFields
|
||||
|
||||
internal fun GroupSummaryEntity.Companion.where(realm: Realm, groupId: String? = null): RealmQuery<GroupSummaryEntity> {
|
||||
val query = realm.where<GroupSummaryEntity>()
|
||||
if (groupId != null) {
|
||||
query.equalTo(GroupSummaryEntityFields.GROUP_ID, groupId)
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
internal fun GroupSummaryEntity.Companion.where(realm: Realm, groupIds: List<String>): RealmQuery<GroupSummaryEntity> {
|
||||
return realm.where<GroupSummaryEntity>()
|
||||
.`in`(GroupSummaryEntityFields.GROUP_ID, groupIds.toTypedArray())
|
||||
}
|
||||
|
||||
internal fun GroupSummaryEntity.Companion.getOrCreate(realm: Realm, groupId: String): GroupSummaryEntity {
|
||||
return where(realm, groupId).findFirst() ?: realm.createObject(groupId)
|
||||
}
|
|
@ -41,7 +41,6 @@ import org.matrix.android.sdk.api.session.crypto.CryptoService
|
|||
import org.matrix.android.sdk.api.session.events.EventService
|
||||
import org.matrix.android.sdk.api.session.file.ContentDownloadStateTracker
|
||||
import org.matrix.android.sdk.api.session.file.FileService
|
||||
import org.matrix.android.sdk.api.session.group.GroupService
|
||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
|
||||
import org.matrix.android.sdk.api.session.identity.IdentityService
|
||||
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
|
||||
|
@ -97,7 +96,6 @@ internal class DefaultSession @Inject constructor(
|
|||
private val sessionListeners: SessionListeners,
|
||||
private val roomService: Lazy<RoomService>,
|
||||
private val roomDirectoryService: Lazy<RoomDirectoryService>,
|
||||
private val groupService: Lazy<GroupService>,
|
||||
private val userService: Lazy<UserService>,
|
||||
private val filterService: Lazy<FilterService>,
|
||||
private val federationService: Lazy<FederationService>,
|
||||
|
@ -209,7 +207,6 @@ internal class DefaultSession @Inject constructor(
|
|||
override fun homeServerCapabilitiesService(): HomeServerCapabilitiesService = homeServerCapabilitiesService.get()
|
||||
override fun roomService(): RoomService = roomService.get()
|
||||
override fun roomDirectoryService(): RoomDirectoryService = roomDirectoryService.get()
|
||||
override fun groupService(): GroupService = groupService.get()
|
||||
override fun userService(): UserService = userService.get()
|
||||
override fun signOutService(): SignOutService = signOutService.get()
|
||||
override fun filterService(): FilterService = filterService.get()
|
||||
|
|
|
@ -35,8 +35,6 @@ import org.matrix.android.sdk.internal.session.content.ContentModule
|
|||
import org.matrix.android.sdk.internal.session.content.UploadContentWorker
|
||||
import org.matrix.android.sdk.internal.session.contentscanner.ContentScannerModule
|
||||
import org.matrix.android.sdk.internal.session.filter.FilterModule
|
||||
import org.matrix.android.sdk.internal.session.group.GetGroupDataWorker
|
||||
import org.matrix.android.sdk.internal.session.group.GroupModule
|
||||
import org.matrix.android.sdk.internal.session.homeserver.HomeServerCapabilitiesModule
|
||||
import org.matrix.android.sdk.internal.session.identity.IdentityModule
|
||||
import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationManagerModule
|
||||
|
@ -74,10 +72,8 @@ import org.matrix.android.sdk.internal.util.system.SystemModule
|
|||
SyncModule::class,
|
||||
HomeServerCapabilitiesModule::class,
|
||||
SignOutModule::class,
|
||||
GroupModule::class,
|
||||
UserModule::class,
|
||||
FilterModule::class,
|
||||
GroupModule::class,
|
||||
ContentModule::class,
|
||||
CacheModule::class,
|
||||
MediaModule::class,
|
||||
|
@ -124,8 +120,6 @@ internal interface SessionComponent {
|
|||
|
||||
fun inject(worker: RedactEventWorker)
|
||||
|
||||
fun inject(worker: GetGroupDataWorker)
|
||||
|
||||
fun inject(worker: UploadContentWorker)
|
||||
|
||||
fun inject(worker: SyncWorker)
|
||||
|
|
|
@ -25,7 +25,7 @@ internal class DisplayNameResolver @Inject constructor(
|
|||
private val matrixConfiguration: MatrixConfiguration
|
||||
) {
|
||||
fun getBestName(matrixItem: MatrixItem): String {
|
||||
return if (matrixItem is MatrixItem.GroupItem || matrixItem is MatrixItem.RoomAliasItem) {
|
||||
return if (matrixItem is MatrixItem.RoomAliasItem) {
|
||||
// Best name is the id, and we keep the displayName of the room for the case we need the first letter
|
||||
matrixItem.id
|
||||
} else {
|
||||
|
|
|
@ -1,30 +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.group
|
||||
|
||||
import org.matrix.android.sdk.api.session.group.Group
|
||||
|
||||
internal class DefaultGroup(
|
||||
override val groupId: String,
|
||||
private val getGroupDataTask: GetGroupDataTask
|
||||
) : Group {
|
||||
|
||||
override suspend fun fetchGroupData() {
|
||||
val params = GetGroupDataTask.Params.FetchWithIds(listOf(groupId))
|
||||
getGroupDataTask.execute(params)
|
||||
}
|
||||
}
|
|
@ -1,80 +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.group
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
import org.matrix.android.sdk.api.session.group.Group
|
||||
import org.matrix.android.sdk.api.session.group.GroupService
|
||||
import org.matrix.android.sdk.api.session.group.GroupSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import org.matrix.android.sdk.internal.database.mapper.asDomain
|
||||
import org.matrix.android.sdk.internal.database.model.GroupEntity
|
||||
import org.matrix.android.sdk.internal.database.model.GroupSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.model.GroupSummaryEntityFields
|
||||
import org.matrix.android.sdk.internal.database.query.where
|
||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||
import org.matrix.android.sdk.internal.query.QueryStringValueProcessor
|
||||
import org.matrix.android.sdk.internal.query.process
|
||||
import org.matrix.android.sdk.internal.util.fetchCopyMap
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultGroupService @Inject constructor(
|
||||
@SessionDatabase private val monarchy: Monarchy,
|
||||
private val groupFactory: GroupFactory,
|
||||
private val queryStringValueProcessor: QueryStringValueProcessor,
|
||||
) : GroupService {
|
||||
|
||||
override fun getGroup(groupId: String): Group? {
|
||||
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
|
||||
GroupEntity.where(realm, groupId).findFirst()?.let {
|
||||
groupFactory.create(groupId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getGroupSummary(groupId: String): GroupSummary? {
|
||||
return monarchy.fetchCopyMap(
|
||||
{ realm -> GroupSummaryEntity.where(realm, groupId).findFirst() },
|
||||
{ it, _ -> it.asDomain() }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getGroupSummaries(groupSummaryQueryParams: GroupSummaryQueryParams): List<GroupSummary> {
|
||||
return monarchy.fetchAllMappedSync(
|
||||
{ groupSummariesQuery(it, groupSummaryQueryParams) },
|
||||
{ it.asDomain() }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getGroupSummariesLive(groupSummaryQueryParams: GroupSummaryQueryParams): LiveData<List<GroupSummary>> {
|
||||
return monarchy.findAllMappedWithChanges(
|
||||
{ groupSummariesQuery(it, groupSummaryQueryParams) },
|
||||
{ it.asDomain() }
|
||||
)
|
||||
}
|
||||
|
||||
private fun groupSummariesQuery(realm: Realm, queryParams: GroupSummaryQueryParams): RealmQuery<GroupSummaryEntity> {
|
||||
return with(queryStringValueProcessor) {
|
||||
GroupSummaryEntity.where(realm)
|
||||
.process(GroupSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
|
||||
.process(GroupSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,110 +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.group
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.internal.database.model.GroupEntity
|
||||
import org.matrix.android.sdk.internal.database.model.GroupSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.query.getOrCreate
|
||||
import org.matrix.android.sdk.internal.database.query.where
|
||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
||||
import org.matrix.android.sdk.internal.network.executeRequest
|
||||
import org.matrix.android.sdk.internal.session.group.model.GroupRooms
|
||||
import org.matrix.android.sdk.internal.session.group.model.GroupSummaryResponse
|
||||
import org.matrix.android.sdk.internal.session.group.model.GroupUsers
|
||||
import org.matrix.android.sdk.internal.task.Task
|
||||
import org.matrix.android.sdk.internal.util.awaitTransaction
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetGroupDataTask : Task<GetGroupDataTask.Params, Unit> {
|
||||
sealed class Params {
|
||||
object FetchAllActive : Params()
|
||||
data class FetchWithIds(val groupIds: List<String>) : Params()
|
||||
}
|
||||
}
|
||||
|
||||
internal class DefaultGetGroupDataTask @Inject constructor(
|
||||
private val groupAPI: GroupAPI,
|
||||
@SessionDatabase private val monarchy: Monarchy,
|
||||
private val globalErrorReceiver: GlobalErrorReceiver
|
||||
) : GetGroupDataTask {
|
||||
|
||||
private data class GroupData(
|
||||
val groupId: String,
|
||||
val groupSummary: GroupSummaryResponse,
|
||||
val groupRooms: GroupRooms,
|
||||
val groupUsers: GroupUsers
|
||||
)
|
||||
|
||||
override suspend fun execute(params: GetGroupDataTask.Params) {
|
||||
val groupIds = when (params) {
|
||||
is GetGroupDataTask.Params.FetchAllActive -> {
|
||||
getActiveGroupIds()
|
||||
}
|
||||
is GetGroupDataTask.Params.FetchWithIds -> {
|
||||
params.groupIds
|
||||
}
|
||||
}
|
||||
Timber.v("Fetch data for group with ids: ${groupIds.joinToString(";")}")
|
||||
val data = groupIds.map { groupId ->
|
||||
val groupSummary = executeRequest(globalErrorReceiver) {
|
||||
groupAPI.getSummary(groupId)
|
||||
}
|
||||
val groupRooms = executeRequest(globalErrorReceiver) {
|
||||
groupAPI.getRooms(groupId)
|
||||
}
|
||||
val groupUsers = executeRequest(globalErrorReceiver) {
|
||||
groupAPI.getUsers(groupId)
|
||||
}
|
||||
GroupData(groupId, groupSummary, groupRooms, groupUsers)
|
||||
}
|
||||
insertInDb(data)
|
||||
}
|
||||
|
||||
private fun getActiveGroupIds(): List<String> {
|
||||
return monarchy.fetchAllMappedSync(
|
||||
{ realm ->
|
||||
GroupEntity.where(realm, Membership.activeMemberships())
|
||||
},
|
||||
{ it.groupId }
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun insertInDb(groupDataList: List<GroupData>) {
|
||||
monarchy
|
||||
.awaitTransaction { realm ->
|
||||
groupDataList.forEach { groupData ->
|
||||
|
||||
val groupSummaryEntity = GroupSummaryEntity.getOrCreate(realm, groupData.groupId)
|
||||
|
||||
groupSummaryEntity.avatarUrl = groupData.groupSummary.profile?.avatarUrl ?: ""
|
||||
val name = groupData.groupSummary.profile?.name
|
||||
groupSummaryEntity.displayName = if (name.isNullOrEmpty()) groupData.groupId else name
|
||||
groupSummaryEntity.shortDescription = groupData.groupSummary.profile?.shortDescription ?: ""
|
||||
|
||||
groupSummaryEntity.roomIds.clear()
|
||||
groupData.groupRooms.rooms.mapTo(groupSummaryEntity.roomIds) { it.roomId }
|
||||
|
||||
groupSummaryEntity.userIds.clear()
|
||||
groupData.groupUsers.users.mapTo(groupSummaryEntity.userIds) { it.userId }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,59 +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.group
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.WorkerParameters
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.session.SessionComponent
|
||||
import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
|
||||
import org.matrix.android.sdk.internal.worker.SessionWorkerParams
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Possible previous worker: None.
|
||||
* Possible next worker : None.
|
||||
*/
|
||||
internal class GetGroupDataWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
|
||||
SessionSafeCoroutineWorker<GetGroupDataWorker.Params>(context, params, sessionManager, Params::class.java) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
override val sessionId: String,
|
||||
override val lastFailureMessage: String? = null
|
||||
) : SessionWorkerParams
|
||||
|
||||
@Inject lateinit var getGroupDataTask: GetGroupDataTask
|
||||
|
||||
override fun injectWith(injector: SessionComponent) {
|
||||
injector.inject(this)
|
||||
}
|
||||
|
||||
override suspend fun doSafeWork(params: Params): Result {
|
||||
return runCatching {
|
||||
getGroupDataTask.execute(GetGroupDataTask.Params.FetchAllActive)
|
||||
}.fold(
|
||||
{ Result.success() },
|
||||
{ Result.retry() }
|
||||
)
|
||||
}
|
||||
|
||||
override fun buildErrorParams(params: Params, message: String): Params {
|
||||
return params.copy(lastFailureMessage = params.lastFailureMessage ?: message)
|
||||
}
|
||||
}
|
|
@ -1,51 +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.group
|
||||
|
||||
import org.matrix.android.sdk.internal.network.NetworkConstants
|
||||
import org.matrix.android.sdk.internal.session.group.model.GroupRooms
|
||||
import org.matrix.android.sdk.internal.session.group.model.GroupSummaryResponse
|
||||
import org.matrix.android.sdk.internal.session.group.model.GroupUsers
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Path
|
||||
|
||||
internal interface GroupAPI {
|
||||
|
||||
/**
|
||||
* Request a group summary.
|
||||
*
|
||||
* @param groupId the group id
|
||||
*/
|
||||
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "groups/{groupId}/summary")
|
||||
suspend fun getSummary(@Path("groupId") groupId: String): GroupSummaryResponse
|
||||
|
||||
/**
|
||||
* Request the rooms list.
|
||||
*
|
||||
* @param groupId the group id
|
||||
*/
|
||||
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "groups/{groupId}/rooms")
|
||||
suspend fun getRooms(@Path("groupId") groupId: String): GroupRooms
|
||||
|
||||
/**
|
||||
* Request the users list.
|
||||
*
|
||||
* @param groupId the group id
|
||||
*/
|
||||
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "groups/{groupId}/users")
|
||||
suspend fun getUsers(@Path("groupId") groupId: String): GroupUsers
|
||||
}
|
|
@ -1,37 +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.group
|
||||
|
||||
import org.matrix.android.sdk.api.session.group.Group
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GroupFactory {
|
||||
fun create(groupId: String): Group
|
||||
}
|
||||
|
||||
@SessionScope
|
||||
internal class DefaultGroupFactory @Inject constructor(private val getGroupDataTask: GetGroupDataTask) :
|
||||
GroupFactory {
|
||||
|
||||
override fun create(groupId: String): Group {
|
||||
return DefaultGroup(
|
||||
groupId = groupId,
|
||||
getGroupDataTask = getGroupDataTask
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,47 +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.group
|
||||
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import org.matrix.android.sdk.api.session.group.GroupService
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import retrofit2.Retrofit
|
||||
|
||||
@Module
|
||||
internal abstract class GroupModule {
|
||||
|
||||
@Module
|
||||
companion object {
|
||||
@Provides
|
||||
@JvmStatic
|
||||
@SessionScope
|
||||
fun providesGroupAPI(retrofit: Retrofit): GroupAPI {
|
||||
return retrofit.create(GroupAPI::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@Binds
|
||||
abstract fun bindGroupFactory(factory: DefaultGroupFactory): GroupFactory
|
||||
|
||||
@Binds
|
||||
abstract fun bindGetGroupDataTask(task: DefaultGetGroupDataTask): GetGroupDataTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindGroupService(service: DefaultGroupService): GroupService
|
||||
}
|
|
@ -1,49 +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.group.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* This class represents a community profile in the server responses.
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class GroupProfile(
|
||||
|
||||
@Json(name = "short_description") val shortDescription: String? = null,
|
||||
|
||||
/**
|
||||
* Tell whether the group is public.
|
||||
*/
|
||||
@Json(name = "is_public") val isPublic: Boolean? = null,
|
||||
|
||||
/**
|
||||
* The URL for the group's avatar. May be nil.
|
||||
*/
|
||||
@Json(name = "avatar_url") val avatarUrl: String? = null,
|
||||
|
||||
/**
|
||||
* The group's name.
|
||||
*/
|
||||
@Json(name = "name") val name: String? = null,
|
||||
|
||||
/**
|
||||
* The optional HTML formatted string used to described the group.
|
||||
*/
|
||||
@Json(name = "long_description") val longDescription: String? = null
|
||||
)
|
|
@ -1,35 +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.group.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class GroupRoom(
|
||||
|
||||
@Json(name = "aliases") val aliases: List<String> = emptyList(),
|
||||
@Json(name = "canonical_alias") val canonicalAlias: String? = null,
|
||||
@Json(name = "name") val name: String? = null,
|
||||
@Json(name = "num_joined_members") val numJoinedMembers: Int = 0,
|
||||
@Json(name = "room_id") val roomId: String,
|
||||
@Json(name = "topic") val topic: String? = null,
|
||||
@Json(name = "world_readable") val worldReadable: Boolean = false,
|
||||
@Json(name = "guest_can_join") val guestCanJoin: Boolean = false,
|
||||
@Json(name = "avatar_url") val avatarUrl: String? = null
|
||||
|
||||
)
|
|
@ -1,46 +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.group.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* This class represents the summary of a community in the server response.
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class GroupSummaryResponse(
|
||||
/**
|
||||
* The group profile.
|
||||
*/
|
||||
@Json(name = "profile") val profile: GroupProfile? = null,
|
||||
|
||||
/**
|
||||
* The group users.
|
||||
*/
|
||||
@Json(name = "users_section") val usersSection: GroupSummaryUsersSection? = null,
|
||||
|
||||
/**
|
||||
* The current user status.
|
||||
*/
|
||||
@Json(name = "user") val user: GroupSummaryUser? = null,
|
||||
|
||||
/**
|
||||
* The rooms linked to the community.
|
||||
*/
|
||||
@Json(name = "rooms_section") val roomsSection: GroupSummaryRoomsSection? = 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.group.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* This class represents the community rooms in a group summary response.
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class GroupSummaryRoomsSection(
|
||||
|
||||
@Json(name = "total_room_count_estimate") val totalRoomCountEstimate: Int? = null,
|
||||
|
||||
@Json(name = "rooms") val rooms: List<String> = emptyList()
|
||||
|
||||
// TODO Check the meaning and the usage of these categories. This dictionary is empty FTM.
|
||||
// public Map<Object, Object> categories;
|
||||
)
|
|
@ -1,37 +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.group.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* This class represents the current user status in a group summary response.
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class GroupSummaryUser(
|
||||
|
||||
/**
|
||||
* The current user membership in this community.
|
||||
*/
|
||||
@Json(name = "membership") val membership: String? = null,
|
||||
|
||||
/**
|
||||
* Tell whether the user published this community on his profile.
|
||||
*/
|
||||
@Json(name = "is_publicised") val isPublicised: Boolean? = null
|
||||
)
|
|
@ -1,35 +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.group.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* This class represents the community members in a group summary response.
|
||||
*/
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class GroupSummaryUsersSection(
|
||||
|
||||
@Json(name = "total_user_count_estimate") val totalUserCountEstimate: Int,
|
||||
|
||||
@Json(name = "users") val users: List<String> = emptyList()
|
||||
|
||||
// TODO Check the meaning and the usage of these roles. This dictionary is empty FTM.
|
||||
// public Map<Object, Object> roles;
|
||||
)
|
|
@ -1,29 +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.group.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class GroupUser(
|
||||
@Json(name = "display_name") val displayName: String = "",
|
||||
@Json(name = "user_id") val userId: String,
|
||||
@Json(name = "is_privileged") val isPrivileged: Boolean = false,
|
||||
@Json(name = "avatar_url") val avatarUrl: String? = "",
|
||||
@Json(name = "is_public") val isPublic: Boolean = false
|
||||
)
|
|
@ -1,26 +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.group.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class GroupUsers(
|
||||
@Json(name = "total_user_count_estimate") val totalUserCountEstimate: Int,
|
||||
@Json(name = "chunk") val users: List<GroupUser> = emptyList()
|
||||
)
|
|
@ -97,7 +97,6 @@ internal class PermalinkFactory @Inject constructor(
|
|||
url.startsWith(MATRIX_TO_URL_BASE) -> url.substring(MATRIX_TO_URL_BASE.length)
|
||||
clientBaseUrl != null && url.startsWith(clientBaseUrl) -> {
|
||||
when (PermalinkParser.parse(url)) {
|
||||
is PermalinkData.GroupLink -> url.substring(clientBaseUrl.length + GROUP_PATH.length)
|
||||
is PermalinkData.RoomLink -> url.substring(clientBaseUrl.length + ROOM_PATH.length)
|
||||
is PermalinkData.UserLink -> url.substring(clientBaseUrl.length + USER_PATH.length)
|
||||
else -> null
|
||||
|
|
|
@ -328,9 +328,6 @@ internal class RoomSummaryDataSource @Inject constructor(
|
|||
null -> Unit // nop
|
||||
}
|
||||
|
||||
queryParams.activeGroupId?.let { activeGroupId ->
|
||||
query.contains(RoomSummaryEntityFields.GROUP_IDS, activeGroupId)
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ import org.matrix.android.sdk.internal.crypto.crosssigning.DefaultCrossSigningSe
|
|||
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
|
||||
import org.matrix.android.sdk.internal.database.mapper.asDomain
|
||||
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
|
||||
import org.matrix.android.sdk.internal.database.model.GroupSummaryEntity
|
||||
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.RoomSummaryEntityFields
|
||||
|
@ -438,38 +437,6 @@ internal class RoomSummaryUpdater @Inject constructor(
|
|||
space.notificationCount = notificationCount
|
||||
}
|
||||
// xxx invites??
|
||||
|
||||
// LEGACY GROUPS
|
||||
// lets mark rooms that belongs to groups
|
||||
val existingGroups = GroupSummaryEntity.where(realm).findAll()
|
||||
|
||||
// For rooms
|
||||
realm.where(RoomSummaryEntity::class.java)
|
||||
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships())
|
||||
.equalTo(RoomSummaryEntityFields.IS_DIRECT, false)
|
||||
.findAll().forEach { room ->
|
||||
val belongsTo = existingGroups.filter { it.roomIds.contains(room.roomId) }
|
||||
room.groupIds = if (belongsTo.isEmpty()) {
|
||||
null
|
||||
} else {
|
||||
"|${belongsTo.joinToString("|")}|"
|
||||
}
|
||||
}
|
||||
|
||||
// For DMS
|
||||
realm.where(RoomSummaryEntity::class.java)
|
||||
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships())
|
||||
.equalTo(RoomSummaryEntityFields.IS_DIRECT, true)
|
||||
.findAll().forEach { room ->
|
||||
val belongsTo = existingGroups.filter {
|
||||
it.userIds.intersect(room.otherMemberIds).isNotEmpty()
|
||||
}
|
||||
room.groupIds = if (belongsTo.isEmpty()) {
|
||||
null
|
||||
} else {
|
||||
"|${belongsTo.joinToString("|")}|"
|
||||
}
|
||||
}
|
||||
}.also {
|
||||
Timber.v("## SPACES: Finish checking room hierarchy in $it ms")
|
||||
}
|
||||
|
|
|
@ -16,47 +16,36 @@
|
|||
|
||||
package org.matrix.android.sdk.internal.session.sync
|
||||
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import org.matrix.android.sdk.api.session.pushrules.PushRuleService
|
||||
import org.matrix.android.sdk.api.session.pushrules.RuleScope
|
||||
import org.matrix.android.sdk.api.session.sync.InitialSyncStep
|
||||
import org.matrix.android.sdk.api.session.sync.model.GroupsSyncResponse
|
||||
import org.matrix.android.sdk.api.session.sync.model.RoomsSyncResponse
|
||||
import org.matrix.android.sdk.api.session.sync.model.SyncResponse
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
|
||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||
import org.matrix.android.sdk.internal.di.SessionId
|
||||
import org.matrix.android.sdk.internal.di.WorkManagerProvider
|
||||
import org.matrix.android.sdk.internal.session.SessionListeners
|
||||
import org.matrix.android.sdk.internal.session.dispatchTo
|
||||
import org.matrix.android.sdk.internal.session.group.GetGroupDataWorker
|
||||
import org.matrix.android.sdk.internal.session.pushrules.ProcessEventForPushTask
|
||||
import org.matrix.android.sdk.internal.session.sync.handler.CryptoSyncHandler
|
||||
import org.matrix.android.sdk.internal.session.sync.handler.GroupSyncHandler
|
||||
import org.matrix.android.sdk.internal.session.sync.handler.PresenceSyncHandler
|
||||
import org.matrix.android.sdk.internal.session.sync.handler.SyncResponsePostTreatmentAggregatorHandler
|
||||
import org.matrix.android.sdk.internal.session.sync.handler.UserAccountDataSyncHandler
|
||||
import org.matrix.android.sdk.internal.session.sync.handler.room.RoomSyncHandler
|
||||
import org.matrix.android.sdk.internal.util.awaitTransaction
|
||||
import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER"
|
||||
|
||||
internal class SyncResponseHandler @Inject constructor(
|
||||
@SessionDatabase private val monarchy: Monarchy,
|
||||
@SessionId private val sessionId: String,
|
||||
private val sessionManager: SessionManager,
|
||||
private val sessionListeners: SessionListeners,
|
||||
private val workManagerProvider: WorkManagerProvider,
|
||||
private val roomSyncHandler: RoomSyncHandler,
|
||||
private val userAccountDataSyncHandler: UserAccountDataSyncHandler,
|
||||
private val groupSyncHandler: GroupSyncHandler,
|
||||
private val cryptoSyncHandler: CryptoSyncHandler,
|
||||
private val aggregatorHandler: SyncResponsePostTreatmentAggregatorHandler,
|
||||
private val cryptoService: DefaultCryptoService,
|
||||
|
@ -109,7 +98,7 @@ internal class SyncResponseHandler @Inject constructor(
|
|||
// IMPORTANT nothing should be suspend here as we are accessing the realm instance (thread local)
|
||||
measureTimeMillis {
|
||||
Timber.v("Handle rooms")
|
||||
reportSubtask(reporter, InitialSyncStep.ImportingAccountRoom, 1, 0.7f) {
|
||||
reportSubtask(reporter, InitialSyncStep.ImportingAccountRoom, 1, 0.8f) {
|
||||
if (syncResponse.rooms != null) {
|
||||
roomSyncHandler.handle(realm, syncResponse.rooms, isInitialSync, aggregator, reporter)
|
||||
}
|
||||
|
@ -118,17 +107,6 @@ internal class SyncResponseHandler @Inject constructor(
|
|||
Timber.v("Finish handling rooms in $it ms")
|
||||
}
|
||||
|
||||
measureTimeMillis {
|
||||
reportSubtask(reporter, InitialSyncStep.ImportingAccountGroups, 1, 0.1f) {
|
||||
Timber.v("Handle groups")
|
||||
if (syncResponse.groups != null) {
|
||||
groupSyncHandler.handle(realm, syncResponse.groups, reporter)
|
||||
}
|
||||
}
|
||||
}.also {
|
||||
Timber.v("Finish handling groups in $it ms")
|
||||
}
|
||||
|
||||
measureTimeMillis {
|
||||
reportSubtask(reporter, InitialSyncStep.ImportingAccountData, 1, 0.1f) {
|
||||
Timber.v("Handle accountData")
|
||||
|
@ -155,9 +133,6 @@ internal class SyncResponseHandler @Inject constructor(
|
|||
userAccountDataSyncHandler.synchronizeWithServerIfNeeded(it.invite)
|
||||
dispatchInvitedRoom(it)
|
||||
}
|
||||
syncResponse.groups?.let {
|
||||
scheduleGroupDataFetchingIfNeeded(it)
|
||||
}
|
||||
|
||||
Timber.v("On sync completed")
|
||||
cryptoSyncHandler.onSyncCompleted(syncResponse)
|
||||
|
@ -177,31 +152,6 @@ internal class SyncResponseHandler @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* At the moment we don't get any group data through the sync, so we poll where every hour.
|
||||
* You can also force to refetch group data using [Group] API.
|
||||
*/
|
||||
private fun scheduleGroupDataFetchingIfNeeded(groupsSyncResponse: GroupsSyncResponse) {
|
||||
val groupIds = ArrayList<String>()
|
||||
groupIds.addAll(groupsSyncResponse.join.keys)
|
||||
groupIds.addAll(groupsSyncResponse.invite.keys)
|
||||
if (groupIds.isEmpty()) {
|
||||
Timber.v("No new groups to fetch data for.")
|
||||
return
|
||||
}
|
||||
Timber.v("There are ${groupIds.size} new groups to fetch data for.")
|
||||
val getGroupDataWorkerParams = GetGroupDataWorker.Params(sessionId)
|
||||
val workData = WorkerParamsFactory.toData(getGroupDataWorkerParams)
|
||||
|
||||
val getGroupWork = workManagerProvider.matrixPeriodicWorkRequestBuilder<GetGroupDataWorker>(1, TimeUnit.HOURS)
|
||||
.setInputData(workData)
|
||||
.setConstraints(WorkManagerProvider.workConstraints)
|
||||
.build()
|
||||
|
||||
workManagerProvider.workManager
|
||||
.enqueueUniquePeriodicWork(GET_GROUP_DATA_WORKER, ExistingPeriodicWorkPolicy.REPLACE, getGroupWork)
|
||||
}
|
||||
|
||||
private suspend fun checkPushRules(roomsSyncResponse: RoomsSyncResponse, isInitialSync: Boolean) {
|
||||
Timber.v("[PushRules] --> checkPushRules")
|
||||
if (isInitialSync) {
|
||||
|
|
|
@ -1,104 +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.sync.handler
|
||||
|
||||
import io.realm.Realm
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.sync.InitialSyncStep
|
||||
import org.matrix.android.sdk.api.session.sync.model.GroupsSyncResponse
|
||||
import org.matrix.android.sdk.api.session.sync.model.InvitedGroupSync
|
||||
import org.matrix.android.sdk.internal.database.model.GroupEntity
|
||||
import org.matrix.android.sdk.internal.database.model.GroupSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.query.getOrCreate
|
||||
import org.matrix.android.sdk.internal.database.query.where
|
||||
import org.matrix.android.sdk.internal.session.sync.ProgressReporter
|
||||
import org.matrix.android.sdk.internal.session.sync.mapWithProgress
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class GroupSyncHandler @Inject constructor() {
|
||||
|
||||
sealed class HandlingStrategy {
|
||||
data class JOINED(val data: Map<String, Any>) : HandlingStrategy()
|
||||
data class INVITED(val data: Map<String, InvitedGroupSync>) : HandlingStrategy()
|
||||
data class LEFT(val data: Map<String, Any>) : HandlingStrategy()
|
||||
}
|
||||
|
||||
fun handle(
|
||||
realm: Realm,
|
||||
roomsSyncResponse: GroupsSyncResponse,
|
||||
reporter: ProgressReporter? = null
|
||||
) {
|
||||
handleGroupSync(realm, HandlingStrategy.JOINED(roomsSyncResponse.join), reporter)
|
||||
handleGroupSync(realm, HandlingStrategy.INVITED(roomsSyncResponse.invite), reporter)
|
||||
handleGroupSync(realm, HandlingStrategy.LEFT(roomsSyncResponse.leave), reporter)
|
||||
}
|
||||
|
||||
// PRIVATE METHODS *****************************************************************************
|
||||
|
||||
private fun handleGroupSync(realm: Realm, handlingStrategy: HandlingStrategy, reporter: ProgressReporter?) {
|
||||
val groups = when (handlingStrategy) {
|
||||
is HandlingStrategy.JOINED ->
|
||||
handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountGroups, 0.6f) {
|
||||
handleJoinedGroup(realm, it.key)
|
||||
}
|
||||
|
||||
is HandlingStrategy.INVITED ->
|
||||
handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountGroups, 0.3f) {
|
||||
handleInvitedGroup(realm, it.key)
|
||||
}
|
||||
|
||||
is HandlingStrategy.LEFT ->
|
||||
handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountGroups, 0.1f) {
|
||||
handleLeftGroup(realm, it.key)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(groups)
|
||||
}
|
||||
|
||||
private fun handleJoinedGroup(
|
||||
realm: Realm,
|
||||
groupId: String
|
||||
): GroupEntity {
|
||||
val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId)
|
||||
val groupSummaryEntity = GroupSummaryEntity.getOrCreate(realm, groupId)
|
||||
groupEntity.membership = Membership.JOIN
|
||||
groupSummaryEntity.membership = Membership.JOIN
|
||||
return groupEntity
|
||||
}
|
||||
|
||||
private fun handleInvitedGroup(
|
||||
realm: Realm,
|
||||
groupId: String
|
||||
): GroupEntity {
|
||||
val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId)
|
||||
val groupSummaryEntity = GroupSummaryEntity.getOrCreate(realm, groupId)
|
||||
groupEntity.membership = Membership.INVITE
|
||||
groupSummaryEntity.membership = Membership.INVITE
|
||||
return groupEntity
|
||||
}
|
||||
|
||||
private fun handleLeftGroup(
|
||||
realm: Realm,
|
||||
groupId: String
|
||||
): GroupEntity {
|
||||
val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId)
|
||||
val groupSummaryEntity = GroupSummaryEntity.getOrCreate(realm, groupId)
|
||||
groupEntity.membership = Membership.LEAVE
|
||||
groupSummaryEntity.membership = Membership.LEAVE
|
||||
return groupEntity
|
||||
}
|
||||
}
|
|
@ -25,7 +25,6 @@ import org.matrix.android.sdk.internal.SessionManager
|
|||
import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorker
|
||||
import org.matrix.android.sdk.internal.di.MatrixScope
|
||||
import org.matrix.android.sdk.internal.session.content.UploadContentWorker
|
||||
import org.matrix.android.sdk.internal.session.group.GetGroupDataWorker
|
||||
import org.matrix.android.sdk.internal.session.pushers.AddPusherWorker
|
||||
import org.matrix.android.sdk.internal.session.room.aggregation.livelocation.DeactivateLiveLocationShareWorker
|
||||
import org.matrix.android.sdk.internal.session.room.send.MultipleEventSendingDispatcherWorker
|
||||
|
@ -53,8 +52,6 @@ internal class MatrixWorkerFactory @Inject constructor(private val sessionManage
|
|||
CheckFactoryWorker(appContext, workerParameters, true)
|
||||
AddPusherWorker::class.java.name ->
|
||||
AddPusherWorker(appContext, workerParameters, sessionManager)
|
||||
GetGroupDataWorker::class.java.name ->
|
||||
GetGroupDataWorker(appContext, workerParameters, sessionManager)
|
||||
MultipleEventSendingDispatcherWorker::class.java.name ->
|
||||
MultipleEventSendingDispatcherWorker(appContext, workerParameters, sessionManager)
|
||||
RedactEventWorker::class.java.name ->
|
||||
|
|
|
@ -40,20 +40,11 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
|
|||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.getRoom
|
||||
import org.matrix.android.sdk.api.session.getRoomSummary
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.sync.SyncRequestState
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
sealed class RoomGroupingMethod {
|
||||
data class ByLegacyGroup(val groupSummary: GroupSummary?) : RoomGroupingMethod()
|
||||
data class BySpace(val spaceSummary: RoomSummary?) : RoomGroupingMethod()
|
||||
}
|
||||
|
||||
fun RoomGroupingMethod.space() = (this as? RoomGroupingMethod.BySpace)?.spaceSummary
|
||||
fun RoomGroupingMethod.group() = (this as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary
|
||||
|
||||
/**
|
||||
* This class handles the global app state.
|
||||
* It requires to be added to ProcessLifecycleOwner.get().lifecycle
|
||||
|
@ -68,29 +59,20 @@ class AppStateHandler @Inject constructor(
|
|||
) : DefaultLifecycleObserver {
|
||||
|
||||
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
||||
private val selectedSpaceDataSource = BehaviorDataSource<Option<RoomGroupingMethod>>(Option.empty())
|
||||
private val selectedSpaceDataSource = BehaviorDataSource<Option<RoomSummary>>(Option.empty())
|
||||
|
||||
val selectedRoomGroupingFlow = selectedSpaceDataSource.stream()
|
||||
val selectedSpaceFlow = selectedSpaceDataSource.stream()
|
||||
|
||||
private val spaceBackstack = ArrayDeque<String?>()
|
||||
|
||||
fun getCurrentRoomGroupingMethod(): RoomGroupingMethod? {
|
||||
// XXX we should somehow make it live :/ just a work around
|
||||
// For example just after creating a space and switching to it the
|
||||
// name in the app Bar could show Empty Room, and it will not update unless you
|
||||
// switch space
|
||||
return selectedSpaceDataSource.currentValue?.orNull()?.let {
|
||||
if (it is RoomGroupingMethod.BySpace) {
|
||||
// try to refresh sum?
|
||||
it.spaceSummary?.roomId?.let { activeSessionHolder.getSafeActiveSession()?.roomService()?.getRoomSummary(it) }?.let {
|
||||
RoomGroupingMethod.BySpace(it)
|
||||
} ?: it
|
||||
} else it
|
||||
fun getCurrentSpace(): RoomSummary? {
|
||||
return selectedSpaceDataSource.currentValue?.orNull()?.let { spaceSummary ->
|
||||
activeSessionHolder.getSafeActiveSession()?.roomService()?.getRoomSummary(spaceSummary.roomId)
|
||||
}
|
||||
}
|
||||
|
||||
fun setCurrentSpace(spaceId: String?, session: Session? = null, persistNow: Boolean = false, isForwardNavigation: Boolean = true) {
|
||||
val currentSpace = (selectedSpaceDataSource.currentValue?.orNull() as? RoomGroupingMethod.BySpace)?.space()
|
||||
val currentSpace = selectedSpaceDataSource.currentValue?.orNull()
|
||||
val uSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return
|
||||
if (currentSpace != null && spaceId == currentSpace.roomId) return
|
||||
val spaceSum = spaceId?.let { uSession.getRoomSummary(spaceId) }
|
||||
|
@ -100,11 +82,15 @@ class AppStateHandler @Inject constructor(
|
|||
}
|
||||
|
||||
if (persistNow) {
|
||||
uiStateRepository.storeGroupingMethod(true, uSession.sessionId)
|
||||
uiStateRepository.storeSelectedSpace(spaceSum?.roomId, uSession.sessionId)
|
||||
}
|
||||
|
||||
selectedSpaceDataSource.post(Option.just(RoomGroupingMethod.BySpace(spaceSum)))
|
||||
if (spaceSum == null) {
|
||||
selectedSpaceDataSource.post(Option.empty())
|
||||
} else {
|
||||
selectedSpaceDataSource.post(Option.just(spaceSum))
|
||||
}
|
||||
|
||||
if (spaceId != null) {
|
||||
uSession.coroutineScope.launch(Dispatchers.IO) {
|
||||
tryOrNull {
|
||||
|
@ -114,32 +100,13 @@ class AppStateHandler @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun setCurrentGroup(groupId: String?, session: Session? = null) {
|
||||
val uSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return
|
||||
if (selectedSpaceDataSource.currentValue?.orNull() is RoomGroupingMethod.ByLegacyGroup &&
|
||||
groupId == selectedSpaceDataSource.currentValue?.orNull()?.group()?.groupId) return
|
||||
val activeGroup = groupId?.let { uSession.groupService().getGroupSummary(groupId) }
|
||||
selectedSpaceDataSource.post(Option.just(RoomGroupingMethod.ByLegacyGroup(activeGroup)))
|
||||
if (groupId != null) {
|
||||
uSession.coroutineScope.launch {
|
||||
tryOrNull {
|
||||
uSession.groupService().getGroup(groupId)?.fetchGroupData()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeActiveSession() {
|
||||
sessionDataSource.stream()
|
||||
.distinctUntilChanged()
|
||||
.onEach {
|
||||
// sessionDataSource could already return a session while activeSession holder still returns null
|
||||
it.orNull()?.let { session ->
|
||||
if (uiStateRepository.isGroupingMethodSpace(session.sessionId)) {
|
||||
setCurrentSpace(uiStateRepository.getSelectedSpace(session.sessionId), session)
|
||||
} else {
|
||||
setCurrentGroup(uiStateRepository.getSelectedGroup(session.sessionId), session)
|
||||
}
|
||||
observeSyncStatus(session)
|
||||
}
|
||||
}
|
||||
|
@ -160,11 +127,7 @@ class AppStateHandler @Inject constructor(
|
|||
fun getSpaceBackstack() = spaceBackstack
|
||||
|
||||
fun safeActiveSpaceId(): String? {
|
||||
return (selectedSpaceDataSource.currentValue?.orNull() as? RoomGroupingMethod.BySpace)?.spaceSummary?.roomId
|
||||
}
|
||||
|
||||
fun safeActiveGroupId(): String? {
|
||||
return (selectedSpaceDataSource.currentValue?.orNull() as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary?.groupId
|
||||
return selectedSpaceDataSource.currentValue?.orNull()?.roomId
|
||||
}
|
||||
|
||||
override fun onResume(owner: LifecycleOwner) {
|
||||
|
@ -174,15 +137,6 @@ class AppStateHandler @Inject constructor(
|
|||
override fun onPause(owner: LifecycleOwner) {
|
||||
coroutineScope.coroutineContext.cancelChildren()
|
||||
val session = activeSessionHolder.getSafeActiveSession() ?: return
|
||||
when (val currentMethod = selectedSpaceDataSource.currentValue?.orNull() ?: RoomGroupingMethod.BySpace(null)) {
|
||||
is RoomGroupingMethod.BySpace -> {
|
||||
uiStateRepository.storeGroupingMethod(true, session.sessionId)
|
||||
uiStateRepository.storeSelectedSpace(currentMethod.spaceSummary?.roomId, session.sessionId)
|
||||
}
|
||||
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||
uiStateRepository.storeGroupingMethod(false, session.sessionId)
|
||||
uiStateRepository.storeSelectedGroup(currentMethod.groupSummary?.groupId, session.sessionId)
|
||||
}
|
||||
}
|
||||
uiStateRepository.storeSelectedSpace(selectedSpaceDataSource.currentValue?.orNull()?.roomId, session.sessionId)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,19 +16,13 @@
|
|||
|
||||
package im.vector.app.features.analytics.extensions
|
||||
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import im.vector.app.features.analytics.plan.ViewRoom
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||
|
||||
fun RoomSummary?.toAnalyticsViewRoom(trigger: ViewRoom.Trigger?, groupingMethod: RoomGroupingMethod? = null, viaKeyboard: Boolean? = null): ViewRoom {
|
||||
val activeSpace = groupingMethod?.let {
|
||||
when (it) {
|
||||
is RoomGroupingMethod.BySpace -> it.spaceSummary?.toActiveSpace() ?: ViewRoom.ActiveSpace.Home
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
fun RoomSummary?.toAnalyticsViewRoom(trigger: ViewRoom.Trigger?, selectedSpace: RoomSummary? = null, viaKeyboard: Boolean? = null): ViewRoom {
|
||||
val activeSpace = selectedSpace?.toActiveSpace() ?: ViewRoom.ActiveSpace.Home
|
||||
|
||||
return ViewRoom(
|
||||
isDM = this?.isDirect.orFalse(),
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.autocomplete.group
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.app.features.autocomplete.AutocompleteClickListener
|
||||
import im.vector.app.features.autocomplete.autocompleteMatrixItem
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import javax.inject.Inject
|
||||
|
||||
class AutocompleteGroupController @Inject constructor() : TypedEpoxyController<List<GroupSummary>>() {
|
||||
|
||||
var listener: AutocompleteClickListener<GroupSummary>? = null
|
||||
|
||||
@Inject lateinit var avatarRenderer: AvatarRenderer
|
||||
|
||||
override fun buildModels(data: List<GroupSummary>?) {
|
||||
if (data.isNullOrEmpty()) {
|
||||
return
|
||||
}
|
||||
val host = this
|
||||
data.forEach { groupSummary ->
|
||||
autocompleteMatrixItem {
|
||||
id(groupSummary.groupId)
|
||||
matrixItem(groupSummary.toMatrixItem())
|
||||
avatarRenderer(host.avatarRenderer)
|
||||
clickListener { host.listener?.onItemClick(groupSummary) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.autocomplete.group
|
||||
|
||||
import android.content.Context
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import im.vector.app.features.autocomplete.AutocompleteClickListener
|
||||
import im.vector.app.features.autocomplete.RecyclerViewPresenter
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.group.groupSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import javax.inject.Inject
|
||||
|
||||
class AutocompleteGroupPresenter @Inject constructor(
|
||||
context: Context,
|
||||
private val controller: AutocompleteGroupController,
|
||||
private val session: Session
|
||||
) : RecyclerViewPresenter<GroupSummary>(context), AutocompleteClickListener<GroupSummary> {
|
||||
|
||||
init {
|
||||
controller.listener = this
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
controller.listener = null
|
||||
}
|
||||
|
||||
override fun instantiateAdapter(): RecyclerView.Adapter<*> {
|
||||
return controller.adapter
|
||||
}
|
||||
|
||||
override fun onItemClick(t: GroupSummary) {
|
||||
dispatchClick(t)
|
||||
}
|
||||
|
||||
override fun onQuery(query: CharSequence?) {
|
||||
val queryParams = groupSummaryQueryParams {
|
||||
displayName = if (query.isNullOrBlank()) {
|
||||
QueryStringValue.IsNotEmpty
|
||||
} else {
|
||||
QueryStringValue.Contains(query.toString(), QueryStringValue.Case.INSENSITIVE)
|
||||
}
|
||||
}
|
||||
val groups = session.groupService().getGroupSummaries(queryParams)
|
||||
.asSequence()
|
||||
.sortedBy { it.displayName }
|
||||
controller.setData(groups.toList())
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ import org.matrix.android.sdk.api.util.MatrixItem
|
|||
|
||||
fun MatrixItem.getBestName(): String {
|
||||
// Note: this code is copied from [DisplayNameResolver] in the SDK
|
||||
return if (this is MatrixItem.GroupItem || this is MatrixItem.RoomAliasItem) {
|
||||
return if (this is MatrixItem.RoomAliasItem) {
|
||||
// Best name is the id, and we keep the displayName of the room for the case we need the first letter
|
||||
id
|
||||
} else {
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.grouplist
|
||||
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.ClickListener
|
||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.app.core.epoxy.onClick
|
||||
import im.vector.app.core.platform.CheckableConstraintLayout
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
||||
@EpoxyModelClass
|
||||
abstract class GroupSummaryItem : VectorEpoxyModel<GroupSummaryItem.Holder>(R.layout.item_group) {
|
||||
|
||||
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
|
||||
@EpoxyAttribute lateinit var matrixItem: MatrixItem
|
||||
@EpoxyAttribute var selected: Boolean = false
|
||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.rootView.onClick(listener)
|
||||
holder.groupNameView.text = matrixItem.displayName
|
||||
holder.rootView.isChecked = selected
|
||||
avatarRenderer.render(matrixItem, holder.avatarImageView)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val avatarImageView by bind<ImageView>(R.id.groupAvatarImageView)
|
||||
val groupNameView by bind<TextView>(R.id.groupNameView)
|
||||
val rootView by bind<CheckableConstraintLayout>(R.id.itemGroupLayout)
|
||||
}
|
||||
}
|
|
@ -214,13 +214,12 @@ class HomeActivity :
|
|||
when (sharedAction) {
|
||||
is HomeActivitySharedAction.OpenDrawer -> views.drawerLayout.openDrawer(GravityCompat.START)
|
||||
is HomeActivitySharedAction.CloseDrawer -> views.drawerLayout.closeDrawer(GravityCompat.START)
|
||||
is HomeActivitySharedAction.OpenGroup -> openGroup(sharedAction.shouldClearFragment)
|
||||
is HomeActivitySharedAction.OpenSpacePreview -> startActivity(SpacePreviewActivity.newIntent(this, sharedAction.spaceId))
|
||||
is HomeActivitySharedAction.AddSpace -> createSpaceResultLauncher.launch(SpaceCreationActivity.newIntent(this))
|
||||
is HomeActivitySharedAction.ShowSpaceSettings -> showSpaceSettings(sharedAction.spaceId)
|
||||
is HomeActivitySharedAction.OpenSpaceInvite -> openSpaceInvite(sharedAction.spaceId)
|
||||
HomeActivitySharedAction.SendSpaceFeedBack -> bugReporter.openBugReportScreen(this, ReportType.SPACE_BETA_FEEDBACK)
|
||||
HomeActivitySharedAction.CloseGroup -> closeGroup()
|
||||
HomeActivitySharedAction.OnCloseSpace -> onCloseSpace()
|
||||
}
|
||||
}
|
||||
.launchIn(lifecycleScope)
|
||||
|
@ -265,17 +264,6 @@ class HomeActivity :
|
|||
homeActivityViewModel.handle(HomeActivityViewActions.ViewStarted)
|
||||
}
|
||||
|
||||
private fun openGroup(shouldClearFragment: Boolean) {
|
||||
views.drawerLayout.closeDrawer(GravityCompat.START)
|
||||
|
||||
// When switching from space to group or group to space, we need to reload the fragment
|
||||
if (shouldClearFragment) {
|
||||
replaceFragment(views.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true)
|
||||
} else {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSpaceSettings(spaceId: String) {
|
||||
// open bottom sheet
|
||||
SpaceSettingsMenuBottomSheet
|
||||
|
@ -292,7 +280,7 @@ class HomeActivity :
|
|||
.show(supportFragmentManager, "SPACE_INVITE")
|
||||
}
|
||||
|
||||
private fun closeGroup() {
|
||||
private fun onCloseSpace() {
|
||||
views.drawerLayout.openDrawer(GravityCompat.START)
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,7 @@ import im.vector.app.core.platform.VectorSharedAction
|
|||
sealed class HomeActivitySharedAction : VectorSharedAction {
|
||||
object OpenDrawer : HomeActivitySharedAction()
|
||||
object CloseDrawer : HomeActivitySharedAction()
|
||||
data class OpenGroup(val shouldClearFragment: Boolean) : HomeActivitySharedAction()
|
||||
object CloseGroup : HomeActivitySharedAction()
|
||||
object OnCloseSpace : HomeActivitySharedAction()
|
||||
object AddSpace : HomeActivitySharedAction()
|
||||
data class OpenSpacePreview(val spaceId: String) : HomeActivitySharedAction()
|
||||
data class OpenSpaceInvite(val spaceId: String) : HomeActivitySharedAction()
|
||||
|
|
|
@ -30,7 +30,6 @@ import com.airbnb.mvrx.withState
|
|||
import com.google.android.material.badge.BadgeDrawable
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.R
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import im.vector.app.core.extensions.commitTransaction
|
||||
import im.vector.app.core.extensions.toMvRxBundle
|
||||
import im.vector.app.core.platform.OnBackPressed
|
||||
|
@ -58,7 +57,6 @@ import im.vector.app.features.themes.ThemeUtils
|
|||
import im.vector.app.features.workers.signout.BannerState
|
||||
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -130,11 +128,8 @@ class HomeDetailFragment @Inject constructor(
|
|||
views.bottomNavigationView.selectedItemId = it.currentTab.toMenuId()
|
||||
}
|
||||
|
||||
viewModel.onEach(HomeDetailViewState::roomGroupingMethod) { roomGroupingMethod ->
|
||||
when (roomGroupingMethod) {
|
||||
is RoomGroupingMethod.ByLegacyGroup -> onGroupChange(roomGroupingMethod.groupSummary)
|
||||
is RoomGroupingMethod.BySpace -> onSpaceChange(roomGroupingMethod.spaceSummary)
|
||||
}
|
||||
viewModel.onEach(HomeDetailViewState::selectedSpace) { selectedSpace ->
|
||||
onSpaceChange(selectedSpace)
|
||||
}
|
||||
|
||||
viewModel.onEach(HomeDetailViewState::currentTab) { currentTab ->
|
||||
|
@ -188,26 +183,16 @@ class HomeDetailFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun navigateBack() {
|
||||
try {
|
||||
val lastSpace = appStateHandler.getSpaceBackstack().removeLast()
|
||||
setCurrentSpace(lastSpace)
|
||||
} catch (e: NoSuchElementException) {
|
||||
navigateUpOneSpace()
|
||||
}
|
||||
val previousSpaceId = appStateHandler.getSpaceBackstack().removeLastOrNull()
|
||||
val parentSpaceId = appStateHandler.getCurrentSpace()?.flattenParentIds?.lastOrNull()
|
||||
setCurrentSpace(previousSpaceId ?: parentSpaceId)
|
||||
}
|
||||
|
||||
private fun setCurrentSpace(spaceId: String?) {
|
||||
appStateHandler.setCurrentSpace(spaceId, isForwardNavigation = false)
|
||||
sharedActionViewModel.post(HomeActivitySharedAction.CloseGroup)
|
||||
sharedActionViewModel.post(HomeActivitySharedAction.OnCloseSpace)
|
||||
}
|
||||
|
||||
private fun navigateUpOneSpace() {
|
||||
val parentId = getCurrentSpace()?.flattenParentIds?.lastOrNull()
|
||||
setCurrentSpace(parentId)
|
||||
}
|
||||
|
||||
private fun getCurrentSpace() = (appStateHandler.getCurrentRoomGroupingMethod() as? RoomGroupingMethod.BySpace)?.spaceSummary
|
||||
|
||||
private fun handleCallStarted() {
|
||||
dismissLoadingDialog()
|
||||
val fragmentTag = HomeTab.DialPad.toFragmentTag()
|
||||
|
@ -227,10 +212,8 @@ class HomeDetailFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun refreshSpaceState() {
|
||||
when (val roomGroupingMethod = appStateHandler.getCurrentRoomGroupingMethod()) {
|
||||
is RoomGroupingMethod.ByLegacyGroup -> onGroupChange(roomGroupingMethod.groupSummary)
|
||||
is RoomGroupingMethod.BySpace -> onSpaceChange(roomGroupingMethod.spaceSummary)
|
||||
else -> Unit
|
||||
appStateHandler.getCurrentSpace()?.let {
|
||||
onSpaceChange(it)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -291,15 +274,6 @@ class HomeDetailFragment @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun onGroupChange(groupSummary: GroupSummary?) {
|
||||
if (groupSummary == null) {
|
||||
views.groupToolbarSpaceTitleView.isVisible = false
|
||||
} else {
|
||||
views.groupToolbarSpaceTitleView.isVisible = true
|
||||
views.groupToolbarSpaceTitleView.text = groupSummary.displayName
|
||||
}
|
||||
}
|
||||
|
||||
private fun onSpaceChange(spaceSummary: RoomSummary?) {
|
||||
if (spaceSummary == null) {
|
||||
views.groupToolbarSpaceTitleView.isVisible = false
|
||||
|
@ -335,16 +309,9 @@ class HomeDetailFragment @Inject constructor(
|
|||
}
|
||||
|
||||
views.homeToolbarContent.debouncedClicks {
|
||||
withState(viewModel) {
|
||||
when (it.roomGroupingMethod) {
|
||||
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||
// do nothing
|
||||
}
|
||||
is RoomGroupingMethod.BySpace -> {
|
||||
it.roomGroupingMethod.spaceSummary?.let { spaceSummary ->
|
||||
sharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(spaceSummary.roomId))
|
||||
}
|
||||
}
|
||||
withState(viewModel) { viewState ->
|
||||
viewState.selectedSpace?.let {
|
||||
sharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(it.roomId))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -499,7 +466,7 @@ class HomeDetailFragment @Inject constructor(
|
|||
return this
|
||||
}
|
||||
|
||||
override fun onBackPressed(toolbarButton: Boolean) = if (getCurrentSpace() != null) {
|
||||
override fun onBackPressed(toolbarButton: Boolean) = if (appStateHandler.getCurrentSpace() != null) {
|
||||
navigateBack()
|
||||
true
|
||||
} else {
|
||||
|
|
|
@ -23,7 +23,6 @@ import dagger.assisted.Assisted
|
|||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||
import im.vector.app.core.extensions.singletonEntryPoint
|
||||
|
@ -208,16 +207,16 @@ class HomeDetailViewModel @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private fun observeRoomGroupingMethod() {
|
||||
appStateHandler.selectedRoomGroupingFlow
|
||||
appStateHandler.selectedSpaceFlow
|
||||
.setOnEach {
|
||||
copy(
|
||||
roomGroupingMethod = it.orNull() ?: RoomGroupingMethod.BySpace(null)
|
||||
selectedSpace = it.orNull()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeRoomSummaries() {
|
||||
appStateHandler.selectedRoomGroupingFlow.distinctUntilChanged().flatMapLatest {
|
||||
appStateHandler.selectedSpaceFlow.distinctUntilChanged().flatMapLatest {
|
||||
// we use it as a trigger to all changes in room, but do not really load
|
||||
// the actual models
|
||||
session.roomService().getPagedRoomSummariesLive(
|
||||
|
@ -229,12 +228,7 @@ class HomeDetailViewModel @AssistedInject constructor(
|
|||
}
|
||||
.throttleFirst(300)
|
||||
.onEach {
|
||||
when (val groupingMethod = appStateHandler.getCurrentRoomGroupingMethod()) {
|
||||
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||
// TODO!!
|
||||
}
|
||||
is RoomGroupingMethod.BySpace -> {
|
||||
val activeSpaceRoomId = groupingMethod.spaceSummary?.roomId
|
||||
val activeSpaceRoomId = appStateHandler.getCurrentSpace()?.roomId
|
||||
var dmInvites = 0
|
||||
var roomsInvite = 0
|
||||
if (autoAcceptInvites.showInvites()) {
|
||||
|
@ -250,7 +244,7 @@ class HomeDetailViewModel @AssistedInject constructor(
|
|||
roomSummaryQueryParams {
|
||||
memberships = listOf(Membership.INVITE)
|
||||
roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
spaceFilter = groupingMethod.toActiveSpaceOrOrphanRooms()
|
||||
spaceFilter = activeSpaceRoomId.toActiveSpaceOrOrphanRooms()
|
||||
}
|
||||
).size
|
||||
}
|
||||
|
@ -267,7 +261,7 @@ class HomeDetailViewModel @AssistedInject constructor(
|
|||
roomSummaryQueryParams {
|
||||
memberships = listOf(Membership.JOIN)
|
||||
roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
spaceFilter = groupingMethod.toActiveSpaceOrOrphanRooms()
|
||||
spaceFilter = activeSpaceRoomId.toActiveSpaceOrOrphanRooms()
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -283,13 +277,6 @@ class HomeDetailViewModel @AssistedInject constructor(
|
|||
)
|
||||
}
|
||||
}
|
||||
null -> Unit
|
||||
}
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
private fun RoomGroupingMethod.BySpace.toActiveSpaceOrOrphanRooms(): SpaceFilter {
|
||||
return spaceSummary?.roomId.toActiveSpaceOrOrphanRooms()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,14 +21,13 @@ import com.airbnb.mvrx.Async
|
|||
import com.airbnb.mvrx.MavericksState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.app.R
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.sync.SyncRequestState
|
||||
import org.matrix.android.sdk.api.session.sync.SyncState
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
||||
data class HomeDetailViewState(
|
||||
val roomGroupingMethod: RoomGroupingMethod = RoomGroupingMethod.BySpace(null),
|
||||
val selectedSpace: RoomSummary? = null,
|
||||
val myMatrixItem: MatrixItem? = null,
|
||||
val asyncRooms: Async<List<RoomSummary>> = Uninitialized,
|
||||
val currentTab: HomeTab = HomeTab.RoomList(RoomListDisplayMode.PEOPLE),
|
||||
|
|
|
@ -32,7 +32,6 @@ class InitSyncStepFormatter @Inject constructor(
|
|||
InitialSyncStep.ImportingAccount -> R.string.initial_sync_start_importing_account
|
||||
InitialSyncStep.ImportingAccountCrypto -> R.string.initial_sync_start_importing_account_crypto
|
||||
InitialSyncStep.ImportingAccountRoom -> R.string.initial_sync_start_importing_account_rooms
|
||||
InitialSyncStep.ImportingAccountGroups -> R.string.initial_sync_start_importing_account_groups
|
||||
InitialSyncStep.ImportingAccountData -> R.string.initial_sync_start_importing_account_data
|
||||
InitialSyncStep.ImportingAccountJoinedRooms -> R.string.initial_sync_start_importing_account_joined_rooms
|
||||
InitialSyncStep.ImportingAccountInvitedRooms -> R.string.initial_sync_start_importing_account_invited_rooms
|
||||
|
|
|
@ -23,7 +23,6 @@ import dagger.assisted.Assisted
|
|||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||
import im.vector.app.core.platform.EmptyAction
|
||||
|
@ -110,8 +109,8 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(
|
|||
}
|
||||
|
||||
combine(
|
||||
appStateHandler.selectedRoomGroupingFlow.distinctUntilChanged(),
|
||||
appStateHandler.selectedRoomGroupingFlow.flatMapLatest {
|
||||
appStateHandler.selectedSpaceFlow.distinctUntilChanged(),
|
||||
appStateHandler.selectedSpaceFlow.flatMapLatest {
|
||||
roomService.getPagedRoomSummariesLive(
|
||||
roomSummaryQueryParams {
|
||||
this.memberships = Membership.activeMemberships()
|
||||
|
@ -119,17 +118,8 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(
|
|||
).asFlow()
|
||||
.throttleFirst(300)
|
||||
}
|
||||
) { groupingMethod, _ ->
|
||||
when (groupingMethod.orNull()) {
|
||||
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||
// currently not supported
|
||||
CountInfo(
|
||||
RoomAggregateNotificationCount(0, 0),
|
||||
RoomAggregateNotificationCount(0, 0)
|
||||
)
|
||||
}
|
||||
is RoomGroupingMethod.BySpace -> {
|
||||
val selectedSpace = appStateHandler.safeActiveSpaceId()
|
||||
) { selectedSpaceOption, _ ->
|
||||
val selectedSpace = selectedSpaceOption.orNull()?.roomId
|
||||
|
||||
val inviteCount = if (autoAcceptInvites.hideInvites) {
|
||||
0
|
||||
|
@ -179,14 +169,6 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(
|
|||
spaceInviteCount
|
||||
)
|
||||
)
|
||||
}
|
||||
null -> {
|
||||
CountInfo(
|
||||
RoomAggregateNotificationCount(0, 0),
|
||||
RoomAggregateNotificationCount(0, 0)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
.flowOn(Dispatchers.Default)
|
||||
.execute {
|
||||
|
|
|
@ -32,7 +32,6 @@ import im.vector.app.core.glide.GlideRequests
|
|||
import im.vector.app.features.autocomplete.command.AutocompleteCommandPresenter
|
||||
import im.vector.app.features.autocomplete.command.CommandAutocompletePolicy
|
||||
import im.vector.app.features.autocomplete.emoji.AutocompleteEmojiPresenter
|
||||
import im.vector.app.features.autocomplete.group.AutocompleteGroupPresenter
|
||||
import im.vector.app.features.autocomplete.member.AutocompleteMemberItem
|
||||
import im.vector.app.features.autocomplete.member.AutocompleteMemberPresenter
|
||||
import im.vector.app.features.autocomplete.room.AutocompleteRoomPresenter
|
||||
|
@ -41,7 +40,6 @@ import im.vector.app.features.displayname.getBestName
|
|||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.html.PillImageSpan
|
||||
import im.vector.app.features.themes.ThemeUtils
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import org.matrix.android.sdk.api.util.toEveryoneInRoomMatrixItem
|
||||
|
@ -56,7 +54,6 @@ class AutoCompleter @AssistedInject constructor(
|
|||
autocompleteCommandPresenterFactory: AutocompleteCommandPresenter.Factory,
|
||||
private val autocompleteMemberPresenterFactory: AutocompleteMemberPresenter.Factory,
|
||||
private val autocompleteRoomPresenter: AutocompleteRoomPresenter,
|
||||
private val autocompleteGroupPresenter: AutocompleteGroupPresenter,
|
||||
private val autocompleteEmojiPresenter: AutocompleteEmojiPresenter
|
||||
) {
|
||||
|
||||
|
@ -89,7 +86,6 @@ class AutoCompleter @AssistedInject constructor(
|
|||
val backgroundDrawable = ColorDrawable(ThemeUtils.getColor(editText.context, android.R.attr.colorBackground))
|
||||
setupCommands(backgroundDrawable, editText)
|
||||
setupMembers(backgroundDrawable, editText)
|
||||
setupGroups(backgroundDrawable, editText)
|
||||
setupEmojis(backgroundDrawable, editText)
|
||||
setupRooms(backgroundDrawable, editText)
|
||||
}
|
||||
|
@ -97,7 +93,6 @@ class AutoCompleter @AssistedInject constructor(
|
|||
fun clear() {
|
||||
this.editText = null
|
||||
autocompleteEmojiPresenter.clear()
|
||||
autocompleteGroupPresenter.clear()
|
||||
autocompleteRoomPresenter.clear()
|
||||
autocompleteCommandPresenter.clear()
|
||||
autocompleteMemberPresenter.clear()
|
||||
|
@ -170,24 +165,6 @@ class AutoCompleter @AssistedInject constructor(
|
|||
.build()
|
||||
}
|
||||
|
||||
private fun setupGroups(backgroundDrawable: ColorDrawable, editText: EditText) {
|
||||
Autocomplete.on<GroupSummary>(editText)
|
||||
.with(CharPolicy(TRIGGER_AUTO_COMPLETE_GROUPS, true))
|
||||
.with(autocompleteGroupPresenter)
|
||||
.with(ELEVATION_DP)
|
||||
.with(backgroundDrawable)
|
||||
.with(object : AutocompleteCallback<GroupSummary> {
|
||||
override fun onPopupItemClicked(editable: Editable, item: GroupSummary): Boolean {
|
||||
insertMatrixItem(editText, editable, TRIGGER_AUTO_COMPLETE_GROUPS, item.toMatrixItem())
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPopupVisibilityChanged(shown: Boolean) {
|
||||
}
|
||||
})
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun setupEmojis(backgroundDrawable: Drawable, editText: EditText) {
|
||||
Autocomplete.on<String>(editText)
|
||||
.with(CharPolicy(TRIGGER_AUTO_COMPLETE_EMOJIS, false))
|
||||
|
@ -262,7 +239,6 @@ class AutoCompleter @AssistedInject constructor(
|
|||
private const val ELEVATION_DP = 6f
|
||||
private const val TRIGGER_AUTO_COMPLETE_MEMBERS = '@'
|
||||
private const val TRIGGER_AUTO_COMPLETE_ROOMS = '#'
|
||||
private const val TRIGGER_AUTO_COMPLETE_GROUPS = '+'
|
||||
private const val TRIGGER_AUTO_COMPLETE_EMOJIS = ':'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,6 @@ import im.vector.app.features.raw.wellknown.withElementWellKnown
|
|||
import im.vector.app.features.session.coroutineScope
|
||||
import im.vector.app.features.settings.VectorDataStore
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import im.vector.app.space
|
||||
import im.vector.lib.core.utils.flow.chunk
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
@ -219,7 +218,7 @@ class TimelineViewModel @AssistedInject constructor(
|
|||
if (initialState.switchToParentSpace) {
|
||||
// We are coming from a notification, try to switch to the most relevant space
|
||||
// so that when hitting back the room will appear in the list
|
||||
appStateHandler.getCurrentRoomGroupingMethod()?.space().let { currentSpace ->
|
||||
appStateHandler.getCurrentSpace().let { currentSpace ->
|
||||
val currentRoomSummary = room.roomSummary() ?: return@let
|
||||
// nothing we are good
|
||||
if ((currentSpace == null && !vectorPreferences.prefSpacesShowAllRoomInHome()) ||
|
||||
|
|
|
@ -24,7 +24,6 @@ import im.vector.app.core.resources.UserPreferencesProvider
|
|||
import im.vector.app.features.home.RoomListDisplayMode
|
||||
import im.vector.app.features.home.room.filtered.FilteredRoomFooterItem
|
||||
import im.vector.app.features.home.room.filtered.filteredRoomFooterItem
|
||||
import im.vector.app.space
|
||||
import javax.inject.Inject
|
||||
|
||||
class RoomListFooterController @Inject constructor(
|
||||
|
@ -42,7 +41,7 @@ class RoomListFooterController @Inject constructor(
|
|||
id("filter_footer")
|
||||
listener(host.listener)
|
||||
currentFilter(data.roomFilter)
|
||||
inSpace(data.currentRoomGrouping.invoke()?.space() != null)
|
||||
inSpace(data.asyncSelectedSpace.invoke() != null)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
|
|
|
@ -16,8 +16,443 @@
|
|||
|
||||
package im.vector.app.features.home.room.list
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.asFlow
|
||||
import androidx.lifecycle.liveData
|
||||
import androidx.paging.PagedList
|
||||
import com.airbnb.mvrx.Async
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.home.RoomListDisplayMode
|
||||
import im.vector.app.features.invite.AutoAcceptInvites
|
||||
import im.vector.app.features.invite.showInvites
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.update
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.query.RoomCategoryFilter
|
||||
import org.matrix.android.sdk.api.query.RoomTagQueryFilter
|
||||
import org.matrix.android.sdk.api.query.SpaceFilter
|
||||
import org.matrix.android.sdk.api.query.toActiveSpaceOrOrphanRooms
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.getRoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
||||
import timber.log.Timber
|
||||
|
||||
interface RoomListSectionBuilder {
|
||||
fun buildSections(mode: RoomListDisplayMode): List<RoomsSection>
|
||||
class RoomListSectionBuilder(
|
||||
private val session: Session,
|
||||
private val stringProvider: StringProvider,
|
||||
private val appStateHandler: AppStateHandler,
|
||||
private val viewModelScope: CoroutineScope,
|
||||
private val autoAcceptInvites: AutoAcceptInvites,
|
||||
private val onUpdatable: (UpdatableLivePageResult) -> Unit,
|
||||
private val suggestedRoomJoiningState: LiveData<Map<String, Async<Unit>>>,
|
||||
private val onlyOrphansInHome: Boolean = false
|
||||
) {
|
||||
|
||||
private val pagedListConfig = PagedList.Config.Builder()
|
||||
.setPageSize(10)
|
||||
.setInitialLoadSizeHint(20)
|
||||
.setEnablePlaceholders(true)
|
||||
.setPrefetchDistance(10)
|
||||
.build()
|
||||
|
||||
fun buildSections(mode: RoomListDisplayMode): List<RoomsSection> {
|
||||
val sections = mutableListOf<RoomsSection>()
|
||||
val activeSpaceAwareQueries = mutableListOf<RoomListViewModel.ActiveSpaceQueryUpdater>()
|
||||
when (mode) {
|
||||
RoomListDisplayMode.PEOPLE -> {
|
||||
// 4 sections Invites / Fav / Dms / Low Priority
|
||||
buildDmSections(sections, activeSpaceAwareQueries)
|
||||
}
|
||||
RoomListDisplayMode.ROOMS -> {
|
||||
// 6 sections invites / Fav / Rooms / Low Priority / Server notice / Suggested rooms
|
||||
buildRoomsSections(sections, activeSpaceAwareQueries)
|
||||
}
|
||||
RoomListDisplayMode.FILTERED -> {
|
||||
// Used when searching for rooms
|
||||
buildFilteredSection(sections)
|
||||
}
|
||||
RoomListDisplayMode.NOTIFICATIONS -> {
|
||||
buildNotificationsSection(sections, activeSpaceAwareQueries)
|
||||
}
|
||||
}
|
||||
|
||||
appStateHandler.selectedSpaceFlow
|
||||
.distinctUntilChanged()
|
||||
.onEach { selectedSpaceOption ->
|
||||
val selectedSpace = selectedSpaceOption.orNull()
|
||||
activeSpaceAwareQueries.onEach { updater ->
|
||||
updater.updateForSpaceId(selectedSpace?.roomId)
|
||||
}
|
||||
}.launchIn(viewModelScope)
|
||||
|
||||
return sections
|
||||
}
|
||||
|
||||
private fun buildRoomsSections(
|
||||
sections: MutableList<RoomsSection>,
|
||||
activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>
|
||||
) {
|
||||
if (autoAcceptInvites.showInvites()) {
|
||||
addSection(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.invitations_header,
|
||||
notifyOfLocalEcho = true,
|
||||
spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
|
||||
countRoomAsNotif = true
|
||||
) {
|
||||
it.memberships = listOf(Membership.INVITE)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
}
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_favourites,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.bottom_action_rooms,
|
||||
notifyOfLocalEcho = false,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
}
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(false, false, false)
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.low_priority_header,
|
||||
notifyOfLocalEcho = false,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
}
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(null, true, null)
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.system_alerts_header,
|
||||
notifyOfLocalEcho = false,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
}
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(null, null, true)
|
||||
}
|
||||
|
||||
// add suggested rooms
|
||||
val suggestedRoomsFlow = // MutableLiveData<List<SpaceChildInfo>>()
|
||||
appStateHandler.selectedSpaceFlow
|
||||
.distinctUntilChanged()
|
||||
.flatMapLatest { selectedSpaceOption ->
|
||||
val selectedSpace = selectedSpaceOption.orNull()
|
||||
if (selectedSpace == null) {
|
||||
flowOf(emptyList())
|
||||
} else {
|
||||
liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
|
||||
val spaceSum = tryOrNull {
|
||||
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.
|
||||
val filtered = value.filter {
|
||||
session.getRoomSummary(it.childRoomId)?.membership?.isActive() != true
|
||||
}
|
||||
emit(filtered)
|
||||
}.asFlow()
|
||||
}
|
||||
}
|
||||
|
||||
val liveSuggestedRooms = MutableLiveData<SuggestedRoomInfo>()
|
||||
combine(
|
||||
suggestedRoomsFlow,
|
||||
suggestedRoomJoiningState.asFlow()
|
||||
) { rooms, joinStates ->
|
||||
SuggestedRoomInfo(
|
||||
rooms,
|
||||
joinStates
|
||||
)
|
||||
}.onEach {
|
||||
liveSuggestedRooms.postValue(it)
|
||||
}.launchIn(viewModelScope)
|
||||
|
||||
sections.add(
|
||||
RoomsSection(
|
||||
sectionName = stringProvider.getString(R.string.suggested_header),
|
||||
liveSuggested = liveSuggestedRooms,
|
||||
notifyOfLocalEcho = false,
|
||||
itemCount = suggestedRoomsFlow.map { suggestions -> suggestions.size }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildDmSections(
|
||||
sections: MutableList<RoomsSection>,
|
||||
activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>
|
||||
) {
|
||||
if (autoAcceptInvites.showInvites()) {
|
||||
addSection(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.invitations_header,
|
||||
notifyOfLocalEcho = true,
|
||||
spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
|
||||
countRoomAsNotif = true
|
||||
) {
|
||||
it.memberships = listOf(Membership.INVITE)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
}
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_favourites,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_people_x,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(false, false, null)
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.low_priority_header,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(false, true, null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildNotificationsSection(
|
||||
sections: MutableList<RoomsSection>,
|
||||
activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>
|
||||
) {
|
||||
if (autoAcceptInvites.showInvites()) {
|
||||
addSection(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.invitations_header,
|
||||
notifyOfLocalEcho = true,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
},
|
||||
countRoomAsNotif = true
|
||||
) {
|
||||
it.memberships = listOf(Membership.INVITE)
|
||||
}
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.bottom_action_rooms,
|
||||
notifyOfLocalEcho = false,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
}
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildFilteredSection(sections: MutableList<RoomsSection>) {
|
||||
// Used when searching for rooms
|
||||
withQueryParams(
|
||||
{
|
||||
it.memberships = Membership.activeMemberships()
|
||||
},
|
||||
{ queryParams ->
|
||||
val name = stringProvider.getString(R.string.bottom_action_rooms)
|
||||
val updatableFilterLivePageResult = session.roomService().getFilteredPagedRoomSummariesLive(queryParams, getFlattenParents = true)
|
||||
onUpdatable(updatableFilterLivePageResult)
|
||||
|
||||
val itemCountFlow = updatableFilterLivePageResult.livePagedList.asFlow()
|
||||
.flatMapLatest { session.roomService().getRoomCountLive(updatableFilterLivePageResult.queryParams).asFlow() }
|
||||
.distinctUntilChanged()
|
||||
|
||||
sections.add(
|
||||
RoomsSection(
|
||||
sectionName = name,
|
||||
livePages = updatableFilterLivePageResult.livePagedList,
|
||||
itemCount = itemCountFlow
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun addSection(
|
||||
sections: MutableList<RoomsSection>,
|
||||
activeSpaceUpdaters: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>,
|
||||
@StringRes nameRes: Int,
|
||||
notifyOfLocalEcho: Boolean = false,
|
||||
spaceFilterStrategy: RoomListViewModel.SpaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.NONE,
|
||||
countRoomAsNotif: Boolean = false,
|
||||
query: (RoomSummaryQueryParams.Builder) -> Unit
|
||||
) {
|
||||
withQueryParams(query) { roomQueryParams ->
|
||||
val updatedQueryParams = roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId())
|
||||
val liveQueryParams = MutableStateFlow(updatedQueryParams)
|
||||
val itemCountFlow = liveQueryParams
|
||||
.flatMapLatest {
|
||||
session.roomService().getRoomCountLive(it).asFlow()
|
||||
}
|
||||
.flowOn(Dispatchers.Main)
|
||||
.distinctUntilChanged()
|
||||
|
||||
val name = stringProvider.getString(nameRes)
|
||||
val filteredPagedRoomSummariesLive = session.roomService().getFilteredPagedRoomSummariesLive(
|
||||
roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId()),
|
||||
pagedListConfig
|
||||
)
|
||||
when (spaceFilterStrategy) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL -> {
|
||||
activeSpaceUpdaters.add(object : RoomListViewModel.ActiveSpaceQueryUpdater {
|
||||
override fun updateForSpaceId(roomId: String?) {
|
||||
filteredPagedRoomSummariesLive.queryParams = roomQueryParams.copy(
|
||||
spaceFilter = roomId?.toActiveSpaceOrOrphanRooms()
|
||||
)
|
||||
liveQueryParams.update { filteredPagedRoomSummariesLive.queryParams }
|
||||
}
|
||||
})
|
||||
}
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL -> {
|
||||
activeSpaceUpdaters.add(object : RoomListViewModel.ActiveSpaceQueryUpdater {
|
||||
override fun updateForSpaceId(roomId: String?) {
|
||||
if (roomId != null) {
|
||||
filteredPagedRoomSummariesLive.queryParams = roomQueryParams.copy(
|
||||
spaceFilter = SpaceFilter.ActiveSpace(roomId)
|
||||
)
|
||||
} else {
|
||||
filteredPagedRoomSummariesLive.queryParams = roomQueryParams.copy(
|
||||
spaceFilter = null
|
||||
)
|
||||
}
|
||||
liveQueryParams.update { filteredPagedRoomSummariesLive.queryParams }
|
||||
}
|
||||
})
|
||||
}
|
||||
RoomListViewModel.SpaceFilterStrategy.NONE -> {
|
||||
// we ignore current space for this one
|
||||
}
|
||||
}
|
||||
|
||||
val livePagedList = filteredPagedRoomSummariesLive.livePagedList
|
||||
// use it also as a source to update count
|
||||
livePagedList.asFlow()
|
||||
.onEach {
|
||||
Timber.v("Thread space list: ${Thread.currentThread()}")
|
||||
sections.find { it.sectionName == name }
|
||||
?.notificationCount
|
||||
?.postValue(
|
||||
if (countRoomAsNotif) {
|
||||
RoomAggregateNotificationCount(it.size, it.size)
|
||||
} else {
|
||||
session.roomService().getNotificationCountForRooms(
|
||||
roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId())
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
.flowOn(Dispatchers.Default)
|
||||
.launchIn(viewModelScope)
|
||||
|
||||
sections.add(
|
||||
RoomsSection(
|
||||
sectionName = name,
|
||||
livePages = livePagedList,
|
||||
notifyOfLocalEcho = notifyOfLocalEcho,
|
||||
itemCount = itemCountFlow
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun withQueryParams(builder: (RoomSummaryQueryParams.Builder) -> Unit, block: (RoomSummaryQueryParams) -> Unit) {
|
||||
block(roomSummaryQueryParams { builder.invoke(this) })
|
||||
}
|
||||
|
||||
internal fun RoomSummaryQueryParams.process(spaceFilter: RoomListViewModel.SpaceFilterStrategy, currentSpace: String?): RoomSummaryQueryParams {
|
||||
return when (spaceFilter) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL -> {
|
||||
copy(
|
||||
spaceFilter = currentSpace?.toActiveSpaceOrOrphanRooms()
|
||||
)
|
||||
}
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL -> {
|
||||
copy(
|
||||
spaceFilter = currentSpace?.let { SpaceFilter.ActiveSpace(it) }
|
||||
)
|
||||
}
|
||||
RoomListViewModel.SpaceFilterStrategy.NONE -> this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,290 +0,0 @@
|
|||
/*
|
||||
* 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.home.room.list
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.lifecycle.asFlow
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.R
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.home.RoomListDisplayMode
|
||||
import im.vector.app.features.invite.AutoAcceptInvites
|
||||
import im.vector.app.features.invite.showInvites
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import org.matrix.android.sdk.api.query.RoomCategoryFilter
|
||||
import org.matrix.android.sdk.api.query.RoomTagQueryFilter
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||
|
||||
class RoomListSectionBuilderGroup(
|
||||
private val coroutineScope: CoroutineScope,
|
||||
private val session: Session,
|
||||
private val stringProvider: StringProvider,
|
||||
private val appStateHandler: AppStateHandler,
|
||||
private val autoAcceptInvites: AutoAcceptInvites,
|
||||
private val onUpdatable: (UpdatableLivePageResult) -> Unit
|
||||
) : RoomListSectionBuilder {
|
||||
|
||||
override fun buildSections(mode: RoomListDisplayMode): List<RoomsSection> {
|
||||
val activeGroupAwareQueries = mutableListOf<UpdatableLivePageResult>()
|
||||
val sections = mutableListOf<RoomsSection>()
|
||||
val actualGroupId = appStateHandler.safeActiveGroupId()
|
||||
|
||||
when (mode) {
|
||||
RoomListDisplayMode.PEOPLE -> {
|
||||
// 4 sections Invites / Fav / Dms / Low Priority
|
||||
buildPeopleSections(sections, activeGroupAwareQueries, actualGroupId)
|
||||
}
|
||||
RoomListDisplayMode.ROOMS -> {
|
||||
// 5 sections invites / Fav / Rooms / Low Priority / Server notice
|
||||
buildRoomsSections(sections, activeGroupAwareQueries, actualGroupId)
|
||||
}
|
||||
RoomListDisplayMode.FILTERED -> {
|
||||
// Used when searching for rooms
|
||||
withQueryParams(
|
||||
{
|
||||
it.memberships = Membership.activeMemberships()
|
||||
},
|
||||
{ qpm ->
|
||||
val name = stringProvider.getString(R.string.bottom_action_rooms)
|
||||
val updatableFilterLivePageResult = session.roomService().getFilteredPagedRoomSummariesLive(qpm, getFlattenParents = true)
|
||||
onUpdatable(updatableFilterLivePageResult)
|
||||
|
||||
val itemCountFlow = updatableFilterLivePageResult.livePagedList.asFlow()
|
||||
.flatMapLatest { session.roomService().getRoomCountLive(updatableFilterLivePageResult.queryParams).asFlow() }
|
||||
.distinctUntilChanged()
|
||||
|
||||
sections.add(
|
||||
RoomsSection(
|
||||
sectionName = name,
|
||||
livePages = updatableFilterLivePageResult.livePagedList,
|
||||
itemCount = itemCountFlow
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
RoomListDisplayMode.NOTIFICATIONS -> {
|
||||
if (autoAcceptInvites.showInvites()) {
|
||||
addSection(
|
||||
sections,
|
||||
activeGroupAwareQueries,
|
||||
R.string.invitations_header,
|
||||
true
|
||||
) {
|
||||
it.memberships = listOf(Membership.INVITE)
|
||||
it.activeGroupId = actualGroupId
|
||||
}
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeGroupAwareQueries,
|
||||
R.string.bottom_action_rooms,
|
||||
false
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS
|
||||
it.activeGroupId = actualGroupId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
appStateHandler.selectedRoomGroupingFlow
|
||||
.distinctUntilChanged()
|
||||
.onEach { groupingMethod ->
|
||||
val selectedGroupId = (groupingMethod.orNull() as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary?.groupId
|
||||
activeGroupAwareQueries.onEach { updater ->
|
||||
updater.queryParams = updater.queryParams.copy(activeGroupId = selectedGroupId)
|
||||
}
|
||||
}.launchIn(coroutineScope)
|
||||
|
||||
return sections
|
||||
}
|
||||
|
||||
private fun buildRoomsSections(
|
||||
sections: MutableList<RoomsSection>,
|
||||
activeSpaceAwareQueries: MutableList<UpdatableLivePageResult>,
|
||||
actualGroupId: String?
|
||||
) {
|
||||
if (autoAcceptInvites.showInvites()) {
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.invitations_header,
|
||||
true
|
||||
) {
|
||||
it.memberships = listOf(Membership.INVITE)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
it.activeGroupId = actualGroupId
|
||||
}
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_favourites,
|
||||
false
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
|
||||
it.activeGroupId = actualGroupId
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_rooms,
|
||||
false
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(false, false, false)
|
||||
it.activeGroupId = actualGroupId
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.low_priority_header,
|
||||
false
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(null, true, null)
|
||||
it.activeGroupId = actualGroupId
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.system_alerts_header,
|
||||
false
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(null, null, true)
|
||||
it.activeGroupId = actualGroupId
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildPeopleSections(
|
||||
sections: MutableList<RoomsSection>,
|
||||
activeSpaceAwareQueries: MutableList<UpdatableLivePageResult>,
|
||||
actualGroupId: String?
|
||||
) {
|
||||
if (autoAcceptInvites.showInvites()) {
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.invitations_header,
|
||||
true
|
||||
) {
|
||||
it.memberships = listOf(Membership.INVITE)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
it.activeGroupId = actualGroupId
|
||||
}
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_favourites,
|
||||
false
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
|
||||
it.activeGroupId = actualGroupId
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_people_x,
|
||||
false
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(false, false, null)
|
||||
it.activeGroupId = actualGroupId
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.low_priority_header,
|
||||
false
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(false, true, null)
|
||||
it.activeGroupId = actualGroupId
|
||||
}
|
||||
}
|
||||
|
||||
private fun addSection(
|
||||
sections: MutableList<RoomsSection>,
|
||||
activeSpaceUpdaters: MutableList<UpdatableLivePageResult>,
|
||||
@StringRes nameRes: Int,
|
||||
notifyOfLocalEcho: Boolean = false,
|
||||
query: (RoomSummaryQueryParams.Builder) -> Unit
|
||||
) {
|
||||
withQueryParams(query) { roomQueryParams ->
|
||||
val name = stringProvider.getString(nameRes)
|
||||
session.roomService().getFilteredPagedRoomSummariesLive(roomQueryParams)
|
||||
.also {
|
||||
activeSpaceUpdaters.add(it)
|
||||
}.livePagedList
|
||||
.let { livePagedList ->
|
||||
// use it also as a source to update count
|
||||
livePagedList.asFlow()
|
||||
.onEach {
|
||||
sections.find { it.sectionName == name }
|
||||
?.notificationCount
|
||||
?.postValue(session.roomService().getNotificationCountForRooms(roomQueryParams))
|
||||
}
|
||||
.flowOn(Dispatchers.Default)
|
||||
.launchIn(coroutineScope)
|
||||
|
||||
sections.add(
|
||||
RoomsSection(
|
||||
sectionName = name,
|
||||
livePages = livePagedList,
|
||||
notifyOfLocalEcho = notifyOfLocalEcho,
|
||||
itemCount = session.roomService().getRoomCountLive(roomQueryParams).asFlow()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun withQueryParams(builder: (RoomSummaryQueryParams.Builder) -> Unit, block: (RoomSummaryQueryParams) -> Unit) {
|
||||
block(roomSummaryQueryParams { builder.invoke(this) })
|
||||
}
|
||||
}
|
|
@ -1,459 +0,0 @@
|
|||
/*
|
||||
* 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.home.room.list
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.asFlow
|
||||
import androidx.lifecycle.liveData
|
||||
import androidx.paging.PagedList
|
||||
import com.airbnb.mvrx.Async
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.home.RoomListDisplayMode
|
||||
import im.vector.app.features.invite.AutoAcceptInvites
|
||||
import im.vector.app.features.invite.showInvites
|
||||
import im.vector.app.space
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.update
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.query.RoomCategoryFilter
|
||||
import org.matrix.android.sdk.api.query.RoomTagQueryFilter
|
||||
import org.matrix.android.sdk.api.query.SpaceFilter
|
||||
import org.matrix.android.sdk.api.query.toActiveSpaceOrOrphanRooms
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.getRoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
||||
import timber.log.Timber
|
||||
|
||||
class RoomListSectionBuilderSpace(
|
||||
private val session: Session,
|
||||
private val stringProvider: StringProvider,
|
||||
private val appStateHandler: AppStateHandler,
|
||||
private val viewModelScope: CoroutineScope,
|
||||
private val autoAcceptInvites: AutoAcceptInvites,
|
||||
private val onUpdatable: (UpdatableLivePageResult) -> Unit,
|
||||
private val suggestedRoomJoiningState: LiveData<Map<String, Async<Unit>>>,
|
||||
private val onlyOrphansInHome: Boolean = false
|
||||
) : RoomListSectionBuilder {
|
||||
|
||||
private val pagedListConfig = PagedList.Config.Builder()
|
||||
.setPageSize(10)
|
||||
.setInitialLoadSizeHint(20)
|
||||
.setEnablePlaceholders(true)
|
||||
.setPrefetchDistance(10)
|
||||
.build()
|
||||
|
||||
override fun buildSections(mode: RoomListDisplayMode): List<RoomsSection> {
|
||||
val sections = mutableListOf<RoomsSection>()
|
||||
val activeSpaceAwareQueries = mutableListOf<RoomListViewModel.ActiveSpaceQueryUpdater>()
|
||||
when (mode) {
|
||||
RoomListDisplayMode.PEOPLE -> {
|
||||
// 4 sections Invites / Fav / Dms / Low Priority
|
||||
buildDmSections(sections, activeSpaceAwareQueries)
|
||||
}
|
||||
RoomListDisplayMode.ROOMS -> {
|
||||
// 6 sections invites / Fav / Rooms / Low Priority / Server notice / Suggested rooms
|
||||
buildRoomsSections(sections, activeSpaceAwareQueries)
|
||||
}
|
||||
RoomListDisplayMode.FILTERED -> {
|
||||
// Used when searching for rooms
|
||||
buildFilteredSection(sections)
|
||||
}
|
||||
RoomListDisplayMode.NOTIFICATIONS -> {
|
||||
buildNotificationsSection(sections, activeSpaceAwareQueries)
|
||||
}
|
||||
}
|
||||
|
||||
appStateHandler.selectedRoomGroupingFlow
|
||||
.distinctUntilChanged()
|
||||
.onEach { groupingMethod ->
|
||||
val selectedSpace = groupingMethod.orNull()?.space()
|
||||
activeSpaceAwareQueries.onEach { updater ->
|
||||
updater.updateForSpaceId(selectedSpace?.roomId)
|
||||
}
|
||||
}.launchIn(viewModelScope)
|
||||
|
||||
return sections
|
||||
}
|
||||
|
||||
private fun buildRoomsSections(
|
||||
sections: MutableList<RoomsSection>,
|
||||
activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>
|
||||
) {
|
||||
if (autoAcceptInvites.showInvites()) {
|
||||
addSection(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.invitations_header,
|
||||
notifyOfLocalEcho = true,
|
||||
spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
|
||||
countRoomAsNotif = true
|
||||
) {
|
||||
it.memberships = listOf(Membership.INVITE)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
}
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_favourites,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.bottom_action_rooms,
|
||||
notifyOfLocalEcho = false,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
}
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(false, false, false)
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.low_priority_header,
|
||||
notifyOfLocalEcho = false,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
}
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(null, true, null)
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.system_alerts_header,
|
||||
notifyOfLocalEcho = false,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
}
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(null, null, true)
|
||||
}
|
||||
|
||||
// add suggested rooms
|
||||
val suggestedRoomsFlow = // MutableLiveData<List<SpaceChildInfo>>()
|
||||
appStateHandler.selectedRoomGroupingFlow
|
||||
.distinctUntilChanged()
|
||||
.flatMapLatest { groupingMethod ->
|
||||
val selectedSpace = groupingMethod.orNull()?.space()
|
||||
if (selectedSpace == null) {
|
||||
flowOf(emptyList())
|
||||
} else {
|
||||
liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
|
||||
val spaceSum = tryOrNull {
|
||||
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.
|
||||
val filtered = value.filter {
|
||||
session.getRoomSummary(it.childRoomId)?.membership?.isActive() != true
|
||||
}
|
||||
emit(filtered)
|
||||
}.asFlow()
|
||||
}
|
||||
}
|
||||
|
||||
val liveSuggestedRooms = MutableLiveData<SuggestedRoomInfo>()
|
||||
combine(
|
||||
suggestedRoomsFlow,
|
||||
suggestedRoomJoiningState.asFlow()
|
||||
) { rooms, joinStates ->
|
||||
SuggestedRoomInfo(
|
||||
rooms,
|
||||
joinStates
|
||||
)
|
||||
}.onEach {
|
||||
liveSuggestedRooms.postValue(it)
|
||||
}.launchIn(viewModelScope)
|
||||
|
||||
sections.add(
|
||||
RoomsSection(
|
||||
sectionName = stringProvider.getString(R.string.suggested_header),
|
||||
liveSuggested = liveSuggestedRooms,
|
||||
notifyOfLocalEcho = false,
|
||||
itemCount = suggestedRoomsFlow.map { suggestions -> suggestions.size }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildDmSections(
|
||||
sections: MutableList<RoomsSection>,
|
||||
activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>
|
||||
) {
|
||||
if (autoAcceptInvites.showInvites()) {
|
||||
addSection(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.invitations_header,
|
||||
notifyOfLocalEcho = true,
|
||||
spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
|
||||
countRoomAsNotif = true
|
||||
) {
|
||||
it.memberships = listOf(Membership.INVITE)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
}
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_favourites,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_people_x,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(false, false, null)
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.low_priority_header,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(false, true, null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildNotificationsSection(
|
||||
sections: MutableList<RoomsSection>,
|
||||
activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>
|
||||
) {
|
||||
if (autoAcceptInvites.showInvites()) {
|
||||
addSection(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.invitations_header,
|
||||
notifyOfLocalEcho = true,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
},
|
||||
countRoomAsNotif = true
|
||||
) {
|
||||
it.memberships = listOf(Membership.INVITE)
|
||||
}
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.bottom_action_rooms,
|
||||
notifyOfLocalEcho = false,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
}
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildFilteredSection(sections: MutableList<RoomsSection>) {
|
||||
// Used when searching for rooms
|
||||
withQueryParams(
|
||||
{
|
||||
it.memberships = Membership.activeMemberships()
|
||||
},
|
||||
{ queryParams ->
|
||||
val name = stringProvider.getString(R.string.bottom_action_rooms)
|
||||
val updatableFilterLivePageResult = session.roomService().getFilteredPagedRoomSummariesLive(queryParams, getFlattenParents = true)
|
||||
onUpdatable(updatableFilterLivePageResult)
|
||||
|
||||
val itemCountFlow = updatableFilterLivePageResult.livePagedList.asFlow()
|
||||
.flatMapLatest { session.roomService().getRoomCountLive(updatableFilterLivePageResult.queryParams).asFlow() }
|
||||
.distinctUntilChanged()
|
||||
|
||||
sections.add(
|
||||
RoomsSection(
|
||||
sectionName = name,
|
||||
livePages = updatableFilterLivePageResult.livePagedList,
|
||||
itemCount = itemCountFlow
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun addSection(
|
||||
sections: MutableList<RoomsSection>,
|
||||
activeSpaceUpdaters: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>,
|
||||
@StringRes nameRes: Int,
|
||||
notifyOfLocalEcho: Boolean = false,
|
||||
spaceFilterStrategy: RoomListViewModel.SpaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.NONE,
|
||||
countRoomAsNotif: Boolean = false,
|
||||
query: (RoomSummaryQueryParams.Builder) -> Unit
|
||||
) {
|
||||
withQueryParams(query) { roomQueryParams ->
|
||||
val updatedQueryParams = roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId())
|
||||
val liveQueryParams = MutableStateFlow(updatedQueryParams)
|
||||
val itemCountFlow = liveQueryParams
|
||||
.flatMapLatest {
|
||||
session.roomService().getRoomCountLive(it).asFlow()
|
||||
}
|
||||
.flowOn(Dispatchers.Main)
|
||||
.distinctUntilChanged()
|
||||
|
||||
val name = stringProvider.getString(nameRes)
|
||||
val filteredPagedRoomSummariesLive = session.roomService().getFilteredPagedRoomSummariesLive(
|
||||
roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId()),
|
||||
pagedListConfig
|
||||
)
|
||||
when (spaceFilterStrategy) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL -> {
|
||||
activeSpaceUpdaters.add(object : RoomListViewModel.ActiveSpaceQueryUpdater {
|
||||
override fun updateForSpaceId(roomId: String?) {
|
||||
filteredPagedRoomSummariesLive.queryParams = roomQueryParams.copy(
|
||||
spaceFilter = roomId.toActiveSpaceOrOrphanRooms()
|
||||
)
|
||||
liveQueryParams.update { filteredPagedRoomSummariesLive.queryParams }
|
||||
}
|
||||
})
|
||||
}
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL -> {
|
||||
activeSpaceUpdaters.add(object : RoomListViewModel.ActiveSpaceQueryUpdater {
|
||||
override fun updateForSpaceId(roomId: String?) {
|
||||
if (roomId != null) {
|
||||
filteredPagedRoomSummariesLive.queryParams = roomQueryParams.copy(
|
||||
spaceFilter = SpaceFilter.ActiveSpace(roomId)
|
||||
)
|
||||
} else {
|
||||
filteredPagedRoomSummariesLive.queryParams = roomQueryParams.copy(
|
||||
spaceFilter = null
|
||||
)
|
||||
}
|
||||
liveQueryParams.update { filteredPagedRoomSummariesLive.queryParams }
|
||||
}
|
||||
})
|
||||
}
|
||||
RoomListViewModel.SpaceFilterStrategy.NONE -> {
|
||||
// we ignore current space for this one
|
||||
}
|
||||
}
|
||||
|
||||
val livePagedList = filteredPagedRoomSummariesLive.livePagedList
|
||||
// use it also as a source to update count
|
||||
livePagedList.asFlow()
|
||||
.onEach {
|
||||
Timber.v("Thread space list: ${Thread.currentThread()}")
|
||||
sections.find { it.sectionName == name }
|
||||
?.notificationCount
|
||||
?.postValue(
|
||||
if (countRoomAsNotif) {
|
||||
RoomAggregateNotificationCount(it.size, it.size)
|
||||
} else {
|
||||
session.roomService().getNotificationCountForRooms(
|
||||
roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId())
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
.flowOn(Dispatchers.Default)
|
||||
.launchIn(viewModelScope)
|
||||
|
||||
sections.add(
|
||||
RoomsSection(
|
||||
sectionName = name,
|
||||
livePages = livePagedList,
|
||||
notifyOfLocalEcho = notifyOfLocalEcho,
|
||||
itemCount = itemCountFlow
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun withQueryParams(builder: (RoomSummaryQueryParams.Builder) -> Unit, block: (RoomSummaryQueryParams) -> Unit) {
|
||||
block(roomSummaryQueryParams { builder.invoke(this) })
|
||||
}
|
||||
|
||||
internal fun RoomSummaryQueryParams.process(spaceFilter: RoomListViewModel.SpaceFilterStrategy, currentSpace: String?): RoomSummaryQueryParams {
|
||||
return when (spaceFilter) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL -> {
|
||||
copy(
|
||||
spaceFilter = currentSpace.toActiveSpaceOrOrphanRooms()
|
||||
)
|
||||
}
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL -> {
|
||||
copy(
|
||||
spaceFilter = currentSpace?.let { SpaceFilter.ActiveSpace(it) }
|
||||
)
|
||||
}
|
||||
RoomListViewModel.SpaceFilterStrategy.NONE -> this
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,7 +26,6 @@ import dagger.assisted.Assisted
|
|||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
|
@ -101,11 +100,11 @@ class RoomListViewModel @AssistedInject constructor(
|
|||
observeMembershipChanges()
|
||||
observeLocalRooms()
|
||||
|
||||
appStateHandler.selectedRoomGroupingFlow
|
||||
appStateHandler.selectedSpaceFlow
|
||||
.distinctUntilChanged()
|
||||
.execute {
|
||||
copy(
|
||||
currentRoomGrouping = it.invoke()?.orNull()?.let { Success(it) } ?: Loading()
|
||||
asyncSelectedSpace = it.invoke()?.orNull()?.let { Success(it) } ?: Loading()
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -146,8 +145,7 @@ class RoomListViewModel @AssistedInject constructor(
|
|||
|
||||
companion object : MavericksViewModelFactory<RoomListViewModel, RoomListViewState> by hiltMavericksViewModelFactory()
|
||||
|
||||
private val roomListSectionBuilder = if (appStateHandler.getCurrentRoomGroupingMethod() is RoomGroupingMethod.BySpace) {
|
||||
RoomListSectionBuilderSpace(
|
||||
private val roomListSectionBuilder = RoomListSectionBuilder(
|
||||
session,
|
||||
stringProvider,
|
||||
appStateHandler,
|
||||
|
@ -159,17 +157,6 @@ class RoomListViewModel @AssistedInject constructor(
|
|||
suggestedRoomJoiningState,
|
||||
!vectorPreferences.prefSpacesShowAllRoomInHome()
|
||||
)
|
||||
} else {
|
||||
RoomListSectionBuilderGroup(
|
||||
viewModelScope,
|
||||
session,
|
||||
stringProvider,
|
||||
appStateHandler,
|
||||
autoAcceptInvites
|
||||
) {
|
||||
updatableQuery = it
|
||||
}
|
||||
}
|
||||
|
||||
val sections: List<RoomsSection> by lazy {
|
||||
roomListSectionBuilder.buildSections(initialState.displayMode)
|
||||
|
|
|
@ -19,9 +19,9 @@ package im.vector.app.features.home.room.list
|
|||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MavericksState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import im.vector.app.features.home.RoomListDisplayMode
|
||||
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.SpaceChildInfo
|
||||
|
||||
data class RoomListViewState(
|
||||
|
@ -30,7 +30,7 @@ data class RoomListViewState(
|
|||
val roomMembershipChanges: Map<String, ChangeMembershipState> = emptyMap(),
|
||||
val asyncSuggestedRooms: Async<List<SpaceChildInfo>> = Uninitialized,
|
||||
val currentUserName: String? = null,
|
||||
val currentRoomGrouping: Async<RoomGroupingMethod> = Uninitialized,
|
||||
val asyncSelectedSpace: Async<RoomSummary?> = Uninitialized,
|
||||
val localRoomIds: Set<String> = emptySet()
|
||||
) : MavericksState {
|
||||
|
||||
|
|
|
@ -94,7 +94,6 @@ class PillsPostProcessor @AssistedInject constructor(
|
|||
val matrixItem = when (val permalinkData = PermalinkParser.parse(url)) {
|
||||
is PermalinkData.UserLink -> permalinkData.toMatrixItem(roomId)
|
||||
is PermalinkData.RoomLink -> permalinkData.toMatrixItem()
|
||||
is PermalinkData.GroupLink -> permalinkData.toMatrixItem()
|
||||
else -> null
|
||||
} ?: return null
|
||||
return createPillImageSpan(matrixItem)
|
||||
|
@ -118,9 +117,4 @@ class PillsPostProcessor @AssistedInject constructor(
|
|||
// Exclude event link (used in reply events, we do not want to pill the "in reply to")
|
||||
null
|
||||
}
|
||||
|
||||
private fun PermalinkData.GroupLink.toMatrixItem(): MatrixItem? {
|
||||
val group = sessionHolder.getSafeActiveSession()?.groupService()?.getGroupSummary(groupId)
|
||||
return MatrixItem.GroupItem(groupId, group?.displayName, group?.avatarUrl)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,8 +75,7 @@ class MatrixToBottomSheet :
|
|||
views.matrixToCardContentLoading.isVisible = state.matrixItem is Incomplete
|
||||
showFragment(MatrixToUserFragment::class, Bundle())
|
||||
}
|
||||
is PermalinkData.GroupLink -> Unit
|
||||
is PermalinkData.FallbackLink -> Unit
|
||||
is PermalinkData.FallbackLink,
|
||||
is PermalinkData.RoomEmailInviteLink -> Unit
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,13 +76,8 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor(
|
|||
copy(matrixItem = Loading())
|
||||
}
|
||||
}
|
||||
is PermalinkData.GroupLink -> {
|
||||
// Not yet supported
|
||||
}
|
||||
is PermalinkData.FallbackLink -> {
|
||||
// Not yet supported
|
||||
}
|
||||
is PermalinkData.RoomEmailInviteLink -> Unit
|
||||
is PermalinkData.RoomEmailInviteLink,
|
||||
is PermalinkData.FallbackLink -> Unit
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
resolveLink(initialState)
|
||||
|
@ -186,10 +181,6 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
is PermalinkData.GroupLink -> {
|
||||
// not yet supported
|
||||
_viewEvents.post(MatrixToViewEvents.Dismiss)
|
||||
}
|
||||
is PermalinkData.RoomEmailInviteLink,
|
||||
is PermalinkData.FallbackLink -> {
|
||||
_viewEvents.post(MatrixToViewEvents.Dismiss)
|
||||
|
|
|
@ -23,6 +23,7 @@ import android.net.Uri
|
|||
import android.os.Build
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityOptionsCompat
|
||||
|
@ -32,11 +33,8 @@ import androidx.core.view.ViewCompat
|
|||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.R
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.error.fatalError
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.features.VectorFeatures
|
||||
import im.vector.app.features.VectorFeatures.OnboardingVariant
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
|
@ -105,11 +103,11 @@ import im.vector.app.features.spaces.people.SpacePeopleActivity
|
|||
import im.vector.app.features.terms.ReviewTermsActivity
|
||||
import im.vector.app.features.widgets.WidgetActivity
|
||||
import im.vector.app.features.widgets.WidgetArgsBuilder
|
||||
import im.vector.app.space
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.IncomingSasVerificationTransaction
|
||||
import org.matrix.android.sdk.api.session.getRoom
|
||||
import org.matrix.android.sdk.api.session.getRoomSummary
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkData
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
||||
import org.matrix.android.sdk.api.session.terms.TermsService
|
||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||
|
@ -169,7 +167,7 @@ class DefaultNavigator @Inject constructor(
|
|||
analyticsTracker.capture(
|
||||
sessionHolder.getActiveSession().getRoomSummary(roomId).toAnalyticsViewRoom(
|
||||
trigger = trigger,
|
||||
groupingMethod = appStateHandler.getCurrentRoomGroupingMethod()
|
||||
selectedSpace = appStateHandler.getCurrentSpace()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -284,14 +282,6 @@ class DefaultNavigator @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun openGroupDetail(groupId: String, context: Context, buildTask: Boolean) {
|
||||
if (context is VectorBaseActivity<*>) {
|
||||
context.notImplemented("Open group detail")
|
||||
} else {
|
||||
context.toast(R.string.not_implemented)
|
||||
}
|
||||
}
|
||||
|
||||
override fun openRoomMemberProfile(userId: String, roomId: String?, context: Context, buildTask: Boolean) {
|
||||
val args = RoomMemberProfileArgs(userId = userId, roomId = roomId)
|
||||
val intent = RoomMemberProfileActivity.newIntent(context, args)
|
||||
|
@ -328,25 +318,10 @@ class DefaultNavigator @Inject constructor(
|
|||
}
|
||||
|
||||
override fun openRoomDirectory(context: Context, initialFilter: String) {
|
||||
when (val groupingMethod = appStateHandler.getCurrentRoomGroupingMethod()) {
|
||||
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||
// TODO should open list of rooms of this group
|
||||
val intent = RoomDirectoryActivity.getIntent(context, initialFilter)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
is RoomGroupingMethod.BySpace -> {
|
||||
val selectedSpace = groupingMethod.space()
|
||||
if (selectedSpace == null) {
|
||||
val intent = RoomDirectoryActivity.getIntent(context, initialFilter)
|
||||
context.startActivity(intent)
|
||||
} else {
|
||||
SpaceExploreActivity.newIntent(context, selectedSpace.roomId).let {
|
||||
context.startActivity(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
null -> Unit
|
||||
}
|
||||
when (val currentSpace = appStateHandler.getCurrentSpace()) {
|
||||
null -> RoomDirectoryActivity.getIntent(context, initialFilter)
|
||||
else -> SpaceExploreActivity.newIntent(context, currentSpace.roomId)
|
||||
}.start(context)
|
||||
}
|
||||
|
||||
override fun openCreateRoom(context: Context, initialName: String, openAfterCreate: Boolean) {
|
||||
|
@ -355,55 +330,25 @@ class DefaultNavigator @Inject constructor(
|
|||
}
|
||||
|
||||
override fun openCreateDirectRoom(context: Context) {
|
||||
val intent = when (val currentGroupingMethod = appStateHandler.getCurrentRoomGroupingMethod()) {
|
||||
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||
CreateDirectRoomActivity.getIntent(context)
|
||||
}
|
||||
is RoomGroupingMethod.BySpace -> {
|
||||
if (currentGroupingMethod.spaceSummary != null) {
|
||||
SpacePeopleActivity.newIntent(context, currentGroupingMethod.spaceSummary.roomId)
|
||||
} else {
|
||||
CreateDirectRoomActivity.getIntent(context)
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
} ?: return
|
||||
context.startActivity(intent)
|
||||
when (val currentSpace = appStateHandler.getCurrentSpace()) {
|
||||
null -> CreateDirectRoomActivity.getIntent(context)
|
||||
else -> SpacePeopleActivity.newIntent(context, currentSpace.roomId)
|
||||
}.start(context)
|
||||
}
|
||||
|
||||
override fun openInviteUsersToRoom(context: Context, roomId: String) {
|
||||
when (val currentGroupingMethod = appStateHandler.getCurrentRoomGroupingMethod()) {
|
||||
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||
val intent = InviteUsersToRoomActivity.getIntent(context, roomId)
|
||||
context.startActivity(intent)
|
||||
when (val currentSpace = appStateHandler.getCurrentSpace()) {
|
||||
null -> InviteUsersToRoomActivity.getIntent(context, roomId).start(context)
|
||||
else -> showInviteToDialog(context, currentSpace, roomId)
|
||||
}
|
||||
is RoomGroupingMethod.BySpace -> {
|
||||
if (currentGroupingMethod.spaceSummary != null) {
|
||||
// let user decides if he does it from space or room
|
||||
(context as? AppCompatActivity)?.supportFragmentManager?.let { fm ->
|
||||
InviteRoomSpaceChooserBottomSheet.newInstance(
|
||||
currentGroupingMethod.spaceSummary.roomId,
|
||||
roomId,
|
||||
object : InviteRoomSpaceChooserBottomSheet.InteractionListener {
|
||||
override fun inviteToSpace(spaceId: String) {
|
||||
val intent = InviteUsersToRoomActivity.getIntent(context, spaceId)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
override fun inviteToRoom(roomId: String) {
|
||||
val intent = InviteUsersToRoomActivity.getIntent(context, roomId)
|
||||
context.startActivity(intent)
|
||||
private fun showInviteToDialog(context: Context, currentSpace: RoomSummary, roomId: String) {
|
||||
(context as? AppCompatActivity)?.supportFragmentManager?.let { fragmentManager ->
|
||||
InviteRoomSpaceChooserBottomSheet.showInstance(fragmentManager, currentSpace.roomId, roomId) { itemId ->
|
||||
InviteUsersToRoomActivity.getIntent(context, itemId).start(context)
|
||||
}
|
||||
}
|
||||
).show(fm, InviteRoomSpaceChooserBottomSheet::class.java.name)
|
||||
}
|
||||
} else {
|
||||
val intent = InviteUsersToRoomActivity.getIntent(context, roomId)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
null -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
override fun openRoomsFiltering(context: Context) {
|
||||
|
@ -449,6 +394,10 @@ class DefaultNavigator @Inject constructor(
|
|||
context.startActivity(KeysBackupManageActivity.intent(context))
|
||||
}
|
||||
|
||||
override fun showGroupsUnsupportedWarning(context: Context) {
|
||||
Toast.makeText(context, context.getString(R.string.permalink_unsupported_groups), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
override fun openRoomProfile(context: Context, roomId: String, directAccess: Int?) {
|
||||
context.startActivity(RoomProfileActivity.newIntent(context, roomId, directAccess))
|
||||
}
|
||||
|
@ -658,4 +607,8 @@ class DefaultNavigator @Inject constructor(
|
|||
) {
|
||||
activityResultLauncher.launch(screenCaptureIntent)
|
||||
}
|
||||
|
||||
private fun Intent.start(context: Context) {
|
||||
context.startActivity(this)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ interface Navigator {
|
|||
|
||||
fun openKeysBackupManager(context: Context)
|
||||
|
||||
fun openGroupDetail(groupId: String, context: Context, buildTask: Boolean = false)
|
||||
fun showGroupsUnsupportedWarning(context: Context)
|
||||
|
||||
fun openRoomMemberProfile(userId: String, roomId: String?, context: Context, buildTask: Boolean = false)
|
||||
|
||||
|
|
|
@ -90,7 +90,20 @@ class PermalinkHandler @Inject constructor(
|
|||
buildTask: Boolean
|
||||
): Boolean {
|
||||
return when (permalinkData) {
|
||||
is PermalinkData.RoomLink -> {
|
||||
is PermalinkData.RoomLink -> handleRoomLink(permalinkData, rawLink, context, navigationInterceptor, buildTask)
|
||||
is PermalinkData.UserLink -> handleUserLink(permalinkData, rawLink, context, navigationInterceptor, buildTask)
|
||||
is PermalinkData.FallbackLink -> handleFallbackLink(permalinkData, context)
|
||||
is PermalinkData.RoomEmailInviteLink -> handleRoomInviteLink(permalinkData, context)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun handleRoomLink(
|
||||
permalinkData: PermalinkData.RoomLink,
|
||||
rawLink: Uri,
|
||||
context: Context,
|
||||
navigationInterceptor: NavigationInterceptor?,
|
||||
buildTask: Boolean
|
||||
): Boolean {
|
||||
val roomId = permalinkData.getRoomId()
|
||||
val session = activeSessionHolder.getSafeActiveSession()
|
||||
|
||||
|
@ -113,22 +126,26 @@ class PermalinkHandler @Inject constructor(
|
|||
buildTask = buildTask,
|
||||
rootThreadEventId = rootThreadEventId
|
||||
)
|
||||
true
|
||||
return true
|
||||
}
|
||||
is PermalinkData.GroupLink -> {
|
||||
navigator.openGroupDetail(permalinkData.groupId, context, buildTask)
|
||||
true
|
||||
}
|
||||
is PermalinkData.UserLink -> {
|
||||
|
||||
private fun handleUserLink(
|
||||
permalinkData: PermalinkData.UserLink,
|
||||
rawLink: Uri,
|
||||
context: Context,
|
||||
navigationInterceptor: NavigationInterceptor?,
|
||||
buildTask: Boolean
|
||||
): Boolean {
|
||||
if (navigationInterceptor?.navToMemberProfile(permalinkData.userId, rawLink) != true) {
|
||||
navigator.openRoomMemberProfile(userId = permalinkData.userId, roomId = null, context = context, buildTask = buildTask)
|
||||
}
|
||||
true
|
||||
return true
|
||||
}
|
||||
is PermalinkData.FallbackLink -> {
|
||||
false
|
||||
}
|
||||
is PermalinkData.RoomEmailInviteLink -> {
|
||||
|
||||
private fun handleRoomInviteLink(
|
||||
permalinkData: PermalinkData.RoomEmailInviteLink,
|
||||
context: Context
|
||||
): Boolean {
|
||||
val data = RoomPreviewData(
|
||||
roomId = permalinkData.roomId,
|
||||
roomName = permalinkData.roomName,
|
||||
|
@ -137,8 +154,20 @@ class PermalinkHandler @Inject constructor(
|
|||
roomType = permalinkData.roomType
|
||||
)
|
||||
navigator.openRoomPreview(context, data)
|
||||
true
|
||||
return true
|
||||
}
|
||||
|
||||
private suspend fun handleFallbackLink(
|
||||
permalinkData: PermalinkData.FallbackLink,
|
||||
context: Context
|
||||
): Boolean {
|
||||
return if (permalinkData.isLegacyGroupLink) {
|
||||
withContext(Dispatchers.Main) {
|
||||
navigator.showGroupsUnsupportedWarning(context)
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import com.airbnb.mvrx.args
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import im.vector.app.R
|
||||
|
@ -47,12 +48,7 @@ class InviteRoomSpaceChooserBottomSheet : VectorBaseBottomSheetDialogFragment<Bo
|
|||
@Inject
|
||||
lateinit var activeSessionHolder: ActiveSessionHolder
|
||||
|
||||
interface InteractionListener {
|
||||
fun inviteToSpace(spaceId: String)
|
||||
fun inviteToRoom(roomId: String)
|
||||
}
|
||||
|
||||
var interactionListener: InteractionListener? = null
|
||||
var onItemSelected: ((roomId: String) -> Unit)? = null
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetSpaceInviteChooserBinding {
|
||||
return BottomSheetSpaceInviteChooserBinding.inflate(inflater, container, false)
|
||||
|
@ -72,7 +68,7 @@ class InviteRoomSpaceChooserBottomSheet : VectorBaseBottomSheetDialogFragment<Bo
|
|||
views.inviteToSpaceButton.subTitle = getString(R.string.invite_to_space_with_name_desc, spaceName)
|
||||
views.inviteToSpaceButton.debouncedClicks {
|
||||
dismiss()
|
||||
interactionListener?.inviteToSpace(inviteArgs.spaceId)
|
||||
onItemSelected?.invoke(inviteArgs.spaceId)
|
||||
}
|
||||
|
||||
views.inviteToRoomOnly.isVisible = true
|
||||
|
@ -80,17 +76,21 @@ class InviteRoomSpaceChooserBottomSheet : VectorBaseBottomSheetDialogFragment<Bo
|
|||
views.inviteToRoomOnly.subTitle = getString(R.string.invite_just_to_this_room_desc, spaceName)
|
||||
views.inviteToRoomOnly.debouncedClicks {
|
||||
dismiss()
|
||||
interactionListener?.inviteToRoom(inviteArgs.roomId)
|
||||
onItemSelected?.invoke(inviteArgs.roomId)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance(spaceId: String, roomId: String, interactionListener: InteractionListener): InviteRoomSpaceChooserBottomSheet {
|
||||
return InviteRoomSpaceChooserBottomSheet().apply {
|
||||
this.interactionListener = interactionListener
|
||||
fun showInstance(
|
||||
fragmentManager: FragmentManager,
|
||||
spaceId: String,
|
||||
roomId: String,
|
||||
onItemSelected: (roomId: String) -> Unit
|
||||
) {
|
||||
InviteRoomSpaceChooserBottomSheet().apply {
|
||||
this.onItemSelected = onItemSelected
|
||||
setArguments(Args(spaceId, roomId))
|
||||
}
|
||||
}.show(fragmentManager, InviteRoomSpaceChooserBottomSheet::class.java.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package im.vector.app.features.spaces
|
||||
|
||||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
|
||||
sealed class SpaceListAction : VectorViewModelAction {
|
||||
|
@ -29,6 +28,4 @@ sealed class SpaceListAction : VectorViewModelAction {
|
|||
data class MoveSpace(val spaceId: String, val delta: Int) : SpaceListAction()
|
||||
data class OnStartDragging(val spaceId: String, val expanded: Boolean) : SpaceListAction()
|
||||
data class OnEndDragging(val spaceId: String, val expanded: Boolean) : SpaceListAction()
|
||||
|
||||
data class SelectLegacyGroup(val groupSummary: GroupSummary?) : SpaceListAction()
|
||||
}
|
||||
|
|
|
@ -34,7 +34,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 org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -76,19 +75,16 @@ class SpaceListFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onDragReleased(model: SpaceSummaryItem?, itemView: View?) {
|
||||
// Timber.v("VAL: onModelMoved from $fromPositionM to $toPositionM ${model?.matrixItem?.getBestName()}")
|
||||
if (toPositionM == null || fromPositionM == null) return
|
||||
val movingSpace = model?.matrixItem?.id ?: return
|
||||
viewModel.handle(SpaceListAction.MoveSpace(movingSpace, toPositionM!! - fromPositionM!!))
|
||||
}
|
||||
|
||||
override fun clearView(model: SpaceSummaryItem?, itemView: View?) {
|
||||
// Timber.v("VAL: clearView ${model?.matrixItem?.getBestName()}")
|
||||
itemView?.elevation = initialElevation ?: 0f
|
||||
}
|
||||
|
||||
override fun onModelMoved(fromPosition: Int, toPosition: Int, modelBeingMoved: SpaceSummaryItem?, itemView: View?) {
|
||||
// Timber.v("VAL: onModelMoved incremental from $fromPosition to $toPosition ${modelBeingMoved?.matrixItem?.getBestName()}")
|
||||
if (fromPositionM == null) {
|
||||
fromPositionM = fromPosition
|
||||
}
|
||||
|
@ -97,7 +93,6 @@ class SpaceListFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun isDragEnabledForModel(model: SpaceSummaryItem?): Boolean {
|
||||
// Timber.v("VAL: isDragEnabledForModel ${model?.matrixItem?.getBestName()}")
|
||||
return model?.canDrag == true
|
||||
}
|
||||
})
|
||||
|
@ -105,10 +100,9 @@ class SpaceListFragment @Inject constructor(
|
|||
viewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is SpaceListViewEvents.OpenSpaceSummary -> sharedActionViewModel.post(HomeActivitySharedAction.OpenSpacePreview(it.id))
|
||||
is SpaceListViewEvents.OpenSpace -> sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup(it.groupingMethodHasChanged))
|
||||
is SpaceListViewEvents.AddSpace -> sharedActionViewModel.post(HomeActivitySharedAction.AddSpace)
|
||||
is SpaceListViewEvents.OpenGroup -> sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup(it.groupingMethodHasChanged))
|
||||
is SpaceListViewEvents.OpenSpaceInvite -> sharedActionViewModel.post(HomeActivitySharedAction.OpenSpaceInvite(it.id))
|
||||
SpaceListViewEvents.CloseDrawer -> sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -149,10 +143,6 @@ class SpaceListFragment @Inject constructor(
|
|||
viewModel.handle(SpaceListAction.AddSpace)
|
||||
}
|
||||
|
||||
override fun onGroupSelected(groupSummary: GroupSummary?) {
|
||||
viewModel.handle(SpaceListAction.SelectLegacyGroup(groupSummary))
|
||||
}
|
||||
|
||||
override fun sendFeedBack() {
|
||||
sharedActionViewModel.post(HomeActivitySharedAction.SendSpaceFeedBack)
|
||||
}
|
||||
|
|
|
@ -22,9 +22,8 @@ import im.vector.app.core.platform.VectorViewEvents
|
|||
* Transient events for group list screen.
|
||||
*/
|
||||
sealed class SpaceListViewEvents : VectorViewEvents {
|
||||
data class OpenSpace(val groupingMethodHasChanged: Boolean) : SpaceListViewEvents()
|
||||
data class OpenSpaceSummary(val id: String) : SpaceListViewEvents()
|
||||
data class OpenSpaceInvite(val id: String) : SpaceListViewEvents()
|
||||
object AddSpace : SpaceListViewEvents()
|
||||
data class OpenGroup(val groupingMethodHasChanged: Boolean) : SpaceListViewEvents()
|
||||
object CloseDrawer : SpaceListViewEvents()
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import dagger.assisted.Assisted
|
|||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
|
@ -33,8 +32,6 @@ import im.vector.app.features.analytics.plan.Interaction
|
|||
import im.vector.app.features.invite.AutoAcceptInvites
|
||||
import im.vector.app.features.session.coroutineScope
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import im.vector.app.group
|
||||
import im.vector.app.space
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
|
@ -50,7 +47,6 @@ import org.matrix.android.sdk.api.session.Session
|
|||
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.getRoom
|
||||
import org.matrix.android.sdk.api.session.group.groupSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.RoomSortOrder
|
||||
import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataTypes
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
|
@ -79,10 +75,7 @@ class SpaceListViewModel @AssistedInject constructor(
|
|||
|
||||
companion object : MavericksViewModelFactory<SpaceListViewModel, SpaceListViewState> by hiltMavericksViewModelFactory()
|
||||
|
||||
// private var currentGroupingMethod : RoomGroupingMethod? = null
|
||||
|
||||
init {
|
||||
|
||||
session.userService().getUserLive(session.myUserId)
|
||||
.asFlow()
|
||||
.setOnEach {
|
||||
|
@ -93,20 +86,14 @@ class SpaceListViewModel @AssistedInject constructor(
|
|||
|
||||
observeSpaceSummaries()
|
||||
// observeSelectionState()
|
||||
appStateHandler.selectedRoomGroupingFlow
|
||||
appStateHandler.selectedSpaceFlow
|
||||
.distinctUntilChanged()
|
||||
.setOnEach {
|
||||
.setOnEach { selectedSpaceOption ->
|
||||
copy(
|
||||
selectedGroupingMethod = it.orNull() ?: RoomGroupingMethod.BySpace(null)
|
||||
selectedSpace = selectedSpaceOption.orNull()
|
||||
)
|
||||
}
|
||||
|
||||
session.groupService().getGroupSummariesLive(groupSummaryQueryParams {})
|
||||
.asFlow()
|
||||
.setOnEach {
|
||||
copy(legacyGroups = it)
|
||||
}
|
||||
|
||||
// XXX there should be a way to refactor this and share it
|
||||
session.roomService().getPagedRoomSummariesLive(
|
||||
roomSummaryQueryParams {
|
||||
|
@ -154,7 +141,6 @@ class SpaceListViewModel @AssistedInject constructor(
|
|||
SpaceListAction.AddSpace -> handleAddSpace()
|
||||
is SpaceListAction.ToggleExpand -> handleToggleExpand(action)
|
||||
is SpaceListAction.OpenSpaceInvite -> handleSelectSpaceInvite(action)
|
||||
is SpaceListAction.SelectLegacyGroup -> handleSelectGroup(action)
|
||||
is SpaceListAction.MoveSpace -> handleMoveSpace(action)
|
||||
is SpaceListAction.OnEndDragging -> handleEndDragging()
|
||||
is SpaceListAction.OnStartDragging -> handleStartDragging()
|
||||
|
@ -229,26 +215,16 @@ class SpaceListViewModel @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private fun handleSelectSpace(action: SpaceListAction.SelectSpace) = withState { state ->
|
||||
val groupingMethod = state.selectedGroupingMethod
|
||||
if (groupingMethod is RoomGroupingMethod.ByLegacyGroup || groupingMethod.space()?.roomId != action.spaceSummary?.roomId) {
|
||||
if (state.selectedSpace?.roomId != action.spaceSummary?.roomId) {
|
||||
analyticsTracker.capture(Interaction(null, null, Interaction.Name.SpacePanelSwitchSpace))
|
||||
setState { copy(selectedGroupingMethod = RoomGroupingMethod.BySpace(action.spaceSummary)) }
|
||||
setState { copy(selectedSpace = action.spaceSummary) }
|
||||
appStateHandler.setCurrentSpace(action.spaceSummary?.roomId)
|
||||
_viewEvents.post(SpaceListViewEvents.OpenSpace(groupingMethod is RoomGroupingMethod.ByLegacyGroup))
|
||||
_viewEvents.post(SpaceListViewEvents.CloseDrawer)
|
||||
} else {
|
||||
analyticsTracker.capture(Interaction(null, null, Interaction.Name.SpacePanelSelectedSpace))
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSelectGroup(action: SpaceListAction.SelectLegacyGroup) = withState { state ->
|
||||
val groupingMethod = state.selectedGroupingMethod
|
||||
if (groupingMethod is RoomGroupingMethod.BySpace || groupingMethod.group()?.groupId != action.groupSummary?.groupId) {
|
||||
setState { copy(selectedGroupingMethod = RoomGroupingMethod.ByLegacyGroup(action.groupSummary)) }
|
||||
appStateHandler.setCurrentGroup(action.groupSummary?.groupId)
|
||||
_viewEvents.post(SpaceListViewEvents.OpenGroup(groupingMethod is RoomGroupingMethod.BySpace))
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSelectSpaceInvite(action: SpaceListAction.OpenSpaceInvite) {
|
||||
_viewEvents.post(SpaceListViewEvents.OpenSpaceInvite(action.spaceSummary.roomId))
|
||||
}
|
||||
|
|
|
@ -19,8 +19,6 @@ package im.vector.app.features.spaces
|
|||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MavericksState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
@ -28,11 +26,10 @@ import org.matrix.android.sdk.api.util.MatrixItem
|
|||
data class SpaceListViewState(
|
||||
val myMxItem: Async<MatrixItem.UserItem> = Uninitialized,
|
||||
val asyncSpaces: Async<List<RoomSummary>> = Uninitialized,
|
||||
val selectedGroupingMethod: RoomGroupingMethod = RoomGroupingMethod.BySpace(null),
|
||||
val selectedSpace: RoomSummary? = null,
|
||||
val rootSpacesOrdered: List<RoomSummary>? = null,
|
||||
val spaceOrderInfo: Map<String, String?>? = null,
|
||||
val spaceOrderLocalEchos: Map<String, String?>? = null,
|
||||
val legacyGroups: List<GroupSummary>? = null,
|
||||
val expandedStates: Map<String, Boolean> = emptyMap(),
|
||||
val homeAggregateCount: RoomAggregateNotificationCount = RoomAggregateNotificationCount(0, 0)
|
||||
) : MavericksState
|
||||
|
|
|
@ -18,20 +18,11 @@ package im.vector.app.features.spaces
|
|||
|
||||
import com.airbnb.epoxy.EpoxyController
|
||||
import im.vector.app.R
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.core.ui.list.genericFooterItem
|
||||
import im.vector.app.core.ui.list.genericHeaderItem
|
||||
import im.vector.app.features.grouplist.groupSummaryItem
|
||||
import im.vector.app.features.grouplist.homeSpaceSummaryItem
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.list.UnreadCounterBadgeView
|
||||
import im.vector.app.group
|
||||
import im.vector.app.space
|
||||
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
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.SpaceChildInfo
|
||||
|
@ -41,7 +32,6 @@ import javax.inject.Inject
|
|||
|
||||
class SpaceSummaryController @Inject constructor(
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val colorProvider: ColorProvider,
|
||||
private val stringProvider: StringProvider,
|
||||
) : EpoxyController() {
|
||||
|
||||
|
@ -57,59 +47,18 @@ class SpaceSummaryController @Inject constructor(
|
|||
|
||||
override fun buildModels() {
|
||||
val nonNullViewState = viewState ?: return
|
||||
val host = this
|
||||
buildGroupModels(
|
||||
nonNullViewState.asyncSpaces(),
|
||||
nonNullViewState.selectedGroupingMethod,
|
||||
nonNullViewState.selectedSpace,
|
||||
nonNullViewState.rootSpacesOrdered,
|
||||
nonNullViewState.expandedStates,
|
||||
nonNullViewState.homeAggregateCount
|
||||
)
|
||||
|
||||
if (!nonNullViewState.legacyGroups.isNullOrEmpty()) {
|
||||
genericFooterItem {
|
||||
id("legacy_space")
|
||||
text(" ".toEpoxyCharSequence())
|
||||
}
|
||||
|
||||
genericHeaderItem {
|
||||
id("legacy_groups")
|
||||
text(host.stringProvider.getString(R.string.groups_header))
|
||||
textColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
||||
}
|
||||
|
||||
// add home for communities
|
||||
nonNullViewState.myMxItem.invoke()?.let { mxItem ->
|
||||
groupSummaryItem {
|
||||
avatarRenderer(host.avatarRenderer)
|
||||
id("all_communities")
|
||||
matrixItem(mxItem.copy(displayName = host.stringProvider.getString(R.string.group_all_communities)))
|
||||
selected(
|
||||
nonNullViewState.selectedGroupingMethod is RoomGroupingMethod.ByLegacyGroup &&
|
||||
nonNullViewState.selectedGroupingMethod.group() == null
|
||||
)
|
||||
listener { host.callback?.onGroupSelected(null) }
|
||||
}
|
||||
}
|
||||
|
||||
nonNullViewState.legacyGroups.forEach { groupSummary ->
|
||||
groupSummaryItem {
|
||||
avatarRenderer(host.avatarRenderer)
|
||||
id(groupSummary.groupId)
|
||||
matrixItem(groupSummary.toMatrixItem())
|
||||
selected(
|
||||
nonNullViewState.selectedGroupingMethod is RoomGroupingMethod.ByLegacyGroup &&
|
||||
nonNullViewState.selectedGroupingMethod.group()?.groupId == groupSummary.groupId
|
||||
)
|
||||
listener { host.callback?.onGroupSelected(groupSummary) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildGroupModels(
|
||||
summaries: List<RoomSummary>?,
|
||||
selected: RoomGroupingMethod,
|
||||
selectedSpace: RoomSummary?,
|
||||
rootSpaces: List<RoomSummary>?,
|
||||
expandedStates: Map<String, Boolean>,
|
||||
homeCount: RoomAggregateNotificationCount
|
||||
|
@ -137,7 +86,7 @@ class SpaceSummaryController @Inject constructor(
|
|||
|
||||
homeSpaceSummaryItem {
|
||||
id("space_home")
|
||||
selected(selected is RoomGroupingMethod.BySpace && selected.space() == null)
|
||||
selected(selectedSpace == null)
|
||||
countState(UnreadCounterBadgeView.State(homeCount.totalCount, homeCount.isHighlight))
|
||||
listener { host.callback?.onSpaceSelected(null) }
|
||||
}
|
||||
|
@ -145,7 +94,7 @@ class SpaceSummaryController @Inject constructor(
|
|||
rootSpaces
|
||||
?.filter { it.membership != Membership.INVITE }
|
||||
?.forEach { roomSummary ->
|
||||
val isSelected = selected is RoomGroupingMethod.BySpace && roomSummary.roomId == selected.space()?.roomId
|
||||
val isSelected = roomSummary.roomId == selectedSpace?.roomId
|
||||
// does it have children?
|
||||
val subSpaces = roomSummary.spaceChildren?.filter { childInfo ->
|
||||
summaries?.any { it.roomId == childInfo.childRoomId }.orFalse()
|
||||
|
@ -178,7 +127,7 @@ class SpaceSummaryController @Inject constructor(
|
|||
if (hasChildren && expanded) {
|
||||
// it's expanded
|
||||
subSpaces?.forEach { child ->
|
||||
buildSubSpace(roomSummary.roomId, summaries, expandedStates, selected, child, 1, 3)
|
||||
buildSubSpace(roomSummary.roomId, summaries, expandedStates, selectedSpace, child, 1, 3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -193,7 +142,7 @@ class SpaceSummaryController @Inject constructor(
|
|||
idPrefix: String,
|
||||
summaries: List<RoomSummary>?,
|
||||
expandedStates: Map<String, Boolean>,
|
||||
selected: RoomGroupingMethod,
|
||||
selectedSpace: RoomSummary?,
|
||||
info: SpaceChildInfo, currentDepth: Int, maxDepth: Int
|
||||
) {
|
||||
val host = this
|
||||
|
@ -204,7 +153,7 @@ class SpaceSummaryController @Inject constructor(
|
|||
summaries.any { it.roomId == childInfo.childRoomId }
|
||||
}?.sortedWith(subSpaceComparator)
|
||||
val expanded = expandedStates[childSummary.roomId] == true
|
||||
val isSelected = selected is RoomGroupingMethod.BySpace && childSummary.roomId == selected.space()?.roomId
|
||||
val isSelected = childSummary.roomId == selectedSpace?.roomId
|
||||
|
||||
val id = "$idPrefix:${childSummary.roomId}"
|
||||
|
||||
|
@ -229,7 +178,7 @@ class SpaceSummaryController @Inject constructor(
|
|||
|
||||
if (expanded) {
|
||||
subSpaces?.forEach {
|
||||
buildSubSpace(id, summaries, expandedStates, selected, it, currentDepth + 1, maxDepth)
|
||||
buildSubSpace(id, summaries, expandedStates, selectedSpace, it, currentDepth + 1, maxDepth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -240,7 +189,6 @@ class SpaceSummaryController @Inject constructor(
|
|||
fun onSpaceSettings(spaceSummary: RoomSummary)
|
||||
fun onToggleExpand(spaceSummary: RoomSummary)
|
||||
fun onAddSpaceSelected()
|
||||
fun onGroupSelected(groupSummary: GroupSummary?)
|
||||
fun sendFeedBack()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,30 +67,10 @@ class SharedPreferencesUiStateRepository @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun storeSelectedGroup(groupId: String?, sessionId: String) {
|
||||
sharedPreferences.edit {
|
||||
putString("$KEY_SELECTED_GROUP@$sessionId", groupId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun storeGroupingMethod(isSpace: Boolean, sessionId: String) {
|
||||
sharedPreferences.edit {
|
||||
putBoolean("$KEY_SELECTED_METHOD@$sessionId", isSpace)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSelectedGroup(sessionId: String): String? {
|
||||
return sharedPreferences.getString("$KEY_SELECTED_GROUP@$sessionId", null)
|
||||
}
|
||||
|
||||
override fun getSelectedSpace(sessionId: String): String? {
|
||||
return sharedPreferences.getString("$KEY_SELECTED_SPACE@$sessionId", null)
|
||||
}
|
||||
|
||||
override fun isGroupingMethodSpace(sessionId: String): Boolean {
|
||||
return sharedPreferences.getBoolean("$KEY_SELECTED_METHOD@$sessionId", true)
|
||||
}
|
||||
|
||||
override fun setCustomRoomDirectoryHomeservers(sessionId: String, servers: Set<String>) {
|
||||
sharedPreferences.edit {
|
||||
putStringSet("$KEY_CUSTOM_DIRECTORY_HOMESERVER@$sessionId", servers)
|
||||
|
@ -110,8 +90,6 @@ class SharedPreferencesUiStateRepository @Inject constructor(
|
|||
private const val VALUE_DISPLAY_MODE_ROOMS = 2
|
||||
|
||||
private const val KEY_SELECTED_SPACE = "UI_STATE_SELECTED_SPACE"
|
||||
private const val KEY_SELECTED_GROUP = "UI_STATE_SELECTED_GROUP"
|
||||
private const val KEY_SELECTED_METHOD = "UI_STATE_SELECTED_METHOD"
|
||||
|
||||
private const val KEY_CUSTOM_DIRECTORY_HOMESERVER = "KEY_CUSTOM_DIRECTORY_HOMESERVER"
|
||||
}
|
||||
|
|
|
@ -34,13 +34,7 @@ interface UiStateRepository {
|
|||
|
||||
// TODO Handle SharedPreference per session in a better way, also to cleanup when login out
|
||||
fun storeSelectedSpace(spaceId: String?, sessionId: String)
|
||||
fun storeSelectedGroup(groupId: String?, sessionId: String)
|
||||
|
||||
fun storeGroupingMethod(isSpace: Boolean, sessionId: String)
|
||||
|
||||
fun getSelectedSpace(sessionId: String): String?
|
||||
fun getSelectedGroup(sessionId: String): String?
|
||||
fun isGroupingMethodSpace(sessionId: String): Boolean
|
||||
|
||||
fun setCustomRoomDirectoryHomeservers(sessionId: String, servers: Set<String>)
|
||||
fun getCustomRoomDirectoryHomeservers(sessionId: String): Set<String>
|
||||
|
|
|
@ -29,7 +29,6 @@ import im.vector.app.features.createdirect.DirectRoomHelper
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.raw.RawService
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.getUser
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkData
|
||||
|
@ -42,7 +41,6 @@ class UserCodeSharedViewModel @AssistedInject constructor(
|
|||
private val session: Session,
|
||||
private val stringProvider: StringProvider,
|
||||
private val directRoomHelper: DirectRoomHelper,
|
||||
private val rawService: RawService
|
||||
) : VectorViewModel<UserCodeState, UserCodeActions, UserCodeShareViewEvents>(initialState) {
|
||||
|
||||
companion object : MavericksViewModelFactory<UserCodeSharedViewModel, UserCodeState> by hiltMavericksViewModelFactory()
|
||||
|
@ -129,15 +127,11 @@ class UserCodeSharedViewModel @AssistedInject constructor(
|
|||
)
|
||||
}
|
||||
}
|
||||
is PermalinkData.GroupLink -> {
|
||||
// not yet supported
|
||||
_viewEvents.post(UserCodeShareViewEvents.ToastMessage(stringProvider.getString(R.string.not_implemented)))
|
||||
}
|
||||
is PermalinkData.RoomEmailInviteLink,
|
||||
is PermalinkData.FallbackLink -> {
|
||||
// not yet supported
|
||||
_viewEvents.post(UserCodeShareViewEvents.ToastMessage(stringProvider.getString(R.string.not_implemented)))
|
||||
}
|
||||
is PermalinkData.RoomEmailInviteLink -> Unit
|
||||
}
|
||||
_viewEvents.post(UserCodeShareViewEvents.HideWaitingScreen)
|
||||
}
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<im.vector.app.core.platform.CheckableConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/itemGroupLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="65dp"
|
||||
android:background="@drawable/bg_space_item"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
tools:viewBindingIgnore="true">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/groupAvatarImageView"
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="42dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||
android:duplicateParentState="true"
|
||||
android:importantForAccessibility="no"
|
||||
app:layout_constraintBottom_toTopOf="@id/groupBottomSeparator"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@sample/room_round_avatars" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/groupNameView"
|
||||
style="@style/Widget.Vector.TextView.Subtitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?vctr_content_primary"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@id/groupBottomSeparator"
|
||||
app:layout_constraintEnd_toStartOf="@id/groupAvatarChevron"
|
||||
app:layout_constraintStart_toEndOf="@id/groupAvatarImageView"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/groupAvatarChevron"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="21dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_arrow_right"
|
||||
app:layout_constraintBottom_toTopOf="@id/groupBottomSeparator"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="?vctr_content_primary"
|
||||
tools:ignore="MissingPrefix" />
|
||||
|
||||
<View
|
||||
android:id="@+id/groupBottomSeparator"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:background="?vctr_list_separator"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</im.vector.app.core.platform.CheckableConstraintLayout>
|
|
@ -174,7 +174,8 @@
|
|||
<string name="initial_sync_start_importing_account_joined_rooms">Initial sync:\nLoading your conversations\nIf you\'ve joined lots of rooms, this might take a while</string>
|
||||
<string name="initial_sync_start_importing_account_invited_rooms">Initial sync:\nImporting invited rooms</string>
|
||||
<string name="initial_sync_start_importing_account_left_rooms">Initial sync:\nImporting left rooms</string>
|
||||
<string name="initial_sync_start_importing_account_groups">Initial sync:\nImporting communities</string>
|
||||
<!--TODO:delete-->
|
||||
<string name="initial_sync_start_importing_account_groups" tools:ignore="UnusedResources">Initial sync:\nImporting communities</string>
|
||||
<string name="initial_sync_start_importing_account_data">Initial sync:\nImporting account data</string>
|
||||
|
||||
<string name="initial_sync_request_title">Initial sync request</string>
|
||||
|
@ -442,7 +443,8 @@
|
|||
<string name="settings_room_directory_show_all_rooms_summary">Show all rooms in the room directory, including rooms with explicit content.</string>
|
||||
|
||||
<!-- Groups fragment -->
|
||||
<string name="groups_header">Communities</string>
|
||||
<!--TODO: delete-->
|
||||
<string name="groups_header" tools:ignore="UnusedResources">Communities</string>
|
||||
|
||||
<string name="spaces_header">Spaces</string>
|
||||
|
||||
|
@ -1614,7 +1616,8 @@
|
|||
<string name="error_no_network">No network. Please check your Internet connection.</string>
|
||||
<string name="change_room_directory_network">"Change network"</string>
|
||||
<string name="please_wait">"Please wait…"</string>
|
||||
<string name="group_all_communities">"All Communities"</string>
|
||||
<!--TODO: delete-->
|
||||
<string name="group_all_communities" tools:ignore="UnusedResources">"All Communities"</string>
|
||||
|
||||
<string name="room_preview_no_preview">"This room can't be previewed"</string>
|
||||
<string name="room_preview_not_found">This room is not accessible at this time.\nTry again later, or ask a room admin to check if you have access.</string>
|
||||
|
@ -2084,6 +2087,7 @@
|
|||
<string name="soft_logout_sso_not_same_user_error">The current session is for user %1$s and you provide credentials for user %2$s. This is not supported by ${app_name}.\nPlease first clear data, then sign in again on another account.</string>
|
||||
|
||||
<string name="permalink_malformed">Your matrix.to link was malformed</string>
|
||||
<string name="permalink_unsupported_groups">Cannot open this link: communities have been replaced by spaces</string>
|
||||
<string name="bug_report_error_too_short">The description is too short</string>
|
||||
|
||||
<string name="notification_initial_sync">Initial Sync…</string>
|
||||
|
|
Loading…
Reference in a new issue