Introduce SpaceItem

This commit is contained in:
Valere 2021-05-26 11:16:38 +02:00
parent a832da2124
commit b75d0cbfc6
21 changed files with 98 additions and 77 deletions

View file

@ -20,6 +20,7 @@ import org.matrix.android.sdk.BuildConfig
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
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
import org.matrix.android.sdk.api.session.room.sender.SenderInfo
@ -38,6 +39,8 @@ sealed class MatrixItem(
init {
if (BuildConfig.DEBUG) checkId()
}
override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
}
data class EventItem(override val id: String,
@ -47,6 +50,8 @@ sealed class MatrixItem(
init {
if (BuildConfig.DEBUG) checkId()
}
override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
}
data class RoomItem(override val id: String,
@ -56,6 +61,19 @@ sealed class MatrixItem(
init {
if (BuildConfig.DEBUG) checkId()
}
override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
}
data class SpaceItem(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)
}
data class RoomAliasItem(override val id: String,
@ -68,6 +86,8 @@ sealed class MatrixItem(
// Best name is the id, and we keep the displayName of the room for the case we need the first letter
override fun getBestName() = id
override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
}
data class GroupItem(override val id: String,
@ -80,6 +100,8 @@ sealed class MatrixItem(
// Best name is the id, and we keep the displayName of the room for the case we need the first letter
override fun getBestName() = id
override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
}
open fun getBestName(): String {
@ -92,12 +114,15 @@ sealed class MatrixItem(
}
}
abstract fun updateAvatar(newAvatar: String?): MatrixItem
/**
* Return the prefix as defined in the matrix spec (and not extracted from the id)
*/
fun getIdPrefix() = when (this) {
is UserItem -> '@'
is EventItem -> '$'
is SpaceItem,
is RoomItem -> '!'
is RoomAliasItem -> '#'
is GroupItem -> '+'
@ -148,7 +173,11 @@ fun User.toMatrixItem() = MatrixItem.UserItem(userId, displayName, avatarUrl)
fun GroupSummary.toMatrixItem() = MatrixItem.GroupItem(groupId, displayName, avatarUrl)
fun RoomSummary.toMatrixItem() = MatrixItem.RoomItem(roomId, displayName, avatarUrl)
fun RoomSummary.toMatrixItem() = if (roomType == RoomType.SPACE) {
MatrixItem.SpaceItem(roomId, displayName, avatarUrl)
} else {
MatrixItem.RoomItem(roomId, displayName, avatarUrl)
}
fun RoomSummary.toRoomAliasMatrixItem() = MatrixItem.RoomAliasItem(canonicalAlias ?: roomId, displayName, avatarUrl)
@ -159,4 +188,8 @@ fun RoomMemberSummary.toMatrixItem() = MatrixItem.UserItem(userId, displayName,
fun SenderInfo.toMatrixItem() = MatrixItem.UserItem(userId, disambiguatedDisplayName, avatarUrl)
fun SpaceChildInfo.toMatrixItem() = MatrixItem.RoomItem(childRoomId, name ?: canonicalAlias, avatarUrl)
fun SpaceChildInfo.toMatrixItem() = if (roomType == RoomType.SPACE) {
MatrixItem.SpaceItem(childRoomId, name ?: canonicalAlias, avatarUrl)
} else {
MatrixItem.RoomItem(childRoomId, name ?: canonicalAlias, avatarUrl)
}

View file

@ -71,7 +71,7 @@ abstract class FormEditableSquareAvatarItem : EpoxyModelWithHolder<FormEditableS
.into(holder.image)
}
matrixItem != null -> {
avatarRenderer?.renderSpace(matrixItem!!, holder.image)
avatarRenderer?.render(matrixItem!!, holder.image)
}
else -> {
avatarRenderer?.clear(holder.image)

View file

@ -66,24 +66,24 @@ class AvatarRenderer @Inject constructor(private val activeSessionHolder: Active
DrawableImageViewTarget(imageView))
}
@UiThread
fun renderSpace(matrixItem: MatrixItem, imageView: ImageView, glideRequests: GlideRequests) {
val placeholder = getSpacePlaceholderDrawable(matrixItem)
val resolvedUrl = resolvedUrl(matrixItem.avatarUrl)
glideRequests
.load(resolvedUrl)
.transform(MultiTransformation(CenterCrop(), RoundedCorners(dimensionConverter.dpToPx(8))))
.placeholder(placeholder)
.into(DrawableImageViewTarget(imageView))
}
fun renderSpace(matrixItem: MatrixItem, imageView: ImageView) {
renderSpace(
matrixItem,
imageView,
GlideApp.with(imageView)
)
}
// fun renderSpace(matrixItem: MatrixItem, imageView: ImageView) {
// renderSpace(
// matrixItem,
// imageView,
// GlideApp.with(imageView)
// )
// }
//
// @UiThread
// private fun renderSpace(matrixItem: MatrixItem, imageView: ImageView, glideRequests: GlideRequests) {
// val placeholder = getSpacePlaceholderDrawable(matrixItem)
// val resolvedUrl = resolvedUrl(matrixItem.avatarUrl)
// glideRequests
// .load(resolvedUrl)
// .transform(MultiTransformation(CenterCrop(), RoundedCorners(dimensionConverter.dpToPx(8))))
// .placeholder(placeholder)
// .into(DrawableImageViewTarget(imageView))
// }
fun clear(imageView: ImageView) {
// It can be called after recycler view is destroyed, just silently catch
@ -137,7 +137,16 @@ class AvatarRenderer @Inject constructor(private val activeSessionHolder: Active
target: Target<Drawable>) {
val placeholder = getPlaceholderDrawable(matrixItem)
buildGlideRequest(glideRequests, matrixItem.avatarUrl)
.apply(RequestOptions.circleCropTransform())
.apply {
when (matrixItem) {
is MatrixItem.SpaceItem -> {
transform(MultiTransformation(CenterCrop(), RoundedCorners(dimensionConverter.dpToPx(8))))
}
else -> {
apply(RequestOptions.circleCropTransform())
}
}
}
.placeholder(placeholder)
.into(target)
}
@ -197,17 +206,16 @@ class AvatarRenderer @Inject constructor(private val activeSessionHolder: Active
.beginConfig()
.bold()
.endConfig()
.buildRound(matrixItem.firstLetterOfDisplayName(), avatarColor)
}
@AnyThread
fun getSpacePlaceholderDrawable(matrixItem: MatrixItem): Drawable {
val avatarColor = matrixItemColorProvider.getColor(matrixItem)
return TextDrawable.builder()
.beginConfig()
.bold()
.endConfig()
.buildRoundRect(matrixItem.firstLetterOfDisplayName(), avatarColor, dimensionConverter.dpToPx(8))
.let {
when (matrixItem) {
is MatrixItem.SpaceItem -> {
it.buildRoundRect(matrixItem.firstLetterOfDisplayName(), avatarColor, dimensionConverter.dpToPx(8))
}
else -> {
it.buildRound(matrixItem.firstLetterOfDisplayName(), avatarColor)
}
}
}
}
// PRIVATE API *********************************************************************************

View file

@ -48,7 +48,6 @@ abstract class SpaceChildInfoItem : VectorEpoxyModel<SpaceChildInfoItem.Holder>(
@EpoxyAttribute var memberCount: Int = 0
@EpoxyAttribute var loading: Boolean = false
@EpoxyAttribute var space: Boolean = false
@EpoxyAttribute var buttonLabel: String? = null
@ -64,11 +63,7 @@ abstract class SpaceChildInfoItem : VectorEpoxyModel<SpaceChildInfoItem.Holder>(
itemLongClickListener?.onLongClick(it) ?: false
}
holder.titleView.text = matrixItem.displayName ?: holder.rootView.context.getString(R.string.unnamed_room)
if (space) {
avatarRenderer.renderSpace(matrixItem, holder.avatarImageView)
} else {
avatarRenderer.render(matrixItem, holder.avatarImageView)
}
avatarRenderer.render(matrixItem, holder.avatarImageView)
holder.descriptionText.text = span {
span {

View file

@ -41,7 +41,7 @@ data class MatrixToBottomSheetState(
sealed class RoomInfoResult {
data class FullInfo(
val roomItem: MatrixItem.RoomItem,
val roomItem: MatrixItem,
val name: String,
val topic: String,
val memberCount: Int?,

View file

@ -78,9 +78,9 @@ class MatrixToRoomSpaceFragment @Inject constructor(
when (val peek = item.invoke()) {
is RoomInfoResult.FullInfo -> {
val matrixItem = peek.roomItem
avatarRenderer.render(matrixItem, views.matrixToCardAvatar)
if (peek.roomType == RoomType.SPACE) {
views.matrixToBetaTag.isVisible = true
avatarRenderer.renderSpace(matrixItem, views.matrixToCardAvatar)
if (peek.isPublic) {
views.matrixToAccessText.setTextOrHide(context?.getString(R.string.public_space))
views.matrixToAccessImage.isVisible = true
@ -92,7 +92,6 @@ class MatrixToRoomSpaceFragment @Inject constructor(
}
} else {
views.matrixToBetaTag.isVisible = false
avatarRenderer.render(matrixItem, views.matrixToCardAvatar)
}
views.matrixToCardNameText.setTextOrHide(peek.name)
views.matrixToCardAliasText.setTextOrHide(peek.alias)

View file

@ -51,7 +51,7 @@ class SpaceCardHelper @Inject constructor(
} else {
inCard.matrixToCardContentVisibility.isVisible = true
inCard.matrixToCardButtonLoading.isVisible = false
avatarRenderer.renderSpace(spaceSummary.toMatrixItem(), inCard.matrixToCardAvatar)
avatarRenderer.render(spaceSummary.toMatrixItem(), inCard.matrixToCardAvatar)
inCard.matrixToCardNameText.text = spaceSummary.name
inCard.matrixToBetaTag.isVisible = true
inCard.matrixToCardAliasText.setTextOrHide(spaceSummary.canonicalAlias)
@ -119,7 +119,7 @@ class SpaceCardHelper @Inject constructor(
} else {
inCard.matrixToCardContentVisibility.isVisible = true
inCard.matrixToCardButtonLoading.isVisible = false
avatarRenderer.renderSpace(spaceChildInfo.toMatrixItem(), inCard.matrixToCardAvatar)
avatarRenderer.render(spaceChildInfo.toMatrixItem(), inCard.matrixToCardAvatar)
inCard.matrixToCardNameText.setTextOrHide(spaceChildInfo.name)
inCard.matrixToBetaTag.isVisible = true
inCard.matrixToCardAliasText.setTextOrHide(spaceChildInfo.canonicalAlias)

View file

@ -68,16 +68,14 @@ class RoomSettingsController @Inject constructor(
id("avatar")
enabled(data.actionPermissions.canChangeAvatar)
when (val avatarAction = data.avatarAction) {
RoomSettingsViewState.AvatarAction.None -> {
RoomSettingsViewState.AvatarAction.None -> {
// Use the current value
avatarRenderer(host.avatarRenderer)
// We do not want to use the fallback avatar url, which can be the other user avatar, or the current user avatar.
matrixItem(roomSummary.toMatrixItem().copy(avatarUrl = data.currentRoomAvatarUrl))
matrixItem(roomSummary.toMatrixItem().updateAvatar(data.currentRoomAvatarUrl))
}
RoomSettingsViewState.AvatarAction.DeleteAvatar ->
imageUri(null)
is RoomSettingsViewState.AvatarAction.UpdateAvatar ->
imageUri(avatarAction.newAvatarUri)
RoomSettingsViewState.AvatarAction.DeleteAvatar -> imageUri(null)
is RoomSettingsViewState.AvatarAction.UpdateAvatar -> imageUri(avatarAction.newAvatarUri)
}
clickListener { host.callback?.onAvatarChange() }
deleteListener { host.callback?.onAvatarDelete() }

View file

@ -96,7 +96,7 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomS
val session = activeSessionHolder.getSafeActiveSession() ?: return
val roomSummary = session.getRoomSummary(spaceArgs.spaceId)
roomSummary?.toMatrixItem()?.let {
avatarRenderer.renderSpace(it, views.spaceAvatarImageView)
avatarRenderer.render(it, views.spaceAvatarImageView)
}
views.spaceNameView.text = roomSummary?.displayName
views.spaceDescription.setTextOrHide(roomSummary?.topic?.takeIf { it.isNotEmpty() })

View file

@ -87,7 +87,7 @@ abstract class SpaceSummaryItem : VectorEpoxyModel<SpaceSummaryItem.Holder>() {
holder.indentSpace.isVisible = indent > 0
holder.separator.isVisible = showSeparator
avatarRenderer.renderSpace(matrixItem, holder.avatarImageView)
avatarRenderer.render(matrixItem, holder.avatarImageView)
holder.counterBadgeView.render(countState)
}

View file

@ -81,7 +81,7 @@ abstract class SubSpaceSummaryItem : VectorEpoxyModel<SubSpaceSummaryItem.Holder
width = indent * 30
}
avatarRenderer.renderSpace(matrixItem, holder.avatarImageView)
avatarRenderer.render(matrixItem, holder.avatarImageView)
holder.counterBadgeView.render(countState)
}

View file

@ -54,7 +54,7 @@ class SpaceDetailEpoxyController @Inject constructor(
enabled(true)
imageUri(data?.avatarUri)
avatarRenderer(host.avatarRenderer)
matrixItem(data?.name?.let { MatrixItem.RoomItem("!", it, null).takeIf { !it.displayName.isNullOrBlank() } })
matrixItem(data?.name?.let { MatrixItem.SpaceItem("!", it, null).takeIf { !it.displayName.isNullOrBlank() } })
clickListener { host.listener?.onAvatarChange() }
deleteListener { host.listener?.onAvatarDelete() }
}

View file

@ -131,7 +131,6 @@ class SpaceDirectoryController @Inject constructor(
avatarRenderer(host.avatarRenderer)
topic(info.topic)
memberCount(info.activeMemberCount ?: 0)
space(isSpace)
loading(isLoading)
buttonLabel(
if (isJoined) host.stringProvider.getString(R.string.action_open)

View file

@ -27,7 +27,6 @@ import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.list.RoomCategoryItem_
import org.matrix.android.sdk.api.session.room.ResultBoundaries
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.RoomType
import org.matrix.android.sdk.api.util.toMatrixItem
import javax.inject.Inject
@ -155,7 +154,6 @@ class AddRoomListController @Inject constructor(
id(item.roomId)
matrixItem(item.toMatrixItem())
avatarRenderer(host.avatarRenderer)
space(item.roomType == RoomType.SPACE)
selected(host.selectedItems[item.roomId] ?: false)
itemClickListener(DebouncedClickListener({
host.listener?.onItemSelected(item)

View file

@ -34,18 +34,14 @@ abstract class RoomManageSelectionItem : VectorEpoxyModel<RoomManageSelectionIte
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
@EpoxyAttribute lateinit var matrixItem: MatrixItem
@EpoxyAttribute var space: Boolean = false
@EpoxyAttribute var selected: Boolean = false
@EpoxyAttribute var suggested: Boolean = false
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var itemClickListener: View.OnClickListener? = null
override fun bind(holder: Holder) {
super.bind(holder)
if (space) {
avatarRenderer.renderSpace(matrixItem, holder.avatarImageView)
} else {
avatarRenderer.render(matrixItem, holder.avatarImageView)
}
avatarRenderer.render(matrixItem, holder.avatarImageView)
holder.titleText.text = matrixItem.getBestName()
if (selected) {

View file

@ -33,17 +33,13 @@ abstract class RoomSelectionItem : VectorEpoxyModel<RoomSelectionItem.Holder>()
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
@EpoxyAttribute lateinit var matrixItem: MatrixItem
@EpoxyAttribute var space: Boolean = false
@EpoxyAttribute var selected: Boolean = false
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var itemClickListener: View.OnClickListener? = null
override fun bind(holder: Holder) {
super.bind(holder)
if (space) {
avatarRenderer.renderSpace(matrixItem, holder.avatarImageView)
} else {
avatarRenderer.render(matrixItem, holder.avatarImageView)
}
avatarRenderer.render(matrixItem, holder.avatarImageView)
holder.titleText.text = matrixItem.getBestName()
if (selected) {

View file

@ -27,7 +27,6 @@ import im.vector.app.core.resources.StringProvider
import im.vector.app.core.ui.list.genericFooterItem
import im.vector.app.core.utils.DebouncedClickListener
import im.vector.app.features.home.AvatarRenderer
import org.matrix.android.sdk.api.session.room.model.RoomType
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
import org.matrix.android.sdk.api.util.toMatrixItem
import javax.inject.Inject
@ -83,7 +82,6 @@ class SpaceManageRoomsController @Inject constructor(
matrixItem(childInfo.toMatrixItem())
avatarRenderer(host.avatarRenderer)
suggested(childInfo.suggested ?: false)
space(childInfo.roomType == RoomType.SPACE)
selected(data.selectedRooms.contains(childInfo.childRoomId))
itemClickListener(DebouncedClickListener({
host.listener?.toggleSelection(childInfo)

View file

@ -70,8 +70,9 @@ class SpaceSettingsController @Inject constructor(
RoomSettingsViewState.AvatarAction.None -> {
// Use the current value
avatarRenderer(host.avatarRenderer)
val mxItem = roomSummary.toMatrixItem()
// We do not want to use the fallback avatar url, which can be the other user avatar, or the current user avatar.
matrixItem(roomSummary.toMatrixItem().copy(avatarUrl = data.currentRoomAvatarUrl))
matrixItem(roomSummary.toMatrixItem().updateAvatar(data.currentRoomAvatarUrl))
}
RoomSettingsViewState.AvatarAction.DeleteAvatar ->
imageUri(null)

View file

@ -139,7 +139,7 @@ class SpaceSettingsFragment @Inject constructor(
drawableProvider.getDrawable(R.drawable.ic_beta_pill),
null
)
avatarRenderer.renderSpace(it.toMatrixItem(), views.roomSettingsToolbarAvatarImageView)
avatarRenderer.render(it.toMatrixItem(), views.roomSettingsToolbarAvatarImageView)
views.roomSettingsDecorationToolbarAvatarImageView.render(it.roomEncryptionTrustLevel)
}

View file

@ -148,8 +148,8 @@ class SpacePreviewFragment @Inject constructor(
// val roomPeekResult = preview.summary.roomPeekResult
val spaceName = spacePreviewState.spaceInfo.invoke()?.name ?: spacePreviewState.name ?: ""
val spaceAvatarUrl = spacePreviewState.spaceInfo.invoke()?.avatarUrl ?: spacePreviewState.avatarUrl
val mxItem = MatrixItem.RoomItem(spacePreviewState.idOrAlias, spaceName, spaceAvatarUrl)
avatarRenderer.renderSpace(mxItem, views.spacePreviewToolbarAvatar)
val mxItem = MatrixItem.SpaceItem(spacePreviewState.idOrAlias, spaceName, spaceAvatarUrl)
avatarRenderer.render(mxItem, views.spacePreviewToolbarAvatar)
views.roomPreviewNoPreviewToolbarTitle.text = spaceName
// }
// is SpacePeekResult.SpacePeekError,

View file

@ -48,8 +48,8 @@ abstract class SubSpaceItem : VectorEpoxyModel<SubSpaceItem.Holder>() {
super.bind(holder)
holder.nameText.text = title
avatarRenderer.renderSpace(
MatrixItem.RoomItem(roomId, title, avatarUrl),
avatarRenderer.render(
MatrixItem.SpaceItem(roomId, title, avatarUrl),
holder.avatarImageView
)
holder.tabView.tabDepth = depth