Settings rows carried their own platform-conditional typography and density, so on desktop and TV they rendered a 16px title, 14px subtitle and 80px row while every other row in the app — the Focusable*ListTile defaults plus ThemeData.listTileTheme's `dense: true` — renders 13/12 in 61px. Drop the overrides instead of re-tuning them: the tile defaults already encode the app's row style, and the explicit title styles were redundant under a dense ListTile (they also masked the disabled/selected title color). settingsOptionTitleStyle now only serves group children that are not ListTiles, and matches the dense title unconditionally. SettingsGroup hands its children that same compact density, so the plain ListTiles used as non-interactive info rows stop standing 11px taller than their interactive siblings.
95 lines
3.9 KiB
Dart
95 lines
3.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:plezy/theme/mono_theme.dart';
|
|
import 'package:plezy/widgets/focusable_list_tile.dart';
|
|
import 'package:plezy/widgets/setting_tile.dart';
|
|
import 'package:plezy/widgets/settings_section.dart';
|
|
|
|
/// Settings rows must render exactly like every other row in the app on every
|
|
/// platform. Each row type is measured against an untouched [FocusableListTile]
|
|
/// — the app-wide reference row — rather than against a hard-coded size, so the
|
|
/// assertions still hold if the app's row density is ever retuned.
|
|
void main() {
|
|
for (final platform in [TargetPlatform.android, TargetPlatform.macOS]) {
|
|
testWidgets('settings rows match the standard app row on $platform', (tester) async {
|
|
await tester.pumpWidget(_harness(platform));
|
|
|
|
final referenceTitle = _titleFontSize(tester, 'Clear Cache');
|
|
final referenceSubtitle = _subtitleFontSize(tester, 'Clear cached data');
|
|
final referenceHeight = tester.getSize(find.byKey(const ValueKey('reference'))).height;
|
|
|
|
// The dense ListTile title/subtitle sizes; spelled out so a silent
|
|
// theme-wide inflation can't make every side of the comparison agree.
|
|
expect(referenceTitle, 13);
|
|
expect(referenceSubtitle, 12);
|
|
|
|
for (final title in ['View Logs', 'Enable Thing', 'View Mode', 'Account']) {
|
|
expect(_titleFontSize(tester, title), referenceTitle, reason: '$title title size');
|
|
}
|
|
for (final subtitle in ['View application logs', 'Toggles the thing', 'signed in']) {
|
|
expect(_subtitleFontSize(tester, subtitle), referenceSubtitle, reason: '$subtitle subtitle size');
|
|
}
|
|
for (final key in ['navigation', 'switch', 'plain']) {
|
|
expect(tester.getSize(find.byKey(ValueKey(key))).height, referenceHeight, reason: '$key row height');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
double? _titleFontSize(WidgetTester tester, String text) {
|
|
final finder = find.text(text);
|
|
final inherited = DefaultTextStyle.of(tester.element(finder)).style;
|
|
return inherited.merge(tester.widget<Text>(finder).style).fontSize;
|
|
}
|
|
|
|
double? _subtitleFontSize(WidgetTester tester, String text) =>
|
|
DefaultTextStyle.of(tester.element(find.text(text))).style.fontSize;
|
|
|
|
Widget _harness(TargetPlatform platform) {
|
|
return MaterialApp(
|
|
theme: monoTheme(dark: false).copyWith(platform: platform),
|
|
home: Scaffold(
|
|
body: SettingsGroup(
|
|
children: [
|
|
SettingNavigationTile(
|
|
key: const ValueKey('navigation'),
|
|
icon: Icons.article,
|
|
title: 'View Logs',
|
|
subtitle: 'View application logs',
|
|
onTap: () {},
|
|
),
|
|
FocusableListTile(
|
|
key: const ValueKey('reference'),
|
|
leading: const Icon(Icons.cleaning_services),
|
|
title: const Text('Clear Cache'),
|
|
subtitle: const Text('Clear cached data'),
|
|
trailing: const Icon(Icons.chevron_right),
|
|
onTap: () {},
|
|
),
|
|
FocusableSwitchListTile(
|
|
key: const ValueKey('switch'),
|
|
secondary: const Icon(Icons.toggle_on),
|
|
title: const Text('Enable Thing'),
|
|
subtitle: const Text('Toggles the thing'),
|
|
value: true,
|
|
onChanged: (_) {},
|
|
),
|
|
SegmentedSetting<String>(
|
|
icon: Icons.view_list,
|
|
title: 'View Mode',
|
|
segments: const [
|
|
ButtonSegment(value: 'grid', label: Text('Grid')),
|
|
ButtonSegment(value: 'list', label: Text('List')),
|
|
],
|
|
selected: 'grid',
|
|
onChanged: (_) {},
|
|
),
|
|
// Non-interactive info rows are plain ListTiles; the group hands them
|
|
// the same geometry as their interactive siblings.
|
|
const ListTile(key: ValueKey('plain'), title: Text('Account'), subtitle: Text('signed in')),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|