Skip to content

Commit b4f33cf

Browse files
committed
test(settings): Adapt BrowserPreference tests to FigmaToggle
1 parent ea7abd2 commit b4f33cf

File tree

2 files changed

+249
-103
lines changed

2 files changed

+249
-103
lines changed

lib/widgets/settings.dart

Lines changed: 144 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class FigmaToggle extends StatelessWidget {
3434
final theme = Theme.of(context);
3535
final colorScheme = theme.colorScheme;
3636

37-
// Figma-specified dimensions
37+
// Exact Figma-specified dimensions
3838
final trackWidth = value ? 48.0 : 46.0;
3939
final trackHeight = value ? 28.0 : 26.0;
4040
final thumbRadius = value ? 10.0 : 7.0;
@@ -48,6 +48,13 @@ class FigmaToggle extends StatelessWidget {
4848
final trackColor = value ? effectiveActiveColor : effectiveInactiveColor;
4949
final thumbColor = value ? effectiveActiveThumbColor : effectiveInactiveThumbColor;
5050

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+
5158
return GestureDetector(
5259
onTap: onChanged != null ? () => onChanged!(!value) : null,
5360
child: AnimatedContainer(
@@ -64,21 +71,19 @@ class FigmaToggle extends StatelessWidget {
6471
AnimatedPositioned(
6572
duration: const Duration(milliseconds: 200),
6673
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,
7176
child: AnimatedContainer(
7277
duration: const Duration(milliseconds: 200),
7378
curve: Curves.easeInOut,
74-
width: thumbRadius * 2,
75-
height: thumbRadius * 2,
79+
width: thumbDiameter,
80+
height: thumbDiameter,
7681
decoration: BoxDecoration(
7782
shape: BoxShape.circle,
7883
color: thumbColor,
7984
boxShadow: [
8085
BoxShadow(
81-
color: Colors.black.withOpacity(0.2),
86+
color: Colors.black.withValues(alpha: 0.2),
8287
blurRadius: 4,
8388
offset: const Offset(0, 2),
8489
),
@@ -105,26 +110,35 @@ class SettingsPage extends StatelessWidget {
105110

106111
static AccountRoute<void> buildRoute({required BuildContext context}) {
107112
return MaterialAccountWidgetRoute(
108-
context: context, page: const SettingsPage());
113+
context: context,
114+
page: const SettingsPage(),
115+
);
109116
}
110117

111118
@override
112119
Widget build(BuildContext context) {
113120
final zulipLocalizations = ZulipLocalizations.of(context);
114121
return Scaffold(
115122
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+
);
128142
}
129143
}
130144

@@ -143,18 +157,24 @@ class _ThemeSetting extends StatelessWidget {
143157
return Column(
144158
children: [
145159
ListTile(title: Text(zulipLocalizations.themeSettingTitle)),
146-
for (final themeSettingOption in [null, ...ThemeSetting.values])
147-
RadioListTile<ThemeSetting?>.adaptive(
148-
title: Text(ThemeSetting.displayName(
149-
themeSetting: themeSettingOption,
150-
zulipLocalizations: zulipLocalizations)),
151-
value: themeSettingOption,
152-
// TODO(#1545) stop using the deprecated members
153-
// ignore: deprecated_member_use
154-
groupValue: globalSettings.themeSetting,
155-
// ignore: deprecated_member_use
156-
onChanged: (newValue) => _handleChange(context, newValue)),
157-
]);
160+
RadioGroup<ThemeSetting?>(
161+
groupValue: globalSettings.themeSetting,
162+
onChanged: (newValue) => _handleChange(context, newValue),
163+
child: Column(
164+
children: [
165+
for (final themeSettingOption in [null, ...ThemeSetting.values])
166+
RadioListTile<ThemeSetting?>.adaptive(
167+
title: Text(ThemeSetting.displayName(
168+
themeSetting: themeSettingOption,
169+
zulipLocalizations: zulipLocalizations,
170+
)),
171+
value: themeSettingOption,
172+
),
173+
],
174+
),
175+
),
176+
],
177+
);
158178
}
159179
}
160180

@@ -165,7 +185,8 @@ class _BrowserPreferenceSetting extends StatelessWidget {
165185
final globalSettings = GlobalStoreWidget.settingsOf(context);
166186
globalSettings.setBrowserPreference(
167187
newOpenLinksWithInAppBrowser ? BrowserPreference.inApp
168-
: BrowserPreference.external);
188+
: BrowserPreference.external,
189+
);
169190
}
170191

171192
@override
@@ -194,9 +215,14 @@ class _VisitFirstUnreadSetting extends StatelessWidget {
194215
return ListTile(
195216
title: Text(zulipLocalizations.initialAnchorSettingTitle),
196217
subtitle: Text(VisitFirstUnreadSettingPage._valueDisplayName(
197-
globalSettings.visitFirstUnread, zulipLocalizations: zulipLocalizations)),
198-
onTap: () => Navigator.push(context,
199-
VisitFirstUnreadSettingPage.buildRoute()));
218+
globalSettings.visitFirstUnread,
219+
zulipLocalizations: zulipLocalizations,
220+
)),
221+
onTap: () => Navigator.push(
222+
context,
223+
VisitFirstUnreadSettingPage.buildRoute(),
224+
),
225+
);
200226
}
201227
}
202228

@@ -207,7 +233,8 @@ class VisitFirstUnreadSettingPage extends StatelessWidget {
207233
return MaterialWidgetRoute(page: const VisitFirstUnreadSettingPage());
208234
}
209235

210-
static String _valueDisplayName(VisitFirstUnreadSetting value, {
236+
static String _valueDisplayName(
237+
VisitFirstUnreadSetting value, {
211238
required ZulipLocalizations zulipLocalizations,
212239
}) {
213240
return switch (value) {
@@ -221,7 +248,7 @@ class VisitFirstUnreadSettingPage extends StatelessWidget {
221248
}
222249

223250
void _handleChange(BuildContext context, VisitFirstUnreadSetting? value) {
224-
if (value == null) return; // TODO(log); can this actually happen? how?
251+
if (value == null) return;
225252
final globalSettings = GlobalStoreWidget.settingsOf(context);
226253
globalSettings.setVisitFirstUnread(value);
227254
}
@@ -232,19 +259,28 @@ class VisitFirstUnreadSettingPage extends StatelessWidget {
232259
final globalSettings = GlobalStoreWidget.settingsOf(context);
233260
return Scaffold(
234261
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
262+
body: Column(
263+
children: [
264+
ListTile(title: Text(zulipLocalizations.initialAnchorSettingDescription)),
265+
RadioGroup<VisitFirstUnreadSetting>(
244266
groupValue: globalSettings.visitFirstUnread,
245-
// ignore: deprecated_member_use
246-
onChanged: (newValue) => _handleChange(context, newValue)),
247-
]));
267+
onChanged: (newValue) => _handleChange(context, newValue),
268+
child: Column(
269+
children: [
270+
for (final value in VisitFirstUnreadSetting.values)
271+
RadioListTile.adaptive(
272+
title: Text(_valueDisplayName(
273+
value,
274+
zulipLocalizations: zulipLocalizations,
275+
)),
276+
value: value,
277+
),
278+
],
279+
),
280+
),
281+
],
282+
),
283+
);
248284
}
249285
}
250286

@@ -258,9 +294,14 @@ class _MarkReadOnScrollSetting extends StatelessWidget {
258294
return ListTile(
259295
title: Text(zulipLocalizations.markReadOnScrollSettingTitle),
260296
subtitle: Text(MarkReadOnScrollSettingPage._valueDisplayName(
261-
globalSettings.markReadOnScroll, zulipLocalizations: zulipLocalizations)),
262-
onTap: () => Navigator.push(context,
263-
MarkReadOnScrollSettingPage.buildRoute()));
297+
globalSettings.markReadOnScroll,
298+
zulipLocalizations: zulipLocalizations,
299+
)),
300+
onTap: () => Navigator.push(
301+
context,
302+
MarkReadOnScrollSettingPage.buildRoute(),
303+
),
304+
);
264305
}
265306
}
266307

@@ -271,7 +312,8 @@ class MarkReadOnScrollSettingPage extends StatelessWidget {
271312
return MaterialWidgetRoute(page: const MarkReadOnScrollSettingPage());
272313
}
273314

274-
static String _valueDisplayName(MarkReadOnScrollSetting value, {
315+
static String _valueDisplayName(
316+
MarkReadOnScrollSetting value, {
275317
required ZulipLocalizations zulipLocalizations,
276318
}) {
277319
return switch (value) {
@@ -284,7 +326,8 @@ class MarkReadOnScrollSettingPage extends StatelessWidget {
284326
};
285327
}
286328

287-
static String? _valueDescription(MarkReadOnScrollSetting value, {
329+
static String? _valueDescription(
330+
MarkReadOnScrollSetting value, {
288331
required ZulipLocalizations zulipLocalizations,
289332
}) {
290333
return switch (value) {
@@ -296,7 +339,7 @@ class MarkReadOnScrollSettingPage extends StatelessWidget {
296339
}
297340

298341
void _handleChange(BuildContext context, MarkReadOnScrollSetting? value) {
299-
if (value == null) return; // TODO(log); can this actually happen? how?
342+
if (value == null) return;
300343
final globalSettings = GlobalStoreWidget.settingsOf(context);
301344
globalSettings.setMarkReadOnScroll(value);
302345
}
@@ -307,24 +350,35 @@ class MarkReadOnScrollSettingPage extends StatelessWidget {
307350
final globalSettings = GlobalStoreWidget.settingsOf(context);
308351
return Scaffold(
309352
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
353+
body: Column(
354+
children: [
355+
ListTile(title: Text(zulipLocalizations.markReadOnScrollSettingDescription)),
356+
RadioGroup<MarkReadOnScrollSetting>(
324357
groupValue: globalSettings.markReadOnScroll,
325-
// ignore: deprecated_member_use
326-
onChanged: (newValue) => _handleChange(context, newValue)),
327-
]));
358+
onChanged: (newValue) => _handleChange(context, newValue),
359+
child: Column(
360+
children: [
361+
for (final value in MarkReadOnScrollSetting.values)
362+
RadioListTile.adaptive(
363+
title: Text(_valueDisplayName(
364+
value,
365+
zulipLocalizations: zulipLocalizations,
366+
)),
367+
subtitle: () {
368+
final result = _valueDescription(
369+
value,
370+
zulipLocalizations: zulipLocalizations,
371+
);
372+
return result == null ? null : Text(result);
373+
}(),
374+
value: value,
375+
),
376+
],
377+
),
378+
),
379+
],
380+
),
381+
);
328382
}
329383
}
330384

@@ -343,18 +397,23 @@ class ExperimentalFeaturesPage extends StatelessWidget {
343397
assert(flags.isNotEmpty);
344398
return Scaffold(
345399
appBar: AppBar(
346-
title: Text(zulipLocalizations.experimentalFeatureSettingsPageTitle)),
347-
body: Column(children: [
348-
ListTile(
349-
title: Text(zulipLocalizations.experimentalFeatureSettingsWarning)),
350-
for (final flag in flags)
400+
title: Text(zulipLocalizations.experimentalFeatureSettingsPageTitle),
401+
),
402+
body: Column(
403+
children: [
351404
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-
),
405+
title: Text(zulipLocalizations.experimentalFeatureSettingsWarning),
357406
),
358-
]));
407+
for (final flag in flags)
408+
ListTile(
409+
title: Text(flag.name), // no i18n; these are developer-facing settings
410+
trailing: FigmaToggle(
411+
value: globalSettings.getBool(flag),
412+
onChanged: (value) => globalSettings.setBool(flag, value),
413+
),
414+
),
415+
],
416+
),
417+
);
359418
}
360419
}

0 commit comments

Comments
 (0)