Sfoglia il codice sorgente

feat(dialogs): Redesign Video Quality dialog & change dialog background color

master
Vlad Piersec 3 anni fa
parent
commit
1ad8f77179

+ 0
- 55
css/_atlaskit_overrides.scss Vedi File

@@ -24,61 +24,6 @@
24 24
     bottom: calc(#{$newToolbarSizeWithPadding}) !important;
25 25
 }
26 26
 
27
-.modal-dialog-form {
28
-    /**
29
-     * Override @atlaskit/dropdown-menu styling when in a modal because the
30
-     * dropdown backgrounds clash with the modal backgrounds.
31
-     */
32
-    .dropdown-menu div[style*="transform"] {
33
-        outline: 1px solid #455166;
34
-    }
35
-    .dropdown-menu button:not(:active):not(:hover) > span {
36
-        color: #B8C7E0;
37
-    }
38
-
39
-    /**
40
-    * Override @atlaskit/tab styling when in a modal because the
41
-    * tab text color clash with the modal backgrounds.
42
-    */
43
-    div[role="tablist"] > div:not([data-selected]):not(:hover),
44
-    label > div > span {
45
-        color: #B8C7E0 !important;
46
-    }
47
-}
48
-
49
-/**
50
- * Override @atlaskit/modal-dialog header styling
51
- */
52
-.atlaskit-portal [role="dialog"] header {
53
-    box-shadow: none;
54
-    .jitsi-icon {
55
-        cursor: pointer;
56
-    }
57
-
58
-    .jitsi-icon svg {
59
-        fill: #B8C7E0;
60
-    }
61
-}
62
-
63
-/**
64
- * Override @atlaskit/modal-dialog footer styling.
65
- */
66
- .atlaskit-portal [role="dialog"] footer {
67
-     box-shadow: none;
68
- }
69
-
70
-/**
71
- * Make header close button more easily tappable on mobile.
72
- */
73
-.mobile-browser .atlaskit-portal [role="dialog"] header .jitsi-icon {
74
-    display: grid;
75
-    place-items: center;
76
-    height: 48px;
77
-    width: 48px;
78
-    background: #2a3a4b;
79
-    border-radius: 3px;
80
-}
81
-
82 27
 /**
83 28
  * Override @atlaskit/theme styling for the top toolbar so it displays over
84 29
  * the video thumbnail while obscuring as little as possible.

+ 0
- 1
css/main.scss Vedi File

@@ -44,7 +44,6 @@ $flagsImagePath: "../images/";
44 44
 @import 'modals/screen-share/share-audio';
45 45
 @import 'modals/screen-share/share-screen-warning';
46 46
 @import 'modals/speaker_stats/speaker_stats';
47
-@import 'modals/video-quality/video-quality';
48 47
 @import 'modals/virtual-background/virtual-background';
49 48
 @import 'modals/local-recording/local-recording';
50 49
 @import 'videolayout_default';

+ 0
- 3
css/modals/_dialog.scss Vedi File

@@ -122,9 +122,6 @@
122 122
         margin-bottom: 8px;
123 123
     }
124 124
 }
125
-.modal-dialog-footer {
126
-    font-size: $modalButtonFontSize;
127
-}
128 125
 
129 126
 /**
130 127
  * Styling inline dialog errors.

+ 0
- 114
css/modals/video-quality/_video-quality.scss Vedi File

@@ -1,114 +0,0 @@
1
-.video-quality-dialog {
2
-    .video-quality-dialog-title {
3
-        margin-bottom: 10px;
4
-    }
5
-
6
-    .video-quality-dialog-contents {
7
-        align-items: center;
8
-        display: flex;
9
-        flex-direction: column;
10
-        padding: 10px;
11
-        min-width: 250px;
12
-
13
-        .video-quality-dialog-slider-container {
14
-            width: 100%;
15
-            text-align: center;
16
-        }
17
-
18
-        .video-quality-dialog-slider {
19
-            width: calc(100% - 5px);
20
-
21
-            @mixin sliderTrackStyles() {
22
-                height: 15px;
23
-                border-radius: 10px;
24
-                background: rgb(14, 22, 36);
25
-            }
26
-
27
-            &::-ms-track {
28
-                @include sliderTrackStyles();
29
-            }
30
-
31
-            &::-moz-range-track {
32
-                @include sliderTrackStyles();
33
-            }
34
-
35
-            &::-webkit-slider-runnable-track {
36
-                @include sliderTrackStyles();
37
-            }
38
-
39
-            @mixin sliderThumbStyles() {
40
-                top: 50%;
41
-                border: none;
42
-                position: relative;
43
-                opacity: 0;
44
-            }
45
-
46
-            &::-ms-thumb {
47
-                @include sliderThumbStyles();
48
-            }
49
-
50
-            &::-moz-range-thumb {
51
-                @include sliderThumbStyles();
52
-
53
-            }
54
-
55
-            &::-webkit-slider-thumb {
56
-                @include sliderThumbStyles();
57
-            }
58
-        }
59
-
60
-        .video-quality-dialog-labels {
61
-            box-sizing: border-box;
62
-            display: flex;
63
-            margin-top: 5px;
64
-            position: relative;
65
-            width: 90%;
66
-        }
67
-
68
-        .video-quality-dialog-label-container {
69
-            position: absolute;
70
-            text-align: center;
71
-            transform: translate(-50%, 0%);
72
-
73
-            &::before {
74
-                content: '';
75
-                border-radius: 50%;
76
-                left: 0;
77
-                height: 6px;
78
-                margin: 0 auto;
79
-                pointer-events: none;
80
-                position: absolute;
81
-                right: 0;
82
-                top: -16px;
83
-                width: 6px;
84
-            }
85
-        }
86
-
87
-        .video-quality-dialog-label-container.active {
88
-            color: $videoQualityActive;
89
-            font-weight: bold;
90
-
91
-            &::before {
92
-                background: $videoQualityActive;
93
-                height: 12px;
94
-                top: -19px;
95
-                width: 12px;
96
-            }
97
-        }
98
-
99
-        .video-quality-dialog-label-container:first-child {
100
-            position: relative;
101
-        }
102
-
103
-        .video-quality-dialog-label {
104
-            display: table-caption;
105
-            word-spacing: unset;
106
-        }
107
-    }
108
-}
109
-
110
-.modal-dialog-form {
111
-    .video-quality-dialog-title {
112
-        display: none;
113
-    }
114
-}

+ 3
- 0
lang/main.json Vedi File

@@ -1045,7 +1045,10 @@
1045 1045
         "pending": "{{displayName}} has been invited"
1046 1046
     },
1047 1047
     "videoStatus": {
1048
+        "adjustFor": "Adjust for:",
1048 1049
         "audioOnly": "AUD",
1050
+        "bestPerformance": "Best performance",
1051
+        "highestQuality": "Highest quality",
1049 1052
         "audioOnlyExpanded": "You are in low bandwidth mode. In this mode you will receive only audio and screen sharing.",
1050 1053
         "callQuality": "Video Quality",
1051 1054
         "hd": "HD",

+ 2
- 0
react/features/app/components/App.web.js Vedi File

@@ -4,6 +4,7 @@ import { AtlasKitThemeProvider } from '@atlaskit/theme';
4 4
 import React from 'react';
5 5
 
6 6
 import { DialogContainer } from '../../base/dialog';
7
+import GlobalStyles from '../../base/ui/components/GlobalStyles';
7 8
 import JitsiThemeProvider from '../../base/ui/components/JitsiThemeProvider';
8 9
 import { ChromeExtensionBanner } from '../../chrome-extension-banner';
9 10
 
@@ -29,6 +30,7 @@ export class App extends AbstractApp {
29 30
         return (
30 31
             <JitsiThemeProvider>
31 32
                 <AtlasKitThemeProvider mode = 'dark'>
33
+                    <GlobalStyles />
32 34
                     <ChromeExtensionBanner />
33 35
                     { super._createMainElement(component, props) }
34 36
                 </AtlasKitThemeProvider>

+ 54
- 9
react/features/base/dialog/components/web/ModalHeader.js Vedi File

@@ -8,10 +8,12 @@ import {
8 8
     titleIconWrapperStyles,
9 9
     TitleText
10 10
 } from '@atlaskit/modal-dialog/dist/es2019/styled/Content';
11
+import { withStyles } from '@material-ui/core/styles';
11 12
 import React from 'react';
12 13
 
13 14
 import { translate } from '../../../i18n';
14 15
 import { Icon, IconClose } from '../../../icons';
16
+import { withPixelLineHeight } from '../../../styles/functions';
15 17
 
16 18
 const TitleIcon = ({ appearance }: { appearance?: 'danger' | 'warning' }) => {
17 19
     if (!appearance) {
@@ -30,6 +32,7 @@ const TitleIcon = ({ appearance }: { appearance?: 'danger' | 'warning' }) => {
30 32
 type Props = {
31 33
     id: string,
32 34
     appearance?: 'danger' | 'warning',
35
+    classes: Object,
33 36
     heading: string,
34 37
     hideCloseIconButton: boolean,
35 38
     onClose: Function,
@@ -39,6 +42,40 @@ type Props = {
39 42
     t: Function
40 43
 }
41 44
 
45
+/**
46
+ * Creates the styles for the component.
47
+ *
48
+ * @param {Object} theme - The current UI theme.
49
+ *
50
+ * @returns {Object}
51
+ */
52
+const styles = theme => {
53
+    return {
54
+        closeButton: {
55
+            borderRadius: theme.shape.borderRadius,
56
+            cursor: 'pointer',
57
+            padding: 13,
58
+
59
+            [theme.breakpoints.down('480')]: {
60
+                background: theme.palette.action02
61
+            },
62
+
63
+            '&:hover': {
64
+                background: theme.palette.action02
65
+            }
66
+        },
67
+        header: {
68
+            boxShadow: 'none',
69
+
70
+            '& h4': {
71
+                ...withPixelLineHeight(theme.typography.heading5),
72
+                color: theme.palette.text01
73
+            }
74
+        }
75
+    };
76
+};
77
+
78
+
42 79
 /**
43 80
  * A default header for modal-dialog components
44 81
  *
@@ -90,6 +127,7 @@ class ModalHeader extends React.Component<Props> {
90 127
         const {
91 128
             id,
92 129
             appearance,
130
+            classes,
93 131
             heading,
94 132
             hideCloseIconButton,
95 133
             onClose,
@@ -104,7 +142,9 @@ class ModalHeader extends React.Component<Props> {
104 142
         }
105 143
 
106 144
         return (
107
-            <Header showKeyline = { showKeyline }>
145
+            <Header
146
+                className = { classes.header }
147
+                showKeyline = { showKeyline }>
108 148
                 <Title>
109 149
                     <TitleIcon appearance = { appearance } />
110 150
                     <TitleText
@@ -116,16 +156,21 @@ class ModalHeader extends React.Component<Props> {
116 156
                 </Title>
117 157
 
118 158
                 {
119
-                    !hideCloseIconButton && <Icon
120
-                        ariaLabel = { t('dialog.close') }
121
-                        onClick = { onClose }
122
-                        onKeyPress = { this._onKeyPress }
123
-                        role = 'button'
124
-                        src = { IconClose }
125
-                        tabIndex = { 0 } />
159
+                    !hideCloseIconButton
160
+                        && <div
161
+                            className = { classes.closeButton }
162
+                            id = 'modal-header-close-button'
163
+                            onClick = { onClose }>
164
+                            <Icon
165
+                                ariaLabel = { t('dialog.close') }
166
+                                onKeyPress = { this._onKeyPress }
167
+                                role = 'button'
168
+                                src = { IconClose }
169
+                                tabIndex = { 0 } />
170
+                        </div>
126 171
                 }
127 172
             </Header>
128 173
         );
129 174
     }
130 175
 }
131
-export default translate(ModalHeader);
176
+export default translate(withStyles(styles)(ModalHeader));

+ 23
- 2
react/features/base/dialog/components/web/StatelessDialog.js Vedi File

@@ -3,6 +3,7 @@
3 3
 import ButtonGroup from '@atlaskit/button/button-group';
4 4
 import Button from '@atlaskit/button/standard-button';
5 5
 import Modal, { ModalFooter } from '@atlaskit/modal-dialog';
6
+import { withStyles } from '@material-ui/core/styles';
6 7
 import _ from 'lodash';
7 8
 import React, { Component } from 'react';
8 9
 
@@ -30,6 +31,11 @@ const OK_BUTTON_ID = 'modal-dialog-ok-button';
30 31
  */
31 32
 type Props = DialogProps & {
32 33
 
34
+    /**
35
+     * An object containing the CSS classes.
36
+     */
37
+    classes: Object,
38
+
33 39
     /**
34 40
      * Custom dialog header that replaces the standard heading.
35 41
      */
@@ -101,6 +107,19 @@ type Props = DialogProps & {
101 107
     width: string
102 108
 };
103 109
 
110
+/**
111
+ * Creates the styles for the component.
112
+ *
113
+ * @returns {Object}
114
+ */
115
+const styles = () => {
116
+    return {
117
+        footer: {
118
+            boxShadow: 'none'
119
+        }
120
+    };
121
+};
122
+
104 123
 /**
105 124
  * Web dialog that uses atlaskit modal-dialog to display dialogs.
106 125
  */
@@ -205,7 +224,9 @@ class StatelessDialog extends Component<Props> {
205 224
         }
206 225
 
207 226
         return (
208
-            <ModalFooter showKeyline = { propsFromModalFooter.showKeyline } >
227
+            <ModalFooter
228
+                className = { this.props.classes.footer }
229
+                showKeyline = { propsFromModalFooter.showKeyline } >
209 230
                 {
210 231
 
211 232
                     /**
@@ -367,4 +388,4 @@ class StatelessDialog extends Component<Props> {
367 388
     }
368 389
 }
369 390
 
370
-export default translate(StatelessDialog);
391
+export default translate(withStyles(styles)(StatelessDialog));

+ 7
- 1
react/features/base/ui/components/BaseTheme.web.js Vedi File

@@ -9,5 +9,11 @@ export default createWebTheme({
9 9
     colorMap,
10 10
     spacing,
11 11
     shape,
12
-    typography
12
+    typography,
13
+    breakpoints: {
14
+        values: {
15
+            '0': 0,
16
+            '480': 480
17
+        }
18
+    }
13 19
 });

+ 35
- 0
react/features/base/ui/components/GlobalStyles.js Vedi File

@@ -0,0 +1,35 @@
1
+// @flow
2
+
3
+import { createStyles, makeStyles } from '@material-ui/core';
4
+
5
+import { commonStyles, getGlobalStyles } from '../constants';
6
+import { formatCommonClasses } from '../functions';
7
+
8
+/**
9
+ * Creates all the global styles.
10
+ *
11
+ * @param {Object} theme - The current UI theme.
12
+ *
13
+ * @returns {Object}
14
+ */
15
+const useStyles = makeStyles(theme =>
16
+    createStyles({
17
+        '@global': {
18
+            ...formatCommonClasses(commonStyles),
19
+            ...getGlobalStyles(theme)
20
+        }
21
+    })
22
+);
23
+
24
+/**
25
+ * A component generating all the global styles.
26
+ *
27
+ * @returns {void}
28
+ */
29
+function GlobalStyles() {
30
+    useStyles();
31
+
32
+    return null;
33
+}
34
+
35
+export default GlobalStyles;

+ 41
- 0
react/features/base/ui/constants.js Vedi File

@@ -0,0 +1,41 @@
1
+// @flow
2
+
3
+/**
4
+ * An object containing all the class names for common CSS.
5
+ * Add a new name here and the styles to {@code commonStyles} object.
6
+ *
7
+ */
8
+export const commonClassName = {
9
+    emptyList: 'empty-list'
10
+};
11
+
12
+/**
13
+ * An object containing the declaration of the common, reusable CSS classes.
14
+ */
15
+export const commonStyles = {
16
+    // '.empty-list'
17
+    [commonClassName.emptyList]: {
18
+        listStyleType: 'none',
19
+        margin: 0,
20
+        padding: 0
21
+    }
22
+};
23
+
24
+/**
25
+ * Returns the global styles.
26
+ *
27
+ * @param {Object} theme - The Jitsi theme.
28
+ * @returns {Object}
29
+ */
30
+export const getGlobalStyles = (theme: Object) => {
31
+    return {
32
+        // @atlaskit/modal-dialog OVERRIDES
33
+        '.atlaskit-portal div[role=dialog]': {
34
+            // override dialog background
35
+            '& > div': {
36
+                background: theme.palette.ui02,
37
+                color: theme.palette.text01
38
+            }
39
+        }
40
+    };
41
+};

+ 16
- 0
react/features/base/ui/functions.web.js Vedi File

@@ -30,3 +30,19 @@ export function createWebTheme({ font, colors, colorMap, shape, spacing, typogra
30 30
         }
31 31
     });
32 32
 }
33
+
34
+/**
35
+ * Formats the common styles object to be interpreted as proper CSS.
36
+ *
37
+ * @param {Object} stylesObj - The styles object.
38
+ * @returns {Object}
39
+ */
40
+export function formatCommonClasses(stylesObj: Object) {
41
+    const formatted = {};
42
+
43
+    for (const [ key, value ] of Object.entries(stylesObj)) {
44
+        formatted[`.${key}`] = value;
45
+    }
46
+
47
+    return formatted;
48
+}

+ 2
- 3
react/features/speaker-stats/components/SpeakerStatsSearch.js Vedi File

@@ -13,8 +13,8 @@ const useStyles = makeStyles(() => {
13 13
     return {
14 14
         speakerStatsSearch: {
15 15
             position: 'absolute',
16
-            right: '50px',
17
-            top: '-5px'
16
+            right: '80px',
17
+            top: '8px'
18 18
         }
19 19
     };
20 20
 });
@@ -70,4 +70,3 @@ function SpeakerStatsSearch({ onSearch }: Props) {
70 70
 }
71 71
 
72 72
 export default SpeakerStatsSearch;
73
-

+ 169
- 0
react/features/video-quality/components/Slider.js Vedi File

@@ -0,0 +1,169 @@
1
+// @flow
2
+import { makeStyles } from '@material-ui/core/styles';
3
+import clsx from 'clsx';
4
+import React from 'react';
5
+
6
+import { commonClassName } from '../../base/ui/constants';
7
+
8
+type Props = {
9
+
10
+    /**
11
+     * The 'aria-label' text.
12
+     */
13
+    ariaLabel: string,
14
+
15
+    /**
16
+     * The maximum value for slider value.
17
+     */
18
+    max: number,
19
+
20
+    /**
21
+     * The minimum value for slider value.
22
+     */
23
+    min: number,
24
+
25
+    /**
26
+     * Callback invoked on change.
27
+     */
28
+    onChange: Function,
29
+
30
+    /**
31
+     * The granularity that the value must adhere to.
32
+     */
33
+    step: number,
34
+
35
+    /**
36
+     * The current value where the knob is positioned.
37
+     */
38
+    value: number
39
+}
40
+
41
+const useStyles = makeStyles(theme => {
42
+    // keep the same hight for all elements:
43
+    // input, input track & fake track(div)
44
+    const height = 6;
45
+
46
+    const inputTrack = {
47
+        background: 'transparent',
48
+        height
49
+    };
50
+    const inputThumb = {
51
+        background: theme.palette.text01,
52
+        border: 0,
53
+        borderRadius: '50%',
54
+        height: 24,
55
+        width: 24
56
+    };
57
+
58
+    const focused = {
59
+        outline: `1px solid ${theme.palette.action03Focus}`
60
+    };
61
+
62
+    return {
63
+        sliderContainer: {
64
+            cursor: 'pointer',
65
+            width: '100%',
66
+            position: 'relative',
67
+            textAlign: 'center'
68
+
69
+        },
70
+        knobContainer: {
71
+            display: 'flex',
72
+            justifyContent: 'space-between',
73
+            marginLeft: 2,
74
+            marginRight: 2,
75
+            position: 'absolute',
76
+            width: '100%'
77
+        },
78
+        knob: {
79
+            background: theme.palette.text01,
80
+            borderRadius: '50%',
81
+            display: 'inline-block',
82
+            height,
83
+            width: 6
84
+        },
85
+        track: {
86
+            background: theme.palette.ui02,
87
+            borderRadius: theme.shape.borderRadius / 2,
88
+            height
89
+        },
90
+        slider: {
91
+            // Use an additional class here to override global CSS specificity
92
+            '&.custom-slider': {
93
+                '-webkit-appearance': 'none',
94
+                background: 'transparent',
95
+                left: 0,
96
+                position: 'absolute',
97
+                top: 0,
98
+                width: '100%',
99
+
100
+                '&:focus': {
101
+                    // override global styles in order to use our own color
102
+                    outline: 'none !important',
103
+
104
+                    '&::-webkit-slider-runnable-track': focused,
105
+                    '&::ms-track': focused,
106
+                    '&::-moz-range-track': focused
107
+                },
108
+
109
+                '&::-webkit-slider-runnable-track': {
110
+                    '-webkit-appearance': 'none',
111
+                    ...inputTrack
112
+                },
113
+                '&::-webkit-slider-thumb': {
114
+                    '-webkit-appearance': 'none',
115
+                    position: 'relative',
116
+                    top: -6,
117
+                    ...inputThumb
118
+                },
119
+
120
+                '&::ms-track': {
121
+                    ...inputTrack
122
+                },
123
+                '&::-ms-thumb': {
124
+                    ...inputThumb
125
+                },
126
+
127
+                '&::-moz-range-track': {
128
+                    ...inputTrack
129
+                },
130
+                '&::-moz-range-thumb': {
131
+                    ...inputThumb
132
+                }
133
+            }
134
+        }
135
+    };
136
+});
137
+
138
+/**
139
+ *  Custom slider.
140
+ *
141
+ *  @returns {ReactElement}
142
+ */
143
+function Slider({ ariaLabel, max, min, onChange, step, value }: Props) {
144
+    const classes = useStyles();
145
+    const knobs = [ ...Array(Math.floor((max - min) / step) + 1) ];
146
+
147
+    return (
148
+        <div className = { classes.sliderContainer }>
149
+            <ul className = { clsx(commonClassName.emptyList, classes.knobContainer) }>
150
+                {knobs.map((_, i) => (
151
+                    <li
152
+                        className = { classes.knob }
153
+                        key = { `knob-${i}` } />))}
154
+            </ul>
155
+            <div className = { classes.track } />
156
+            <input
157
+                aria-label = { ariaLabel }
158
+                className = { clsx(classes.slider, 'custom-slider') }
159
+                max = { max }
160
+                min = { min }
161
+                onChange = { onChange }
162
+                step = { step }
163
+                type = 'range'
164
+                value = { value } />
165
+        </div>
166
+    );
167
+}
168
+
169
+export default Slider;

+ 2
- 2
react/features/video-quality/components/VideoQualityDialog.web.js Vedi File

@@ -21,8 +21,8 @@ export default class VideoQualityDialog extends Component {
21 21
         return (
22 22
             <Dialog
23 23
                 hideCancelButton = { true }
24
-                okKey = 'dialog.done'
25
-                titleKey = 'videoStatus.callQuality'
24
+                submitDisabled = { true }
25
+                titleKey = 'videoStatus.performanceSettings'
26 26
                 width = 'small'>
27 27
                 <VideoQualitySlider />
28 28
             </Dialog>

+ 57
- 63
react/features/video-quality/components/VideoQualitySlider.web.js Vedi File

@@ -1,5 +1,6 @@
1 1
 // @flow
2
-
2
+import { withStyles } from '@material-ui/core/styles';
3
+import clsx from 'clsx';
3 4
 import React, { Component } from 'react';
4 5
 import type { Dispatch } from 'redux';
5 6
 
@@ -8,10 +9,13 @@ import { setAudioOnly } from '../../base/audio-only';
8 9
 import { translate } from '../../base/i18n';
9 10
 import { setLastN, getLastNForQualityLevel } from '../../base/lastn';
10 11
 import { connect } from '../../base/redux';
12
+import { withPixelLineHeight } from '../../base/styles/functions.web';
11 13
 import { setPreferredVideoQuality } from '../actions';
12 14
 import { DEFAULT_LAST_N, VIDEO_QUALITY_LEVELS } from '../constants';
13 15
 import logger from '../logger';
14 16
 
17
+import Slider from './Slider';
18
+
15 19
 const {
16 20
     ULTRA,
17 21
     HIGH,
@@ -61,6 +65,11 @@ type Props = {
61 65
      */
62 66
     _sendrecvVideoQuality: Number,
63 67
 
68
+  /**
69
+     * An object containing the CSS classes.
70
+     */
71
+    classes: Object,
72
+
64 73
     /**
65 74
      * Invoked to request toggling of audio only mode.
66 75
      */
@@ -72,6 +81,38 @@ type Props = {
72 81
     t: Function
73 82
 };
74 83
 
84
+
85
+/**
86
+ * Creates the styles for the component.
87
+ *
88
+ * @param {Object} theme - The current UI theme.
89
+ *
90
+ * @returns {Object}
91
+ */
92
+const styles = theme => {
93
+    return {
94
+        dialog: {
95
+            color: theme.palette.text01
96
+        },
97
+        dialogDetails: {
98
+            ...withPixelLineHeight(theme.typography.bodyShortRegularLarge),
99
+            marginBottom: 16
100
+        },
101
+        dialogContents: {
102
+            background: theme.palette.ui01,
103
+            padding: '16px 16px 48px 16px'
104
+        },
105
+        sliderDescription: {
106
+            ...withPixelLineHeight(theme.typography.heading6),
107
+
108
+            display: 'flex',
109
+            justifyContent: 'space-between',
110
+            marginBottom: 40
111
+        }
112
+    };
113
+};
114
+
115
+
75 116
 /**
76 117
  * Implements a React {@link Component} which displays a slider for selecting a
77 118
  * new receive video quality.
@@ -139,76 +180,29 @@ class VideoQualitySlider extends Component<Props> {
139 180
      * @returns {ReactElement}
140 181
      */
141 182
     render() {
142
-        const { t } = this.props;
183
+        const { classes, t } = this.props;
143 184
         const activeSliderOption = this._mapCurrentQualityToSliderValue();
144 185
 
145 186
         return (
146
-            <div className = { 'video-quality-dialog' }>
147
-                <h3 className = 'video-quality-dialog-title'>
148
-                    { t('videoStatus.callQuality') }
149
-                </h3>
150
-                <div className = 'video-quality-dialog-contents'>
151
-                    <div className = 'video-quality-dialog-slider-container'>
152
-                        { /* FIXME: onChange and onMouseUp are both used for
153
-                           * compatibility with IE11. This workaround can be
154
-                           * removed after upgrading to React 16.
155
-                           */ }
156
-                        <input
157
-                            aria-label = { t('videoStatus.callQuality') }
158
-                            className = 'video-quality-dialog-slider'
159
-                            max = { this._sliderOptions.length - 1 }
160
-                            min = '0'
161
-                            onChange = { this._onSliderChange }
162
-                            onMouseUp = { this._onSliderChange }
163
-                            step = '1'
164
-                            type = 'range'
165
-                            value
166
-                                = { activeSliderOption } />
167
-
168
-                    </div>
169
-                    <div className = 'video-quality-dialog-labels'>
170
-                        { this._createLabels(activeSliderOption) }
187
+            <div className = { clsx('video-quality-dialog', classes.dialog) }>
188
+                <div className = { classes.dialogDetails }>{t('videoStatus.adjustFor')}</div>
189
+                <div className = { classes.dialogContents }>
190
+                    <div className = { classes.sliderDescription }>
191
+                        <span>{t('videoStatus.bestPerformance')}</span>
192
+                        <span>{t('videoStatus.highestQuality')}</span>
171 193
                     </div>
194
+                    <Slider
195
+                        ariaLabel = { t('videoStatus.callQuality') }
196
+                        max = { this._sliderOptions.length - 1 }
197
+                        min = { 0 }
198
+                        onChange = { this._onSliderChange }
199
+                        step = { 1 }
200
+                        value = { activeSliderOption } />
172 201
                 </div>
173 202
             </div>
174 203
         );
175 204
     }
176 205
 
177
-    /**
178
-     * Creates React Elements to display mock tick marks with associated labels.
179
-     *
180
-     * @param {number} activeLabelIndex - Which of the sliderOptions should
181
-     * display as currently active.
182
-     * @private
183
-     * @returns {ReactElement[]}
184
-     */
185
-    _createLabels(activeLabelIndex) {
186
-        const labelsCount = this._sliderOptions.length;
187
-        const maxWidthOfLabel = `${100 / labelsCount}%`;
188
-
189
-        return this._sliderOptions.map((sliderOption, index) => {
190
-            const style = {
191
-                maxWidth: maxWidthOfLabel,
192
-                left: `${(index * 100) / (labelsCount - 1)}%`
193
-            };
194
-
195
-            const isActiveClass = activeLabelIndex === index ? 'active' : '';
196
-            const className
197
-                = `video-quality-dialog-label-container ${isActiveClass}`;
198
-
199
-            return (
200
-                <div
201
-                    className = { className }
202
-                    key = { index }
203
-                    style = { style }>
204
-                    <div className = 'video-quality-dialog-label'>
205
-                        { this.props.t(sliderOption.textKey) }
206
-                    </div>
207
-                </div>
208
-            );
209
-        });
210
-    }
211
-
212 206
     _enableAudioOnly: () => void;
213 207
 
214 208
     /**
@@ -386,4 +380,4 @@ function _mapStateToProps(state) {
386 380
     };
387 381
 }
388 382
 
389
-export default translate(connect(_mapStateToProps)(VideoQualitySlider));
383
+export default translate(connect(_mapStateToProps)(withStyles(styles)(VideoQualitySlider)));

Loading…
Annulla
Salva