瀏覽代碼

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,14 +33,14 @@ import java.net.URL;
33 33
 
34 34
 /**
35 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 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 40
  * instance gives us access to a view which displays the welcome page and the
41 41
  * conference itself. All lifetime methods associated with this Activity are
42 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 45
 public class JitsiMeetActivity extends AppCompatActivity {
46 46
     /**

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

@@ -47,16 +47,18 @@
47 47
     },
48 48
     "welcomepage":{
49 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 54
         "go": "GO",
52
-        "hintText": "Enter a room name you want to join to, or simply create a new room name, eg. MeetingWithJohn",
53 55
         "join": "JOIN",
54 56
         "privacy": "Privacy",
55 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 59
         "sendFeedback": "Send feedback",
57 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 63
     "startupoverlay": {
62 64
         "policyText": " ",
@@ -503,7 +505,7 @@
503 505
         "title": "Call info",
504 506
         "tooltip": "Get access info about the meeting"
505 507
     },
506
-    "settingsScreen": {
508
+    "settingsView": {
507 509
         "alertOk": "OK",
508 510
         "alertTitle": "Warning",
509 511
         "alertURLText": "The entered server URL is invalid",
@@ -515,8 +517,5 @@
515 517
         "serverURL": "Server URL",
516 518
         "startWithAudioMuted": "Start with audio muted",
517 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,17 +1,18 @@
1 1
 /* global $, APP, interfaceConfig */
2 2
 
3 3
 /* eslint-disable no-unused-vars */
4
+
4 5
 import React from 'react';
5 6
 import ReactDOM from 'react-dom';
6 7
 import { I18nextProvider } from 'react-i18next';
7 8
 import { Provider } from 'react-redux';
8 9
 
9 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 12
 import UIUtil from '../../util/UIUtil';
14 13
 
14
+/* eslint-enable no-unused-vars */
15
+
15 16
 export default {
16 17
     init() {
17 18
         const settingsMenuContainer = document.createElement('div');
@@ -31,8 +32,7 @@ export default {
31 32
         ReactDOM.render(
32 33
             <Provider store = { APP.store }>
33 34
                 <I18nextProvider i18n = { i18next }>
34
-                    <SettingsMenu
35
-                        { ...props } />
35
+                    <SettingsMenu { ...props } />
36 36
                 </I18nextProvider>
37 37
             </Provider>,
38 38
             settingsMenuContainer

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

@@ -76,13 +76,13 @@ export const VIDEO_MUTE = 'video.mute';
76 76
  * @returns {Object} The event in a format suitable for sending via
77 77
  * sendAnalytics.
78 78
  */
79
-export const createApiEvent = function(action, attributes = {}) {
79
+export function createApiEvent(action, attributes = {}) {
80 80
     return {
81 81
         action,
82 82
         attributes,
83 83
         source: 'jitsi-meet-api'
84 84
     };
85
-};
85
+}
86 86
 
87 87
 /**
88 88
  * Creates an event which indicates that the audio-only mode has been changed.
@@ -91,11 +91,11 @@ export const createApiEvent = function(action, attributes = {}) {
91 91
  * @returns {Object} The event in a format suitable for sending via
92 92
  * sendAnalytics.
93 93
  */
94
-export const createAudioOnlyChangedEvent = function(enabled) {
94
+export function createAudioOnlyChangedEvent(enabled) {
95 95
     return {
96 96
         action: `audio.only.${enabled ? 'enabled' : 'disabled'}`
97 97
     };
98
-};
98
+}
99 99
 
100 100
 /**
101 101
  * Creates an event which indicates that a device was changed.
@@ -106,7 +106,7 @@ export const createAudioOnlyChangedEvent = function(enabled) {
106 106
  * @returns {Object} The event in a format suitable for sending via
107 107
  * sendAnalytics.
108 108
  */
109
-export const createDeviceChangedEvent = function(mediaType, deviceType) {
109
+export function createDeviceChangedEvent(mediaType, deviceType) {
110 110
     return {
111 111
         action: 'device.changed',
112 112
         attributes: {
@@ -114,7 +114,7 @@ export const createDeviceChangedEvent = function(mediaType, deviceType) {
114 114
             'media_type': mediaType
115 115
         }
116 116
     };
117
-};
117
+}
118 118
 
119 119
 /**
120 120
  * Creates an event which specifies that the feedback dialog has been opened.
@@ -122,11 +122,11 @@ export const createDeviceChangedEvent = function(mediaType, deviceType) {
122 122
  * @returns {Object} The event in a format suitable for sending via
123 123
  * sendAnalytics.
124 124
  */
125
-export const createFeedbackOpenEvent = function() {
125
+export function createFeedbackOpenEvent() {
126 126
     return {
127 127
         action: 'feedback.opened'
128 128
     };
129
-};
129
+}
130 130
 
131 131
 /**
132 132
  * Creates an event which indicates that the invite dialog was closed. This is
@@ -136,11 +136,11 @@ export const createFeedbackOpenEvent = function() {
136 136
  * @returns {Object} The event in a format suitable for sending via
137 137
  * sendAnalytics.
138 138
  */
139
-export const createInviteDialogClosedEvent = function() {
139
+export function createInviteDialogClosedEvent() {
140 140
     return {
141 141
         action: 'invite.dialog.closed'
142 142
     };
143
-};
143
+}
144 144
 
145 145
 /**
146 146
  * Creates a "page reload" event.
@@ -152,17 +152,16 @@ export const createInviteDialogClosedEvent = function() {
152 152
  * @returns {Object} The event in a format suitable for sending via
153 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 167
  * Creates a "pinned" or "unpinned" event.
@@ -173,17 +172,16 @@ export const createPageReloadScheduledEvent
173 172
  * @returns {Object} The event in a format suitable for sending via
174 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 187
  * Creates an event which indicates that a button in the profile panel was
@@ -194,16 +192,15 @@ export const createPinnedEvent
194 192
  * @returns {Object} The event in a format suitable for sending via
195 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 206
  * Creates an event which indicates that a specific button on one of the
@@ -215,14 +212,14 @@ export const createProfilePanelButtonEvent
215 212
  * @returns {Object} The event in a format suitable for sending via
216 213
  * sendAnalytics.
217 214
  */
218
-export const createRecordingDialogEvent = function(dialogName, buttonName) {
215
+export function createRecordingDialogEvent(dialogName, buttonName) {
219 216
     return {
220 217
         action: 'clicked',
221 218
         actionSubject: buttonName,
222 219
         source: `${dialogName}.recording.dialog`,
223 220
         type: TYPE_UI
224 221
     };
225
-};
222
+}
226 223
 
227 224
 /**
228 225
  * Creates an event which specifies that the "confirm" button on the remote
@@ -233,7 +230,7 @@ export const createRecordingDialogEvent = function(dialogName, buttonName) {
233 230
  * @returns {Object} The event in a format suitable for sending via
234 231
  * sendAnalytics.
235 232
  */
236
-export const createRemoteMuteConfirmedEvent = function(participantId) {
233
+export function createRemoteMuteConfirmedEvent(participantId) {
237 234
     return {
238 235
         action: 'clicked',
239 236
         actionSubject: 'remote.mute.dialog.confirm.button',
@@ -243,7 +240,7 @@ export const createRemoteMuteConfirmedEvent = function(participantId) {
243 240
         source: 'remote.mute.dialog',
244 241
         type: TYPE_UI
245 242
     };
246
-};
243
+}
247 244
 
248 245
 /**
249 246
  * Creates an event which indicates that one of the buttons in the "remote
@@ -254,16 +251,15 @@ export const createRemoteMuteConfirmedEvent = function(participantId) {
254 251
  * @returns {Object} The event in a format suitable for sending via
255 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 265
  * Creates an event indicating that an action related to screen sharing
@@ -273,12 +269,12 @@ export const createRemoteVideoMenuButtonEvent
273 269
  * @returns {Object} The event in a format suitable for sending via
274 270
  * sendAnalytics.
275 271
  */
276
-export const createScreenSharingEvent = function(action) {
272
+export function createScreenSharingEvent(action) {
277 273
     return {
278 274
         action,
279 275
         actionSubject: 'screen.sharing'
280 276
     };
281
-};
277
+}
282 278
 
283 279
 /**
284 280
  * The local participant failed to send a "selected endpoint" message to the
@@ -288,7 +284,7 @@ export const createScreenSharingEvent = function(action) {
288 284
  * @returns {Object} The event in a format suitable for sending via
289 285
  * sendAnalytics.
290 286
  */
291
-export const createSelectParticipantFailedEvent = function(error) {
287
+export function createSelectParticipantFailedEvent(error) {
292 288
     const event = {
293 289
         action: 'select.participant.failed'
294 290
     };
@@ -298,7 +294,7 @@ export const createSelectParticipantFailedEvent = function(error) {
298 294
     }
299 295
 
300 296
     return event;
301
-};
297
+}
302 298
 
303 299
 /**
304 300
  * Creates an event associated with the "shared video" feature.
@@ -308,13 +304,13 @@ export const createSelectParticipantFailedEvent = function(error) {
308 304
  * @returns {Object} The event in a format suitable for sending via
309 305
  * sendAnalytics.
310 306
  */
311
-export const createSharedVideoEvent = function(action, attributes = {}) {
307
+export function createSharedVideoEvent(action, attributes = {}) {
312 308
     return {
313 309
         action,
314 310
         attributes,
315 311
         actionSubject: 'shared.video'
316 312
     };
317
-};
313
+}
318 314
 
319 315
 /**
320 316
  * Creates an event associated with a shortcut being pressed, released or
@@ -331,17 +327,19 @@ export const createSharedVideoEvent = function(action, attributes = {}) {
331 327
  * @returns {Object} The event in a format suitable for sending via
332 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 345
  * Creates an event which indicates the "start audio only" configuration.
@@ -350,14 +348,14 @@ export const createShortcutEvent
350 348
  * @returns {Object} The event in a format suitable for sending via
351 349
  * sendAnalytics.
352 350
  */
353
-export const createStartAudioOnlyEvent = function(audioOnly) {
351
+export function createStartAudioOnlyEvent(audioOnly) {
354 352
     return {
355 353
         action: 'start.audio.only',
356 354
         attributes: {
357 355
             enabled: audioOnly
358 356
         }
359 357
     };
360
-};
358
+}
361 359
 
362 360
 /**
363 361
  * Creates an event which indicates the "start muted" configuration.
@@ -372,17 +370,19 @@ export const createStartAudioOnlyEvent = function(audioOnly) {
372 370
  * @returns {Object} The event in a format suitable for sending via
373 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 388
  * Creates an event which indicates the delay for switching between simulcast
@@ -392,12 +392,12 @@ export const createStartMutedConfigurationEvent
392 392
  * @returns {Object} The event in a format suitable for sending via
393 393
  * sendAnalytics.
394 394
  */
395
-export const createStreamSwitchDelayEvent = function(attributes) {
395
+export function createStreamSwitchDelayEvent(attributes) {
396 396
     return {
397 397
         action: 'stream.switch.delay',
398 398
         attributes
399 399
     };
400
-};
400
+}
401 401
 
402 402
 /**
403 403
  * Automatically changing the mute state of a media track in order to match
@@ -409,7 +409,7 @@ export const createStreamSwitchDelayEvent = function(attributes) {
409 409
  * @returns {Object} The event in a format suitable for sending via
410 410
  * sendAnalytics.
411 411
  */
412
-export const createSyncTrackStateEvent = function(mediaType, muted) {
412
+export function createSyncTrackStateEvent(mediaType, muted) {
413 413
     return {
414 414
         action: 'sync.track.state',
415 415
         attributes: {
@@ -417,7 +417,7 @@ export const createSyncTrackStateEvent = function(mediaType, muted) {
417 417
             muted
418 418
         }
419 419
     };
420
-};
420
+}
421 421
 
422 422
 /**
423 423
  * Creates an event associated with a toolbar button being clicked/pressed. By
@@ -431,7 +431,7 @@ export const createSyncTrackStateEvent = function(mediaType, muted) {
431 431
  * @returns {Object} The event in a format suitable for sending via
432 432
  * sendAnalytics.
433 433
  */
434
-export const createToolbarEvent = function(buttonName, attributes = {}) {
434
+export function createToolbarEvent(buttonName, attributes = {}) {
435 435
     return {
436 436
         action: 'clicked',
437 437
         actionSubject: buttonName,
@@ -439,7 +439,7 @@ export const createToolbarEvent = function(buttonName, attributes = {}) {
439 439
         source: 'toolbar.button',
440 440
         type: TYPE_UI
441 441
     };
442
-};
442
+}
443 443
 
444 444
 /**
445 445
  * Creates an event which indicates that a local track was muted.
@@ -452,7 +452,7 @@ export const createToolbarEvent = function(buttonName, attributes = {}) {
452 452
  * @returns {Object} The event in a format suitable for sending via
453 453
  * sendAnalytics.
454 454
  */
455
-export const createTrackMutedEvent = function(mediaType, reason, muted = true) {
455
+export function createTrackMutedEvent(mediaType, reason, muted = true) {
456 456
     return {
457 457
         action: 'track.muted',
458 458
         attributes: {
@@ -461,7 +461,7 @@ export const createTrackMutedEvent = function(mediaType, reason, muted = true) {
461 461
             reason
462 462
         }
463 463
     };
464
-};
464
+}
465 465
 
466 466
 /**
467 467
  * Creates an event for an action on the welcome page.
@@ -472,12 +472,11 @@ export const createTrackMutedEvent = function(mediaType, reason, muted = true) {
472 472
  * @returns {Object} The event in a format suitable for sending via
473 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,19 +0,0 @@
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,29 +0,0 @@
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,238 +0,0 @@
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 +0,0 @@
1
-export { default as AppSettings } from './AppSettings';

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

@@ -1,3 +0,0 @@
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,33 +0,0 @@
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,31 +0,0 @@
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,17 +125,20 @@ function _connectionEstablished({ dispatch }, next, action) {
125 125
  */
126 126
 function _conferenceFailedOrLeft({ dispatch, getState }, next, action) {
127 127
     const result = next(action);
128
+
128 129
     const state = getState();
129 130
     const { audioOnly } = state['features/base/conference'];
130 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 142
         sendAnalytics(createAudioOnlyChangedEvent(true));
140 143
         logger.log('Audio only enabled');
141 144
         dispatch(setAudioOnly(true));

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

@@ -32,7 +32,36 @@ type Props = {
32 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 66
      * @inheritdoc
38 67
      */
@@ -77,8 +106,8 @@ export default class Header extends Component<Props> {
77 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 111
      * Note: This is a workaround for iOS 10 (and older) devices only to fix
83 112
      * usability, but it doesn't take orientation into account, so unnecessary
84 113
      * padding is rendered in some cases.
@@ -99,5 +128,4 @@ export default class Header extends Component<Props> {
99 128
 
100 129
         return null;
101 130
     }
102
-
103 131
 }

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

@@ -1,4 +1,4 @@
1
-/* @flow */
1
+// @flow
2 2
 
3 3
 import React, { Component } from 'react';
4 4
 import {
@@ -10,9 +10,8 @@ import {
10 10
 
11 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 16
 type Props = {
18 17
 
@@ -38,17 +37,20 @@ type Props = {
38 37
     show: boolean
39 38
 }
40 39
 
40
+/**
41
+ * The type of the React {@code Component} state of {@link SideBar}.
42
+ */
41 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 56
      * The native animation object.
@@ -63,7 +65,7 @@ export default class SideBar extends Component<Props, State> {
63 65
     _mounted: boolean;
64 66
 
65 67
     /**
66
-     * Component's contructor.
68
+     * Initializes a new {@code SideBar} instance.
67 69
      *
68 70
      * @inheritdoc
69 71
      */
@@ -71,15 +73,15 @@ export default class SideBar extends Component<Props, State> {
71 73
         super(props);
72 74
 
73 75
         this.state = {
74
-            showSideBar: false,
75 76
             showOverlay: false,
77
+            showSideBar: false,
76 78
             sliderAnimation: new Animated.Value(-SIDEBAR_WIDTH)
77 79
         };
78 80
 
79
-        this._setShow = this._setShow.bind(this);
80
-
81 81
         this._getContainerStyle = this._getContainerStyle.bind(this);
82 82
         this._onHideMenu = this._onHideMenu.bind(this);
83
+        this._setShow = this._setShow.bind(this);
84
+
83 85
         this._setShow(props.show);
84 86
     }
85 87
 
@@ -171,8 +173,8 @@ export default class SideBar extends Component<Props, State> {
171 173
     /**
172 174
      * Sets the side menu visible or hidden.
173 175
      *
174
-     * @private
175 176
      * @param {boolean} show - The new expected visibility value.
177
+     * @private
176 178
      * @returns {void}
177 179
      */
178 180
     _setShow(show) {
@@ -183,15 +185,17 @@ export default class SideBar extends Component<Props, State> {
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 201
         if (this._mounted) {
@@ -200,5 +204,4 @@ export default class SideBar extends Component<Props, State> {
200 204
             });
201 205
         }
202 206
     }
203
-
204 207
 }

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

@@ -1,8 +1,7 @@
1 1
 export { default as Container } from './Container';
2
+export { default as Header } from './Header';
2 3
 export { default as Link } from './Link';
3 4
 export { default as LoadingIndicator } from './LoadingIndicator';
4
-export { default as Header } from './Header';
5 5
 export { default as SideBar } from './SideBar';
6
-export * from './styles';
7
-export { default as TintedView } from './TintedView';
8 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,11 +14,20 @@ export const STATUSBAR_COLOR = ColorPalette.blueHighlight;
14 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 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 32
      * Style of the header overlay to cover the unsafe areas.
24 33
      */
@@ -26,6 +35,29 @@ export default createStyleSheet({
26 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 62
      * Base style of Header
31 63
      */

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

@@ -1,41 +0,0 @@
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,3 +1,2 @@
1 1
 export * from './BoxModel';
2 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 +0,0 @@
1
-export * from './components';

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

@@ -0,0 +1,10 @@
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 查看文件

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

@@ -0,0 +1 @@
1
+export * from './web';

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

@@ -0,0 +1 @@
1
+export * from './_';

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

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

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

@@ -47,6 +47,7 @@ class FormRow extends Component<Props> {
47 47
         super(props);
48 48
 
49 49
         React.Children.only(this.props.children);
50
+
50 51
         this._getDefaultFieldProps = this._getDefaultFieldProps.bind(this);
51 52
         this._getRowStyle = this._getRowStyle.bind(this);
52 53
     }
@@ -63,10 +64,10 @@ class FormRow extends Component<Props> {
63 64
 
64 65
         // Some field types need additional props to look good and standardized
65 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 72
         return (
72 73
             <View
@@ -74,7 +75,8 @@ class FormRow extends Component<Props> {
74 75
                 <View style = { styles.fieldLabelContainer } >
75 76
                     <Text
76 77
                         style = { [
77
-                            styles.text, styles.fieldLabelText
78
+                            styles.text,
79
+                            styles.fieldLabelText
78 80
                         ] } >
79 81
                         { t(this.props.i18nLabel) }
80 82
                     </Text>
@@ -96,8 +98,8 @@ class FormRow extends Component<Props> {
96 98
      *     - TextInput
97 99
      *     - Switch (needs no addition props ATM).
98 100
      *
99
-     * @private
100 101
      * @param {Object} field - The field (child) component.
102
+     * @private
101 103
      * @returns {Object}
102 104
      */
103 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 查看文件

@@ -0,0 +1,251 @@
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 查看文件

@@ -0,0 +1 @@
1
+export { default as SettingsView } from './SettingsView';

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

@@ -7,8 +7,7 @@ export const ANDROID_UNDERLINE_COLOR = 'transparent';
7 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 12
 export default createStyleSheet({
14 13
     /**

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

@@ -3,8 +3,8 @@ import PropTypes from 'prop-types';
3 3
 import React, { Component } from 'react';
4 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 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,7 +5,7 @@ import DropdownMenu, {
5 5
 import PropTypes from 'prop-types';
6 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 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,8 +2,8 @@ import PropTypes from 'prop-types';
2 2
 import React, { Component } from 'react';
3 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 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,8 +2,11 @@ import PropTypes from 'prop-types';
2 2
 import React, { Component } from 'react';
3 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 11
 import DeviceSelectionButton from './DeviceSelectionButton';
9 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,6 +14,7 @@ export function normalizeUserInputURL(url: string) {
14 14
 
15 15
     if (url) {
16 16
         url = url.replace(/\s/g, '').toLowerCase();
17
+
17 18
         const urlRegExp = new RegExp('^(\\w+://)?(.+)$');
18 19
         const urlComponents = urlRegExp.exec(url);
19 20
 
@@ -21,8 +22,7 @@ export function normalizeUserInputURL(url: string) {
21 22
             url = `https://${urlComponents[2]}`;
22 23
         }
23 24
 
24
-        const parsedURI
25
-            = parseStandardURIString(url);
25
+        const parsedURI = parseStandardURIString(url);
26 26
 
27 27
         if (!parsedURI.host) {
28 28
             return null;

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

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

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

@@ -3,35 +3,34 @@
3 3
 import { SET_ROOM } from '../base/conference';
4 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 12
  * @returns {Function}
14 13
  */
15 14
 MiddlewareRegistry.register(store => next => action => {
16 15
     switch (action.type) {
17 16
     case SET_ROOM:
18
-        return _closeAppSettings(store, next, action);
17
+        return _hideSettingsView(store, next, action);
19 18
     }
20 19
 
21 20
     return next(action);
22 21
 });
23 22
 
24 23
 /**
25
- * Hides the settings screen.
24
+ * Hides {@link SettingsView}.
26 25
  *
27 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 28
  * @param {Action} action - The redux action.
30 29
  * @private
31 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 35
     return next(action);
37 36
 }

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

@@ -0,0 +1,17 @@
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,4 +1,10 @@
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,19 +1,20 @@
1 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 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 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,11 +3,11 @@
3 3
 import React, { Component } from 'react';
4 4
 import { Linking, Text, TouchableOpacity, View } from 'react-native';
5 5
 
6
-import styles from './styles';
7
-
8 6
 import { Icon } from '../../base/font-icons';
9 7
 import { translate } from '../../base/i18n';
10 8
 
9
+import styles from './styles';
10
+
11 11
 type Props = {
12 12
 
13 13
     /**
@@ -43,13 +43,14 @@ type Props = {
43 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 48
      * @inheritdoc
49 49
      */
50 50
     constructor(props: Props) {
51 51
         super(props);
52 52
 
53
+        // Bind event handlers so they are only bound once per instance.
53 54
         this._onOpenURL = this._onOpenURL.bind(this);
54 55
     }
55 56
 

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

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

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

@@ -4,12 +4,6 @@ import React, { Component } from 'react';
4 4
 import { SafeAreaView, ScrollView, Text } from 'react-native';
5 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 7
 import {
14 8
     Avatar,
15 9
     getAvatarURL,
@@ -20,6 +14,11 @@ import {
20 14
     Header,
21 15
     SideBar
22 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 24
  * The URL at which the privacy policy is available to the user.
@@ -71,6 +70,7 @@ class WelcomePageSideBar extends Component<Props> {
71 70
     constructor(props) {
72 71
         super(props);
73 72
 
73
+        // Bind event handlers so they are only bound once per instance.
74 74
         this._onHideSideBar = this._onHideSideBar.bind(this);
75 75
         this._onOpenSettings = this._onOpenSettings.bind(this);
76 76
     }
@@ -122,19 +122,19 @@ class WelcomePageSideBar extends Component<Props> {
122 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 127
      * @private
128 128
      * @returns {void}
129 129
      */
130 130
     _onHideSideBar() {
131
-        this.props.dispatch(setSideBarVisibility(false));
131
+        this.props.dispatch(setSideBarVisible(false));
132 132
     }
133 133
 
134 134
     _onOpenSettings: () => void;
135 135
 
136 136
     /**
137
-     * Opens the settings screen.
137
+     * Shows the {@link SettingsView}.
138 138
      *
139 139
      * @private
140 140
      * @returns {void}
@@ -142,8 +142,8 @@ class WelcomePageSideBar extends Component<Props> {
142 142
     _onOpenSettings() {
143 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,14 +98,7 @@ export default createStyleSheet({
98 98
      */
99 99
     hintButtonContainer: {
100 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,6 +116,13 @@ export default createStyleSheet({
123 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 127
      * Container for the items in the side bar.
128 128
      */
@@ -142,7 +142,7 @@ export default createStyleSheet({
142 142
     },
143 143
 
144 144
     /**
145
-     * Top level screen style
145
+     * Top-level screen style.
146 146
      */
147 147
     page: {
148 148
         flex: 1,

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

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

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

@@ -1,23 +1,20 @@
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
+});

Loading…
取消
儲存