frosty/lib/screens/settings/widgets/settings_list_slider.dart
Tommy Chow 02f4cd417b audit and optimize haptic feedback across the app
Add selectionClick to settings switches, discrete slider steps, bottom
nav tabs, and expandable section headers. Fix intensity levels for cache
clear and random color (medium → light). Add lightImpact to thumbnail
long-press. Fix inconsistent search result long-press level. Replace
blanket lightImpact in updateNotification with targeted haptics at
error/warning call sites to eliminate double-firing and match severity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 17:46:24 -08:00

84 lines
2.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
/// A custom-styled adaptive [Slider].
class SettingsListSlider extends StatefulWidget {
final String title;
final String trailing;
final String? subtitle;
final double value;
final ValueChanged<double>? onChanged;
final double min;
final double max;
final int? divisions;
const SettingsListSlider({
super.key,
required this.title,
required this.trailing,
this.subtitle,
required this.value,
this.onChanged,
this.min = 0.0,
this.max = 1.0,
this.divisions,
});
@override
State<SettingsListSlider> createState() => _SettingsListSliderState();
}
class _SettingsListSliderState extends State<SettingsListSlider> {
int? _previousStep;
void _handleChanged(double newValue) {
if (widget.divisions != null) {
final step =
((newValue - widget.min) /
(widget.max - widget.min) *
widget.divisions!)
.round();
if (_previousStep != null && step != _previousStep) {
HapticFeedback.selectionClick();
}
_previousStep = step;
}
widget.onChanged?.call(newValue);
}
@override
Widget build(BuildContext context) {
return ListTile(
title: Row(
children: [
Text(widget.title),
const Spacer(),
Text(
widget.trailing,
style: const TextStyle(
fontFeatures: [FontFeature.tabularFigures()],
),
),
],
),
subtitle: Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Slider.adaptive(
value: widget.value,
min: widget.min,
max: widget.max,
divisions: widget.divisions,
onChanged:
widget.onChanged != null ? _handleChanged : null,
),
if (widget.subtitle != null) Text(widget.subtitle!),
],
),
),
);
}
}