This repository has been archived by the owner on Sep 11, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 832
Improve UX for Jitsi by adding local echo for widgets #2035
Merged
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
8b64ddc
Do some level of local echo for widgets
dbkr 3199e68
Lint
dbkr 13530e5
Merge remote-tracking branch 'origin/develop' into dbkr/widget_echo
dbkr 9d41b87
i18n
dbkr c665ab8
Add error dialog if widget remove fails
dbkr 5f2e2ef
Revert 8b64ddc for MatrixActionCreators
dbkr eb552e5
Just pass the roomId into WidgetEchoStore
dbkr 1f2d279
Consistency, redundant check & doc
dbkr fb7ce9d
More doc
dbkr 7e2b559
Make if clearer
dbkr 8c10dc1
Remove unhelpful commented code
dbkr 3f60300
Remove redundant check
dbkr 658ac73
comments
dbkr c26b300
more comments
dbkr 3f20eb9
Use more helpful dialog tracking title
dbkr b6f854a
Simplify event name as it's the only one
dbkr 0f32c3a
PR feedback
dbkr 4c6419a
Merge remote-tracking branch 'origin/develop' into dbkr/widget_echo
dbkr 983dc3a
lint
dbkr 7aab6fa
Merge remote-tracking branch 'origin/develop' into dbkr/widget_echo
dbkr 68c46a6
lint
dbkr File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
/* | ||
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'; | ||
|
||
/** | ||
* 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 = { | ||
// Map as below. Object is the content of the widget state event, | ||
// so for widgets that have been deleted locally, the object is empty. | ||
// 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, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In theory, you could have a class that represents widget data within an event which doesn't care about MatrixEvents. Then you'd just need instantiate one of those as per usual (not a fake one). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep, true, it just means changing everything else to add that layer of abstraction |
||
* and we don't really need the actual widget events anyway since we just want to | ||
* show a spinner / prevent widgets being added twice. | ||
* | ||
* @param {Room} roomId The ID of the room to get widgets for | ||
* @param {MatrixEvent[]} currentRoomWidgets Current widgets for the room | ||
* @returns {MatrixEvent[]} List of widgets in the room, minus any pending removal | ||
*/ | ||
getEchoedRoomWidgets(roomId, currentRoomWidgets) { | ||
const echoedWidgets = []; | ||
|
||
const roomEchoState = Object.assign({}, this._roomWidgetEcho[roomId]); | ||
|
||
for (const w of currentRoomWidgets) { | ||
const widgetId = w.getStateKey(); | ||
// If there's no echo, or the echo still has a widget present, show the *old* widget | ||
// we don't include widgets that have changed for the same reason we don't include new ones, | ||
// ie. we'd need to fake matrix events to do so and therte's currently no need. | ||
if (!roomEchoState[widgetId] || Object.keys(roomEchoState[widgetId]).length !== 0) { | ||
echoedWidgets.push(w); | ||
} | ||
delete roomEchoState[widgetId]; | ||
} | ||
|
||
return echoedWidgets; | ||
} | ||
|
||
roomHasPendingWidgetsOfType(roomId, currentRoomWidgets, type) { | ||
const roomEchoState = Object.assign({}, this._roomWidgetEcho[roomId]); | ||
|
||
// any widget IDs that are already in the room are not pending, so | ||
// echoes for them don't count as pending. | ||
for (const w of currentRoomWidgets) { | ||
const widgetId = w.getStateKey(); | ||
delete roomEchoState[widgetId]; | ||
} | ||
|
||
// if there's anything left then there are pending widgets. | ||
if (type === undefined) { | ||
return Object.keys(roomEchoState).length > 0; | ||
} else { | ||
return Object.values(roomEchoState).some((widget) => { | ||
return widget.type === type; | ||
}); | ||
} | ||
} | ||
|
||
roomHasPendingWidgets(roomId, currentRoomWidgets) { | ||
return this.roomHasPendingWidgetsOfType(roomId, currentRoomWidgets); | ||
} | ||
|
||
setRoomWidgetEcho(roomId, widgetId, state) { | ||
if (this._roomWidgetEcho[roomId] === undefined) this._roomWidgetEcho[roomId] = {}; | ||
|
||
this._roomWidgetEcho[roomId][widgetId] = state; | ||
this.emit('update'); | ||
} | ||
|
||
removeRoomWidgetEcho(roomId, widgetId) { | ||
delete this._roomWidgetEcho[roomId][widgetId]; | ||
if (Object.keys(this._roomWidgetEcho[roomId]).length === 0) delete this._roomWidgetEcho[roomId]; | ||
this.emit('update'); | ||
} | ||
} | ||
|
||
let singletonWidgetEchoStore = null; | ||
if (!singletonWidgetEchoStore) { | ||
singletonWidgetEchoStore = new WidgetEchoStore(); | ||
} | ||
module.exports = singletonWidgetEchoStore; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,11 @@ import MatrixClientPeg from '../MatrixClientPeg'; | |
import SdkConfig from "../SdkConfig"; | ||
import dis from '../dispatcher'; | ||
import * as url from "url"; | ||
import WidgetEchoStore from '../stores/WidgetEchoStore'; | ||
|
||
// How long we wait for the state event echo to come back from the server | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's worth commenting what happens when the timeout elapses. |
||
// before waitFor[Room/User]Widget rejects its promise | ||
const WIDGET_WAIT_TIME = 20000; | ||
import SettingsStore from "../settings/SettingsStore"; | ||
|
||
/** | ||
|
@@ -155,7 +160,7 @@ export default class WidgetUtils { | |
const timerId = setTimeout(() => { | ||
MatrixClientPeg.get().removeListener('accountData', onAccountData); | ||
reject(new Error("Timed out waiting for widget ID " + widgetId + " to appear")); | ||
}, 10000); | ||
}, WIDGET_WAIT_TIME); | ||
MatrixClientPeg.get().on('accountData', onAccountData); | ||
}); | ||
} | ||
|
@@ -208,7 +213,7 @@ export default class WidgetUtils { | |
const timerId = setTimeout(() => { | ||
MatrixClientPeg.get().removeListener('RoomState.events', onRoomStateEvents); | ||
reject(new Error("Timed out waiting for widget ID " + widgetId + " to appear")); | ||
}, 10000); | ||
}, WIDGET_WAIT_TIME); | ||
MatrixClientPeg.get().on('RoomState.events', onRoomStateEvents); | ||
}); | ||
} | ||
|
@@ -271,11 +276,15 @@ export default class WidgetUtils { | |
content = {}; | ||
} | ||
|
||
WidgetEchoStore.setRoomWidgetEcho(roomId, 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(roomId, widgetId); | ||
}); | ||
} | ||
|
||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As it happens this does need a (c) 2018