forked from GitHub-Mirror/riotX-android
Reply in e2e room
+ Add reply option in e2e room + Fix bug 242 + Show preview of messages in menu and in text composer preview
This commit is contained in:
parent
cea8abb9b1
commit
a9dd06562a
@ -25,6 +25,7 @@ import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
|
||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
typealias Content = JsonDict
|
||||
|
||||
@ -146,21 +147,25 @@ data class Event(
|
||||
val adapter = MoshiProvider.providesMoshi().adapter(Event::class.java)
|
||||
mClearEvent = adapter.fromJsonValue(decryptionResult.clearEvent)
|
||||
|
||||
}
|
||||
mClearEvent?.apply {
|
||||
mSenderCurve25519Key = decryptionResult.senderCurve25519Key
|
||||
mClaimedEd25519Key = decryptionResult.claimedEd25519Key
|
||||
mForwardingCurve25519KeyChain = decryptionResult.forwardingCurve25519KeyChain
|
||||
try {
|
||||
// Add "m.relates_to" data from e2e event to the unencrypted event
|
||||
// TODO
|
||||
//if (getWireContent().getAsJsonObject().has("m.relates_to")) {
|
||||
// clearEvent!!.getContentAsJsonObject()
|
||||
// .add("m.relates_to", getWireContent().getAsJsonObject().get("m.relates_to"))
|
||||
//}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Unable to restore 'm.relates_to' the clear event")
|
||||
if (mClearEvent != null) {
|
||||
mSenderCurve25519Key = decryptionResult.senderCurve25519Key
|
||||
mClaimedEd25519Key = decryptionResult.claimedEd25519Key
|
||||
mForwardingCurve25519KeyChain = decryptionResult.forwardingCurve25519KeyChain
|
||||
|
||||
try {
|
||||
content?.get("m.relates_to")?.let { clearRelates ->
|
||||
mClearEvent = mClearEvent?.copy(
|
||||
content = HashMap(mClearEvent!!.content).apply {
|
||||
this["m.relates_to"] = clearRelates
|
||||
}
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Unable to restore 'm.relates_to' the clear event")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
mCryptoError = null
|
||||
|
@ -69,7 +69,7 @@ internal class RoomFactory @Inject constructor(private val context: Context,
|
||||
val stateService = DefaultStateService(roomId, taskExecutor, sendStateTask)
|
||||
val roomMembersService = DefaultMembershipService(roomId, monarchy, taskExecutor, loadRoomMembersTask, inviteTask, joinRoomTask, leaveRoomTask)
|
||||
val readService = DefaultReadService(roomId, monarchy, taskExecutor, setReadMarkersTask, credentials)
|
||||
val relationService = DefaultRelationService(context, credentials, roomId, eventFactory, findReactionEventForUndoTask, monarchy, taskExecutor)
|
||||
val relationService = DefaultRelationService(context, credentials, roomId, eventFactory, cryptoService, findReactionEventForUndoTask, monarchy, taskExecutor)
|
||||
|
||||
return DefaultRoom(
|
||||
roomId,
|
||||
|
@ -21,6 +21,7 @@ import androidx.work.OneTimeWorkRequest
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageType
|
||||
@ -33,6 +34,7 @@ import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryE
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.session.room.send.EncryptEventWorker
|
||||
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
|
||||
import im.vector.matrix.android.internal.session.room.send.RedactEventWorker
|
||||
import im.vector.matrix.android.internal.session.room.send.SendEventWorker
|
||||
@ -49,12 +51,12 @@ internal class DefaultRelationService @Inject constructor(private val context: C
|
||||
private val credentials: Credentials,
|
||||
private val roomId: String,
|
||||
private val eventFactory: LocalEchoEventFactory,
|
||||
private val cryptoService: CryptoService,
|
||||
private val findReactionEventForUndoTask: FindReactionEventForUndoTask,
|
||||
private val monarchy: Monarchy,
|
||||
private val taskExecutor: TaskExecutor)
|
||||
: RelationService {
|
||||
|
||||
|
||||
override fun sendReaction(reaction: String, targetEventId: String): Cancelable {
|
||||
val event = eventFactory.createReactionEvent(roomId, targetEventId, reaction)
|
||||
.also {
|
||||
@ -65,13 +67,8 @@ internal class DefaultRelationService @Inject constructor(private val context: C
|
||||
return CancelableWork(context, sendRelationWork.id)
|
||||
}
|
||||
|
||||
|
||||
private fun createSendRelationWork(event: Event): OneTimeWorkRequest {
|
||||
val sendContentWorkerParams = SendEventWorker.Params(credentials.userId, roomId, event)
|
||||
val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
|
||||
|
||||
return TimelineSendEventWorkCommon.createWork<SendEventWorker>(sendWorkData)
|
||||
|
||||
return createSendEventWork(event)
|
||||
}
|
||||
|
||||
override fun undoReaction(reaction: String, targetEventId: String, myUserId: String)/*: Cancelable*/ {
|
||||
@ -119,31 +116,44 @@ internal class DefaultRelationService @Inject constructor(private val context: C
|
||||
val event = eventFactory.createReplaceTextEvent(roomId, targetEventId, newBodyText, newBodyAutoMarkdown, MessageType.MSGTYPE_TEXT, compatibilityBodyText).also {
|
||||
saveLocalEcho(it)
|
||||
}
|
||||
val sendContentWorkerParams = SendEventWorker.Params(credentials.userId, roomId, event)
|
||||
val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
|
||||
|
||||
//TODO use relation API?
|
||||
|
||||
val workRequest = TimelineSendEventWorkCommon.createWork<SendEventWorker>(sendWorkData)
|
||||
val workRequest = createSendEventWork(event)
|
||||
TimelineSendEventWorkCommon.postWork(context, roomId, workRequest)
|
||||
return CancelableWork(context, workRequest.id)
|
||||
|
||||
}
|
||||
|
||||
|
||||
override fun replyToMessage(eventReplied: Event, replyText: String): Cancelable? {
|
||||
val event = eventFactory.createReplyTextEvent(roomId, eventReplied, replyText)?.also {
|
||||
saveLocalEcho(it)
|
||||
} ?: return null
|
||||
val sendContentWorkerParams = SendEventWorker.Params(credentials.userId, roomId, event)
|
||||
val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
|
||||
|
||||
if (cryptoService.isRoomEncrypted(roomId)) {
|
||||
val encryptWork = createEncryptEventWork(event, listOf("m.relates_to"))
|
||||
val workRequest = createSendEventWork(event)
|
||||
TimelineSendEventWorkCommon.postSequentialWorks(context, roomId, encryptWork, workRequest)
|
||||
return CancelableWork(context, encryptWork.id)
|
||||
|
||||
} else {
|
||||
val workRequest = createSendEventWork(event)
|
||||
TimelineSendEventWorkCommon.postWork(context, roomId, workRequest)
|
||||
return CancelableWork(context, workRequest.id)
|
||||
}
|
||||
|
||||
val workRequest = TimelineSendEventWorkCommon.createWork<SendEventWorker>(sendWorkData)
|
||||
TimelineSendEventWorkCommon.postWork(context, roomId, workRequest)
|
||||
return CancelableWork(context, workRequest.id)
|
||||
}
|
||||
|
||||
private fun createEncryptEventWork(event: Event, keepKeys: List<String>?): OneTimeWorkRequest {
|
||||
// Same parameter
|
||||
val params = EncryptEventWorker.Params(credentials.userId, roomId, event, keepKeys)
|
||||
val sendWorkData = WorkerParamsFactory.toData(params)
|
||||
return TimelineSendEventWorkCommon.createWork<EncryptEventWorker>(sendWorkData)
|
||||
}
|
||||
|
||||
private fun createSendEventWork(event: Event): OneTimeWorkRequest {
|
||||
val sendContentWorkerParams = SendEventWorker.Params(credentials.userId, roomId, event)
|
||||
val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
|
||||
val workRequest = TimelineSendEventWorkCommon.createWork<SendEventWorker>(sendWorkData)
|
||||
return workRequest
|
||||
}
|
||||
|
||||
override fun getEventSummaryLive(eventId: String): LiveData<List<EventAnnotationsSummary>> {
|
||||
return monarchy.findAllMappedWithChanges(
|
||||
|
@ -39,11 +39,15 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters)
|
||||
internal data class Params(
|
||||
override val userId: String,
|
||||
val roomId: String,
|
||||
val event: Event
|
||||
val event: Event,
|
||||
/**Do not encrypt these keys, keep them as is in encrypted content (e.g. m.relates_to)*/
|
||||
val keepKeys: List<String>? = null
|
||||
) : SessionWorkerParams
|
||||
|
||||
@Inject lateinit var crypto: CryptoService
|
||||
@Inject lateinit var localEchoUpdater: LocalEchoUpdater
|
||||
@Inject
|
||||
lateinit var crypto: CryptoService
|
||||
@Inject
|
||||
lateinit var localEchoUpdater: LocalEchoUpdater
|
||||
|
||||
override fun doWork(): Result {
|
||||
|
||||
@ -65,8 +69,13 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters)
|
||||
var result: MXEncryptEventContentResult? = null
|
||||
var error: Throwable? = null
|
||||
|
||||
val localMutableContent = HashMap(localEvent.content)
|
||||
params.keepKeys?.forEach {
|
||||
localMutableContent.remove(it)
|
||||
}
|
||||
|
||||
try {
|
||||
crypto.encryptEventContent(localEvent.content!!, localEvent.type, params.roomId, object : MatrixCallback<MXEncryptEventContentResult> {
|
||||
crypto.encryptEventContent(localMutableContent, localEvent.type, params.roomId, object : MatrixCallback<MXEncryptEventContentResult> {
|
||||
override fun onSuccess(data: MXEncryptEventContentResult) {
|
||||
result = data
|
||||
latch.countDown()
|
||||
@ -83,15 +92,24 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters)
|
||||
}
|
||||
latch.await()
|
||||
|
||||
val safeResult = result
|
||||
if (safeResult != null) {
|
||||
if (result != null) {
|
||||
var modifiedContent = HashMap(result?.eventContent)
|
||||
params.keepKeys?.forEach { toKeep ->
|
||||
localEvent.content?.get(toKeep)?.let {
|
||||
//put it back in the encrypted thing
|
||||
modifiedContent[toKeep] = it
|
||||
}
|
||||
}
|
||||
val safeResult = result!!.copy(eventContent = modifiedContent)
|
||||
val encryptedEvent = localEvent.copy(
|
||||
type = safeResult.eventType,
|
||||
content = safeResult.eventContent
|
||||
)
|
||||
val nextWorkerParams = SendEventWorker.Params(params.userId, params.roomId, encryptedEvent)
|
||||
return Result.success(WorkerParamsFactory.toData(nextWorkerParams))
|
||||
|
||||
}
|
||||
|
||||
val safeError = error
|
||||
val sendState = when (safeError) {
|
||||
is Failure.CryptoError -> SendState.FAILED_UNKNOWN_DEVICES
|
||||
|
@ -100,7 +100,7 @@ object JsonCanonicalizer {
|
||||
|
||||
return result.toString()
|
||||
}
|
||||
is String -> return "\"" + src.toString() + "\""
|
||||
is String -> return JSONObject.quote(src.toString())
|
||||
else -> return src.toString()
|
||||
}
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ class RoomDetailFragment :
|
||||
//TODO this is used at several places, find way to refactor?
|
||||
val messageContent: MessageContent? =
|
||||
event.annotations?.editSummary?.aggregatedContent?.toModel()
|
||||
?: event.root.content.toModel()
|
||||
?: event.root.getClearContent().toModel()
|
||||
val nonFormattedBody = messageContent?.body ?: ""
|
||||
var formattedBody: CharSequence? = null
|
||||
if (messageContent is MessageTextContent && messageContent.format == MessageType.FORMAT_MATRIX_HTML) {
|
||||
|
@ -15,10 +15,8 @@
|
||||
*/
|
||||
package im.vector.riotredesign.features.home.room.detail.timeline.action
|
||||
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
@ -33,11 +31,10 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
import im.vector.riotredesign.core.utils.isSingleEmoji
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData
|
||||
import org.json.JSONObject
|
||||
|
||||
import im.vector.riotredesign.core.utils.isSingleEmoji
|
||||
|
||||
|
||||
data class SimpleAction(val uid: String, val titleRes: Int, val iconResId: Int?, val data: Any? = null)
|
||||
|
||||
@ -80,11 +77,6 @@ class MessageMenuViewModel @AssistedInject constructor(@Assisted initialState: M
|
||||
const val ACTION_FLAG = "ACTION_FLAG"
|
||||
const val ACTION_QUICK_REACT = "ACTION_QUICK_REACT"
|
||||
const val ACTION_VIEW_REACTIONS = "ACTION_VIEW_REACTIONS"
|
||||
|
||||
override fun create(viewModelContext: ViewModelContext, state: MessageMenuState): MessageMenuViewModel? {
|
||||
val fragment: MessageMenuFragment = (viewModelContext as FragmentViewModelContext).fragment()
|
||||
return fragment.messageMenuViewModelFactory.create(state)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
@ -95,7 +87,7 @@ class MessageMenuViewModel @AssistedInject constructor(@Assisted initialState: M
|
||||
val event = session.getRoom(state.roomId)?.getTimeLineEvent(state.eventId) ?: return state
|
||||
|
||||
val messageContent: MessageContent? = event.annotations?.editSummary?.aggregatedContent?.toModel()
|
||||
?: event.root.content.toModel()
|
||||
?: event.root.getClearContent().toModel()
|
||||
val type = messageContent?.type
|
||||
|
||||
val actions = if (!event.sendState.isSent()) {
|
||||
|
Loading…
Reference in New Issue
Block a user