@@ -34,7 +34,7 @@ class FigmaToggle extends StatelessWidget {
34
34
final theme = Theme .of (context);
35
35
final colorScheme = theme.colorScheme;
36
36
37
- // Figma-specified dimensions
37
+ // Exact Figma-specified dimensions
38
38
final trackWidth = value ? 48.0 : 46.0 ;
39
39
final trackHeight = value ? 28.0 : 26.0 ;
40
40
final thumbRadius = value ? 10.0 : 7.0 ;
@@ -48,6 +48,13 @@ class FigmaToggle extends StatelessWidget {
48
48
final trackColor = value ? effectiveActiveColor : effectiveInactiveColor;
49
49
final thumbColor = value ? effectiveActiveThumbColor : effectiveInactiveThumbColor;
50
50
51
+ // Calculate thumb positioning with proper padding
52
+ final thumbDiameter = thumbRadius * 2 ;
53
+ final horizontalPadding = 4.0 ;
54
+ final thumbLeftPosition = value
55
+ ? trackWidth - thumbDiameter - horizontalPadding
56
+ : horizontalPadding;
57
+
51
58
return GestureDetector (
52
59
onTap: onChanged != null ? () => onChanged !(! value) : null ,
53
60
child: AnimatedContainer (
@@ -64,15 +71,13 @@ class FigmaToggle extends StatelessWidget {
64
71
AnimatedPositioned (
65
72
duration: const Duration (milliseconds: 200 ),
66
73
curve: Curves .easeInOut,
67
- left: value
68
- ? trackWidth - (thumbRadius * 2 ) - 4.0 // 4px padding from edge
69
- : 4.0 , // 4px padding from edge
70
- top: (trackHeight - (thumbRadius * 2 )) / 2 ,
74
+ left: thumbLeftPosition,
75
+ top: (trackHeight - thumbDiameter) / 2 ,
71
76
child: AnimatedContainer (
72
77
duration: const Duration (milliseconds: 200 ),
73
78
curve: Curves .easeInOut,
74
- width: thumbRadius * 2 ,
75
- height: thumbRadius * 2 ,
79
+ width: thumbDiameter ,
80
+ height: thumbDiameter ,
76
81
decoration: BoxDecoration (
77
82
shape: BoxShape .circle,
78
83
color: thumbColor,
@@ -105,26 +110,35 @@ class SettingsPage extends StatelessWidget {
105
110
106
111
static AccountRoute <void > buildRoute ({required BuildContext context}) {
107
112
return MaterialAccountWidgetRoute (
108
- context: context, page: const SettingsPage ());
113
+ context: context,
114
+ page: const SettingsPage (),
115
+ );
109
116
}
110
117
111
118
@override
112
119
Widget build (BuildContext context) {
113
120
final zulipLocalizations = ZulipLocalizations .of (context);
114
121
return Scaffold (
115
122
appBar: ZulipAppBar (
116
- title: Text (zulipLocalizations.settingsPageTitle)),
117
- body: Column (children: [
118
- const _ThemeSetting (),
119
- const _BrowserPreferenceSetting (),
120
- const _VisitFirstUnreadSetting (),
121
- const _MarkReadOnScrollSetting (),
122
- if (GlobalSettingsStore .experimentalFeatureFlags.isNotEmpty)
123
- ListTile (
124
- title: Text (zulipLocalizations.experimentalFeatureSettingsPageTitle),
125
- onTap: () => Navigator .push (context,
126
- ExperimentalFeaturesPage .buildRoute ()))
127
- ]));
123
+ title: Text (zulipLocalizations.settingsPageTitle),
124
+ ),
125
+ body: Column (
126
+ children: [
127
+ const _ThemeSetting (),
128
+ const _BrowserPreferenceSetting (),
129
+ const _VisitFirstUnreadSetting (),
130
+ const _MarkReadOnScrollSetting (),
131
+ if (GlobalSettingsStore .experimentalFeatureFlags.isNotEmpty)
132
+ ListTile (
133
+ title: Text (zulipLocalizations.experimentalFeatureSettingsPageTitle),
134
+ onTap: () => Navigator .push (
135
+ context,
136
+ ExperimentalFeaturesPage .buildRoute (),
137
+ ),
138
+ ),
139
+ ],
140
+ ),
141
+ );
128
142
}
129
143
}
130
144
@@ -147,14 +161,14 @@ class _ThemeSetting extends StatelessWidget {
147
161
RadioListTile <ThemeSetting ?>.adaptive (
148
162
title: Text (ThemeSetting .displayName (
149
163
themeSetting: themeSettingOption,
150
- zulipLocalizations: zulipLocalizations)),
164
+ zulipLocalizations: zulipLocalizations,
165
+ )),
151
166
value: themeSettingOption,
152
- // TODO(#1545) stop using the deprecated members
153
- // ignore: deprecated_member_use
154
167
groupValue: globalSettings.themeSetting,
155
- // ignore: deprecated_member_use
156
- onChanged: (newValue) => _handleChange (context, newValue)),
157
- ]);
168
+ onChanged: (newValue) => _handleChange (context, newValue),
169
+ ),
170
+ ],
171
+ );
158
172
}
159
173
}
160
174
@@ -165,7 +179,8 @@ class _BrowserPreferenceSetting extends StatelessWidget {
165
179
final globalSettings = GlobalStoreWidget .settingsOf (context);
166
180
globalSettings.setBrowserPreference (
167
181
newOpenLinksWithInAppBrowser ? BrowserPreference .inApp
168
- : BrowserPreference .external );
182
+ : BrowserPreference .external ,
183
+ );
169
184
}
170
185
171
186
@override
@@ -194,9 +209,14 @@ class _VisitFirstUnreadSetting extends StatelessWidget {
194
209
return ListTile (
195
210
title: Text (zulipLocalizations.initialAnchorSettingTitle),
196
211
subtitle: Text (VisitFirstUnreadSettingPage ._valueDisplayName (
197
- globalSettings.visitFirstUnread, zulipLocalizations: zulipLocalizations)),
198
- onTap: () => Navigator .push (context,
199
- VisitFirstUnreadSettingPage .buildRoute ()));
212
+ globalSettings.visitFirstUnread,
213
+ zulipLocalizations: zulipLocalizations,
214
+ )),
215
+ onTap: () => Navigator .push (
216
+ context,
217
+ VisitFirstUnreadSettingPage .buildRoute (),
218
+ ),
219
+ );
200
220
}
201
221
}
202
222
@@ -207,7 +227,8 @@ class VisitFirstUnreadSettingPage extends StatelessWidget {
207
227
return MaterialWidgetRoute (page: const VisitFirstUnreadSettingPage ());
208
228
}
209
229
210
- static String _valueDisplayName (VisitFirstUnreadSetting value, {
230
+ static String _valueDisplayName (
231
+ VisitFirstUnreadSetting value, {
211
232
required ZulipLocalizations zulipLocalizations,
212
233
}) {
213
234
return switch (value) {
@@ -221,7 +242,7 @@ class VisitFirstUnreadSettingPage extends StatelessWidget {
221
242
}
222
243
223
244
void _handleChange (BuildContext context, VisitFirstUnreadSetting ? value) {
224
- if (value == null ) return ; // TODO(log); can this actually happen? how?
245
+ if (value == null ) return ;
225
246
final globalSettings = GlobalStoreWidget .settingsOf (context);
226
247
globalSettings.setVisitFirstUnread (value);
227
248
}
@@ -232,19 +253,28 @@ class VisitFirstUnreadSettingPage extends StatelessWidget {
232
253
final globalSettings = GlobalStoreWidget .settingsOf (context);
233
254
return Scaffold (
234
255
appBar: AppBar (title: Text (zulipLocalizations.initialAnchorSettingTitle)),
235
- body: Column (children: [
236
- ListTile (title: Text (zulipLocalizations.initialAnchorSettingDescription)),
237
- for (final value in VisitFirstUnreadSetting .values)
238
- RadioListTile .adaptive (
239
- title: Text (_valueDisplayName (value,
240
- zulipLocalizations: zulipLocalizations)),
241
- value: value,
242
- // TODO(#1545) stop using the deprecated members
243
- // ignore: deprecated_member_use
256
+ body: Column (
257
+ children: [
258
+ ListTile (title: Text (zulipLocalizations.initialAnchorSettingDescription)),
259
+ RadioGroup <VisitFirstUnreadSetting >(
244
260
groupValue: globalSettings.visitFirstUnread,
245
- // ignore: deprecated_member_use
246
- onChanged: (newValue) => _handleChange (context, newValue)),
247
- ]));
261
+ onChanged: (newValue) => _handleChange (context, newValue),
262
+ child: Column (
263
+ children: [
264
+ for (final value in VisitFirstUnreadSetting .values)
265
+ RadioListTile .adaptive (
266
+ title: Text (_valueDisplayName (
267
+ value,
268
+ zulipLocalizations: zulipLocalizations,
269
+ )),
270
+ value: value,
271
+ ),
272
+ ],
273
+ ),
274
+ ),
275
+ ],
276
+ ),
277
+ );
248
278
}
249
279
}
250
280
@@ -258,9 +288,14 @@ class _MarkReadOnScrollSetting extends StatelessWidget {
258
288
return ListTile (
259
289
title: Text (zulipLocalizations.markReadOnScrollSettingTitle),
260
290
subtitle: Text (MarkReadOnScrollSettingPage ._valueDisplayName (
261
- globalSettings.markReadOnScroll, zulipLocalizations: zulipLocalizations)),
262
- onTap: () => Navigator .push (context,
263
- MarkReadOnScrollSettingPage .buildRoute ()));
291
+ globalSettings.markReadOnScroll,
292
+ zulipLocalizations: zulipLocalizations,
293
+ )),
294
+ onTap: () => Navigator .push (
295
+ context,
296
+ MarkReadOnScrollSettingPage .buildRoute (),
297
+ ),
298
+ );
264
299
}
265
300
}
266
301
@@ -271,7 +306,8 @@ class MarkReadOnScrollSettingPage extends StatelessWidget {
271
306
return MaterialWidgetRoute (page: const MarkReadOnScrollSettingPage ());
272
307
}
273
308
274
- static String _valueDisplayName (MarkReadOnScrollSetting value, {
309
+ static String _valueDisplayName (
310
+ MarkReadOnScrollSetting value, {
275
311
required ZulipLocalizations zulipLocalizations,
276
312
}) {
277
313
return switch (value) {
@@ -284,7 +320,8 @@ class MarkReadOnScrollSettingPage extends StatelessWidget {
284
320
};
285
321
}
286
322
287
- static String ? _valueDescription (MarkReadOnScrollSetting value, {
323
+ static String ? _valueDescription (
324
+ MarkReadOnScrollSetting value, {
288
325
required ZulipLocalizations zulipLocalizations,
289
326
}) {
290
327
return switch (value) {
@@ -296,7 +333,7 @@ class MarkReadOnScrollSettingPage extends StatelessWidget {
296
333
}
297
334
298
335
void _handleChange (BuildContext context, MarkReadOnScrollSetting ? value) {
299
- if (value == null ) return ; // TODO(log); can this actually happen? how?
336
+ if (value == null ) return ;
300
337
final globalSettings = GlobalStoreWidget .settingsOf (context);
301
338
globalSettings.setMarkReadOnScroll (value);
302
339
}
@@ -307,24 +344,35 @@ class MarkReadOnScrollSettingPage extends StatelessWidget {
307
344
final globalSettings = GlobalStoreWidget .settingsOf (context);
308
345
return Scaffold (
309
346
appBar: AppBar (title: Text (zulipLocalizations.markReadOnScrollSettingTitle)),
310
- body: Column (children: [
311
- ListTile (title: Text (zulipLocalizations.markReadOnScrollSettingDescription)),
312
- for (final value in MarkReadOnScrollSetting .values)
313
- RadioListTile .adaptive (
314
- title: Text (_valueDisplayName (value,
315
- zulipLocalizations: zulipLocalizations)),
316
- subtitle: () {
317
- final result = _valueDescription (value,
318
- zulipLocalizations: zulipLocalizations);
319
- return result == null ? null : Text (result);
320
- }(),
321
- value: value,
322
- // TODO(#1545) stop using the deprecated members
323
- // ignore: deprecated_member_use
347
+ body: Column (
348
+ children: [
349
+ ListTile (title: Text (zulipLocalizations.markReadOnScrollSettingDescription)),
350
+ RadioGroup <MarkReadOnScrollSetting >(
324
351
groupValue: globalSettings.markReadOnScroll,
325
- // ignore: deprecated_member_use
326
- onChanged: (newValue) => _handleChange (context, newValue)),
327
- ]));
352
+ onChanged: (newValue) => _handleChange (context, newValue),
353
+ child: Column (
354
+ children: [
355
+ for (final value in MarkReadOnScrollSetting .values)
356
+ RadioListTile .adaptive (
357
+ title: Text (_valueDisplayName (
358
+ value,
359
+ zulipLocalizations: zulipLocalizations,
360
+ )),
361
+ subtitle: () {
362
+ final result = _valueDescription (
363
+ value,
364
+ zulipLocalizations: zulipLocalizations,
365
+ );
366
+ return result == null ? null : Text (result);
367
+ }(),
368
+ value: value,
369
+ ),
370
+ ],
371
+ ),
372
+ ),
373
+ ],
374
+ ),
375
+ );
328
376
}
329
377
}
330
378
@@ -343,18 +391,23 @@ class ExperimentalFeaturesPage extends StatelessWidget {
343
391
assert (flags.isNotEmpty);
344
392
return Scaffold (
345
393
appBar: AppBar (
346
- title: Text (zulipLocalizations.experimentalFeatureSettingsPageTitle)),
347
- body: Column (children: [
348
- ListTile (
349
- title: Text (zulipLocalizations.experimentalFeatureSettingsWarning)),
350
- for (final flag in flags)
394
+ title: Text (zulipLocalizations.experimentalFeatureSettingsPageTitle),
395
+ ),
396
+ body: Column (
397
+ children: [
351
398
ListTile (
352
- title: Text (flag.name), // no i18n; these are developer-facing settings
353
- trailing: FigmaToggle (
354
- value: globalSettings.getBool (flag),
355
- onChanged: (value) => globalSettings.setBool (flag, value),
356
- ),
399
+ title: Text (zulipLocalizations.experimentalFeatureSettingsWarning),
357
400
),
358
- ]));
401
+ for (final flag in flags)
402
+ ListTile (
403
+ title: Text (flag.name), // no i18n; these are developer-facing settings
404
+ trailing: FigmaToggle (
405
+ value: globalSettings.getBool (flag),
406
+ onChanged: (value) => globalSettings.setBool (flag, value),
407
+ ),
408
+ ),
409
+ ],
410
+ ),
411
+ );
359
412
}
360
413
}
0 commit comments