mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 20:06:51 +03:00
Merge pull request #214 from vector-im/feature/update_quick_reactions
Feature/ Update quick reactions
This commit is contained in:
commit
8fe0bd5abe
13 changed files with 144 additions and 411 deletions
|
@ -63,19 +63,6 @@ interface RelationService {
|
|||
fun undoReaction(reaction: String, targetEventId: String, myUserId: String)//: Cancelable
|
||||
|
||||
|
||||
/**
|
||||
* Update a quick reaction (toggle).
|
||||
* If you have reacted with agree and then you click on disagree, this call will delete(redact)
|
||||
* the disagree and add the agree
|
||||
* If you click on a reaction that you already reacted with, it will undo it
|
||||
* @param reaction the reaction (preferably emoji)
|
||||
* @param oppositeReaction the opposite reaction(preferably emoji)
|
||||
* @param targetEventId the id of the event being reacted
|
||||
* @param myUserId used to know if a reaction event was made by the user
|
||||
*/
|
||||
fun updateQuickReaction(reaction: String, oppositeReaction: String, targetEventId: String, myUserId: String)
|
||||
|
||||
|
||||
/**
|
||||
* Edit a text message body. Limited to "m.text" contentType
|
||||
* @param targetEventId The event to edit
|
||||
|
|
|
@ -29,7 +29,6 @@ import im.vector.matrix.android.internal.session.room.read.DefaultReadService
|
|||
import im.vector.matrix.android.internal.session.room.read.SetReadMarkersTask
|
||||
import im.vector.matrix.android.internal.session.room.relation.DefaultRelationService
|
||||
import im.vector.matrix.android.internal.session.room.relation.FindReactionEventForUndoTask
|
||||
import im.vector.matrix.android.internal.session.room.relation.UpdateQuickReactionTask
|
||||
import im.vector.matrix.android.internal.session.room.send.DefaultSendService
|
||||
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
|
||||
import im.vector.matrix.android.internal.session.room.state.DefaultStateService
|
||||
|
@ -51,7 +50,6 @@ internal class RoomFactory(private val monarchy: Monarchy,
|
|||
private val setReadMarkersTask: SetReadMarkersTask,
|
||||
private val cryptoService: CryptoService,
|
||||
private val findReactionEventForUndoTask: FindReactionEventForUndoTask,
|
||||
private val updateQuickReactionTask: UpdateQuickReactionTask,
|
||||
private val joinRoomTask: JoinRoomTask,
|
||||
private val leaveRoomTask: LeaveRoomTask) {
|
||||
|
||||
|
@ -64,7 +62,7 @@ internal class RoomFactory(private val monarchy: Monarchy,
|
|||
val stateService = DefaultStateService(roomId, taskExecutor, sendStateTask)
|
||||
val roomMembersService = DefaultMembershipService(roomId, monarchy, taskExecutor, loadRoomMembersTask, inviteTask, joinRoomTask, leaveRoomTask)
|
||||
val readService = DefaultReadService(roomId, monarchy, taskExecutor, setReadMarkersTask)
|
||||
val reactionService = DefaultRelationService(roomId, eventFactory, findReactionEventForUndoTask, updateQuickReactionTask, monarchy, taskExecutor)
|
||||
val reactionService = DefaultRelationService(roomId, eventFactory, findReactionEventForUndoTask, monarchy, taskExecutor)
|
||||
|
||||
return DefaultRoom(
|
||||
roomId,
|
||||
|
|
|
@ -32,9 +32,7 @@ import im.vector.matrix.android.internal.session.room.prune.PruneEventTask
|
|||
import im.vector.matrix.android.internal.session.room.read.DefaultSetReadMarkersTask
|
||||
import im.vector.matrix.android.internal.session.room.read.SetReadMarkersTask
|
||||
import im.vector.matrix.android.internal.session.room.relation.DefaultFindReactionEventForUndoTask
|
||||
import im.vector.matrix.android.internal.session.room.relation.DefaultUpdateQuickReactionTask
|
||||
import im.vector.matrix.android.internal.session.room.relation.FindReactionEventForUndoTask
|
||||
import im.vector.matrix.android.internal.session.room.relation.UpdateQuickReactionTask
|
||||
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
|
||||
import im.vector.matrix.android.internal.session.room.send.LocalEchoUpdater
|
||||
import im.vector.matrix.android.internal.session.room.state.DefaultSendStateTask
|
||||
|
@ -82,7 +80,7 @@ class RoomModule {
|
|||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
RoomFactory(get(), get(), 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) {
|
||||
|
@ -109,10 +107,6 @@ class RoomModule {
|
|||
DefaultFindReactionEventForUndoTask(get()) as FindReactionEventForUndoTask
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
DefaultUpdateQuickReactionTask(get()) as UpdateQuickReactionTask
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
DefaultPruneEventTask(get()) as PruneEventTask
|
||||
}
|
||||
|
|
|
@ -46,7 +46,6 @@ import timber.log.Timber
|
|||
internal class DefaultRelationService(private val roomId: String,
|
||||
private val eventFactory: LocalEchoEventFactory,
|
||||
private val findReactionEventForUndoTask: FindReactionEventForUndoTask,
|
||||
private val updateQuickReactionTask: UpdateQuickReactionTask,
|
||||
private val monarchy: Monarchy,
|
||||
private val taskExecutor: TaskExecutor)
|
||||
: RelationService {
|
||||
|
@ -105,31 +104,6 @@ internal class DefaultRelationService(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 redactEvent = eventFactory.createRedactEvent(roomId, it, null).also {
|
||||
saveLocalEcho(it)
|
||||
}
|
||||
val redactWork = createRedactEventWork(redactEvent, it, null)
|
||||
TimelineSendEventWorkCommon.postWork(roomId, redactWork)
|
||||
}
|
||||
}
|
||||
})
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
private fun buildWorkIdentifier(identifier: String): String {
|
||||
return "${roomId}_$identifier"
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* 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.relation
|
||||
|
||||
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 suspend 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)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ sealed class RoomDetailActions {
|
|||
data class SendReaction(val reaction: String, val targetEventId: String) : RoomDetailActions()
|
||||
data class RedactAction(val targetEventId: String, val reason: String? = "") : RoomDetailActions()
|
||||
data class UndoReaction(val targetEventId: String, val key: String, val reason: String? = "") : RoomDetailActions()
|
||||
data class UpdateQuickReactAction(val targetEventId: String, val selectedReaction: String, val opposite: String) : RoomDetailActions()
|
||||
data class UpdateQuickReactAction(val targetEventId: String, val selectedReaction: String, val add: Boolean) : RoomDetailActions()
|
||||
data class ShowEditHistoryAction(val event: String, val editAggregatedSummary: EditAggregatedSummary) : RoomDetailActions()
|
||||
data class NavigateToEvent(val eventId: String, val position: Int?) : RoomDetailActions()
|
||||
object AcceptInvite : RoomDetailActions()
|
||||
|
|
|
@ -708,9 +708,9 @@ class RoomDetailFragment :
|
|||
.show()
|
||||
}
|
||||
MessageMenuViewModel.ACTION_QUICK_REACT -> {
|
||||
//eventId,ClickedOn,Opposite
|
||||
(actionData.data as? Triple<String, String, String>)?.let { (eventId, clickedOn, opposite) ->
|
||||
roomDetailViewModel.process(RoomDetailActions.UpdateQuickReactAction(eventId, clickedOn, opposite))
|
||||
//eventId,ClickedOn,Add
|
||||
(actionData.data as? Triple<String, String, Boolean>)?.let { (eventId, clickedOn, add) ->
|
||||
roomDetailViewModel.process(RoomDetailActions.UpdateQuickReactAction(eventId, clickedOn, add))
|
||||
}
|
||||
}
|
||||
MessageMenuViewModel.ACTION_EDIT -> {
|
||||
|
|
|
@ -341,7 +341,11 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
|||
|
||||
|
||||
private fun handleUpdateQuickReaction(action: RoomDetailActions.UpdateQuickReactAction) {
|
||||
room.updateQuickReaction(action.selectedReaction, action.opposite, action.targetEventId, session.sessionParams.credentials.userId)
|
||||
if (action.add) {
|
||||
room.sendReaction(action.selectedReaction, action.targetEventId)
|
||||
} else {
|
||||
room.undoReaction(action.selectedReaction, action.targetEventId, session.sessionParams.credentials.userId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSendMedia(action: RoomDetailActions.SendMedia) {
|
||||
|
|
|
@ -94,8 +94,9 @@ class MessageActionsBottomSheet : BaseMvRxBottomSheetDialog() {
|
|||
.commit()
|
||||
}
|
||||
quickReactionFragment.interactionListener = object : QuickReactionFragment.InteractionListener {
|
||||
override fun didQuickReactWith(clikedOn: String, opposite: String, reactions: List<String>, eventId: String) {
|
||||
actionHandlerModel.fireAction(MessageMenuViewModel.ACTION_QUICK_REACT, Triple(eventId, clikedOn, opposite))
|
||||
|
||||
override fun didQuickReactWith(clikedOn: String, add: Boolean, eventId: String) {
|
||||
actionHandlerModel.fireAction(MessageMenuViewModel.ACTION_QUICK_REACT, Triple(eventId, clikedOn, add))
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,6 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.transition.TransitionManager
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import com.airbnb.mvrx.BaseMvRxFragment
|
||||
import com.airbnb.mvrx.MvRx
|
||||
|
@ -31,6 +28,7 @@ import com.airbnb.mvrx.fragmentViewModel
|
|||
import com.airbnb.mvrx.withState
|
||||
import im.vector.riotredesign.EmojiCompatFontProvider
|
||||
import im.vector.riotredesign.R
|
||||
import kotlinx.android.synthetic.main.adapter_item_action_quick_reaction.*
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
/**
|
||||
|
@ -40,21 +38,6 @@ class QuickReactionFragment : BaseMvRxFragment() {
|
|||
|
||||
private val viewModel: QuickReactionViewModel by fragmentViewModel(QuickReactionViewModel::class)
|
||||
|
||||
@BindView(R.id.root_layout)
|
||||
lateinit var rootLayout: ConstraintLayout
|
||||
|
||||
@BindView(R.id.quick_react_1_text)
|
||||
lateinit var quickReact1Text: TextView
|
||||
|
||||
@BindView(R.id.quick_react_2_text)
|
||||
lateinit var quickReact2Text: TextView
|
||||
|
||||
@BindView(R.id.quick_react_3_text)
|
||||
lateinit var quickReact3Text: TextView
|
||||
|
||||
@BindView(R.id.quick_react_4_text)
|
||||
lateinit var quickReact4Text: TextView
|
||||
|
||||
var interactionListener: InteractionListener? = null
|
||||
|
||||
val fontProvider by inject<EmojiCompatFontProvider>()
|
||||
|
@ -65,77 +48,38 @@ class QuickReactionFragment : BaseMvRxFragment() {
|
|||
return view
|
||||
}
|
||||
|
||||
lateinit var textViews: List<TextView>
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
quickReact1Text.text = QuickReactionViewModel.agreePositive
|
||||
quickReact2Text.text = QuickReactionViewModel.agreeNegative
|
||||
quickReact3Text.text = QuickReactionViewModel.likePositive
|
||||
quickReact4Text.text = QuickReactionViewModel.likeNegative
|
||||
textViews = listOf(quickReaction0, quickReaction1, quickReaction2, quickReaction3,
|
||||
quickReaction4, quickReaction5, quickReaction6, quickReaction7)
|
||||
|
||||
listOf(quickReact1Text, quickReact2Text, quickReact3Text, quickReact4Text).forEach {
|
||||
it.typeface = fontProvider.typeface ?: Typeface.DEFAULT
|
||||
}
|
||||
|
||||
//configure click listeners
|
||||
quickReact1Text.setOnClickListener {
|
||||
viewModel.toggleAgree(true)
|
||||
}
|
||||
quickReact2Text.setOnClickListener {
|
||||
viewModel.toggleAgree(false)
|
||||
}
|
||||
quickReact3Text.setOnClickListener {
|
||||
viewModel.toggleLike(true)
|
||||
}
|
||||
quickReact4Text.setOnClickListener {
|
||||
viewModel.toggleLike(false)
|
||||
textViews.forEachIndexed { index, textView ->
|
||||
textView.typeface = fontProvider.typeface ?: Typeface.DEFAULT
|
||||
textView.setOnClickListener {
|
||||
viewModel.didSelect(index)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) {
|
||||
|
||||
TransitionManager.beginDelayedTransition(rootLayout)
|
||||
when (it.agreeTrigleState) {
|
||||
TriggleState.NONE -> {
|
||||
quickReact1Text.alpha = 1f
|
||||
quickReact2Text.alpha = 1f
|
||||
}
|
||||
TriggleState.FIRST -> {
|
||||
quickReact1Text.alpha = 1f
|
||||
quickReact2Text.alpha = 0.2f
|
||||
|
||||
}
|
||||
TriggleState.SECOND -> {
|
||||
quickReact1Text.alpha = 0.2f
|
||||
quickReact2Text.alpha = 1f
|
||||
}
|
||||
}
|
||||
when (it.likeTriggleState) {
|
||||
TriggleState.NONE -> {
|
||||
quickReact3Text.alpha = 1f
|
||||
quickReact4Text.alpha = 1f
|
||||
}
|
||||
TriggleState.FIRST -> {
|
||||
quickReact3Text.alpha = 1f
|
||||
quickReact4Text.alpha = 0.2f
|
||||
|
||||
}
|
||||
TriggleState.SECOND -> {
|
||||
quickReact3Text.alpha = 0.2f
|
||||
quickReact4Text.alpha = 1f
|
||||
}
|
||||
it.quickStates.forEachIndexed { index, qs ->
|
||||
textViews[index].text = qs.reaction
|
||||
textViews[index].alpha = if (qs.isSelected) 0.2f else 1f
|
||||
}
|
||||
|
||||
if (it.selectionResult != null) {
|
||||
val clikedOn = it.selectionResult.first
|
||||
interactionListener?.didQuickReactWith(clikedOn, QuickReactionViewModel.getOpposite(clikedOn)
|
||||
?: "", it.selectionResult.second, it.eventId)
|
||||
if (it.result != null) {
|
||||
interactionListener?.didQuickReactWith(it.result.reaction, it.result.isSelected, it.eventId)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface InteractionListener {
|
||||
fun didQuickReactWith(clikedOn: String, opposite: String, reactions: List<String>, eventId: String)
|
||||
fun didQuickReactWith(clikedOn: String, add: Boolean, eventId: String)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -25,18 +25,16 @@ import org.koin.android.ext.android.get
|
|||
/**
|
||||
* Quick reactions state, it's a toggle with 3rd state
|
||||
*/
|
||||
enum class TriggleState {
|
||||
NONE,
|
||||
FIRST,
|
||||
SECOND
|
||||
}
|
||||
data class ToggleState(
|
||||
val reaction: String,
|
||||
val isSelected: Boolean
|
||||
)
|
||||
|
||||
data class QuickReactionState(
|
||||
val agreeTrigleState: TriggleState = TriggleState.NONE,
|
||||
val likeTriggleState: TriggleState = TriggleState.NONE,
|
||||
/** Pair of 'clickedOn' and current toggles state*/
|
||||
val selectionResult: Pair<String, List<String>>? = null,
|
||||
val eventId: String = "") : MvRxState
|
||||
val quickStates: List<ToggleState>,
|
||||
val eventId: String = "",
|
||||
val result: ToggleState? = null
|
||||
) : MvRxState
|
||||
|
||||
/**
|
||||
* Quick reaction view model
|
||||
|
@ -44,107 +42,28 @@ data class QuickReactionState(
|
|||
class QuickReactionViewModel(initialState: QuickReactionState) : VectorViewModel<QuickReactionState>(initialState) {
|
||||
|
||||
|
||||
fun toggleAgree(isFirst: Boolean) = withState {
|
||||
if (isFirst) {
|
||||
setState {
|
||||
val newTriggle = if (it.agreeTrigleState == TriggleState.FIRST) TriggleState.NONE else TriggleState.FIRST
|
||||
copy(
|
||||
agreeTrigleState = newTriggle,
|
||||
selectionResult = Pair(agreePositive, getReactions(this, newTriggle, null))
|
||||
)
|
||||
}
|
||||
} else {
|
||||
setState {
|
||||
val newTriggle = if (it.agreeTrigleState == TriggleState.SECOND) TriggleState.NONE else TriggleState.SECOND
|
||||
copy(
|
||||
agreeTrigleState = agreeTrigleState,
|
||||
selectionResult = Pair(agreeNegative, getReactions(this, newTriggle, null))
|
||||
)
|
||||
}
|
||||
fun didSelect(index: Int) = withState {
|
||||
val isSelected = it.quickStates[index].isSelected
|
||||
setState {
|
||||
copy(result = ToggleState(it.quickStates[index].reaction, !isSelected))
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleLike(isFirst: Boolean) = withState {
|
||||
if (isFirst) {
|
||||
setState {
|
||||
val newTriggle = if (it.likeTriggleState == TriggleState.FIRST) TriggleState.NONE else TriggleState.FIRST
|
||||
copy(
|
||||
likeTriggleState = newTriggle,
|
||||
selectionResult = Pair(likePositive, getReactions(this, null, newTriggle))
|
||||
)
|
||||
}
|
||||
} else {
|
||||
setState {
|
||||
val newTriggle = if (it.likeTriggleState == TriggleState.SECOND) TriggleState.NONE else TriggleState.SECOND
|
||||
copy(
|
||||
likeTriggleState = newTriggle,
|
||||
selectionResult = Pair(likeNegative, getReactions(this, null, newTriggle))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getReactions(state: QuickReactionState, newState1: TriggleState?, newState2: TriggleState?): List<String> {
|
||||
return ArrayList<String>(4).apply {
|
||||
when (newState2 ?: state.likeTriggleState) {
|
||||
TriggleState.FIRST -> add(likePositive)
|
||||
TriggleState.SECOND -> add(likeNegative)
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
when (newState1 ?: state.agreeTrigleState) {
|
||||
TriggleState.FIRST -> add(agreePositive)
|
||||
TriggleState.SECOND -> add(agreeNegative)
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object : MvRxViewModelFactory<QuickReactionViewModel, QuickReactionState> {
|
||||
|
||||
val agreePositive = "👍"
|
||||
val agreeNegative = "👎"
|
||||
val likePositive = "🙂"
|
||||
val likeNegative = "😔"
|
||||
|
||||
fun getOpposite(reaction: String): String? {
|
||||
return when (reaction) {
|
||||
agreePositive -> agreeNegative
|
||||
agreeNegative -> agreePositive
|
||||
likePositive -> likeNegative
|
||||
likeNegative -> likePositive
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
val quickEmojis = listOf("👍", "👎", "😄", "🎉", "😕", "❤️", "🚀", "👀")
|
||||
|
||||
override fun initialState(viewModelContext: ViewModelContext): QuickReactionState? {
|
||||
// Args are accessible from the context.
|
||||
// val foo = vieWModelContext.args<MyArgs>.foo
|
||||
val currentSession = viewModelContext.activity.get<Session>()
|
||||
val parcel = viewModelContext.args as TimelineEventFragmentArgs
|
||||
val event = currentSession.getRoom(parcel.roomId)?.getTimeLineEvent(parcel.eventId)
|
||||
?: return null
|
||||
var agreeTriggle: TriggleState = TriggleState.NONE
|
||||
var likeTriggle: TriggleState = TriggleState.NONE
|
||||
event.annotations?.reactionsSummary?.forEach {
|
||||
//it.addedByMe
|
||||
if (it.addedByMe) {
|
||||
if (agreePositive == it.key) {
|
||||
agreeTriggle = TriggleState.FIRST
|
||||
} else if (agreeNegative == it.key) {
|
||||
agreeTriggle = TriggleState.SECOND
|
||||
}
|
||||
|
||||
if (likePositive == it.key) {
|
||||
likeTriggle = TriggleState.FIRST
|
||||
} else if (likeNegative == it.key) {
|
||||
likeTriggle = TriggleState.SECOND
|
||||
}
|
||||
}
|
||||
val summary = event.annotations?.reactionsSummary
|
||||
val quickReactions = quickEmojis.map { emoji ->
|
||||
ToggleState(emoji, summary?.firstOrNull { it.key == emoji }?.addedByMe ?: false)
|
||||
}
|
||||
return QuickReactionState(agreeTriggle, likeTriggle, null, event.root.eventId ?: "")
|
||||
return QuickReactionState(quickReactions, event.root.eventId ?: "")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,116 +4,116 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/root_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="96dp">
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/quick_react_1_text"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_marginRight="4dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="30sp"
|
||||
app:autoSizeTextType="uniform"
|
||||
app:layout_constraintBottom_toTopOf="@id/quick_react_agree_text"
|
||||
app:layout_constraintEnd_toStartOf="@id/quick_react_2_text"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
android:id="@+id/quickReactionTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="@string/quick_reactions"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/quickReaction0"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dp"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="24sp"
|
||||
tools:ignore="MissingConstraints"
|
||||
tools:text="👍" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/quick_react_2_text"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="30sp"
|
||||
app:autoSizeTextType="uniform"
|
||||
app:layout_constraintBottom_toBottomOf="@id/quick_react_1_text"
|
||||
app:layout_constraintEnd_toStartOf="@id/center_guideline"
|
||||
app:layout_constraintStart_toEndOf="@id/quick_react_1_text"
|
||||
app:layout_constraintTop_toTopOf="@id/quick_react_1_text"
|
||||
tools:text="👎" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/quick_react_agree_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="@string/reactions_agree"
|
||||
android:textAlignment="center"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/center_guideline"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/quick_react_1_text" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/center_guideline"
|
||||
android:id="@+id/quickReaction1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_percent="0.5" />
|
||||
android:padding="4dp"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="24sp"
|
||||
tools:ignore="MissingConstraints"
|
||||
tools:text="👎" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/quick_react_3_text"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_marginRight="4dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="30sp"
|
||||
app:autoSizeTextType="uniform"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/quick_react_1_text"
|
||||
app:layout_constraintEnd_toStartOf="@id/quick_react_4_text"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toEndOf="@id/center_guideline"
|
||||
app:layout_constraintTop_toTopOf="@id/quick_react_1_text"
|
||||
android:id="@+id/quickReaction2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dp"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="24sp"
|
||||
tools:ignore="MissingConstraints"
|
||||
tools:text="😀" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/quick_react_4_text"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="30sp"
|
||||
app:autoSizeTextType="uniform"
|
||||
app:layout_constraintBottom_toBottomOf="@id/quick_react_3_text"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/quick_react_3_text"
|
||||
app:layout_constraintTop_toTopOf="@id/quick_react_3_text"
|
||||
tools:text="😞" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/quick_react_like_text"
|
||||
android:id="@+id/quickReaction3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dp"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="24sp"
|
||||
tools:ignore="MissingConstraints"
|
||||
tools:text="🎉" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/quickReaction4"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dp"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="24sp"
|
||||
tools:ignore="MissingConstraints"
|
||||
tools:text="😕" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/quickReaction5"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dp"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="24sp"
|
||||
tools:ignore="MissingConstraints"
|
||||
tools:text="♥" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/quickReaction6"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dp"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="24sp"
|
||||
tools:ignore="MissingConstraints"
|
||||
tools:text="🍆" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/quickReaction7"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dp"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="26sp"
|
||||
tools:ignore="MissingConstraints"
|
||||
tools:text="👀" />
|
||||
|
||||
<androidx.constraintlayout.helper.widget.Flow
|
||||
android:id="@+id/reactionsFlowHelper"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/reactions_like"
|
||||
android:textAlignment="center"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="@id/quick_react_agree_text"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:constraint_referenced_ids="quickReaction0,quickReaction1,quickReaction2,quickReaction3,quickReaction4,quickReaction5,quickReaction6,quickReaction7"
|
||||
app:flow_horizontalGap="8dp"
|
||||
app:flow_horizontalStyle="spread"
|
||||
app:flow_verticalBias="0"
|
||||
app:flow_verticalGap="4dp"
|
||||
app:flow_wrapMode="chain"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/center_guideline"
|
||||
app:layout_constraintTop_toTopOf="@id/quick_react_agree_text" />
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/quickReactionTitle" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -10,4 +10,5 @@
|
|||
<string name="settings_other_third_party_notices">Other third party notices</string>
|
||||
<string name="navigate_to_room_when_already_in_the_room">You are already viewing this room!</string>
|
||||
|
||||
<string name="quick_reactions">Quick Reactions</string>
|
||||
</resources>
|
Loading…
Reference in a new issue