import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; /// A reusable time picker widget that can be used anywhere in the app /// Shows a bottom sheet with iOS-style time picker class TimePickerWidget { /// Shows a time picker bottom sheet /// /// [context] - BuildContext for showing the bottom sheet /// [initialTime] - Initial time to display (defaults to current time) /// [use24HourFormat] - Whether to use 24-hour format (defaults to false) /// [onTimeSelected] - Callback when time is selected /// /// Returns the selected TimeOfDay or null if cancelled static Future show( BuildContext context, { TimeOfDay? initialTime, bool use24HourFormat = false, bool displaySelectedTime = false, Function(TimeOfDay)? onTimeSelected, }) async { final selectedTime = initialTime ?? TimeOfDay.now(); final result = await showModalBottomSheet( context: context, backgroundColor: Colors.transparent, isScrollControlled: true, builder: (BuildContext context) { return _TimePickerBottomSheet( initialTime: selectedTime, use24HourFormat: use24HourFormat, displaySelectedTime: displaySelectedTime, onTimeChanged: (time) { // Time is being changed in real-time }, ); }, ); if (result != null && onTimeSelected != null) { onTimeSelected(result); } return result; } /// Formats TimeOfDay to string (HH:mm format) static String formatTime(TimeOfDay time, {bool use24HourFormat = false}) { if (use24HourFormat) { return '${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}'; } else { final hour = time.hourOfPeriod == 0 ? 12 : time.hourOfPeriod; final period = time.period == DayPeriod.am ? 'AM' : 'PM'; return '${hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')} $period'; } } /// Parses time string to TimeOfDay static TimeOfDay? parseTime(String timeString) { try { final parts = timeString.split(':'); if (parts.length == 2) { final hour = int.parse(parts[0]); final minute = int.parse(parts[1].split(' ')[0]); return TimeOfDay(hour: hour, minute: minute); } } catch (e) { return null; } return null; } } class _TimePickerBottomSheet extends StatefulWidget { final TimeOfDay initialTime; final bool use24HourFormat; final bool displaySelectedTime; final Function(TimeOfDay) onTimeChanged; const _TimePickerBottomSheet({ required this.initialTime, required this.use24HourFormat, required this.displaySelectedTime, required this.onTimeChanged, }); @override State<_TimePickerBottomSheet> createState() => _TimePickerBottomSheetState(); } class _TimePickerBottomSheetState extends State<_TimePickerBottomSheet> { late int selectedHour; late int selectedMinute; late DayPeriod selectedPeriod; @override void initState() { super.initState(); selectedHour = widget.use24HourFormat ? widget.initialTime.hour : widget.initialTime.hourOfPeriod; if (selectedHour == 0 && !widget.use24HourFormat) selectedHour = 12; selectedMinute = widget.initialTime.minute; selectedPeriod = widget.initialTime.period; } TimeOfDay _getCurrentTime() { if (widget.use24HourFormat) { return TimeOfDay(hour: selectedHour, minute: selectedMinute); } else { int hour = selectedHour; if (selectedPeriod == DayPeriod.pm && hour != 12) { hour += 12; } else if (selectedPeriod == DayPeriod.am && hour == 12) { hour = 0; } return TimeOfDay(hour: hour, minute: selectedMinute); } } @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( color: AppColors.whiteColor, borderRadius: BorderRadius.only( topLeft: Radius.circular(20.r), topRight: Radius.circular(20.r), ), ), child: SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ // Header Container( padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 16.h), decoration: BoxDecoration( border: Border( bottom: BorderSide( color: AppColors.dividerColor, width: 1, ), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ "Select Time".needTranslation.toText18( weight: FontWeight.w600, color: AppColors.textColor, ), GestureDetector( onTap: () => Navigator.pop(context), child: Utils.buildSvgWithAssets( icon: AppAssets.cancel, width: 24.h, height: 24.h, iconColor: AppColors.textColor, ), ), ], ), ), // Time Picker SizedBox( height: 250.h, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ // Hour Picker Expanded( child: CupertinoPicker( scrollController: FixedExtentScrollController( initialItem: widget.use24HourFormat ? selectedHour : (selectedHour - 1), ), itemExtent: 50.h, onSelectedItemChanged: (index) { setState(() { if (widget.use24HourFormat) { selectedHour = index; } else { selectedHour = index + 1; } widget.onTimeChanged(_getCurrentTime()); }); }, children: List.generate( widget.use24HourFormat ? 24 : 12, (index) { final hour = widget.use24HourFormat ? index : index + 1; return Center( child: Text( hour.toString().padLeft(2, '0'), style: TextStyle( fontSize: 24.f, fontWeight: FontWeight.w500, color: AppColors.textColor, ), ), ); }, ), ), ), // Separator Text( ':', style: TextStyle( fontSize: 24.f, fontWeight: FontWeight.w500, color: AppColors.textColor, ), ), // Minute Picker Expanded( child: CupertinoPicker( scrollController: FixedExtentScrollController( initialItem: selectedMinute, ), itemExtent: 50.h, onSelectedItemChanged: (index) { setState(() { selectedMinute = index; widget.onTimeChanged(_getCurrentTime()); }); }, children: List.generate( 60, (index) => Center( child: Text( index.toString().padLeft(2, '0'), style: TextStyle( fontSize: 24.f, fontWeight: FontWeight.w500, color: AppColors.textColor, ), ), ), ), ), ), // AM/PM Picker (only for 12-hour format) if (!widget.use24HourFormat) Expanded( child: CupertinoPicker( scrollController: FixedExtentScrollController( initialItem: selectedPeriod == DayPeriod.am ? 0 : 1, ), itemExtent: 50.h, onSelectedItemChanged: (index) { setState(() { selectedPeriod = index == 0 ? DayPeriod.am : DayPeriod.pm; widget.onTimeChanged(_getCurrentTime()); }); }, children: [ Center( child: Text( 'AM', style: TextStyle( fontSize: 24.f, fontWeight: FontWeight.w500, color: AppColors.textColor, ), ), ), Center( child: Text( 'PM', style: TextStyle( fontSize: 24.f, fontWeight: FontWeight.w500, color: AppColors.textColor, ), ), ), ], ), ), ], ), ), if (widget.displaySelectedTime) // Current Time Display Container( margin: EdgeInsets.symmetric(horizontal: 20.w, vertical: 16.h), padding: EdgeInsets.symmetric(vertical: 12.h), decoration: BoxDecoration( color: AppColors.lightGrayBGColor, borderRadius: BorderRadius.circular(12.r), ), child: Center( child: TimePickerWidget.formatTime( _getCurrentTime(), use24HourFormat: widget.use24HourFormat, ).toText20( weight: FontWeight.w600, color: AppColors.textColor, ), ), ), // Action Buttons Padding( padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 16.h), child: Row( children: [ Expanded( child: CustomButton( height: 56.h, text: "Cancel".needTranslation, onPressed: () => Navigator.pop(context), textColor: AppColors.textColor, backgroundColor: AppColors.greyColor, borderColor: AppColors.greyColor, ), ), SizedBox(width: 12.w), Expanded( child: CustomButton( height: 56.h, text: "Confirm".needTranslation, onPressed: () { Navigator.pop(context, _getCurrentTime()); }, textColor: AppColors.whiteColor, backgroundColor: AppColors.primaryRedColor, ), ), ], ), ), ], ), ), ); } }