mirror of https://github.com/vector-im/riot-web
Do some level of local echo for widgets
* Show a spinner while we wait for widgets to be deleted * Hide widgets while they're pending deletion * Don't put another jitsi widget into the room if there's already one pendingpull/21833/head
parent
767e67dc70
commit
8b64ddcbe8
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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({
|
|||
</div>;
|
||||
}
|
||||
|
||||
let spinner;
|
||||
if (
|
||||
apps.length === 0 && WidgetEchoStore.roomHasPendingWidgets(
|
||||
this.props.room,
|
||||
WidgetUtils.getRoomWidgets(this.props.room),
|
||||
)
|
||||
) {
|
||||
const Loader = sdk.getComponent("elements.Spinner");
|
||||
spinner = <Loader />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={'mx_AppsDrawer' + (this.props.hide ? ' mx_AppsDrawer_hidden' : '')}>
|
||||
<div id='apps' className='mx_AppsContainer'>
|
||||
{ apps }
|
||||
{ spinner }
|
||||
</div>
|
||||
{ this._canUserModify() && addWidget }
|
||||
</div>
|
||||
|
|
|
@ -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",
|
||||
"<target> accepted the invitation for %(displayName)s.": "<target> accepted the invitation for %(displayName)s.",
|
||||
"<target> accepted an invitation.": "<target> accepted an invitation.",
|
||||
"<sender> requested a VoIP conference.": "<sender> requested a VoIP conference.",
|
||||
"<sender> invited <target>.": "<sender> invited <target>.",
|
||||
"<sender> banned <target>.": "<sender> banned <target>.",
|
||||
"<oldDisplayName> changed their display name to <displayName>.": "<oldDisplayName> changed their display name to <displayName>.",
|
||||
"<sender> set their display name to <displayName>.": "<sender> set their display name to <displayName>.",
|
||||
"<sender> removed their display name (<oldDisplayName>).": "<sender> removed their display name (<oldDisplayName>).",
|
||||
"<sender> removed their profile picture.": "<sender> removed their profile picture.",
|
||||
"<sender> changed their profile picture.": "<sender> changed their profile picture.",
|
||||
"<sender> set a profile picture.": "<sender> set a profile picture.",
|
||||
"VoIP conference started.": "VoIP conference started.",
|
||||
"<target> joined the room.": "<target> joined the room.",
|
||||
"VoIP conference finished.": "VoIP conference finished.",
|
||||
"%(senderDisplayName)s sent an image.": "%(senderDisplayName)s sent an image.",
|
||||
"<target> rejected the invitation.": "<target> rejected the invitation.",
|
||||
"<target> left the room.": "<target> left the room.",
|
||||
"<sender> unbanned <target>.": "<sender> unbanned <target>.",
|
||||
"<sender> kicked <target>.": "<sender> kicked <target>.",
|
||||
"<sender> withdrew <target>'s invitation.": "<sender> withdrew <target>'s invitation.",
|
||||
"<sender> changed the topic to \"%(topic)s\".": "<sender> changed the topic to \"%(topic)s\".",
|
||||
"<sender> removed the room name.": "<sender> removed the room name.",
|
||||
"<sender> changed the room name to %(roomName)s.": "<sender> changed the room name to %(roomName)s.",
|
||||
"<sender> sent an image.": "<sender> sent an image.",
|
||||
"Someone": "Someone",
|
||||
"(not supported by this browser)": "(not supported by this browser)",
|
||||
"<sender> answered the call.": "<sender> answered the call.",
|
||||
"(could not connect media)": "(could not connect media)",
|
||||
"(no answer)": "(no answer)",
|
||||
"(unknown failure: %(reason)s)": "(unknown failure: %(reason)s)",
|
||||
"<sender> ended the call.": "<sender> ended the call.",
|
||||
"<sender> placed a %(callType)s call.": "<sender> placed a %(callType)s call.",
|
||||
"<sender> sent an invitation to %(targetDisplayName)s to join the room.": "<sender> sent an invitation to %(targetDisplayName)s to join the room.",
|
||||
"<sender> made future room history visible to all room members, from the point they are invited.": "<sender> made future room history visible to all room members, from the point they are invited.",
|
||||
"<sender> made future room history visible to all room members, from the point they joined.": "<sender> made future room history visible to all room members, from the point they joined.",
|
||||
"<sender> made future room history visible to all room members.": "<sender> made future room history visible to all room members.",
|
||||
"<sender> made future room history visible to anyone.": "<sender> made future room history visible to anyone.",
|
||||
"<sender> made future room history visible to unknown (%(visibility)s).": "<sender> made future room history visible to unknown (%(visibility)s).",
|
||||
"<sender> turned on end-to-end encryption (algorithm %(algorithm)s).": "<sender> turned on end-to-end encryption (algorithm %(algorithm)s).",
|
||||
"<user> from %(fromPowerLevel)s to %(toPowerLevel)s": "<user> from %(fromPowerLevel)s to %(toPowerLevel)s",
|
||||
"<sender> changed the power level of %(powerLevelDiffText)s.": "<sender> changed the power level of %(powerLevelDiffText)s.",
|
||||
"<sender> changed the pinned messages for the room.": "<sender> changed the pinned messages for the room.",
|
||||
"%(widgetName)s widget modified by <sender>": "%(widgetName)s widget modified by <sender>",
|
||||
"%(widgetName)s widget added by <sender>": "%(widgetName)s widget added by <sender>",
|
||||
"%(widgetName)s widget removed by <sender>": "%(widgetName)s widget removed by <sender>",
|
||||
"%(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 <a>enabled</a> URL previews by default.": "You have <a>enabled</a> URL previews by default.",
|
||||
"You have <a>disabled</a> URL previews by default.": "You have <a>disabled</a> 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 <img/>": "%(senderDisplayName)s changed the room avatar to <img/>",
|
||||
"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",
|
||||
"<target> accepted the invitation for %(displayName)s.": "<target> accepted the invitation for %(displayName)s.",
|
||||
"<target> accepted an invitation.": "<target> accepted an invitation.",
|
||||
"<sender> requested a VoIP conference.": "<sender> requested a VoIP conference.",
|
||||
"<sender> invited <target>.": "<sender> invited <target>.",
|
||||
"<sender> banned <target>.": "<sender> banned <target>.",
|
||||
"<oldDisplayName> changed their display name to <displayName>.": "<oldDisplayName> changed their display name to <displayName>.",
|
||||
"<sender> set their display name to <displayName>.": "<sender> set their display name to <displayName>.",
|
||||
"<sender> removed their display name (<oldDisplayName>).": "<sender> removed their display name (<oldDisplayName>).",
|
||||
"<sender> removed their profile picture.": "<sender> removed their profile picture.",
|
||||
"<sender> changed their profile picture.": "<sender> changed their profile picture.",
|
||||
"<sender> set a profile picture.": "<sender> set a profile picture.",
|
||||
"<target> joined the room.": "<target> joined the room.",
|
||||
"<target> rejected the invitation.": "<target> rejected the invitation.",
|
||||
"<target> left the room.": "<target> left the room.",
|
||||
"<sender> unbanned <target>.": "<sender> unbanned <target>.",
|
||||
"<sender> kicked <target>.": "<sender> kicked <target>.",
|
||||
"<sender> withdrew <target>'s invitation.": "<sender> withdrew <target>'s invitation.",
|
||||
"<sender> changed the topic to \"%(topic)s\".": "<sender> changed the topic to \"%(topic)s\".",
|
||||
"<sender> changed the room name to %(roomName)s.": "<sender> changed the room name to %(roomName)s.",
|
||||
"<sender> changed the avatar for %(roomName)s": "<sender> changed the avatar for %(roomName)s",
|
||||
"<sender> changed the room avatar to <img/>": "<sender> changed the room avatar to <img/>",
|
||||
"<sender> removed the room name.": "<sender> removed the room name.",
|
||||
"<sender> removed the room avatar.": "<sender> removed the room avatar.",
|
||||
"<sender> answered the call.": "<sender> answered the call.",
|
||||
"<sender> ended the call.": "<sender> ended the call.",
|
||||
"<sender> placed a %(callType)s call.": "<sender> placed a %(callType)s call.",
|
||||
"<sender> sent an invitation to %(targetDisplayName)s to join the room.": "<sender> sent an invitation to %(targetDisplayName)s to join the room.",
|
||||
"<sender> made future room history visible to all room members, from the point they are invited.": "<sender> made future room history visible to all room members, from the point they are invited.",
|
||||
"<sender> made future room history visible to all room members, from the point they joined.": "<sender> made future room history visible to all room members, from the point they joined.",
|
||||
"<sender> made future room history visible to all room members.": "<sender> made future room history visible to all room members.",
|
||||
"<sender> made future room history visible to anyone.": "<sender> made future room history visible to anyone.",
|
||||
"<sender> made future room history visible to unknown (%(visibility)s).": "<sender> made future room history visible to unknown (%(visibility)s).",
|
||||
"<sender> turned on end-to-end encryption (algorithm %(algorithm)s).": "<sender> turned on end-to-end encryption (algorithm %(algorithm)s).",
|
||||
"<user> from %(fromPowerLevel)s to %(toPowerLevel)s": "<user> from %(fromPowerLevel)s to %(toPowerLevel)s",
|
||||
"<sender> changed the power level of %(powerLevelDiffText)s.": "<sender> changed the power level of %(powerLevelDiffText)s.",
|
||||
"<sender> changed the pinned messages for the room.": "<sender> changed the pinned messages for the room.",
|
||||
"%(widgetName)s widget modified by <sender>": "%(widgetName)s widget modified by <sender>",
|
||||
"%(widgetName)s widget added by <sender>": "%(widgetName)s widget added by <sender>",
|
||||
"%(widgetName)s widget removed by <sender>": "%(widgetName)s widget removed by <sender>"
|
||||
"Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room"
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue