import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; import 'package:lba/res/colors.dart'; import 'package:lba/widgets/button.dart'; import 'dart:math' as math; class TimeSelectionBottomSheet extends StatefulWidget { const TimeSelectionBottomSheet({super.key}); @override State createState() => _TimeSelectionBottomSheetState(); } class _TimeSelectionBottomSheetState extends State { final List _timeSlots = []; String? _selectedTimeSlot; late ScrollController _scrollController; static const double _itemHeight = 50.0; static const int _visibleItems = 3; @override void initState() { super.initState(); _generateTimeSlots(); final initialIndex = _timeSlots.length > 1 ? 1 : 0; if (_timeSlots.isNotEmpty) { _selectedTimeSlot = _timeSlots[initialIndex]; } _scrollController = ScrollController(initialScrollOffset: initialIndex * _itemHeight); _scrollController.addListener(_onScroll); } void _onScroll() { setState(() {}); } @override void dispose() { _scrollController.removeListener(_onScroll); _scrollController.dispose(); super.dispose(); } void _generateTimeSlots() { final now = DateTime.now(); final endTime = DateTime(now.year, now.month, now.day, 22, 0); DateTime startTime = DateTime( now.year, now.month, now.day, now.hour, now.minute > 30 ? 60 : 30, ); if (startTime.isAfter(endTime)) return; _timeSlots.add(''); while (startTime.isBefore(endTime)) { final slotEnd = startTime.add(const Duration(minutes: 30)); final formattedStart = DateFormat('HH:mm').format(startTime); final formattedEnd = DateFormat('HH:mm').format(slotEnd); _timeSlots.add('$formattedStart - $formattedEnd'); startTime = slotEnd; } _timeSlots.add(''); } void _onScrollEnd() { final currentOffset = _scrollController.offset; final targetIndex = (currentOffset / _itemHeight).round(); final targetOffset = targetIndex * _itemHeight; if ((targetOffset - currentOffset).abs() > 0.1) { _scrollController.animateTo( targetOffset, duration: const Duration(milliseconds: 300), curve: Curves.easeOut, ); } if (mounted && _timeSlots.isNotEmpty) { final finalIndex = targetIndex.clamp(0, _timeSlots.length - 1); final newSelection = _timeSlots[finalIndex]; if (_selectedTimeSlot != newSelection && newSelection.isNotEmpty) { setState(() { _selectedTimeSlot = newSelection; }); HapticFeedback.lightImpact(); } } } @override Widget build(BuildContext context) { return Container( decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.vertical(top: Radius.circular(20.0)), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( width: 40, height: 4, margin: const EdgeInsets.symmetric(vertical: 10), decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(10), ), ), Padding( padding: const EdgeInsets.symmetric(horizontal: 24.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('Select a time', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 8), Divider(color: Colors.grey.shade300), const SizedBox(height: 8), Text( 'Philadelphia Honey Pecan Cream Cheese Spread, 7.5 oz Tub available from Now - 10:00 PM Today', style: TextStyle(color: Colors.grey.shade600, fontSize: 14), ), const SizedBox(height: 16), _buildTimePicker(), const SizedBox(height: 24), SizedBox( width: double.infinity, height: 50, child: Button( text: 'Confirm', onPressed: () { if (_selectedTimeSlot != null && _selectedTimeSlot!.isNotEmpty) { Navigator.pop(context, _selectedTimeSlot); } }, color: LightAppColors.offerTimer, ), ), const SizedBox(height: 20), ], ), ), ], ), ); } Widget _buildTimePicker() { if (_timeSlots.length <= 2) { return const Center( child: Padding( padding: EdgeInsets.all(20.0), child: Text('No available time slots for today.'), ), ); } final listHeight = _itemHeight * _visibleItems; return SizedBox( height: listHeight, child: Stack( alignment: Alignment.center, children: [ Positioned( top: _itemHeight, bottom: _itemHeight, left: 0, right: 0, child: Container( decoration: BoxDecoration( color: LightAppColors.fillOrder, borderRadius: BorderRadius.circular(8), ), ), ), NotificationListener( onNotification: (notification) { if (notification is ScrollEndNotification) { _onScrollEnd(); } return true; }, child: ListView.builder( controller: _scrollController, padding: EdgeInsets.symmetric(vertical: (listHeight - _itemHeight) / 2), itemCount: _timeSlots.length, itemExtent: _itemHeight, itemBuilder: (context, index) { final centerOffset = _scrollController.offset; final itemOffset = index * _itemHeight; final distance = (itemOffset - centerOffset).abs(); final isSelected = distance < _itemHeight / 2; final scale = math.max(1.0 - (distance / listHeight) * 0.7, 0.8); final opacity = math.max(1.0 - (distance / listHeight) * 1.2, 0.3); return Center( child: Transform.scale( scale: scale, child: Text( _timeSlots[index], style: TextStyle( fontSize: 18, color: isSelected ? Colors.black : Colors.grey.shade600.withOpacity(opacity), fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, ), ), ), ); }, ), ), ], ), ); } }