diff --git a/src/CallHandler.js b/src/CallHandler.js
index 7403483e36..abbd407e7f 100644
--- a/src/CallHandler.js
+++ b/src/CallHandler.js
@@ -62,6 +62,7 @@ import dis from './dispatcher';
import { showUnknownDeviceDialogForCalls } from './cryptodevices';
import SettingsStore from "./settings/SettingsStore";
import WidgetUtils from './utils/WidgetUtils';
+import WidgetEchoStore from './stores/WidgetEchoStore';
global.mxCalls = {
//room_id: MatrixCall
@@ -402,18 +403,30 @@ function _onAction(payload) {
}
function _startCallApp(roomId, type) {
- dis.dispatch({
- action: 'appsDrawer',
- show: true,
- });
-
const room = MatrixClientPeg.get().getRoom(roomId);
if (!room) {
console.error("Attempted to start conference call widget in unknown room: " + roomId);
return;
}
- const currentJitsiWidgets = WidgetUtils.getRoomWidgets(room).filter((ev) => {
+ dis.dispatch({
+ action: 'appsDrawer',
+ show: true,
+ });
+
+ const currentRoomWidgets = WidgetUtils.getRoomWidgets(room);
+
+ if (WidgetEchoStore.roomHasPendingWidgetsOfType(room, currentRoomWidgets, 'jitsi')) {
+ const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
+
+ Modal.createTrackedDialog('Already have pending Jitsi Widget', '', ErrorDialog, {
+ title: _t('Call in Progress'),
+ description: _t('A call is currently being placed!'),
+ });
+ return;
+ }
+
+ const currentJitsiWidgets = currentRoomWidgets.filter((ev) => {
return ev.getContent().type === 'jitsi';
});
if (currentJitsiWidgets.length > 0) {
diff --git a/src/actions/MatrixActionCreators.js b/src/actions/MatrixActionCreators.js
index 6e1d52a88f..d8c315f505 100644
--- a/src/actions/MatrixActionCreators.js
+++ b/src/actions/MatrixActionCreators.js
@@ -183,6 +183,20 @@ function createEventDecryptedAction(matrixClient, event) {
return { action: 'MatrixActions.Event.decrypted', event };
}
+/**
+ * Create a MatrixActions.RoomState.vents action that represents
+ * a MatrixClient `RoomState.events` matrix event, emitted when the
+ * state events in a room change.
+ *
+ * @param {MatrixClient} matrixClient the matrix client.
+ * @param {MatrixEvent} event matrix event which caused this event to fire.
+ * @param {RoomState} state room state whose RoomState.events dictionary was updated.
+ * @returns {EventDecryptedAction} an action of type `MatrixActions.Event.decrypted`.
+ */
+function createRoomStateEventsAction(matrixClient, event, state) {
+ return { action: 'MatrixActions.RoomState.events', event, state };
+}
+
/**
* This object is responsible for dispatching actions when certain events are emitted by
* the given MatrixClient.
@@ -204,6 +218,7 @@ export default {
this._addMatrixClientListener(matrixClient, 'Room.timeline', createRoomTimelineAction);
this._addMatrixClientListener(matrixClient, 'RoomMember.membership', createRoomMembershipAction);
this._addMatrixClientListener(matrixClient, 'Event.decrypted', createEventDecryptedAction);
+ this._addMatrixClientListener(matrixClient, 'RoomState.events', createRoomStateEventsAction);
},
/**
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index 98d700e0a0..5c97b5c29a 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -45,6 +45,7 @@ import { KeyCode, isOnlyCtrlOrCmdKeyEvent } from '../../Keyboard';
import RoomViewStore from '../../stores/RoomViewStore';
import RoomScrollStateStore from '../../stores/RoomScrollStateStore';
+import WidgetEchoStore from '../../stores/WidgetEchoStore';
import SettingsStore, {SettingLevel} from "../../settings/SettingsStore";
import WidgetUtils from '../../utils/WidgetUtils';
@@ -153,6 +154,8 @@ module.exports = React.createClass({
// Start listening for RoomViewStore updates
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
this._onRoomViewStoreUpdate(true);
+
+ WidgetEchoStore.on('updateRoomWidgetEcho', this._onWidgetEchoStoreUpdate);
},
_onRoomViewStoreUpdate: function(initial) {
@@ -243,6 +246,12 @@ module.exports = React.createClass({
}
},
+ _onWidgetEchoStoreUpdate: function() {
+ this.setState({
+ showApps: this._shouldShowApps(this.state.room),
+ });
+ },
+
_setupRoom: function(room, roomId, joining, shouldPeek) {
// if this is an unknown room then we're in one of three states:
// - This is a room we can peek into (search engine) (we can /peek)
@@ -319,7 +328,9 @@ module.exports = React.createClass({
return false;
}
- return WidgetUtils.getRoomWidgets(room).length > 0;
+ const widgets = WidgetEchoStore.getEchoedRoomWidgets(room, WidgetUtils.getRoomWidgets(room));
+
+ return widgets.length > 0 || WidgetEchoStore.roomHasPendingWidgets(room, WidgetUtils.getRoomWidgets(room));
},
componentDidMount: function() {
@@ -414,6 +425,8 @@ module.exports = React.createClass({
this._roomStoreToken.remove();
}
+ WidgetEchoStore.removeListener('updateRoomWidgetEcho', this._onWidgetEchoStoreUpdate);
+
// cancel any pending calls to the rate_limited_funcs
this._updateRoomMembers.cancelPendingCall();
diff --git a/src/components/views/rooms/AppsDrawer.js b/src/components/views/rooms/AppsDrawer.js
index 04e47f0f9f..64aa8fadc8 100644
--- a/src/components/views/rooms/AppsDrawer.js
+++ b/src/components/views/rooms/AppsDrawer.js
@@ -29,6 +29,7 @@ import ScalarMessaging from '../../../ScalarMessaging';
import { _t } from '../../../languageHandler';
import WidgetUtils from '../../../utils/WidgetUtils';
import SettingsStore from "../../../settings/SettingsStore";
+import WidgetEchoStore from "../../../stores/WidgetEchoStore";
// The maximum number of widgets that can be added in a room
const MAX_WIDGETS = 2;
@@ -57,6 +58,7 @@ module.exports = React.createClass({
componentWillMount: function() {
ScalarMessaging.startListening();
MatrixClientPeg.get().on('RoomState.events', this.onRoomStateEvents);
+ WidgetEchoStore.on('updateRoomWidgetEcho', this._updateApps);
},
componentDidMount: function() {
@@ -82,6 +84,7 @@ module.exports = React.createClass({
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener('RoomState.events', this.onRoomStateEvents);
}
+ WidgetEchoStore.removeListener('updateRoomWidgetEcho', this._updateApps);
dis.unregister(this.dispatcherRef);
},
@@ -163,7 +166,10 @@ module.exports = React.createClass({
},
_getApps: function() {
- return WidgetUtils.getRoomWidgets(this.props.room).map((ev) => {
+ const widgets = WidgetEchoStore.getEchoedRoomWidgets(
+ this.props.room, WidgetUtils.getRoomWidgets(this.props.room),
+ );
+ return widgets.map((ev) => {
return this._initAppConfig(ev.getStateKey(), ev.getContent(), ev.sender);
});
},
@@ -231,7 +237,8 @@ module.exports = React.createClass({
waitForIframeLoad={app.waitForIframeLoad}
whitelistCapabilities={enableScreenshots ? ["m.capability.screenshot"] : []}
/>);
- });
+ },
+ );
let addWidget;
if (this.props.showApps &&
@@ -250,10 +257,22 @@ module.exports = React.createClass({
;
}
+ let spinner;
+ if (
+ apps.length === 0 && WidgetEchoStore.roomHasPendingWidgets(
+ this.props.room,
+ WidgetUtils.getRoomWidgets(this.props.room),
+ )
+ ) {
+ const Loader = sdk.getComponent("elements.Spinner");
+ spinner = ;
+ }
+
return (
{ apps }
+ { spinner }
{ this._canUserModify() && addWidget }
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index d02ab8ff29..ae4ca74085 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -40,14 +40,11 @@
"Failed to set up conference call": "Failed to set up conference call",
"Conference call failed.": "Conference call failed.",
"Call in Progress": "Call in Progress",
+ "A call is currently being placed!": "A call is currently being placed!",
"A call is already in progress!": "A call is already in progress!",
"The file '%(fileName)s' failed to upload": "The file '%(fileName)s' failed to upload",
"The file '%(fileName)s' exceeds this home server's size limit for uploads": "The file '%(fileName)s' exceeds this home server's size limit for uploads",
"Upload Failed": "Upload Failed",
- "Failure to create room": "Failure to create room",
- "Server may be unavailable, overloaded, or you hit a bug.": "Server may be unavailable, overloaded, or you hit a bug.",
- "Send anyway": "Send anyway",
- "Send": "Send",
"Sun": "Sun",
"Mon": "Mon",
"Tue": "Tue",
@@ -87,7 +84,6 @@
"Failed to invite users to community": "Failed to invite users to community",
"Failed to invite users to %(groupId)s": "Failed to invite users to %(groupId)s",
"Failed to add the following rooms to %(groupId)s:": "Failed to add the following rooms to %(groupId)s:",
- "Unnamed Room": "Unnamed Room",
"Riot does not have permission to send you notifications - please check your browser settings": "Riot does not have permission to send you notifications - please check your browser settings",
"Riot was not given permission to send notifications - please try again": "Riot was not given permission to send notifications - please try again",
"Unable to enable Notifications": "Unable to enable Notifications",
@@ -153,18 +149,59 @@
"Displays action": "Displays action",
"Unrecognised command:": "Unrecognised command:",
"Reason": "Reason",
+ " accepted the invitation for %(displayName)s.": " accepted the invitation for %(displayName)s.",
+ " accepted an invitation.": " accepted an invitation.",
+ " requested a VoIP conference.": " requested a VoIP conference.",
+ " invited .": " invited .",
+ " banned .": " banned .",
+ " changed their display name to .": " changed their display name to .",
+ " set their display name to .": " set their display name to .",
+ " removed their display name ().": " removed their display name ().",
+ " removed their profile picture.": " removed their profile picture.",
+ " changed their profile picture.": " changed their profile picture.",
+ " set a profile picture.": " set a profile picture.",
"VoIP conference started.": "VoIP conference started.",
+ " joined the room.": " joined the room.",
"VoIP conference finished.": "VoIP conference finished.",
- "%(senderDisplayName)s sent an image.": "%(senderDisplayName)s sent an image.",
+ " rejected the invitation.": " rejected the invitation.",
+ " left the room.": " left the room.",
+ " unbanned .": " unbanned .",
+ " kicked .": " kicked .",
+ " withdrew 's invitation.": " withdrew 's invitation.",
+ " changed the topic to \"%(topic)s\".": " changed the topic to \"%(topic)s\".",
+ " removed the room name.": " removed the room name.",
+ " changed the room name to %(roomName)s.": " changed the room name to %(roomName)s.",
+ " sent an image.": " sent an image.",
"Someone": "Someone",
"(not supported by this browser)": "(not supported by this browser)",
+ " answered the call.": " answered the call.",
"(could not connect media)": "(could not connect media)",
"(no answer)": "(no answer)",
"(unknown failure: %(reason)s)": "(unknown failure: %(reason)s)",
+ " ended the call.": " ended the call.",
+ " placed a %(callType)s call.": " placed a %(callType)s call.",
+ " sent an invitation to %(targetDisplayName)s to join the room.": " sent an invitation to %(targetDisplayName)s to join the room.",
+ " made future room history visible to all room members, from the point they are invited.": " made future room history visible to all room members, from the point they are invited.",
+ " made future room history visible to all room members, from the point they joined.": " made future room history visible to all room members, from the point they joined.",
+ " made future room history visible to all room members.": " made future room history visible to all room members.",
+ " made future room history visible to anyone.": " made future room history visible to anyone.",
+ " made future room history visible to unknown (%(visibility)s).": " made future room history visible to unknown (%(visibility)s).",
+ " turned on end-to-end encryption (algorithm %(algorithm)s).": " turned on end-to-end encryption (algorithm %(algorithm)s).",
+ " from %(fromPowerLevel)s to %(toPowerLevel)s": " from %(fromPowerLevel)s to %(toPowerLevel)s",
+ " changed the power level of %(powerLevelDiffText)s.": " changed the power level of %(powerLevelDiffText)s.",
+ " changed the pinned messages for the room.": " changed the pinned messages for the room.",
+ "%(widgetName)s widget modified by ": "%(widgetName)s widget modified by ",
+ "%(widgetName)s widget added by ": "%(widgetName)s widget added by ",
+ "%(widgetName)s widget removed by ": "%(widgetName)s widget removed by ",
"%(displayName)s is typing": "%(displayName)s is typing",
"%(names)s and %(count)s others are typing|other": "%(names)s and %(count)s others are typing",
"%(names)s and %(count)s others are typing|one": "%(names)s and one other is typing",
"%(names)s and %(lastPerson)s are typing": "%(names)s and %(lastPerson)s are typing",
+ "Failure to create room": "Failure to create room",
+ "Server may be unavailable, overloaded, or you hit a bug.": "Server may be unavailable, overloaded, or you hit a bug.",
+ "Send anyway": "Send anyway",
+ "Send": "Send",
+ "Unnamed Room": "Unnamed Room",
"Your browser does not support the required cryptography extensions": "Your browser does not support the required cryptography extensions",
"Not a valid Riot keyfile": "Not a valid Riot keyfile",
"Authentication check failed: incorrect password?": "Authentication check failed: incorrect password?",
@@ -277,29 +314,6 @@
"Off": "Off",
"On": "On",
"Noisy": "Noisy",
- "Invalid alias format": "Invalid alias format",
- "'%(alias)s' is not a valid format for an alias": "'%(alias)s' is not a valid format for an alias",
- "Invalid address format": "Invalid address format",
- "'%(alias)s' is not a valid format for an address": "'%(alias)s' is not a valid format for an address",
- "not specified": "not specified",
- "not set": "not set",
- "Remote addresses for this room:": "Remote addresses for this room:",
- "Addresses": "Addresses",
- "The main address for this room is": "The main address for this room is",
- "Local addresses for this room:": "Local addresses for this room:",
- "This room has no local addresses": "This room has no local addresses",
- "New address (e.g. #foo:%(localDomain)s)": "New address (e.g. #foo:%(localDomain)s)",
- "Invalid community ID": "Invalid community ID",
- "'%(groupId)s' is not a valid community ID": "'%(groupId)s' is not a valid community ID",
- "Flair": "Flair",
- "Showing flair for these communities:": "Showing flair for these communities:",
- "This room is not showing flair for any communities": "This room is not showing flair for any communities",
- "New community ID (e.g. +foo:%(localDomain)s)": "New community ID (e.g. +foo:%(localDomain)s)",
- "You have enabled URL previews by default.": "You have enabled URL previews by default.",
- "You have disabled URL previews by default.": "You have disabled URL previews by default.",
- "URL previews are enabled by default for participants in this room.": "URL previews are enabled by default for participants in this room.",
- "URL previews are disabled by default for participants in this room.": "URL previews are disabled by default for participants in this room.",
- "URL Previews": "URL Previews",
"Cannot add any more widgets": "Cannot add any more widgets",
"The maximum permitted number of widgets have already been added to this room.": "The maximum permitted number of widgets have already been added to this room.",
"Add a widget": "Add a widget",
@@ -401,11 +415,11 @@
"numbullet": "numbullet",
"Markdown is disabled": "Markdown is disabled",
"Markdown is enabled": "Markdown is enabled",
+ "Unpin Message": "Unpin Message",
+ "Jump to message": "Jump to message",
"No pinned messages.": "No pinned messages.",
"Loading...": "Loading...",
"Pinned Messages": "Pinned Messages",
- "Unpin Message": "Unpin Message",
- "Jump to message": "Jump to message",
"%(duration)ss": "%(duration)ss",
"%(duration)sm": "%(duration)sm",
"%(duration)sh": "%(duration)sh",
@@ -580,6 +594,9 @@
"Invalid file%(extra)s": "Invalid file%(extra)s",
"Error decrypting image": "Error decrypting image",
"Error decrypting video": "Error decrypting video",
+ "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s changed the avatar for %(roomName)s",
+ "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removed the room avatar.",
+ "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s changed the room avatar to ",
"Copied!": "Copied!",
"Failed to copy": "Failed to copy",
"Add an Integration": "Add an Integration",
@@ -755,7 +772,6 @@
"Room directory": "Room directory",
"Start chat": "Start chat",
"And %(count)s more...|other": "And %(count)s more...",
- "Share Link to User": "Share Link to User",
"ex. @bob:example.com": "ex. @bob:example.com",
"Add User": "Add User",
"Matrix ID": "Matrix ID",
@@ -1193,44 +1209,5 @@
"Import": "Import",
"Failed to set direct chat tag": "Failed to set direct chat tag",
"Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room",
- "Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room",
- " accepted the invitation for %(displayName)s.": " accepted the invitation for %(displayName)s.",
- " accepted an invitation.": " accepted an invitation.",
- " requested a VoIP conference.": " requested a VoIP conference.",
- " invited .": " invited .",
- " banned .": " banned .",
- " changed their display name to .": " changed their display name to .",
- " set their display name to .": " set their display name to .",
- " removed their display name ().": " removed their display name ().",
- " removed their profile picture.": " removed their profile picture.",
- " changed their profile picture.": " changed their profile picture.",
- " set a profile picture.": " set a profile picture.",
- " joined the room.": " joined the room.",
- " rejected the invitation.": " rejected the invitation.",
- " left the room.": " left the room.",
- " unbanned .": " unbanned .",
- " kicked .": " kicked .",
- " withdrew 's invitation.": " withdrew 's invitation.",
- " changed the topic to \"%(topic)s\".": " changed the topic to \"%(topic)s\".",
- " changed the room name to %(roomName)s.": " changed the room name to %(roomName)s.",
- " changed the avatar for %(roomName)s": " changed the avatar for %(roomName)s",
- " changed the room avatar to ": " changed the room avatar to ",
- " removed the room name.": " removed the room name.",
- " removed the room avatar.": " removed the room avatar.",
- " answered the call.": " answered the call.",
- " ended the call.": " ended the call.",
- " placed a %(callType)s call.": " placed a %(callType)s call.",
- " sent an invitation to %(targetDisplayName)s to join the room.": " sent an invitation to %(targetDisplayName)s to join the room.",
- " made future room history visible to all room members, from the point they are invited.": " made future room history visible to all room members, from the point they are invited.",
- " made future room history visible to all room members, from the point they joined.": " made future room history visible to all room members, from the point they joined.",
- " made future room history visible to all room members.": " made future room history visible to all room members.",
- " made future room history visible to anyone.": " made future room history visible to anyone.",
- " made future room history visible to unknown (%(visibility)s).": " made future room history visible to unknown (%(visibility)s).",
- " turned on end-to-end encryption (algorithm %(algorithm)s).": " turned on end-to-end encryption (algorithm %(algorithm)s).",
- " from %(fromPowerLevel)s to %(toPowerLevel)s": " from %(fromPowerLevel)s to %(toPowerLevel)s",
- " changed the power level of %(powerLevelDiffText)s.": " changed the power level of %(powerLevelDiffText)s.",
- " changed the pinned messages for the room.": " changed the pinned messages for the room.",
- "%(widgetName)s widget modified by ": "%(widgetName)s widget modified by ",
- "%(widgetName)s widget added by ": "%(widgetName)s widget added by ",
- "%(widgetName)s widget removed by ": "%(widgetName)s widget removed by "
+ "Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room"
}
diff --git a/src/stores/RoomViewStore.js b/src/stores/RoomViewStore.js
index 35cfe69086..fed0d7b4a1 100644
--- a/src/stores/RoomViewStore.js
+++ b/src/stores/RoomViewStore.js
@@ -1,6 +1,6 @@
/*
Copyright 2017 Vector Creations Ltd
-Copyright 2017 New Vector Ltd
+Copyright 2017, 2018 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.
diff --git a/src/stores/WidgetEchoStore.js b/src/stores/WidgetEchoStore.js
new file mode 100644
index 0000000000..26d24c0563
--- /dev/null
+++ b/src/stores/WidgetEchoStore.js
@@ -0,0 +1,112 @@
+/*
+Copyright 2018 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.
+*/
+
+import EventEmitter from 'events';
+
+import WidgetUtils from '../utils/WidgetUtils';
+import MatrixClientPeg from '../MatrixClientPeg';
+
+/**
+ * Acts as a place to get & set widget state, storing local echo state and
+ * proxying through state from the js-sdk.
+ */
+class WidgetEchoStore extends EventEmitter {
+ constructor() {
+ super();
+
+ this._roomWidgetEcho = {
+ // roomId: {
+ // widgetId: [object]
+ // }
+ };
+ }
+
+ /**
+ * Gets the widgets for a room, substracting those that are pending deletion.
+ * Widgets that are pending addition are not included, since widgets are
+ * represted as MatrixEvents, so to do this we'd have to create fake MatrixEvents,
+ * and we don't really need the actual widget events anyway since we just want to
+ * show a spinner / prevent widgets being added twice.
+ */
+ getEchoedRoomWidgets(room, currentRoomWidgets) {
+ const echoedWidgets = [];
+
+ const roomEchoState = Object.assign({}, this._roomWidgetEcho[room.roomId]);
+
+ for (const w of currentRoomWidgets) {
+ const widgetId = w.getStateKey();
+ if (roomEchoState && roomEchoState[widgetId] && Object.keys(roomEchoState[widgetId]).length === 0) {
+ // delete locally so don't copy it
+ // we don't include widgets that have changed for the same rason we don't include new ones,
+ // so fall into the 'else' case and use the old one
+ //} else if (roomEchoState && roomEchoState[widgetId]) {
+ // echoedWidgets.push(roomEchoState[widgetId]);
+ } else {
+ echoedWidgets.push(w);
+ }
+ delete roomEchoState[widgetId];
+ }
+
+ // any remining in roomEchoState are extra that need to be added
+ // We don't do this for the reasons above
+ /*for (const widgetId of Object.keys(roomEchoState)) {
+ echoedWidgets.push(roomEchoState[widgetId]);
+ }*/
+
+ return echoedWidgets;
+ }
+
+ roomHasPendingWidgetsOfType(room, currentRoomWidgets, type) {
+ const roomEchoState = Object.assign({}, this._roomWidgetEcho[room.roomId]);
+ if (roomEchoState === undefined) return false;
+
+ for (const w of currentRoomWidgets) {
+ const widgetId = w.getStateKey();
+ delete roomEchoState[widgetId];
+ }
+
+ if (type === undefined) {
+ return Object.keys(roomEchoState).length > 0;
+ } else {
+ return Object.values(roomEchoState).some((widget) => {
+ return widget.type === type;
+ });
+ }
+ }
+
+ roomHasPendingWidgets(room, currentRoomWidgets) {
+ return this.roomHasPendingWidgetsOfType(room, currentRoomWidgets);
+ }
+
+ setRoomWidgetEcho(room, widgetId, state) {
+ if (this._roomWidgetEcho[room.roomId] === undefined) this._roomWidgetEcho[room.roomId] = {};
+
+ this._roomWidgetEcho[room.roomId][widgetId] = state;
+ this.emit('updateRoomWidgetEcho');
+ }
+
+ removeRoomWidgetEcho(room, widgetId) {
+ delete this._roomWidgetEcho[room.roomId][widgetId];
+ if (this._roomWidgetEcho[room.roomId] === {}) delete this._roomWidgetEcho[room.roomId];
+ this.emit('updateRoomWidgetEcho');
+ }
+}
+
+let singletonWidgetEchoStore = null;
+if (!singletonWidgetEchoStore) {
+ singletonWidgetEchoStore = new WidgetEchoStore();
+}
+module.exports = singletonWidgetEchoStore;
diff --git a/src/utils/WidgetUtils.js b/src/utils/WidgetUtils.js
index ab5b5b0130..43ca20e886 100644
--- a/src/utils/WidgetUtils.js
+++ b/src/utils/WidgetUtils.js
@@ -19,6 +19,7 @@ import MatrixClientPeg from '../MatrixClientPeg';
import SdkConfig from "../SdkConfig";
import dis from '../dispatcher';
import * as url from "url";
+import WidgetEchoStore from '../stores/WidgetEchoStore';
export default class WidgetUtils {
/* Returns true if user is able to send state events to modify widgets in this room
@@ -250,11 +251,16 @@ export default class WidgetUtils {
content = {};
}
+ const room = MatrixClientPeg.get().getRoom(roomId);
+ WidgetEchoStore.setRoomWidgetEcho(room, widgetId, content);
+
const client = MatrixClientPeg.get();
// TODO - Room widgets need to be moved to 'm.widget' state events
// https://docs.google.com/document/d/1uPF7XWY_dXTKVKV7jZQ2KmsI19wn9-kFRgQ1tFQP7wQ/edit?usp=sharing
return client.sendStateEvent(roomId, "im.vector.modular.widgets", content, widgetId).then(() => {
return WidgetUtils.waitForRoomWidget(widgetId, roomId, addingWidget);
+ }).finally(() => {
+ WidgetEchoStore.removeRoomWidgetEcho(room, widgetId);
});
}