You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
5.5 KiB
Dart
182 lines
5.5 KiB
Dart
|
11 hours ago
|
import 'package:flutter/material.dart';
|
||
|
|
import 'package:hmg_patient_app_new/core/app_export.dart';
|
||
|
|
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||
|
|
|
||
|
|
|
||
|
|
class ScrollWheelTimePicker extends StatefulWidget {
|
||
|
|
final int initialHour;
|
||
|
|
|
||
|
|
final int initialMinute;
|
||
|
|
|
||
|
|
final bool use24HourFormat;
|
||
|
|
|
||
|
|
final ValueChanged<TimeOfDay>? onTimeChanged;
|
||
|
|
|
||
|
|
final double itemExtent;
|
||
|
|
|
||
|
|
final double pickerHeight;
|
||
|
|
|
||
|
|
final TextStyle? digitTextStyle;
|
||
|
|
|
||
|
|
final TextStyle? separatorTextStyle;
|
||
|
|
|
||
|
|
const ScrollWheelTimePicker({
|
||
|
|
super.key,
|
||
|
|
this.initialHour = 8,
|
||
|
|
this.initialMinute = 15,
|
||
|
|
this.use24HourFormat = true,
|
||
|
|
this.onTimeChanged,
|
||
|
|
this.itemExtent = 60,
|
||
|
|
this.pickerHeight = 180,
|
||
|
|
this.digitTextStyle,
|
||
|
|
this.separatorTextStyle,
|
||
|
|
});
|
||
|
|
|
||
|
|
@override
|
||
|
|
State<ScrollWheelTimePicker> createState() => _ScrollWheelTimePickerState();
|
||
|
|
}
|
||
|
|
|
||
|
|
class _ScrollWheelTimePickerState extends State<ScrollWheelTimePicker> {
|
||
|
|
late FixedExtentScrollController _hourController;
|
||
|
|
late FixedExtentScrollController _minuteController;
|
||
|
|
late int _selectedHour;
|
||
|
|
late int _selectedMinute;
|
||
|
|
|
||
|
|
int get _maxHour => widget.use24HourFormat ? 24 : 12;
|
||
|
|
|
||
|
|
@override
|
||
|
|
void initState() {
|
||
|
|
super.initState();
|
||
|
|
_selectedHour = widget.initialHour;
|
||
|
|
_selectedMinute = widget.initialMinute;
|
||
|
|
|
||
|
|
final hourIndex =
|
||
|
|
widget.use24HourFormat ? _selectedHour : (_selectedHour == 0 ? 11 : _selectedHour - 1);
|
||
|
|
|
||
|
|
_hourController = FixedExtentScrollController(initialItem: hourIndex);
|
||
|
|
_minuteController = FixedExtentScrollController(initialItem: _selectedMinute);
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
void dispose() {
|
||
|
|
_hourController.dispose();
|
||
|
|
_minuteController.dispose();
|
||
|
|
super.dispose();
|
||
|
|
}
|
||
|
|
|
||
|
|
void _notifyChange() {
|
||
|
|
widget.onTimeChanged?.call(TimeOfDay(hour: _selectedHour, minute: _selectedMinute));
|
||
|
|
}
|
||
|
|
|
||
|
|
TextStyle get _defaultDigitStyle => TextStyle(
|
||
|
|
fontSize: 72.f,
|
||
|
|
fontWeight: FontWeight.w800,
|
||
|
|
color: AppColors.textColor,
|
||
|
|
letterSpacing: 0,
|
||
|
|
);
|
||
|
|
|
||
|
|
TextStyle get _defaultSeparatorStyle => TextStyle(
|
||
|
|
fontSize: 40.f,
|
||
|
|
fontWeight: FontWeight.w800,
|
||
|
|
color: AppColors.textColor,
|
||
|
|
letterSpacing: 0,
|
||
|
|
);
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) {
|
||
|
|
final digitStyle = widget.digitTextStyle ?? _defaultDigitStyle;
|
||
|
|
final separatorStyle = widget.separatorTextStyle ?? _defaultSeparatorStyle;
|
||
|
|
|
||
|
|
return SizedBox(
|
||
|
|
height: widget.pickerHeight,
|
||
|
|
child: Row(
|
||
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
||
|
|
mainAxisSize: MainAxisSize.min,
|
||
|
|
children: [
|
||
|
|
SizedBox(
|
||
|
|
width: 150.w,
|
||
|
|
child: ListWheelScrollView.useDelegate(
|
||
|
|
controller: _hourController,
|
||
|
|
itemExtent: widget.itemExtent,
|
||
|
|
physics: const FixedExtentScrollPhysics(),
|
||
|
|
perspective: 0.005,
|
||
|
|
diameterRatio: 1.2,
|
||
|
|
onSelectedItemChanged: (index) {
|
||
|
|
setState(() {
|
||
|
|
_selectedHour =
|
||
|
|
widget.use24HourFormat ? index : index + 1;
|
||
|
|
});
|
||
|
|
_notifyChange();
|
||
|
|
},
|
||
|
|
childDelegate: ListWheelChildBuilderDelegate(
|
||
|
|
childCount: _maxHour,
|
||
|
|
builder: (context, index) {
|
||
|
|
final hour =
|
||
|
|
widget.use24HourFormat ? index : index + 1;
|
||
|
|
final isSelected = hour == _selectedHour;
|
||
|
|
return Visibility(
|
||
|
|
visible: isSelected,
|
||
|
|
child: Center(
|
||
|
|
child: AnimatedDefaultTextStyle(
|
||
|
|
duration: const Duration(milliseconds: 200),
|
||
|
|
style: digitStyle.copyWith(
|
||
|
|
color: isSelected
|
||
|
|
? AppColors.textColor
|
||
|
|
: AppColors.textColor.withValues(alpha: 0.3),
|
||
|
|
),
|
||
|
|
child: Text(hour.toString().padLeft(2, '0')),
|
||
|
|
),
|
||
|
|
));
|
||
|
|
},
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
|
||
|
|
Padding(
|
||
|
|
padding: EdgeInsets.symmetric(horizontal: 2.w),
|
||
|
|
child: Text(':', style: separatorStyle),
|
||
|
|
),
|
||
|
|
|
||
|
|
SizedBox(
|
||
|
|
width: 150.w,
|
||
|
|
child: ListWheelScrollView.useDelegate(
|
||
|
|
controller: _minuteController,
|
||
|
|
itemExtent: widget.itemExtent,
|
||
|
|
physics: const FixedExtentScrollPhysics(),
|
||
|
|
perspective: 0.005,
|
||
|
|
diameterRatio: 1.2,
|
||
|
|
onSelectedItemChanged: (index) {
|
||
|
|
setState(() {
|
||
|
|
_selectedMinute = index;
|
||
|
|
});
|
||
|
|
_notifyChange();
|
||
|
|
},
|
||
|
|
childDelegate: ListWheelChildBuilderDelegate(
|
||
|
|
childCount: 60,
|
||
|
|
|
||
|
|
builder: (context, index) {
|
||
|
|
final isSelected = index == _selectedMinute;
|
||
|
|
return Visibility(
|
||
|
|
visible: isSelected,
|
||
|
|
child:
|
||
|
|
Center(
|
||
|
|
child: AnimatedDefaultTextStyle(
|
||
|
|
duration: const Duration(milliseconds: 200),
|
||
|
|
style: digitStyle.copyWith(
|
||
|
|
color: isSelected
|
||
|
|
? AppColors.textColor
|
||
|
|
: AppColors.transparent.withValues(alpha: 0.3),
|
||
|
|
),
|
||
|
|
child: Text(index.toString().padLeft(2, '0')),
|
||
|
|
),
|
||
|
|
));
|
||
|
|
},
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|