浏览代码

Grow features/settings from features/app-settings and features/settings-menu

master
Lyubo Marinov 7 年前
父节点
当前提交
9f69c4d730
共有 55 个文件被更改,包括 647 次插入673 次删除
  1. 3
    3
      android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java
  2. 7
    8
      lang/main.json
  3. 5
    5
      modules/UI/side_pannels/settings/SettingsMenu.js
  4. 96
    97
      react/features/analytics/AnalyticsEvents.js
  5. 0
    19
      react/features/app-settings/actionTypes.js
  6. 0
    29
      react/features/app-settings/actions.js
  7. 0
    238
      react/features/app-settings/components/AppSettings.native.js
  8. 0
    0
      react/features/app-settings/components/AppSettings.web.js
  9. 0
    0
      react/features/app-settings/components/_.web.js
  10. 0
    1
      react/features/app-settings/components/index.js
  11. 0
    3
      react/features/app-settings/components/native/index.js
  12. 0
    33
      react/features/app-settings/components/styles.js
  13. 0
    31
      react/features/app-settings/reducer.js
  14. 10
    7
      react/features/base/conference/middleware.js
  15. 32
    4
      react/features/base/react/components/native/Header.js
  16. 25
    22
      react/features/base/react/components/native/SideBar.js
  17. 2
    3
      react/features/base/react/components/native/index.js
  18. 34
    2
      react/features/base/react/components/native/styles.js
  19. 0
    41
      react/features/base/styles/components/styles/PlatformElements.native.js
  20. 0
    0
      react/features/base/styles/components/styles/PlatformElements.web.js
  21. 0
    1
      react/features/base/styles/components/styles/index.js
  22. 0
    0
      react/features/settings-menu/components/DeviceSelectionButton.native.js
  23. 0
    0
      react/features/settings-menu/components/LanguageSelectDropdown.native.js
  24. 0
    0
      react/features/settings-menu/components/ModeratorCheckboxes.native.js
  25. 0
    0
      react/features/settings-menu/components/SettingsMenu.native.js
  26. 0
    1
      react/features/settings-menu/index.js
  27. 10
    0
      react/features/settings/actionTypes.js
  28. 20
    0
      react/features/settings/actions.js
  29. 23
    20
      react/features/settings/components/AbstractSettingsView.js
  30. 0
    0
      react/features/settings/components/_.native.js
  31. 1
    0
      react/features/settings/components/_.web.js
  32. 1
    0
      react/features/settings/components/index.js
  33. 2
    2
      react/features/settings/components/native/BackButton.js
  34. 8
    6
      react/features/settings/components/native/FormRow.js
  35. 0
    0
      react/features/settings/components/native/FormSectionHeader.js
  36. 251
    0
      react/features/settings/components/native/SettingsView.js
  37. 1
    0
      react/features/settings/components/native/index.js
  38. 1
    2
      react/features/settings/components/native/styles.js
  39. 2
    2
      react/features/settings/components/web/DeviceSelectionButton.js
  40. 1
    1
      react/features/settings/components/web/LanguageSelectDropdown.js
  41. 2
    2
      react/features/settings/components/web/ModeratorCheckboxes.js
  42. 5
    2
      react/features/settings/components/web/SettingsMenu.js
  43. 0
    0
      react/features/settings/components/web/index.js
  44. 2
    2
      react/features/settings/functions.js
  45. 2
    0
      react/features/settings/index.js
  46. 8
    9
      react/features/settings/middleware.js
  47. 17
    0
      react/features/settings/reducer.js
  48. 8
    2
      react/features/welcome/actionTypes.js
  49. 9
    8
      react/features/welcome/actions.js
  50. 4
    3
      react/features/welcome/components/SideBarItem.js
  51. 17
    23
      react/features/welcome/components/WelcomePage.native.js
  52. 11
    11
      react/features/welcome/components/WelcomePageSideBar.native.js
  53. 9
    9
      react/features/welcome/components/styles.js
  54. 3
    3
      react/features/welcome/index.js
  55. 15
    18
      react/features/welcome/reducer.js

+ 3
- 3
android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java 查看文件

33
 
33
 
34
 /**
34
 /**
35
  * Base Activity for applications integrating Jitsi Meet at a higher level. It
35
  * Base Activity for applications integrating Jitsi Meet at a higher level. It
36
- * contains all the required wiring between the {@code JKConferenceView} and
36
+ * contains all the required wiring between the {@code JitsiMeetView} and
37
  * the Activity lifecycle methods already implemented.
37
  * the Activity lifecycle methods already implemented.
38
  *
38
  *
39
- * In this activity we use a single {@code JKConferenceView} instance. This
39
+ * In this activity we use a single {@code JitsiMeetView} instance. This
40
  * instance gives us access to a view which displays the welcome page and the
40
  * instance gives us access to a view which displays the welcome page and the
41
  * conference itself. All lifetime methods associated with this Activity are
41
  * conference itself. All lifetime methods associated with this Activity are
42
  * hooked to the React Native subsystem via proxy calls through the
42
  * hooked to the React Native subsystem via proxy calls through the
43
- * {@code JKConferenceView} static methods.
43
+ * {@code JitsiMeetView} static methods.
44
  */
44
  */
45
 public class JitsiMeetActivity extends AppCompatActivity {
45
 public class JitsiMeetActivity extends AppCompatActivity {
46
     /**
46
     /**

+ 7
- 8
lang/main.json 查看文件

47
     },
47
     },
48
     "welcomepage":{
48
     "welcomepage":{
49
         "appDescription": "Go ahead, video chat with the whole team. In fact, invite everyone you know. __app__ is a fully encrypted, 100% open source video conferencing solution that you can use all day, every day, for free — with no account needed.",
49
         "appDescription": "Go ahead, video chat with the whole team. In fact, invite everyone you know. __app__ is a fully encrypted, 100% open source video conferencing solution that you can use all day, every day, for free — with no account needed.",
50
-        "audioOnlyLabel": "Voice",
50
+        "audioVideoSwitch": {
51
+            "audio": "Voice",
52
+            "video": "Video"
53
+        },
51
         "go": "GO",
54
         "go": "GO",
52
-        "hintText": "Enter a room name you want to join to, or simply create a new room name, eg. MeetingWithJohn",
53
         "join": "JOIN",
55
         "join": "JOIN",
54
         "privacy": "Privacy",
56
         "privacy": "Privacy",
55
         "roomname": "Enter room name",
57
         "roomname": "Enter room name",
58
+        "roomnameHint": "Enter the name or URL of the room you want to join. You may make a name up, just let the people you are meeting know it so that they enter the same name.",
56
         "sendFeedback": "Send feedback",
59
         "sendFeedback": "Send feedback",
57
         "terms": "Terms",
60
         "terms": "Terms",
58
-        "title": "More secure, more flexible, and completely free video conferencing",
59
-        "videoEnabledLabel": "Video"
61
+        "title": "More secure, more flexible, and completely free video conferencing"
60
     },
62
     },
61
     "startupoverlay": {
63
     "startupoverlay": {
62
         "policyText": " ",
64
         "policyText": " ",
503
         "title": "Call info",
505
         "title": "Call info",
504
         "tooltip": "Get access info about the meeting"
506
         "tooltip": "Get access info about the meeting"
505
     },
507
     },
506
-    "settingsScreen": {
508
+    "settingsView": {
507
         "alertOk": "OK",
509
         "alertOk": "OK",
508
         "alertTitle": "Warning",
510
         "alertTitle": "Warning",
509
         "alertURLText": "The entered server URL is invalid",
511
         "alertURLText": "The entered server URL is invalid",
515
         "serverURL": "Server URL",
517
         "serverURL": "Server URL",
516
         "startWithAudioMuted": "Start with audio muted",
518
         "startWithAudioMuted": "Start with audio muted",
517
         "startWithVideoMuted": "Start with video muted"
519
         "startWithVideoMuted": "Start with video muted"
518
-    },
519
-    "sideBar": {
520
-        "settings": "Settings"
521
     }
520
     }
522
 }
521
 }

+ 5
- 5
modules/UI/side_pannels/settings/SettingsMenu.js 查看文件

1
 /* global $, APP, interfaceConfig */
1
 /* global $, APP, interfaceConfig */
2
 
2
 
3
 /* eslint-disable no-unused-vars */
3
 /* eslint-disable no-unused-vars */
4
+
4
 import React from 'react';
5
 import React from 'react';
5
 import ReactDOM from 'react-dom';
6
 import ReactDOM from 'react-dom';
6
 import { I18nextProvider } from 'react-i18next';
7
 import { I18nextProvider } from 'react-i18next';
7
 import { Provider } from 'react-redux';
8
 import { Provider } from 'react-redux';
8
 
9
 
9
 import { i18next } from '../../../../react/features/base/i18n';
10
 import { i18next } from '../../../../react/features/base/i18n';
10
-import { SettingsMenu } from '../../../../react/features/settings-menu';
11
-/* eslint-enable no-unused-vars */
12
-
11
+import { SettingsMenu } from '../../../../react/features/settings';
13
 import UIUtil from '../../util/UIUtil';
12
 import UIUtil from '../../util/UIUtil';
14
 
13
 
14
+/* eslint-enable no-unused-vars */
15
+
15
 export default {
16
 export default {
16
     init() {
17
     init() {
17
         const settingsMenuContainer = document.createElement('div');
18
         const settingsMenuContainer = document.createElement('div');
31
         ReactDOM.render(
32
         ReactDOM.render(
32
             <Provider store = { APP.store }>
33
             <Provider store = { APP.store }>
33
                 <I18nextProvider i18n = { i18next }>
34
                 <I18nextProvider i18n = { i18next }>
34
-                    <SettingsMenu
35
-                        { ...props } />
35
+                    <SettingsMenu { ...props } />
36
                 </I18nextProvider>
36
                 </I18nextProvider>
37
             </Provider>,
37
             </Provider>,
38
             settingsMenuContainer
38
             settingsMenuContainer

+ 96
- 97
react/features/analytics/AnalyticsEvents.js 查看文件

76
  * @returns {Object} The event in a format suitable for sending via
76
  * @returns {Object} The event in a format suitable for sending via
77
  * sendAnalytics.
77
  * sendAnalytics.
78
  */
78
  */
79
-export const createApiEvent = function(action, attributes = {}) {
79
+export function createApiEvent(action, attributes = {}) {
80
     return {
80
     return {
81
         action,
81
         action,
82
         attributes,
82
         attributes,
83
         source: 'jitsi-meet-api'
83
         source: 'jitsi-meet-api'
84
     };
84
     };
85
-};
85
+}
86
 
86
 
87
 /**
87
 /**
88
  * Creates an event which indicates that the audio-only mode has been changed.
88
  * Creates an event which indicates that the audio-only mode has been changed.
91
  * @returns {Object} The event in a format suitable for sending via
91
  * @returns {Object} The event in a format suitable for sending via
92
  * sendAnalytics.
92
  * sendAnalytics.
93
  */
93
  */
94
-export const createAudioOnlyChangedEvent = function(enabled) {
94
+export function createAudioOnlyChangedEvent(enabled) {
95
     return {
95
     return {
96
         action: `audio.only.${enabled ? 'enabled' : 'disabled'}`
96
         action: `audio.only.${enabled ? 'enabled' : 'disabled'}`
97
     };
97
     };
98
-};
98
+}
99
 
99
 
100
 /**
100
 /**
101
  * Creates an event which indicates that a device was changed.
101
  * Creates an event which indicates that a device was changed.
106
  * @returns {Object} The event in a format suitable for sending via
106
  * @returns {Object} The event in a format suitable for sending via
107
  * sendAnalytics.
107
  * sendAnalytics.
108
  */
108
  */
109
-export const createDeviceChangedEvent = function(mediaType, deviceType) {
109
+export function createDeviceChangedEvent(mediaType, deviceType) {
110
     return {
110
     return {
111
         action: 'device.changed',
111
         action: 'device.changed',
112
         attributes: {
112
         attributes: {
114
             'media_type': mediaType
114
             'media_type': mediaType
115
         }
115
         }
116
     };
116
     };
117
-};
117
+}
118
 
118
 
119
 /**
119
 /**
120
  * Creates an event which specifies that the feedback dialog has been opened.
120
  * Creates an event which specifies that the feedback dialog has been opened.
122
  * @returns {Object} The event in a format suitable for sending via
122
  * @returns {Object} The event in a format suitable for sending via
123
  * sendAnalytics.
123
  * sendAnalytics.
124
  */
124
  */
125
-export const createFeedbackOpenEvent = function() {
125
+export function createFeedbackOpenEvent() {
126
     return {
126
     return {
127
         action: 'feedback.opened'
127
         action: 'feedback.opened'
128
     };
128
     };
129
-};
129
+}
130
 
130
 
131
 /**
131
 /**
132
  * Creates an event which indicates that the invite dialog was closed. This is
132
  * Creates an event which indicates that the invite dialog was closed. This is
136
  * @returns {Object} The event in a format suitable for sending via
136
  * @returns {Object} The event in a format suitable for sending via
137
  * sendAnalytics.
137
  * sendAnalytics.
138
  */
138
  */
139
-export const createInviteDialogClosedEvent = function() {
139
+export function createInviteDialogClosedEvent() {
140
     return {
140
     return {
141
         action: 'invite.dialog.closed'
141
         action: 'invite.dialog.closed'
142
     };
142
     };
143
-};
143
+}
144
 
144
 
145
 /**
145
 /**
146
  * Creates a "page reload" event.
146
  * Creates a "page reload" event.
152
  * @returns {Object} The event in a format suitable for sending via
152
  * @returns {Object} The event in a format suitable for sending via
153
  * sendAnalytics.
153
  * sendAnalytics.
154
  */
154
  */
155
-export const createPageReloadScheduledEvent
156
-    = function(reason, timeout, details) {
157
-        return {
158
-            action: 'page.reload.scheduled',
159
-            attributes: {
160
-                reason,
161
-                timeout,
162
-                ...details
163
-            }
164
-        };
155
+export function createPageReloadScheduledEvent(reason, timeout, details) {
156
+    return {
157
+        action: 'page.reload.scheduled',
158
+        attributes: {
159
+            reason,
160
+            timeout,
161
+            ...details
162
+        }
165
     };
163
     };
164
+}
166
 
165
 
167
 /**
166
 /**
168
  * Creates a "pinned" or "unpinned" event.
167
  * Creates a "pinned" or "unpinned" event.
173
  * @returns {Object} The event in a format suitable for sending via
172
  * @returns {Object} The event in a format suitable for sending via
174
  * sendAnalytics.
173
  * sendAnalytics.
175
  */
174
  */
176
-export const createPinnedEvent
177
-        = function(action, participantId, attributes) {
178
-            return {
179
-                type: TYPE_TRACK,
180
-                action,
181
-                actionSubject: 'participant',
182
-                objectType: 'participant',
183
-                objectId: participantId,
184
-                attributes
185
-            };
186
-        };
175
+export function createPinnedEvent(action, participantId, attributes) {
176
+    return {
177
+        type: TYPE_TRACK,
178
+        action,
179
+        actionSubject: 'participant',
180
+        objectType: 'participant',
181
+        objectId: participantId,
182
+        attributes
183
+    };
184
+}
187
 
185
 
188
 /**
186
 /**
189
  * Creates an event which indicates that a button in the profile panel was
187
  * Creates an event which indicates that a button in the profile panel was
194
  * @returns {Object} The event in a format suitable for sending via
192
  * @returns {Object} The event in a format suitable for sending via
195
  * sendAnalytics.
193
  * sendAnalytics.
196
  */
194
  */
197
-export const createProfilePanelButtonEvent
198
-    = function(buttonName, attributes = {}) {
199
-        return {
200
-            action: 'clicked',
201
-            actionSubject: buttonName,
202
-            attributes,
203
-            source: 'profile.panel',
204
-            type: TYPE_UI
205
-        };
195
+export function createProfilePanelButtonEvent(buttonName, attributes = {}) {
196
+    return {
197
+        action: 'clicked',
198
+        actionSubject: buttonName,
199
+        attributes,
200
+        source: 'profile.panel',
201
+        type: TYPE_UI
206
     };
202
     };
203
+}
207
 
204
 
208
 /**
205
 /**
209
  * Creates an event which indicates that a specific button on one of the
206
  * Creates an event which indicates that a specific button on one of the
215
  * @returns {Object} The event in a format suitable for sending via
212
  * @returns {Object} The event in a format suitable for sending via
216
  * sendAnalytics.
213
  * sendAnalytics.
217
  */
214
  */
218
-export const createRecordingDialogEvent = function(dialogName, buttonName) {
215
+export function createRecordingDialogEvent(dialogName, buttonName) {
219
     return {
216
     return {
220
         action: 'clicked',
217
         action: 'clicked',
221
         actionSubject: buttonName,
218
         actionSubject: buttonName,
222
         source: `${dialogName}.recording.dialog`,
219
         source: `${dialogName}.recording.dialog`,
223
         type: TYPE_UI
220
         type: TYPE_UI
224
     };
221
     };
225
-};
222
+}
226
 
223
 
227
 /**
224
 /**
228
  * Creates an event which specifies that the "confirm" button on the remote
225
  * Creates an event which specifies that the "confirm" button on the remote
233
  * @returns {Object} The event in a format suitable for sending via
230
  * @returns {Object} The event in a format suitable for sending via
234
  * sendAnalytics.
231
  * sendAnalytics.
235
  */
232
  */
236
-export const createRemoteMuteConfirmedEvent = function(participantId) {
233
+export function createRemoteMuteConfirmedEvent(participantId) {
237
     return {
234
     return {
238
         action: 'clicked',
235
         action: 'clicked',
239
         actionSubject: 'remote.mute.dialog.confirm.button',
236
         actionSubject: 'remote.mute.dialog.confirm.button',
243
         source: 'remote.mute.dialog',
240
         source: 'remote.mute.dialog',
244
         type: TYPE_UI
241
         type: TYPE_UI
245
     };
242
     };
246
-};
243
+}
247
 
244
 
248
 /**
245
 /**
249
  * Creates an event which indicates that one of the buttons in the "remote
246
  * Creates an event which indicates that one of the buttons in the "remote
254
  * @returns {Object} The event in a format suitable for sending via
251
  * @returns {Object} The event in a format suitable for sending via
255
  * sendAnalytics.
252
  * sendAnalytics.
256
  */
253
  */
257
-export const createRemoteVideoMenuButtonEvent
258
-    = function(buttonName, attributes) {
259
-        return {
260
-            action: 'clicked',
261
-            actionSubject: buttonName,
262
-            attributes,
263
-            source: 'remote.video.menu',
264
-            type: TYPE_UI
265
-        };
254
+export function createRemoteVideoMenuButtonEvent(buttonName, attributes) {
255
+    return {
256
+        action: 'clicked',
257
+        actionSubject: buttonName,
258
+        attributes,
259
+        source: 'remote.video.menu',
260
+        type: TYPE_UI
266
     };
261
     };
262
+}
267
 
263
 
268
 /**
264
 /**
269
  * Creates an event indicating that an action related to screen sharing
265
  * Creates an event indicating that an action related to screen sharing
273
  * @returns {Object} The event in a format suitable for sending via
269
  * @returns {Object} The event in a format suitable for sending via
274
  * sendAnalytics.
270
  * sendAnalytics.
275
  */
271
  */
276
-export const createScreenSharingEvent = function(action) {
272
+export function createScreenSharingEvent(action) {
277
     return {
273
     return {
278
         action,
274
         action,
279
         actionSubject: 'screen.sharing'
275
         actionSubject: 'screen.sharing'
280
     };
276
     };
281
-};
277
+}
282
 
278
 
283
 /**
279
 /**
284
  * The local participant failed to send a "selected endpoint" message to the
280
  * The local participant failed to send a "selected endpoint" message to the
288
  * @returns {Object} The event in a format suitable for sending via
284
  * @returns {Object} The event in a format suitable for sending via
289
  * sendAnalytics.
285
  * sendAnalytics.
290
  */
286
  */
291
-export const createSelectParticipantFailedEvent = function(error) {
287
+export function createSelectParticipantFailedEvent(error) {
292
     const event = {
288
     const event = {
293
         action: 'select.participant.failed'
289
         action: 'select.participant.failed'
294
     };
290
     };
298
     }
294
     }
299
 
295
 
300
     return event;
296
     return event;
301
-};
297
+}
302
 
298
 
303
 /**
299
 /**
304
  * Creates an event associated with the "shared video" feature.
300
  * Creates an event associated with the "shared video" feature.
308
  * @returns {Object} The event in a format suitable for sending via
304
  * @returns {Object} The event in a format suitable for sending via
309
  * sendAnalytics.
305
  * sendAnalytics.
310
  */
306
  */
311
-export const createSharedVideoEvent = function(action, attributes = {}) {
307
+export function createSharedVideoEvent(action, attributes = {}) {
312
     return {
308
     return {
313
         action,
309
         action,
314
         attributes,
310
         attributes,
315
         actionSubject: 'shared.video'
311
         actionSubject: 'shared.video'
316
     };
312
     };
317
-};
313
+}
318
 
314
 
319
 /**
315
 /**
320
  * Creates an event associated with a shortcut being pressed, released or
316
  * Creates an event associated with a shortcut being pressed, released or
331
  * @returns {Object} The event in a format suitable for sending via
327
  * @returns {Object} The event in a format suitable for sending via
332
  * sendAnalytics.
328
  * sendAnalytics.
333
  */
329
  */
334
-export const createShortcutEvent
335
-    = function(shortcut, action = ACTION_SHORTCUT_TRIGGERED, attributes = {}) {
336
-        return {
337
-            action,
338
-            actionSubject: 'keyboard.shortcut',
339
-            actionSubjectId: shortcut,
340
-            attributes,
341
-            source: 'keyboard.shortcut',
342
-            type: TYPE_UI
343
-        };
330
+export function createShortcutEvent(
331
+        shortcut,
332
+        action = ACTION_SHORTCUT_TRIGGERED,
333
+        attributes = {}) {
334
+    return {
335
+        action,
336
+        actionSubject: 'keyboard.shortcut',
337
+        actionSubjectId: shortcut,
338
+        attributes,
339
+        source: 'keyboard.shortcut',
340
+        type: TYPE_UI
344
     };
341
     };
342
+}
345
 
343
 
346
 /**
344
 /**
347
  * Creates an event which indicates the "start audio only" configuration.
345
  * Creates an event which indicates the "start audio only" configuration.
350
  * @returns {Object} The event in a format suitable for sending via
348
  * @returns {Object} The event in a format suitable for sending via
351
  * sendAnalytics.
349
  * sendAnalytics.
352
  */
350
  */
353
-export const createStartAudioOnlyEvent = function(audioOnly) {
351
+export function createStartAudioOnlyEvent(audioOnly) {
354
     return {
352
     return {
355
         action: 'start.audio.only',
353
         action: 'start.audio.only',
356
         attributes: {
354
         attributes: {
357
             enabled: audioOnly
355
             enabled: audioOnly
358
         }
356
         }
359
     };
357
     };
360
-};
358
+}
361
 
359
 
362
 /**
360
 /**
363
  * Creates an event which indicates the "start muted" configuration.
361
  * Creates an event which indicates the "start muted" configuration.
372
  * @returns {Object} The event in a format suitable for sending via
370
  * @returns {Object} The event in a format suitable for sending via
373
  * sendAnalytics.
371
  * sendAnalytics.
374
  */
372
  */
375
-export const createStartMutedConfigurationEvent
376
-    = function(source, audioMute, videoMute) {
377
-        return {
378
-            action: 'start.muted.configuration',
379
-            attributes: {
380
-                source,
381
-                'audio_mute': audioMute,
382
-                'video_mute': videoMute
383
-            }
384
-        };
373
+export function createStartMutedConfigurationEvent(
374
+        source,
375
+        audioMute,
376
+        videoMute) {
377
+    return {
378
+        action: 'start.muted.configuration',
379
+        attributes: {
380
+            source,
381
+            'audio_mute': audioMute,
382
+            'video_mute': videoMute
383
+        }
385
     };
384
     };
385
+}
386
 
386
 
387
 /**
387
 /**
388
  * Creates an event which indicates the delay for switching between simulcast
388
  * Creates an event which indicates the delay for switching between simulcast
392
  * @returns {Object} The event in a format suitable for sending via
392
  * @returns {Object} The event in a format suitable for sending via
393
  * sendAnalytics.
393
  * sendAnalytics.
394
  */
394
  */
395
-export const createStreamSwitchDelayEvent = function(attributes) {
395
+export function createStreamSwitchDelayEvent(attributes) {
396
     return {
396
     return {
397
         action: 'stream.switch.delay',
397
         action: 'stream.switch.delay',
398
         attributes
398
         attributes
399
     };
399
     };
400
-};
400
+}
401
 
401
 
402
 /**
402
 /**
403
  * Automatically changing the mute state of a media track in order to match
403
  * Automatically changing the mute state of a media track in order to match
409
  * @returns {Object} The event in a format suitable for sending via
409
  * @returns {Object} The event in a format suitable for sending via
410
  * sendAnalytics.
410
  * sendAnalytics.
411
  */
411
  */
412
-export const createSyncTrackStateEvent = function(mediaType, muted) {
412
+export function createSyncTrackStateEvent(mediaType, muted) {
413
     return {
413
     return {
414
         action: 'sync.track.state',
414
         action: 'sync.track.state',
415
         attributes: {
415
         attributes: {
417
             muted
417
             muted
418
         }
418
         }
419
     };
419
     };
420
-};
420
+}
421
 
421
 
422
 /**
422
 /**
423
  * Creates an event associated with a toolbar button being clicked/pressed. By
423
  * Creates an event associated with a toolbar button being clicked/pressed. By
431
  * @returns {Object} The event in a format suitable for sending via
431
  * @returns {Object} The event in a format suitable for sending via
432
  * sendAnalytics.
432
  * sendAnalytics.
433
  */
433
  */
434
-export const createToolbarEvent = function(buttonName, attributes = {}) {
434
+export function createToolbarEvent(buttonName, attributes = {}) {
435
     return {
435
     return {
436
         action: 'clicked',
436
         action: 'clicked',
437
         actionSubject: buttonName,
437
         actionSubject: buttonName,
439
         source: 'toolbar.button',
439
         source: 'toolbar.button',
440
         type: TYPE_UI
440
         type: TYPE_UI
441
     };
441
     };
442
-};
442
+}
443
 
443
 
444
 /**
444
 /**
445
  * Creates an event which indicates that a local track was muted.
445
  * Creates an event which indicates that a local track was muted.
452
  * @returns {Object} The event in a format suitable for sending via
452
  * @returns {Object} The event in a format suitable for sending via
453
  * sendAnalytics.
453
  * sendAnalytics.
454
  */
454
  */
455
-export const createTrackMutedEvent = function(mediaType, reason, muted = true) {
455
+export function createTrackMutedEvent(mediaType, reason, muted = true) {
456
     return {
456
     return {
457
         action: 'track.muted',
457
         action: 'track.muted',
458
         attributes: {
458
         attributes: {
461
             reason
461
             reason
462
         }
462
         }
463
     };
463
     };
464
-};
464
+}
465
 
465
 
466
 /**
466
 /**
467
  * Creates an event for an action on the welcome page.
467
  * Creates an event for an action on the welcome page.
472
  * @returns {Object} The event in a format suitable for sending via
472
  * @returns {Object} The event in a format suitable for sending via
473
  * sendAnalytics.
473
  * sendAnalytics.
474
  */
474
  */
475
-export const createWelcomePageEvent
476
-    = function(action, actionSubject, attributes = {}) {
477
-        return {
478
-            action,
479
-            actionSubject,
480
-            attributes,
481
-            source: 'welcomePage'
482
-        };
475
+export function createWelcomePageEvent(action, actionSubject, attributes = {}) {
476
+    return {
477
+        action,
478
+        actionSubject,
479
+        attributes,
480
+        source: 'welcomePage'
483
     };
481
     };
482
+}

+ 0
- 19
react/features/app-settings/actionTypes.js 查看文件

1
-/**
2
- * The type of (redux) action which signals the request
3
- * to hide the app settings screen.
4
- *
5
- * {
6
- *     type: HIDE_APP_SETTINGS
7
- * }
8
- */
9
-export const HIDE_APP_SETTINGS = Symbol('HIDE_APP_SETTINGS');
10
-
11
-/**
12
- * The type of (redux) action which signals the request
13
- * to show the app settings screen where available.
14
- *
15
- * {
16
- *     type: SHOW_APP_SETTINGS
17
- * }
18
- */
19
-export const SHOW_APP_SETTINGS = Symbol('SHOW_APP_SETTINGS');

+ 0
- 29
react/features/app-settings/actions.js 查看文件

1
-// @flow
2
-
3
-import { HIDE_APP_SETTINGS, SHOW_APP_SETTINGS } from './actionTypes';
4
-
5
-/**
6
- * Redux-signals the request to hide the app settings screen.
7
- *
8
- * @returns {{
9
- *     type: HIDE_APP_SETTINGS
10
- * }}
11
- */
12
-export function hideAppSettings() {
13
-    return {
14
-        type: HIDE_APP_SETTINGS
15
-    };
16
-}
17
-
18
-/**
19
- * Redux-signals the request to open the app settings screen.
20
- *
21
- * @returns {{
22
- *     type: SHOW_APP_SETTINGS
23
- * }}
24
- */
25
-export function showAppSettings() {
26
-    return {
27
-        type: SHOW_APP_SETTINGS
28
-    };
29
-}

+ 0
- 238
react/features/app-settings/components/AppSettings.native.js 查看文件

1
-// @flow
2
-
3
-import React from 'react';
4
-import {
5
-    Alert,
6
-    Modal,
7
-    SafeAreaView,
8
-    ScrollView,
9
-    Switch,
10
-    Text,
11
-    TextInput,
12
-    View
13
-} from 'react-native';
14
-import { connect } from 'react-redux';
15
-
16
-import { translate } from '../../base/i18n';
17
-import { Header } from '../../base/react';
18
-import { PlatformElements } from '../../base/styles';
19
-
20
-import { hideAppSettings } from '../actions';
21
-import { normalizeUserInputURL } from '../functions';
22
-
23
-import { BackButton, FormRow, FormSectionHeader } from './_';
24
-import { _mapStateToProps, AbstractAppSettings } from './AbstractAppSettings';
25
-import styles from './styles';
26
-
27
-/**
28
- * The native container rendering the app settings page.
29
- *
30
- * @extends AbstractAppSettings
31
- */
32
-class AppSettings extends AbstractAppSettings {
33
-    _urlField: Object;
34
-
35
-    /**
36
-     * Instantiates a new {@code AppSettings} instance.
37
-     *
38
-     * @inheritdoc
39
-     */
40
-    constructor(props) {
41
-        super(props);
42
-
43
-        this._onBlurServerURL = this._onBlurServerURL.bind(this);
44
-        this._onRequestClose = this._onRequestClose.bind(this);
45
-        this._setURLFieldReference = this._setURLFieldReference.bind(this);
46
-        this._showURLAlert = this._showURLAlert.bind(this);
47
-    }
48
-
49
-    /**
50
-     * Implements React's {@link Component#render()}, renders the settings page.
51
-     *
52
-     * @inheritdoc
53
-     * @returns {ReactElement}
54
-     */
55
-    render() {
56
-        const { _profile, t } = this.props;
57
-
58
-        return (
59
-            <Modal
60
-                animationType = 'slide'
61
-                onRequestClose = { this._onRequestClose }
62
-                presentationStyle = 'fullScreen'
63
-                supportedOrientations = { [
64
-                    'landscape',
65
-                    'portrait'
66
-                ] }
67
-                visible = { this.props._visible }>
68
-                <View style = { PlatformElements.page }>
69
-                    <Header>
70
-                        <BackButton
71
-                            onPress = { this._onRequestClose } />
72
-                        <Text
73
-                            style = { [
74
-                                styles.text,
75
-                                PlatformElements.headerText
76
-                            ] } >
77
-                            { t('settingsScreen.header') }
78
-                        </Text>
79
-                    </Header>
80
-                    <SafeAreaView style = { styles.settingsForm }>
81
-                        <ScrollView>
82
-                            <FormSectionHeader
83
-                                i18nLabel = 'settingsScreen.profileSection' />
84
-                            <FormRow
85
-                                fieldSeparator = { true }
86
-                                i18nLabel = 'settingsScreen.displayName' >
87
-                                <TextInput
88
-                                    onChangeText = { this._onChangeDisplayName }
89
-                                    placeholder = 'John Doe'
90
-                                    value = { _profile.displayName } />
91
-                            </FormRow>
92
-                            <FormRow
93
-                                i18nLabel = 'settingsScreen.email' >
94
-                                <TextInput
95
-                                    keyboardType = { 'email-address' }
96
-                                    onChangeText = { this._onChangeEmail }
97
-                                    placeholder = 'email@example.com'
98
-                                    value = { _profile.email } />
99
-                            </FormRow>
100
-                            <FormSectionHeader
101
-                                i18nLabel
102
-                                    = 'settingsScreen.conferenceSection' />
103
-                            <FormRow
104
-                                fieldSeparator = { true }
105
-                                i18nLabel = 'settingsScreen.serverURL' >
106
-                                <TextInput
107
-                                    autoCapitalize = 'none'
108
-                                    onBlur = { this._onBlurServerURL }
109
-                                    onChangeText = { this._onChangeServerURL }
110
-                                    placeholder = { this.props._serverURL }
111
-                                    value = { _profile.serverURL } />
112
-                            </FormRow>
113
-                            <FormRow
114
-                                fieldSeparator = { true }
115
-                                i18nLabel
116
-                                    = 'settingsScreen.startWithAudioMuted' >
117
-                                <Switch
118
-                                    onValueChange = {
119
-                                        this._onStartAudioMutedChange
120
-                                    }
121
-                                    value = {
122
-                                        _profile.startWithAudioMuted
123
-                                    } />
124
-                            </FormRow>
125
-                            <FormRow
126
-                                i18nLabel
127
-                                    = 'settingsScreen.startWithVideoMuted' >
128
-                                <Switch
129
-                                    onValueChange = {
130
-                                        this._onStartVideoMutedChange
131
-                                    }
132
-                                    value = {
133
-                                        _profile.startWithVideoMuted
134
-                                    } />
135
-                            </FormRow>
136
-                        </ScrollView>
137
-                    </SafeAreaView>
138
-                </View>
139
-            </Modal>
140
-        );
141
-    }
142
-
143
-    _onBlurServerURL: () => void;
144
-
145
-    /**
146
-     * Handler the server URL lose focus event. Here we validate the server URL
147
-     * and update it to the normalized version, or show an error if incorrect.
148
-     *
149
-     * @private
150
-     * @returns {void}
151
-     */
152
-    _onBlurServerURL() {
153
-        this._processServerURL(false /* hideOnSuccess */);
154
-    }
155
-
156
-    _onChangeDisplayName: (string) => void;
157
-
158
-    _onChangeEmail: (string) => void;
159
-
160
-    _onChangeServerURL: (string) => void;
161
-
162
-    _onStartAudioMutedChange: (boolean) => void;
163
-
164
-    _onStartVideoMutedChange: (boolean) => void;
165
-
166
-    /**
167
-     * Processes the server URL. It normalizes it and an error alert is
168
-     * displayed in case it's incorrect.
169
-     *
170
-     * @param {boolean} hideOnSuccess - True if the dialog should be hidden if
171
-     * normalization / validation succeeds, false otherwise.
172
-     * @private
173
-     * @returns {void}
174
-     */
175
-    _processServerURL(hideOnSuccess: boolean) {
176
-        const { serverURL } = this.props._profile;
177
-        const normalizedURL = normalizeUserInputURL(serverURL);
178
-
179
-        if (normalizedURL === null) {
180
-            this._showURLAlert();
181
-        } else {
182
-            this._onChangeServerURL(normalizedURL);
183
-            if (hideOnSuccess) {
184
-                this.props.dispatch(hideAppSettings());
185
-            }
186
-        }
187
-    }
188
-
189
-    _onRequestClose: () => void;
190
-
191
-    /**
192
-     * Handles the back button.
193
-     * Also invokes normalizeUserInputURL to validate the URL entered
194
-     * by the user.
195
-     *
196
-     * @returns {void}
197
-     */
198
-    _onRequestClose() {
199
-        this._processServerURL(true /* hideOnSuccess */);
200
-    }
201
-
202
-    _setURLFieldReference: (React$ElementRef<*> | null) => void;
203
-
204
-    /**
205
-     *  Stores a reference to the URL field for later use.
206
-     *
207
-     * @protected
208
-     * @param {Object} component - The field component.
209
-     * @returns {void}
210
-     */
211
-    _setURLFieldReference(component) {
212
-        this._urlField = component;
213
-    }
214
-
215
-    _showURLAlert: () => void;
216
-
217
-    /**
218
-     * Shows an alert telling the user that the URL he/she entered was invalid.
219
-     *
220
-     * @returns {void}
221
-     */
222
-    _showURLAlert() {
223
-        const { t } = this.props;
224
-
225
-        Alert.alert(
226
-            t('settingsScreen.alertTitle'),
227
-            t('settingsScreen.alertURLText'),
228
-            [
229
-                {
230
-                    onPress: () => this._urlField.focus(),
231
-                    text: t('settingsScreen.alertOk')
232
-                }
233
-            ]
234
-        );
235
-    }
236
-}
237
-
238
-export default translate(connect(_mapStateToProps)(AppSettings));

+ 0
- 0
react/features/app-settings/components/AppSettings.web.js 查看文件


+ 0
- 0
react/features/app-settings/components/_.web.js 查看文件


+ 0
- 1
react/features/app-settings/components/index.js 查看文件

1
-export { default as AppSettings } from './AppSettings';

+ 0
- 3
react/features/app-settings/components/native/index.js 查看文件

1
-export { default as BackButton } from './BackButton';
2
-export { default as FormRow } from './FormRow';
3
-export { default as FormSectionHeader } from './FormSectionHeader';

+ 0
- 33
react/features/app-settings/components/styles.js 查看文件

1
-import {
2
-    BoxModel,
3
-    ColorPalette,
4
-    createStyleSheet
5
-} from '../../base/styles';
6
-
7
-/**
8
- * The styles of the React {@code Components} of the feature
9
- * {@code app-settings}.
10
- */
11
-export default createStyleSheet({
12
-    /**
13
-     * Style of the ScrollView to be able to scroll the content.
14
-     */
15
-    scrollView: {
16
-        flex: 1
17
-    },
18
-
19
-    /**
20
-     * Style of the settings screen content (form).
21
-     */
22
-    settingsForm: {
23
-        flex: 1,
24
-        margin: BoxModel.margin
25
-    },
26
-
27
-    /**
28
-     * Global {@code Text} color for the page.
29
-     */
30
-    text: {
31
-        color: ColorPalette.black
32
-    }
33
-});

+ 0
- 31
react/features/app-settings/reducer.js 查看文件

1
-// @flow
2
-
3
-import {
4
-    HIDE_APP_SETTINGS,
5
-    SHOW_APP_SETTINGS
6
-} from './actionTypes';
7
-
8
-import { ReducerRegistry } from '../base/redux';
9
-
10
-const DEFAULT_STATE = {
11
-    visible: false
12
-};
13
-
14
-ReducerRegistry.register(
15
-    'features/app-settings', (state = DEFAULT_STATE, action) => {
16
-        switch (action.type) {
17
-        case HIDE_APP_SETTINGS:
18
-            return {
19
-                ...state,
20
-                visible: false
21
-            };
22
-
23
-        case SHOW_APP_SETTINGS:
24
-            return {
25
-                ...state,
26
-                visible: true
27
-            };
28
-        }
29
-
30
-        return state;
31
-    });

+ 10
- 7
react/features/base/conference/middleware.js 查看文件

125
  */
125
  */
126
 function _conferenceFailedOrLeft({ dispatch, getState }, next, action) {
126
 function _conferenceFailedOrLeft({ dispatch, getState }, next, action) {
127
     const result = next(action);
127
     const result = next(action);
128
+
128
     const state = getState();
129
     const state = getState();
129
     const { audioOnly } = state['features/base/conference'];
130
     const { audioOnly } = state['features/base/conference'];
130
     const { startAudioOnly } = state['features/base/profile'].profile;
131
     const { startAudioOnly } = state['features/base/profile'].profile;
131
 
132
 
132
-    // FIXME: Consider implementing a standalone audio-only feature
133
-    // that handles all these state changes.
134
-    if (audioOnly && !startAudioOnly) {
135
-        sendAnalytics(createAudioOnlyChangedEvent(false));
136
-        logger.log('Audio only disabled');
137
-        dispatch(setAudioOnly(false));
138
-    } else if (!audioOnly && startAudioOnly) {
133
+    // FIXME: Consider implementing a standalone audio-only feature that handles
134
+    // all these state changes.
135
+    if (audioOnly) {
136
+        if (!startAudioOnly) {
137
+            sendAnalytics(createAudioOnlyChangedEvent(false));
138
+            logger.log('Audio only disabled');
139
+            dispatch(setAudioOnly(false));
140
+        }
141
+    } else if (startAudioOnly) {
139
         sendAnalytics(createAudioOnlyChangedEvent(true));
142
         sendAnalytics(createAudioOnlyChangedEvent(true));
140
         logger.log('Audio only enabled');
143
         logger.log('Audio only enabled');
141
         dispatch(setAudioOnly(true));
144
         dispatch(setAudioOnly(true));

+ 32
- 4
react/features/base/react/components/native/Header.js 查看文件

32
 export default class Header extends Component<Props> {
32
 export default class Header extends Component<Props> {
33
 
33
 
34
     /**
34
     /**
35
-     * Constructor of the Header component.
35
+     * The style of button-like React {@code Component}s rendered in
36
+     * {@code Header}.
37
+     *
38
+     * @returns {Object}
39
+     */
40
+    static get buttonStyle() {
41
+        return styles.headerButton;
42
+    }
43
+
44
+    /**
45
+     * The style of a React {@code Component} rendering a {@code Header} as its
46
+     * child.
47
+     *
48
+     * @returns {Object}
49
+     */
50
+    static get pageStyle() {
51
+        return styles.page;
52
+    }
53
+
54
+    /**
55
+     * The style of text rendered in {@code Header}.
56
+     *
57
+     * @returns {Object}
58
+     */
59
+    static get textStyle() {
60
+        return styles.headerText;
61
+    }
62
+
63
+    /**
64
+     * Initializes a new {@code Header} instance.
36
      *
65
      *
37
      * @inheritdoc
66
      * @inheritdoc
38
      */
67
      */
77
     _getIOS10CompatiblePadding: () => Object;
106
     _getIOS10CompatiblePadding: () => Object;
78
 
107
 
79
     /**
108
     /**
80
-     * Adds a padding for iOS 10 (and older) devices to avoid clipping
81
-     * with the status bar.
109
+     * Adds a padding for iOS 10 (and older) devices to avoid clipping with the
110
+     * status bar.
82
      * Note: This is a workaround for iOS 10 (and older) devices only to fix
111
      * Note: This is a workaround for iOS 10 (and older) devices only to fix
83
      * usability, but it doesn't take orientation into account, so unnecessary
112
      * usability, but it doesn't take orientation into account, so unnecessary
84
      * padding is rendered in some cases.
113
      * padding is rendered in some cases.
99
 
128
 
100
         return null;
129
         return null;
101
     }
130
     }
102
-
103
 }
131
 }

+ 25
- 22
react/features/base/react/components/native/SideBar.js 查看文件

1
-/* @flow */
1
+// @flow
2
 
2
 
3
 import React, { Component } from 'react';
3
 import React, { Component } from 'react';
4
 import {
4
 import {
10
 
10
 
11
 import styles, { SIDEBAR_WIDTH } from './styles';
11
 import styles, { SIDEBAR_WIDTH } from './styles';
12
 
12
 
13
-
14
 /**
13
 /**
15
- * The type of the React {@code Component} props of {@link SideBar}
14
+ * The type of the React {@code Component} props of {@link SideBar}.
16
  */
15
  */
17
 type Props = {
16
 type Props = {
18
 
17
 
38
     show: boolean
37
     show: boolean
39
 }
38
 }
40
 
39
 
40
+/**
41
+ * The type of the React {@code Component} state of {@link SideBar}.
42
+ */
41
 type State = {
43
 type State = {
42
 
44
 
43
     /**
45
     /**
44
-     * Indicates whether the side bar is visible or not.
46
+     * Indicates whether the side overlay should be rendered or not.
45
      */
47
      */
46
-    showSideBar: boolean,
48
+    showOverlay: boolean,
47
 
49
 
48
     /**
50
     /**
49
-     * Indicates whether the side overlay should be rendered or not.
51
+     * Indicates whether the side bar is visible or not.
50
      */
52
      */
51
-    showOverlay: boolean,
53
+    showSideBar: boolean,
52
 
54
 
53
     /**
55
     /**
54
      * The native animation object.
56
      * The native animation object.
63
     _mounted: boolean;
65
     _mounted: boolean;
64
 
66
 
65
     /**
67
     /**
66
-     * Component's contructor.
68
+     * Initializes a new {@code SideBar} instance.
67
      *
69
      *
68
      * @inheritdoc
70
      * @inheritdoc
69
      */
71
      */
71
         super(props);
73
         super(props);
72
 
74
 
73
         this.state = {
75
         this.state = {
74
-            showSideBar: false,
75
             showOverlay: false,
76
             showOverlay: false,
77
+            showSideBar: false,
76
             sliderAnimation: new Animated.Value(-SIDEBAR_WIDTH)
78
             sliderAnimation: new Animated.Value(-SIDEBAR_WIDTH)
77
         };
79
         };
78
 
80
 
79
-        this._setShow = this._setShow.bind(this);
80
-
81
         this._getContainerStyle = this._getContainerStyle.bind(this);
81
         this._getContainerStyle = this._getContainerStyle.bind(this);
82
         this._onHideMenu = this._onHideMenu.bind(this);
82
         this._onHideMenu = this._onHideMenu.bind(this);
83
+        this._setShow = this._setShow.bind(this);
84
+
83
         this._setShow(props.show);
85
         this._setShow(props.show);
84
     }
86
     }
85
 
87
 
171
     /**
173
     /**
172
      * Sets the side menu visible or hidden.
174
      * Sets the side menu visible or hidden.
173
      *
175
      *
174
-     * @private
175
      * @param {boolean} show - The new expected visibility value.
176
      * @param {boolean} show - The new expected visibility value.
177
+     * @private
176
      * @returns {void}
178
      * @returns {void}
177
      */
179
      */
178
     _setShow(show) {
180
     _setShow(show) {
183
                 });
185
                 });
184
             }
186
             }
185
 
187
 
186
-            Animated.timing(this.state.sliderAnimation, {
187
-                toValue: show ? 0 : -SIDEBAR_WIDTH
188
-            }).start(animationState => {
189
-                if (animationState.finished && !show) {
190
-                    this.setState({
191
-                        showOverlay: false
192
-                    });
193
-                }
194
-            });
188
+            Animated
189
+                .timing(
190
+                    this.state.sliderAnimation,
191
+                    { toValue: show ? 0 : -SIDEBAR_WIDTH })
192
+                .start(animationState => {
193
+                    if (animationState.finished && !show) {
194
+                        this.setState({
195
+                            showOverlay: false
196
+                        });
197
+                    }
198
+                });
195
         }
199
         }
196
 
200
 
197
         if (this._mounted) {
201
         if (this._mounted) {
200
             });
204
             });
201
         }
205
         }
202
     }
206
     }
203
-
204
 }
207
 }

+ 2
- 3
react/features/base/react/components/native/index.js 查看文件

1
 export { default as Container } from './Container';
1
 export { default as Container } from './Container';
2
+export { default as Header } from './Header';
2
 export { default as Link } from './Link';
3
 export { default as Link } from './Link';
3
 export { default as LoadingIndicator } from './LoadingIndicator';
4
 export { default as LoadingIndicator } from './LoadingIndicator';
4
-export { default as Header } from './Header';
5
 export { default as SideBar } from './SideBar';
5
 export { default as SideBar } from './SideBar';
6
-export * from './styles';
7
-export { default as TintedView } from './TintedView';
8
 export { default as Text } from './Text';
6
 export { default as Text } from './Text';
7
+export { default as TintedView } from './TintedView';

+ 34
- 2
react/features/base/react/components/native/styles.js 查看文件

14
 export const SIDEBAR_WIDTH = 250;
14
 export const SIDEBAR_WIDTH = 250;
15
 
15
 
16
 /**
16
 /**
17
- * The styles of the React {@code Components} of the generic components
18
- * in the app.
17
+ * The styles of the generic React {@code Components} of the app.
19
  */
18
  */
20
 export default createStyleSheet({
19
 export default createStyleSheet({
21
 
20
 
21
+    /**
22
+     * Platform specific header button (e.g. back, menu...etc).
23
+     */
24
+    headerButton: {
25
+        alignSelf: 'center',
26
+        color: ColorPalette.white,
27
+        fontSize: 26,
28
+        paddingRight: 22
29
+    },
30
+
22
     /**
31
     /**
23
      * Style of the header overlay to cover the unsafe areas.
32
      * Style of the header overlay to cover the unsafe areas.
24
      */
33
      */
26
         backgroundColor: HEADER_COLOR
35
         backgroundColor: HEADER_COLOR
27
     },
36
     },
28
 
37
 
38
+    /**
39
+     * Generic style for a label placed in the header.
40
+     */
41
+    headerText: {
42
+        color: ColorPalette.white,
43
+        fontSize: 20
44
+    },
45
+
46
+    /**
47
+     * The top-level element of a page.
48
+     */
49
+    page: {
50
+        alignItems: 'stretch',
51
+        bottom: 0,
52
+        flex: 1,
53
+        flexDirection: 'column',
54
+        left: 0,
55
+        overflow: 'hidden',
56
+        position: 'absolute',
57
+        right: 0,
58
+        top: 0
59
+    },
60
+
29
     /**
61
     /**
30
      * Base style of Header
62
      * Base style of Header
31
      */
63
      */

+ 0
- 41
react/features/base/styles/components/styles/PlatformElements.native.js 查看文件

1
-import { ColorPalette } from './ColorPalette';
2
-
3
-import {
4
-    createStyleSheet
5
-} from '../../functions';
6
-
7
-export const PlatformElements = createStyleSheet({
8
-
9
-    /**
10
-     * Platform specific header button (e.g. back, menu...etc).
11
-     */
12
-    headerButton: {
13
-        alignSelf: 'center',
14
-        color: ColorPalette.white,
15
-        fontSize: 26,
16
-        paddingRight: 22
17
-    },
18
-
19
-    /**
20
-     * Generic style for a label placed in the header.
21
-     */
22
-    headerText: {
23
-        color: ColorPalette.white,
24
-        fontSize: 20
25
-    },
26
-
27
-    /**
28
-     * The topmost level element of a page.
29
-     */
30
-    page: {
31
-        alignItems: 'stretch',
32
-        bottom: 0,
33
-        flex: 1,
34
-        flexDirection: 'column',
35
-        left: 0,
36
-        overflow: 'hidden',
37
-        position: 'absolute',
38
-        right: 0,
39
-        top: 0
40
-    }
41
-});

+ 0
- 0
react/features/base/styles/components/styles/PlatformElements.web.js 查看文件


+ 0
- 1
react/features/base/styles/components/styles/index.js 查看文件

1
 export * from './BoxModel';
1
 export * from './BoxModel';
2
 export * from './ColorPalette';
2
 export * from './ColorPalette';
3
-export * from './PlatformElements';

+ 0
- 0
react/features/settings-menu/components/DeviceSelectionButton.native.js 查看文件


+ 0
- 0
react/features/settings-menu/components/LanguageSelectDropdown.native.js 查看文件


+ 0
- 0
react/features/settings-menu/components/ModeratorCheckboxes.native.js 查看文件


+ 0
- 0
react/features/settings-menu/components/SettingsMenu.native.js 查看文件


+ 0
- 1
react/features/settings-menu/index.js 查看文件

1
-export * from './components';

+ 10
- 0
react/features/settings/actionTypes.js 查看文件

1
+/**
2
+ * The type of (redux) action which sets the visibility of the view/UI rendering
3
+ * the app's settings.
4
+ *
5
+ * {
6
+ *     type: SET_SETTINGS_VIEW_VISIBLE
7
+ *     visible: boolean
8
+ * }
9
+ */
10
+export const SET_SETTINGS_VIEW_VISIBLE = Symbol('SET_SETTINGS_VIEW_VISIBLE');

+ 20
- 0
react/features/settings/actions.js 查看文件

1
+// @flow
2
+
3
+import { SET_SETTINGS_VIEW_VISIBLE } from './actionTypes';
4
+
5
+/**
6
+ * Sets the visibility of the view/UI which renders the app's settings.
7
+ *
8
+ * @param {boolean} visible - If the view/UI which renders the app's settings is
9
+ * to be made visible, {@code true}; otherwise, {@code false}.
10
+ * @returns {{
11
+ *     type: SET_SETTINGS_VIEW_VISIBLE,
12
+ *     visible: boolean
13
+ * }}
14
+ */
15
+export function setSettingsViewVisible(visible: boolean) {
16
+    return {
17
+        type: SET_SETTINGS_VIEW_VISIBLE,
18
+        visible
19
+    };
20
+}

react/features/app-settings/components/AbstractAppSettings.js → react/features/settings/components/AbstractSettingsView.js 查看文件

5
 import { getProfile, updateProfile } from '../../base/profile';
5
 import { getProfile, updateProfile } from '../../base/profile';
6
 
6
 
7
 /**
7
 /**
8
- * The type of the React {@code Component} props of {@link AbstractAppSettings}
8
+ * The type of the React {@code Component} props of
9
+ * {@link AbstractSettingsView}.
9
  */
10
  */
10
 type Props = {
11
 type Props = {
11
 
12
 
20
     _serverURL: string,
21
     _serverURL: string,
21
 
22
 
22
     /**
23
     /**
23
-     * The visibility prop of the settings screen.
24
+     * Whether {@link AbstractSettingsView} is visible.
24
      */
25
      */
25
     _visible: boolean,
26
     _visible: boolean,
26
 
27
 
41
  *
42
  *
42
  * @abstract
43
  * @abstract
43
  */
44
  */
44
-export class AbstractAppSettings extends Component<Props> {
45
+export class AbstractSettingsView extends Component<Props> {
45
 
46
 
46
     /**
47
     /**
47
-     * Initializes a new {@code AbstractAppSettings} instance.
48
+     * Initializes a new {@code AbstractSettingsView} instance.
48
      *
49
      *
49
      * @param {Props} props - The React {@code Component} props to initialize
50
      * @param {Props} props - The React {@code Component} props to initialize
50
      * the component.
51
      * the component.
52
     constructor(props: Props) {
53
     constructor(props: Props) {
53
         super(props);
54
         super(props);
54
 
55
 
56
+        // Bind event handlers so they are only bound once per instance.
55
         this._onChangeDisplayName = this._onChangeDisplayName.bind(this);
57
         this._onChangeDisplayName = this._onChangeDisplayName.bind(this);
56
         this._onChangeEmail = this._onChangeEmail.bind(this);
58
         this._onChangeEmail = this._onChangeEmail.bind(this);
57
         this._onChangeServerURL = this._onChangeServerURL.bind(this);
59
         this._onChangeServerURL = this._onChangeServerURL.bind(this);
66
     /**
68
     /**
67
      * Handles the display name field value change.
69
      * Handles the display name field value change.
68
      *
70
      *
69
-     * @protected
70
      * @param {string} text - The value typed in the name field.
71
      * @param {string} text - The value typed in the name field.
72
+     * @protected
71
      * @returns {void}
73
      * @returns {void}
72
      */
74
      */
73
     _onChangeDisplayName(text) {
75
     _onChangeDisplayName(text) {
81
     /**
83
     /**
82
      * Handles the email field value change.
84
      * Handles the email field value change.
83
      *
85
      *
84
-     * @protected
85
      * @param {string} text - The value typed in the email field.
86
      * @param {string} text - The value typed in the email field.
87
+     * @protected
86
      * @returns {void}
88
      * @returns {void}
87
      */
89
      */
88
     _onChangeEmail(text) {
90
     _onChangeEmail(text) {
96
     /**
98
     /**
97
      * Handles the server name field value change.
99
      * Handles the server name field value change.
98
      *
100
      *
99
-     * @protected
100
      * @param {string} text - The server URL typed in the server field.
101
      * @param {string} text - The server URL typed in the server field.
102
+     * @protected
101
      * @returns {void}
103
      * @returns {void}
102
      */
104
      */
103
     _onChangeServerURL(text) {
105
     _onChangeServerURL(text) {
111
     /**
113
     /**
112
      * Handles the start audio muted change event.
114
      * Handles the start audio muted change event.
113
      *
115
      *
116
+     * @param {boolean} newValue - The new value for the start audio muted
117
+     * option.
114
      * @protected
118
      * @protected
115
-     * @param {boolean} newValue - The new value for the
116
-     * start audio muted option.
117
      * @returns {void}
119
      * @returns {void}
118
      */
120
      */
119
     _onStartAudioMutedChange(newValue) {
121
     _onStartAudioMutedChange(newValue) {
127
     /**
129
     /**
128
      * Handles the start video muted change event.
130
      * Handles the start video muted change event.
129
      *
131
      *
132
+     * @param {boolean} newValue - The new value for the start video muted
133
+     * option.
130
      * @protected
134
      * @protected
131
-     * @param {boolean} newValue - The new value for the
132
-     * start video muted option.
133
      * @returns {void}
135
      * @returns {void}
134
      */
136
      */
135
     _onStartVideoMutedChange(newValue) {
137
     _onStartVideoMutedChange(newValue) {
143
     /**
145
     /**
144
      * Updates the persisted profile on any change.
146
      * Updates the persisted profile on any change.
145
      *
147
      *
146
-     * @private
147
      * @param {Object} updateObject - The partial update object for the profile.
148
      * @param {Object} updateObject - The partial update object for the profile.
149
+     * @private
148
      * @returns {void}
150
      * @returns {void}
149
      */
151
      */
150
     _updateProfile(updateObject: Object) {
152
     _updateProfile(updateObject: Object) {
157
 
159
 
158
 /**
160
 /**
159
  * Maps (parts of) the redux state to the React {@code Component} props of
161
  * Maps (parts of) the redux state to the React {@code Component} props of
160
- * {@code AbstractAppSettings}.
162
+ * {@code AbstractSettingsView}.
161
  *
163
  *
162
  * @param {Object} state - The redux state.
164
  * @param {Object} state - The redux state.
163
  * @protected
165
  * @protected
164
- * @returns {Object}
166
+ * @returns {{
167
+ *     _profile: Object,
168
+ *     _serverURL: string,
169
+ *     _visible: boolean
170
+ * }}
165
  */
171
  */
166
 export function _mapStateToProps(state: Object) {
172
 export function _mapStateToProps(state: Object) {
167
-    const _serverURL = state['features/app'].app._getDefaultURL();
168
-    const _profile = getProfile(state);
169
-
170
     return {
173
     return {
171
-        _profile,
172
-        _serverURL,
173
-        _visible: state['features/app-settings'].visible
174
+        _profile: getProfile(state),
175
+        _serverURL: state['features/app'].app._getDefaultURL(),
176
+        _visible: state['features/settings'].visible
174
     };
177
     };
175
 }
178
 }

react/features/app-settings/components/_.native.js → react/features/settings/components/_.native.js 查看文件


+ 1
- 0
react/features/settings/components/_.web.js 查看文件

1
+export * from './web';

+ 1
- 0
react/features/settings/components/index.js 查看文件

1
+export * from './_';

react/features/app-settings/components/native/BackButton.js → react/features/settings/components/native/BackButton.js 查看文件

4
 import { TouchableOpacity } from 'react-native';
4
 import { TouchableOpacity } from 'react-native';
5
 
5
 
6
 import { Icon } from '../../../base/font-icons';
6
 import { Icon } from '../../../base/font-icons';
7
-import { PlatformElements } from '../../../base/styles';
7
+import { Header } from '../../../base/react';
8
 
8
 
9
 /**
9
 /**
10
  * The type of the React {@code Component} props of {@link BackButton}
10
  * The type of the React {@code Component} props of {@link BackButton}
40
                 <Icon
40
                 <Icon
41
                     name = { 'arrow_back' }
41
                     name = { 'arrow_back' }
42
                     style = { [
42
                     style = { [
43
-                        PlatformElements.headerButton,
43
+                        Header.buttonStyle,
44
                         this.props.style
44
                         this.props.style
45
                     ] } />
45
                     ] } />
46
             </TouchableOpacity>
46
             </TouchableOpacity>

react/features/app-settings/components/native/FormRow.js → react/features/settings/components/native/FormRow.js 查看文件

47
         super(props);
47
         super(props);
48
 
48
 
49
         React.Children.only(this.props.children);
49
         React.Children.only(this.props.children);
50
+
50
         this._getDefaultFieldProps = this._getDefaultFieldProps.bind(this);
51
         this._getDefaultFieldProps = this._getDefaultFieldProps.bind(this);
51
         this._getRowStyle = this._getRowStyle.bind(this);
52
         this._getRowStyle = this._getRowStyle.bind(this);
52
     }
53
     }
63
 
64
 
64
         // Some field types need additional props to look good and standardized
65
         // Some field types need additional props to look good and standardized
65
         // on a form.
66
         // on a form.
66
-        const newChild = React.cloneElement(
67
-            this.props.children,
68
-            this._getDefaultFieldProps(this.props.children)
69
-        );
67
+        const newChild
68
+            = React.cloneElement(
69
+                this.props.children,
70
+                this._getDefaultFieldProps(this.props.children));
70
 
71
 
71
         return (
72
         return (
72
             <View
73
             <View
74
                 <View style = { styles.fieldLabelContainer } >
75
                 <View style = { styles.fieldLabelContainer } >
75
                     <Text
76
                     <Text
76
                         style = { [
77
                         style = { [
77
-                            styles.text, styles.fieldLabelText
78
+                            styles.text,
79
+                            styles.fieldLabelText
78
                         ] } >
80
                         ] } >
79
                         { t(this.props.i18nLabel) }
81
                         { t(this.props.i18nLabel) }
80
                     </Text>
82
                     </Text>
96
      *     - TextInput
98
      *     - TextInput
97
      *     - Switch (needs no addition props ATM).
99
      *     - Switch (needs no addition props ATM).
98
      *
100
      *
99
-     * @private
100
      * @param {Object} field - The field (child) component.
101
      * @param {Object} field - The field (child) component.
102
+     * @private
101
      * @returns {Object}
103
      * @returns {Object}
102
      */
104
      */
103
     _getDefaultFieldProps(field: Object) {
105
     _getDefaultFieldProps(field: Object) {

react/features/app-settings/components/native/FormSectionHeader.js → react/features/settings/components/native/FormSectionHeader.js 查看文件


+ 251
- 0
react/features/settings/components/native/SettingsView.js 查看文件

1
+// @flow
2
+
3
+import React from 'react';
4
+import {
5
+    Alert,
6
+    Modal,
7
+    SafeAreaView,
8
+    ScrollView,
9
+    Switch,
10
+    Text,
11
+    TextInput,
12
+    View
13
+} from 'react-native';
14
+import { connect } from 'react-redux';
15
+
16
+import { translate } from '../../../base/i18n';
17
+import { Header } from '../../../base/react';
18
+
19
+import {
20
+    AbstractSettingsView,
21
+    _mapStateToProps
22
+} from '../AbstractSettingsView';
23
+import { setSettingsViewVisible } from '../../actions';
24
+import BackButton from './BackButton';
25
+import FormRow from './FormRow';
26
+import FormSectionHeader from './FormSectionHeader';
27
+import { normalizeUserInputURL } from '../../functions';
28
+import styles from './styles';
29
+
30
+/**
31
+ * The native container rendering the app settings page.
32
+ *
33
+ * @extends AbstractSettingsView
34
+ */
35
+class SettingsView extends AbstractSettingsView {
36
+    _urlField: Object;
37
+
38
+    /**
39
+     * Initializes a new {@code SettingsView} instance.
40
+     *
41
+     * @inheritdoc
42
+     */
43
+    constructor(props) {
44
+        super(props);
45
+
46
+        // Bind event handlers so they are only bound once per instance.
47
+        this._onBlurServerURL = this._onBlurServerURL.bind(this);
48
+        this._onRequestClose = this._onRequestClose.bind(this);
49
+        this._setURLFieldReference = this._setURLFieldReference.bind(this);
50
+        this._showURLAlert = this._showURLAlert.bind(this);
51
+    }
52
+
53
+    /**
54
+     * Implements React's {@link Component#render()}, renders the settings page.
55
+     *
56
+     * @inheritdoc
57
+     * @returns {ReactElement}
58
+     */
59
+    render() {
60
+        return (
61
+            <Modal
62
+                animationType = 'slide'
63
+                onRequestClose = { this._onRequestClose }
64
+                presentationStyle = 'fullScreen'
65
+                supportedOrientations = { [
66
+                    'landscape',
67
+                    'portrait'
68
+                ] }
69
+                visible = { this.props._visible }>
70
+                <View style = { Header.pageStyle }>
71
+                    { this._renderHeader() }
72
+                    { this._renderBody() }
73
+                </View>
74
+            </Modal>
75
+        );
76
+    }
77
+
78
+    _onBlurServerURL: () => void;
79
+
80
+    /**
81
+     * Handler the server URL lose focus event. Here we validate the server URL
82
+     * and update it to the normalized version, or show an error if incorrect.
83
+     *
84
+     * @private
85
+     * @returns {void}
86
+     */
87
+    _onBlurServerURL() {
88
+        this._processServerURL(false /* hideOnSuccess */);
89
+    }
90
+
91
+    _onChangeDisplayName: (string) => void;
92
+
93
+    _onChangeEmail: (string) => void;
94
+
95
+    _onChangeServerURL: (string) => void;
96
+
97
+    _onRequestClose: () => void;
98
+
99
+    /**
100
+     * Handles the back button. Also invokes normalizeUserInputURL to validate
101
+     * the URL entered by the user.
102
+     *
103
+     * @returns {void}
104
+     */
105
+    _onRequestClose() {
106
+        this._processServerURL(true /* hideOnSuccess */);
107
+    }
108
+
109
+    _onStartAudioMutedChange: (boolean) => void;
110
+
111
+    _onStartVideoMutedChange: (boolean) => void;
112
+
113
+    /**
114
+     * Processes the server URL. It normalizes it and an error alert is
115
+     * displayed in case it's incorrect.
116
+     *
117
+     * @param {boolean} hideOnSuccess - True if the dialog should be hidden if
118
+     * normalization / validation succeeds, false otherwise.
119
+     * @private
120
+     * @returns {void}
121
+     */
122
+    _processServerURL(hideOnSuccess: boolean) {
123
+        const { serverURL } = this.props._profile;
124
+        const normalizedURL = normalizeUserInputURL(serverURL);
125
+
126
+        if (normalizedURL === null) {
127
+            this._showURLAlert();
128
+        } else {
129
+            this._onChangeServerURL(normalizedURL);
130
+            if (hideOnSuccess) {
131
+                this.props.dispatch(setSettingsViewVisible(false));
132
+            }
133
+        }
134
+    }
135
+
136
+    /**
137
+     * Renders the body (under the header) of {@code SettingsView}.
138
+     *
139
+     * @private
140
+     * @returns {React$Element}
141
+     */
142
+    _renderBody() {
143
+        const { _profile } = this.props;
144
+
145
+        return (
146
+            <SafeAreaView style = { styles.settingsForm }>
147
+                <ScrollView>
148
+                    <FormSectionHeader
149
+                        i18nLabel = 'settingsView.profileSection' />
150
+                    <FormRow
151
+                        fieldSeparator = { true }
152
+                        i18nLabel = 'settingsView.displayName'>
153
+                        <TextInput
154
+                            onChangeText = { this._onChangeDisplayName }
155
+                            placeholder = 'John Doe'
156
+                            value = { _profile.displayName } />
157
+                    </FormRow>
158
+                    <FormRow i18nLabel = 'settingsView.email'>
159
+                        <TextInput
160
+                            keyboardType = { 'email-address' }
161
+                            onChangeText = { this._onChangeEmail }
162
+                            placeholder = 'email@example.com'
163
+                            value = { _profile.email } />
164
+                    </FormRow>
165
+                    <FormSectionHeader
166
+                        i18nLabel = 'settingsView.conferenceSection' />
167
+                    <FormRow
168
+                        fieldSeparator = { true }
169
+                        i18nLabel = 'settingsView.serverURL'>
170
+                        <TextInput
171
+                            autoCapitalize = 'none'
172
+                            onBlur = { this._onBlurServerURL }
173
+                            onChangeText = { this._onChangeServerURL }
174
+                            placeholder = { this.props._serverURL }
175
+                            value = { _profile.serverURL } />
176
+                    </FormRow>
177
+                    <FormRow
178
+                        fieldSeparator = { true }
179
+                        i18nLabel = 'settingsView.startWithAudioMuted'>
180
+                        <Switch
181
+                            onValueChange = { this._onStartAudioMutedChange }
182
+                            value = { _profile.startWithAudioMuted } />
183
+                    </FormRow>
184
+                    <FormRow i18nLabel = 'settingsView.startWithVideoMuted'>
185
+                        <Switch
186
+                            onValueChange = { this._onStartVideoMutedChange }
187
+                            value = { _profile.startWithVideoMuted } />
188
+                    </FormRow>
189
+                </ScrollView>
190
+            </SafeAreaView>
191
+        );
192
+    }
193
+
194
+    /**
195
+     * Renders the header of {@code SettingsView}.
196
+     *
197
+     * @private
198
+     * @returns {React$Element}
199
+     */
200
+    _renderHeader() {
201
+        return (
202
+            <Header>
203
+                <BackButton onPress = { this._onRequestClose } />
204
+                <Text
205
+                    style = { [
206
+                        styles.text,
207
+                        Header.textStyle
208
+                    ] }>
209
+                    { this.props.t('settingsView.header') }
210
+                </Text>
211
+            </Header>
212
+        );
213
+    }
214
+
215
+    _setURLFieldReference: (React$ElementRef<*> | null) => void;
216
+
217
+    /**
218
+     *  Stores a reference to the URL field for later use.
219
+     *
220
+     * @param {Object} component - The field component.
221
+     * @protected
222
+     * @returns {void}
223
+     */
224
+    _setURLFieldReference(component) {
225
+        this._urlField = component;
226
+    }
227
+
228
+    _showURLAlert: () => void;
229
+
230
+    /**
231
+     * Shows an alert telling the user that the URL he/she entered was invalid.
232
+     *
233
+     * @returns {void}
234
+     */
235
+    _showURLAlert() {
236
+        const { t } = this.props;
237
+
238
+        Alert.alert(
239
+            t('settingsView.alertTitle'),
240
+            t('settingsView.alertURLText'),
241
+            [
242
+                {
243
+                    onPress: () => this._urlField.focus(),
244
+                    text: t('settingsView.alertOk')
245
+                }
246
+            ]
247
+        );
248
+    }
249
+}
250
+
251
+export default translate(connect(_mapStateToProps)(SettingsView));

+ 1
- 0
react/features/settings/components/native/index.js 查看文件

1
+export { default as SettingsView } from './SettingsView';

react/features/app-settings/components/native/styles.js → react/features/settings/components/native/styles.js 查看文件

7
 const TEXT_SIZE = 17;
7
 const TEXT_SIZE = 17;
8
 
8
 
9
 /**
9
 /**
10
- * The styles of the native components of the feature
11
- * {@code app-settings}.
10
+ * The styles of the native components of the feature {@code settings}.
12
  */
11
  */
13
 export default createStyleSheet({
12
 export default createStyleSheet({
14
     /**
13
     /**

react/features/settings-menu/components/DeviceSelectionButton.web.js → react/features/settings/components/web/DeviceSelectionButton.js 查看文件

3
 import React, { Component } from 'react';
3
 import React, { Component } from 'react';
4
 import { connect } from 'react-redux';
4
 import { connect } from 'react-redux';
5
 
5
 
6
-import { translate } from '../../base/i18n';
7
-import { openDeviceSelectionDialog } from '../../device-selection';
6
+import { translate } from '../../../base/i18n';
7
+import { openDeviceSelectionDialog } from '../../../device-selection';
8
 
8
 
9
 /**
9
 /**
10
  * Implements a React {@link Component} which displays a button for opening the
10
  * Implements a React {@link Component} which displays a button for opening the

react/features/settings-menu/components/LanguageSelectDropdown.web.js → react/features/settings/components/web/LanguageSelectDropdown.js 查看文件

5
 import PropTypes from 'prop-types';
5
 import PropTypes from 'prop-types';
6
 import React, { Component } from 'react';
6
 import React, { Component } from 'react';
7
 
7
 
8
-import { DEFAULT_LANGUAGE, LANGUAGES, translate } from '../../base/i18n';
8
+import { DEFAULT_LANGUAGE, LANGUAGES, translate } from '../../../base/i18n';
9
 
9
 
10
 /**
10
 /**
11
  * Implements a React {@link Component} which displays a dropdown for changing
11
  * Implements a React {@link Component} which displays a dropdown for changing

react/features/settings-menu/components/ModeratorCheckboxes.web.js → react/features/settings/components/web/ModeratorCheckboxes.js 查看文件

2
 import React, { Component } from 'react';
2
 import React, { Component } from 'react';
3
 import { connect } from 'react-redux';
3
 import { connect } from 'react-redux';
4
 
4
 
5
-import { setFollowMe, setStartMutedPolicy } from '../../base/conference';
6
-import { translate } from '../../base/i18n';
5
+import { setFollowMe, setStartMutedPolicy } from '../../../base/conference';
6
+import { translate } from '../../../base/i18n';
7
 
7
 
8
 /**
8
 /**
9
  * Implements a React {@link Component} which displays checkboxes for enabling
9
  * Implements a React {@link Component} which displays checkboxes for enabling

react/features/settings-menu/components/SettingsMenu.web.js → react/features/settings/components/web/SettingsMenu.js 查看文件

2
 import React, { Component } from 'react';
2
 import React, { Component } from 'react';
3
 import { connect } from 'react-redux';
3
 import { connect } from 'react-redux';
4
 
4
 
5
-import { translate } from '../../base/i18n';
6
-import { getLocalParticipant, PARTICIPANT_ROLE } from '../../base/participants';
5
+import { translate } from '../../../base/i18n';
6
+import {
7
+    getLocalParticipant,
8
+    PARTICIPANT_ROLE
9
+} from '../../../base/participants';
7
 
10
 
8
 import DeviceSelectionButton from './DeviceSelectionButton';
11
 import DeviceSelectionButton from './DeviceSelectionButton';
9
 import LanguageSelectDropdown from './LanguageSelectDropdown';
12
 import LanguageSelectDropdown from './LanguageSelectDropdown';

react/features/settings-menu/components/index.js → react/features/settings/components/web/index.js 查看文件


react/features/app-settings/functions.js → react/features/settings/functions.js 查看文件

14
 
14
 
15
     if (url) {
15
     if (url) {
16
         url = url.replace(/\s/g, '').toLowerCase();
16
         url = url.replace(/\s/g, '').toLowerCase();
17
+
17
         const urlRegExp = new RegExp('^(\\w+://)?(.+)$');
18
         const urlRegExp = new RegExp('^(\\w+://)?(.+)$');
18
         const urlComponents = urlRegExp.exec(url);
19
         const urlComponents = urlRegExp.exec(url);
19
 
20
 
21
             url = `https://${urlComponents[2]}`;
22
             url = `https://${urlComponents[2]}`;
22
         }
23
         }
23
 
24
 
24
-        const parsedURI
25
-            = parseStandardURIString(url);
25
+        const parsedURI = parseStandardURIString(url);
26
 
26
 
27
         if (!parsedURI.host) {
27
         if (!parsedURI.host) {
28
             return null;
28
             return null;

react/features/app-settings/index.js → react/features/settings/index.js 查看文件

1
 export * from './actions';
1
 export * from './actions';
2
+export * from './actionTypes';
2
 export * from './components';
3
 export * from './components';
3
 
4
 
5
+import './middleware';
4
 import './reducer';
6
 import './reducer';

react/features/app-settings/middleware.js → react/features/settings/middleware.js 查看文件

3
 import { SET_ROOM } from '../base/conference';
3
 import { SET_ROOM } from '../base/conference';
4
 import { MiddlewareRegistry } from '../base/redux';
4
 import { MiddlewareRegistry } from '../base/redux';
5
 
5
 
6
-import { hideAppSettings } from './actions';
6
+import { setSettingsViewVisible } from './actions';
7
 
7
 
8
 /**
8
 /**
9
- * The Redux middleware to trigger settings screen show or hide
10
- * when necessary.
9
+ * The redux middleware to set the visibility of {@link SettingsView}.
11
  *
10
  *
12
- * @param {Store} store - The Redux store.
11
+ * @param {Store} store - The redux store.
13
  * @returns {Function}
12
  * @returns {Function}
14
  */
13
  */
15
 MiddlewareRegistry.register(store => next => action => {
14
 MiddlewareRegistry.register(store => next => action => {
16
     switch (action.type) {
15
     switch (action.type) {
17
     case SET_ROOM:
16
     case SET_ROOM:
18
-        return _closeAppSettings(store, next, action);
17
+        return _hideSettingsView(store, next, action);
19
     }
18
     }
20
 
19
 
21
     return next(action);
20
     return next(action);
22
 });
21
 });
23
 
22
 
24
 /**
23
 /**
25
- * Hides the settings screen.
24
+ * Hides {@link SettingsView}.
26
  *
25
  *
27
  * @param {Store} store - The redux store.
26
  * @param {Store} store - The redux store.
28
- * @param {Dispatch} next - The redux dispatch function.
27
+ * @param {Dispatch} next - The redux {@code dispatch} function.
29
  * @param {Action} action - The redux action.
28
  * @param {Action} action - The redux action.
30
  * @private
29
  * @private
31
  * @returns {Object} The new state.
30
  * @returns {Object} The new state.
32
  */
31
  */
33
-function _closeAppSettings({ dispatch }, next, action) {
34
-    dispatch(hideAppSettings());
32
+function _hideSettingsView({ dispatch }, next, action) {
33
+    dispatch(setSettingsViewVisible(false));
35
 
34
 
36
     return next(action);
35
     return next(action);
37
 }
36
 }

+ 17
- 0
react/features/settings/reducer.js 查看文件

1
+// @flow
2
+
3
+import { ReducerRegistry } from '../base/redux';
4
+
5
+import { SET_SETTINGS_VIEW_VISIBLE } from './actionTypes';
6
+
7
+ReducerRegistry.register('features/settings', (state = {}, action) => {
8
+    switch (action.type) {
9
+    case SET_SETTINGS_VIEW_VISIBLE:
10
+        return {
11
+            ...state,
12
+            visible: action.visible
13
+        };
14
+    }
15
+
16
+    return state;
17
+});

+ 8
- 2
react/features/welcome/actionTypes.js 查看文件

1
 /**
1
 /**
2
- * Action type to signal the need to hide or show the side bar.
2
+ * The type of the (redux) action which sets the visibility of
3
+ * {@link WelcomePageSideBar}.
4
+ *
5
+ * {
6
+ *     type: SET_SIDEBAR_VISIBLE,
7
+ *     visible: boolean
8
+ * }
3
  */
9
  */
4
-export const SET_SIDEBAR_VISIBILITY = Symbol('SET_SIDEBAR_VISIBILITY');
10
+export const SET_SIDEBAR_VISIBLE = Symbol('SET_SIDEBAR_VISIBLE');

+ 9
- 8
react/features/welcome/actions.js 查看文件

1
 // @flow
1
 // @flow
2
 
2
 
3
-import { SET_SIDEBAR_VISIBILITY } from './actionTypes';
3
+import { SET_SIDEBAR_VISIBLE } from './actionTypes';
4
 
4
 
5
 /**
5
 /**
6
- * Redux action to hide or show the status bar.
6
+ * Sets the visibility of {@link WelcomePageSideBar}.
7
  *
7
  *
8
- * @param {boolean} visible - The new value of the visibility.
8
+ * @param {boolean} visible - If the {@code WelcomePageSideBar} is to be made
9
+ * visible, {@code true}; otherwise, {@code false}.
9
  * @returns {{
10
  * @returns {{
10
- *     type: SET_SIDEBAR_VISIBILITY,
11
- *     sideBarVisible: boolean
11
+ *     type: SET_SIDEBAR_VISIBLE,
12
+ *     visible: boolean
12
  * }}
13
  * }}
13
  */
14
  */
14
-export function setSideBarVisibility(visible: boolean) {
15
+export function setSideBarVisible(visible: boolean) {
15
     return {
16
     return {
16
-        type: SET_SIDEBAR_VISIBILITY,
17
-        sideBarVisible: visible
17
+        type: SET_SIDEBAR_VISIBLE,
18
+        visible
18
     };
19
     };
19
 }
20
 }

+ 4
- 3
react/features/welcome/components/SideBarItem.js 查看文件

3
 import React, { Component } from 'react';
3
 import React, { Component } from 'react';
4
 import { Linking, Text, TouchableOpacity, View } from 'react-native';
4
 import { Linking, Text, TouchableOpacity, View } from 'react-native';
5
 
5
 
6
-import styles from './styles';
7
-
8
 import { Icon } from '../../base/font-icons';
6
 import { Icon } from '../../base/font-icons';
9
 import { translate } from '../../base/i18n';
7
 import { translate } from '../../base/i18n';
10
 
8
 
9
+import styles from './styles';
10
+
11
 type Props = {
11
 type Props = {
12
 
12
 
13
     /**
13
     /**
43
 class SideBarItem extends Component<Props> {
43
 class SideBarItem extends Component<Props> {
44
 
44
 
45
     /**
45
     /**
46
-     * Contructor of the SideBarItem Component.
46
+     * Initializes a new {@code SideBarItem} instance.
47
      *
47
      *
48
      * @inheritdoc
48
      * @inheritdoc
49
      */
49
      */
50
     constructor(props: Props) {
50
     constructor(props: Props) {
51
         super(props);
51
         super(props);
52
 
52
 
53
+        // Bind event handlers so they are only bound once per instance.
53
         this._onOpenURL = this._onOpenURL.bind(this);
54
         this._onOpenURL = this._onOpenURL.bind(this);
54
     }
55
     }
55
 
56
 

+ 17
- 23
react/features/welcome/components/WelcomePage.native.js 查看文件

11
 } from 'react-native';
11
 } from 'react-native';
12
 import { connect } from 'react-redux';
12
 import { connect } from 'react-redux';
13
 
13
 
14
-import { AppSettings } from '../../app-settings';
15
 import { translate } from '../../base/i18n';
14
 import { translate } from '../../base/i18n';
16
 import { Icon } from '../../base/font-icons';
15
 import { Icon } from '../../base/font-icons';
17
 import { MEDIA_TYPE } from '../../base/media';
16
 import { MEDIA_TYPE } from '../../base/media';
18
 import { updateProfile } from '../../base/profile';
17
 import { updateProfile } from '../../base/profile';
19
-import {
20
-    LoadingIndicator,
21
-    Header,
22
-    Text
23
-} from '../../base/react';
24
-import { ColorPalette, PlatformElements } from '../../base/styles';
18
+import { LoadingIndicator, Header, Text } from '../../base/react';
19
+import { ColorPalette } from '../../base/styles';
25
 import {
20
 import {
26
     createDesiredLocalTracks,
21
     createDesiredLocalTracks,
27
     destroyLocalTracks
22
     destroyLocalTracks
28
 } from '../../base/tracks';
23
 } from '../../base/tracks';
29
 import { RecentList } from '../../recent-list';
24
 import { RecentList } from '../../recent-list';
30
-
31
-import { setSideBarVisibility } from '../actions';
25
+import { SettingsView } from '../../settings';
32
 
26
 
33
 import { AbstractWelcomePage, _mapStateToProps } from './AbstractWelcomePage';
27
 import { AbstractWelcomePage, _mapStateToProps } from './AbstractWelcomePage';
28
+import { setSideBarVisible } from '../actions';
34
 import LocalVideoTrackUnderlay from './LocalVideoTrackUnderlay';
29
 import LocalVideoTrackUnderlay from './LocalVideoTrackUnderlay';
35
 import styles, {
30
 import styles, {
36
     PLACEHOLDER_TEXT_COLOR,
31
     PLACEHOLDER_TEXT_COLOR,
62
 
57
 
63
         this.state.hintBoxAnimation = new Animated.Value(0);
58
         this.state.hintBoxAnimation = new Animated.Value(0);
64
 
59
 
60
+        // Bind event handlers so they are only bound once per instance.
65
         this._getHintBoxStyle = this._getHintBoxStyle.bind(this);
61
         this._getHintBoxStyle = this._getHintBoxStyle.bind(this);
66
         this._onFieldFocusChange = this._onFieldFocusChange.bind(this);
62
         this._onFieldFocusChange = this._onFieldFocusChange.bind(this);
67
         this._onShowSideBar = this._onShowSideBar.bind(this);
63
         this._onShowSideBar = this._onShowSideBar.bind(this);
97
      * @returns {ReactElement}
93
      * @returns {ReactElement}
98
      */
94
      */
99
     render() {
95
     render() {
96
+        const { buttonStyle, pageStyle, textStyle } = Header;
100
         const { t, _profile } = this.props;
97
         const { t, _profile } = this.props;
101
 
98
 
102
         return (
99
         return (
103
             <LocalVideoTrackUnderlay style = { styles.welcomePage }>
100
             <LocalVideoTrackUnderlay style = { styles.welcomePage }>
104
-                <View style = { PlatformElements.page }>
101
+                <View style = { pageStyle }>
105
                     <Header style = { styles.header }>
102
                     <Header style = { styles.header }>
106
                         <TouchableOpacity onPress = { this._onShowSideBar } >
103
                         <TouchableOpacity onPress = { this._onShowSideBar } >
107
                             <Icon
104
                             <Icon
108
                                 name = 'menu'
105
                                 name = 'menu'
109
-                                style = { PlatformElements.headerButton } />
106
+                                style = { buttonStyle } />
110
                         </TouchableOpacity>
107
                         </TouchableOpacity>
111
                         <View style = { styles.audioVideoSwitchContainer }>
108
                         <View style = { styles.audioVideoSwitchContainer }>
112
-                            <Text style = { PlatformElements.headerText } >
113
-                                { t('welcomepage.videoEnabledLabel') }
109
+                            <Text style = { textStyle } >
110
+                                { t('welcomepage.audioVideoSwitch.video') }
114
                             </Text>
111
                             </Text>
115
                             <Switch
112
                             <Switch
116
                                 onTintColor = { SWITCH_UNDER_COLOR }
113
                                 onTintColor = { SWITCH_UNDER_COLOR }
118
                                 style = { styles.audioVideoSwitch }
115
                                 style = { styles.audioVideoSwitch }
119
                                 thumbTintColor = { SWITCH_THUMB_COLOR }
116
                                 thumbTintColor = { SWITCH_THUMB_COLOR }
120
                                 value = { _profile.startAudioOnly } />
117
                                 value = { _profile.startAudioOnly } />
121
-                            <Text style = { PlatformElements.headerText } >
122
-                                { t('welcomepage.audioOnlyLabel') }
118
+                            <Text style = { textStyle } >
119
+                                { t('welcomepage.audioVideoSwitch.audio') }
123
                             </Text>
120
                             </Text>
124
                         </View>
121
                         </View>
125
                     </Header>
122
                     </Header>
145
                         }
142
                         }
146
                         <RecentList disabled = { this.state._fieldFocused } />
143
                         <RecentList disabled = { this.state._fieldFocused } />
147
                     </SafeAreaView>
144
                     </SafeAreaView>
148
-                    <AppSettings />
145
+                    <SettingsView />
149
                 </View>
146
                 </View>
150
                 <WelcomePageSideBar />
147
                 <WelcomePageSideBar />
151
             </LocalVideoTrackUnderlay>
148
             </LocalVideoTrackUnderlay>
204
      */
201
      */
205
     _onShowSideBar() {
202
     _onShowSideBar() {
206
         Keyboard.dismiss();
203
         Keyboard.dismiss();
207
-        this.props.dispatch(setSideBarVisibility(true));
204
+        this.props.dispatch(setSideBarVisible(true));
208
     }
205
     }
209
 
206
 
210
     /**
207
     /**
234
             const { t } = this.props;
231
             const { t } = this.props;
235
 
232
 
236
             return (
233
             return (
237
-                <Animated.View
238
-                    style = { this._getHintBoxStyle() }>
234
+                <Animated.View style = { this._getHintBoxStyle() }>
239
                     <View style = { styles.hintTextContainer } >
235
                     <View style = { styles.hintTextContainer } >
240
                         <Text>
236
                         <Text>
241
-                            { t('welcomepage.hintText') }
237
+                            { t('welcomepage.roomnameHint') }
242
                         </Text>
238
                         </Text>
243
                     </View>
239
                     </View>
244
                     <View style = { styles.hintButtonContainer } >
240
                     <View style = { styles.hintButtonContainer } >
245
-                        {
246
-                            this._renderJoinButton()
247
-                        }
241
+                        { this._renderJoinButton() }
248
                     </View>
242
                     </View>
249
                 </Animated.View>
243
                 </Animated.View>
250
             );
244
             );

+ 11
- 11
react/features/welcome/components/WelcomePageSideBar.native.js 查看文件

4
 import { SafeAreaView, ScrollView, Text } from 'react-native';
4
 import { SafeAreaView, ScrollView, Text } from 'react-native';
5
 import { connect } from 'react-redux';
5
 import { connect } from 'react-redux';
6
 
6
 
7
-import SideBarItem from './SideBarItem';
8
-import styles from './styles';
9
-
10
-import { setSideBarVisibility } from '../actions';
11
-
12
-import { showAppSettings } from '../../app-settings';
13
 import {
7
 import {
14
     Avatar,
8
     Avatar,
15
     getAvatarURL,
9
     getAvatarURL,
20
     Header,
14
     Header,
21
     SideBar
15
     SideBar
22
 } from '../../base/react';
16
 } from '../../base/react';
17
+import { setSettingsViewVisible } from '../../settings';
18
+
19
+import { setSideBarVisible } from '../actions';
20
+import SideBarItem from './SideBarItem';
21
+import styles from './styles';
23
 
22
 
24
 /**
23
 /**
25
  * The URL at which the privacy policy is available to the user.
24
  * The URL at which the privacy policy is available to the user.
71
     constructor(props) {
70
     constructor(props) {
72
         super(props);
71
         super(props);
73
 
72
 
73
+        // Bind event handlers so they are only bound once per instance.
74
         this._onHideSideBar = this._onHideSideBar.bind(this);
74
         this._onHideSideBar = this._onHideSideBar.bind(this);
75
         this._onOpenSettings = this._onOpenSettings.bind(this);
75
         this._onOpenSettings = this._onOpenSettings.bind(this);
76
     }
76
     }
122
     _onHideSideBar: () => void;
122
     _onHideSideBar: () => void;
123
 
123
 
124
     /**
124
     /**
125
-     * Invoked when the sidebar has closed itslef (e.g. overlay pressed).
125
+     * Invoked when the sidebar has closed itself (e.g. overlay pressed).
126
      *
126
      *
127
      * @private
127
      * @private
128
      * @returns {void}
128
      * @returns {void}
129
      */
129
      */
130
     _onHideSideBar() {
130
     _onHideSideBar() {
131
-        this.props.dispatch(setSideBarVisibility(false));
131
+        this.props.dispatch(setSideBarVisible(false));
132
     }
132
     }
133
 
133
 
134
     _onOpenSettings: () => void;
134
     _onOpenSettings: () => void;
135
 
135
 
136
     /**
136
     /**
137
-     * Opens the settings screen.
137
+     * Shows the {@link SettingsView}.
138
      *
138
      *
139
      * @private
139
      * @private
140
      * @returns {void}
140
      * @returns {void}
142
     _onOpenSettings() {
142
     _onOpenSettings() {
143
         const { dispatch } = this.props;
143
         const { dispatch } = this.props;
144
 
144
 
145
-        dispatch(setSideBarVisibility(false));
146
-        dispatch(showAppSettings());
145
+        dispatch(setSideBarVisible(false));
146
+        dispatch(setSettingsViewVisible(true));
147
     }
147
     }
148
 }
148
 }
149
 
149
 

+ 9
- 9
react/features/welcome/components/styles.js 查看文件

98
      */
98
      */
99
     hintButtonContainer: {
99
     hintButtonContainer: {
100
         flexDirection: 'row',
100
         flexDirection: 'row',
101
-        justifyContent: 'flex-end'
102
-    },
103
-
104
-    /**
105
-     * Container for the text on the hint box.
106
-     */
107
-    hintTextContainer: {
108
-        marginBottom: 2 * BoxModel.margin
101
+        justifyContent: 'center'
109
     },
102
     },
110
 
103
 
111
     /**
104
     /**
123
         paddingVertical: 2 * BoxModel.padding
116
         paddingVertical: 2 * BoxModel.padding
124
     },
117
     },
125
 
118
 
119
+    /**
120
+     * Container for the text on the hint box.
121
+     */
122
+    hintTextContainer: {
123
+        marginBottom: 2 * BoxModel.margin
124
+    },
125
+
126
     /**
126
     /**
127
      * Container for the items in the side bar.
127
      * Container for the items in the side bar.
128
      */
128
      */
142
     },
142
     },
143
 
143
 
144
     /**
144
     /**
145
-     * Top level screen style
145
+     * Top-level screen style.
146
      */
146
      */
147
     page: {
147
     page: {
148
         flex: 1,
148
         flex: 1,

+ 3
- 3
react/features/welcome/index.js 查看文件

1
-import './reducer';
2
-import './route';
3
-
4
 export * from './components';
1
 export * from './components';
5
 export * from './functions';
2
 export * from './functions';
3
+
4
+import './reducer';
5
+import './route';

+ 15
- 18
react/features/welcome/reducer.js 查看文件

1
-import { ReducerRegistry } from '../base/redux';
2
-import { SET_SIDEBAR_VISIBILITY } from './actionTypes';
1
+// @flow
3
 
2
 
4
-const DEFAULT_STATE = {
5
-    sideBarVisible: false
6
-};
3
+import { ReducerRegistry } from '../base/redux';
4
+import { SET_SIDEBAR_VISIBLE } from './actionTypes';
7
 
5
 
8
 /**
6
 /**
9
- * Reduces the Redux actions of the feature features/recording.
7
+ * Reduces redux actions for the purposes of {@code features/welcome}.
10
  */
8
  */
11
-ReducerRegistry.register('features/welcome',
12
-    (state = DEFAULT_STATE, action) => {
13
-        switch (action.type) {
14
-        case SET_SIDEBAR_VISIBILITY:
15
-            return {
16
-                ...state,
17
-                sideBarVisible: action.sideBarVisible
18
-            };
9
+ReducerRegistry.register('features/welcome', (state = {}, action) => {
10
+    switch (action.type) {
11
+    case SET_SIDEBAR_VISIBLE:
12
+        return {
13
+            ...state,
14
+            sideBarVisible: action.visible
15
+        };
19
 
16
 
20
-        default:
21
-            return state;
22
-        }
23
-    });
17
+    default:
18
+        return state;
19
+    }
20
+});

正在加载...
取消
保存