瀏覽代碼

[RN] Room lock button

master
Lyubomir Marinov 8 年之前
父節點
當前提交
9a49a01713

+ 12
- 0
react/features/base/conference/actionTypes.js 查看文件

45
  */
45
  */
46
 export const CONFERENCE_WILL_LEAVE = Symbol('CONFERENCE_WILL_LEAVE');
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
  * The type of the Redux action which sets the password to join or lock a
61
  * The type of the Redux action which sets the password to join or lock a
50
  * specific JitsiConference.
62
  * specific JitsiConference.

+ 26
- 0
react/features/base/conference/actions.js 查看文件

13
     CONFERENCE_JOINED,
13
     CONFERENCE_JOINED,
14
     CONFERENCE_LEFT,
14
     CONFERENCE_LEFT,
15
     CONFERENCE_WILL_LEAVE,
15
     CONFERENCE_WILL_LEAVE,
16
+    LOCK_STATE_CHANGED,
16
     SET_PASSWORD,
17
     SET_PASSWORD,
17
     SET_ROOM
18
     SET_ROOM
18
 } from './actionTypes';
19
 } from './actionTypes';
46
             JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED,
47
             JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED,
47
             (...args) => dispatch(dominantSpeakerChanged(...args)));
48
             (...args) => dispatch(dominantSpeakerChanged(...args)));
48
 
49
 
50
+    conference.on(
51
+            JitsiConferenceEvents.LOCK_STATE_CHANGED,
52
+            (...args) => dispatch(_lockStateChanged(conference, ...args)));
53
+
49
     conference.on(
54
     conference.on(
50
             JitsiConferenceEvents.TRACK_ADDED,
55
             JitsiConferenceEvents.TRACK_ADDED,
51
             t => t && !t.isLocal() && dispatch(trackAdded(t)));
56
             t => t && !t.isLocal() && dispatch(trackAdded(t)));
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
  * Sets the password to join or lock a specific JitsiConference.
215
  * Sets the password to join or lock a specific JitsiConference.
190
  *
216
  *

+ 40
- 1
react/features/base/conference/reducer.js 查看文件

10
     CONFERENCE_JOINED,
10
     CONFERENCE_JOINED,
11
     CONFERENCE_LEFT,
11
     CONFERENCE_LEFT,
12
     CONFERENCE_WILL_LEAVE,
12
     CONFERENCE_WILL_LEAVE,
13
+    LOCK_STATE_CHANGED,
13
     SET_PASSWORD,
14
     SET_PASSWORD,
14
     SET_ROOM
15
     SET_ROOM
15
 } from './actionTypes';
16
 } from './actionTypes';
33
     case CONFERENCE_WILL_LEAVE:
34
     case CONFERENCE_WILL_LEAVE:
34
         return _conferenceWillLeave(state, action);
35
         return _conferenceWillLeave(state, action);
35
 
36
 
37
+    case LOCK_STATE_CHANGED:
38
+        return _lockStateChanged(state, action);
39
+
36
     case SET_PASSWORD:
40
     case SET_PASSWORD:
37
         return _setPassword(state, action);
41
         return _setPassword(state, action);
38
 
42
 
70
         setStateProperties(state, {
74
         setStateProperties(state, {
71
             conference: undefined,
75
             conference: undefined,
72
             leaving: undefined,
76
             leaving: undefined,
77
+            locked: undefined,
73
             password: undefined,
78
             password: undefined,
74
 
79
 
75
             /**
80
             /**
92
  * reduction of the specified action.
97
  * reduction of the specified action.
93
  */
98
  */
94
 function _conferenceJoined(state, action) {
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
     return (
108
     return (
96
         setStateProperties(state, {
109
         setStateProperties(state, {
97
             /**
110
             /**
100
              *
113
              *
101
              * @type {JitsiConference}
114
              * @type {JitsiConference}
102
              */
115
              */
103
-            conference: action.conference,
116
+            conference,
104
             leaving: undefined,
117
             leaving: undefined,
118
+
119
+            /**
120
+             * The indicator which determines whether the conference is locked.
121
+             *
122
+             * @type {boolean}
123
+             */
124
+            locked,
105
             passwordRequired: undefined
125
             passwordRequired: undefined
106
         }));
126
         }));
107
 }
127
 }
127
         setStateProperties(state, {
147
         setStateProperties(state, {
128
             conference: undefined,
148
             conference: undefined,
129
             leaving: undefined,
149
             leaving: undefined,
150
+            locked: undefined,
130
             password: undefined,
151
             password: undefined,
131
             passwordRequired: undefined
152
             passwordRequired: undefined
132
         }));
153
         }));
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
  * Reduces a specific Redux action SET_PASSWORD of the feature base/conference.
205
  * Reduces a specific Redux action SET_PASSWORD of the feature base/conference.
167
  *
206
  *

+ 14
- 4
react/features/base/react/Symbol.js 查看文件

1
 // FIXME React Native does not polyfill Symbol at versions 0.39.2 or earlier.
1
 // FIXME React Native does not polyfill Symbol at versions 0.39.2 or earlier.
2
 export default (global => {
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
         // XXX At the time of this writing we use Symbol only as a way to
6
         // XXX At the time of this writing we use Symbol only as a way to
7
         // prevent collisions in Redux action types. Consequently, the Symbol
7
         // prevent collisions in Redux action types. Consequently, the Symbol
8
         // implementation provided bellow is minimal and specific to our
8
         // implementation provided bellow is minimal and specific to our
9
         // purpose.
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
 })(global || window || this); // eslint-disable-line no-invalid-this
24
 })(global || window || this); // eslint-disable-line no-invalid-this

+ 39
- 16
react/features/toolbar/components/AbstractToolbar.js 查看文件

1
 import React, { Component } from 'react';
1
 import React, { Component } from 'react';
2
 
2
 
3
 import { appNavigate } from '../../app';
3
 import { appNavigate } from '../../app';
4
-import {
5
-    toggleAudioMuted,
6
-    toggleVideoMuted
7
-} from '../../base/media';
4
+import { toggleAudioMuted, toggleVideoMuted } from '../../base/media';
8
 import { ColorPalette } from '../../base/styles';
5
 import { ColorPalette } from '../../base/styles';
9
 
6
 
10
 import { styles } from './styles';
7
 import { styles } from './styles';
23
     static propTypes = {
20
     static propTypes = {
24
         audioMuted: React.PropTypes.bool,
21
         audioMuted: React.PropTypes.bool,
25
         dispatch: React.PropTypes.func,
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
         videoMuted: React.PropTypes.bool,
29
         videoMuted: React.PropTypes.bool,
27
         visible: React.PropTypes.bool.isRequired
30
         visible: React.PropTypes.bool.isRequired
28
     }
31
     }
39
         // Bind event handlers so they are only bound once for every instance.
42
         // Bind event handlers so they are only bound once for every instance.
40
         this._onHangup = this._onHangup.bind(this);
43
         this._onHangup = this._onHangup.bind(this);
41
         this._toggleAudio = this._toggleAudio.bind(this);
44
         this._toggleAudio = this._toggleAudio.bind(this);
45
+        this._toggleLock = this._toggleLock.bind(this);
42
         this._toggleVideo = this._toggleVideo.bind(this);
46
         this._toggleVideo = this._toggleVideo.bind(this);
43
     }
47
     }
44
 
48
 
50
      * button to get styles for.
54
      * button to get styles for.
51
      * @protected
55
      * @protected
52
      * @returns {{
56
      * @returns {{
53
-     *      buttonStyle: Object,
54
      *      iconName: string,
57
      *      iconName: string,
55
-     *      iconStyle: Object
58
+     *      iconStyle: Object,
59
+     *      style: Object
56
      * }}
60
      * }}
57
      */
61
      */
58
     _getMuteButtonStyles(mediaType) {
62
     _getMuteButtonStyles(mediaType) {
59
-        let buttonStyle;
60
         let iconName;
63
         let iconName;
61
         let iconStyle;
64
         let iconStyle;
65
+        let style = styles.primaryToolbarButton;
62
 
66
 
63
         if (this.props[`${mediaType}Muted`]) {
67
         if (this.props[`${mediaType}Muted`]) {
64
-            buttonStyle = {
65
-                ...styles.toolbarButton,
66
-                backgroundColor: ColorPalette.buttonUnderlay
67
-            };
68
             iconName = this[`${mediaType}MutedIcon`];
68
             iconName = this[`${mediaType}MutedIcon`];
69
             iconStyle = styles.whiteIcon;
69
             iconStyle = styles.whiteIcon;
70
+            style = {
71
+                ...style,
72
+                backgroundColor: ColorPalette.buttonUnderlay
73
+            };
70
         } else {
74
         } else {
71
-            buttonStyle = styles.toolbarButton;
72
             iconName = this[`${mediaType}Icon`];
75
             iconName = this[`${mediaType}Icon`];
73
             iconStyle = styles.icon;
76
             iconStyle = styles.icon;
74
         }
77
         }
75
 
78
 
76
         return {
79
         return {
77
-            buttonStyle,
78
             iconName,
80
             iconName,
79
-            iconStyle
81
+            iconStyle,
82
+            style
80
         };
83
         };
81
     }
84
     }
82
 
85
 
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
      * @protected
104
      * @protected
102
      * @returns {void}
105
      * @returns {void}
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
      * @protected
125
      * @protected
112
      * @returns {void}
126
      * @returns {void}
123
  * @returns {{ audioMuted: boolean, videoMuted: boolean }}
137
  * @returns {{ audioMuted: boolean, videoMuted: boolean }}
124
  */
138
  */
125
 export function mapStateToProps(state) {
139
 export function mapStateToProps(state) {
140
+    const conference = state['features/base/conference'];
126
     const media = state['features/base/media'];
141
     const media = state['features/base/media'];
127
 
142
 
128
     return {
143
     return {
129
         audioMuted: media.audio.muted,
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
         videoMuted: media.video.muted
153
         videoMuted: media.video.muted
131
     };
154
     };
132
 }
155
 }

+ 20
- 8
react/features/toolbar/components/Toolbar.native.js 查看文件

77
                     iconName = { audioButtonStyles.iconName }
77
                     iconName = { audioButtonStyles.iconName }
78
                     iconStyle = { audioButtonStyles.iconStyle }
78
                     iconStyle = { audioButtonStyles.iconStyle }
79
                     onClick = { this._toggleAudio }
79
                     onClick = { this._toggleAudio }
80
-                    style = { audioButtonStyles.buttonStyle } />
80
+                    style = { audioButtonStyles.style } />
81
                 <ToolbarButton
81
                 <ToolbarButton
82
                     iconName = 'hangup'
82
                     iconName = 'hangup'
83
                     iconStyle = { styles.whiteIcon }
83
                     iconStyle = { styles.whiteIcon }
84
                     onClick = { this._onHangup }
84
                     onClick = { this._onHangup }
85
                     style = {{
85
                     style = {{
86
-                        ...styles.toolbarButton,
86
+                        ...styles.primaryToolbarButton,
87
                         backgroundColor: ColorPalette.red
87
                         backgroundColor: ColorPalette.red
88
                     }}
88
                     }}
89
                     underlayColor = { ColorPalette.buttonUnderlay } />
89
                     underlayColor = { ColorPalette.buttonUnderlay } />
91
                     iconName = { videoButtonStyles.iconName }
91
                     iconName = { videoButtonStyles.iconName }
92
                     iconStyle = { videoButtonStyles.iconStyle }
92
                     iconStyle = { videoButtonStyles.iconStyle }
93
                     onClick = { this._toggleVideo }
93
                     onClick = { this._toggleVideo }
94
-                    style = { videoButtonStyles.buttonStyle } />
94
+                    style = { videoButtonStyles.style } />
95
             </View>
95
             </View>
96
         );
96
         );
97
 
97
 
106
      * @returns {ReactElement}
106
      * @returns {ReactElement}
107
      */
107
      */
108
     _renderSecondaryToolbar() {
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
         // TODO Use an appropriate icon for toggle camera facing mode.
115
         // TODO Use an appropriate icon for toggle camera facing mode.
112
         return (
116
         return (
113
             <View style = { styles.secondaryToolbar }>
117
             <View style = { styles.secondaryToolbar }>
114
                 <ToolbarButton
118
                 <ToolbarButton
115
                     iconName = 'reload'
119
                     iconName = 'reload'
116
-                    iconStyle = { styles.whiteIcon }
120
+                    iconStyle = { iconStyle }
117
                     onClick = { this._toggleCameraFacingMode }
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
             </View>
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 查看文件

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
  * @type {Object}
6
  * @type {Object}
7
  */
7
  */
8
 const button = {
8
 const button = {
9
-    alignSelf: 'center',
10
     borderRadius: 35,
9
     borderRadius: 35,
11
     borderWidth: 0,
10
     borderWidth: 0,
11
+    flex: 0,
12
     flexDirection: 'row',
12
     flexDirection: 'row',
13
     height: 60,
13
     height: 60,
14
     justifyContent: 'center',
14
     justifyContent: 'center',
15
+    margin: BoxModel.margin,
15
     width: 60
16
     width: 60
16
 };
17
 };
17
 
18
 
18
 /**
19
 /**
19
- * Generic container for buttons.
20
+ * The base style for icons.
20
  *
21
  *
21
  * @type {Object}
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
  * @type {Object}
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
  * The (conference) toolbar related styles.
41
  * The (conference) toolbar related styles.
44
- * TODO Make styles more generic and reusable. Use ColorPalette for all colors.
45
  */
42
  */
46
 export const styles = createStyleSheet({
43
 export const styles = createStyleSheet({
47
     /**
44
     /**
48
      * The toolbar button icon style.
45
      * The toolbar button icon style.
49
      */
46
      */
50
-    icon: {
51
-        ...icon,
52
-        color: ColorPalette.darkGrey
53
-    },
47
+    icon,
54
 
48
 
55
     /**
49
     /**
56
      * The style of the toolbar which contains the primary buttons such as
50
      * The style of the toolbar which contains the primary buttons such as
57
      * hangup, audio and video mute.
51
      * hangup, audio and video mute.
58
      */
52
      */
59
     primaryToolbar: {
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
         ...button,
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
     toolbarContainer: {
94
     toolbarContainer: {
99
-        ...container,
100
         bottom: 0,
95
         bottom: 0,
96
+        left: 0,
97
+        position: 'absolute',
98
+        right: 0,
101
         top: 0
99
         top: 0
102
     },
100
     },
103
 
101
 

Loading…
取消
儲存