Merge pull request #2369 from vector-im/feature/bca/quick_invite_room_tile
EmptyRoom tile with quick actions
This commit is contained in:
commit
4df68479ac
|
@ -5,6 +5,7 @@ Features ✨:
|
|||
-
|
||||
|
||||
Improvements 🙌:
|
||||
- New room creation tile with quick action (#2346)
|
||||
- Open an existing DM instead of creating a new one (#2319)
|
||||
- Ask for explicit user consent to send their contact details to the identity server (#2375)
|
||||
- Handle events of type "m.room.server_acl" (#890)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.matrix.android.sdk.api.session.permalinks
|
||||
|
||||
import android.text.Spannable
|
||||
import org.matrix.android.sdk.api.MatrixPatterns
|
||||
|
||||
/**
|
||||
* MatrixLinkify take a piece of text and turns all of the
|
||||
|
@ -35,7 +36,7 @@ object MatrixLinkify {
|
|||
* I disable it because it mess up with pills, and even with pills, it does not work correctly:
|
||||
* The url is not correct. Ex: for @user:matrix.org, the url will be @user:matrix.org, instead of a matrix.to
|
||||
*/
|
||||
/*
|
||||
|
||||
// sanity checks
|
||||
if (spannable.isEmpty()) {
|
||||
return false
|
||||
|
@ -48,14 +49,21 @@ object MatrixLinkify {
|
|||
val startPos = match.range.first
|
||||
if (startPos == 0 || text[startPos - 1] != '/') {
|
||||
val endPos = match.range.last + 1
|
||||
val url = text.substring(match.range)
|
||||
var url = text.substring(match.range)
|
||||
if (MatrixPatterns.isUserId(url)
|
||||
|| MatrixPatterns.isRoomAlias(url)
|
||||
|| MatrixPatterns.isRoomId(url)
|
||||
|| MatrixPatterns.isGroupId(url)
|
||||
|| MatrixPatterns.isEventId(url)) {
|
||||
url = PermalinkService.MATRIX_TO_URL_BASE + url
|
||||
}
|
||||
val span = MatrixPermalinkSpan(url, callback)
|
||||
spannable.setSpan(span, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasMatch
|
||||
*/
|
||||
return false
|
||||
|
||||
// return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ import org.matrix.android.sdk.internal.database.query.getOrNull
|
|||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
|
||||
import io.realm.Realm
|
||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.query.where
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class RoomAvatarResolver @Inject constructor(@UserId private val userId: String) {
|
||||
|
@ -46,12 +48,15 @@ internal class RoomAvatarResolver @Inject constructor(@UserId private val userId
|
|||
val roomMembers = RoomMemberHelper(realm, roomId)
|
||||
val members = roomMembers.queryActiveRoomMembersEvent().findAll()
|
||||
// detect if it is a room with no more than 2 members (i.e. an alone or a 1:1 chat)
|
||||
val isDirectRoom = RoomSummaryEntity.where(realm, roomId).findFirst()?.isDirect ?: false
|
||||
if (isDirectRoom) {
|
||||
if (members.size == 1) {
|
||||
res = members.firstOrNull()?.avatarUrl
|
||||
} else if (members.size == 2) {
|
||||
val firstOtherMember = members.where().notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId).findFirst()
|
||||
res = firstOtherMember?.avatarUrl
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
package org.matrix.android.sdk.internal.session.room.alias
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import io.realm.Realm
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.query.findByAlias
|
||||
|
@ -24,8 +27,6 @@ import org.matrix.android.sdk.internal.di.SessionDatabase
|
|||
import org.matrix.android.sdk.internal.network.executeRequest
|
||||
import org.matrix.android.sdk.internal.session.room.RoomAPI
|
||||
import org.matrix.android.sdk.internal.task.Task
|
||||
import io.realm.Realm
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetRoomIdByAliasTask : Task<GetRoomIdByAliasTask.Params, Optional<String>> {
|
||||
|
@ -50,9 +51,11 @@ internal class DefaultGetRoomIdByAliasTask @Inject constructor(
|
|||
} else if (!params.searchOnServer) {
|
||||
Optional.from<String>(null)
|
||||
} else {
|
||||
roomId = executeRequest<RoomAliasDescription>(eventBus) {
|
||||
roomId = tryOrNull("## Failed to get roomId from alias") {
|
||||
executeRequest<RoomAliasDescription>(eventBus) {
|
||||
apiCall = roomAPI.getRoomIdByAlias(params.roomAlias)
|
||||
}.roomId
|
||||
}
|
||||
}?.roomId
|
||||
Optional.from(roomId)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,6 +93,8 @@ internal class RoomDisplayNameResolver @Inject constructor(
|
|||
}
|
||||
} else if (roomEntity?.membership == Membership.JOIN) {
|
||||
val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst()
|
||||
val invitedCount = roomSummary?.invitedMembersCount ?: 0
|
||||
val joinedCount = roomSummary?.joinedMembersCount ?: 0
|
||||
val otherMembersSubset: List<RoomMemberSummaryEntity> = if (roomSummary?.heroes?.isNotEmpty() == true) {
|
||||
roomSummary.heroes.mapNotNull { userId ->
|
||||
roomMembers.getLastRoomMember(userId)?.takeIf {
|
||||
|
@ -102,22 +104,49 @@ internal class RoomDisplayNameResolver @Inject constructor(
|
|||
} else {
|
||||
activeMembers.where()
|
||||
.notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId)
|
||||
.limit(3)
|
||||
.limit(5)
|
||||
.findAll()
|
||||
.createSnapshot()
|
||||
}
|
||||
val otherMembersCount = otherMembersSubset.count()
|
||||
name = when (otherMembersCount) {
|
||||
0 -> stringProvider.getString(R.string.room_displayname_empty_room)
|
||||
0 -> {
|
||||
stringProvider.getString(R.string.room_displayname_empty_room)
|
||||
// TODO (was xx and yyy) ...
|
||||
}
|
||||
1 -> resolveRoomMemberName(otherMembersSubset[0], roomMembers)
|
||||
2 -> stringProvider.getString(R.string.room_displayname_two_members,
|
||||
2 -> {
|
||||
stringProvider.getString(R.string.room_displayname_two_members,
|
||||
resolveRoomMemberName(otherMembersSubset[0], roomMembers),
|
||||
resolveRoomMemberName(otherMembersSubset[1], roomMembers)
|
||||
)
|
||||
else -> stringProvider.getQuantityString(R.plurals.room_displayname_three_and_more_members,
|
||||
roomMembers.getNumberOfJoinedMembers() - 1,
|
||||
}
|
||||
3 -> {
|
||||
stringProvider.getString(R.string.room_displayname_3_members,
|
||||
resolveRoomMemberName(otherMembersSubset[0], roomMembers),
|
||||
roomMembers.getNumberOfJoinedMembers() - 1)
|
||||
resolveRoomMemberName(otherMembersSubset[1], roomMembers),
|
||||
resolveRoomMemberName(otherMembersSubset[2], roomMembers)
|
||||
)
|
||||
}
|
||||
4 -> {
|
||||
stringProvider.getString(R.string.room_displayname_4_members,
|
||||
resolveRoomMemberName(otherMembersSubset[0], roomMembers),
|
||||
resolveRoomMemberName(otherMembersSubset[1], roomMembers),
|
||||
resolveRoomMemberName(otherMembersSubset[2], roomMembers),
|
||||
resolveRoomMemberName(otherMembersSubset[3], roomMembers)
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
val remainingCount = invitedCount + joinedCount - otherMembersCount + 1
|
||||
stringProvider.getQuantityString(
|
||||
R.plurals.room_displayname_four_and_more_members,
|
||||
remainingCount,
|
||||
resolveRoomMemberName(otherMembersSubset[0], roomMembers),
|
||||
resolveRoomMemberName(otherMembersSubset[1], roomMembers),
|
||||
resolveRoomMemberName(otherMembersSubset[2], roomMembers),
|
||||
remainingCount
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return name ?: roomId
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.matrix.android.sdk.internal.session.room.membership
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
|
||||
|
@ -25,8 +27,6 @@ import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFie
|
|||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.query.getOrNull
|
||||
import org.matrix.android.sdk.internal.database.query.where
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
|
||||
/**
|
||||
* This class is an helper around STATE_ROOM_MEMBER events.
|
||||
|
|
|
@ -175,13 +175,22 @@
|
|||
|
||||
<!-- The 2 parameters will be members' name -->
|
||||
<string name="room_displayname_two_members">%1$s and %2$s</string>
|
||||
|
||||
<!-- The 3 parameters will be members' name -->
|
||||
<string name="room_displayname_3_members">%1$s, %2$s and %3$s</string>
|
||||
<!-- The 4 parameters will be members' name -->
|
||||
<string name="room_displayname_4_members">%1$s, %2$s, %3$s and %4$s</string>
|
||||
<!-- The 3 first parameters will be members' name -->
|
||||
<plurals name="room_displayname_four_and_more_members">
|
||||
<item quantity="one">%1$s, %2$s, %3$s and %4$d other</item>
|
||||
<item quantity="other">%1$s, %2$s, %3$s and %4$d others</item>
|
||||
</plurals>
|
||||
<plurals name="room_displayname_three_and_more_members">
|
||||
<item quantity="one">%1$s and 1 other</item>
|
||||
<item quantity="other">%1$s and %2$d others</item>
|
||||
</plurals>
|
||||
|
||||
<string name="room_displayname_empty_room">Empty room</string>
|
||||
<string name="room_displayname_empty_room_was">Empty room (was %s)</string>
|
||||
|
||||
<string name="initial_sync_start_importing_account">Initial Sync:\nImporting account…</string>
|
||||
<string name="initial_sync_start_importing_account_crypto">Initial Sync:\nImporting crypto</string>
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package im.vector.app.features.home.room.detail
|
||||
|
||||
import android.net.Uri
|
||||
import android.view.View
|
||||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
|
@ -24,6 +26,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachme
|
|||
import org.matrix.android.sdk.api.session.room.timeline.Timeline
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
||||
sealed class RoomDetailAction : VectorViewModelAction {
|
||||
data class UserIsTyping(val isTyping: Boolean) : RoomDetailAction()
|
||||
|
@ -90,4 +93,9 @@ sealed class RoomDetailAction : VectorViewModelAction {
|
|||
|
||||
data class OpenOrCreateDm(val userId: String) : RoomDetailAction()
|
||||
data class JumpToReadReceipt(val userId: String) : RoomDetailAction()
|
||||
object QuickActionInvitePeople : RoomDetailAction()
|
||||
object QuickActionSetAvatar : RoomDetailAction()
|
||||
data class SetAvatarAction(val newAvatarUri: Uri, val newAvatarFileName: String) : RoomDetailAction()
|
||||
object QuickActionSetTopic : RoomDetailAction()
|
||||
data class ShowRoomAvatarFullScreen(val matrixItem: MatrixItem?, val transitionView: View?) : RoomDetailAction()
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ import com.google.android.material.textfield.TextInputEditText
|
|||
import com.jakewharton.rxbinding3.widget.textChanges
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.dialogs.ConfirmationDialogBuilder
|
||||
import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper
|
||||
import im.vector.app.core.dialogs.withColoredButton
|
||||
import im.vector.app.core.epoxy.LayoutManagerStateRestorer
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
|
@ -82,6 +83,7 @@ import im.vector.app.core.extensions.showKeyboard
|
|||
import im.vector.app.core.extensions.trackItemsVisibilityChange
|
||||
import im.vector.app.core.glide.GlideApp
|
||||
import im.vector.app.core.glide.GlideRequests
|
||||
import im.vector.app.core.intent.getFilenameFromUri
|
||||
import im.vector.app.core.intent.getMimeTypeFromUri
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
|
@ -149,6 +151,7 @@ import im.vector.app.features.notifications.NotificationUtils
|
|||
import im.vector.app.features.permalink.NavigationInterceptor
|
||||
import im.vector.app.features.permalink.PermalinkHandler
|
||||
import im.vector.app.features.reactions.EmojiReactionPickerActivity
|
||||
import im.vector.app.features.roomprofile.RoomProfileActivity
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import im.vector.app.features.settings.VectorSettingsActivity
|
||||
import im.vector.app.features.share.SharedData
|
||||
|
@ -196,6 +199,7 @@ import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode
|
|||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -229,7 +233,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
JumpToReadMarkerView.Callback,
|
||||
AttachmentTypeSelectorView.Callback,
|
||||
AttachmentsHelper.Callback,
|
||||
// RoomWidgetsBannerView.Callback,
|
||||
GalleryOrCameraDialogHelper.Listener,
|
||||
ActiveCallView.Callback {
|
||||
|
||||
companion object {
|
||||
|
@ -250,6 +254,8 @@ class RoomDetailFragment @Inject constructor(
|
|||
private const val ircPattern = " (IRC)"
|
||||
}
|
||||
|
||||
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider)
|
||||
|
||||
private val roomDetailArgs: RoomDetailArgs by args()
|
||||
private val glideRequests by lazy {
|
||||
GlideApp.with(this)
|
||||
|
@ -364,6 +370,12 @@ class RoomDetailFragment @Inject constructor(
|
|||
RoomDetailViewEvents.HideWaitingView -> vectorBaseActivity.hideWaitingView()
|
||||
is RoomDetailViewEvents.RequestNativeWidgetPermission -> requestNativeWidgetPermission(it)
|
||||
is RoomDetailViewEvents.OpenRoom -> handleOpenRoom(it)
|
||||
RoomDetailViewEvents.OpenInvitePeople -> navigator.openInviteUsersToRoom(requireContext(), roomDetailArgs.roomId)
|
||||
RoomDetailViewEvents.OpenSetRoomAvatarDialog -> galleryOrCameraDialogHelper.show()
|
||||
RoomDetailViewEvents.OpenRoomSettings -> handleOpenRoomSettings()
|
||||
is RoomDetailViewEvents.ShowRoomAvatarFullScreen -> it.matrixItem?.let { item ->
|
||||
navigator.openBigImageViewer(requireActivity(), it.view, item)
|
||||
}
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
|
@ -372,6 +384,24 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onImageReady(uri: Uri?) {
|
||||
uri ?: return
|
||||
roomDetailViewModel.handle(
|
||||
RoomDetailAction.SetAvatarAction(
|
||||
newAvatarUri = uri,
|
||||
newAvatarFileName = getFilenameFromUri(requireContext(), uri) ?: UUID.randomUUID().toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun handleOpenRoomSettings() {
|
||||
navigator.openRoomProfile(
|
||||
requireContext(),
|
||||
roomDetailArgs.roomId,
|
||||
RoomProfileActivity.EXTRA_DIRECT_ACCESS_ROOM_SETTINGS
|
||||
)
|
||||
}
|
||||
|
||||
private fun handleOpenRoom(openRoom: RoomDetailViewEvents.OpenRoom) {
|
||||
navigator.openRoom(requireContext(), openRoom.roomId, null)
|
||||
}
|
||||
|
|
|
@ -17,10 +17,12 @@
|
|||
package im.vector.app.features.home.room.detail
|
||||
|
||||
import android.net.Uri
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
||||
import im.vector.app.core.platform.VectorViewEvents
|
||||
import im.vector.app.features.command.Command
|
||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode
|
||||
import java.io.File
|
||||
|
||||
|
@ -43,6 +45,11 @@ sealed class RoomDetailViewEvents : VectorViewEvents {
|
|||
data class NavigateToEvent(val eventId: String) : RoomDetailViewEvents()
|
||||
data class JoinJitsiConference(val widget: Widget, val withVideo: Boolean) : RoomDetailViewEvents()
|
||||
|
||||
object OpenInvitePeople : RoomDetailViewEvents()
|
||||
object OpenSetRoomAvatarDialog : RoomDetailViewEvents()
|
||||
object OpenRoomSettings : RoomDetailViewEvents()
|
||||
data class ShowRoomAvatarFullScreen(val matrixItem: MatrixItem?, val view: View?) : RoomDetailViewEvents()
|
||||
|
||||
object ShowWaitingView : RoomDetailViewEvents()
|
||||
object HideWaitingView : RoomDetailViewEvents()
|
||||
|
||||
|
|
|
@ -277,9 +277,39 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
is RoomDetailAction.CancelSend -> handleCancel(action)
|
||||
is RoomDetailAction.OpenOrCreateDm -> handleOpenOrCreateDm(action)
|
||||
is RoomDetailAction.JumpToReadReceipt -> handleJumpToReadReceipt(action)
|
||||
RoomDetailAction.QuickActionInvitePeople -> handleInvitePeople()
|
||||
RoomDetailAction.QuickActionSetAvatar -> handleQuickSetAvatar()
|
||||
is RoomDetailAction.SetAvatarAction -> handleSetNewAvatar(action)
|
||||
RoomDetailAction.QuickActionSetTopic -> _viewEvents.post(RoomDetailViewEvents.OpenRoomSettings)
|
||||
is RoomDetailAction.ShowRoomAvatarFullScreen -> {
|
||||
_viewEvents.post(
|
||||
RoomDetailViewEvents.ShowRoomAvatarFullScreen(action.matrixItem, action.transitionView)
|
||||
)
|
||||
}
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
private fun handleSetNewAvatar(action: RoomDetailAction.SetAvatarAction) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
awaitCallback<Unit> {
|
||||
room.updateAvatar(action.newAvatarUri, action.newAvatarFileName, it)
|
||||
}
|
||||
_viewEvents.post(RoomDetailViewEvents.ActionSuccess(action))
|
||||
} catch (failure: Throwable) {
|
||||
_viewEvents.post(RoomDetailViewEvents.ActionFailure(action, failure))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleInvitePeople() {
|
||||
_viewEvents.post(RoomDetailViewEvents.OpenInvitePeople)
|
||||
}
|
||||
|
||||
private fun handleQuickSetAvatar() {
|
||||
_viewEvents.post(RoomDetailViewEvents.OpenSetRoomAvatarDialog)
|
||||
}
|
||||
|
||||
private fun handleOpenOrCreateDm(action: RoomDetailAction.OpenOrCreateDm) {
|
||||
val existingDmRoomId = session.getExistingDirectRoomWithUser(action.userId)
|
||||
if (existingDmRoomId == null) {
|
||||
|
|
|
@ -31,10 +31,14 @@ import im.vector.app.features.home.room.detail.timeline.item.MergedMembershipEve
|
|||
import im.vector.app.features.home.room.detail.timeline.item.MergedMembershipEventsItem_
|
||||
import im.vector.app.features.home.room.detail.timeline.item.MergedRoomCreationItem
|
||||
import im.vector.app.features.home.room.detail.timeline.item.MergedRoomCreationItem_
|
||||
import im.vector.app.features.home.room.detail.timeline.tools.createLinkMovementMethod
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.crypto.model.event.EncryptionEventContent
|
||||
|
@ -187,6 +191,11 @@ class MergedHeaderItemFactory @Inject constructor(private val activeSessionHolde
|
|||
collapsedEventIds.removeAll(mergedEventIds)
|
||||
}
|
||||
val mergeId = mergedEventIds.joinToString(separator = "_") { it.toString() }
|
||||
val powerLevelsHelper = roomSummaryHolder.roomSummary?.roomId
|
||||
?.let { activeSessionHolder.getSafeActiveSession()?.getRoom(it) }
|
||||
?.let { it.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)?.content?.toModel<PowerLevelsContent>() }
|
||||
?.let { PowerLevelsHelper(it) }
|
||||
val currentUserId = activeSessionHolder.getSafeActiveSession()?.myUserId ?: ""
|
||||
val attributes = MergedRoomCreationItem.Attributes(
|
||||
isCollapsed = isCollapsed,
|
||||
mergeData = mergedData,
|
||||
|
@ -198,13 +207,19 @@ class MergedHeaderItemFactory @Inject constructor(private val activeSessionHolde
|
|||
hasEncryptionEvent = hasEncryption,
|
||||
isEncryptionAlgorithmSecure = encryptionAlgorithm == MXCRYPTO_ALGORITHM_MEGOLM,
|
||||
readReceiptsCallback = callback,
|
||||
currentUserId = activeSessionHolder.getSafeActiveSession()?.myUserId ?: ""
|
||||
callback = callback,
|
||||
currentUserId = currentUserId,
|
||||
roomSummary = roomSummaryHolder.roomSummary,
|
||||
canChangeAvatar = powerLevelsHelper?.isUserAllowedToSend(currentUserId, true, EventType.STATE_ROOM_AVATAR) ?: false,
|
||||
canChangeTopic = powerLevelsHelper?.isUserAllowedToSend(currentUserId, true, EventType.STATE_ROOM_TOPIC) ?: false,
|
||||
canChangeName = powerLevelsHelper?.isUserAllowedToSend(currentUserId, true, EventType.STATE_ROOM_NAME) ?: false
|
||||
)
|
||||
MergedRoomCreationItem_()
|
||||
.id(mergeId)
|
||||
.leftGuideline(avatarSizeProvider.leftGuideline)
|
||||
.highlighted(isCollapsed && highlighted)
|
||||
.attributes(attributes)
|
||||
.movementMethod(createLinkMovementMethod(callback))
|
||||
.also {
|
||||
it.setOnVisibilityStateChanged(MergedTimelineEventVisibilityStateChangedListener(callback, mergedEvents))
|
||||
}
|
||||
|
|
|
@ -16,11 +16,14 @@
|
|||
|
||||
package im.vector.app.features.home.room.detail.timeline.item
|
||||
|
||||
import android.text.SpannableString
|
||||
import android.text.method.MovementMethod
|
||||
import android.text.style.ClickableSpan
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
|
@ -28,8 +31,16 @@ import androidx.core.view.updateLayoutParams
|
|||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.setTextOrHide
|
||||
import im.vector.app.core.utils.DebouncedClickListener
|
||||
import im.vector.app.core.utils.tappableMatchingText
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.RoomDetailAction
|
||||
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
|
||||
import im.vector.app.features.home.room.detail.timeline.tools.linkify
|
||||
import me.gujun.android.span.span
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_timeline_event_base_noinfo)
|
||||
abstract class MergedRoomCreationItem : BasedMergedItem<MergedRoomCreationItem.Holder>() {
|
||||
|
@ -37,11 +48,16 @@ abstract class MergedRoomCreationItem : BasedMergedItem<MergedRoomCreationItem.H
|
|||
@EpoxyAttribute
|
||||
override lateinit var attributes: Attributes
|
||||
|
||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
|
||||
var movementMethod: MovementMethod? = null
|
||||
|
||||
override fun getViewType() = STUB_ID
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
|
||||
bindCreationSummaryTile(holder)
|
||||
|
||||
if (attributes.isCollapsed) {
|
||||
// Take the oldest data
|
||||
val data = distinctMergeData.lastOrNull()
|
||||
|
@ -70,9 +86,20 @@ abstract class MergedRoomCreationItem : BasedMergedItem<MergedRoomCreationItem.H
|
|||
holder.avatarView.visibility = View.GONE
|
||||
}
|
||||
|
||||
bindEncryptionTile(holder, data)
|
||||
} else {
|
||||
holder.avatarView.visibility = View.INVISIBLE
|
||||
holder.summaryView.visibility = View.GONE
|
||||
holder.encryptionTile.isGone = true
|
||||
}
|
||||
// No read receipt for this item
|
||||
holder.readReceiptsView.isVisible = false
|
||||
}
|
||||
|
||||
private fun bindEncryptionTile(holder: Holder, data: Data?) {
|
||||
if (attributes.hasEncryptionEvent) {
|
||||
holder.encryptionTile.isVisible = true
|
||||
holder.encryptionTile.updateLayoutParams<RelativeLayout.LayoutParams> {
|
||||
holder.encryptionTile.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
this.marginEnd = leftGuideline
|
||||
}
|
||||
if (attributes.isEncryptionAlgorithmSecure) {
|
||||
|
@ -98,13 +125,78 @@ abstract class MergedRoomCreationItem : BasedMergedItem<MergedRoomCreationItem.H
|
|||
} else {
|
||||
holder.encryptionTile.isVisible = false
|
||||
}
|
||||
} else {
|
||||
holder.avatarView.visibility = View.INVISIBLE
|
||||
holder.summaryView.visibility = View.GONE
|
||||
holder.encryptionTile.isGone = true
|
||||
}
|
||||
// No read receipt for this item
|
||||
holder.readReceiptsView.isVisible = false
|
||||
|
||||
private fun bindCreationSummaryTile(holder: Holder) {
|
||||
val roomSummary = attributes.roomSummary
|
||||
val roomDisplayName = roomSummary?.displayName
|
||||
holder.roomNameText.setTextOrHide(roomDisplayName)
|
||||
val isDirect = roomSummary?.isDirect == true
|
||||
val membersCount = roomSummary?.otherMemberIds?.size ?: 0
|
||||
|
||||
if (isDirect) {
|
||||
holder.roomDescriptionText.text = holder.view.resources.getString(R.string.this_is_the_beginning_of_dm, roomSummary?.displayName ?: "")
|
||||
} else if (roomDisplayName.isNullOrBlank() || roomSummary.name.isBlank()) {
|
||||
holder.roomDescriptionText.text = holder.view.resources.getString(R.string.this_is_the_beginning_of_room_no_name)
|
||||
} else {
|
||||
holder.roomDescriptionText.text = holder.view.resources.getString(R.string.this_is_the_beginning_of_room, roomDisplayName)
|
||||
}
|
||||
|
||||
val topic = roomSummary?.topic
|
||||
if (topic.isNullOrBlank()) {
|
||||
// do not show hint for DMs or group DMs
|
||||
if (!isDirect) {
|
||||
val addTopicLink = holder.view.resources.getString(R.string.add_a_topic_link_text)
|
||||
val styledText = SpannableString(holder.view.resources.getString(R.string.room_created_summary_no_topic_creation_text, addTopicLink))
|
||||
holder.roomTopicText.setTextOrHide(styledText.tappableMatchingText(addTopicLink, object : ClickableSpan() {
|
||||
override fun onClick(widget: View) {
|
||||
attributes.callback?.onTimelineItemAction(RoomDetailAction.QuickActionSetTopic)
|
||||
}
|
||||
}))
|
||||
}
|
||||
} else {
|
||||
holder.roomTopicText.setTextOrHide(
|
||||
span {
|
||||
span(holder.view.resources.getString(R.string.topic_prefix)) {
|
||||
textStyle = "bold"
|
||||
}
|
||||
+topic.linkify(attributes.callback)
|
||||
}
|
||||
)
|
||||
}
|
||||
holder.roomTopicText.movementMethod = movementMethod
|
||||
|
||||
val roomItem = roomSummary?.toMatrixItem()
|
||||
val shouldSetAvatar = attributes.canChangeAvatar
|
||||
&& (roomSummary?.isDirect == false || (isDirect && membersCount >= 2))
|
||||
&& roomItem?.avatarUrl.isNullOrBlank()
|
||||
|
||||
holder.roomAvatarImageView.isVisible = roomItem != null
|
||||
if (roomItem != null) {
|
||||
attributes.avatarRenderer.render(roomItem, holder.roomAvatarImageView)
|
||||
holder.roomAvatarImageView.setOnClickListener(DebouncedClickListener({ view ->
|
||||
if (shouldSetAvatar) {
|
||||
attributes.callback?.onTimelineItemAction(RoomDetailAction.QuickActionSetAvatar)
|
||||
} else {
|
||||
// Note: this is no op if there is no avatar on the room
|
||||
attributes.callback?.onTimelineItemAction(RoomDetailAction.ShowRoomAvatarFullScreen(roomItem, view))
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
holder.setAvatarButton.isVisible = shouldSetAvatar
|
||||
if (shouldSetAvatar) {
|
||||
holder.setAvatarButton.setOnClickListener(DebouncedClickListener({ _ ->
|
||||
attributes.callback?.onTimelineItemAction(RoomDetailAction.QuickActionSetAvatar)
|
||||
}))
|
||||
}
|
||||
|
||||
holder.addPeopleButton.isVisible = !isDirect
|
||||
if (!isDirect) {
|
||||
holder.addPeopleButton.setOnClickListener(DebouncedClickListener({ _ ->
|
||||
attributes.callback?.onTimelineItemAction(RoomDetailAction.QuickActionInvitePeople)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
class Holder : BasedMergedItem.Holder(STUB_ID) {
|
||||
|
@ -114,6 +206,13 @@ abstract class MergedRoomCreationItem : BasedMergedItem<MergedRoomCreationItem.H
|
|||
|
||||
val e2eTitleTextView by bind<TextView>(R.id.itemVerificationDoneTitleTextView)
|
||||
val e2eTitleDescriptionView by bind<TextView>(R.id.itemVerificationDoneDetailTextView)
|
||||
|
||||
val roomNameText by bind<TextView>(R.id.roomNameTileText)
|
||||
val roomDescriptionText by bind<TextView>(R.id.roomNameDescriptionText)
|
||||
val roomTopicText by bind<TextView>(R.id.roomNameTopicText)
|
||||
val roomAvatarImageView by bind<ImageView>(R.id.creationTileRoomAvatarImageView)
|
||||
val addPeopleButton by bind<View>(R.id.creationTileAddPeopleButton)
|
||||
val setAvatarButton by bind<View>(R.id.creationTileSetAvatarButton)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -126,8 +225,13 @@ abstract class MergedRoomCreationItem : BasedMergedItem<MergedRoomCreationItem.H
|
|||
override val avatarRenderer: AvatarRenderer,
|
||||
override val readReceiptsCallback: TimelineEventController.ReadReceiptsCallback? = null,
|
||||
override val onCollapsedStateChanged: (Boolean) -> Unit,
|
||||
val callback: TimelineEventController.Callback? = null,
|
||||
val currentUserId: String,
|
||||
val hasEncryptionEvent: Boolean,
|
||||
val isEncryptionAlgorithmSecure: Boolean
|
||||
val isEncryptionAlgorithmSecure: Boolean,
|
||||
val roomSummary: RoomSummary?,
|
||||
val canChangeAvatar: Boolean = false,
|
||||
val canChangeName: Boolean = false,
|
||||
val canChangeTopic: Boolean = false
|
||||
) : BasedMergedItem.Attributes
|
||||
}
|
||||
|
|
|
@ -248,8 +248,8 @@ class DefaultNavigator @Inject constructor(
|
|||
context.startActivity(KeysBackupManageActivity.intent(context))
|
||||
}
|
||||
|
||||
override fun openRoomProfile(context: Context, roomId: String) {
|
||||
context.startActivity(RoomProfileActivity.newIntent(context, roomId))
|
||||
override fun openRoomProfile(context: Context, roomId: String, directAccess: Int?) {
|
||||
context.startActivity(RoomProfileActivity.newIntent(context, roomId, directAccess))
|
||||
}
|
||||
|
||||
override fun openBigImageViewer(activity: Activity, sharedElement: View?, matrixItem: MatrixItem) {
|
||||
|
|
|
@ -78,7 +78,7 @@ interface Navigator {
|
|||
|
||||
fun openRoomMemberProfile(userId: String, roomId: String?, context: Context, buildTask: Boolean = false)
|
||||
|
||||
fun openRoomProfile(context: Context, roomId: String)
|
||||
fun openRoomProfile(context: Context, roomId: String, directAccess: Int? = null)
|
||||
|
||||
fun openBigImageViewer(activity: Activity, sharedElement: View?, matrixItem: MatrixItem)
|
||||
|
||||
|
|
|
@ -46,10 +46,16 @@ class RoomProfileActivity :
|
|||
|
||||
companion object {
|
||||
|
||||
fun newIntent(context: Context, roomId: String): Intent {
|
||||
private const val EXTRA_DIRECT_ACCESS = "EXTRA_DIRECT_ACCESS"
|
||||
|
||||
const val EXTRA_DIRECT_ACCESS_ROOM_ROOT = 0
|
||||
const val EXTRA_DIRECT_ACCESS_ROOM_SETTINGS = 1
|
||||
|
||||
fun newIntent(context: Context, roomId: String, directAccess: Int?): Intent {
|
||||
val roomProfileArgs = RoomProfileArgs(roomId)
|
||||
return Intent(context, RoomProfileActivity::class.java).apply {
|
||||
putExtra(MvRx.KEY_ARG, roomProfileArgs)
|
||||
putExtra(EXTRA_DIRECT_ACCESS, directAccess)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +86,13 @@ class RoomProfileActivity :
|
|||
sharedActionViewModel = viewModelProvider.get(RoomProfileSharedActionViewModel::class.java)
|
||||
roomProfileArgs = intent?.extras?.getParcelable(MvRx.KEY_ARG) ?: return
|
||||
if (isFirstCreation()) {
|
||||
when (intent?.extras?.getInt(EXTRA_DIRECT_ACCESS, EXTRA_DIRECT_ACCESS_ROOM_ROOT)) {
|
||||
EXTRA_DIRECT_ACCESS_ROOM_SETTINGS -> {
|
||||
addFragment(R.id.simpleFragmentContainer, RoomProfileFragment::class.java, roomProfileArgs)
|
||||
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomSettingsFragment::class.java, roomProfileArgs)
|
||||
}
|
||||
else -> addFragment(R.id.simpleFragmentContainer, RoomProfileFragment::class.java, roomProfileArgs)
|
||||
}
|
||||
}
|
||||
sharedActionViewModel
|
||||
.observe()
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M19.1001,9C18.7779,9 18.5168,8.7388 18.5168,8.4167V6.0833H16.1834C15.8613,6.0833 15.6001,5.8222 15.6001,5.5C15.6001,5.1778 15.8613,4.9167 16.1834,4.9167H18.5168V2.5833C18.5168,2.2612 18.7779,2 19.1001,2C19.4223,2 19.6834,2.2612 19.6834,2.5833V4.9167H22.0168C22.3389,4.9167 22.6001,5.1778 22.6001,5.5C22.6001,5.8222 22.3389,6.0833 22.0168,6.0833H19.6834V8.4167C19.6834,8.7388 19.4223,9 19.1001,9ZM19.6001,11C20.0669,11 20.5212,10.9467 20.9574,10.8458C21.1161,11.5383 21.2,12.2594 21.2,13C21.2,16.1409 19.6917,18.9294 17.3598,20.6808V20.6807C16.0014,21.7011 14.3635,22.3695 12.5815,22.5505C12.2588,22.5832 11.9314,22.6 11.6,22.6C6.2981,22.6 2,18.302 2,13C2,7.6981 6.2981,3.4 11.6,3.4C12.3407,3.4 13.0618,3.4839 13.7543,3.6427C13.6534,4.0788 13.6001,4.5332 13.6001,5C13.6001,8.3137 16.2864,11 19.6001,11ZM11.5999,20.68C13.6754,20.68 15.5585,19.8567 16.9407,18.5189C16.0859,16.4086 14.0167,14.92 11.5998,14.92C9.183,14.92 7.1138,16.4086 6.259,18.5189C7.6411,19.8567 9.5244,20.68 11.5999,20.68ZM11.7426,7.4117C10.3168,7.5417 9.2,8.7404 9.2,10.2C9.2,11.7464 10.4536,13 12,13C13.0308,13 13.9315,12.443 14.4176,11.6135C13.0673,10.6058 12.0929,9.1225 11.7426,7.4117Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
|
@ -1,31 +1,149 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/creationTile"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/creationEncryptionTile"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_marginEnd="52dp"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:background="@drawable/rounded_rect_shape_8"
|
||||
android:padding="8dp">
|
||||
android:padding="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<include layout="@layout/item_timeline_event_status_tile_stub" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/creationTileRoomAvatarImageView"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginTop="20dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/creationEncryptionTile"
|
||||
tools:srcCompat="@tools:sample/avatars" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/creationTileSetAvatarButton"
|
||||
style="@style/Widget.MaterialComponents.Button.Icon"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:backgroundTint="?riotx_bottom_nav_background_color"
|
||||
android:contentDescription="@string/room_settings_set_avatar"
|
||||
android:elevation="2dp"
|
||||
android:insetLeft="0dp"
|
||||
android:insetTop="0dp"
|
||||
android:insetRight="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:padding="0dp"
|
||||
app:cornerRadius="30dp"
|
||||
app:icon="@drawable/ic_camera"
|
||||
app:iconGravity="textStart"
|
||||
app:iconPadding="0dp"
|
||||
app:iconSize="20dp"
|
||||
app:iconTint="?riot_primary_text_color"
|
||||
app:layout_constraintCircle="@+id/creationTileRoomAvatarImageView"
|
||||
app:layout_constraintCircleAngle="135"
|
||||
app:layout_constraintCircleRadius="34dp"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/roomNameTileText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/creationTileRoomAvatarImageView"
|
||||
tools:text="@sample/matrix.json/data/roomName" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/roomNameDescriptionText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="normal"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/roomNameTileText"
|
||||
tools:text="@string/this_is_the_beginning_of_room_no_name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/roomNameTopicText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textColorLink="@color/riotx_accent"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="normal"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/roomNameDescriptionText"
|
||||
tools:text="@string/room_created_summary_no_topic_creation_text" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/creationTileAddPeopleButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/add_people"
|
||||
android:focusable="true"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/roomNameTopicText">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/addPeopleButtonBg"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="@drawable/circle"
|
||||
android:backgroundTint="@color/riotx_accent"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_add_people" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:text="@string/add_people"
|
||||
android:textColor="@color/riotx_accent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/mergedSumContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/creationEncryptionTile">
|
||||
android:layout_below="@+id/creationTile"
|
||||
android:layout_marginTop="8dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/itemNoticeAvatarView"
|
||||
|
|
|
@ -2403,6 +2403,13 @@
|
|||
<string name="room_created_summary_item_by_you">You created and configured the room.</string>
|
||||
<string name="direct_room_created_summary_item">%s joined.</string>
|
||||
<string name="direct_room_created_summary_item_by_you">You joined.</string>
|
||||
<string name="this_is_the_beginning_of_room">This is the beginning of %s.</string>
|
||||
<string name="this_is_the_beginning_of_room_no_name">This is the beginning of this conversation.</string>
|
||||
<string name="this_is_the_beginning_of_dm">This is the beginning of your direct message history with %s.</string>
|
||||
<!-- First param will be replaced by the value of add_a_topic_link_text, that will be clickable-->
|
||||
<string name="room_created_summary_no_topic_creation_text">%s to let people know what this room is about.</string>
|
||||
<string name="add_a_topic_link_text">Add a topic</string>
|
||||
<string name="topic_prefix">"Topic: "</string>
|
||||
|
||||
<string name="qr_code_scanned_self_verif_notice">Almost there! Is the other device showing the same shield?</string>
|
||||
<string name="qr_code_scanned_verif_waiting_notice">Almost there! Waiting for confirmation…</string>
|
||||
|
@ -2511,6 +2518,7 @@
|
|||
<string name="create_room_dm_failure">"We couldn't create your DM. Please check the users you want to invite and try again."</string>
|
||||
|
||||
<string name="add_members_to_room">Add members</string>
|
||||
<string name="add_people">Add people</string>
|
||||
<string name="invite_users_to_room_action_invite">INVITE</string>
|
||||
<string name="inviting_users_to_room">Inviting users…</string>
|
||||
<string name="invite_users_to_room_title">Invite Users</string>
|
||||
|
@ -2575,6 +2583,8 @@
|
|||
<string name="room_settings_name_hint">Room Name</string>
|
||||
<string name="room_settings_topic_hint">Topic</string>
|
||||
<string name="room_settings_save_success">You changed room settings successfully</string>
|
||||
<string name="room_settings_set_avatar">Set avatar</string>
|
||||
|
||||
|
||||
<string name="notice_crypto_unable_to_decrypt_final">You cannot access this message</string>
|
||||
<string name="notice_crypto_unable_to_decrypt_friendly">Waiting for this message, this may take a while</string>
|
||||
|
|
Loading…
Reference in New Issue