Browse Source

[RN] Room lock button

master
Lyubomir Marinov 8 years ago
parent
commit
9a49a01713

+ 12
- 0
react/features/base/conference/actionTypes.js View File

@@ -45,6 +45,18 @@ export const CONFERENCE_LEFT = Symbol('CONFERENCE_LEFT');
45 45
  */
46 46
 export const CONFERENCE_WILL_LEAVE = Symbol('CONFERENCE_WILL_LEAVE');
47 47
 
48
+/**
49
+ * The type of the Redux action which signals that the lock state of a specific
50
+ * <tt>JitsiConference</tt> changed.
51
+ *
52
+ * {
53
+ *     type: LOCK_STATE_CHANGED,
54
+ *     conference: JitsiConference,
55
+ *     locked: boolean
56
+ * }
57
+ */
58
+export const LOCK_STATE_CHANGED = Symbol('LOCK_STATE_CHANGED');
59
+
48 60
 /**
49 61
  * The type of the Redux action which sets the password to join or lock a
50 62
  * specific JitsiConference.

+ 26
- 0
react/features/base/conference/actions.js View File

@@ -13,6 +13,7 @@ import {
13 13
     CONFERENCE_JOINED,
14 14
     CONFERENCE_LEFT,
15 15
     CONFERENCE_WILL_LEAVE,
16
+    LOCK_STATE_CHANGED,
16 17
     SET_PASSWORD,
17 18
     SET_ROOM
18 19
 } from './actionTypes';
@@ -46,6 +47,10 @@ function _addConferenceListeners(conference, dispatch) {
46 47
             JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED,
47 48
             (...args) => dispatch(dominantSpeakerChanged(...args)));
48 49
 
50
+    conference.on(
51
+            JitsiConferenceEvents.LOCK_STATE_CHANGED,
52
+            (...args) => dispatch(_lockStateChanged(conference, ...args)));
53
+
49 54
     conference.on(
50 55
             JitsiConferenceEvents.TRACK_ADDED,
51 56
             t => t && !t.isLocal() && dispatch(trackAdded(t)));
@@ -185,6 +190,27 @@ export function createConference() {
185 190
     };
186 191
 }
187 192
 
193
+/**
194
+ * Signals that the lock state of a specific JitsiConference changed.
195
+ *
196
+ * @param {JitsiConference} conference - The JitsiConference which had its lock
197
+ * state changed.
198
+ * @param {boolean} locked - If the specified conference became locked, true;
199
+ * otherwise, false.
200
+ * @returns {{
201
+ *     type: LOCK_STATE_CHANGED,
202
+ *     conference: JitsiConference,
203
+ *     locked: boolean
204
+ * }}
205
+ */
206
+function _lockStateChanged(conference, locked) {
207
+    return {
208
+        type: LOCK_STATE_CHANGED,
209
+        conference,
210
+        locked
211
+    };
212
+}
213
+
188 214
 /**
189 215
  * Sets the password to join or lock a specific JitsiConference.
190 216
  *

+ 40
- 1
react/features/base/conference/reducer.js View File

@@ -10,6 +10,7 @@ import {
10 10
     CONFERENCE_JOINED,
11 11
     CONFERENCE_LEFT,
12 12
     CONFERENCE_WILL_LEAVE,
13
+    LOCK_STATE_CHANGED,
13 14
     SET_PASSWORD,
14 15
     SET_ROOM
15 16
 } from './actionTypes';
@@ -33,6 +34,9 @@ ReducerRegistry.register('features/base/conference', (state = {}, action) => {
33 34
     case CONFERENCE_WILL_LEAVE:
34 35
         return _conferenceWillLeave(state, action);
35 36
 
37
+    case LOCK_STATE_CHANGED:
38
+        return _lockStateChanged(state, action);
39
+
36 40
     case SET_PASSWORD:
37 41
         return _setPassword(state, action);
38 42
 
@@ -70,6 +74,7 @@ function _conferenceFailed(state, action) {
70 74
         setStateProperties(state, {
71 75
             conference: undefined,
72 76
             leaving: undefined,
77
+            locked: undefined,
73 78
             password: undefined,
74 79
 
75 80
             /**
@@ -92,6 +97,14 @@ function _conferenceFailed(state, action) {
92 97
  * reduction of the specified action.
93 98
  */
94 99
 function _conferenceJoined(state, action) {
100
+    const conference = action.conference;
101
+
102
+    // FIXME The indicator which determines whether a JitsiConference is locked
103
+    // i.e. password-protected is private to lib-jitsi-meet. However, the
104
+    // library does not fire LOCK_STATE_CHANGED upon joining a JitsiConference
105
+    // with a password.
106
+    const locked = conference.room.locked || undefined;
107
+
95 108
     return (
96 109
         setStateProperties(state, {
97 110
             /**
@@ -100,8 +113,15 @@ function _conferenceJoined(state, action) {
100 113
              *
101 114
              * @type {JitsiConference}
102 115
              */
103
-            conference: action.conference,
116
+            conference,
104 117
             leaving: undefined,
118
+
119
+            /**
120
+             * The indicator which determines whether the conference is locked.
121
+             *
122
+             * @type {boolean}
123
+             */
124
+            locked,
105 125
             passwordRequired: undefined
106 126
         }));
107 127
 }
@@ -127,6 +147,7 @@ function _conferenceLeft(state, action) {
127 147
         setStateProperties(state, {
128 148
             conference: undefined,
129 149
             leaving: undefined,
150
+            locked: undefined,
130 151
             password: undefined,
131 152
             passwordRequired: undefined
132 153
         }));
@@ -162,6 +183,24 @@ function _conferenceWillLeave(state, action) {
162 183
         }));
163 184
 }
164 185
 
186
+/**
187
+ * Reduces a specific Redux action LOCK_STATE_CHANGED of the feature
188
+ * base/conference.
189
+ *
190
+ * @param {Object} state - The Redux state of the feature base/conference.
191
+ * @param {Action} action - The Redux action LOCK_STATE_CHANGED to reduce.
192
+ * @private
193
+ * @returns {Object} The new state of the feature base/conference after the
194
+ * reduction of the specified action.
195
+ */
196
+function _lockStateChanged(state, action) {
197
+    if (state.conference !== action.conference) {
198
+        return state;
199
+    }
200
+
201
+    return setStateProperty(state, 'locked', action.locked || undefined);
202
+}
203
+
165 204
 /**
166 205
  * Reduces a specific Redux action SET_PASSWORD of the feature base/conference.
167 206
  *

+ 14
- 4
react/features/base/react/Symbol.js View File

@@ -1,14 +1,24 @@
1 1
 // FIXME React Native does not polyfill Symbol at versions 0.39.2 or earlier.
2 2
 export default (global => {
3
-    let s = global.Symbol;
3
+    let clazz = global.Symbol;
4 4
 
5
-    if (typeof s === 'undefined') {
5
+    if (typeof clazz === 'undefined') {
6 6
         // XXX At the time of this writing we use Symbol only as a way to
7 7
         // prevent collisions in Redux action types. Consequently, the Symbol
8 8
         // implementation provided bellow is minimal and specific to our
9 9
         // purpose.
10
-        s = description => (description || '').split('');
10
+        const toString = function() {
11
+            return this.join(''); // eslint-disable-line no-invalid-this
12
+        };
13
+
14
+        clazz = description => {
15
+            const thiz = (description || '').split('');
16
+
17
+            thiz.toString = toString;
18
+
19
+            return thiz;
20
+        };
11 21
     }
12 22
 
13
-    return s;
23
+    return clazz;
14 24
 })(global || window || this); // eslint-disable-line no-invalid-this

+ 39
- 16
react/features/toolbar/components/AbstractToolbar.js View File

@@ -1,10 +1,7 @@
1 1
 import React, { Component } from 'react';
2 2
 
3 3
 import { appNavigate } from '../../app';
4
-import {
5
-    toggleAudioMuted,
6
-    toggleVideoMuted
7
-} from '../../base/media';
4
+import { toggleAudioMuted, toggleVideoMuted } from '../../base/media';
8 5
 import { ColorPalette } from '../../base/styles';
9 6
 
10 7
 import { styles } from './styles';
@@ -23,6 +20,12 @@ export class AbstractToolbar extends Component {
23 20
     static propTypes = {
24 21
         audioMuted: React.PropTypes.bool,
25 22
         dispatch: React.PropTypes.func,
23
+
24
+        /**
25
+         * The indicator which determines whether the conference is
26
+         * locked/password-protected.
27
+         */
28
+        locked: React.PropTypes.bool,
26 29
         videoMuted: React.PropTypes.bool,
27 30
         visible: React.PropTypes.bool.isRequired
28 31
     }
@@ -39,6 +42,7 @@ export class AbstractToolbar extends Component {
39 42
         // Bind event handlers so they are only bound once for every instance.
40 43
         this._onHangup = this._onHangup.bind(this);
41 44
         this._toggleAudio = this._toggleAudio.bind(this);
45
+        this._toggleLock = this._toggleLock.bind(this);
42 46
         this._toggleVideo = this._toggleVideo.bind(this);
43 47
     }
44 48
 
@@ -50,33 +54,32 @@ export class AbstractToolbar extends Component {
50 54
      * button to get styles for.
51 55
      * @protected
52 56
      * @returns {{
53
-     *      buttonStyle: Object,
54 57
      *      iconName: string,
55
-     *      iconStyle: Object
58
+     *      iconStyle: Object,
59
+     *      style: Object
56 60
      * }}
57 61
      */
58 62
     _getMuteButtonStyles(mediaType) {
59
-        let buttonStyle;
60 63
         let iconName;
61 64
         let iconStyle;
65
+        let style = styles.primaryToolbarButton;
62 66
 
63 67
         if (this.props[`${mediaType}Muted`]) {
64
-            buttonStyle = {
65
-                ...styles.toolbarButton,
66
-                backgroundColor: ColorPalette.buttonUnderlay
67
-            };
68 68
             iconName = this[`${mediaType}MutedIcon`];
69 69
             iconStyle = styles.whiteIcon;
70
+            style = {
71
+                ...style,
72
+                backgroundColor: ColorPalette.buttonUnderlay
73
+            };
70 74
         } else {
71
-            buttonStyle = styles.toolbarButton;
72 75
             iconName = this[`${mediaType}Icon`];
73 76
             iconStyle = styles.icon;
74 77
         }
75 78
 
76 79
         return {
77
-            buttonStyle,
78 80
             iconName,
79
-            iconStyle
81
+            iconStyle,
82
+            style
80 83
         };
81 84
     }
82 85
 
@@ -96,7 +99,7 @@ export class AbstractToolbar extends Component {
96 99
     }
97 100
 
98 101
     /**
99
-     * Dispatches action to toggle the mute state of the audio/microphone.
102
+     * Dispatches an action to toggle the mute state of the audio/microphone.
100 103
      *
101 104
      * @protected
102 105
      * @returns {void}
@@ -106,7 +109,18 @@ export class AbstractToolbar extends Component {
106 109
     }
107 110
 
108 111
     /**
109
-     * Dispatches action to toggle the mute state of the video/camera.
112
+     * Dispatches an action to toggle the lock i.e. password protection of the
113
+     * conference.
114
+     *
115
+     * @protected
116
+     * @returns {void}
117
+     */
118
+    _toggleLock() {
119
+        // TODO Auto-generated method stub
120
+    }
121
+
122
+    /**
123
+     * Dispatches an action to toggle the mute state of the video/camera.
110 124
      *
111 125
      * @protected
112 126
      * @returns {void}
@@ -123,10 +137,19 @@ export class AbstractToolbar extends Component {
123 137
  * @returns {{ audioMuted: boolean, videoMuted: boolean }}
124 138
  */
125 139
 export function mapStateToProps(state) {
140
+    const conference = state['features/base/conference'];
126 141
     const media = state['features/base/media'];
127 142
 
128 143
     return {
129 144
         audioMuted: media.audio.muted,
145
+
146
+        /**
147
+         * The indicator which determines whether the conference is
148
+         * locked/password-protected.
149
+         *
150
+         * @type {boolean}
151
+         */
152
+        locked: conference.locked,
130 153
         videoMuted: media.video.muted
131 154
     };
132 155
 }

+ 20
- 8
react/features/toolbar/components/Toolbar.native.js View File

@@ -77,13 +77,13 @@ class Toolbar extends AbstractToolbar {
77 77
                     iconName = { audioButtonStyles.iconName }
78 78
                     iconStyle = { audioButtonStyles.iconStyle }
79 79
                     onClick = { this._toggleAudio }
80
-                    style = { audioButtonStyles.buttonStyle } />
80
+                    style = { audioButtonStyles.style } />
81 81
                 <ToolbarButton
82 82
                     iconName = 'hangup'
83 83
                     iconStyle = { styles.whiteIcon }
84 84
                     onClick = { this._onHangup }
85 85
                     style = {{
86
-                        ...styles.toolbarButton,
86
+                        ...styles.primaryToolbarButton,
87 87
                         backgroundColor: ColorPalette.red
88 88
                     }}
89 89
                     underlayColor = { ColorPalette.buttonUnderlay } />
@@ -91,7 +91,7 @@ class Toolbar extends AbstractToolbar {
91 91
                     iconName = { videoButtonStyles.iconName }
92 92
                     iconStyle = { videoButtonStyles.iconStyle }
93 93
                     onClick = { this._toggleVideo }
94
-                    style = { videoButtonStyles.buttonStyle } />
94
+                    style = { videoButtonStyles.style } />
95 95
             </View>
96 96
         );
97 97
 
@@ -106,21 +106,33 @@ class Toolbar extends AbstractToolbar {
106 106
      * @returns {ReactElement}
107 107
      */
108 108
     _renderSecondaryToolbar() {
109
-        /* eslint-disable react/jsx-handler-names */
109
+        const iconStyle = styles.whiteIcon;
110
+        const style = styles.secondaryToolbarButton;
111
+        const underlayColor = 'transparent';
112
+
113
+        /* eslint-disable react/jsx-curly-spacing,react/jsx-handler-names */
110 114
 
111 115
         // TODO Use an appropriate icon for toggle camera facing mode.
112 116
         return (
113 117
             <View style = { styles.secondaryToolbar }>
114 118
                 <ToolbarButton
115 119
                     iconName = 'reload'
116
-                    iconStyle = { styles.whiteIcon }
120
+                    iconStyle = { iconStyle }
117 121
                     onClick = { this._toggleCameraFacingMode }
118
-                    style = { styles.toggleCameraFacingModeButton }
119
-                    underlayColor = 'transparent' />
122
+                    style = { style }
123
+                    underlayColor = { underlayColor } />
124
+                <ToolbarButton
125
+                    iconName = {
126
+                        this.props.locked ? 'security-locked' : 'security'
127
+                    }
128
+                    iconStyle = { iconStyle }
129
+                    onClick = { this._toggleLock }
130
+                    style = { style }
131
+                    underlayColor = { underlayColor } />
120 132
             </View>
121 133
         );
122 134
 
123
-        /* eslint-enable react/jsx-handler-names */
135
+        /* eslint-enable react/jsx-curly-spacing,react/jsx-handler-names */
124 136
     }
125 137
 
126 138
     /**

+ 40
- 42
react/features/toolbar/components/styles.js View File

@@ -1,103 +1,101 @@
1
-import { ColorPalette, createStyleSheet } from '../../base/styles';
1
+import { BoxModel, ColorPalette, createStyleSheet } from '../../base/styles';
2 2
 
3 3
 /**
4
- * Generic styles for a button.
4
+ * The base style for (toolbar) buttons.
5 5
  *
6 6
  * @type {Object}
7 7
  */
8 8
 const button = {
9
-    alignSelf: 'center',
10 9
     borderRadius: 35,
11 10
     borderWidth: 0,
11
+    flex: 0,
12 12
     flexDirection: 'row',
13 13
     height: 60,
14 14
     justifyContent: 'center',
15
+    margin: BoxModel.margin,
15 16
     width: 60
16 17
 };
17 18
 
18 19
 /**
19
- * Generic container for buttons.
20
+ * The base style for icons.
20 21
  *
21 22
  * @type {Object}
22 23
  */
23
-const container = {
24
-    flex: 1,
25
-    flexDirection: 'row',
26
-    left: 0,
27
-    position: 'absolute',
28
-    right: 0
24
+const icon = {
25
+    alignSelf: 'center',
26
+    color: ColorPalette.darkGrey,
27
+    fontSize: 24
29 28
 };
30 29
 
31 30
 /**
32
- * Generic styles for an icon.
31
+ * The base style for toolbars.
33 32
  *
34 33
  * @type {Object}
35 34
  */
36
-const icon = {
37
-    alignSelf: 'center',
38
-    color: ColorPalette.darkGrey,
39
-    fontSize: 24
35
+const toolbar = {
36
+    flex: 1,
37
+    position: 'absolute'
40 38
 };
41 39
 
42 40
 /**
43 41
  * The (conference) toolbar related styles.
44
- * TODO Make styles more generic and reusable. Use ColorPalette for all colors.
45 42
  */
46 43
 export const styles = createStyleSheet({
47 44
     /**
48 45
      * The toolbar button icon style.
49 46
      */
50
-    icon: {
51
-        ...icon,
52
-        color: ColorPalette.darkGrey
53
-    },
47
+    icon,
54 48
 
55 49
     /**
56 50
      * The style of the toolbar which contains the primary buttons such as
57 51
      * hangup, audio and video mute.
58 52
      */
59 53
     primaryToolbar: {
60
-        ...container,
61
-        bottom: 30,
62
-        height: 60,
63
-        justifyContent: 'center'
54
+        ...toolbar,
55
+        bottom: 3 * BoxModel.margin,
56
+        flexDirection: 'row',
57
+        justifyContent: 'center',
58
+        left: 0,
59
+        right: 0
64 60
     },
65 61
 
66 62
     /**
67
-     * The style of the toolbar which contains the secondary buttons such as
68
-     * toggle camera facing mode.
63
+     * The style of button in primaryToolbar.
69 64
      */
70
-    secondaryToolbar: {
71
-        ...container,
72
-        height: 60,
73
-        justifyContent: 'flex-end'
65
+    primaryToolbarButton: {
66
+        ...button,
67
+        backgroundColor: ColorPalette.white,
68
+        opacity: 0.8
74 69
     },
75 70
 
76 71
     /**
77
-     * The toggle camera facing mode button style.
72
+     * The style of the toolbar which contains the secondary buttons such as
73
+     * toggle camera facing mode.
78 74
      */
79
-    toggleCameraFacingModeButton: {
80
-        ...button,
81
-        backgroundColor: 'transparent'
75
+    secondaryToolbar: {
76
+        ...toolbar,
77
+        bottom: 0,
78
+        flexDirection: 'column',
79
+        right: 0,
80
+        top: 0
82 81
     },
83 82
 
84 83
     /**
85
-     * The toolbar button style.
84
+     * The style of button in secondaryToolbar.
86 85
      */
87
-    toolbarButton: {
86
+    secondaryToolbarButton: {
88 87
         ...button,
89
-        backgroundColor: ColorPalette.white,
90
-        marginLeft: 20,
91
-        marginRight: 20,
92
-        opacity: 0.8
88
+        backgroundColor: 'transparent'
93 89
     },
94 90
 
95 91
     /**
96
-     * The toolbar container style.
92
+     * The style of the root/top-level Container of Toolbar.
97 93
      */
98 94
     toolbarContainer: {
99
-        ...container,
100 95
         bottom: 0,
96
+        left: 0,
97
+        position: 'absolute',
98
+        right: 0,
101 99
         top: 0
102 100
     },
103 101
 

Loading…
Cancel
Save