import 'package:flutter/material.dart'; class DurationPicker extends StatefulWidget { const DurationPicker({super.key, required this.onChangedCallback}); final void Function(Duration duration) onChangedCallback; @override State createState() => _DurationPickerState(); } class _DurationPickerState extends State { String _timeString = ''; @override Widget build(BuildContext context) { return SizedBox( width: 400, child: Column( mainAxisSize: MainAxisSize.min, children: [ Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( _timeString.padLeft(4, '0').substring(0, 2), style: Theme.of(context).textTheme.displayMedium, ), Padding(padding: EdgeInsets.only(left: 5)), Text( 'h', style: Theme.of(context).textTheme.bodyLarge!.copyWith(height: 2), ), Padding(padding: EdgeInsets.only(left: 10)), Text( _timeString.padLeft(4, '0').substring(2, 4), style: Theme.of(context).textTheme.displayMedium, ), Padding(padding: EdgeInsets.only(left: 5)), Text( 'm', style: Theme.of(context).textTheme.bodyLarge!.copyWith(height: 2), ), ], ), Padding(padding: EdgeInsets.only(top: 10)), Expanded( child: GridView.count( crossAxisSpacing: 10, mainAxisSpacing: 10, crossAxisCount: 3, physics: NeverScrollableScrollPhysics(), children: [ ElevatedButton( style: _buttonTheme, onPressed: () => _addTime(7), child: _getTextWidget('7'), ), ElevatedButton( style: _buttonTheme, onPressed: () => _addTime(8), child: _getTextWidget('8'), ), ElevatedButton( style: _buttonTheme, onPressed: () => _addTime(9), child: _getTextWidget('9'), ), ElevatedButton( style: _buttonTheme, onPressed: () => _addTime(4), child: _getTextWidget('4'), ), ElevatedButton( style: _buttonTheme, onPressed: () => _addTime(5), child: _getTextWidget('5'), ), ElevatedButton( style: _buttonTheme, onPressed: () => _addTime(6), child: _getTextWidget('6'), ), ElevatedButton( style: _buttonTheme, onPressed: () => _addTime(1), child: _getTextWidget('1'), ), ElevatedButton( style: _buttonTheme, onPressed: () => _addTime(2), child: _getTextWidget('2'), ), ElevatedButton( style: _buttonTheme, onPressed: () => _addTime(3), child: _getTextWidget('3'), ), Padding(padding: EdgeInsets.all(0)), ElevatedButton( style: _buttonTheme, onPressed: () => _addTime(0), child: _getTextWidget('0'), ), ElevatedButton( style: _buttonTheme, onPressed: _removeTime, child: Icon( Icons.backspace, size: 24, ), ), ], ), ), ], ), ); } Text _getTextWidget(String text) { return Text(text); } void _addTime(int time) { if (_timeString.length >= 4) return; setState(() { _timeString += time.toString(); }); widget.onChangedCallback(_duration); } void _removeTime() { if (_timeString.isEmpty) return; setState(() { _timeString = _timeString.substring(0, _timeString.length - 1); }); widget.onChangedCallback(_duration); } Duration get _duration { return Duration( hours: int.parse(_timeString.padLeft(4, '0').substring(0, 2)), minutes: int.parse(_timeString.padLeft(4, '0').substring(2, 4)), ); } ButtonStyle get _buttonTheme => ElevatedButton.styleFrom( textStyle: Theme.of(context).textTheme.displaySmall, ); }