160 lines
4.8 KiB
Dart
160 lines
4.8 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();
|
|
|
|
// Ensure initialDate is within firstDate..lastDate
|
|
final first = DateTime(2000);
|
|
final last = current.isAfter(DateTime.now()) ? current : DateTime.now();
|
|
|
|
final DateTime? picked = await showDatePicker(
|
|
context: context,
|
|
initialDate: current,
|
|
firstDate: first,
|
|
lastDate: last,
|
|
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;
|
|
// Auto-adjust endDate if needed
|
|
if (widget.endDate.value != null &&
|
|
widget.endDate.value!.isBefore(picked)) {
|
|
widget.endDate.value = picked;
|
|
}
|
|
} else {
|
|
widget.endDate.value = picked;
|
|
// Auto-adjust startDate if needed
|
|
if (widget.startDate.value != null &&
|
|
widget.startDate.value!.isAfter(picked)) {
|
|
widget.startDate.value = picked;
|
|
}
|
|
}
|
|
|
|
widget.onDateRangeSelected
|
|
?.call(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,
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|