As Element Call grows in complexity, it has become a pain point that our business logic remains so tightly coupled to the UI code. In particular, this has made testing difficult, and the complex semantics of React hooks are not a great match for arbitrary business logic. Here, I show the beginnings of what it would look like for us to adopt the MVVM pattern. I've created a CallViewModel and TileViewModel that expose their state to the UI as rxjs Observables, as well as a couple of helper functions for consuming view models in React code.
This should contain no user-visible changes, but we need to watch out for regressions particularly around focus switching and promotion of speakers, because this was the logic I chose to refactor first.
reorderTiles was programmed to only place a tile in the speaker section if that tile's previous position was off-screen. But for speakers that started off-screen, this would cause them to oscillate in and out of the speaker section on each render, because the speaker section is, of course, on-screen. The solution I've gone with here is to avoid referencing the previous position, and instead go by the computed natural ordering, which ought to be more stable.
Splits out the room locartion parsing from everything else to avoid
one function that fills out different parts of its return struct
depending on its args.
For the most part, at least. If the edge cases where they differ still feel weird, I can iterate on this further.
The diff is unfortunately a bit impenetrable, because I had to change both the fillGaps and cycleTileSize core algorithms used by the big grid layout. But: the main change of significance is the addition of a function vacateArea, which clears out an area within the grid in a specific way that mirrors the motion performed by fillGaps.
by fixing the cause rather than the symptom: this upgrades the code to use the new, recommended JSX transform mode of React 17+, which no longer requires you to import React manually just to write JSX.
In preparation for adding layouts other than big grid to the NewVideoGrid component, I've abstracted the grid layout system into an interface called Layout. For now, the only implementation of this interface is BigGrid, but this will allow us to easily plug in Spotlight, SplitGrid, and OneOnOne layout systems so we can get rid of the old VideoGrid component and have One Grid to Rule Them All™.
Please do shout if any of this seems obtuse or underdocumented, because I'm not super happy with how approachable the NewVideoGrid code looks right now…
Incidentally, this refactoring made it way easier to save the state of the grid while in fullscreen / another layout, so I went ahead and did that.
React 18's strict mode intentionally mounts all components twice, which was causing Olm to get double-loaded. Also, it doesn't need to be loaded if the app is running as a widget.