* Enforce fixed column number at various width breakpoints.
* Bring back the filmstrip at small sizes but hide it.
* Change default maximum columns to 7.
Due to how the filmstrip size if computed I don't think there is a good way to
animate the change in size, so just ignore the toolbar, it will be hidden soon
enough.
Up until now we relied on implicit loading of middlewares and reducers, through
having imports in each feature's index.js.
This leads to many complex import cycles which result in (sometimes) hard to fix
bugs in addition to (often) breaking mobile because a web-only feature gets
imported on mobile too, thanks to the implicit loading.
This PR changes that to make the process explicit. Both middlewares and reducers
are imported in a single place, the app entrypoint. They have been divided into
3 categories: any, web and native, which represent each of the platforms
respectively.
Ideally no feature should have an index.js exporting actions, action types and
components, but that's a larger ordeal, so this is just the first step in
getting there. In order to both set example and avoid large cycles the app
feature has been refactored to not have an idex.js itself.
Use a dimensions detecting root component. The Dimensions module does not
measure the app's view size, but the Window, which may not be the same, for
example on iOS when PiP is used.
Also refactor the aspect ratio wrap component since it can be taken directly
from the store.
Last, remove the use of DimensionsDetector on LargeVideo and TileView since they
occupy the full-screen anyway.
Fixes PiP mode on iOS.
When the reccorder joins, they have a local participant, which is not rendered,
so don't count it towards the partcipant count used for computing the tile
sizes.
Regresssion from bd8a7edbd2.
When the toolbar buttons are overridden with URL parameters, our computed set of
buttons will be wrong. Thus, compute it every time and check for the
differences.
* fix(thumbnail): Optimize status bar moderator icon
Moved all moderator functionality to react to optimize the number of
status bar updates.
* fix(RemoteVideoMenuTriggerButton): Use nullish coalescing
Co-Authored-By: Saúl Ibarra Corretgé <saghul@jitsi.org>
* ref(StatusBar): rename to StatusIndicators
* fix(RemoteVideoMenu): isModerator value.
* fix(notification): mobile.
Co-authored-by: Saúl Ibarra Corretgé <s@saghul.net>
Since the verical filmstrip doesn't set its width explicitly anymore,
calculating the available area for the large video based on the
filmstrip width retrieved from the HTML element was wrong
in the cases when the rendering and cleanup of the filmstrip hasn't
finish yet. For example when switching from tile view to stage view.
Audio streams are automatically played by WebRTC and this won't change, probably
ever. There is no point in having checks and an Audio component which does
nothing.
Mobile uses a different logic for deciding whether to show the filmstrip or not:
if there are more than 1 participants or not, and there is no way to manually
toggle it.
This refactors all handling of audio-only and last N to 2 features in preparation
for "low bandwidth mode".
The main motivation to do this is that lastN is a "global" setting so it helps
to have all processing for it in a single place.
Using anything non-serializable for action types is discouraged:
https://redux.js.org/faq/actions#actions
In fact, this is the Flow definition for dispatching actions:
declare export type DispatchAPI<A> = (action: A) => A;
declare export type Dispatch<A: { type: $Subtype<string> }> = DispatchAPI<A>;
Note how the `type` field is defined as a subtype of string, which Symbol isn’t.
Touch feedback manifests in some ugly black border bleeding out of the thumbnail
itself. Since we already provide feedback (be that by adding the blue border in
case of pinning, or showing the menu in case of long press) the perception is
the same, without the graphical glitch.
Filmstrip remote thumbnails display under certain conditions, as
defined in filmstrip/functions.web.js. Previously the raw
participant count was used, which included fake participants.
Using the selector getParticipantCount excludes fake participants,
causing YouTube thumbnails to remain hidden in a 1-on-1 call.
For the most part the changes are taking the "static propTypes" declaration off
of components and declaring them as Flow types. Sometimes to support flow some
method signatures had to be added. There are some exceptions in which more had
to be done to tame the beast:
- AbstractVideoTrack: put in additional truthy checks for videoTrack.
- Video: add truthy checks for the _videoElement ref.
- shouldRenderVideoTrack function: Some component could pass null for the
videoTrack argument and Flow wanted that called out explicitly.
- DisplayName: Add a truthy check for the input ref before acting on it.
- NumbersList: Move array checks inline for Flow to comprehend array methods
could be called. Add type checks in the Object.entries loop as the value is
assumed to be a mixed type by Flow.
- AbstractToolbarButton: add additional truthy check for passed in type.
* feat(tile-view): initial implementation for mobile
- Create a tile view component for displaying thumbnails in a
two-dimensional grid.
- Update the existing TileViewButton so it shows a label in the
overflow menu.
- Modify conference so it can display TileView while hiding
Filmstrip.
- Modify Thumbnail so its width/height can be set and to prevent
pinning while in tile view mode.
* use style array for thumbnail styles
* change ternary to math.min for expressiveness
* use dimensiondetector
* pass explicit disableTint prop
* use makeAspectRatioAware instead of aspectRatio prop
* update docs
* fix docs again (fix laziest copy/paste job I've ever done)
* large-video: rename onPress prop to onClick
* change forEach to for...of
* use truthy check fallthrough logic instead of explicit if
* put tile view button second to last in menu
* move spacer to a constant
* the magical incantation to make flow shut up
* feat(tile-view): initial implementation for tile view
- Modify the classname on the app root so layout can adjust
depending on the desired layout mode--vertical filmstrip,
horizontal filmstrip, and tile view.
- Create a button for toggling tile view.
- Add a StateListenerRegistry to automatically update the
selected participant and max receiver frame height on tile
view toggle.
- Rezise thumbnails when switching in and out of tile view.
- Move the local video when switching in and out of tile view.
- Update reactified pieces of thumbnails when switching in and
out of tile view.
- Cap the max receiver video quality in tile view based on tile
size.
- Use CSS to hide UI components that should not display in tile
view.
- Signal follow me changes.
* change local video id for tests
* change approach: leverage more css
* squash: fix some formatting
* squash: prevent pinning, hide pin border in tile view
* squash: change logic for maxReceiverQuality due to sidestepping resizing logic
* squash: fix typo, columns configurable, remove unused constants
* squash: resize with js again
* squash: use yana's math for calculating tile size
* ref(filmstrip): create an empty container for local filmstrip move
This might be necessary for tile view. To support making the
local video display at the end of remote videos while in tile
view, but separateed from scrollable remote videos, moving
the local video might be necessary. By creating an empty
container, there is a target for local video to move to.
* squash: rename id
This zOrder change fixes the issue that the scrollable filmstrip videos
rendered in front of the local participant, however there is still an
issue that needs to be fixed later: The rendered videos should have
overflow: 'hidden' property applied so then they don't get rendered when
scrolled out of the ScrollView, that property however doesn't seem to
work for Video components.
As part of the work on fixing the problem with the multiplying
thumbnails, we've associated remote participant w/ JitsiConference.
However, there are periods of time when multiple JitsiConferences are in
the redux state (and that period is going to be shorted by
StateListenerRegistry). In order to give more control to the feature
base/participants, reduce the occurrences of direct access to the
features/base/participants redux state and utilize the feature's
existing read access functions. Which will allow us in the future to
enhance these functions to access participants which are relevant to the
current conference of interest to the user only.
Contributing all buttons in one place goes against the designs that we
set out at the beginning of the project's rewrite and that multiple of
us have been following since then.
Adds base/sounds feature which allows other features to register a sound
source under specified id. A new SoundsCollection component will then
render corresponding HTMLAudioElement for each such sound. Once "setRef"
callback is called by the HTMLAudioElement, this element will be added
to the Redux store. When that happens sound can be played through the
new 'playSound' action which will call play() method on the stored
HTMLAudioElement instance.
* feat(invite): be able to call numbers from the invite dialog
The major changes:
- Remove DialOutDialog, its views, redux hooks, css, and images.
Its main functionality has been moved into AddPeopleDialog.
- Modify the AppPeopleDialog styling a bit so it is wider.
- Add phone numbers to AddPeopleDialog search results. Phone
numbers are validated in parallel with the request for people
and then appended to the result. The validation includes
an ajax to validate the number is recognized as dialable by
the server. The trigger for the validation is essentially if
the entered input is numbers only.
- AddPeopleDialog holds onto the full object representation of
an item selected in MultiSelectAutocomplete. This is so
selected items can be removed on successful invite, leaving
only unsuccessful items.
- More granular error handling on invite so individual invitees
can be removed from the selected items list.
* squash: change load state, new regex for numbers
* squash: change strings, auto prepend 1 if no country code, add reminders
When in PiP mode the LargeView will not be large enough to hold the avatar (for
those interested in the details, our avatar's size is 200, and in PiP mode the
app is resized to about 150).
In order to solve it, this PR refactors how the avatar style is passed along,
reducing it to a single "size" prop. With this only prop, the Avatar compononent
will compute the width, height and borderRadius, plus deal with some Android
shenanigans.
In addition, the LargeView component now uses DimensionsDetector to check its
own size and adjust the size prop passed to the Avatar component as needed.