Merge pull request #3401 from vector-im/feature/bca/spaces_fix_3386
Fixes #3386 show space description in explore header
This commit is contained in:
commit
5657da3493
|
@ -54,7 +54,7 @@ interface PermalinkService {
|
|||
*
|
||||
* @return the permalink, or null in case of error
|
||||
*/
|
||||
fun createRoomPermalink(roomId: String): String?
|
||||
fun createRoomPermalink(roomId: String, viaServers: List<String>? = null): String?
|
||||
|
||||
/**
|
||||
* Creates a permalink for an event. If you have an event you can use [createPermalink]
|
||||
|
|
|
@ -32,5 +32,7 @@ data class SpaceChildInfo(
|
|||
val parentRoomId: String?,
|
||||
val suggested: Boolean?,
|
||||
val canonicalAlias: String?,
|
||||
val aliases: List<String>?
|
||||
val aliases: List<String>?,
|
||||
val worldReadable: Boolean
|
||||
|
||||
)
|
||||
|
|
|
@ -28,7 +28,8 @@ sealed class PeekResult {
|
|||
val numJoinedMembers: Int?,
|
||||
val roomType: String?,
|
||||
val viaServers: List<String>,
|
||||
val someMembers: List<MatrixItem.UserItem>?
|
||||
val someMembers: List<MatrixItem.UserItem>?,
|
||||
val isPublic: Boolean
|
||||
) : PeekResult()
|
||||
|
||||
data class PeekingNotAllowed(
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.matrix.android.sdk.internal.database.mapper
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||
import org.matrix.android.sdk.api.session.room.model.SpaceParentInfo
|
||||
|
@ -92,7 +93,8 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa
|
|||
parentRoomId = roomSummaryEntity.roomId,
|
||||
suggested = it.suggested,
|
||||
canonicalAlias = it.childSummaryEntity?.canonicalAlias,
|
||||
aliases = it.childSummaryEntity?.aliases?.toList()
|
||||
aliases = it.childSummaryEntity?.aliases?.toList(),
|
||||
worldReadable = it.childSummaryEntity?.joinRules == RoomJoinRules.PUBLIC
|
||||
)
|
||||
},
|
||||
flattenParentIds = roomSummaryEntity.flattenParentIds?.split("|") ?: emptyList()
|
||||
|
|
|
@ -33,8 +33,8 @@ internal class DefaultPermalinkService @Inject constructor(
|
|||
return permalinkFactory.createPermalink(id)
|
||||
}
|
||||
|
||||
override fun createRoomPermalink(roomId: String): String? {
|
||||
return permalinkFactory.createRoomPermalink(roomId)
|
||||
override fun createRoomPermalink(roomId: String, viaServers: List<String>?): String? {
|
||||
return permalinkFactory.createRoomPermalink(roomId, viaServers)
|
||||
}
|
||||
|
||||
override fun createPermalink(roomId: String, eventId: String): String {
|
||||
|
|
|
@ -40,11 +40,18 @@ internal class PermalinkFactory @Inject constructor(
|
|||
} else MATRIX_TO_URL_BASE + escape(id)
|
||||
}
|
||||
|
||||
fun createRoomPermalink(roomId: String): String? {
|
||||
fun createRoomPermalink(roomId: String, via: List<String>? = null): String? {
|
||||
return if (roomId.isEmpty()) {
|
||||
null
|
||||
} else {
|
||||
MATRIX_TO_URL_BASE + escape(roomId) + viaParameterFinder.computeViaParams(userId, roomId)
|
||||
buildString {
|
||||
append(MATRIX_TO_URL_BASE)
|
||||
append(escape(roomId))
|
||||
append(
|
||||
via?.takeIf { it.isNotEmpty() }?.let { viaParameterFinder.asUrlViaParameters(it) }
|
||||
?: viaParameterFinder.computeViaParams(userId, roomId)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,8 +39,11 @@ internal class ViaParameterFinder @Inject constructor(
|
|||
* current user one.
|
||||
*/
|
||||
fun computeViaParams(userId: String, roomId: String): String {
|
||||
return computeViaParams(userId, roomId, 3)
|
||||
.joinToString(prefix = "?via=", separator = "&via=") { URLEncoder.encode(it, "utf-8") }
|
||||
return asUrlViaParameters(computeViaParams(userId, roomId, 3))
|
||||
}
|
||||
|
||||
fun asUrlViaParameters(viaList: List<String>): String {
|
||||
return viaList.joinToString(prefix = "?via=", separator = "&via=") { URLEncoder.encode(it, "utf-8") }
|
||||
}
|
||||
|
||||
fun computeViaParams(userId: String, roomId: String, max: Int): List<String> {
|
||||
|
|
|
@ -23,6 +23,8 @@ 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.RoomHistoryVisibility
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
|
||||
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
|
||||
|
@ -105,7 +107,8 @@ internal class DefaultPeekRoomTask @Inject constructor(
|
|||
numJoinedMembers = publicRepoResult.numJoinedMembers,
|
||||
viaServers = serverList,
|
||||
roomType = null, // would be nice to get that from directory...
|
||||
someMembers = null
|
||||
someMembers = null,
|
||||
isPublic = true
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -143,6 +146,11 @@ internal class DefaultPeekRoomTask @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
val historyVisibility =
|
||||
stateEvents
|
||||
.lastOrNull { it.type == EventType.STATE_ROOM_HISTORY_VISIBILITY && it.stateKey?.isNotEmpty() == true }
|
||||
?.let { it.content?.toModel<RoomHistoryVisibilityContent>()?.historyVisibility }
|
||||
|
||||
val roomType = stateEvents
|
||||
.lastOrNull { it.type == EventType.STATE_ROOM_CREATE }
|
||||
?.content
|
||||
|
@ -158,7 +166,8 @@ internal class DefaultPeekRoomTask @Inject constructor(
|
|||
numJoinedMembers = memberCount,
|
||||
roomType = roomType,
|
||||
viaServers = serverList,
|
||||
someMembers = someMembers
|
||||
someMembers = someMembers,
|
||||
isPublic = historyVisibility == RoomHistoryVisibility.WORLD_READABLE
|
||||
)
|
||||
} catch (failure: Throwable) {
|
||||
// Would be M_FORBIDDEN if cannot peek :/
|
||||
|
|
|
@ -147,7 +147,8 @@ internal class DefaultSpaceService @Inject constructor(
|
|||
parentRoomId = childStateEv.roomId,
|
||||
suggested = childStateEvContent.suggested,
|
||||
canonicalAlias = childSummary.canonicalAlias,
|
||||
aliases = childSummary.aliases
|
||||
aliases = childSummary.aliases,
|
||||
worldReadable = childSummary.worldReadable
|
||||
)
|
||||
}
|
||||
}.orEmpty()
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Fix | On Android it seems to be impossible to view the complete description of a Space (without dev tools)
|
|
@ -0,0 +1 @@
|
|||
Fix | Suggest Rooms, Show a detailed view of the room on click
|
|
@ -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)
|
||||
|
|
|
@ -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 *********************************************************************************
|
||||
|
|
|
@ -30,4 +30,5 @@ sealed class RoomListAction : VectorViewModelAction {
|
|||
data class ToggleTag(val roomId: String, val tag: String) : RoomListAction()
|
||||
data class LeaveRoom(val roomId: String) : RoomListAction()
|
||||
data class JoinSuggestedRoom(val roomId: String, val viaServers: List<String>?) : RoomListAction()
|
||||
data class ShowRoomDetails(val roomId: String, val viaServers: List<String>?) : RoomListAction()
|
||||
}
|
||||
|
|
|
@ -108,10 +108,11 @@ class RoomListFragment @Inject constructor(
|
|||
sharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java)
|
||||
roomListViewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is RoomListViewEvents.Loading -> showLoading(it.message)
|
||||
is RoomListViewEvents.Failure -> showFailure(it.throwable)
|
||||
is RoomListViewEvents.SelectRoom -> handleSelectRoom(it)
|
||||
is RoomListViewEvents.Done -> Unit
|
||||
is RoomListViewEvents.Loading -> showLoading(it.message)
|
||||
is RoomListViewEvents.Failure -> showFailure(it.throwable)
|
||||
is RoomListViewEvents.SelectRoom -> handleSelectRoom(it)
|
||||
is RoomListViewEvents.Done -> Unit
|
||||
is RoomListViewEvents.NavigateToMxToBottomSheet -> handleShowMxToLink(it.link)
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
|
@ -155,6 +156,10 @@ class RoomListFragment @Inject constructor(
|
|||
showErrorInSnackbar(throwable)
|
||||
}
|
||||
|
||||
private fun handleShowMxToLink(link: String) {
|
||||
navigator.openMatrixToBottomSheet(requireContext(), link)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
adapterInfosList.onEach { it.contentEpoxyController.removeModelBuildListener(modelBuildListener) }
|
||||
adapterInfosList.clear()
|
||||
|
@ -474,6 +479,10 @@ class RoomListFragment @Inject constructor(
|
|||
roomListViewModel.handle(RoomListAction.JoinSuggestedRoom(room.childRoomId, room.viaServers))
|
||||
}
|
||||
|
||||
override fun onSuggestedRoomClicked(room: SpaceChildInfo) {
|
||||
roomListViewModel.handle(RoomListAction.ShowRoomDetails(room.childRoomId, room.viaServers))
|
||||
}
|
||||
|
||||
override fun onRejectRoomInvitation(room: RoomSummary) {
|
||||
notificationDrawerManager.clearMemberShipNotificationForRoom(room.roomId)
|
||||
roomListViewModel.handle(RoomListAction.RejectInvitation(room))
|
||||
|
|
|
@ -26,4 +26,5 @@ interface RoomListListener : FilteredRoomFooterItem.FilteredRoomFooterItemListen
|
|||
fun onRejectRoomInvitation(room: RoomSummary)
|
||||
fun onAcceptRoomInvitation(room: RoomSummary)
|
||||
fun onJoinSuggestedRoom(room: SpaceChildInfo)
|
||||
fun onSuggestedRoomClicked(room: SpaceChildInfo)
|
||||
}
|
||||
|
|
|
@ -29,4 +29,5 @@ sealed class RoomListViewEvents : VectorViewEvents {
|
|||
|
||||
data class SelectRoom(val roomSummary: RoomSummary) : RoomListViewEvents()
|
||||
object Done : RoomListViewEvents()
|
||||
data class NavigateToMxToBottomSheet(val link: String) : RoomListViewEvents()
|
||||
}
|
||||
|
|
|
@ -161,6 +161,7 @@ class RoomListViewModel @Inject constructor(
|
|||
is RoomListAction.ToggleTag -> handleToggleTag(action)
|
||||
is RoomListAction.ToggleSection -> handleToggleSection(action.section)
|
||||
is RoomListAction.JoinSuggestedRoom -> handleJoinSuggestedRoom(action)
|
||||
is RoomListAction.ShowRoomDetails -> handleShowRoomDetails(action)
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
|
@ -289,6 +290,12 @@ class RoomListViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleShowRoomDetails(action: RoomListAction.ShowRoomDetails) {
|
||||
session.permalinkService().createRoomPermalink(action.roomId, action.viaServers)?.let {
|
||||
_viewEvents.post(RoomListViewEvents.NavigateToMxToBottomSheet(it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleToggleTag(action: RoomListAction.ToggleTag) {
|
||||
session.getRoom(action.roomId)?.let { room ->
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package im.vector.app.features.home.room.list
|
||||
|
||||
import android.view.View
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.Loading
|
||||
import im.vector.app.R
|
||||
|
@ -56,7 +55,7 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
|
|||
|
||||
fun createSuggestion(spaceChildInfo: SpaceChildInfo,
|
||||
suggestedRoomJoiningStates: Map<String, Async<Unit>>,
|
||||
onJoinClick: View.OnClickListener): VectorEpoxyModel<*> {
|
||||
listener: RoomListListener?): VectorEpoxyModel<*> {
|
||||
return SpaceChildInfoItem_()
|
||||
.id("sug_${spaceChildInfo.childRoomId}")
|
||||
.matrixItem(spaceChildInfo.toMatrixItem())
|
||||
|
@ -65,7 +64,8 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
|
|||
.buttonLabel(stringProvider.getString(R.string.join))
|
||||
.loading(suggestedRoomJoiningStates[spaceChildInfo.childRoomId] is Loading)
|
||||
.memberCount(spaceChildInfo.activeMemberCount ?: 0)
|
||||
.buttonClickListener(onJoinClick)
|
||||
.buttonClickListener(DebouncedClickListener({ listener?.onJoinSuggestedRoom(spaceChildInfo) }))
|
||||
.itemClickListener(DebouncedClickListener({ listener?.onSuggestedRoomClicked(spaceChildInfo) }))
|
||||
}
|
||||
|
||||
private fun createInvitationItem(roomSummary: RoomSummary,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -63,12 +62,8 @@ abstract class SpaceChildInfoItem : VectorEpoxyModel<SpaceChildInfoItem.Holder>(
|
|||
it.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||
itemLongClickListener?.onLongClick(it) ?: false
|
||||
}
|
||||
holder.titleView.text = matrixItem.getBestName()
|
||||
if (space) {
|
||||
avatarRenderer.renderSpace(matrixItem, holder.avatarImageView)
|
||||
} else {
|
||||
avatarRenderer.render(matrixItem, holder.avatarImageView)
|
||||
}
|
||||
holder.titleView.text = matrixItem.displayName ?: holder.rootView.context.getString(R.string.unnamed_room)
|
||||
avatarRenderer.render(matrixItem, holder.avatarImageView)
|
||||
|
||||
holder.descriptionText.text = span {
|
||||
span {
|
||||
|
|
|
@ -24,11 +24,7 @@ class SuggestedRoomListController(
|
|||
|
||||
override fun buildModels(data: SuggestedRoomInfo?) {
|
||||
data?.rooms?.forEach { info ->
|
||||
roomSummaryItemFactory.createSuggestion(info, data.joinEcho) {
|
||||
listener?.onJoinSuggestedRoom(info)
|
||||
}.let {
|
||||
add(it)
|
||||
}
|
||||
add(roomSummaryItemFactory.createSuggestion(info, data.joinEcho, listener))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,14 +41,15 @@ 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?,
|
||||
val alias: String?,
|
||||
val membership: Membership,
|
||||
val roomType: String?,
|
||||
val viaServers: List<String>?
|
||||
val viaServers: List<String>?,
|
||||
val isPublic: Boolean
|
||||
) : RoomInfoResult()
|
||||
|
||||
data class PartialInfo(
|
||||
|
|
|
@ -118,11 +118,9 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor(
|
|||
session.getRoom(permalinkData.roomIdOrAlias)
|
||||
}
|
||||
?.roomSummary()
|
||||
// don't take if not active, as it could be outdated
|
||||
?.takeIf { it.membership.isActive() }
|
||||
// XXX fix that
|
||||
val forceRefresh = true
|
||||
if (!forceRefresh && knownRoom != null) {
|
||||
// don't take if not Join, as it could be outdated
|
||||
?.takeIf { it.membership == Membership.JOIN }
|
||||
if (knownRoom != null) {
|
||||
setState {
|
||||
copy(
|
||||
roomPeekResult = Success(
|
||||
|
@ -134,7 +132,8 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor(
|
|||
alias = knownRoom.canonicalAlias,
|
||||
membership = knownRoom.membership,
|
||||
roomType = knownRoom.roomType,
|
||||
viaServers = null
|
||||
viaServers = null,
|
||||
isPublic = knownRoom.isPublic
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -150,7 +149,8 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor(
|
|||
alias = peekResult.alias,
|
||||
membership = knownRoom?.membership ?: Membership.NONE,
|
||||
roomType = peekResult.roomType,
|
||||
viaServers = peekResult.viaServers.takeIf { it.isNotEmpty() } ?: permalinkData.viaParameters
|
||||
viaServers = peekResult.viaServers.takeIf { it.isNotEmpty() } ?: permalinkData.viaParameters,
|
||||
isPublic = peekResult.isPublic
|
||||
).also {
|
||||
peekResult.someMembers?.let { checkForKnownMembers(it) }
|
||||
}
|
||||
|
|
|
@ -39,7 +39,8 @@ import org.matrix.android.sdk.api.session.room.model.RoomType
|
|||
import javax.inject.Inject
|
||||
|
||||
class MatrixToRoomSpaceFragment @Inject constructor(
|
||||
private val avatarRenderer: AvatarRenderer
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val spaceCardRenderer: SpaceCardRenderer
|
||||
) : VectorBaseFragment<FragmentMatrixToRoomSpaceCardBinding>() {
|
||||
|
||||
private val sharedViewModel: MatrixToBottomSheetViewModel by parentFragmentViewModel()
|
||||
|
@ -78,12 +79,19 @@ 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)
|
||||
views.matrixToAccessImage.isVisible = true
|
||||
if (peek.isPublic) {
|
||||
views.matrixToAccessText.setTextOrHide(context?.getString(R.string.public_space))
|
||||
views.matrixToAccessImage.setImageResource(R.drawable.ic_public_room)
|
||||
} else {
|
||||
views.matrixToAccessText.setTextOrHide(context?.getString(R.string.private_space))
|
||||
views.matrixToAccessImage.setImageResource(R.drawable.ic_room_private)
|
||||
}
|
||||
} else {
|
||||
views.matrixToBetaTag.isVisible = false
|
||||
avatarRenderer.render(matrixItem, views.matrixToCardAvatar)
|
||||
}
|
||||
views.matrixToCardNameText.setTextOrHide(peek.name)
|
||||
views.matrixToCardAliasText.setTextOrHide(peek.alias)
|
||||
|
@ -166,25 +174,12 @@ class MatrixToRoomSpaceFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
val images = listOf(views.knownMember1, views.knownMember2, views.knownMember3, views.knownMember4, views.knownMember5)
|
||||
listOf(views.knownMember1, views.knownMember2, views.knownMember3, views.knownMember4, views.knownMember5)
|
||||
.onEach { it.isGone = true }
|
||||
when (state.peopleYouKnow) {
|
||||
is Success -> {
|
||||
val someYouKnow = state.peopleYouKnow.invoke()
|
||||
if (someYouKnow.isEmpty()) {
|
||||
views.peopleYouMayKnowText.isVisible = false
|
||||
} else {
|
||||
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()
|
||||
)
|
||||
)
|
||||
}
|
||||
spaceCardRenderer.renderPeopleYouKnow(views, someYouKnow)
|
||||
}
|
||||
else -> {
|
||||
views.peopleYouMayKnowText.isVisible = false
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* 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.matrixto
|
||||
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.setTextOrHide
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.databinding.FragmentMatrixToRoomSpaceCardBinding
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
|
||||
import im.vector.app.features.home.room.detail.timeline.tools.createLinkMovementMethod
|
||||
import im.vector.app.features.home.room.detail.timeline.tools.linkify
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import javax.inject.Inject
|
||||
|
||||
class SpaceCardRenderer @Inject constructor(
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val stringProvider: StringProvider
|
||||
) {
|
||||
|
||||
fun render(spaceSummary: RoomSummary?,
|
||||
peopleYouKnow: List<User>,
|
||||
matrixLinkCallback: TimelineEventController.UrlClickCallback?,
|
||||
inCard: FragmentMatrixToRoomSpaceCardBinding) {
|
||||
if (spaceSummary == null) {
|
||||
inCard.matrixToCardContentVisibility.isVisible = false
|
||||
inCard.matrixToCardButtonLoading.isVisible = true
|
||||
} else {
|
||||
inCard.matrixToCardContentVisibility.isVisible = true
|
||||
inCard.matrixToCardButtonLoading.isVisible = false
|
||||
avatarRenderer.render(spaceSummary.toMatrixItem(), inCard.matrixToCardAvatar)
|
||||
inCard.matrixToCardNameText.text = spaceSummary.name
|
||||
inCard.matrixToBetaTag.isVisible = true
|
||||
inCard.matrixToCardAliasText.setTextOrHide(spaceSummary.canonicalAlias)
|
||||
inCard.matrixToCardDescText.setTextOrHide(spaceSummary.topic.linkify(matrixLinkCallback))
|
||||
if (spaceSummary.isPublic) {
|
||||
inCard.matrixToAccessText.setTextOrHide(stringProvider.getString(R.string.public_space))
|
||||
inCard.matrixToAccessImage.isVisible = true
|
||||
inCard.matrixToAccessImage.setImageResource(R.drawable.ic_public_room)
|
||||
} else {
|
||||
inCard.matrixToAccessText.setTextOrHide(stringProvider.getString(R.string.private_space))
|
||||
inCard.matrixToAccessImage.isVisible = true
|
||||
inCard.matrixToAccessImage.setImageResource(R.drawable.ic_room_private)
|
||||
}
|
||||
val memberCount = spaceSummary.otherMemberIds.size
|
||||
if (memberCount != 0) {
|
||||
inCard.matrixToMemberPills.isVisible = true
|
||||
inCard.spaceChildMemberCountText.text = stringProvider.getQuantityString(R.plurals.room_title_members, memberCount, memberCount)
|
||||
} else {
|
||||
// hide the pill
|
||||
inCard.matrixToMemberPills.isVisible = false
|
||||
}
|
||||
|
||||
renderPeopleYouKnow(inCard, peopleYouKnow.map { it.toMatrixItem() })
|
||||
}
|
||||
inCard.matrixToCardDescText.movementMethod = createLinkMovementMethod(object : TimelineEventController.UrlClickCallback {
|
||||
override fun onUrlClicked(url: String, title: String): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onUrlLongClicked(url: String): Boolean {
|
||||
// host.callback?.onUrlInTopicLongClicked(url)
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun render(spaceChildInfo: SpaceChildInfo?,
|
||||
peopleYouKnow: List<User>,
|
||||
matrixLinkCallback: TimelineEventController.UrlClickCallback?,
|
||||
inCard: FragmentMatrixToRoomSpaceCardBinding) {
|
||||
if (spaceChildInfo == null) {
|
||||
inCard.matrixToCardContentVisibility.isVisible = false
|
||||
inCard.matrixToCardButtonLoading.isVisible = true
|
||||
} else {
|
||||
inCard.matrixToCardContentVisibility.isVisible = true
|
||||
inCard.matrixToCardButtonLoading.isVisible = false
|
||||
avatarRenderer.render(spaceChildInfo.toMatrixItem(), inCard.matrixToCardAvatar)
|
||||
inCard.matrixToCardNameText.setTextOrHide(spaceChildInfo.name)
|
||||
inCard.matrixToBetaTag.isVisible = true
|
||||
inCard.matrixToCardAliasText.setTextOrHide(spaceChildInfo.canonicalAlias)
|
||||
inCard.matrixToCardDescText.setTextOrHide(spaceChildInfo.topic?.linkify(matrixLinkCallback))
|
||||
if (spaceChildInfo.worldReadable) {
|
||||
inCard.matrixToAccessText.setTextOrHide(stringProvider.getString(R.string.public_space))
|
||||
inCard.matrixToAccessImage.isVisible = true
|
||||
inCard.matrixToAccessImage.setImageResource(R.drawable.ic_public_room)
|
||||
} else {
|
||||
inCard.matrixToAccessText.setTextOrHide(stringProvider.getString(R.string.private_space))
|
||||
inCard.matrixToAccessImage.isVisible = true
|
||||
inCard.matrixToAccessImage.setImageResource(R.drawable.ic_room_private)
|
||||
}
|
||||
val memberCount = spaceChildInfo.activeMemberCount ?: 0
|
||||
if (memberCount != 0) {
|
||||
inCard.matrixToMemberPills.isVisible = true
|
||||
inCard.spaceChildMemberCountText.text = stringProvider.getQuantityString(R.plurals.room_title_members, memberCount, memberCount)
|
||||
} else {
|
||||
// hide the pill
|
||||
inCard.matrixToMemberPills.isVisible = false
|
||||
}
|
||||
|
||||
renderPeopleYouKnow(inCard, peopleYouKnow.map { it.toMatrixItem() })
|
||||
}
|
||||
}
|
||||
|
||||
fun renderPeopleYouKnow(inCard: FragmentMatrixToRoomSpaceCardBinding, peopleYouKnow: List<MatrixItem.UserItem>) {
|
||||
val images = listOf(
|
||||
inCard.knownMember1,
|
||||
inCard.knownMember2,
|
||||
inCard.knownMember3,
|
||||
inCard.knownMember4,
|
||||
inCard.knownMember5
|
||||
).onEach { it.isGone = true }
|
||||
|
||||
if (peopleYouKnow.isEmpty()) {
|
||||
inCard.peopleYouMayKnowText.isVisible = false
|
||||
} else {
|
||||
peopleYouKnow.forEachIndexed { index, item ->
|
||||
images[index].isVisible = true
|
||||
avatarRenderer.render(item, images[index])
|
||||
}
|
||||
inCard.peopleYouMayKnowText.setTextOrHide(
|
||||
stringProvider.getQuantityString(R.plurals.space_people_you_know,
|
||||
peopleYouKnow.count(),
|
||||
peopleYouKnow.count()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -245,7 +245,7 @@ class ImageContentRenderer @Inject constructor(private val localFilesHelper: Loc
|
|||
val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver()
|
||||
val resolvedUrl = when (mode) {
|
||||
Mode.FULL_SIZE,
|
||||
Mode.STICKER -> resolveUrl(data)
|
||||
Mode.STICKER -> resolveUrl(data)
|
||||
Mode.THUMBNAIL -> contentUrlResolver.resolveThumbnail(data.url, size.width, size.height, ContentUrlResolver.ThumbnailMethod.SCALE)
|
||||
}
|
||||
// Fallback to base url
|
||||
|
@ -313,7 +313,7 @@ class ImageContentRenderer @Inject constructor(private val localFilesHelper: Loc
|
|||
finalHeight = min(maxImageWidth * height / width, maxImageHeight)
|
||||
finalWidth = finalHeight * width / height
|
||||
}
|
||||
Mode.STICKER -> {
|
||||
Mode.STICKER -> {
|
||||
// limit on width
|
||||
val maxWidthDp = min(dimensionConverter.dpToPx(120), maxImageWidth / 2)
|
||||
finalWidth = min(dimensionConverter.dpToPx(width), maxWidthDp)
|
||||
|
|
|
@ -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() }
|
||||
|
|
|
@ -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() })
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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() }
|
||||
}
|
||||
|
|
|
@ -122,13 +122,15 @@ class SpaceDirectoryController @Inject constructor(
|
|||
val isSpace = info.roomType == RoomType.SPACE
|
||||
val isJoined = data?.joinedRoomsIds?.contains(info.childRoomId) == true
|
||||
val isLoading = data?.changeMembershipStates?.get(info.childRoomId)?.isInProgress() ?: false
|
||||
// if it's known use that matrixItem because it would have a better computed name
|
||||
val matrixItem = data?.knownRoomSummaries?.find { it.roomId == info.childRoomId }?.toMatrixItem()
|
||||
?: info.toMatrixItem()
|
||||
spaceChildInfoItem {
|
||||
id(info.childRoomId)
|
||||
matrixItem(info.toMatrixItem())
|
||||
matrixItem(matrixItem)
|
||||
avatarRenderer(host.avatarRenderer)
|
||||
topic(info.topic)
|
||||
memberCount(info.activeMemberCount ?: 0)
|
||||
space(isSpace)
|
||||
loading(isLoading)
|
||||
buttonLabel(
|
||||
if (isJoined) host.stringProvider.getString(R.string.action_open)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package im.vector.app.features.spaces.explore
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.LayoutInflater
|
||||
|
@ -23,19 +24,33 @@ import android.view.Menu
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.text.toSpannable
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.dialogs.withColoredButton
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.OnBackPressed
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.utils.colorizeMatchingText
|
||||
import im.vector.app.core.utils.isValidUrl
|
||||
import im.vector.app.core.utils.openUrlInExternalBrowser
|
||||
import im.vector.app.databinding.FragmentRoomDirectoryPickerBinding
|
||||
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
|
||||
import im.vector.app.features.matrixto.SpaceCardRenderer
|
||||
import im.vector.app.features.permalink.PermalinkHandler
|
||||
import im.vector.app.features.spaces.manage.ManageType
|
||||
import im.vector.app.features.spaces.manage.SpaceManageActivity
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||
import java.net.URL
|
||||
import javax.inject.Inject
|
||||
|
||||
@Parcelize
|
||||
|
@ -44,9 +59,13 @@ data class SpaceDirectoryArgs(
|
|||
) : Parcelable
|
||||
|
||||
class SpaceDirectoryFragment @Inject constructor(
|
||||
private val epoxyController: SpaceDirectoryController
|
||||
private val epoxyController: SpaceDirectoryController,
|
||||
private val permalinkHandler: PermalinkHandler,
|
||||
private val spaceCardRenderer: SpaceCardRenderer,
|
||||
private val colorProvider: ColorProvider
|
||||
) : VectorBaseFragment<FragmentRoomDirectoryPickerBinding>(),
|
||||
SpaceDirectoryController.InteractionListener,
|
||||
TimelineEventController.UrlClickCallback,
|
||||
OnBackPressed {
|
||||
|
||||
override fun getMenuRes() = R.menu.menu_space_directory
|
||||
|
@ -71,6 +90,9 @@ class SpaceDirectoryFragment @Inject constructor(
|
|||
viewModel.selectSubscribe(this, SpaceDirectoryState::canAddRooms) {
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
|
||||
views.spaceCard.matrixToCardMainButton.isVisible = false
|
||||
views.spaceCard.matrixToCardSecondaryButton.isVisible = false
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -82,10 +104,21 @@ class SpaceDirectoryFragment @Inject constructor(
|
|||
override fun invalidate() = withState(viewModel) { state ->
|
||||
epoxyController.setData(state)
|
||||
|
||||
val title = state.hierarchyStack.lastOrNull()?.let { currentParent ->
|
||||
val currentParent = state.hierarchyStack.lastOrNull()?.let { currentParent ->
|
||||
state.spaceSummaryApiResult.invoke()?.firstOrNull { it.childRoomId == currentParent }
|
||||
}?.name ?: getString(R.string.space_explore_activity_title)
|
||||
views.toolbar.title = title
|
||||
}
|
||||
|
||||
if (currentParent == null) {
|
||||
val title = getString(R.string.space_explore_activity_title)
|
||||
views.toolbar.title = title
|
||||
|
||||
spaceCardRenderer.render(state.spaceSummary.invoke(), emptyList(), this, views.spaceCard)
|
||||
} else {
|
||||
val title = currentParent.name ?: currentParent.canonicalAlias ?: getString(R.string.space_explore_activity_title)
|
||||
views.toolbar.title = title
|
||||
|
||||
spaceCardRenderer.render(currentParent, emptyList(), this, views.spaceCard)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) = withState(viewModel) { state ->
|
||||
|
@ -96,7 +129,7 @@ class SpaceDirectoryFragment @Inject constructor(
|
|||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.spaceAddRoom -> {
|
||||
R.id.spaceAddRoom -> {
|
||||
withState(viewModel) { state ->
|
||||
addExistingRooms(state.spaceId)
|
||||
}
|
||||
|
@ -138,6 +171,44 @@ class SpaceDirectoryFragment @Inject constructor(
|
|||
override fun addExistingRooms(spaceId: String) {
|
||||
addExistingRoomActivityResult.launch(SpaceManageActivity.newIntent(requireContext(), spaceId, ManageType.AddRooms))
|
||||
}
|
||||
|
||||
override fun onUrlClicked(url: String, title: String): Boolean {
|
||||
permalinkHandler
|
||||
.launch(requireActivity(), url, null)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { managed ->
|
||||
if (!managed) {
|
||||
if (title.isValidUrl() && url.isValidUrl() && URL(title).host != URL(url).host) {
|
||||
AlertDialog.Builder(requireActivity())
|
||||
.setTitle(R.string.external_link_confirmation_title)
|
||||
.setMessage(
|
||||
getString(R.string.external_link_confirmation_message, title, url)
|
||||
.toSpannable()
|
||||
.colorizeMatchingText(url, colorProvider.getColorFromAttribute(R.attr.riotx_text_primary_body_contrast))
|
||||
.colorizeMatchingText(title, colorProvider.getColorFromAttribute(R.attr.riotx_text_primary_body_contrast))
|
||||
)
|
||||
.setPositiveButton(R.string._continue) { _, _ ->
|
||||
openUrlInExternalBrowser(requireContext(), url)
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
.withColoredButton(DialogInterface.BUTTON_NEGATIVE)
|
||||
} else {
|
||||
// Open in external browser, in a new Tab
|
||||
openUrlInExternalBrowser(requireContext(), url)
|
||||
}
|
||||
}
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
// In fact it is always managed
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onUrlLongClicked(url: String): Boolean {
|
||||
// nothing?
|
||||
return false
|
||||
}
|
||||
// override fun navigateToRoom(roomId: String) {
|
||||
// viewModel.handle(SpaceDirectoryViewAction.NavigateToRoom(roomId))
|
||||
// }
|
||||
|
|
|
@ -37,7 +37,9 @@ data class SpaceDirectoryState(
|
|||
val joinedRoomsIds: Set<String> = emptySet(),
|
||||
// keys are room alias or roomId
|
||||
val changeMembershipStates: Map<String, ChangeMembershipState> = emptyMap(),
|
||||
val canAddRooms: Boolean = false
|
||||
val canAddRooms: Boolean = false,
|
||||
// cached room summaries of known rooms
|
||||
val knownRoomSummaries : List<RoomSummary> = emptyList()
|
||||
) : MvRxState {
|
||||
constructor(args: SpaceDirectoryArgs) : this(
|
||||
spaceId = args.spaceId
|
||||
|
|
|
@ -66,7 +66,8 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
|
|||
val spaceSum = session.getRoomSummary(initialState.spaceId)
|
||||
setState {
|
||||
copy(
|
||||
childList = spaceSum?.spaceChildren ?: emptyList()
|
||||
childList = spaceSum?.spaceChildren ?: emptyList(),
|
||||
spaceSummary = spaceSum?.let { Success(spaceSum) } ?: Loading()
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -101,9 +102,14 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
|
|||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val query = session.spaceService().querySpaceChildren(initialState.spaceId)
|
||||
val knownSummaries = query.second.mapNotNull {
|
||||
session.getRoomSummary(it.childRoomId)
|
||||
?.takeIf { it.membership == Membership.JOIN } // only take if joined because it will be up to date (synced)
|
||||
}
|
||||
setState {
|
||||
copy(
|
||||
spaceSummaryApiResult = Success(query.second)
|
||||
spaceSummaryApiResult = Success(query.second),
|
||||
knownRoomSummaries = knownSummaries
|
||||
)
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
|
@ -148,7 +154,7 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
|
|||
copy(hierarchyStack = hierarchyStack + listOf(action.spaceChildInfo.childRoomId))
|
||||
}
|
||||
}
|
||||
SpaceDirectoryViewAction.HandleBack -> {
|
||||
SpaceDirectoryViewAction.HandleBack -> {
|
||||
withState {
|
||||
if (it.hierarchyStack.isEmpty()) {
|
||||
_viewEvents.post(SpaceDirectoryViewEvents.Dismiss)
|
||||
|
@ -161,20 +167,20 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
is SpaceDirectoryViewAction.JoinOrOpen -> {
|
||||
is SpaceDirectoryViewAction.JoinOrOpen -> {
|
||||
handleJoinOrOpen(action.spaceChildInfo)
|
||||
}
|
||||
is SpaceDirectoryViewAction.NavigateToRoom -> {
|
||||
is SpaceDirectoryViewAction.NavigateToRoom -> {
|
||||
_viewEvents.post(SpaceDirectoryViewEvents.NavigateToRoom(action.roomId))
|
||||
}
|
||||
is SpaceDirectoryViewAction.ShowDetails -> {
|
||||
is SpaceDirectoryViewAction.ShowDetails -> {
|
||||
// This is temporary for now to at least display something for the space beta
|
||||
// It's not ideal as it's doing some peeking that is not needed.
|
||||
session.permalinkService().createRoomPermalink(action.spaceChildInfo.childRoomId)?.let {
|
||||
_viewEvents.post(SpaceDirectoryViewEvents.NavigateToMxToBottomSheet(it))
|
||||
}
|
||||
}
|
||||
SpaceDirectoryViewAction.Retry -> {
|
||||
SpaceDirectoryViewAction.Retry -> {
|
||||
refreshFromApi()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import android.os.Parcelable
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Loading
|
||||
|
@ -33,12 +32,12 @@ import com.airbnb.mvrx.fragmentViewModel
|
|||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ScreenComponent
|
||||
import im.vector.app.core.extensions.setTextOrHide
|
||||
import im.vector.app.core.platform.ButtonStateView
|
||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.databinding.BottomSheetInvitedToSpaceBinding
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.matrixto.SpaceCardRenderer
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import javax.inject.Inject
|
||||
|
@ -60,6 +59,9 @@ class SpaceInviteBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetIn
|
|||
@Inject
|
||||
lateinit var avatarRenderer: AvatarRenderer
|
||||
|
||||
@Inject
|
||||
lateinit var spaceCardRenderer: SpaceCardRenderer
|
||||
|
||||
private val viewModel: SpaceInviteBottomSheetViewModel by fragmentViewModel(SpaceInviteBottomSheetViewModel::class)
|
||||
|
||||
@Inject lateinit var viewModelFactory: SpaceInviteBottomSheetViewModel.Factory
|
||||
|
@ -133,12 +135,7 @@ class SpaceInviteBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetIn
|
|||
views.inviterMxid.isVisible = false
|
||||
}
|
||||
|
||||
views.spaceCard.matrixToCardContentVisibility.isVisible = true
|
||||
summary?.toMatrixItem()?.let { avatarRenderer.renderSpace(it, views.spaceCard.matrixToCardAvatar) }
|
||||
views.spaceCard.matrixToCardNameText.text = summary?.displayName
|
||||
views.spaceCard.matrixToBetaTag.isVisible = true
|
||||
views.spaceCard.matrixToCardAliasText.setTextOrHide(summary?.canonicalAlias)
|
||||
views.spaceCard.matrixToCardDescText.setTextOrHide(summary?.topic)
|
||||
spaceCardRenderer.render(summary, state.peopleYouKnow.invoke().orEmpty(), null, views.spaceCard)
|
||||
|
||||
views.spaceCard.matrixToCardMainButton.button.text = getString(R.string.accept)
|
||||
views.spaceCard.matrixToCardSecondaryButton.button.text = getString(R.string.decline)
|
||||
|
@ -178,40 +175,6 @@ class SpaceInviteBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetIn
|
|||
views.spaceCard.matrixToCardSecondaryButton.button.isEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
val memberCount = summary?.otherMemberIds?.size ?: 0
|
||||
if (memberCount != 0) {
|
||||
views.spaceCard.matrixToMemberPills.isVisible = true
|
||||
views.spaceCard.spaceChildMemberCountText.text = resources.getQuantityString(R.plurals.room_title_members, memberCount, memberCount)
|
||||
} else {
|
||||
// hide the pill
|
||||
views.spaceCard.matrixToMemberPills.isVisible = false
|
||||
}
|
||||
|
||||
val peopleYouKnow = state.peopleYouKnow.invoke().orEmpty()
|
||||
|
||||
val images = listOf(
|
||||
views.spaceCard.knownMember1,
|
||||
views.spaceCard.knownMember2,
|
||||
views.spaceCard.knownMember3,
|
||||
views.spaceCard.knownMember4,
|
||||
views.spaceCard.knownMember5
|
||||
).onEach { it.isGone = true }
|
||||
|
||||
if (peopleYouKnow.isEmpty()) {
|
||||
views.spaceCard.peopleYouMayKnowText.isVisible = false
|
||||
} else {
|
||||
peopleYouKnow.forEachIndexed { index, item ->
|
||||
images[index].isVisible = true
|
||||
avatarRenderer.render(item.toMatrixItem(), images[index])
|
||||
}
|
||||
views.spaceCard.peopleYouMayKnowText.setTextOrHide(
|
||||
resources.getQuantityString(R.plurals.space_people_you_know,
|
||||
peopleYouKnow.count(),
|
||||
peopleYouKnow.count()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetInvitedToSpaceBinding {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -71,7 +71,7 @@ class SpaceSettingsController @Inject constructor(
|
|||
// 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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
android:id="@+id/matrixToCardAliasText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
android:textAlignment="textStart"
|
||||
|
@ -70,12 +70,43 @@
|
|||
tools:text="@sample/rooms.json/data/alias"
|
||||
tools:visibility="visible" />
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/matrixToAccessImage"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/matrixToAccessText"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/matrixToAccessText"
|
||||
app:tint="?riotx_text_secondary"
|
||||
tools:src="@drawable/ic_public_room"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/matrixToAccessText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toEndOf="@id/matrixToAccessImage"
|
||||
app:layout_constraintTop_toBottomOf="@id/matrixToCardAliasText"
|
||||
app:layout_goneMarginTop="0dp"
|
||||
tools:text="Public Space"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/matrixToMemberPills"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@drawable/pill_receipt"
|
||||
android:backgroundTint="?riotx_reaction_background_off"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="12dp"
|
||||
|
@ -85,7 +116,7 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/matrixToCardAliasText">
|
||||
app:layout_constraintTop_toBottomOf="@id/matrixToAccessText">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/spaceChildMemberCountIcon"
|
||||
|
@ -113,6 +144,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:autoLink="web"
|
||||
android:maxLines="4"
|
||||
android:textAlignment="textStart"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
|
|
|
@ -7,29 +7,56 @@
|
|||
android:layout_height="match_parent"
|
||||
android:background="?riotx_background">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
style="@style/VectorAppBarLayoutStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="4dp">
|
||||
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:id="@+id/spaceExploreCollapsingToolbarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="4dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
android:layout_height="match_parent"
|
||||
android:theme="@style/Vector.Toolbar.Profile"
|
||||
app:contentScrim="?riotx_background"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
|
||||
app:scrimAnimationDuration="250"
|
||||
app:scrimVisibleHeightTrigger="120dp"
|
||||
app:titleEnabled="false"
|
||||
app:toolbarId="@+id/toolbar">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/roomDirectoryPickerList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar"
|
||||
tools:listitem="@layout/item_room_directory" />
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="40dp">
|
||||
|
||||
<include
|
||||
android:id="@+id/spaceCard"
|
||||
layout="@layout/fragment_matrix_to_room_space_card" />
|
||||
</FrameLayout>
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="4dp"
|
||||
app:layout_collapseMode="pin"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/roomDirectoryPickerList"
|
||||
android:background="?riotx_background"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:listitem="@layout/item_room_directory" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -3267,6 +3267,7 @@
|
|||
<string name="a11y_rule_notify_off">Do not notify</string>
|
||||
<string name="a11y_view_read_receipts">View read receipts</string>
|
||||
<string name="a11y_public_room">This room is public</string>
|
||||
<string name="a11y_public_space">This Space is public</string>
|
||||
|
||||
<string name="dev_tools_menu_name">Dev Tools</string>
|
||||
<string name="dev_tools_explore_room_state">Explore Room State</string>
|
||||
|
@ -3298,6 +3299,8 @@
|
|||
<string name="event_status_delete_all_failed_dialog_title">Delete unsent messages</string>
|
||||
<string name="event_status_delete_all_failed_dialog_message">Are you sure you want to delete all unsent messages in this room?</string>
|
||||
|
||||
<string name="public_space">Public space</string>
|
||||
<string name="private_space">Private space</string>
|
||||
<string name="add_space">Add Space</string>
|
||||
<string name="your_public_space">Your public space</string>
|
||||
<string name="your_private_space">Your private space</string>
|
||||
|
@ -3393,4 +3396,5 @@
|
|||
<string name="this_space_has_no_rooms_not_admin">Some rooms may be hidden because they’re private and you need an invite.\nYou don’t have permission to add rooms.</string>
|
||||
<string name="this_space_has_no_rooms_admin">Some rooms may be hidden because they’re private and you need an invite.</string>
|
||||
|
||||
<string name="unnamed_room">Unnamed Room</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue