Merge pull request #3031 from vector-im/feature/bma/other_fixies
Some fixies
This commit is contained in:
commit
43fd9910e3
|
@ -8,9 +8,11 @@ Improvements 🙌:
|
||||||
- Split network request `/keys/query` into smaller requests (250 users max) (#2925)
|
- Split network request `/keys/query` into smaller requests (250 users max) (#2925)
|
||||||
- Crypto improvement | Bulk send NO_OLM withheld code
|
- Crypto improvement | Bulk send NO_OLM withheld code
|
||||||
- Display the room shield in all room setting screens
|
- Display the room shield in all room setting screens
|
||||||
|
- Improve message with Emoji only detection (#3017)
|
||||||
|
|
||||||
Bugfix 🐛:
|
Bugfix 🐛:
|
||||||
-
|
- Fix bad theme change for the MainActivity
|
||||||
|
- Handle encrypted reactions (#2509)
|
||||||
|
|
||||||
Translations 🗣:
|
Translations 🗣:
|
||||||
-
|
-
|
||||||
|
|
|
@ -2,7 +2,7 @@ This document aims to describe how Element android displays notifications to the
|
||||||
|
|
||||||
# Table of Contents
|
# Table of Contents
|
||||||
1. [Prerequisites Knowledge](#prerequisites-knowledge)
|
1. [Prerequisites Knowledge](#prerequisites-knowledge)
|
||||||
* [How does a matrix client gets a message from a Home Server?](#how-does-a-matrix-client-gets-a-message-from-a-home-server)
|
* [How does a matrix client get a message from a Home Server?](#how-does-a-matrix-client-get-a-message-from-a-home-server)
|
||||||
* [How does a mobile app receives push notification?](#how-does-a-mobile-app-receives-push-notification)
|
* [How does a mobile app receives push notification?](#how-does-a-mobile-app-receives-push-notification)
|
||||||
* [Push VS Notification](#push-vs-notification)
|
* [Push VS Notification](#push-vs-notification)
|
||||||
* [Push in the matrix federated world](#push-in-the-matrix-federated-world)
|
* [Push in the matrix federated world](#push-in-the-matrix-federated-world)
|
||||||
|
@ -22,7 +22,7 @@ First let's start with some prerequisite knowledge
|
||||||
|
|
||||||
# Prerequisites Knowledge
|
# Prerequisites Knowledge
|
||||||
|
|
||||||
## How does a matrix client gets a message from a Home Server?
|
## How does a matrix client get a message from a Home Server?
|
||||||
|
|
||||||
In order to get messages from a home server, a matrix client need to perform a ``sync`` operation.
|
In order to get messages from a home server, a matrix client need to perform a ``sync`` operation.
|
||||||
|
|
||||||
|
|
|
@ -53,8 +53,9 @@ import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class EventRelationsAggregationProcessor @Inject constructor(@UserId private val userId: String)
|
internal class EventRelationsAggregationProcessor @Inject constructor(
|
||||||
: EventInsertLiveProcessor {
|
@UserId private val userId: String
|
||||||
|
) : EventInsertLiveProcessor {
|
||||||
|
|
||||||
private val allowedTypes = listOf(
|
private val allowedTypes = listOf(
|
||||||
EventType.MESSAGE,
|
EventType.MESSAGE,
|
||||||
|
@ -87,12 +88,12 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr
|
||||||
EventType.REACTION -> {
|
EventType.REACTION -> {
|
||||||
// we got a reaction!!
|
// we got a reaction!!
|
||||||
Timber.v("###REACTION in room $roomId , reaction eventID ${event.eventId}")
|
Timber.v("###REACTION in room $roomId , reaction eventID ${event.eventId}")
|
||||||
handleReaction(event, roomId, realm, userId, isLocalEcho)
|
handleReaction(realm, event, roomId, isLocalEcho)
|
||||||
}
|
}
|
||||||
EventType.MESSAGE -> {
|
EventType.MESSAGE -> {
|
||||||
if (event.unsignedData?.relations?.annotations != null) {
|
if (event.unsignedData?.relations?.annotations != null) {
|
||||||
Timber.v("###REACTION Agreggation in room $roomId for event ${event.eventId}")
|
Timber.v("###REACTION Aggregation in room $roomId for event ${event.eventId}")
|
||||||
handleInitialAggregatedRelations(event, roomId, event.unsignedData.relations.annotations, realm)
|
handleInitialAggregatedRelations(realm, event, roomId, event.unsignedData.relations.annotations)
|
||||||
|
|
||||||
EventAnnotationsSummaryEntity.where(realm, roomId, event.eventId ?: "").findFirst()
|
EventAnnotationsSummaryEntity.where(realm, roomId, event.eventId ?: "").findFirst()
|
||||||
?.let {
|
?.let {
|
||||||
|
@ -108,7 +109,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr
|
||||||
handleReplace(realm, event, content, roomId, isLocalEcho)
|
handleReplace(realm, event, content, roomId, isLocalEcho)
|
||||||
} else if (content?.relatesTo?.type == RelationType.RESPONSE) {
|
} else if (content?.relatesTo?.type == RelationType.RESPONSE) {
|
||||||
Timber.v("###RESPONSE in room $roomId for event ${event.eventId}")
|
Timber.v("###RESPONSE in room $roomId for event ${event.eventId}")
|
||||||
handleResponse(realm, userId, event, content, roomId, isLocalEcho)
|
handleResponse(realm, event, content, roomId, isLocalEcho)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +123,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr
|
||||||
Timber.v("## SAS REF in room $roomId for event ${event.eventId}")
|
Timber.v("## SAS REF in room $roomId for event ${event.eventId}")
|
||||||
event.content.toModel<MessageRelationContent>()?.relatesTo?.let {
|
event.content.toModel<MessageRelationContent>()?.relatesTo?.let {
|
||||||
if (it.type == RelationType.REFERENCE && it.eventId != null) {
|
if (it.type == RelationType.REFERENCE && it.eventId != null) {
|
||||||
handleVerification(realm, event, roomId, isLocalEcho, it.eventId, userId)
|
handleVerification(realm, event, roomId, isLocalEcho, it.eventId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,7 +141,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr
|
||||||
handleReplace(realm, event, it, roomId, isLocalEcho, encryptedEventContent.relatesTo.eventId)
|
handleReplace(realm, event, it, roomId, isLocalEcho, encryptedEventContent.relatesTo.eventId)
|
||||||
} else if (encryptedEventContent.relatesTo.type == RelationType.RESPONSE) {
|
} else if (encryptedEventContent.relatesTo.type == RelationType.RESPONSE) {
|
||||||
Timber.v("###RESPONSE in room $roomId for event ${event.eventId}")
|
Timber.v("###RESPONSE in room $roomId for event ${event.eventId}")
|
||||||
handleResponse(realm, userId, event, it, roomId, isLocalEcho, encryptedEventContent.relatesTo.eventId)
|
handleResponse(realm, event, it, roomId, isLocalEcho, encryptedEventContent.relatesTo.eventId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (encryptedEventContent?.relatesTo?.type == RelationType.REFERENCE) {
|
} else if (encryptedEventContent?.relatesTo?.type == RelationType.REFERENCE) {
|
||||||
|
@ -154,10 +155,17 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr
|
||||||
EventType.KEY_VERIFICATION_KEY -> {
|
EventType.KEY_VERIFICATION_KEY -> {
|
||||||
Timber.v("## SAS REF in room $roomId for event ${event.eventId}")
|
Timber.v("## SAS REF in room $roomId for event ${event.eventId}")
|
||||||
encryptedEventContent.relatesTo.eventId?.let {
|
encryptedEventContent.relatesTo.eventId?.let {
|
||||||
handleVerification(realm, event, roomId, isLocalEcho, it, userId)
|
handleVerification(realm, event, roomId, isLocalEcho, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (encryptedEventContent?.relatesTo?.type == RelationType.ANNOTATION) {
|
||||||
|
// Reaction
|
||||||
|
if (event.getClearType() == EventType.REACTION) {
|
||||||
|
// we got a reaction!!
|
||||||
|
Timber.v("###REACTION e2e in room $roomId , reaction eventID ${event.eventId}")
|
||||||
|
handleReaction(realm, event, roomId, isLocalEcho)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EventType.REDACTION -> {
|
EventType.REDACTION -> {
|
||||||
|
@ -172,11 +180,11 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr
|
||||||
// was this event a m.replace
|
// was this event a m.replace
|
||||||
val contentModel = ContentMapper.map(eventToPrune.content)?.toModel<MessageContent>()
|
val contentModel = ContentMapper.map(eventToPrune.content)?.toModel<MessageContent>()
|
||||||
if (RelationType.REPLACE == contentModel?.relatesTo?.type && contentModel.relatesTo?.eventId != null) {
|
if (RelationType.REPLACE == contentModel?.relatesTo?.type && contentModel.relatesTo?.eventId != null) {
|
||||||
handleRedactionOfReplace(eventToPrune, contentModel.relatesTo!!.eventId!!, realm)
|
handleRedactionOfReplace(realm, eventToPrune, contentModel.relatesTo!!.eventId!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EventType.REACTION -> {
|
EventType.REACTION -> {
|
||||||
handleReactionRedact(eventToPrune, realm, userId)
|
handleReactionRedact(realm, eventToPrune)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,7 +275,6 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleResponse(realm: Realm,
|
private fun handleResponse(realm: Realm,
|
||||||
userId: String,
|
|
||||||
event: Event,
|
event: Event,
|
||||||
content: MessageContent,
|
content: MessageContent,
|
||||||
roomId: String,
|
roomId: String,
|
||||||
|
@ -354,7 +361,10 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr
|
||||||
existingPollSummary.aggregatedContent = ContentMapper.map(sumModel.toContent())
|
existingPollSummary.aggregatedContent = ContentMapper.map(sumModel.toContent())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleInitialAggregatedRelations(event: Event, roomId: String, aggregation: AggregatedAnnotation, realm: Realm) {
|
private fun handleInitialAggregatedRelations(realm: Realm,
|
||||||
|
event: Event,
|
||||||
|
roomId: String,
|
||||||
|
aggregation: AggregatedAnnotation) {
|
||||||
if (SHOULD_HANDLE_SERVER_AGREGGATION) {
|
if (SHOULD_HANDLE_SERVER_AGREGGATION) {
|
||||||
aggregation.chunk?.forEach {
|
aggregation.chunk?.forEach {
|
||||||
if (it.type == EventType.REACTION) {
|
if (it.type == EventType.REACTION) {
|
||||||
|
@ -376,7 +386,10 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleReaction(event: Event, roomId: String, realm: Realm, userId: String, isLocalEcho: Boolean) {
|
private fun handleReaction(realm: Realm,
|
||||||
|
event: Event,
|
||||||
|
roomId: String,
|
||||||
|
isLocalEcho: Boolean) {
|
||||||
val content = event.content.toModel<ReactionContent>()
|
val content = event.content.toModel<ReactionContent>()
|
||||||
if (content == null) {
|
if (content == null) {
|
||||||
Timber.e("Malformed reaction content ${event.content}")
|
Timber.e("Malformed reaction content ${event.content}")
|
||||||
|
@ -441,7 +454,9 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr
|
||||||
/**
|
/**
|
||||||
* Called when an event is deleted
|
* Called when an event is deleted
|
||||||
*/
|
*/
|
||||||
private fun handleRedactionOfReplace(redacted: EventEntity, relatedEventId: String, realm: Realm) {
|
private fun handleRedactionOfReplace(realm: Realm,
|
||||||
|
redacted: EventEntity,
|
||||||
|
relatedEventId: String) {
|
||||||
Timber.d("Handle redaction of m.replace")
|
Timber.d("Handle redaction of m.replace")
|
||||||
val eventSummary = EventAnnotationsSummaryEntity.where(realm, redacted.roomId, relatedEventId).findFirst()
|
val eventSummary = EventAnnotationsSummaryEntity.where(realm, redacted.roomId, relatedEventId).findFirst()
|
||||||
if (eventSummary == null) {
|
if (eventSummary == null) {
|
||||||
|
@ -457,7 +472,8 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr
|
||||||
sourceToDiscard.deleteFromRealm()
|
sourceToDiscard.deleteFromRealm()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleReactionRedact(eventToPrune: EventEntity, realm: Realm, userId: String) {
|
private fun handleReactionRedact(realm: Realm,
|
||||||
|
eventToPrune: EventEntity) {
|
||||||
Timber.v("REDACTION of reaction ${eventToPrune.eventId}")
|
Timber.v("REDACTION of reaction ${eventToPrune.eventId}")
|
||||||
// delete a reaction, need to update the annotation summary if any
|
// delete a reaction, need to update the annotation summary if any
|
||||||
val reactionContent: ReactionContent = EventMapper.map(eventToPrune).content.toModel() ?: return
|
val reactionContent: ReactionContent = EventMapper.map(eventToPrune).content.toModel() ?: return
|
||||||
|
@ -494,7 +510,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleVerification(realm: Realm, event: Event, roomId: String, isLocalEcho: Boolean, relatedEventId: String, userId: String) {
|
private fun handleVerification(realm: Realm, event: Event, roomId: String, isLocalEcho: Boolean, relatedEventId: String) {
|
||||||
val eventSummary = EventAnnotationsSummaryEntity.getOrCreate(realm, roomId, relatedEventId)
|
val eventSummary = EventAnnotationsSummaryEntity.getOrCreate(realm, roomId, relatedEventId)
|
||||||
|
|
||||||
val verifSummary = eventSummary.referencesSummaryEntity
|
val verifSummary = eventSummary.referencesSummaryEntity
|
||||||
|
|
|
@ -16,62 +16,7 @@
|
||||||
|
|
||||||
package im.vector.app.core.utils
|
package im.vector.app.core.utils
|
||||||
|
|
||||||
import java.util.regex.Pattern
|
import com.vanniktech.emoji.EmojiUtils
|
||||||
|
|
||||||
private val emojisPattern = Pattern.compile("((?:[\uD83C\uDF00-\uD83D\uDDFF]" +
|
|
||||||
"|[\uD83E\uDD00-\uD83E\uDDFF]" +
|
|
||||||
"|[\uD83D\uDE00-\uD83D\uDE4F]" +
|
|
||||||
"|[\uD83D\uDE80-\uD83D\uDEFF]" +
|
|
||||||
"|[\u2600-\u26FF]\uFE0F?" +
|
|
||||||
"|[\u2700-\u27BF]\uFE0F?" +
|
|
||||||
"|\u24C2\uFE0F?" +
|
|
||||||
"|[\uD83C\uDDE6-\uD83C\uDDFF]{1,2}" +
|
|
||||||
"|[\uD83C\uDD70\uD83C\uDD71\uD83C\uDD7E\uD83C\uDD7F\uD83C\uDD8E\uD83C\uDD91-\uD83C\uDD9A]\uFE0F?" +
|
|
||||||
"|[\u0023\u002A\u0030-\u0039]\uFE0F?\u20E3" +
|
|
||||||
"|[\u2194-\u2199\u21A9-\u21AA]\uFE0F?" +
|
|
||||||
"|[\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55]\uFE0F?" +
|
|
||||||
"|[\u2934\u2935]\uFE0F?" +
|
|
||||||
"|[\u3030\u303D]\uFE0F?" +
|
|
||||||
"|[\u3297\u3299]\uFE0F?" +
|
|
||||||
"|[\uD83C\uDE01\uD83C\uDE02\uD83C\uDE1A\uD83C\uDE2F\uD83C\uDE32-\uD83C\uDE3A\uD83C\uDE50\uD83C\uDE51]\uFE0F?" +
|
|
||||||
"|[\u203C\u2049]\uFE0F?" +
|
|
||||||
"|[\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE]\uFE0F?" +
|
|
||||||
"|[\u00A9\u00AE]\uFE0F?" +
|
|
||||||
"|[\u2122\u2139]\uFE0F?" +
|
|
||||||
"|\uD83C\uDC04\uFE0F?" +
|
|
||||||
"|\uD83C\uDCCF\uFE0F?" +
|
|
||||||
"|[\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA]\uFE0F?))")
|
|
||||||
|
|
||||||
/*
|
|
||||||
// A hashset from all supported emoji
|
|
||||||
private var knownEmojiSet: HashSet<String>? = null
|
|
||||||
|
|
||||||
fun initKnownEmojiHashSet(context: Context, done: (() -> Unit)? = null) {
|
|
||||||
GlobalScope.launch {
|
|
||||||
context.resources.openRawResource(R.raw.emoji_picker_datasource).use { input ->
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
val jsonAdapter = moshi.adapter(EmojiData::class.java)
|
|
||||||
val inputAsString = input.bufferedReader().use { it.readText() }
|
|
||||||
val source = jsonAdapter.fromJson(inputAsString)
|
|
||||||
knownEmojiSet = HashSet<String>().also {
|
|
||||||
source?.emojis?.mapTo(it) { (_, value) ->
|
|
||||||
value.emojiString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
done?.invoke()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isSingleEmoji(string: String): Boolean {
|
|
||||||
if (knownEmojiSet == null) {
|
|
||||||
Timber.e("Known Emoji Hashset not initialized")
|
|
||||||
// use fallback regexp
|
|
||||||
return containsOnlyEmojis(string)
|
|
||||||
}
|
|
||||||
return knownEmojiSet?.contains(string) ?: false
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if a string contains emojis.
|
* Test if a string contains emojis.
|
||||||
|
@ -82,36 +27,8 @@ fun isSingleEmoji(string: String): Boolean {
|
||||||
* @return true if the body contains only emojis
|
* @return true if the body contains only emojis
|
||||||
*/
|
*/
|
||||||
fun containsOnlyEmojis(str: String?): Boolean {
|
fun containsOnlyEmojis(str: String?): Boolean {
|
||||||
var res = false
|
// Now rely on vanniktech library
|
||||||
|
return EmojiUtils.isOnlyEmojis(str)
|
||||||
if (str != null && str.isNotEmpty()) {
|
|
||||||
val matcher = emojisPattern.matcher(str)
|
|
||||||
|
|
||||||
var start = -1
|
|
||||||
var end = -1
|
|
||||||
|
|
||||||
while (matcher.find()) {
|
|
||||||
val nextStart = matcher.start()
|
|
||||||
|
|
||||||
// first emoji position
|
|
||||||
if (start < 0) {
|
|
||||||
if (nextStart > 0) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// must not have a character between
|
|
||||||
if (nextStart != end) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
start = nextStart
|
|
||||||
end = matcher.end()
|
|
||||||
}
|
|
||||||
|
|
||||||
res = -1 != start && end == str.length
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -43,6 +43,7 @@ import im.vector.app.features.popup.PopupAlertManager
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import im.vector.app.features.signout.hard.SignedOutActivity
|
import im.vector.app.features.signout.hard.SignedOutActivity
|
||||||
import im.vector.app.features.signout.soft.SoftLogoutActivity
|
import im.vector.app.features.signout.soft.SoftLogoutActivity
|
||||||
|
import im.vector.app.features.themes.ActivityOtherThemes
|
||||||
import im.vector.app.features.ui.UiStateRepository
|
import im.vector.app.features.ui.UiStateRepository
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -83,6 +84,8 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
|
||||||
|
|
||||||
override fun getBinding() = ActivityMainBinding.inflate(layoutInflater)
|
override fun getBinding() = ActivityMainBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
override fun getOtherThemes() = ActivityOtherThemes.Launcher
|
||||||
|
|
||||||
private lateinit var args: MainActivityArgs
|
private lateinit var args: MainActivityArgs
|
||||||
|
|
||||||
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
||||||
|
|
|
@ -30,10 +30,8 @@ import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.showPassword
|
import im.vector.app.core.extensions.showPassword
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.utils.colorizeMatchingText
|
|
||||||
import im.vector.app.databinding.FragmentSsssAccessFromPassphraseBinding
|
import im.vector.app.databinding.FragmentSsssAccessFromPassphraseBinding
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -59,8 +57,9 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor(
|
||||||
key
|
key
|
||||||
)
|
)
|
||||||
.toSpannable()
|
.toSpannable()
|
||||||
.colorizeMatchingText(pass, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
|
// TODO Restore coloration when we will have a FAQ to open with those terms
|
||||||
.colorizeMatchingText(key, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
|
// .colorizeMatchingText(pass, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
|
||||||
|
// .colorizeMatchingText(key, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
|
||||||
|
|
||||||
views.ssssPassphraseEnterEdittext.editorActionEvents()
|
views.ssssPassphraseEnterEdittext.editorActionEvents()
|
||||||
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||||
|
|
|
@ -119,13 +119,18 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
||||||
Timber.v("## SAS verificationRequestCreated ${pr.transactionId}")
|
Timber.v("## SAS verificationRequestCreated ${pr.transactionId}")
|
||||||
// For incoming request we should prompt (if not in activity where this request apply)
|
// For incoming request we should prompt (if not in activity where this request apply)
|
||||||
if (pr.isIncoming) {
|
if (pr.isIncoming) {
|
||||||
val user = session?.getUser(pr.otherUserId)
|
val user = session?.getUser(pr.otherUserId)?.toMatrixItem()
|
||||||
val name = user?.getBestName() ?: pr.otherUserId
|
val name = user?.getBestName() ?: pr.otherUserId
|
||||||
|
val description = if (name == pr.otherUserId) {
|
||||||
|
name
|
||||||
|
} else {
|
||||||
|
"$name (${pr.otherUserId})"
|
||||||
|
}
|
||||||
|
|
||||||
val alert = VerificationVectorAlert(
|
val alert = VerificationVectorAlert(
|
||||||
uniqueIdForVerificationRequest(pr),
|
uniqueIdForVerificationRequest(pr),
|
||||||
context.getString(R.string.sas_incoming_request_notif_title),
|
context.getString(R.string.sas_incoming_request_notif_title),
|
||||||
"$name(${pr.otherUserId})",
|
description,
|
||||||
R.drawable.ic_shield_black,
|
R.drawable.ic_shield_black,
|
||||||
shouldBeDisplayedIn = { activity ->
|
shouldBeDisplayedIn = { activity ->
|
||||||
if (activity is RoomDetailActivity) {
|
if (activity is RoomDetailActivity) {
|
||||||
|
@ -136,7 +141,7 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.apply {
|
.apply {
|
||||||
viewBinder = VerificationVectorAlert.ViewBinder(user?.toMatrixItem(), avatarRenderer.get())
|
viewBinder = VerificationVectorAlert.ViewBinder(user, avatarRenderer.get())
|
||||||
contentAction = Runnable {
|
contentAction = Runnable {
|
||||||
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||||
val roomId = pr.roomId
|
val roomId = pr.roomId
|
||||||
|
|
|
@ -64,7 +64,6 @@ class TimelineItemFactory @Inject constructor(private val messageItemFactory: Me
|
||||||
EventType.STATE_ROOM_SERVER_ACL,
|
EventType.STATE_ROOM_SERVER_ACL,
|
||||||
EventType.STATE_ROOM_GUEST_ACCESS,
|
EventType.STATE_ROOM_GUEST_ACCESS,
|
||||||
EventType.STATE_ROOM_POWER_LEVELS,
|
EventType.STATE_ROOM_POWER_LEVELS,
|
||||||
EventType.REACTION,
|
|
||||||
EventType.REDACTION -> noticeItemFactory.create(event, highlight, callback)
|
EventType.REDACTION -> noticeItemFactory.create(event, highlight, callback)
|
||||||
EventType.STATE_ROOM_WIDGET_LEGACY,
|
EventType.STATE_ROOM_WIDGET_LEGACY,
|
||||||
EventType.STATE_ROOM_WIDGET -> widgetItemFactory.create(event, highlight, callback)
|
EventType.STATE_ROOM_WIDGET -> widgetItemFactory.create(event, highlight, callback)
|
||||||
|
@ -91,6 +90,7 @@ class TimelineItemFactory @Inject constructor(private val messageItemFactory: Me
|
||||||
EventType.KEY_VERIFICATION_KEY,
|
EventType.KEY_VERIFICATION_KEY,
|
||||||
EventType.KEY_VERIFICATION_READY,
|
EventType.KEY_VERIFICATION_READY,
|
||||||
EventType.KEY_VERIFICATION_MAC,
|
EventType.KEY_VERIFICATION_MAC,
|
||||||
|
EventType.REACTION,
|
||||||
EventType.CALL_CANDIDATES,
|
EventType.CALL_CANDIDATES,
|
||||||
EventType.CALL_REPLACES,
|
EventType.CALL_REPLACES,
|
||||||
EventType.CALL_SELECT_ANSWER,
|
EventType.CALL_SELECT_ANSWER,
|
||||||
|
|
|
@ -26,6 +26,7 @@ import im.vector.app.R
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.core.utils.isAnimationDisabled
|
import im.vector.app.core.utils.isAnimationDisabled
|
||||||
import im.vector.app.features.pin.PinActivity
|
import im.vector.app.features.pin.PinActivity
|
||||||
|
import im.vector.app.features.signout.hard.SignedOutActivity
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
|
@ -294,6 +295,7 @@ class PopupAlertManager @Inject constructor() {
|
||||||
private fun shouldBeDisplayedIn(alert: VectorAlert?, activity: Activity): Boolean {
|
private fun shouldBeDisplayedIn(alert: VectorAlert?, activity: Activity): Boolean {
|
||||||
return alert != null
|
return alert != null
|
||||||
&& activity !is PinActivity
|
&& activity !is PinActivity
|
||||||
|
&& activity !is SignedOutActivity
|
||||||
&& activity is VectorBaseActivity<*>
|
&& activity is VectorBaseActivity<*>
|
||||||
&& alert.shouldBeDisplayedIn.invoke(activity)
|
&& alert.shouldBeDisplayedIn.invoke(activity)
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,7 +222,6 @@ class RoomProfileController @Inject constructor(
|
||||||
buildProfileAction(
|
buildProfileAction(
|
||||||
id = "devTools",
|
id = "devTools",
|
||||||
title = stringProvider.getString(R.string.dev_tools_menu_name),
|
title = stringProvider.getString(R.string.dev_tools_menu_name),
|
||||||
subtitle = roomSummary.roomId,
|
|
||||||
dividerColor = dividerColor,
|
dividerColor = dividerColor,
|
||||||
divider = false,
|
divider = false,
|
||||||
editable = true,
|
editable = true,
|
||||||
|
|
|
@ -31,6 +31,11 @@ sealed class ActivityOtherThemes(@StyleRes val dark: Int,
|
||||||
R.style.AppTheme_Black
|
R.style.AppTheme_Black
|
||||||
)
|
)
|
||||||
|
|
||||||
|
object Launcher : ActivityOtherThemes(
|
||||||
|
R.style.AppTheme_Launcher,
|
||||||
|
R.style.AppTheme_Launcher
|
||||||
|
)
|
||||||
|
|
||||||
object AttachmentsPreview : ActivityOtherThemes(
|
object AttachmentsPreview : ActivityOtherThemes(
|
||||||
R.style.AppTheme_AttachmentsPreview,
|
R.style.AppTheme_AttachmentsPreview,
|
||||||
R.style.AppTheme_AttachmentsPreview
|
R.style.AppTheme_AttachmentsPreview
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="32dp"
|
||||||
|
android:paddingBottom="32dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/ssss_shield"
|
android:id="@+id/ssss_shield"
|
||||||
|
@ -28,7 +30,6 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginTop="36dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:text="@string/recovery_passphrase"
|
android:text="@string/recovery_passphrase"
|
||||||
android:textColor="?riotx_text_primary"
|
android:textColor="?riotx_text_primary"
|
||||||
|
@ -38,7 +39,6 @@
|
||||||
app:layout_constraintStart_toEndOf="@id/ssss_shield"
|
app:layout_constraintStart_toEndOf="@id/ssss_shield"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/ssss_restore_with_passphrase_warning_text"
|
android:id="@+id/ssss_restore_with_passphrase_warning_text"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
@ -51,7 +51,6 @@
|
||||||
app:layout_constraintTop_toBottomOf="@id/ssss_restore_with_passphrase"
|
app:layout_constraintTop_toBottomOf="@id/ssss_restore_with_passphrase"
|
||||||
tools:text="@string/enter_secret_storage_passphrase_or_key" />
|
tools:text="@string/enter_secret_storage_passphrase_or_key" />
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/ssss_passphrase_enter_til"
|
android:id="@+id/ssss_passphrase_enter_til"
|
||||||
style="@style/VectorTextInputLayout"
|
style="@style/VectorTextInputLayout"
|
||||||
|
@ -82,61 +81,62 @@
|
||||||
android:layout_width="@dimen/layout_touch_size"
|
android:layout_width="@dimen/layout_touch_size"
|
||||||
android:layout_height="@dimen/layout_touch_size"
|
android:layout_height="@dimen/layout_touch_size"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:scaleType="center"
|
android:scaleType="center"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@+id/ssss_passphrase_enter_til"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/ssss_passphrase_enter_til"
|
app:layout_constraintTop_toTopOf="@+id/ssss_passphrase_enter_til"
|
||||||
app:tint="?colorAccent" />
|
app:tint="?colorAccent" />
|
||||||
|
|
||||||
<!-- -->
|
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/ssss_passphrase_use_key"
|
|
||||||
style="@style/Widget.MaterialComponents.Button.TextButton.Icon"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/use_recovery_key"
|
|
||||||
app:icon="@drawable/ic_security_key_24dp"
|
|
||||||
tools:ignore="MissingConstraints" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/ssss_passphrase_submit"
|
android:id="@+id/ssss_passphrase_submit"
|
||||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/_continue"
|
|
||||||
tools:ignore="MissingConstraints" />
|
|
||||||
|
|
||||||
<androidx.constraintlayout.helper.widget.Flow
|
|
||||||
android:id="@+id/ssss_passphrase_flow"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||||
app:constraint_referenced_ids="ssss_passphrase_use_key,ssss_passphrase_submit"
|
android:text="@string/_continue"
|
||||||
app:flow_horizontalStyle="spread_inside"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:flow_wrapMode="chain"
|
app:layout_constraintTop_toBottomOf="@+id/ssss_passphrase_enter_til" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/ssss_passphrase_or"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/or"
|
||||||
|
android:textColor="?riotx_text_primary"
|
||||||
|
android:textSize="18sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/ssss_passphrase_submit" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/ssss_passphrase_use_key"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.TextButton.Icon"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="@string/use_recovery_key"
|
||||||
|
app:icon="@drawable/ic_security_key_24dp"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/ssss_passphrase_reset"
|
app:layout_constraintBottom_toTopOf="@+id/ssss_passphrase_reset"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/ssss_passphrase_enter_til"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_goneMarginBottom="32dp" />
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/ssss_passphrase_or" />
|
||||||
|
|
||||||
<im.vector.app.core.ui.views.BottomSheetActionButton
|
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||||
android:id="@+id/ssss_passphrase_reset"
|
android:id="@+id/ssss_passphrase_reset"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginBottom="32dp"
|
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
app:actionTitle="@string/bad_passphrase_key_reset_all_action"
|
app:actionTitle="@string/bad_passphrase_key_reset_all_action"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/ssss_passphrase_flow"
|
app:layout_constraintTop_toBottomOf="@id/ssss_passphrase_use_key"
|
||||||
app:leftIcon="@drawable/ic_alert_triangle"
|
app:leftIcon="@drawable/ic_alert_triangle"
|
||||||
app:tint="@color/vector_error_color"
|
app:tint="@color/vector_error_color"
|
||||||
app:titleTextColor="?riotx_text_secondary" />
|
app:titleTextColor="?riotx_text_secondary" />
|
||||||
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
Loading…
Reference in New Issue