+ {
+
+ /*
+ This extra video container is needed for
+ scrolling thumbnails in firefox, otherwise the
+ flex thumbnails resize instead of causing
+ overflow.
+ */
+ }
+
+
+
+
+
+
+ );
+ }
}
export default reactReduxConnect()(Conference);
diff --git a/react/features/filmstrip/actionTypes.js b/react/features/filmstrip/actionTypes.js
new file mode 100644
index 000000000..c39cc3cf5
--- /dev/null
+++ b/react/features/filmstrip/actionTypes.js
@@ -0,0 +1,35 @@
+import { Symbol } from '../base/react';
+
+/**
+ * The type of action which signals to change the count of known remote videos
+ * displayed in the filmstrip.
+ *
+ * {
+ * type: SET_FILMSTRIP_REMOTE_VIDEOS_COUNT,
+ * remoteVideosCount: number
+ * }
+ */
+export const SET_FILMSTRIP_REMOTE_VIDEOS_COUNT
+ = Symbol('SET_FILMSTRIP_REMOTE_VIDEOS_COUNT');
+
+/**
+ * The type of action which signals to change the visibility of remote videos in
+ * the filmstrip.
+ *
+ * {
+ * type: SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY,
+ * removeVideosVisible: boolean
+ * }
+ */
+export const SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY
+ = Symbol('SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY');
+
+/**
+ * The type of action sets the visibility of the entire filmstrip;
+ *
+ * {
+ * type: SET_FILMSTRIP_VISIBILITY,
+ * visible: boolean
+ * }
+ */
+export const SET_FILMSTRIP_VISIBILITY = Symbol('SET_FILMSTRIP_VISIBILITY');
diff --git a/react/features/filmstrip/actions.js b/react/features/filmstrip/actions.js
new file mode 100644
index 000000000..76fc9a24c
--- /dev/null
+++ b/react/features/filmstrip/actions.js
@@ -0,0 +1,54 @@
+import {
+ SET_FILMSTRIP_REMOTE_VIDEOS_COUNT,
+ SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY,
+ SET_FILMSTRIP_VISIBILITY
+} from './actionTypes';
+
+/**
+ * Sets the visibility of remote videos in the filmstrip.
+ *
+ * @param {boolean} remoteVideosVisible - Whether or not remote videos in the
+ * filmstrip should be visible.
+ * @returns {{
+ * type: SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY,
+ * remoteVideosVisible: boolean
+ * }}
+ */
+export function setFilmstripRemoteVideosVisibility(remoteVideosVisible) {
+ return {
+ type: SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY,
+ remoteVideosVisible
+ };
+}
+
+/**
+ * Sets how many remote videos are currently in the filmstrip.
+ *
+ * @param {number} remoteVideosCount - The number of remote videos.
+ * @returns {{
+ * type: SET_FILMSTRIP_REMOTE_VIDEOS_COUNT,
+ * remoteVideosCount: number
+ * }}
+ */
+export function setFilmstripRemoteVideosCount(remoteVideosCount) {
+ return {
+ type: SET_FILMSTRIP_REMOTE_VIDEOS_COUNT,
+ remoteVideosCount
+ };
+}
+
+/**
+ * Sets if the entire filmstrip should be visible.
+ *
+ * @param {boolean} visible - Whether not the filmstrip is visible.
+ * @returns {{
+ * type: SET_FILMSTRIP_VISIBILITY,
+ * visible: boolean
+ * }}
+ */
+export function setFilmstripVisibility(visible) {
+ return {
+ type: SET_FILMSTRIP_VISIBILITY,
+ visible
+ };
+}
diff --git a/react/features/filmstrip/components/Filmstrip.js b/react/features/filmstrip/components/Filmstrip.native.js
similarity index 100%
rename from react/features/filmstrip/components/Filmstrip.js
rename to react/features/filmstrip/components/Filmstrip.native.js
diff --git a/react/features/filmstrip/components/Filmstrip.web.js b/react/features/filmstrip/components/Filmstrip.web.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/react/features/filmstrip/index.js b/react/features/filmstrip/index.js
index 07635cbbc..a29aa08e0 100644
--- a/react/features/filmstrip/index.js
+++ b/react/features/filmstrip/index.js
@@ -1 +1,6 @@
+export * from './actions';
+export * from './actionTypes';
export * from './components';
+
+import './middleware';
+import './reducer';
diff --git a/react/features/filmstrip/middleware.js b/react/features/filmstrip/middleware.js
new file mode 100644
index 000000000..560e5c8aa
--- /dev/null
+++ b/react/features/filmstrip/middleware.js
@@ -0,0 +1,30 @@
+import UIEvents from '../../../service/UI/UIEvents';
+
+import { MiddlewareRegistry } from '../base/redux';
+
+import {
+ SET_FILMSTRIP_REMOTE_VIDEOS_COUNT,
+ SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY,
+ SET_FILMSTRIP_VISIBILITY
+} from './actionTypes';
+
+declare var APP: Object;
+
+// eslint-disable-next-line no-unused-vars
+MiddlewareRegistry.register(store => next => action => {
+ const result = next(action);
+
+ switch (action.type) {
+ case SET_FILMSTRIP_REMOTE_VIDEOS_COUNT:
+ case SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY:
+ case SET_FILMSTRIP_VISIBILITY: {
+ if (typeof APP !== 'undefined') {
+ APP.UI.emitEvent(UIEvents.UPDATED_FILMSTRIP_DISPLAY);
+
+ }
+ break;
+ }
+ }
+
+ return result;
+});
diff --git a/react/features/filmstrip/reducer.js b/react/features/filmstrip/reducer.js
new file mode 100644
index 000000000..ae63692af
--- /dev/null
+++ b/react/features/filmstrip/reducer.js
@@ -0,0 +1,36 @@
+import { ReducerRegistry } from '../base/redux';
+import {
+ SET_FILMSTRIP_REMOTE_VIDEOS_COUNT,
+ SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY,
+ SET_FILMSTRIP_VISIBILITY
+} from './actionTypes';
+
+const DEFAULT_STATE = {
+ remoteVideosCount: 0,
+ remoteVideosVisible: true,
+ visible: true
+};
+
+ReducerRegistry.register(
+ 'features/filmstrip',
+ (state = DEFAULT_STATE, action) => {
+ switch (action.type) {
+ case SET_FILMSTRIP_REMOTE_VIDEOS_COUNT:
+ return {
+ ...state,
+ remoteVideosCount: action.remoteVideosCount
+ };
+ case SET_FILMSTRIP_REMOTE_VIDEOS_VISIBLITY:
+ return {
+ ...state,
+ remoteVideosVisible: action.remoteVideosVisible
+ };
+ case SET_FILMSTRIP_VISIBILITY:
+ return {
+ ...state,
+ visible: action.visible
+ };
+ }
+
+ return state;
+ });
diff --git a/react/features/video-status-label/components/VideoStatusLabel.js b/react/features/video-status-label/components/VideoStatusLabel.js
index cc4370bce..6fd6a8e86 100644
--- a/react/features/video-status-label/components/VideoStatusLabel.js
+++ b/react/features/video-status-label/components/VideoStatusLabel.js
@@ -28,6 +28,11 @@ export class VideoStatusLabel extends Component {
*/
_conferenceStarted: React.PropTypes.bool,
+ /**
+ * Whether or not the filmstrip is displayed with remote videos.
+ */
+ _filmstripVisible: React.PropTypes.bool,
+
/**
* Whether or not a high-definition large video is displayed.
*/
@@ -64,7 +69,13 @@ export class VideoStatusLabel extends Component {
* @returns {ReactElement}
*/
render() {
- const { _audioOnly, _conferenceStarted, _largeVideoHD, t } = this.props;
+ const {
+ _audioOnly,
+ _conferenceStarted,
+ _filmstripVisible,
+ _largeVideoHD,
+ t
+ } = this.props;
// FIXME The _conferenceStarted check is used to be defensive against
// toggling audio only mode while there is no conference and hides the
@@ -82,9 +93,14 @@ export class VideoStatusLabel extends Component {
? t('videoStatus.hd') : t('videoStatus.sd');
}
+ const filmstripClassName
+ = _filmstripVisible ? 'with-filmstrip' : 'without-filmstrip';
+ const classNames
+ = `video-state-indicator moveToCorner ${filmstripClassName}`;
+
return (
{ displayedLabel }
{ this._renderVideonMenu() }
@@ -152,10 +168,17 @@ function _mapStateToProps(state) {
conference,
isLargeVideoHD
} = state['features/base/conference'];
+ const {
+ remoteVideosCount,
+ remoteVideosVisible,
+ visible
+ } = state['features/filmstrip'];
return {
_audioOnly: audioOnly,
_conferenceStarted: Boolean(conference),
+ _filmstripVisible:
+ Boolean(remoteVideosCount && remoteVideosVisible && visible),
_largeVideoHD: isLargeVideoHD
};
}
diff --git a/service/UI/UIEvents.js b/service/UI/UIEvents.js
index 6674e6800..d4d445120 100644
--- a/service/UI/UIEvents.js
+++ b/service/UI/UIEvents.js
@@ -65,6 +65,12 @@ export default {
* @see {TOGGLE_FILMSTRIP}
*/
TOGGLED_FILMSTRIP: "UI.toggled_filmstrip",
+
+ /**
+ * Notifies that the filmstrip has updated its appearance, such as by
+ * toggling or removing videos or adding videos.
+ */
+ UPDATED_FILMSTRIP_DISPLAY: "UI.updated_filmstrip_display",
TOGGLE_SCREENSHARING: "UI.toggle_screensharing",
TOGGLED_SHARED_DOCUMENT: "UI.toggled_shared_document",
CONTACT_CLICKED: "UI.contact_clicked",