瀏覽代碼

feat: replace device selection in settings with button for modal

Cleanup existing logic for displaying and updating device
selection settings in the settings menu. In its place
is a button to open the device selection modal.
j8
Leonard Kim 8 年之前
父節點
當前提交
eb7dda85a1
共有 6 個文件被更改,包括 48 次插入219 次删除
  1. 0
    3
      conference.js
  2. 0
    31
      css/_device_settings_dialog.scss
  3. 6
    0
      css/_side_toolbar_container.scss
  4. 0
    1
      css/main.scss
  5. 0
    23
      modules/UI/UI.js
  6. 42
    161
      modules/UI/side_pannels/settings/SettingsMenu.js

+ 0
- 3
conference.js 查看文件

1643
                 })
1643
                 })
1644
                 .catch((err) => {
1644
                 .catch((err) => {
1645
                     APP.UI.showDeviceErrorDialog(null, err);
1645
                     APP.UI.showDeviceErrorDialog(null, err);
1646
-                    APP.UI.setSelectedCameraFromSettings();
1647
                 });
1646
                 });
1648
             }
1647
             }
1649
         );
1648
         );
1665
                 })
1664
                 })
1666
                 .catch((err) => {
1665
                 .catch((err) => {
1667
                     APP.UI.showDeviceErrorDialog(err, null);
1666
                     APP.UI.showDeviceErrorDialog(err, null);
1668
-                    APP.UI.setSelectedMicFromSettings();
1669
                 });
1667
                 });
1670
             }
1668
             }
1671
         );
1669
         );
1681
                         logger.warn('Failed to change audio output device. ' +
1679
                         logger.warn('Failed to change audio output device. ' +
1682
                             'Default or previously set audio output device ' +
1680
                             'Default or previously set audio output device ' +
1683
                             'will be used instead.', err);
1681
                             'will be used instead.', err);
1684
-                        APP.UI.setSelectedAudioOutputFromSettings();
1685
                     });
1682
                     });
1686
             }
1683
             }
1687
         );
1684
         );

+ 0
- 31
css/_device_settings_dialog.scss 查看文件

1
-.settingsContent {
2
-    display: flex;
3
-    display: -webkit-flex;
4
-
5
-    #localVideoPreview {
6
-        width: 50%;
7
-        align-self: baseline;
8
-    }
9
-
10
-    .deviceSelection {
11
-        display: flex;
12
-        display: -webkit-flex;
13
-        -webkit-flex: 1;
14
-        flex: 1;
15
-        flex-direction: column;
16
-        flex-wrap: nowrap;
17
-        justify-content: flex-start;
18
-        align-items: left;
19
-        margin-left: 10px;
20
-
21
-        .device {
22
-            display: flex;
23
-            margin-bottom: 5px;
24
-
25
-            select {
26
-                flex: 1;
27
-                margin_right: 5px;
28
-            }
29
-        }
30
-    }
31
-}

+ 6
- 0
css/_side_toolbar_container.scss 查看文件

113
     text-align: center;
113
     text-align: center;
114
 }
114
 }
115
 
115
 
116
+#deviceOptionsWrapper {
117
+    button {
118
+        float: none;
119
+    }
120
+}
121
+
116
 /**
122
 /**
117
  * Profile
123
  * Profile
118
  */
124
  */

+ 0
- 1
css/main.scss 查看文件

55
 @import 'welcome_page';
55
 @import 'welcome_page';
56
 @import 'toolbars';
56
 @import 'toolbars';
57
 @import 'side_toolbar_container';
57
 @import 'side_toolbar_container';
58
-@import 'device_settings_dialog';
59
 @import 'jquery.contextMenu';
58
 @import 'jquery.contextMenu';
60
 @import 'keyboard-shortcuts';
59
 @import 'keyboard-shortcuts';
61
 @import 'redirect_page';
60
 @import 'redirect_page';

+ 0
- 23
modules/UI/UI.js 查看文件

1084
  * @param {object[]} devices new list of available devices
1084
  * @param {object[]} devices new list of available devices
1085
  */
1085
  */
1086
 UI.onAvailableDevicesChanged = function (devices) {
1086
 UI.onAvailableDevicesChanged = function (devices) {
1087
-    SettingsMenu.changeDevicesList(devices);
1088
     APP.store.dispatch(updateDeviceList(devices));
1087
     APP.store.dispatch(updateDeviceList(devices));
1089
 };
1088
 };
1090
 
1089
 
1091
-/**
1092
- * Sets microphone's <select> element to select microphone ID from settings.
1093
- */
1094
-UI.setSelectedMicFromSettings = function () {
1095
-    SettingsMenu.setSelectedMicFromSettings();
1096
-};
1097
-
1098
-/**
1099
- * Sets camera's <select> element to select camera ID from settings.
1100
- */
1101
-UI.setSelectedCameraFromSettings = function () {
1102
-    SettingsMenu.setSelectedCameraFromSettings();
1103
-};
1104
-
1105
-/**
1106
- * Sets audio outputs's <select> element to select audio output ID from
1107
- * settings.
1108
- */
1109
-UI.setSelectedAudioOutputFromSettings = function () {
1110
-    SettingsMenu.setSelectedAudioOutputFromSettings();
1111
-};
1112
-
1113
 /**
1090
 /**
1114
  * Returns the id of the current video shown on large.
1091
  * Returns the id of the current video shown on large.
1115
  * Currently used by tests (torture).
1092
  * Currently used by tests (torture).

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

1
 /* global $, APP, AJS, interfaceConfig, JitsiMeetJS */
1
 /* global $, APP, AJS, interfaceConfig, JitsiMeetJS */
2
-
2
+import { openDialog } from '../../../../react/features/base/dialog';
3
 import { LANGUAGES } from "../../../../react/features/base/i18n";
3
 import { LANGUAGES } from "../../../../react/features/base/i18n";
4
+import { DeviceSelectionDialog }
5
+    from '../../../../react/features/device-selection';
4
 
6
 
5
 import UIUtil from "../../util/UIUtil";
7
 import UIUtil from "../../util/UIUtil";
6
 import UIEvents from "../../../../service/UI/UIEvents";
8
 import UIEvents from "../../../../service/UI/UIEvents";
7
-import Settings from '../../../settings/Settings';
8
 
9
 
9
 const sidePanelsContainerId = 'sideToolbarContainer';
10
 const sidePanelsContainerId = 'sideToolbarContainer';
11
+const deviceSelectionButtonClasses
12
+    = 'button-control button-control_primary button-control_full-width';
10
 const htmlStr = `
13
 const htmlStr = `
11
     <div id="settings_container" class="sideToolbarContainer__inner">
14
     <div id="settings_container" class="sideToolbarContainer__inner">
12
         <div class="title" data-i18n="settings.title"></div>
15
         <div class="title" data-i18n="settings.title"></div>
19
                 <div id="deviceOptionsTitle" class="subTitle hide" 
22
                 <div id="deviceOptionsTitle" class="subTitle hide" 
20
                     data-i18n="settings.audioVideo"></div>
23
                     data-i18n="settings.audioVideo"></div>
21
                 <div class="sideToolbarBlock first">
24
                 <div class="sideToolbarBlock first">
22
-                    <label class="first" data-i18n="settings.selectCamera">
23
-                    </label>
24
-                    <select id="selectCamera"></select>
25
-                </div>
26
-                <div class="sideToolbarBlock">
27
-                    <label data-i18n="settings.selectMic"></label>
28
-                    <select id="selectMic"></select>
29
-                </div>
30
-                <div class="sideToolbarBlock">
31
-                    <label data-i18n="settings.selectAudioOutput"></label>
32
-                    <select id="selectAudioOutput"></select>
25
+                    <button
26
+                        class="${deviceSelectionButtonClasses}"
27
+                        data-i18n="deviceSelection.deviceSettings"
28
+                        id="deviceSelection"
29
+                        type="button"></button>
33
                 </div>
30
                 </div>
34
             </div>
31
             </div>
35
             <div id="moderatorOptionsWrapper" class="hide">
32
             <div id="moderatorOptionsWrapper" class="hide">
89
     }).join('');
86
     }).join('');
90
 }
87
 }
91
 
88
 
92
-/**
93
- * Generate html select options for available physical devices.
94
- *
95
- * @param {{ deviceId, label }[]} items available devices
96
- * @param {string} [selectedId] id of selected device
97
- * @param {boolean} permissionGranted if permission to use selected device type
98
- *      is granted
99
- * @returns {string}
100
- */
101
-function generateDevicesOptions(items, selectedId, permissionGranted) {
102
-    if (!permissionGranted && items.length) {
103
-        return '<option data-i18n="settings.noPermission"></option>';
104
-    }
105
-
106
-    var options = items.map(function (item) {
107
-        let attrs = {
108
-            value: item.deviceId
109
-        };
110
-
111
-        if (item.deviceId === selectedId) {
112
-            attrs.selected = 'selected';
113
-        }
114
-
115
-        let attrsStr = UIUtil.attrsToString(attrs);
116
-        return `<option ${attrsStr}>${item.label}</option>`;
117
-    });
118
-
119
-    if (!items.length) {
120
-        options.unshift('<option data-i18n="settings.noDevice"></option>');
121
-    }
122
-
123
-    return options.join('');
124
-}
125
-
126
 /**
89
 /**
127
  * Replace html select element to select2 custom dropdown
90
  * Replace html select element to select2 custom dropdown
128
  *
91
  *
138
     }
101
     }
139
 }
102
 }
140
 
103
 
104
+/**
105
+ * Open DeviceSelectionDialog with a configuration based on the environment's
106
+ * supported abilities.
107
+ *
108
+ * @param {boolean} isDeviceListAvailable - Whether or not device enumeration
109
+ * is possible. This is a value obtained through an async operation whereas all
110
+ * other configurations for the modal are obtained synchronously.
111
+ * @private
112
+ * @returns {void}
113
+ */
114
+function _openDeviceSelectionModal(isDeviceListAvailable) {
115
+    APP.store.dispatch(openDialog(DeviceSelectionDialog, {
116
+        currentAudioOutputId: APP.settings.getAudioOutputDeviceId(),
117
+        currentAudioTrack: APP.conference.getLocalAudioTrack(),
118
+        currentVideoTrack: APP.conference.getLocalVideoTrack(),
119
+        disableAudioInputChange: !JitsiMeetJS.isMultipleAudioInputSupported(),
120
+        disableDeviceChange: !isDeviceListAvailable
121
+            || !JitsiMeetJS.mediaDevices.isDeviceChangeAvailable(),
122
+        hasAudioPermission: JitsiMeetJS.mediaDevices
123
+            .isDevicePermissionGranted('audio'),
124
+        hasVideoPermission: JitsiMeetJS.mediaDevices
125
+            .isDevicePermissionGranted('video'),
126
+        hideAudioInputPreview: !JitsiMeetJS.isCollectingLocalStats(),
127
+        hideAudioOutputSelect: !JitsiMeetJS.mediaDevices
128
+            .isDeviceChangeAvailable('output')
129
+    }));
130
+}
131
+
141
 export default {
132
 export default {
142
     init (emitter) {
133
     init (emitter) {
143
         initHTML();
134
         initHTML();
181
 
172
 
182
             JitsiMeetJS.mediaDevices.isDeviceListAvailable()
173
             JitsiMeetJS.mediaDevices.isDeviceListAvailable()
183
                 .then((isDeviceListAvailable) => {
174
                 .then((isDeviceListAvailable) => {
184
-                    if (isDeviceListAvailable &&
185
-                        JitsiMeetJS.mediaDevices.isDeviceChangeAvailable()) {
186
-                        this._initializeDeviceSelectionSettings(emitter);
187
-                    }
175
+                    $('#deviceSelection').on('click', () => {
176
+                        _openDeviceSelectionModal(isDeviceListAvailable);
177
+                    });
188
                 });
178
                 });
179
+
189
             // Only show the subtitle if this isn't the only setting section.
180
             // Only show the subtitle if this isn't the only setting section.
190
             if (interfaceConfig.SETTINGS_SECTIONS.length > 1)
181
             if (interfaceConfig.SETTINGS_SECTIONS.length > 1)
191
                 UIUtil.setVisible("deviceOptionsTitle", true);
182
                 UIUtil.setVisible("deviceOptionsTitle", true);
219
         }
210
         }
220
     },
211
     },
221
 
212
 
222
-    _initializeDeviceSelectionSettings(emitter) {
223
-        this.changeDevicesList([]);
224
-
225
-        $('#selectCamera').change(function () {
226
-            let cameraDeviceId = $(this).val();
227
-            if (cameraDeviceId !== Settings.getCameraDeviceId()) {
228
-                emitter.emit(UIEvents.VIDEO_DEVICE_CHANGED, cameraDeviceId);
229
-            }
230
-        });
231
-        $('#selectMic').change(function () {
232
-            let micDeviceId = $(this).val();
233
-            if (micDeviceId !== Settings.getMicDeviceId()) {
234
-                emitter.emit(UIEvents.AUDIO_DEVICE_CHANGED, micDeviceId);
235
-            }
236
-        });
237
-        $('#selectAudioOutput').change(function () {
238
-            let audioOutputDeviceId = $(this).val();
239
-            if (audioOutputDeviceId !== Settings.getAudioOutputDeviceId()) {
240
-                emitter.emit(
241
-                    UIEvents.AUDIO_OUTPUT_DEVICE_CHANGED, audioOutputDeviceId);
242
-            }
243
-        });
244
-    },
245
-
246
     /**
213
     /**
247
      * If start audio muted/start video muted options should be visible or not.
214
      * If start audio muted/start video muted options should be visible or not.
248
      * @param {boolean} show
215
      * @param {boolean} show
286
      */
253
      */
287
     isVisible () {
254
     isVisible () {
288
         return UIUtil.isVisible(document.getElementById("settings_container"));
255
         return UIUtil.isVisible(document.getElementById("settings_container"));
289
-    },
290
-
291
-    /**
292
-     * Sets microphone's <select> element to select microphone ID from settings.
293
-     */
294
-    setSelectedMicFromSettings () {
295
-        $('#selectMic').val(Settings.getMicDeviceId());
296
-    },
297
-
298
-    /**
299
-     * Sets camera's <select> element to select camera ID from settings.
300
-     */
301
-    setSelectedCameraFromSettings () {
302
-        $('#selectCamera').val(Settings.getCameraDeviceId());
303
-    },
304
-
305
-    /**
306
-     * Sets audio outputs's <select> element to select audio output ID from
307
-     * settings.
308
-     */
309
-    setSelectedAudioOutputFromSettings () {
310
-        $('#selectAudioOutput').val(Settings.getAudioOutputDeviceId());
311
-    },
312
-
313
-    /**
314
-     * Change available cameras/microphones or hide selects completely if
315
-     * no devices available.
316
-     * @param {{ deviceId, label, kind }[]} devices list of available devices
317
-     */
318
-    changeDevicesList (devices) {
319
-        let $selectCamera= AJS.$('#selectCamera'),
320
-            $selectMic = AJS.$('#selectMic'),
321
-            $selectAudioOutput = AJS.$('#selectAudioOutput'),
322
-            $selectAudioOutputParent = $selectAudioOutput.parent();
323
-
324
-        let audio = devices.filter(device => device.kind === 'audioinput'),
325
-            video = devices.filter(device => device.kind === 'videoinput'),
326
-            audioOutput = devices
327
-                .filter(device => device.kind === 'audiooutput'),
328
-            selectedAudioDevice = audio.find(
329
-                d => d.deviceId === Settings.getMicDeviceId()) || audio[0],
330
-            selectedVideoDevice = video.find(
331
-                d => d.deviceId === Settings.getCameraDeviceId()) || video[0],
332
-            selectedAudioOutputDevice = audioOutput.find(
333
-                    d => d.deviceId === Settings.getAudioOutputDeviceId()),
334
-            videoPermissionGranted =
335
-                JitsiMeetJS.mediaDevices.isDevicePermissionGranted('video'),
336
-            audioPermissionGranted =
337
-                JitsiMeetJS.mediaDevices.isDevicePermissionGranted('audio');
338
-
339
-        $selectCamera
340
-            .html(generateDevicesOptions(
341
-                video,
342
-                selectedVideoDevice ? selectedVideoDevice.deviceId : '',
343
-                videoPermissionGranted))
344
-            .prop('disabled', !video.length || !videoPermissionGranted);
345
-
346
-        initSelect2($selectCamera);
347
-
348
-        $selectMic
349
-            .html(generateDevicesOptions(
350
-                audio,
351
-                selectedAudioDevice ? selectedAudioDevice.deviceId : '',
352
-                audioPermissionGranted))
353
-            .prop('disabled', !audio.length || !audioPermissionGranted);
354
-
355
-        initSelect2($selectMic);
356
-
357
-        if (JitsiMeetJS.mediaDevices.isDeviceChangeAvailable('output')) {
358
-            $selectAudioOutput
359
-                .html(generateDevicesOptions(
360
-                    audioOutput,
361
-                    selectedAudioOutputDevice
362
-                        ? selectedAudioOutputDevice.deviceId
363
-                        : 'default',
364
-                    videoPermissionGranted || audioPermissionGranted))
365
-                .prop('disabled', !audioOutput.length ||
366
-                    (!videoPermissionGranted && !audioPermissionGranted));
367
-            initSelect2($selectAudioOutput);
368
-
369
-            $selectAudioOutputParent.show();
370
-        } else {
371
-            $selectAudioOutputParent.hide();
372
-        }
373
-
374
-        APP.translation.translateElement($('#settings_container option'));
375
     }
256
     }
376
 };
257
 };

Loading…
取消
儲存