[RN] Room lock
This commit is contained in:
parent
38b9819b68
commit
80685395ed
|
@ -220,19 +220,57 @@ function _lockStateChanged(conference, locked) {
|
|||
* such as join or lock.
|
||||
* @param {string} password - The password with which the specified conference
|
||||
* is to be joined or locked.
|
||||
* @returns {{
|
||||
* type: SET_PASSWORD,
|
||||
* conference: JitsiConference,
|
||||
* method: Function,
|
||||
* password: string
|
||||
* }}
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function setPassword(conference, method, password) {
|
||||
return {
|
||||
return (dispatch, getState) => {
|
||||
switch (method) {
|
||||
case conference.join: {
|
||||
let state = getState()['features/base/conference'];
|
||||
|
||||
// Make sure that the action will set a password for a conference
|
||||
// that the application wants joined.
|
||||
if (state.passwordRequired === conference) {
|
||||
dispatch({
|
||||
type: SET_PASSWORD,
|
||||
conference,
|
||||
method,
|
||||
password
|
||||
});
|
||||
|
||||
// Join the conference with the newly-set password.
|
||||
|
||||
// Make sure that the action did set the password.
|
||||
state = getState()['features/base/conference'];
|
||||
if (state.password === password
|
||||
&& !state.passwordRequired
|
||||
|
||||
// Make sure that the application still wants the
|
||||
// conference joined.
|
||||
&& !state.conference) {
|
||||
method.call(conference, password);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case conference.lock: {
|
||||
const state = getState()['features/base/conference'];
|
||||
|
||||
if (state.conference === conference) {
|
||||
return (
|
||||
method.call(conference, password)
|
||||
.then(() => dispatch({
|
||||
type: SET_PASSWORD,
|
||||
conference,
|
||||
method,
|
||||
password
|
||||
})));
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import { MiddlewareRegistry } from '../redux';
|
|||
import { TRACK_ADDED, TRACK_REMOVED } from '../tracks';
|
||||
|
||||
import { createConference } from './actions';
|
||||
import { SET_PASSWORD } from './actionTypes';
|
||||
import {
|
||||
_addLocalTracksToConference,
|
||||
_handleParticipantError,
|
||||
|
@ -29,9 +28,6 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
case PIN_PARTICIPANT:
|
||||
return _pinParticipant(store, next, action);
|
||||
|
||||
case SET_PASSWORD:
|
||||
return _setPassword(store, next, action);
|
||||
|
||||
case TRACK_ADDED:
|
||||
case TRACK_REMOVED:
|
||||
return _trackAddedOrRemoved(store, next, action);
|
||||
|
@ -111,56 +107,6 @@ function _pinParticipant(store, next, action) {
|
|||
return next(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the feature base/conference that the action <tt>SET_PASSWORD</tt> is
|
||||
* being dispatched within a specific Redux store. Joins or locks a specific
|
||||
* <tt>JitsiConference</tt> with a specific password.
|
||||
*
|
||||
* @param {Store} store - The Redux store in which the specified action is being
|
||||
* dispatched.
|
||||
* @param {Dispatch} next - The Redux dispatch function to dispatch the
|
||||
* specified action to the specified store.
|
||||
* @param {Action} action - The Redux action <tt>SET_PASSWORD</tt> which is
|
||||
* being dispatched in the specified store.
|
||||
* @private
|
||||
* @returns {Object} The new state that is the result of the reduction of the
|
||||
* specified action.
|
||||
*/
|
||||
function _setPassword(store, next, action) {
|
||||
const { conference, method } = action;
|
||||
|
||||
switch (method) {
|
||||
case conference.join: {
|
||||
let state = store.getState()['features/base/conference'];
|
||||
|
||||
// Make sure that the action will set a password for a conference that
|
||||
// the application wants joined.
|
||||
if (state.passwordRequired === conference) {
|
||||
const result = next(action);
|
||||
|
||||
// Join the conference with the newly-set password.
|
||||
const password = action.password;
|
||||
|
||||
// Make sure that the action did set the password.
|
||||
state = store.getState()['features/base/conference'];
|
||||
if (state.password === password
|
||||
&& !state.passwordRequired
|
||||
|
||||
// Make sure that the application still wants the conference
|
||||
// joined.
|
||||
&& !state.conference) {
|
||||
method.call(conference, password);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return next(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes local tracks from state with local tracks in JitsiConference
|
||||
* instance.
|
||||
|
|
|
@ -5,6 +5,7 @@ import { connect, disconnect } from '../../base/connection';
|
|||
import { Container } from '../../base/react';
|
||||
import { FilmStrip } from '../../filmStrip';
|
||||
import { LargeVideo } from '../../largeVideo';
|
||||
import { RoomLockPrompt } from '../../room-lock';
|
||||
import { Toolbar } from '../../toolbar';
|
||||
|
||||
import PasswordRequiredPrompt from './PasswordRequiredPrompt';
|
||||
|
@ -33,6 +34,15 @@ class Conference extends Component {
|
|||
* @type {JitsiConference}
|
||||
*/
|
||||
_passwordRequired: React.PropTypes.object,
|
||||
|
||||
/**
|
||||
* The indicator which determines whether the user has requested to lock
|
||||
* the conference/room.
|
||||
*
|
||||
* @private
|
||||
* @type {JitsiConference}
|
||||
*/
|
||||
_roomLockRequested: React.PropTypes.object,
|
||||
dispatch: React.PropTypes.func
|
||||
}
|
||||
|
||||
|
@ -142,19 +152,50 @@ class Conference extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a prompt if a password is required to join the conference.
|
||||
*
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderPasswordRequiredPrompt() {
|
||||
const required = this.props._passwordRequired;
|
||||
|
||||
if (required) {
|
||||
return (
|
||||
<PasswordRequiredPrompt conference = { required } />
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a prompt if necessary such as when a password is required to join
|
||||
* the conference.
|
||||
* the conference or the user has requested to lock the conference/room.
|
||||
*
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderPrompt() {
|
||||
const passwordRequired = this.props._passwordRequired;
|
||||
|
||||
if (passwordRequired) {
|
||||
return (
|
||||
<PasswordRequiredPrompt conference = { passwordRequired } />
|
||||
this._renderPasswordRequiredPrompt()
|
||||
|| this._renderRoomLockPrompt()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a prompt if the user has requested to lock the conference/room.
|
||||
*
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderRoomLockPrompt() {
|
||||
const requested = this.props._roomLockRequested;
|
||||
|
||||
if (requested) {
|
||||
return (
|
||||
<RoomLockPrompt conference = { requested } />
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -179,7 +220,16 @@ function mapStateToProps(state) {
|
|||
* @private
|
||||
* @type {JitsiConference}
|
||||
*/
|
||||
_passwordRequired: state['features/base/conference'].passwordRequired
|
||||
_passwordRequired: state['features/base/conference'].passwordRequired,
|
||||
|
||||
/**
|
||||
* The indicator which determines whether the user has requested to lock
|
||||
* the conference/room.
|
||||
*
|
||||
* @private
|
||||
* @type {JitsiConference}
|
||||
*/
|
||||
_roomLockRequested: state['features/room-lock'].requested
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import { Symbol } from '../base/react';
|
||||
|
||||
/**
|
||||
* The type of Redux action which begins a (user) request to lock a specific
|
||||
* JitsiConference.
|
||||
*
|
||||
* {
|
||||
* type: BEGIN_ROOM_LOCK_REQUEST,
|
||||
* conference: JitsiConference
|
||||
* }
|
||||
*/
|
||||
export const BEGIN_ROOM_LOCK_REQUEST = Symbol('BEGIN_ROOM_LOCK_REQUEST');
|
||||
|
||||
/**
|
||||
* The type of Redux action which end a (user) request to lock a specific
|
||||
* JitsiConference.
|
||||
*
|
||||
* {
|
||||
* type: END_ROOM_LOCK_REQUEST,
|
||||
* conference: JitsiConference,
|
||||
* password: string
|
||||
* }
|
||||
*/
|
||||
export const END_ROOM_LOCK_REQUEST = Symbol('END_ROOM_LOCK_REQUEST');
|
|
@ -0,0 +1,56 @@
|
|||
import { setPassword } from '../base/conference';
|
||||
|
||||
import { BEGIN_ROOM_LOCK_REQUEST, END_ROOM_LOCK_REQUEST } from './actionTypes';
|
||||
import './reducer';
|
||||
|
||||
/**
|
||||
* Begins a (user) request to lock a specific conference/room.
|
||||
*
|
||||
* @param {JitsiConference|undefined} conference - The JitsiConference to lock
|
||||
* if specified or undefined if the current JitsiConference is to be locked.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function beginRoomLockRequest(conference) {
|
||||
return (dispatch, getState) => {
|
||||
if (typeof conference === 'undefined') {
|
||||
const state = getState();
|
||||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
conference = state['features/base/conference'].conference;
|
||||
}
|
||||
|
||||
if (conference) {
|
||||
dispatch({
|
||||
type: BEGIN_ROOM_LOCK_REQUEST,
|
||||
conference
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends a (user) request to lock a specific conference/room.
|
||||
*
|
||||
* @param {JitsiConference} conference - The JitsiConference to lock.
|
||||
* @param {string|undefined} password - The password with which the specified
|
||||
* conference is to be locked or undefined to cancel the (user) request to lock
|
||||
* the specified conference.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function endRoomLockRequest(conference, password) {
|
||||
return dispatch => {
|
||||
const setPassword_
|
||||
= password
|
||||
? dispatch(setPassword(conference, conference.lock, password))
|
||||
: Promise.resolve();
|
||||
const endRoomLockRequest_ = () => {
|
||||
dispatch({
|
||||
type: END_ROOM_LOCK_REQUEST,
|
||||
conference,
|
||||
password
|
||||
});
|
||||
};
|
||||
|
||||
setPassword_.then(endRoomLockRequest_, endRoomLockRequest_);
|
||||
};
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
import React, { Component } from 'react';
|
||||
import Prompt from 'react-native-prompt';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { endRoomLockRequest } from '../actions';
|
||||
|
||||
/**
|
||||
* Implements a React Component which prompts the user for a password to lock a
|
||||
* conference/room.
|
||||
*/
|
||||
class RoomLockPrompt extends Component {
|
||||
/**
|
||||
* RoomLockPrompt component's property types.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static propTypes = {
|
||||
/**
|
||||
* The JitsiConference which requires a password.
|
||||
*
|
||||
* @type {JitsiConference}
|
||||
*/
|
||||
conference: React.PropTypes.object,
|
||||
dispatch: React.PropTypes.func
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new RoomLockPrompt instance.
|
||||
*
|
||||
* @param {Object} props - The read-only properties with which the new
|
||||
* instance is to be initialized.
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
// Bind event handlers so they are only bound once for every instance.
|
||||
this._onCancel = this._onCancel.bind(this);
|
||||
this._onSubmit = this._onSubmit.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<Prompt
|
||||
onCancel = { this._onCancel }
|
||||
onSubmit = { this._onSubmit }
|
||||
placeholder = 'Password'
|
||||
title = 'Lock / Unlock room'
|
||||
visible = { true } />
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies this prompt that it has been dismissed by cancel.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onCancel() {
|
||||
// An undefined password is understood to cancel the request to lock the
|
||||
// conference/room.
|
||||
this._onSubmit(undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies this prompt that it has been dismissed by submitting a specific
|
||||
* value.
|
||||
*
|
||||
* @param {string} value - The submitted value.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onSubmit(value) {
|
||||
this.props.dispatch(endRoomLockRequest(this.props.conference, value));
|
||||
}
|
||||
}
|
||||
|
||||
export default connect()(RoomLockPrompt);
|
|
@ -0,0 +1 @@
|
|||
export { default as RoomLockPrompt } from './RoomLockPrompt';
|
|
@ -0,0 +1,2 @@
|
|||
export * from './actions';
|
||||
export * from './components';
|
|
@ -0,0 +1,33 @@
|
|||
import {
|
||||
CONFERENCE_FAILED,
|
||||
CONFERENCE_JOINED,
|
||||
CONFERENCE_LEFT
|
||||
} from '../base/conference';
|
||||
import { ReducerRegistry, setStateProperty } from '../base/redux';
|
||||
|
||||
import { BEGIN_ROOM_LOCK_REQUEST, END_ROOM_LOCK_REQUEST } from './actionTypes';
|
||||
|
||||
ReducerRegistry.register('features/room-lock', (state = {}, action) => {
|
||||
switch (action.type) {
|
||||
case BEGIN_ROOM_LOCK_REQUEST:
|
||||
return setStateProperty(state, 'requested', action.conference);
|
||||
|
||||
case CONFERENCE_FAILED:
|
||||
case CONFERENCE_LEFT:
|
||||
case END_ROOM_LOCK_REQUEST: {
|
||||
if (state.requested === action.conference) {
|
||||
return setStateProperty(state, 'requested', undefined);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CONFERENCE_JOINED: {
|
||||
if (state.requested !== action.conference) {
|
||||
return setStateProperty(state, 'requested', undefined);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
});
|
|
@ -3,6 +3,7 @@ import React, { Component } from 'react';
|
|||
import { appNavigate } from '../../app';
|
||||
import { toggleAudioMuted, toggleVideoMuted } from '../../base/media';
|
||||
import { ColorPalette } from '../../base/styles';
|
||||
import { beginRoomLockRequest } from '../../room-lock';
|
||||
|
||||
import { styles } from './styles';
|
||||
|
||||
|
@ -41,8 +42,8 @@ export class AbstractToolbar extends Component {
|
|||
|
||||
// Bind event handlers so they are only bound once for every instance.
|
||||
this._onHangup = this._onHangup.bind(this);
|
||||
this._onRoomLock = this._onRoomLock.bind(this);
|
||||
this._toggleAudio = this._toggleAudio.bind(this);
|
||||
this._toggleLock = this._toggleLock.bind(this);
|
||||
this._toggleVideo = this._toggleVideo.bind(this);
|
||||
}
|
||||
|
||||
|
@ -98,6 +99,17 @@ export class AbstractToolbar extends Component {
|
|||
this.props.dispatch(appNavigate(undefined));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an action to set the lock i.e. password protection of the
|
||||
* conference/room.
|
||||
*
|
||||
* @protected
|
||||
* @returns {void}
|
||||
*/
|
||||
_onRoomLock() {
|
||||
this.props.dispatch(beginRoomLockRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an action to toggle the mute state of the audio/microphone.
|
||||
*
|
||||
|
@ -108,17 +120,6 @@ export class AbstractToolbar extends Component {
|
|||
this.props.dispatch(toggleAudioMuted());
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an action to toggle the lock i.e. password protection of the
|
||||
* conference.
|
||||
*
|
||||
* @protected
|
||||
* @returns {void}
|
||||
*/
|
||||
_toggleLock() {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an action to toggle the mute state of the video/camera.
|
||||
*
|
||||
|
|
|
@ -126,7 +126,7 @@ class Toolbar extends AbstractToolbar {
|
|||
this.props.locked ? 'security-locked' : 'security'
|
||||
}
|
||||
iconStyle = { iconStyle }
|
||||
onClick = { this._toggleLock }
|
||||
onClick = { this._onRoomLock }
|
||||
style = { style }
|
||||
underlayColor = { underlayColor } />
|
||||
</View>
|
||||
|
|
Loading…
Reference in New Issue