fix(vertical-filmstrip): move video status labels back to top right

The video status labels, which include recording and hd status,
have been moved back to the top left while in vertical filmstrip
mode. The following had to be done:
- Remove styling to move the labels to the bottom left
- For VideoStatusLabel, move filmstrip remote video count, toggle
  state, and 1:1 state into redux.
- Use middleware to emit out to the Recording label when the
  filmstrip changes.
- Create an empty Filmstrip file for web and identify the existing
  Filmstrip component as native.
This commit is contained in:
Leonard Kim 2017-05-23 11:58:07 -07:00
parent 2333249b05
commit 56b12bd969
14 changed files with 232 additions and 45 deletions

View File

@ -87,53 +87,21 @@
} }
} }
/**
* For video labels that display on the top right to adjust its position as
* the filmstrip itself or filmstrip remote videos appear and disappear.
*/
.video-state-indicator { .video-state-indicator {
bottom: 30px; transition: right 2s;
left: 30px;
right: auto;
top: auto;
/**
* Move the label to the bottom left of the screen
*/
&#videoResolutionLabel {
left: 60px;
z-index: $poweredByZ;
/**
* Open the menu above the label.
*/
.video-state-indicator-menu {
bottom: calc(100% - 15px);
left: -10px;
/**
* Create padding for mouse travel on hover.
*/
padding-bottom: 20px;
right: auto;
top: auto;
.video-state-indicator-menu-options {
margin: 0;
/**
* The menu arrow should point down
*/
&::after {
border-color: $popoverBg transparent transparent;
bottom: -10px;
left: 15px;
right: auto;
top: auto;
}
}
}
}
&.with-filmstrip {
&#recordingLabel { &#recordingLabel {
left: 110px; right: 200px;
z-index: $poweredByZ; }
&#videoResolutionLabel {
right: 150px;
}
} }
} }

View File

@ -201,6 +201,15 @@ function _showStopRecordingPrompt(recordingType) {
* position * position
*/ */
function moveToCorner(selector, move) { function moveToCorner(selector, move) {
const {
remoteVideosCount,
remoteVideosVisible,
visible
} = APP.store.getState()['features/filmstrip'];
selector.toggleClass(
'with-filmstrip',
Boolean(remoteVideosCount && remoteVideosVisible && visible));
let moveToCornerClass = "moveToCorner"; let moveToCornerClass = "moveToCorner";
let containsClass = selector.hasClass(moveToCornerClass); let containsClass = selector.hasClass(moveToCornerClass);
@ -295,6 +304,10 @@ var Recording = {
APP.UI.messageHandler.enableNotifications(false); APP.UI.messageHandler.enableNotifications(false);
APP.UI.messageHandler.enablePopups(false); APP.UI.messageHandler.enablePopups(false);
} }
this.eventEmitter.addListener(UIEvents.UPDATED_FILMSTRIP_DISPLAY, () =>{
this._updateStatusLabel();
});
}, },
/** /**

View File

@ -1,5 +1,10 @@
/* global $, APP, config, JitsiMeetJS, interfaceConfig */ /* global $, APP, config, JitsiMeetJS, interfaceConfig */
import {
setFilmstripRemoteVideosVisibility,
setFilmstripVisibility
} from '../../../react/features/filmstrip';
import UIEvents from "../../../service/UI/UIEvents"; import UIEvents from "../../../service/UI/UIEvents";
import UIUtil from "../util/UIUtil"; import UIUtil from "../util/UIUtil";
@ -43,6 +48,7 @@ const Filmstrip = {
return; return;
} }
APP.store.dispatch(setFilmstripRemoteVideosVisibility(shouldShow));
this.filmstripRemoteVideos.toggleClass('hide-videos', !shouldShow); this.filmstripRemoteVideos.toggleClass('hide-videos', !shouldShow);
}, },
@ -172,11 +178,14 @@ const Filmstrip = {
// Emit/fire UIEvents.TOGGLED_FILMSTRIP. // Emit/fire UIEvents.TOGGLED_FILMSTRIP.
const eventEmitter = this.eventEmitter; const eventEmitter = this.eventEmitter;
const isFilmstripVisible = this.isFilmstripVisible();
if (eventEmitter) { if (eventEmitter) {
eventEmitter.emit( eventEmitter.emit(
UIEvents.TOGGLED_FILMSTRIP, UIEvents.TOGGLED_FILMSTRIP,
this.isFilmstripVisible()); this.isFilmstripVisible());
} }
APP.store.dispatch(setFilmstripVisibility(isFilmstripVisible));
}, },
/** /**

View File

@ -1,6 +1,10 @@
/* global APP, $, interfaceConfig */ /* global APP, $, interfaceConfig */
const logger = require("jitsi-meet-logger").getLogger(__filename); const logger = require("jitsi-meet-logger").getLogger(__filename);
import {
setFilmstripRemoteVideosCount
} from '../../../react/features/filmstrip';
import Filmstrip from "./Filmstrip"; import Filmstrip from "./Filmstrip";
import UIEvents from "../../../service/UI/UIEvents"; import UIEvents from "../../../service/UI/UIEvents";
import UIUtil from "../util/UIUtil"; import UIUtil from "../util/UIUtil";
@ -550,6 +554,9 @@ var VideoLayout = {
if (onComplete && typeof onComplete === "function") if (onComplete && typeof onComplete === "function")
onComplete(); onComplete();
}); });
APP.store.dispatch(
setFilmstripRemoteVideosCount(this.getRemoteVideosCount()));
return { localVideo, remoteVideo }; return { localVideo, remoteVideo };
}, },

View File

@ -10,6 +10,7 @@ import { OverlayContainer } from '../../overlay';
import { Toolbox } from '../../toolbox'; import { Toolbox } from '../../toolbox';
import { HideNotificationBarStyle } from '../../unsupported-browser'; import { HideNotificationBarStyle } from '../../unsupported-browser';
import { VideoStatusLabel } from '../../video-status-label'; import { VideoStatusLabel } from '../../video-status-label';
import '../../filmstrip';
declare var $: Function; declare var $: Function;
declare var APP: Object; declare var APP: Object;

View File

@ -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');

View File

@ -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
};
}

View File

@ -1 +1,6 @@
export * from './actions';
export * from './actionTypes';
export * from './components'; export * from './components';
import './middleware';
import './reducer';

View File

@ -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;
});

View File

@ -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;
});

View File

@ -28,6 +28,11 @@ export class VideoStatusLabel extends Component {
*/ */
_conferenceStarted: React.PropTypes.bool, _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. * Whether or not a high-definition large video is displayed.
*/ */
@ -64,7 +69,13 @@ export class VideoStatusLabel extends Component {
* @returns {ReactElement} * @returns {ReactElement}
*/ */
render() { 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 // FIXME The _conferenceStarted check is used to be defensive against
// toggling audio only mode while there is no conference and hides the // 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'); ? t('videoStatus.hd') : t('videoStatus.sd');
} }
const filmstripClassName
= _filmstripVisible ? 'with-filmstrip' : 'without-filmstrip';
const classNames
= `video-state-indicator moveToCorner ${filmstripClassName}`;
return ( return (
<div <div
className = 'video-state-indicator moveToCorner' className = { classNames }
id = 'videoResolutionLabel' > id = 'videoResolutionLabel' >
{ displayedLabel } { displayedLabel }
{ this._renderVideonMenu() } { this._renderVideonMenu() }
@ -152,10 +168,17 @@ function _mapStateToProps(state) {
conference, conference,
isLargeVideoHD isLargeVideoHD
} = state['features/base/conference']; } = state['features/base/conference'];
const {
remoteVideosCount,
remoteVideosVisible,
visible
} = state['features/filmstrip'];
return { return {
_audioOnly: audioOnly, _audioOnly: audioOnly,
_conferenceStarted: Boolean(conference), _conferenceStarted: Boolean(conference),
_filmstripVisible:
Boolean(remoteVideosCount && remoteVideosVisible && visible),
_largeVideoHD: isLargeVideoHD _largeVideoHD: isLargeVideoHD
}; };
} }

View File

@ -65,6 +65,12 @@ export default {
* @see {TOGGLE_FILMSTRIP} * @see {TOGGLE_FILMSTRIP}
*/ */
TOGGLED_FILMSTRIP: "UI.toggled_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", TOGGLE_SCREENSHARING: "UI.toggle_screensharing",
TOGGLED_SHARED_DOCUMENT: "UI.toggled_shared_document", TOGGLED_SHARED_DOCUMENT: "UI.toggled_shared_document",
CONTACT_CLICKED: "UI.contact_clicked", CONTACT_CLICKED: "UI.contact_clicked",