Merge pull request #2674 from element-hq/feature/bma/roomSuggestion
Room / User suggestions
This commit is contained in:
commit
014061facf
34 changed files with 573 additions and 53 deletions
|
|
@ -34,6 +34,7 @@ import androidx.compose.ui.res.painterResource
|
|||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage
|
||||
import io.element.android.libraries.designsystem.R
|
||||
import io.element.android.libraries.designsystem.modifiers.blurCompat
|
||||
import io.element.android.libraries.designsystem.modifiers.blurredShapeShadow
|
||||
|
|
@ -171,6 +172,7 @@ internal fun ElementLogoAtomLargeNoBlurShadowPreview() = ElementPreview {
|
|||
ContentToPreview(ElementLogoAtomSize.Large, useBlurredShadow = false)
|
||||
}
|
||||
|
||||
@ExcludeFromCoverage
|
||||
@Composable
|
||||
private fun ContentToPreview(elementLogoAtomSize: ElementLogoAtomSize, useBlurredShadow: Boolean = true) {
|
||||
Box(
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage
|
||||
import io.element.android.libraries.designsystem.atomic.atoms.RedIndicatorAtom
|
||||
import io.element.android.libraries.designsystem.components.preferences.components.PreferenceIcon
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
|
|
@ -162,6 +163,7 @@ internal fun PreferenceTextWithEndBadgeDarkPreview() = ElementPreviewDark {
|
|||
ContentToPreview(showEndBadge = true)
|
||||
}
|
||||
|
||||
@ExcludeFromCoverage
|
||||
@Composable
|
||||
private fun ContentToPreview(showEndBadge: Boolean) {
|
||||
Column(
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import androidx.compose.ui.unit.Dp
|
|||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage
|
||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
|
@ -269,6 +270,7 @@ internal fun SearchBarActiveWithContentPreview() = ElementThemedPreview {
|
|||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@ExcludeFromCoverage
|
||||
private fun ContentToPreview(
|
||||
query: String = "",
|
||||
active: Boolean = false,
|
||||
|
|
|
|||
|
|
@ -91,4 +91,7 @@ interface MatrixClient : Closeable {
|
|||
fun roomMembershipObserver(): RoomMembershipObserver
|
||||
|
||||
fun isMe(userId: UserId?) = userId == sessionId
|
||||
|
||||
suspend fun trackRecentlyVisitedRoom(roomId: RoomId): Result<Unit>
|
||||
suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,6 +82,12 @@ interface MatrixRoom : Closeable {
|
|||
*/
|
||||
suspend fun updateMembers()
|
||||
|
||||
/**
|
||||
* Get the members of the room. Note: generally this should not be used, please use
|
||||
* [membersStateFlow] and [updateMembers] instead.
|
||||
*/
|
||||
suspend fun getMembers(limit: Int = 5): Result<List<RoomMember>>
|
||||
|
||||
/**
|
||||
* Will return an updated member or an error.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2024 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.api.room.recent
|
||||
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.toMatrixUser
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
private const val MAX_RECENT_DIRECT_ROOMS_TO_RETURN = 5
|
||||
|
||||
data class RecentDirectRoom(
|
||||
val roomId: RoomId,
|
||||
val matrixUser: MatrixUser,
|
||||
)
|
||||
|
||||
suspend fun MatrixClient.getRecentDirectRooms(
|
||||
maxNumberOfResults: Int = MAX_RECENT_DIRECT_ROOMS_TO_RETURN,
|
||||
): List<RecentDirectRoom> {
|
||||
val result = mutableListOf<RecentDirectRoom>()
|
||||
val foundUserIds = mutableSetOf<UserId>()
|
||||
getRecentlyVisitedRooms().getOrNull()?.let { roomIds ->
|
||||
roomIds
|
||||
.mapNotNull { roomId -> getRoom(roomId) }
|
||||
.filter { it.isDm && it.isJoined() }
|
||||
.map { room ->
|
||||
val otherUser = room.getMembers().getOrNull()
|
||||
?.firstOrNull { it.userId != sessionId }
|
||||
?.takeIf { foundUserIds.add(it.userId) }
|
||||
?.toMatrixUser()
|
||||
if (otherUser != null) {
|
||||
result.add(
|
||||
RecentDirectRoom(room.roomId, otherUser)
|
||||
)
|
||||
// Return early to avoid useless computation
|
||||
if (result.size >= maxNumberOfResults) {
|
||||
return@map
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
suspend fun MatrixRoom.isJoined(): Boolean {
|
||||
return roomInfoFlow.first().currentUserMembership == CurrentUserMembership.JOINED
|
||||
}
|
||||
|
|
@ -438,6 +438,18 @@ class RustMatrixClient(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun trackRecentlyVisitedRoom(roomId: RoomId): Result<Unit> = withContext(sessionDispatcher) {
|
||||
runCatching {
|
||||
client.trackRecentlyVisitedRoom(roomId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>> = withContext(sessionDispatcher) {
|
||||
runCatching {
|
||||
client.getRecentlyVisitedRooms().map(::RoomId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun syncService(): SyncService = rustSyncService
|
||||
|
||||
override fun sessionVerificationService(): SessionVerificationService = verificationService
|
||||
|
|
|
|||
|
|
@ -237,6 +237,16 @@ class RustMatrixRoom(
|
|||
roomMemberListFetcher.fetchRoomMembers(source = source)
|
||||
}
|
||||
|
||||
override suspend fun getMembers(limit: Int) = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.members().use {
|
||||
it.nextChunk(limit.toUInt()).orEmpty().map { roomMember ->
|
||||
RoomMemberMapper.map(roomMember)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getUpdatedMember(userId: UserId): Result<RoomMember> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
RoomMemberMapper.map(innerRoom.member(userId.value))
|
||||
|
|
|
|||
|
|
@ -255,4 +255,16 @@ class FakeMatrixClient(
|
|||
fun givenRemoveAvatarResult(result: Result<Unit>) {
|
||||
removeAvatarResult = result
|
||||
}
|
||||
|
||||
private val visitedRoomsId: MutableList<RoomId> = mutableListOf()
|
||||
|
||||
override suspend fun trackRecentlyVisitedRoom(roomId: RoomId): Result<Unit> {
|
||||
visitedRoomsId.removeAll { it == roomId }
|
||||
visitedRoomsId.add(0, roomId)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>> {
|
||||
return Result.success(visitedRoomsId)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,6 +201,10 @@ class FakeMatrixRoom(
|
|||
return getRoomMemberResult
|
||||
}
|
||||
|
||||
override suspend fun getMembers(limit: Int): Result<List<RoomMember>> {
|
||||
return Result.success(emptyList())
|
||||
}
|
||||
|
||||
override suspend fun updateRoomNotificationSettings(): Result<Unit> = simulateLongTask {
|
||||
val notificationSettings = notificationSettingsService.getRoomNotificationSettings(roomId, isEncrypted, isOneToOne).getOrThrow()
|
||||
roomNotificationSettingsStateFlow.value = MatrixRoomNotificationSettingsState.Ready(notificationSettings)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue