From 6b8b03e16276b42b32e428e7abf7ba61b8e5fb50 Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 26 Mar 2021 10:55:43 +0100 Subject: [PATCH] Show people you may no in space bottomsheet --- .../api/session/room/peeking/PeekResult.kt | 5 +- .../session/room/peeking/PeekRoomTask.kt | 18 +++- .../matrixto/MatrixToBottomSheetState.kt | 3 +- .../matrixto/MatrixToBottomSheetViewModel.kt | 68 +++++++++----- .../matrixto/MatrixToRoomSpaceFragment.kt | 23 +++++ .../fragment_matrix_to_room_space_card.xml | 91 +++++++++++++++++-- vector/src/main/res/values/strings.xml | 5 + 7 files changed, 178 insertions(+), 35 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/peeking/PeekResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/peeking/PeekResult.kt index c213eee08d..888950dc12 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/peeking/PeekResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/peeking/PeekResult.kt @@ -16,6 +16,8 @@ package org.matrix.android.sdk.api.session.room.peeking +import org.matrix.android.sdk.api.util.MatrixItem + sealed class PeekResult { data class Success( val roomId: String, @@ -25,7 +27,8 @@ sealed class PeekResult { val avatarUrl: String?, val numJoinedMembers: Int?, val roomType: String?, - val viaServers: List + val viaServers: List, + val someMembers: List? ) : PeekResult() data class PeekingNotAllowed( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt index 5d45259304..ac37b3c812 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt @@ -23,12 +23,14 @@ import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.RoomAvatarContent import org.matrix.android.sdk.api.session.room.model.RoomCanonicalAliasContent import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility +import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.RoomNameContent import org.matrix.android.sdk.api.session.room.model.RoomTopicContent import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsFilter import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams import org.matrix.android.sdk.api.session.room.peeking.PeekResult +import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.internal.session.room.alias.GetRoomIdByAliasTask import org.matrix.android.sdk.internal.session.room.directory.GetPublicRoomTask import org.matrix.android.sdk.internal.session.room.directory.GetRoomDirectoryVisibilityTask @@ -102,7 +104,8 @@ internal class DefaultPeekRoomTask @Inject constructor( topic = publicRepoResult.topic, numJoinedMembers = publicRepoResult.numJoinedMembers, viaServers = serverList, - roomType = null // would be nice to get that from directory... + roomType = null, // would be nice to get that from directory... + someMembers = null ) } @@ -127,11 +130,19 @@ internal class DefaultPeekRoomTask @Inject constructor( ?.let { it.content?.toModel()?.canonicalAlias } // not sure if it's the right way to do that :/ - val memberCount = stateEvents + val membersEvent = stateEvents .filter { it.type == EventType.STATE_ROOM_MEMBER && it.stateKey?.isNotEmpty() == true } + + val memberCount = membersEvent .distinctBy { it.stateKey } .count() + val someMembers = membersEvent.mapNotNull { ev -> + ev.content?.toModel()?.let { + MatrixItem.UserItem(ev.stateKey ?: "", it.displayName, it.avatarUrl) + } + } + val roomType = stateEvents .lastOrNull { it.type == EventType.STATE_ROOM_CREATE } ?.let { it.content?.toModel()?.type } @@ -144,7 +155,8 @@ internal class DefaultPeekRoomTask @Inject constructor( topic = topic, numJoinedMembers = memberCount, roomType = roomType, - viaServers = serverList + viaServers = serverList, + someMembers = someMembers ) } catch (failure: Throwable) { // Would be M_FORBIDDEN if cannot peek :/ diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt index c0d42d60dd..2f341d48ec 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt @@ -29,7 +29,8 @@ data class MatrixToBottomSheetState( val linkType: PermalinkData, val matrixItem: Async = Uninitialized, val startChattingState: Async = Uninitialized, - val roomPeekResult: Async = Uninitialized + val roomPeekResult: Async = Uninitialized, + val peopleYouKnow: Async> = Uninitialized ) : MvRxState { constructor(args: MatrixToBottomSheet.MatrixToArgs) : this( diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt index 3ac5218800..55c3826ef3 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt @@ -36,7 +36,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.failure.Failure import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.permalinks.PermalinkData import org.matrix.android.sdk.api.session.room.model.Membership @@ -48,7 +47,6 @@ import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.internal.session.room.alias.RoomAliasDescription import org.matrix.android.sdk.internal.util.awaitCallback -import javax.net.ssl.HttpsURLConnection class MatrixToBottomSheetViewModel @AssistedInject constructor( @Assisted initialState: MatrixToBottomSheetState, @@ -123,7 +121,10 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( } } else { session.getRoom(permalinkData.roomIdOrAlias) - }?.roomSummary() + } + ?.roomSummary() + // don't take if not active, as it could be outdated + ?.takeIf { it.membership.isActive() } val forceRefresh = true if (!forceRefresh && knownRoom != null) { setState { @@ -154,7 +155,9 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( membership = Membership.NONE, roomType = peekResult.roomType, viaServers = peekResult.viaServers.takeIf { it.isNotEmpty() } ?: permalinkData.viaParameters - ) + ).also { + peekResult.someMembers?.let { checkForKnownMembers(it) } + } } is PeekResult.PeekingNotAllowed -> { RoomInfoResult.PartialInfo( @@ -190,30 +193,47 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( } } - private suspend fun resolveSpace(permalinkData: PermalinkData.RoomLink) : PeekResult { - try { - return session.spaceService().querySpaceChildren(permalinkData.roomIdOrAlias).let { - val roomSummary = it.first - PeekResult.Success( - roomId = roomSummary.roomId, - alias = roomSummary.canonicalAlias, - avatarUrl = roomSummary.avatarUrl, - name = roomSummary.name, - topic = roomSummary.topic, - numJoinedMembers = roomSummary.joinedMembersCount, - roomType = roomSummary.roomType, - viaServers = emptyList() - ) - } - } catch (failure: Throwable) { - if (failure is Failure.OtherServerError && failure.httpCode == HttpsURLConnection.HTTP_NOT_FOUND) { - return resolveRoom(permalinkData.roomIdOrAlias) - } else { - throw failure + private fun checkForKnownMembers(someMembers: List) { + viewModelScope.launch(Dispatchers.Default) { + val knownMembers = someMembers.filter { + session.getExistingDirectRoomWithUser(it.id) != null + } + // put one with avatar first, and take 5 + val finalRes = (knownMembers.filter { it.avatarUrl != null } + knownMembers.filter { it.avatarUrl == null }) + .take(5) + setState { + copy( + peopleYouKnow = Success(finalRes) + ) } } } + private suspend fun resolveSpace(permalinkData: PermalinkData.RoomLink): PeekResult { +// try { +// return session.spaceService().querySpaceChildren(permalinkData.roomIdOrAlias).let { +// val roomSummary = it.first +// PeekResult.Success( +// roomId = roomSummary.roomId, +// alias = roomSummary.canonicalAlias, +// avatarUrl = roomSummary.avatarUrl, +// name = roomSummary.name, +// topic = roomSummary.topic, +// numJoinedMembers = roomSummary.joinedMembersCount, +// roomType = roomSummary.roomType, +// viaServers = emptyList(), +// someMembers = null +// ) +// } +// } catch (failure: Throwable) { +// if (failure is Failure.OtherServerError && failure.httpCode == HttpsURLConnection.HTTP_NOT_FOUND) { + return resolveRoom(permalinkData.roomIdOrAlias) +// } else { +// throw failure +// } +// } + } + private suspend fun resolveUser(userId: String): User { return tryOrNull { session.resolveUser(userId) } // Create raw user in case the user is not searchable diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToRoomSpaceFragment.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToRoomSpaceFragment.kt index a7b5543157..7d303cfc5e 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToRoomSpaceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToRoomSpaceFragment.kt @@ -156,6 +156,29 @@ class MatrixToRoomSpaceFragment @Inject constructor( } } + when (state.peopleYouKnow) { + is Success -> { + views.matrixToCardPeopleYouKnowVisibility.isVisible = true + val images = listOf(views.knownMember1, views.knownMember2, views.knownMember3, views.knownMember4, views.knownMember5) + .onEach { it.isVisible = false } + + val someYouKnow = state.peopleYouKnow.invoke() + someYouKnow.forEachIndexed { index, item -> + images[index].isVisible = true + avatarRenderer.render(item, images[index]) + } + views.peopleYouMayKnowText.setTextOrHide( + resources.getQuantityString(R.plurals.space_people_you_know, + someYouKnow.count(), + someYouKnow.count() + ) + ) + } + else -> { + views.matrixToCardPeopleYouKnowVisibility.isVisible = false + } + } + when (state.startChattingState) { Uninitialized -> { views.matrixToCardButtonLoading.isVisible = false diff --git a/vector/src/main/res/layout/fragment_matrix_to_room_space_card.xml b/vector/src/main/res/layout/fragment_matrix_to_room_space_card.xml index 6f49f15842..198574cab8 100644 --- a/vector/src/main/res/layout/fragment_matrix_to_room_space_card.xml +++ b/vector/src/main/res/layout/fragment_matrix_to_room_space_card.xml @@ -16,6 +16,7 @@ android:elevation="4dp" android:transitionName="profile" app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:src="@tools:sample/avatars" /> @@ -24,10 +25,10 @@ android:id="@+id/matrixToCardNameText" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/layout_vertical_margin_big" + android:layout_marginTop="@dimen/layout_vertical_margin" android:maxLines="1" android:singleLine="true" - android:textAlignment="center" + android:textAlignment="textStart" android:textColor="?riotx_text_primary" android:textSize="15sp" android:textStyle="bold" @@ -41,10 +42,12 @@ android:layout_marginTop="4dp" android:maxLines="1" android:singleLine="true" - android:textAlignment="center" + android:textAlignment="textStart" android:textColor="?riotx_text_secondary" android:textSize="15sp" + android:visibility="gone" app:layout_constraintTop_toBottomOf="@id/matrixToCardNameText" + app:layout_goneMarginTop="0dp" tools:text="@sample/matrix.json/data/roomAlias" /> @@ -89,12 +93,79 @@ android:layout_height="wrap_content" android:layout_marginTop="16dp" android:maxLines="4" - android:textAlignment="center" + android:textAlignment="textStart" android:textColor="?riotx_text_secondary" android:textSize="15sp" app:layout_constraintTop_toBottomOf="@id/matrixToMemberPills" tools:text="@sample/matrix.json/data/roomTopic" /> + + + + + + + + + + + + @@ -134,11 +205,19 @@ app:layout_constraintTop_toTopOf="@id/matrixToCardMainButton" tools:visibility="visible" /> + + diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 3ec514959a..7bda547e6c 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -3303,6 +3303,11 @@ Welcome to %1$s, %2$s. + + %d people you know have already joined + %d people you know have already joined + + Explore rooms Leave Space Are you sure you want to leave the space?