This commit is contained in:
Forrest 2026-08-04 16:08:51 -04:00
parent d558aba246
commit 3bd713d667
17 changed files with 1566 additions and 132 deletions

View file

@ -73,6 +73,18 @@ class SettingsScreen extends ConsumerWidget {
labelFor: AppSettings.formatLabel,
onSelect: controller.setDownloadFormat,
),
const SizedBox(height: TimbreSpacing.lg),
const _Caption(
'How many tracks download at once. Higher is faster on '
'a strong connection; lower is gentler on the server.'),
const SizedBox(height: TimbreSpacing.md),
_Stepper(
label: 'Simultaneous downloads',
value: settings.maxConcurrentDownloads,
min: AppSettings.minConcurrentDownloads,
max: AppSettings.maxConcurrentDownloadsCap,
onChanged: controller.setMaxConcurrentDownloads,
),
],
),
),
@ -380,6 +392,101 @@ class _Chip extends StatelessWidget {
}
}
/// A labelled −/value/+ stepper bounded to [[min], [max]], styled to match the
/// bordered-chip language of [_ChoiceChips].
class _Stepper extends StatelessWidget {
const _Stepper({
required this.label,
required this.value,
required this.min,
required this.max,
required this.onChanged,
});
final String label;
final int value;
final int min;
final int max;
final ValueChanged<int> onChanged;
@override
Widget build(BuildContext context) {
final accent = Theme.of(context).colorScheme.primary;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: const TextStyle(color: TimbreColors.foreground)),
const SizedBox(height: TimbreSpacing.sm),
Row(
children: [
_StepButton(
icon: Icons.remove,
accent: accent,
enabled: value > min,
onTap: () => onChanged(value - 1),
),
Container(
constraints: const BoxConstraints(
minWidth: TimbreSpacing.minTouchTarget,
minHeight: TimbreSpacing.minTouchTarget),
alignment: Alignment.center,
child: Text(
'$value',
style: const TextStyle(
color: TimbreColors.foreground,
fontWeight: FontWeight.w700,
),
),
),
_StepButton(
icon: Icons.add,
accent: accent,
enabled: value < max,
onTap: () => onChanged(value + 1),
),
],
),
],
);
}
}
class _StepButton extends StatelessWidget {
const _StepButton({
required this.icon,
required this.accent,
required this.enabled,
required this.onTap,
});
final IconData icon;
final Color accent;
final bool enabled;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: enabled ? onTap : null,
child: Container(
constraints: const BoxConstraints(
minWidth: TimbreSpacing.minTouchTarget,
minHeight: TimbreSpacing.minTouchTarget),
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border.all(color: TimbreColors.border),
color: TimbreColors.surface,
),
child: Icon(
icon,
size: 18,
color: enabled ? accent : TimbreColors.dimmed,
),
),
);
}
}
/// A row of accent-color chips — like [_ChoiceChips] but each chip shows a
/// color swatch and the color's own hue drives the active border/fill.
class _ColorChips extends StatelessWidget {