Merge pull request #1280 from vector-im/feature/e2e_timeline_decoration
Feature/e2e timeline decoration
This commit is contained in:
commit
8e357c6b7f
@ -28,6 +28,7 @@ Improvements 🙌:
|
|||||||
- Restart broken Olm sessions ([MSC1719](https://github.com/matrix-org/matrix-doc/pull/1719))
|
- Restart broken Olm sessions ([MSC1719](https://github.com/matrix-org/matrix-doc/pull/1719))
|
||||||
- Cross-Signing | Hide Use recovery key when 4S is not setup (#1007)
|
- Cross-Signing | Hide Use recovery key when 4S is not setup (#1007)
|
||||||
- Cross-Signing | Trust account xSigning keys by entering Recovery Key (select file or copy) #1199
|
- Cross-Signing | Trust account xSigning keys by entering Recovery Key (select file or copy) #1199
|
||||||
|
- E2E timeline decoration (#1279)
|
||||||
- Manage Session Settings / Cross Signing update (#1295)
|
- Manage Session Settings / Cross Signing update (#1295)
|
||||||
- Cross-Signing | Review sessions toast update old vs new (#1293, #1306)
|
- Cross-Signing | Review sessions toast update old vs new (#1293, #1306)
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ data class RoomSummary constructor(
|
|||||||
val readMarkerId: String? = null,
|
val readMarkerId: String? = null,
|
||||||
val userDrafts: List<UserDraft> = emptyList(),
|
val userDrafts: List<UserDraft> = emptyList(),
|
||||||
val isEncrypted: Boolean,
|
val isEncrypted: Boolean,
|
||||||
|
val encryptionEventTs: Long?,
|
||||||
val inviterId: String? = null,
|
val inviterId: String? = null,
|
||||||
val typingRoomMemberIds: List<String> = emptyList(),
|
val typingRoomMemberIds: List<String> = emptyList(),
|
||||||
val breadcrumbsIndex: Int = NOT_IN_BREADCRUMBS,
|
val breadcrumbsIndex: Int = NOT_IN_BREADCRUMBS,
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package im.vector.matrix.android.internal.crypto.store.db.model
|
package im.vector.matrix.android.internal.crypto.store.db.model
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.extensions.tryThis
|
||||||
import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper
|
import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper
|
||||||
import im.vector.matrix.android.internal.crypto.store.db.deserializeFromRealm
|
import im.vector.matrix.android.internal.crypto.store.db.deserializeFromRealm
|
||||||
import im.vector.matrix.android.internal.crypto.store.db.serializeForRealm
|
import im.vector.matrix.android.internal.crypto.store.db.serializeForRealm
|
||||||
@ -36,7 +37,7 @@ internal open class OlmInboundGroupSessionEntity(
|
|||||||
: RealmObject() {
|
: RealmObject() {
|
||||||
|
|
||||||
fun getInboundGroupSession(): OlmInboundGroupSessionWrapper? {
|
fun getInboundGroupSession(): OlmInboundGroupSessionWrapper? {
|
||||||
return deserializeFromRealm(olmInboundGroupSessionData)
|
return tryThis { deserializeFromRealm<OlmInboundGroupSessionWrapper?>(olmInboundGroupSessionData) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun putInboundGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper?) {
|
fun putInboundGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper?) {
|
||||||
|
@ -53,6 +53,7 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa
|
|||||||
canonicalAlias = roomSummaryEntity.canonicalAlias,
|
canonicalAlias = roomSummaryEntity.canonicalAlias,
|
||||||
aliases = roomSummaryEntity.aliases.toList(),
|
aliases = roomSummaryEntity.aliases.toList(),
|
||||||
isEncrypted = roomSummaryEntity.isEncrypted,
|
isEncrypted = roomSummaryEntity.isEncrypted,
|
||||||
|
encryptionEventTs = roomSummaryEntity.encryptionEventTs,
|
||||||
typingRoomMemberIds = roomSummaryEntity.typingUserIds.toList(),
|
typingRoomMemberIds = roomSummaryEntity.typingUserIds.toList(),
|
||||||
breadcrumbsIndex = roomSummaryEntity.breadcrumbsIndex,
|
breadcrumbsIndex = roomSummaryEntity.breadcrumbsIndex,
|
||||||
roomEncryptionTrustLevel = roomSummaryEntity.roomEncryptionTrustLevel,
|
roomEncryptionTrustLevel = roomSummaryEntity.roomEncryptionTrustLevel,
|
||||||
|
@ -48,6 +48,7 @@ internal open class RoomSummaryEntity(
|
|||||||
// this is required for querying
|
// this is required for querying
|
||||||
var flatAliases: String = "",
|
var flatAliases: String = "",
|
||||||
var isEncrypted: Boolean = false,
|
var isEncrypted: Boolean = false,
|
||||||
|
var encryptionEventTs: Long? = 0,
|
||||||
var typingUserIds: RealmList<String> = RealmList(),
|
var typingUserIds: RealmList<String> = RealmList(),
|
||||||
var roomEncryptionTrustLevelStr: String? = null,
|
var roomEncryptionTrustLevelStr: String? = null,
|
||||||
var inviterId: String? = null
|
var inviterId: String? = null
|
||||||
|
@ -136,6 +136,7 @@ internal class RoomSummaryUpdater @Inject constructor(
|
|||||||
roomSummaryEntity.aliases.addAll(roomAliases)
|
roomSummaryEntity.aliases.addAll(roomAliases)
|
||||||
roomSummaryEntity.flatAliases = roomAliases.joinToString(separator = "|", prefix = "|")
|
roomSummaryEntity.flatAliases = roomAliases.joinToString(separator = "|", prefix = "|")
|
||||||
roomSummaryEntity.isEncrypted = encryptionEvent != null
|
roomSummaryEntity.isEncrypted = encryptionEvent != null
|
||||||
|
roomSummaryEntity.encryptionEventTs = encryptionEvent?.originServerTs
|
||||||
roomSummaryEntity.typingUserIds.clear()
|
roomSummaryEntity.typingUserIds.clear()
|
||||||
roomSummaryEntity.typingUserIds.addAll(ephemeralResult?.typingUserIds.orEmpty())
|
roomSummaryEntity.typingUserIds.addAll(ephemeralResult?.typingUserIds.orEmpty())
|
||||||
|
|
||||||
|
@ -26,7 +26,6 @@ import android.widget.ImageView
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.constraintlayout.widget.ConstraintSet
|
import androidx.constraintlayout.widget.ConstraintSet
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.text.toSpannable
|
import androidx.core.text.toSpannable
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.transition.AutoTransition
|
import androidx.transition.AutoTransition
|
||||||
@ -172,7 +171,7 @@ class TextComposerView @JvmOverloads constructor(context: Context, attrs: Attrib
|
|||||||
RoomEncryptionTrustLevel.Warning -> R.drawable.ic_shield_warning
|
RoomEncryptionTrustLevel.Warning -> R.drawable.ic_shield_warning
|
||||||
else -> R.drawable.ic_shield_black
|
else -> R.drawable.ic_shield_black
|
||||||
}
|
}
|
||||||
composerShieldImageView.setImageDrawable(ContextCompat.getDrawable(context, shieldRes))
|
composerShieldImageView.setImageResource(shieldRes)
|
||||||
} else {
|
} else {
|
||||||
composerEditText.setHint(R.string.room_message_placeholder)
|
composerEditText.setHint(R.string.room_message_placeholder)
|
||||||
composerShieldImageView.isVisible = false
|
composerShieldImageView.isVisible = false
|
||||||
|
@ -29,6 +29,7 @@ import im.vector.riotx.core.epoxy.dividerItem
|
|||||||
import im.vector.riotx.core.resources.StringProvider
|
import im.vector.riotx.core.resources.StringProvider
|
||||||
import im.vector.riotx.features.home.AvatarRenderer
|
import im.vector.riotx.features.home.AvatarRenderer
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.item.E2EDecoration
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.tools.createLinkMovementMethod
|
import im.vector.riotx.features.home.room.detail.timeline.tools.createLinkMovementMethod
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.tools.linkify
|
import im.vector.riotx.features.home.room.detail.timeline.tools.linkify
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -72,6 +73,29 @@ class MessageActionsEpoxyController @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
when (state.informationData.e2eDecoration) {
|
||||||
|
E2EDecoration.WARN_IN_CLEAR -> {
|
||||||
|
bottomSheetSendStateItem {
|
||||||
|
id("e2e_clear")
|
||||||
|
showProgress(false)
|
||||||
|
text(stringProvider.getString(R.string.unencrypted))
|
||||||
|
drawableStart(R.drawable.ic_shield_warning_small)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
E2EDecoration.WARN_SENT_BY_UNVERIFIED,
|
||||||
|
E2EDecoration.WARN_SENT_BY_UNKNOWN -> {
|
||||||
|
bottomSheetSendStateItem {
|
||||||
|
id("e2e_unverified")
|
||||||
|
showProgress(false)
|
||||||
|
text(stringProvider.getString(R.string.encrypted_unverified))
|
||||||
|
drawableStart(R.drawable.ic_shield_warning_small)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Quick reactions
|
// Quick reactions
|
||||||
if (state.canReact() && state.quickStates is Success) {
|
if (state.canReact() && state.quickStates is Success) {
|
||||||
// Separator
|
// Separator
|
||||||
|
@ -18,19 +18,23 @@
|
|||||||
|
|
||||||
package im.vector.riotx.features.home.room.detail.timeline.helper
|
package im.vector.riotx.features.home.room.detail.timeline.helper
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.extensions.orFalse
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.api.session.events.model.toModel
|
import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
|
import im.vector.matrix.android.api.session.room.Room
|
||||||
import im.vector.matrix.android.api.session.room.model.ReferencesAggregatedContent
|
import im.vector.matrix.android.api.session.room.model.ReferencesAggregatedContent
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageVerificationRequestContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageVerificationRequestContent
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent
|
import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent
|
||||||
import im.vector.matrix.android.api.session.room.timeline.hasBeenEdited
|
import im.vector.matrix.android.api.session.room.timeline.hasBeenEdited
|
||||||
|
import im.vector.matrix.android.internal.crypto.model.event.EncryptedEventContent
|
||||||
import im.vector.matrix.android.internal.session.room.VerificationState
|
import im.vector.matrix.android.internal.session.room.VerificationState
|
||||||
import im.vector.riotx.core.date.VectorDateFormatter
|
import im.vector.riotx.core.date.VectorDateFormatter
|
||||||
import im.vector.riotx.core.extensions.localDateTime
|
import im.vector.riotx.core.extensions.localDateTime
|
||||||
import im.vector.riotx.core.resources.ColorProvider
|
import im.vector.riotx.core.resources.ColorProvider
|
||||||
import im.vector.riotx.core.utils.getColorFromUserId
|
import im.vector.riotx.core.utils.getColorFromUserId
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.item.E2EDecoration
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
|
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.item.PollResponseData
|
import im.vector.riotx.features.home.room.detail.timeline.item.PollResponseData
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.item.ReactionInfoData
|
import im.vector.riotx.features.home.room.detail.timeline.item.ReactionInfoData
|
||||||
@ -72,6 +76,8 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses
|
|||||||
textColor = colorProvider.getColor(getColorFromUserId(event.root.senderId))
|
textColor = colorProvider.getColor(getColorFromUserId(event.root.senderId))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val room = event.root.roomId?.let { session.getRoom(it) }
|
||||||
|
val e2eDecoration = getE2EDecoration(room, event)
|
||||||
return MessageInformationData(
|
return MessageInformationData(
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
senderId = event.root.senderId ?: "",
|
senderId = event.root.senderId ?: "",
|
||||||
@ -111,10 +117,59 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses
|
|||||||
?: VerificationState.REQUEST
|
?: VerificationState.REQUEST
|
||||||
ReferencesInfoData(verificationState)
|
ReferencesInfoData(verificationState)
|
||||||
},
|
},
|
||||||
sentByMe = event.root.senderId == session.myUserId
|
sentByMe = event.root.senderId == session.myUserId,
|
||||||
|
e2eDecoration = e2eDecoration
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getE2EDecoration(room: Room?, event: TimelineEvent): E2EDecoration {
|
||||||
|
return if (room?.isEncrypted() == true
|
||||||
|
// is user verified
|
||||||
|
&& session.cryptoService().crossSigningService().getUserCrossSigningKeys(event.root.senderId ?: "")?.isTrusted() == true) {
|
||||||
|
val ts = room.roomSummary()?.encryptionEventTs ?: 0
|
||||||
|
val eventTs = event.root.originServerTs ?: 0
|
||||||
|
if (event.isEncrypted()) {
|
||||||
|
// Do not decorate failed to decrypt, or redaction (we lost sender device info)
|
||||||
|
if (event.root.getClearType() == EventType.ENCRYPTED || event.root.isRedacted()) {
|
||||||
|
E2EDecoration.NONE
|
||||||
|
} else {
|
||||||
|
val sendingDevice = event.root.content
|
||||||
|
.toModel<EncryptedEventContent>()
|
||||||
|
?.deviceId
|
||||||
|
?.let { deviceId ->
|
||||||
|
session.cryptoService().getDeviceInfo(event.root.senderId ?: "", deviceId)
|
||||||
|
}
|
||||||
|
when {
|
||||||
|
sendingDevice == null -> {
|
||||||
|
// For now do not decorate this with warning
|
||||||
|
// maybe it's a deleted session
|
||||||
|
E2EDecoration.NONE
|
||||||
|
}
|
||||||
|
sendingDevice.trustLevel == null -> {
|
||||||
|
E2EDecoration.WARN_SENT_BY_UNKNOWN
|
||||||
|
}
|
||||||
|
sendingDevice.trustLevel?.isVerified().orFalse() -> {
|
||||||
|
E2EDecoration.NONE
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
E2EDecoration.WARN_SENT_BY_UNVERIFIED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (EventType.isStateEvent(event.root.type)) {
|
||||||
|
// Do not warn for state event, they are always in clear
|
||||||
|
E2EDecoration.NONE
|
||||||
|
} else {
|
||||||
|
// If event is in clear after the room enabled encryption we should warn
|
||||||
|
if (eventTs > ts) E2EDecoration.WARN_IN_CLEAR else E2EDecoration.NONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
E2EDecoration.NONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tiles type message never show the sender information (like verification request), so we should repeat it for next message
|
* Tiles type message never show the sender information (like verification request), so we should repeat it for next message
|
||||||
* even if same sender
|
* even if same sender
|
||||||
|
@ -92,6 +92,18 @@ abstract class AbsBaseMessageItem<H : AbsBaseMessageItem.Holder> : BaseEventItem
|
|||||||
holder.reactionsContainer.setOnLongClickListener(baseAttributes.itemLongClickListener)
|
holder.reactionsContainer.setOnLongClickListener(baseAttributes.itemLongClickListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
when (baseAttributes.informationData.e2eDecoration) {
|
||||||
|
E2EDecoration.NONE -> {
|
||||||
|
holder.e2EDecorationView.isVisible = false
|
||||||
|
}
|
||||||
|
E2EDecoration.WARN_IN_CLEAR,
|
||||||
|
E2EDecoration.WARN_SENT_BY_UNVERIFIED,
|
||||||
|
E2EDecoration.WARN_SENT_BY_UNKNOWN -> {
|
||||||
|
holder.e2EDecorationView.setImageResource(R.drawable.ic_shield_warning)
|
||||||
|
holder.e2EDecorationView.isVisible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
holder.view.setOnClickListener(baseAttributes.itemClickListener)
|
holder.view.setOnClickListener(baseAttributes.itemClickListener)
|
||||||
holder.view.setOnLongClickListener(baseAttributes.itemLongClickListener)
|
holder.view.setOnLongClickListener(baseAttributes.itemLongClickListener)
|
||||||
}
|
}
|
||||||
@ -110,6 +122,7 @@ abstract class AbsBaseMessageItem<H : AbsBaseMessageItem.Holder> : BaseEventItem
|
|||||||
|
|
||||||
abstract class Holder(@IdRes stubId: Int) : BaseEventItem.BaseHolder(stubId) {
|
abstract class Holder(@IdRes stubId: Int) : BaseEventItem.BaseHolder(stubId) {
|
||||||
val reactionsContainer by bind<ViewGroup>(R.id.reactionsContainer)
|
val reactionsContainer by bind<ViewGroup>(R.id.reactionsContainer)
|
||||||
|
val e2EDecorationView by bind<ImageView>(R.id.messageE2EDecoration)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,7 +40,8 @@ data class MessageInformationData(
|
|||||||
val hasPendingEdits: Boolean = false,
|
val hasPendingEdits: Boolean = false,
|
||||||
val readReceipts: List<ReadReceiptData> = emptyList(),
|
val readReceipts: List<ReadReceiptData> = emptyList(),
|
||||||
val referencesInfoData: ReferencesInfoData? = null,
|
val referencesInfoData: ReferencesInfoData? = null,
|
||||||
val sentByMe : Boolean
|
val sentByMe : Boolean,
|
||||||
|
val e2eDecoration: E2EDecoration = E2EDecoration.NONE
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
|
||||||
val matrixItem: MatrixItem
|
val matrixItem: MatrixItem
|
||||||
@ -75,4 +76,11 @@ data class PollResponseData(
|
|||||||
val isClosed: Boolean = false
|
val isClosed: Boolean = false
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
|
enum class E2EDecoration {
|
||||||
|
NONE,
|
||||||
|
WARN_IN_CLEAR,
|
||||||
|
WARN_SENT_BY_UNVERIFIED,
|
||||||
|
WARN_SENT_BY_UNKNOWN
|
||||||
|
}
|
||||||
|
|
||||||
fun ReadReceiptData.toMatrixItem() = MatrixItem.UserItem(userId, displayName, avatarUrl)
|
fun ReadReceiptData.toMatrixItem() = MatrixItem.UserItem(userId, displayName, avatarUrl)
|
||||||
|
@ -19,6 +19,7 @@ package im.vector.riotx.features.home.room.detail.timeline.item
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import com.airbnb.epoxy.EpoxyAttribute
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
import com.airbnb.epoxy.EpoxyModelClass
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
@ -45,6 +46,18 @@ abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
|
|||||||
holder.view.setOnLongClickListener(attributes.itemLongClickListener)
|
holder.view.setOnLongClickListener(attributes.itemLongClickListener)
|
||||||
holder.readReceiptsView.render(attributes.informationData.readReceipts, attributes.avatarRenderer, _readReceiptsClickListener)
|
holder.readReceiptsView.render(attributes.informationData.readReceipts, attributes.avatarRenderer, _readReceiptsClickListener)
|
||||||
holder.avatarImageView.onClick(attributes.avatarClickListener)
|
holder.avatarImageView.onClick(attributes.avatarClickListener)
|
||||||
|
|
||||||
|
when (attributes.informationData.e2eDecoration) {
|
||||||
|
E2EDecoration.NONE -> {
|
||||||
|
holder.e2EDecorationView.isVisible = false
|
||||||
|
}
|
||||||
|
E2EDecoration.WARN_IN_CLEAR,
|
||||||
|
E2EDecoration.WARN_SENT_BY_UNVERIFIED,
|
||||||
|
E2EDecoration.WARN_SENT_BY_UNKNOWN -> {
|
||||||
|
holder.e2EDecorationView.setImageResource(R.drawable.ic_shield_warning)
|
||||||
|
holder.e2EDecorationView.isVisible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getEventIds(): List<String> {
|
override fun getEventIds(): List<String> {
|
||||||
@ -56,6 +69,7 @@ abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
|
|||||||
class Holder : BaseHolder(STUB_ID) {
|
class Holder : BaseHolder(STUB_ID) {
|
||||||
val avatarImageView by bind<ImageView>(R.id.itemNoticeAvatarView)
|
val avatarImageView by bind<ImageView>(R.id.itemNoticeAvatarView)
|
||||||
val noticeTextView by bind<TextView>(R.id.itemNoticeTextView)
|
val noticeTextView by bind<TextView>(R.id.itemNoticeTextView)
|
||||||
|
val e2EDecorationView by bind<ImageView>(R.id.messageE2EDecoration)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Attributes(
|
data class Attributes(
|
||||||
|
20
vector/src/main/res/drawable/ic_shield_warning_small.xml
Normal file
20
vector/src/main/res/drawable/ic_shield_warning_small.xml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="16dp"
|
||||||
|
android:height="16dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="m12,21s9,-3.8 9,-9.5v-6.65l-9,-2.85 -9,2.85v6.65c0,5.7 9,9.5 9,9.5z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#ff4b55"
|
||||||
|
android:strokeColor="#fff"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M12.05,5.5L12.05,5.5A1.25,1.25 0,0 1,13.3 6.75L13.3,12.25A1.25,1.25 0,0 1,12.05 13.5L12.05,13.5A1.25,1.25 0,0 1,10.8 12.25L10.8,6.75A1.25,1.25 0,0 1,12.05 5.5z"
|
||||||
|
android:fillColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M12.05,15L12.05,15A1.25,1.25 0,0 1,13.3 16.25L13.3,16.25A1.25,1.25 0,0 1,12.05 17.5L12.05,17.5A1.25,1.25 0,0 1,10.8 16.25L10.8,16.25A1.25,1.25 0,0 1,12.05 15z"
|
||||||
|
android:fillColor="#fff"/>
|
||||||
|
</vector>
|
@ -62,6 +62,24 @@
|
|||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
tools:layout_marginStart="52dp" />
|
tools:layout_marginStart="52dp" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:id="@+id/decorationSpace"
|
||||||
|
android:layout_width="4dp"
|
||||||
|
android:layout_height="8dp"
|
||||||
|
android:layout_toEndOf="@id/messageStartGuideline"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/messageE2EDecoration"
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:layout_alignTop="@id/viewStubContainer"
|
||||||
|
android:layout_marginTop="7dp"
|
||||||
|
android:layout_alignEnd="@id/decorationSpace"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:src="@drawable/ic_shield_warning"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/viewStubContainer"
|
android:id="@+id/viewStubContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -63,6 +63,18 @@
|
|||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/messageE2EDecoration"
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_toStartOf="@id/viewStubContainer"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:src="@drawable/ic_shield_warning"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
|
||||||
<im.vector.riotx.core.ui.views.ReadReceiptsView
|
<im.vector.riotx.core.ui.views.ReadReceiptsView
|
||||||
android:id="@+id/readReceiptsView"
|
android:id="@+id/readReceiptsView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -54,6 +54,18 @@
|
|||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/messageE2EDecoration"
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_alignTop="@id/viewStubContainer"
|
||||||
|
android:layout_toStartOf="@id/viewStubContainer"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:src="@drawable/ic_shield_warning"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/messageFailToSendIndicator"
|
android:id="@+id/messageFailToSendIndicator"
|
||||||
android:layout_width="14dp"
|
android:layout_width="14dp"
|
||||||
|
@ -6,6 +6,22 @@
|
|||||||
<!-- Sections has been created to limit merge conflicts. -->
|
<!-- Sections has been created to limit merge conflicts. -->
|
||||||
|
|
||||||
<!-- BEGIN Strings added by Valere -->
|
<!-- BEGIN Strings added by Valere -->
|
||||||
|
<string name="use_other_session_content_description">Use the latest Riot on your other devices, Riot Web, Riot Desktop, Riot iOS, RiotX for Android, or another cross-signing capable Matrix client</string>
|
||||||
|
<string name="riot_desktop_web">Riot Web\nRiot Desktop</string>
|
||||||
|
<string name="riot_ios_android">Riot iOS\nRiot X for Android</string>
|
||||||
|
<string name="or_other_mx_capabale_client">or another cross-signing capable Matrix client</string>
|
||||||
|
<string name="use_latest_riot">Use the latest Riot on your other devices:</string>
|
||||||
|
<string name="command_description_discard_session">Forces the current outbound group session in an encrypted room to be discarded</string>
|
||||||
|
<string name="command_description_discard_session_not_handled">Only supported in encrypted rooms</string>
|
||||||
|
<!-- first will be replaced by recovery_passphrase, second will be replaced by recovery_key-->
|
||||||
|
<string name="enter_secret_storage_passphrase_or_key">Use your %1$s or use your %2$s to continue.</string>
|
||||||
|
<string name="use_recovery_key">Use Recovery Key</string>
|
||||||
|
<string name="enter_secret_storage_input_key">Select your Recovery Key, or input it manually by typing it or pasting from your clipboard</string>
|
||||||
|
<string name="keys_backup_recovery_key_error_decrypt">Backup could not be decrypted with this Recovery Key: please verify that you entered the correct Recovery Key.</string>
|
||||||
|
<string name="failed_to_access_secure_storage">Failed to access secure storage</string>
|
||||||
|
|
||||||
|
<string name="unencrypted">Unencrypted</string>
|
||||||
|
<string name="encrypted_unverified">Encrypted by an unverified device</string>
|
||||||
<string name="review_logins">Review where you’re logged in</string>
|
<string name="review_logins">Review where you’re logged in</string>
|
||||||
<string name="verify_other_sessions">Verify all your sessions to ensure your account & messages are safe</string>
|
<string name="verify_other_sessions">Verify all your sessions to ensure your account & messages are safe</string>
|
||||||
<!-- END Strings added by Valere -->
|
<!-- END Strings added by Valere -->
|
||||||
|
Loading…
x
Reference in New Issue
Block a user