You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
276 lines
8.6 KiB
276 lines
8.6 KiB
import 'package:flutter/material.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'package:recook/utils/date/date_models.dart';
|
|
import 'package:recook/utils/date/date_utils.dart';
|
|
import 'package:recook/constants/header.dart';
|
|
import 'package:recook/utils/date/recook_date_util.dart';
|
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
|
|
|
class XiataCalendarWidget extends StatefulWidget {
|
|
final DateTime minDate;
|
|
final DateTime maxDate;
|
|
final MonthBuilder monthBuilder;
|
|
final DayBuilder dayBuilder;
|
|
final DateTime initialMinDate;
|
|
//final DateTime initialMaxDate;
|
|
final ValueChanged<DateTime> onDayPressed;
|
|
final PeriodChanged onRangeSelected;
|
|
final EdgeInsetsGeometry listPadding;
|
|
|
|
XiataCalendarWidget(
|
|
{@required this.minDate,
|
|
@required this.maxDate,
|
|
this.monthBuilder,
|
|
this.dayBuilder,
|
|
this.onDayPressed,
|
|
this.onRangeSelected,
|
|
this.initialMinDate,
|
|
//this.initialMaxDate,
|
|
this.listPadding})
|
|
: assert(minDate != null);
|
|
//assert(maxDate != null),
|
|
//assert(minDate.isBefore(maxDate));
|
|
|
|
@override
|
|
_XiataCalendarWidgetState createState() => _XiataCalendarWidgetState();
|
|
}
|
|
|
|
class _XiataCalendarWidgetState extends State<XiataCalendarWidget> {
|
|
DateTime _minDate;
|
|
DateTime _maxDate;
|
|
List<Month> _months;
|
|
DateTime rangeMinDate;
|
|
//DateTime rangeMaxDate;
|
|
ItemScrollController _itemScrollController = ItemScrollController();
|
|
ItemPositionsListener itemPositionsListener = ItemPositionsListener.create();
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_months = DateUtilss.extractWeeks(widget.minDate, widget.maxDate);
|
|
_minDate = widget.minDate.removeTime();
|
|
_maxDate = widget.maxDate.removeTime();
|
|
rangeMinDate = widget.initialMinDate;
|
|
//rangeMaxDate = widget.initialMaxDate;
|
|
DateTime checkInDate = DateTime.now();
|
|
|
|
Future.delayed(Duration(milliseconds: 500), () {
|
|
int index = RecookDateUtil.monthBetween(DateTime.now(), checkInDate);
|
|
_itemScrollController.scrollTo(
|
|
index: index,
|
|
alignment: checkInDate.day > 15 ? -0.3 : 0.3,
|
|
duration: Duration(milliseconds: 300),
|
|
curve: Curves.easeInOutCubic,
|
|
);
|
|
});
|
|
}
|
|
|
|
@override
|
|
void didUpdateWidget(XiataCalendarWidget oldWidget) {
|
|
super.didUpdateWidget(oldWidget);
|
|
|
|
if (oldWidget.minDate != widget.minDate
|
|
// ||oldWidget.maxDate != widget.maxDate
|
|
) {
|
|
_months = DateUtilss.extractWeeks(widget.minDate, widget.maxDate);
|
|
_minDate = widget.minDate.removeTime();
|
|
_maxDate = widget.maxDate.removeTime();
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Column(
|
|
children: <Widget>[
|
|
Expanded(
|
|
child: ScrollablePositionedList.builder(
|
|
physics: AlwaysScrollableScrollPhysics(),
|
|
itemScrollController: _itemScrollController,
|
|
padding: widget.listPadding ?? EdgeInsets.zero,
|
|
itemCount: _months.length,
|
|
itemBuilder: (BuildContext context, int position) {
|
|
return _MonthView(
|
|
month: _months[position],
|
|
minDate: _minDate,
|
|
maxDate: _maxDate,
|
|
monthBuilder: widget.monthBuilder,
|
|
dayBuilder: widget.dayBuilder,
|
|
onDayPressed: widget.onRangeSelected != null
|
|
? (DateTime date) {
|
|
if (rangeMinDate == null) {
|
|
setState(() {
|
|
print(rangeMinDate);
|
|
print('1111');
|
|
rangeMinDate = date;
|
|
//rangeMaxDate = null;
|
|
});
|
|
} else {
|
|
setState(() {
|
|
print(rangeMinDate);
|
|
print('2222');
|
|
//rangeMaxDate = date;
|
|
rangeMinDate = date;
|
|
});
|
|
}
|
|
|
|
//弹窗自动隐藏判断
|
|
widget.onRangeSelected(rangeMinDate);
|
|
|
|
if (widget.onDayPressed != null) {
|
|
widget.onDayPressed(date);
|
|
}
|
|
}
|
|
: widget.onDayPressed,
|
|
rangeMinDate: rangeMinDate,
|
|
//rangeMaxDate: rangeMaxDate
|
|
);
|
|
}),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class _MonthView extends StatelessWidget {
|
|
final Month month;
|
|
final DateTime minDate;
|
|
final DateTime maxDate;
|
|
final MonthBuilder monthBuilder;
|
|
final DayBuilder dayBuilder;
|
|
final ValueChanged<DateTime> onDayPressed;
|
|
final DateTime rangeMinDate;
|
|
//final DateTime rangeMaxDate;
|
|
|
|
_MonthView(
|
|
{@required this.month,
|
|
@required this.minDate,
|
|
@required this.maxDate,
|
|
this.monthBuilder,
|
|
this.dayBuilder,
|
|
this.onDayPressed,
|
|
this.rangeMinDate,
|
|
//this.rangeMaxDate,
|
|
Key key})
|
|
: super(key: key);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Column(
|
|
children: <Widget>[
|
|
monthBuilder != null
|
|
? monthBuilder(context, month.month, month.year)
|
|
: _DefaultMonthView(month: month.month, year: month.year),
|
|
Table(
|
|
children: month.weeks
|
|
.map((Week week) => _generateFor(context, week))
|
|
.toList(growable: false),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
TableRow _generateFor(BuildContext context, Week week) {
|
|
DateTime firstDay = week.firstDay;
|
|
bool rangeFeatureEnabled = rangeMinDate != null;
|
|
|
|
return TableRow(
|
|
children: List<Widget>.generate(DateTime.daysPerWeek, (int position) {
|
|
DateTime day = DateTime(week.firstDay.year, week.firstDay.month,
|
|
firstDay.day + (position - (firstDay.weekday - 1)));
|
|
|
|
if ((position + 1) < week.firstDay.weekday ||
|
|
(position + 1) > week.lastDay.weekday ||
|
|
day.isBefore(minDate) ||
|
|
day.isAfter(maxDate)) {
|
|
return const SizedBox();
|
|
} else {
|
|
bool isSelected = false;
|
|
print(day);
|
|
print(rangeMinDate);
|
|
|
|
if (rangeFeatureEnabled) {
|
|
if (rangeMinDate != null) {
|
|
isSelected = day.isSameDay(rangeMinDate);
|
|
} else {
|
|
isSelected = day.isAtSameMomentAs(rangeMinDate);
|
|
}
|
|
}
|
|
|
|
return Padding(
|
|
padding: EdgeInsets.symmetric(
|
|
vertical: 4.rw,
|
|
),
|
|
child: AspectRatio(
|
|
aspectRatio: 46 / 64,
|
|
child: GestureDetector(
|
|
behavior: HitTestBehavior.translucent,
|
|
onTap: onDayPressed != null
|
|
? () {
|
|
if (onDayPressed != null) {
|
|
DateTime nowDay = DateTime.now();
|
|
DateTime todayStart = DateTime(
|
|
nowDay.year,
|
|
nowDay.month,
|
|
nowDay.day,
|
|
0,
|
|
);
|
|
if (day.millisecondsSinceEpoch >=
|
|
todayStart.millisecondsSinceEpoch)
|
|
onDayPressed(day);
|
|
}
|
|
}
|
|
: null,
|
|
child: dayBuilder != null
|
|
? dayBuilder(context, day, isSelected: isSelected)
|
|
: _DefaultDayView(date: day, isSelected: isSelected),
|
|
)),
|
|
);
|
|
}
|
|
}, growable: false));
|
|
}
|
|
}
|
|
|
|
class _DefaultMonthView extends StatelessWidget {
|
|
final int month;
|
|
final int year;
|
|
|
|
_DefaultMonthView({@required this.month, @required this.year});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Text(
|
|
DateFormat('MMMM yyyy').format(DateTime(year, month)),
|
|
style: Theme.of(context).textTheme.headline5,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _DefaultDayView extends StatelessWidget {
|
|
final DateTime date;
|
|
final bool isSelected;
|
|
|
|
_DefaultDayView({@required this.date, this.isSelected});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Ink(
|
|
decoration: BoxDecoration(
|
|
color: isSelected == true ? Colors.red : Colors.green,
|
|
shape: BoxShape.circle),
|
|
child: Center(
|
|
child: Text(
|
|
DateFormat('d').format(date),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
typedef MonthBuilder = Widget Function(
|
|
BuildContext context, int month, int year);
|
|
typedef DayBuilder = Widget Function(BuildContext context, DateTime date,
|
|
{bool isSelected});
|
|
typedef PeriodChanged = void Function(DateTime minDate);
|