forked from GitHub-Mirror/riotX-android
Toggle Quick React (agree/disagree like/dislike)
This commit is contained in:
@ -35,4 +35,12 @@ interface ReactionService {
|
||||
*/
|
||||
fun undoReaction(reaction: String, targetEventId: String, myUserId: String)//: Cancelable
|
||||
|
||||
|
||||
/**
|
||||
* Undo a reaction (emoji) to the targetedEvent.
|
||||
* @param reaction the reaction (preferably emoji)
|
||||
* @param targetEventId the id of the event being reacted
|
||||
*/
|
||||
fun updateQuickReaction(reaction: String, oppositeReaction: String, targetEventId: String, myUserId: String)
|
||||
|
||||
}
|
@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.internal.session.room.membership.DefaultMembershipService
|
||||
import im.vector.matrix.android.internal.session.room.annotation.FindReactionEventForUndoTask
|
||||
import im.vector.matrix.android.internal.session.room.annotation.DefaultReactionService
|
||||
import im.vector.matrix.android.internal.session.room.annotation.UpdateQuickReactionTask
|
||||
import im.vector.matrix.android.internal.session.room.membership.LoadRoomMembersTask
|
||||
import im.vector.matrix.android.internal.session.room.membership.SenderRoomMemberExtractor
|
||||
import im.vector.matrix.android.internal.session.room.membership.joining.InviteTask
|
||||
@ -48,6 +49,7 @@ internal class RoomFactory(private val monarchy: Monarchy,
|
||||
private val contextOfEventTask: GetContextOfEventTask,
|
||||
private val setReadMarkersTask: SetReadMarkersTask,
|
||||
private val findReactionEventForUndoTask: FindReactionEventForUndoTask,
|
||||
private val updateQuickReactionTask: UpdateQuickReactionTask,
|
||||
private val joinRoomTask: JoinRoomTask,
|
||||
private val leaveRoomTask: LeaveRoomTask) {
|
||||
|
||||
@ -56,7 +58,7 @@ internal class RoomFactory(private val monarchy: Monarchy,
|
||||
val timelineEventFactory = TimelineEventFactory(roomMemberExtractor, EventRelationExtractor())
|
||||
val timelineService = DefaultTimelineService(roomId, monarchy, taskExecutor, timelineEventFactory, contextOfEventTask, paginationTask)
|
||||
val sendService = DefaultSendService(roomId, eventFactory, monarchy)
|
||||
val reactionService = DefaultReactionService(roomId, eventFactory, monarchy, findReactionEventForUndoTask, taskExecutor)
|
||||
val reactionService = DefaultReactionService(roomId, eventFactory, findReactionEventForUndoTask, updateQuickReactionTask, taskExecutor)
|
||||
val stateService = DefaultStateService(roomId, taskExecutor, sendStateTask)
|
||||
val roomMembersService = DefaultMembershipService(roomId, monarchy, taskExecutor, loadRoomMembersTask, inviteTask, joinRoomTask, leaveRoomTask)
|
||||
val readService = DefaultReadService(roomId, monarchy, taskExecutor, setReadMarkersTask)
|
||||
|
@ -18,7 +18,9 @@ package im.vector.matrix.android.internal.session.room
|
||||
|
||||
import im.vector.matrix.android.internal.session.DefaultSession
|
||||
import im.vector.matrix.android.internal.session.room.annotation.DefaultFindReactionEventForUndoTask
|
||||
import im.vector.matrix.android.internal.session.room.annotation.DefaultUpdateQuickReactionTask
|
||||
import im.vector.matrix.android.internal.session.room.annotation.FindReactionEventForUndoTask
|
||||
import im.vector.matrix.android.internal.session.room.annotation.UpdateQuickReactionTask
|
||||
import im.vector.matrix.android.internal.session.room.create.CreateRoomTask
|
||||
import im.vector.matrix.android.internal.session.room.create.DefaultCreateRoomTask
|
||||
import im.vector.matrix.android.internal.session.room.membership.DefaultLoadRoomMembersTask
|
||||
@ -75,7 +77,7 @@ class RoomModule {
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
RoomFactory(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get())
|
||||
RoomFactory(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
@ -102,6 +104,10 @@ class RoomModule {
|
||||
DefaultFindReactionEventForUndoTask(get()) as FindReactionEventForUndoTask
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
DefaultUpdateQuickReactionTask(get()) as UpdateQuickReactionTask
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
DefaultPruneEventTask(get()) as PruneEventTask
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
package im.vector.matrix.android.internal.session.room.annotation
|
||||
|
||||
import androidx.work.*
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.room.model.annotation.ReactionService
|
||||
@ -39,8 +38,8 @@ private val WORK_CONSTRAINTS = Constraints.Builder()
|
||||
|
||||
internal class DefaultReactionService(private val roomId: String,
|
||||
private val eventFactory: LocalEchoEventFactory,
|
||||
private val monarchy: Monarchy,
|
||||
private val findReactionEventForUndoTask: FindReactionEventForUndoTask,
|
||||
private val updateQuickReactionTask: UpdateQuickReactionTask,
|
||||
private val taskExecutor: TaskExecutor)
|
||||
: ReactionService {
|
||||
|
||||
@ -95,6 +94,32 @@ internal class DefaultReactionService(private val roomId: String,
|
||||
|
||||
}
|
||||
|
||||
|
||||
override fun updateQuickReaction(reaction: String, oppositeReaction: String, targetEventId: String, myUserId: String) {
|
||||
|
||||
val params = UpdateQuickReactionTask.Params(
|
||||
roomId,
|
||||
targetEventId,
|
||||
reaction,
|
||||
oppositeReaction,
|
||||
myUserId
|
||||
)
|
||||
|
||||
updateQuickReactionTask.configureWith(params)
|
||||
.dispatchTo(object : MatrixCallback<UpdateQuickReactionTask.Result> {
|
||||
override fun onSuccess(data: UpdateQuickReactionTask.Result) {
|
||||
data.reactionToAdd?.also { sendReaction(it, targetEventId) }
|
||||
data.reactionToRedact.forEach {
|
||||
val redactWork = createRedactEventWork(it, null)
|
||||
WorkManager.getInstance()
|
||||
.beginUniqueWork(buildWorkIdentifier(REACTION_WORK), ExistingWorkPolicy.APPEND, redactWork)
|
||||
.enqueue()
|
||||
}
|
||||
}
|
||||
})
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
private fun buildWorkIdentifier(identifier: String): String {
|
||||
return "${roomId}_$identifier"
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import android.content.Context
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import com.squareup.moshi.JsonClass
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.annotation.ReactionContent
|
||||
@ -66,6 +67,11 @@ class SendRelationWorker(context: Context, params: WorkerParameters)
|
||||
content = localEvent.content
|
||||
)
|
||||
}
|
||||
return result.fold({ Result.retry() }, { Result.success() })
|
||||
return result.fold({
|
||||
when (it) {
|
||||
is Failure.NetworkConnection -> Result.retry()
|
||||
else -> Result.failure()
|
||||
}
|
||||
}, { Result.success() })
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package im.vector.matrix.android.internal.session.room.annotation
|
||||
|
||||
import arrow.core.Try
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.model.ReactionAggregatedSummaryEntityFields
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import io.realm.Realm
|
||||
|
||||
|
||||
internal interface UpdateQuickReactionTask : Task<UpdateQuickReactionTask.Params, UpdateQuickReactionTask.Result> {
|
||||
|
||||
data class Params(
|
||||
val roomId: String,
|
||||
val eventId: String,
|
||||
val reaction: String,
|
||||
val oppositeReaction: String,
|
||||
val myUserId: String
|
||||
)
|
||||
|
||||
data class Result(
|
||||
val reactionToAdd: String?,
|
||||
val reactionToRedact: List<String>
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultUpdateQuickReactionTask(private val monarchy: Monarchy) : UpdateQuickReactionTask {
|
||||
override fun execute(params: UpdateQuickReactionTask.Params): Try<UpdateQuickReactionTask.Result> {
|
||||
return Try {
|
||||
var res: Pair<String?, List<String>?>? = null
|
||||
monarchy.doWithRealm { realm ->
|
||||
res = updateQuickReaction(realm, params.reaction, params.oppositeReaction, params.eventId, params.myUserId)
|
||||
}
|
||||
UpdateQuickReactionTask.Result(res?.first, res?.second ?: emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun updateQuickReaction(realm: Realm, reaction: String, oppositeReaction: String, eventId: String, myUserId: String): Pair<String?, List<String>?> {
|
||||
//the emoji reaction has been selected, we need to check if we have reacted it or not
|
||||
val existingSummary = EventAnnotationsSummaryEntity.where(realm, eventId).findFirst()
|
||||
?: return Pair(reaction, null)
|
||||
|
||||
//Ok there is already reactions on this event, have we reacted to it
|
||||
val aggregationForReaction = existingSummary.reactionsSummary.where()
|
||||
.equalTo(ReactionAggregatedSummaryEntityFields.KEY, reaction)
|
||||
.findFirst()
|
||||
val aggregationForOppositeReaction = existingSummary.reactionsSummary.where()
|
||||
.equalTo(ReactionAggregatedSummaryEntityFields.KEY, oppositeReaction)
|
||||
.findFirst()
|
||||
|
||||
if (aggregationForReaction == null || !aggregationForReaction.addedByMe) {
|
||||
//i haven't yet reacted to it, so need to add it, but do I need to redact the opposite?
|
||||
val toRedact = aggregationForOppositeReaction?.sourceEvents?.mapNotNull {
|
||||
//find source event
|
||||
val entity = EventEntity.where(realm, it).findFirst()
|
||||
if (entity?.sender == myUserId) entity.eventId else null
|
||||
}
|
||||
return Pair(reaction, toRedact)
|
||||
} else {
|
||||
//I already added it, so i need to undo it (like a toggle)
|
||||
// find all m.redaction coming from me to readact them
|
||||
val toRedact = aggregationForReaction.sourceEvents.mapNotNull {
|
||||
//find source event
|
||||
val entity = EventEntity.where(realm, it).findFirst()
|
||||
if (entity?.sender == myUserId) entity.eventId else null
|
||||
}
|
||||
return Pair(null, toRedact)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user