Show people you may no in space bottomsheet

This commit is contained in:
Valere 2021-03-26 10:55:43 +01:00
parent dda45f1c2a
commit 6b8b03e162
7 changed files with 178 additions and 35 deletions

View File

@ -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<String>
val viaServers: List<String>,
val someMembers: List<MatrixItem.UserItem>?
) : PeekResult()
data class PeekingNotAllowed(

View File

@ -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<RoomCanonicalAliasContent>()?.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<RoomMemberContent>()?.let {
MatrixItem.UserItem(ev.stateKey ?: "", it.displayName, it.avatarUrl)
}
}
val roomType = stateEvents
.lastOrNull { it.type == EventType.STATE_ROOM_CREATE }
?.let { it.content?.toModel<RoomCreateContent>()?.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 :/

View File

@ -29,7 +29,8 @@ data class MatrixToBottomSheetState(
val linkType: PermalinkData,
val matrixItem: Async<MatrixItem> = Uninitialized,
val startChattingState: Async<Unit> = Uninitialized,
val roomPeekResult: Async<RoomInfoResult> = Uninitialized
val roomPeekResult: Async<RoomInfoResult> = Uninitialized,
val peopleYouKnow: Async<List<MatrixItem.UserItem>> = Uninitialized
) : MvRxState {
constructor(args: MatrixToBottomSheet.MatrixToArgs) : this(

View File

@ -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<MatrixItem.UserItem>) {
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

View File

@ -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

View File

@ -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" />
<LinearLayout
@ -60,6 +63,7 @@
android:paddingEnd="12dp"
android:paddingBottom="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/matrixToCardAliasText">
@ -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" />
<ImageView
android:id="@+id/knownMember5"
android:layout_width="30dp"
android:layout_height="30dp"
android:contentDescription="@string/avatar"
app:layout_constraintCircle="@id/knownMember4"
app:layout_constraintCircleAngle="90"
app:layout_constraintCircleRadius="20dp"
tools:ignore="MissingConstraints"
tools:src="@tools:sample/avatars" />
<ImageView
android:id="@+id/knownMember4"
android:layout_width="30dp"
android:layout_height="30dp"
android:contentDescription="@string/avatar"
app:layout_constraintCircle="@id/knownMember3"
app:layout_constraintCircleAngle="90"
app:layout_constraintCircleRadius="20dp"
tools:ignore="MissingConstraints"
tools:src="@tools:sample/avatars" />
<ImageView
android:id="@+id/knownMember3"
android:layout_width="30dp"
android:layout_height="30dp"
android:contentDescription="@string/avatar"
app:layout_constraintCircle="@id/knownMember2"
app:layout_constraintCircleAngle="90"
app:layout_constraintCircleRadius="20dp"
tools:ignore="MissingConstraints"
tools:src="@tools:sample/avatars" />
<ImageView
android:id="@+id/knownMember2"
android:layout_width="30dp"
android:layout_height="30dp"
android:contentDescription="@string/avatar"
app:layout_constraintCircle="@id/knownMember1"
app:layout_constraintCircleAngle="90"
app:layout_constraintCircleRadius="20dp"
tools:ignore="MissingConstraints"
tools:src="@tools:sample/avatars" />
<ImageView
android:id="@+id/knownMember1"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginTop="8dp"
android:contentDescription="@string/avatar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/matrixToCardDescText"
tools:src="@tools:sample/avatars" />
<TextView
android:id="@+id/peopleYouMayKnowText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:textColor="?riotx_text_secondary"
android:textSize="15sp"
app:layout_constraintBottom_toBottomOf="@id/knownMember1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/knownMember5"
app:layout_constraintTop_toTopOf="@id/knownMember1"
tools:text="7 people you may know" />
<com.google.android.material.button.MaterialButton
android:id="@+id/matrixToCardMainButton"
android:layout_width="0dp"
@ -103,7 +174,7 @@
android:layout_marginBottom="@dimen/layout_vertical_margin_big"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/matrixToCardDescText"
app:layout_constraintTop_toBottomOf="@id/knownMember1"
app:layout_constraintWidth_max="400dp"
tools:text="@string/join" />
@ -134,11 +205,19 @@
app:layout_constraintTop_toTopOf="@id/matrixToCardMainButton"
tools:visibility="visible" />
<androidx.constraintlayout.widget.Group
android:id="@+id/matrixToCardPeopleYouKnowVisibility"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="knownMember1,knownMember2,knownMember3,knownMember4,knownMember5,peopleYouMayKnowText"
tools:visibility="visible" />
<androidx.constraintlayout.widget.Group
android:id="@+id/matrixToCardContentVisibility"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="matrixToCardNameText,matrixToCardAvatar,matrixToCardNameText,matrixToCardDescText, matrixToCardMainButton, matrixToCardAliasText, matrixToCardSecondaryButton, matrixToMemberPills"
android:visibility="gone"
app:constraint_referenced_ids="matrixToCardNameText,matrixToCardAvatar,matrixToCardNameText,matrixToCardDescText, matrixToCardMainButton, matrixToCardAliasText, matrixToCardSecondaryButton, matrixToMemberPills,matrixToCardPeopleYouKnowVisibility"
tools:visibility="visible" />

View File

@ -3303,6 +3303,11 @@
<!-- First one is the space name, and the second one is user name -->
<string name="suggested_rooms_pills_on_empty_header">Welcome to %1$s, %2$s.</string>
<plurals name="space_people_you_know">
<item quantity="one">%d people you know have already joined</item>
<item quantity="other">%d people you know have already joined</item>
</plurals>
<string name="space_explore_activity_title">Explore rooms</string>
<string name="leave_space">Leave Space</string>
<string name="space_leave_prompt_msg">Are you sure you want to leave the space?</string>