fix(settings): restore the shared compact row size
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.
This commit is contained in:
@@ -45,12 +45,10 @@ class _SettingRow extends StatelessWidget {
|
||||
return FocusableListTile(
|
||||
focusNode: focusNode,
|
||||
leading: AppIcon(icon, fill: 1),
|
||||
title: Text(title, style: settingsOptionTitleStyle(context)),
|
||||
title: Text(title),
|
||||
subtitle: subtitle,
|
||||
trailing: trailing ?? const AppIcon(Symbols.chevron_right_rounded, fill: 1),
|
||||
onTap: onTap,
|
||||
dense: settingsRowDense(context),
|
||||
visualDensity: settingsRowVisualDensity(context),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -83,11 +81,9 @@ class SettingSwitchTile extends StatelessWidget {
|
||||
builder: (_, value, _) => FocusableSwitchListTile(
|
||||
focusNode: focusNode,
|
||||
secondary: AppIcon(icon, fill: 1),
|
||||
title: Text(title, style: settingsOptionTitleStyle(context)),
|
||||
title: Text(title),
|
||||
subtitle: subtitle != null ? Text(subtitle!) : null,
|
||||
value: value,
|
||||
dense: settingsRowDense(context),
|
||||
visualDensity: settingsRowVisualDensity(context),
|
||||
onChanged: enabled ? (v) => _writeAndNotify(pref, v, onAfterWrite) : null,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../theme/mono_tokens.dart';
|
||||
import '../utils/platform_detector.dart';
|
||||
import 'app_icon.dart';
|
||||
import 'expressive_button_group.dart';
|
||||
|
||||
/// Standard settings-option title style.
|
||||
/// Standard settings-option title style, for group children that are not a
|
||||
/// [ListTile] (segmented controls, sliders) and so don't inherit its
|
||||
/// typography.
|
||||
///
|
||||
/// Mobile uses Flutter's compact ListTile title size. Desktop and TV retain
|
||||
/// the larger body style used for pointer and D-pad readability.
|
||||
TextStyle? settingsOptionTitleStyle(BuildContext context) {
|
||||
final style = Theme.of(context).textTheme.bodyLarge;
|
||||
return PlatformDetector.isMobile(context) ? style?.copyWith(fontSize: 13) : style;
|
||||
}
|
||||
|
||||
/// Standard settings-row density, paired with [settingsOptionTitleStyle]:
|
||||
/// compact on mobile and full-height on desktop and TV.
|
||||
bool settingsRowDense(BuildContext context) => PlatformDetector.isMobile(context);
|
||||
|
||||
VisualDensity settingsRowVisualDensity(BuildContext context) =>
|
||||
settingsRowDense(context) ? const VisualDensity(vertical: -3) : VisualDensity.standard;
|
||||
/// The app renders every row compactly — [ThemeData.listTileTheme] sets
|
||||
/// `dense: true` and the `Focusable*ListTile`s default to it — and Flutter
|
||||
/// draws a dense [ListTile] title at 13. Match that so a settings page reads
|
||||
/// as one family instead of one size per row type.
|
||||
TextStyle? settingsOptionTitleStyle(BuildContext context) =>
|
||||
Theme.of(context).textTheme.bodyLarge?.copyWith(fontSize: 13);
|
||||
|
||||
class SettingsSectionHeader extends StatelessWidget {
|
||||
final String title;
|
||||
@@ -50,6 +44,10 @@ class SettingsSectionHeader extends StatelessWidget {
|
||||
/// highlight paints clipped inside the card — that is the d-pad focus visual
|
||||
/// (background focus). The group adds no [Focus] nodes of its own; traversal
|
||||
/// order and externally-owned tile focus nodes are untouched.
|
||||
///
|
||||
/// Children inherit the compact row geometry the `Focusable*ListTile`s default
|
||||
/// to, so a plain [ListTile] used as a non-interactive info row lines up with
|
||||
/// its interactive siblings instead of standing 11px taller.
|
||||
class SettingsGroup extends StatelessWidget {
|
||||
final String? title;
|
||||
final List<Widget> children;
|
||||
@@ -71,18 +69,21 @@ class SettingsGroup extends StatelessWidget {
|
||||
if (title != null) SettingsSectionHeader(title!),
|
||||
Padding(
|
||||
padding: margin,
|
||||
child: Column(
|
||||
children: [
|
||||
for (var i = 0; i < children.length; i++) ...[
|
||||
if (i > 0) SizedBox(height: t.groupGap),
|
||||
Material(
|
||||
color: t.surface,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
shape: RoundedRectangleBorder(borderRadius: groupItemRadii(context, i, children.length)),
|
||||
child: children[i],
|
||||
),
|
||||
child: ListTileTheme.merge(
|
||||
visualDensity: const VisualDensity(vertical: -3),
|
||||
child: Column(
|
||||
children: [
|
||||
for (var i = 0; i < children.length; i++) ...[
|
||||
if (i > 0) SizedBox(height: t.groupGap),
|
||||
Material(
|
||||
color: t.surface,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
shape: RoundedRectangleBorder(borderRadius: groupItemRadii(context, i, children.length)),
|
||||
child: children[i],
|
||||
),
|
||||
],
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user