import 'package:fitnote/widget/record/common.dart'; import 'package:flutter/material.dart'; class NumberInput extends StatefulWidget { final num? value; final ValueChanged? onChanged; final double min; final double max; final double step; final int precision; final String unit; const NumberInput({ Key? key, this.value, this.onChanged, this.min = double.negativeInfinity, this.max = double.infinity, this.step = 1, this.precision = 2, this.unit = '' }) : super(key: key); @override State createState() => _NumberInputState(); } class _NumberInputState extends State { late TextEditingController _controller; late num _currentValue; final Color disabledColor = Colors.grey.shade400; final double width = 150; final double height = 36; @override void initState() { super.initState(); _currentValue = widget.value ?? 0.0; _controller = TextEditingController(text: _formatValue(_currentValue)); } @override void didUpdateWidget(NumberInput oldWidget) { super.didUpdateWidget(oldWidget); if (widget.value != oldWidget.value && widget.value != _currentValue) { _currentValue = widget.value ?? 0.0; _controller.text = _formatValue(_currentValue); } } String _formatValue(num value) { if (widget.precision == 0) return value.toInt().toString(); return value.toStringAsFixed(widget.precision); } void _handleValueChange(num newValue) { num clampedValue = newValue.clamp(widget.min, widget.max); if (widget.precision > 0) { clampedValue = double.parse( clampedValue.toStringAsFixed(widget.precision), ); } setState(() { _currentValue = clampedValue; _controller.text = _formatValue(clampedValue); }); widget.onChanged?.call(clampedValue); } Widget _buildControlButton({ required IconData icon, required VoidCallback? onPressed, required bool disabled, }) { final colors = Theme.of(context).colorScheme; return Container( width: height, height: height, child: Material( color: disabled ? disabledColor : colors.primary.withAlpha(100), child: InkWell( onTap: disabled ? null : onPressed, borderRadius: BorderRadius.circular(4), child: Icon(icon, size: 18, color: colors.onSurface), ), ), ); } @override Widget build(BuildContext context) { return Container( width: width, decoration: buildBoxDecoration(context), child: IntrinsicWidth( child: Row( mainAxisSize: MainAxisSize.min, children: [ _buildControlButton( icon: Icons.remove, onPressed: () => _handleValueChange(_currentValue - widget.step), disabled: _currentValue <= widget.min, ), Expanded( child: Text( '${_currentValue} ${widget.unit}', textAlign: TextAlign.center, ), ), _buildControlButton( icon: Icons.add, onPressed: () => _handleValueChange(_currentValue + widget.step), disabled: _currentValue >= widget.max, ), ], ), ), ); } @override void dispose() { _controller.dispose(); super.dispose(); } }