support undoing a reaction
This commit is contained in:
parent
20abb01ee8
commit
bb8acbefa3
7 changed files with 45 additions and 5 deletions
|
@ -86,7 +86,11 @@ class ReactionViewModel extends ViewModel {
|
||||||
return this._annotation.count - other._annotation.count;
|
return this._annotation.count - other._annotation.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
react() {
|
toggleReaction() {
|
||||||
return this._parentEntry.react(this.key);
|
if (this.haveReacted) {
|
||||||
|
return this._parentEntry.redactReaction(this.key);
|
||||||
|
} else {
|
||||||
|
return this._parentEntry.react(this.key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -123,7 +123,14 @@ export class BaseMessageTile extends SimpleTile {
|
||||||
}
|
}
|
||||||
|
|
||||||
react(key) {
|
react(key) {
|
||||||
this._room.sendEvent("m.reaction", this._entry.annotate(key));
|
return this._room.sendEvent("m.reaction", this._entry.annotate(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
async redactReaction(key) {
|
||||||
|
const id = await this._entry.getOwnAnnotationId(this._room, key);
|
||||||
|
if (id) {
|
||||||
|
this._room.sendRedaction(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateReactions() {
|
_updateReactions() {
|
||||||
|
|
|
@ -28,6 +28,7 @@ import {EventEntry} from "./timeline/entries/EventEntry.js";
|
||||||
import {ObservedEventMap} from "./ObservedEventMap.js";
|
import {ObservedEventMap} from "./ObservedEventMap.js";
|
||||||
import {DecryptionSource} from "../e2ee/common.js";
|
import {DecryptionSource} from "../e2ee/common.js";
|
||||||
import {ensureLogItem} from "../../logging/utils.js";
|
import {ensureLogItem} from "../../logging/utils.js";
|
||||||
|
import {ANNOTATION_RELATION_TYPE, getRelation} from "./timeline/relations.js";
|
||||||
|
|
||||||
const EVENT_ENCRYPTED_TYPE = "m.room.encrypted";
|
const EVENT_ENCRYPTED_TYPE = "m.room.encrypted";
|
||||||
|
|
||||||
|
@ -451,6 +452,21 @@ export class BaseRoom extends EventEmitter {
|
||||||
return observable;
|
return observable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getOwnAnnotationEventId(targetId, key) {
|
||||||
|
const txn = await this._storage.readWriteTxn([
|
||||||
|
this._storage.storeNames.timelineEvents,
|
||||||
|
this._storage.storeNames.timelineRelations,
|
||||||
|
]);
|
||||||
|
const relations = await txn.timelineRelations.getForTargetAndType(this.id, targetId, ANNOTATION_RELATION_TYPE);
|
||||||
|
for (const relation of relations) {
|
||||||
|
const annotation = await txn.timelineEvents.getByEventId(this.id, relation.sourceEventId);
|
||||||
|
if (annotation.event.sender === this._user.id && getRelation(annotation.event).key === key) {
|
||||||
|
return annotation.event.event_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
async _readEventById(eventId) {
|
async _readEventById(eventId) {
|
||||||
let stores = [this._storage.storeNames.timelineEvents];
|
let stores = [this._storage.storeNames.timelineEvents];
|
||||||
if (this.isEncrypted) {
|
if (this.isEncrypted) {
|
||||||
|
|
|
@ -130,4 +130,8 @@ export class EventEntry extends BaseEventEntry {
|
||||||
get annotations() {
|
get annotations() {
|
||||||
return this._eventEntry.annotations;
|
return this._eventEntry.annotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getOwnAnnotationId(room, key) {
|
||||||
|
return room.getOwnAnnotationEventId(this.id, key);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -85,4 +85,9 @@ export class PendingEventEntry extends BaseEventEntry {
|
||||||
get relatedEventId() {
|
get relatedEventId() {
|
||||||
return this._pendingEvent.relatedEventId;
|
return this._pendingEvent.relatedEventId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getOwnAnnotationId(_, key) {
|
||||||
|
// TODO: implement this once local reactions are implemented
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,6 +217,11 @@ only loads when the top comes into view*/
|
||||||
grid-area: reactions;
|
grid-area: reactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Timeline_messageReactions button.haveReacted {
|
||||||
|
background-color: green;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
.AnnouncementView {
|
.AnnouncementView {
|
||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
padding: 5px 10%;
|
padding: 5px 10%;
|
||||||
|
|
|
@ -32,12 +32,11 @@ class ReactionView extends TemplateView {
|
||||||
render(t, vm) {
|
render(t, vm) {
|
||||||
const haveReacted = vm => vm.haveReacted;
|
const haveReacted = vm => vm.haveReacted;
|
||||||
return t.button({
|
return t.button({
|
||||||
disabled: haveReacted,
|
|
||||||
className: {haveReacted},
|
className: {haveReacted},
|
||||||
}, [vm.key, " ", vm => `${vm.count}`]);
|
}, [vm.key, " ", vm => `${vm.count}`]);
|
||||||
}
|
}
|
||||||
|
|
||||||
onClick() {
|
onClick() {
|
||||||
this.value.react();
|
this.value.toggleReaction();
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in a new issue