marco.pms.mobileapp/lib/helpers/widgets/date_range_picker.dart
Vaibhav Surve 03b82764ed Refactor attendance and document controllers to use reactive date ranges, implement reusable DateRangePickerWidget, and enhance filter functionality in attendance and expense screens.
- Updated AttendanceController to use Rx<DateTime> for date ranges.
- Introduced DateRangePickerWidget for selecting date ranges in attendance and expense filters.
- Refactored attendance filter bottom sheet to utilize the new DateRangePickerWidget.
- Enhanced user document filter bottom sheet with date range selection.
- Improved expense filter bottom sheet to include date range selection and refactored UI components for better readability.
- Cleaned up unused code and improved overall code structure for maintainability.
2025-11-04 14:15:45 +05:30

148 lines
4.4 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
import 'package:marco/helpers/utils/utils.dart';
import 'package:marco/helpers/widgets/my_text.dart';
typedef OnDateRangeSelected = void Function(DateTime? start, DateTime? end);
class DateRangePickerWidget extends StatefulWidget {
final Rx<DateTime?> startDate;
final Rx<DateTime?> endDate;
final OnDateRangeSelected? onDateRangeSelected;
final String? startLabel;
final String? endLabel;
const DateRangePickerWidget({
Key? key,
required this.startDate,
required this.endDate,
this.onDateRangeSelected,
this.startLabel,
this.endLabel,
});
@override
State<DateRangePickerWidget> createState() => _DateRangePickerWidgetState();
}
class _DateRangePickerWidgetState extends State<DateRangePickerWidget>
with UIMixin {
Future<void> _selectDate(BuildContext context, bool isStartDate) async {
final current = isStartDate
? widget.startDate.value ?? DateTime.now()
: widget.endDate.value ?? DateTime.now();
final DateTime? picked = await showDatePicker(
context: context,
initialDate: current,
firstDate: DateTime(2000),
lastDate: DateTime.now(),
builder: (context, child) => Theme(
data: Theme.of(context).copyWith(
colorScheme: ColorScheme.light(
primary: contentTheme.primary,
onPrimary: Colors.white,
onSurface: Colors.black,
),
),
child: child!,
),
);
if (picked != null) {
if (isStartDate) {
widget.startDate.value = picked;
} else {
widget.endDate.value = picked;
}
if (widget.onDateRangeSelected != null) {
widget.onDateRangeSelected!(
widget.startDate.value, widget.endDate.value);
}
}
}
Widget _dateBox({
required BuildContext context,
required String label,
required Rx<DateTime?> date,
required bool isStart,
}) {
return Expanded(
child: Obx(() {
return InkWell(
borderRadius: BorderRadius.circular(8),
onTap: () => _selectDate(context, isStart),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
decoration: BoxDecoration(
color: contentTheme.primary.withOpacity(0.08),
border: Border.all(color: contentTheme.primary.withOpacity(0.3)),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(6),
decoration: BoxDecoration(
color: contentTheme.primary.withOpacity(0.15),
borderRadius: BorderRadius.circular(4),
),
child: Icon(
isStart
? Icons.calendar_today_outlined
: Icons.event_outlined,
size: 14,
color: contentTheme.primary,
),
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MyText(label, fontSize: 10, fontWeight: 500),
const SizedBox(height: 2),
MyText(
date.value != null
? Utils.formatDate(date.value!)
: 'Not selected',
fontWeight: 600,
color: contentTheme.primary,
overflow: TextOverflow.ellipsis,
),
],
),
),
],
),
),
);
}),
);
}
@override
Widget build(BuildContext context) {
return Row(
children: [
_dateBox(
context: context,
label: widget.startLabel ?? 'Start Date',
date: widget.startDate,
isStart: true,
),
const SizedBox(width: 8),
_dateBox(
context: context,
label: widget.endLabel ?? 'End Date',
date: widget.endDate,
isStart: false,
),
],
);
}
}