@@ -14,29 +14,26 @@ See the License for the specific language governing permissions and
14
14
limitations under the License.
15
15
*/
16
16
17
- import React , { ChangeEvent } from "react" ;
17
+ import React from "react" ;
18
18
19
19
import EventTilePreview from "../elements/EventTilePreview" ;
20
- import Field from "../elements/Field" ;
21
- import SettingsFlag from "../elements/SettingsFlag" ;
22
20
import SettingsStore from "../../../settings/SettingsStore" ;
23
- import Slider from "../elements/Slider" ;
24
- import { FontWatcher } from "../../../settings/watchers/FontWatcher" ;
25
- import { IValidationResult , IFieldState } from "../elements/Validation" ;
26
21
import { Layout } from "../../../settings/enums/Layout" ;
27
22
import { MatrixClientPeg } from "../../../MatrixClientPeg" ;
28
23
import { SettingLevel } from "../../../settings/SettingLevel" ;
29
24
import { _t } from "../../../languageHandler" ;
30
- import { clamp } from "../../../utils/numbers" ;
31
25
import SettingsSubsection from "./shared/SettingsSubsection" ;
26
+ import Field from "../elements/Field" ;
27
+ import { FontWatcher } from "../../../settings/watchers/FontWatcher" ;
32
28
33
29
interface IProps { }
34
30
35
31
interface IState {
32
+ browserFontSize : number ;
36
33
// String displaying the current selected fontSize.
37
- // Needs to be string for things like '17 .' without
34
+ // Needs to be string for things like '1 .' without
38
35
// trailing 0s.
39
- fontSize : string ;
36
+ fontSizeDelta : number ;
40
37
useCustomFontSize : boolean ;
41
38
layout : Layout ;
42
39
// User profile data for the message preview
@@ -47,14 +44,19 @@ interface IState {
47
44
48
45
export default class FontScalingPanel extends React . Component < IProps , IState > {
49
46
private readonly MESSAGE_PREVIEW_TEXT = _t ( "common|preview_message" ) ;
47
+ /**
48
+ * Font sizes available (in px)
49
+ */
50
+ private readonly sizes = [ 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 20 , 22 , 24 , 26 , 28 , 30 , 32 , 34 , 36 ] ;
50
51
private layoutWatcherRef ?: string ;
51
52
private unmounted = false ;
52
53
53
54
public constructor ( props : IProps ) {
54
55
super ( props ) ;
55
56
56
57
this . state = {
57
- fontSize : SettingsStore . getValue ( "baseFontSizeV2" , null ) . toString ( ) ,
58
+ fontSizeDelta : SettingsStore . getValue < number > ( "fontSizeDelta" , null ) ,
59
+ browserFontSize : FontWatcher . getBrowserDefaultFontSize ( ) ,
58
60
useCustomFontSize : SettingsStore . getValue ( "useCustomFontSize" ) ,
59
61
layout : SettingsStore . getValue ( "layout" ) ,
60
62
} ;
@@ -90,30 +92,22 @@ export default class FontScalingPanel extends React.Component<IProps, IState> {
90
92
}
91
93
}
92
94
93
- private onFontSizeChanged = ( size : number ) : void => {
94
- this . setState ( { fontSize : size . toString ( ) } ) ;
95
- SettingsStore . setValue ( "baseFontSizeV2" , null , SettingLevel . DEVICE , size ) ;
95
+ /**
96
+ * Save the new font size
97
+ * @param delta
98
+ */
99
+ private onFontSizeChanged = async ( delta : string ) : Promise < void > => {
100
+ const parsedDelta = parseInt ( delta , 10 ) || 0 ;
101
+ this . setState ( { fontSizeDelta : parsedDelta } ) ;
102
+ await SettingsStore . setValue ( "fontSizeDelta" , null , SettingLevel . DEVICE , parsedDelta ) ;
96
103
} ;
97
104
98
- private onValidateFontSize = async ( { value } : Pick < IFieldState , "value" > ) : Promise < IValidationResult > => {
99
- const parsedSize = parseFloat ( value ! ) ;
100
- const min = FontWatcher . MIN_SIZE ;
101
- const max = FontWatcher . MAX_SIZE ;
102
-
103
- if ( isNaN ( parsedSize ) ) {
104
- return { valid : false , feedback : _t ( "settings|appearance|font_size_nan" ) } ;
105
- }
106
-
107
- if ( ! ( min <= parsedSize && parsedSize <= max ) ) {
108
- return {
109
- valid : false ,
110
- feedback : _t ( "settings|appearance|font_size_limit" , { min, max } ) ,
111
- } ;
112
- }
113
-
114
- SettingsStore . setValue ( "baseFontSizeV2" , null , SettingLevel . DEVICE , parseInt ( value ! , 10 ) ) ;
115
-
116
- return { valid : true , feedback : _t ( "settings|appearance|font_size_valid" , { min, max } ) } ;
105
+ /**
106
+ * Compute the difference between the selected font size and the browser font size
107
+ * @param fontSize
108
+ */
109
+ private computeDeltaFontSize = ( fontSize : number ) : number => {
110
+ return fontSize - this . state . browserFontSize ;
117
111
} ;
118
112
119
113
public render ( ) : React . ReactNode {
@@ -123,6 +117,21 @@ export default class FontScalingPanel extends React.Component<IProps, IState> {
123
117
stretchContent
124
118
data-testid = "mx_FontScalingPanel"
125
119
>
120
+ < Field
121
+ element = "select"
122
+ className = "mx_FontScalingPanel_Dropdown"
123
+ label = { _t ( "settings|appearance|font_size" ) }
124
+ value = { this . state . fontSizeDelta . toString ( ) }
125
+ onChange = { ( e ) => this . onFontSizeChanged ( e . target . value ) }
126
+ >
127
+ { this . sizes . map ( ( size ) => (
128
+ < option key = { size } value = { this . computeDeltaFontSize ( size ) } >
129
+ { size === this . state . browserFontSize
130
+ ? _t ( "settings|appearance|font_size_default" , { fontSize : size } )
131
+ : size }
132
+ </ option >
133
+ ) ) }
134
+ </ Field >
126
135
< EventTilePreview
127
136
className = "mx_FontScalingPanel_preview"
128
137
message = { this . MESSAGE_PREVIEW_TEXT }
@@ -131,49 +140,6 @@ export default class FontScalingPanel extends React.Component<IProps, IState> {
131
140
displayName = { this . state . displayName }
132
141
avatarUrl = { this . state . avatarUrl }
133
142
/>
134
- < div className = "mx_FontScalingPanel_fontSlider" >
135
- < div className = "mx_FontScalingPanel_fontSlider_smallText" > Aa</ div >
136
- < Slider
137
- min = { FontWatcher . MIN_SIZE }
138
- max = { FontWatcher . MAX_SIZE }
139
- step = { 1 }
140
- value = { parseInt ( this . state . fontSize , 10 ) }
141
- onChange = { this . onFontSizeChanged }
142
- displayFunc = { ( _ ) => "" }
143
- disabled = { this . state . useCustomFontSize }
144
- label = { _t ( "settings|appearance|font_size" ) }
145
- />
146
- < div className = "mx_FontScalingPanel_fontSlider_largeText" > Aa</ div >
147
- </ div >
148
-
149
- < SettingsFlag
150
- name = "useCustomFontSize"
151
- level = { SettingLevel . ACCOUNT }
152
- onChange = { ( checked ) => {
153
- this . setState ( { useCustomFontSize : checked } ) ;
154
- if ( ! checked ) {
155
- const size = parseInt ( this . state . fontSize , 10 ) ;
156
- const clamped = clamp ( size , FontWatcher . MIN_SIZE , FontWatcher . MAX_SIZE ) ;
157
- if ( clamped !== size ) {
158
- this . onFontSizeChanged ( clamped ) ;
159
- }
160
- }
161
- } }
162
- useCheckbox = { true }
163
- />
164
-
165
- < Field
166
- type = "number"
167
- label = { _t ( "settings|appearance|font_size" ) }
168
- autoComplete = "off"
169
- placeholder = { this . state . fontSize . toString ( ) }
170
- value = { this . state . fontSize . toString ( ) }
171
- id = "font_size_field"
172
- onValidate = { this . onValidateFontSize }
173
- onChange = { ( value : ChangeEvent < HTMLInputElement > ) => this . setState ( { fontSize : value . target . value } ) }
174
- disabled = { ! this . state . useCustomFontSize }
175
- className = "mx_AppearanceUserSettingsTab_checkboxControlledField"
176
- />
177
143
</ SettingsSubsection >
178
144
) ;
179
145
}
0 commit comments