Merge pull request #6001 from jaiwanth-v/save-edited-state-messages

Save edited state of a message when switching rooms
This commit is contained in:
Travis Ralston 2021-05-13 20:06:31 -06:00 committed by GitHub
commit 2d2c0d54c0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 3 deletions

View file

@ -34,6 +34,7 @@ import IRCTimelineProfileResizer from "../views/elements/IRCTimelineProfileResiz
import DMRoomMap from "../../utils/DMRoomMap";
import NewRoomIntro from "../views/rooms/NewRoomIntro";
import {replaceableComponent} from "../../utils/replaceableComponent";
import defaultDispatcher from '../../dispatcher/dispatcher';
const CONTINUATION_MAX_INTERVAL = 5 * 60 * 1000; // 5 minutes
const continuedTypes = ['m.sticker', 'm.room.message'];
@ -471,6 +472,10 @@ export default class MessagePanel extends React.Component {
return {nextEvent, nextTile};
}
get _roomHasPendingEdit() {
return localStorage.getItem(`mx_edit_room_${this.props.room.roomId}`);
}
_getEventTiles() {
this.eventNodes = {};
@ -559,6 +564,13 @@ export default class MessagePanel extends React.Component {
}
}
if (!this.props.editState && this._roomHasPendingEdit) {
defaultDispatcher.dispatch({
action: "edit_event",
event: this.props.room.findEventById(this._roomHasPendingEdit),
});
}
if (grouper) {
ret.push(...grouper.getTiles());
}
@ -574,7 +586,6 @@ export default class MessagePanel extends React.Component {
const isEditing = this.props.editState &&
this.props.editState.getEvent().getId() === mxEv.getId();
// local echoes have a fake date, which could even be yesterday. Treat them
// as 'today' for the date separators.
let ts1 = mxEv.getTs();

View file

@ -35,6 +35,7 @@ import {Action} from "../../../dispatcher/actions";
import CountlyAnalytics from "../../../CountlyAnalytics";
import {getKeyBindingsManager, MessageComposerAction} from '../../../KeyBindingsManager';
import {replaceableComponent} from "../../../utils/replaceableComponent";
import SendHistoryManager from '../../../SendHistoryManager';
import Modal from '../../../Modal';
function _isReply(mxEvent) {
@ -122,6 +123,7 @@ export default class EditMessageComposer extends React.Component {
saveDisabled: true,
};
this._createEditorModel();
window.addEventListener("beforeunload", this._saveStoredEditorState);
}
_setEditorRef = ref => {
@ -175,11 +177,55 @@ export default class EditMessageComposer extends React.Component {
}
}
get _editorRoomKey() {
return `mx_edit_room_${this._getRoom().roomId}`;
}
get _editorStateKey() {
return `mx_edit_state_${this.props.editState.getEvent().getId()}`;
}
_cancelEdit = () => {
this._clearStoredEditorState();
dis.dispatch({action: "edit_event", event: null});
dis.fire(Action.FocusComposer);
}
get _shouldSaveStoredEditorState() {
return localStorage.getItem(this._editorRoomKey) !== null;
}
_restoreStoredEditorState(partCreator) {
const json = localStorage.getItem(this._editorStateKey);
if (json) {
try {
const {parts: serializedParts} = JSON.parse(json);
const parts = serializedParts.map(p => partCreator.deserializePart(p));
return parts;
} catch (e) {
console.error("Error parsing editing state: ", e);
}
}
}
_clearStoredEditorState() {
localStorage.removeItem(this._editorRoomKey);
localStorage.removeItem(this._editorStateKey);
}
_clearPreviousEdit() {
if (localStorage.getItem(this._editorRoomKey)) {
localStorage.removeItem(`mx_edit_state_${localStorage.getItem(this._editorRoomKey)}`);
}
}
_saveStoredEditorState() {
const item = SendHistoryManager.createItem(this.model);
this._clearPreviousEdit();
localStorage.setItem(this._editorRoomKey, this.props.editState.getEvent().getId());
localStorage.setItem(this._editorStateKey, JSON.stringify(item));
}
_isSlashCommand() {
const parts = this.model.parts;
const firstPart = parts[0];
@ -266,6 +312,7 @@ export default class EditMessageComposer extends React.Component {
const editedEvent = this.props.editState.getEvent();
const editContent = createEditContent(this.model, editedEvent);
const newContent = editContent["m.new_content"];
let shouldSend = true;
// If content is modified then send an updated event into the room
@ -311,6 +358,7 @@ export default class EditMessageComposer extends React.Component {
if (shouldSend) {
this._cancelPreviousPendingEdit();
const prom = this.context.sendMessage(roomId, editContent);
this._clearStoredEditorState();
dis.dispatch({action: "message_sent"});
CountlyAnalytics.instance.trackSendMessage(startTime, prom, roomId, true, false, editContent);
}
@ -346,6 +394,10 @@ export default class EditMessageComposer extends React.Component {
// then when mounting the editor again with the same editor state,
// it will set the cursor at the end.
this.props.editState.setEditorState(caret, parts);
window.removeEventListener("beforeunload", this._saveStoredEditorState);
if (this._shouldSaveStoredEditorState) {
this._saveStoredEditorState();
}
}
_createEditorModel() {
@ -358,10 +410,11 @@ export default class EditMessageComposer extends React.Component {
// restore serialized parts from the state
parts = editState.getSerializedParts().map(p => partCreator.deserializePart(p));
} else {
// otherwise, parse the body of the event
parts = parseEvent(editState.getEvent(), partCreator);
//otherwise, either restore serialized parts from localStorage or parse the body of the event
parts = this._restoreStoredEditorState(partCreator) || parseEvent(editState.getEvent(), partCreator);
}
this.model = new EditorModel(parts, partCreator);
this._saveStoredEditorState();
}
_getInitialCaretPosition() {