import 'dart:async'; import 'package:flutter/material.dart'; import 'package:liftmanager/internal/maintenance/model/maintenance_count_item.dart'; import 'package:liftmanager/res/resources.dart'; import 'package:liftmanager/utils/utils.dart'; import 'package:liftmanager/widgets/calendar/calendar_title.dart'; import 'package:tuple/tuple.dart'; typedef DayBuilder(BuildContext context, DateTime day); class Calendar extends StatefulWidget { final ValueChanged onDateSelected; final ValueChanged> onSelectedRangeChange; final bool isExpandable; final DayBuilder dayBuilder; final bool showChevronsToChangeRange; final bool showTodayAction; final bool showCalendarPickerIcon; final DateTime initialCalendarDateOverride; Calendar( {this.onDateSelected, this.onSelectedRangeChange, this.isExpandable: false, this.dayBuilder, this.showTodayAction: true, this.showChevronsToChangeRange: true, this.showCalendarPickerIcon: true, this.initialCalendarDateOverride}); final mCalendarState = CalendarState(); today() { mCalendarState.resetToToday(); } DateTime currentSelected(){ return mCalendarState._selectedDate; } // updateState(int i){ // mCalendarState.mtState = i; // } void updateState(List arrCount) { mCalendarState.updateState(arrCount); } @override CalendarState createState() { return mCalendarState; } } class CalendarState extends State { final calendarUtils = new Utils(); List selectedMonthsDays; Iterable selectedWeeksDays; DateTime _selectedDate = new DateTime.now(); DateTime _selectedPageDate = new DateTime.now(); String currentMonth; bool isExpanded = false; String displayMonth; List arrCount = []; DateTime get selectedDate => _selectedDate; void initState() { super.initState(); if (widget.initialCalendarDateOverride != null) { _selectedDate = widget.initialCalendarDateOverride; } _selectedPageDate = _selectedDate; selectedMonthsDays = Utils.daysInMonth(_selectedDate); var firstDayOfCurrentWeek = Utils.firstDayOfWeek(_selectedDate); var lastDayOfCurrentWeek = Utils.lastDayOfWeek(_selectedDate); selectedWeeksDays = Utils.daysInRange(firstDayOfCurrentWeek, lastDayOfCurrentWeek) .toList() .sublist(0, 7); displayMonth = Utils.formatMonth(_selectedDate); } Widget get nameAndIconRow { var leftInnerIcon; var rightInnerIcon; var leftOuterIcon; var rightOuterIcon; if (widget.showCalendarPickerIcon) { rightInnerIcon = new IconButton( onPressed: () => selectDateFromPicker(), icon: new Icon(Icons.calendar_today), ); } else { rightInnerIcon = new Container(); } if (widget.showChevronsToChangeRange) { leftOuterIcon = new IconButton( onPressed: isExpanded ? previousMonth : previousWeek, icon: new Icon(Icons.chevron_left), ); rightOuterIcon = new IconButton( onPressed: isExpanded ? nextMonth : nextWeek, icon: new Icon(Icons.chevron_right), ); } else { leftOuterIcon = new Container(); rightOuterIcon = new Container(); } if (widget.showTodayAction) { leftInnerIcon = new InkWell( child: Container( child: Image.asset("images/icon_today.png"), ), onTap: resetToToday, ); } else { leftInnerIcon = new Container(); } return Container( padding: EdgeInsets.only(left: 15, right: 15), // decoration: BoxDecoration( // color: Colours.app_main, // gradient: const LinearGradient( // colors: [Color(0xFF00D9FF), Color(0xFF0287FF)]), // ), child: Row( // mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ new GestureDetector( onTap: () => selectDateFromPicker(), child: Text( displayMonth, style: new TextStyle(fontSize: 15.0, color: Colours.text), ), ), Expanded(child: Container()), leftOuterIcon ?? new Container(), leftInnerIcon ?? new Container(), rightInnerIcon ?? new Container(), rightOuterIcon ?? new Container(), ], )); } Widget get calendarGridView { return new Container( child: new GestureDetector( onHorizontalDragStart: (gestureDetails) => beginSwipe(gestureDetails), onHorizontalDragUpdate: (gestureDetails) => getDirection(gestureDetails), onHorizontalDragEnd: (gestureDetails) => endSwipe(gestureDetails), onVerticalDragStart: (gestureDetails) => beginVerticalSwipe(gestureDetails), onVerticalDragUpdate: (gestureDetails) => updateVerticalSwipe(gestureDetails), onVerticalDragEnd: (gestureDetails) => endVerticalSwipe(gestureDetails), child: new GridView.count( physics: NeverScrollableScrollPhysics(), //禁止GridView滚动事件,避免冲突 shrinkWrap: true, crossAxisCount: 7, padding: new EdgeInsets.only(bottom: 0.0), children: calendarBuilder(), ), ), ); } List calendarWeek() { List dayWidgets = []; Utils.weekdays.forEach( (day) { dayWidgets.add( new CalendarTile( // weekBgColor: Colors.white, dayOfWeekStyles: TextStyle(color: Colours.text_gray), isDayOfWeek: true, dayOfWeek: day, ), ); }, ); return dayWidgets; } List calendarBuilder() { List dayWidgets = []; List calendarDays = isExpanded ? selectedMonthsDays : selectedWeeksDays; // Utils.weekdays.forEach( // (day) { // dayWidgets.add( // new CalendarTile( //// weekBgColor: MyColors.app_main, // dayOfWeekStyles:TextStyle(color: Colors.white), // isDayOfWeek: true, // dayOfWeek: day, // ), // ); // }, // ); bool monthStarted = false; bool monthEnded = false; calendarDays.forEach( (day) { if (monthStarted && day.day == 01) { monthEnded = true; } if (Utils.isFirstDayOfMonth(day)) { monthStarted = true; } if (this.widget.dayBuilder != null) { dayWidgets.add( new CalendarTile( child: this.widget.dayBuilder(context, day), date: day, onDateSelected: () => handleSelectedDateAndUserCallback(day), ), ); } else { dayWidgets.add( new CalendarTile( onDateSelected: () => handleSelectedDateAndUserCallback(day), date: day, dateStyles: configureDateStyle(monthStarted, monthEnded), isSelected: "${_selectedDate.year},${_selectedDate.month}" == "${_selectedPageDate.year},${_selectedPageDate.month}" ? Utils.isSameDay(selectedDate, day) : false, mtState: isMtState(day), ), ); } }, ); return dayWidgets; } TextStyle configureDateStyle(monthStarted, monthEnded) { TextStyle dateStyles; if (isExpanded) { dateStyles = monthStarted && !monthEnded ? new TextStyle(color:Colours.dark_bg_gray, fontSize: 13) : new TextStyle(color: Colours.bg_gray, fontSize: 13); } else { dateStyles = new TextStyle(color: Colours.dark_bg_gray, fontSize: 13); } return dateStyles; } Widget get expansionButtonRow { if (widget.isExpandable) { return new Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ new Text(Utils.fullDayFormat(selectedDate)), new IconButton( iconSize: 20.0, padding: new EdgeInsets.all(0.0), onPressed: toggleExpanded, icon: isExpanded ? new Icon(Icons.arrow_drop_up) : new Icon(Icons.arrow_drop_down), ), ], ); } else { return new Container(); } } @override Widget build(BuildContext context) { return new Container( child: new Column( mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ nameAndIconRow, Container( // decoration: BoxDecoration(color: Colours.app_main, // gradient: const LinearGradient( // colors: [Color(0xFF00D9FF), Color(0xFF0287FF)]), // ), child: GridView.count( shrinkWrap: true, crossAxisCount: 7, padding: new EdgeInsets.only(bottom: 0.0), children: calendarWeek(), ), ), new ExpansionCrossFade( collapsed: calendarGridView, expanded: calendarGridView, isExpanded: isExpanded, ), // expansionButtonRow ], ), ); } resetToToday() { print("resetToToday"); _selectedDate = new DateTime.now(); _selectedPageDate = _selectedDate; // if(isExpanded){ var firstDateOfNewMonth = Utils.firstDayOfMonth(_selectedDate); var lastDateOfNewMonth = Utils.lastDayOfMonth(_selectedDate); var firstDayOfCurrentWeek = Utils.firstDayOfWeek(_selectedDate); var lastDayOfCurrentWeek = Utils.lastDayOfWeek(_selectedDate); setState(() { selectedWeeksDays = Utils.daysInRange(firstDayOfCurrentWeek, lastDayOfCurrentWeek) .toList(); updateSelectedRange(firstDateOfNewMonth, lastDateOfNewMonth); selectedMonthsDays = Utils.daysInMonth(_selectedPageDate); displayMonth = Utils.formatMonth(_selectedDate); }); // }else{ // var firstDayOfCurrentWeek = Utils.firstDayOfWeek(_selectedDate); // var lastDayOfCurrentWeek = Utils.lastDayOfWeek(_selectedDate); // setState(() { // selectedWeeksDays = // Utils.daysInRange(firstDayOfCurrentWeek, lastDayOfCurrentWeek) // .toList(); // displayMonth = Utils.formatMonth(_selectedDate); // }); // } _launchDateSelectionCallback(_selectedDate); } void nextMonth() { setState(() { // _selectedDate = Utils.nextMonth(_selectedDate); // var firstDateOfNewMonth = Utils.firstDayOfMonth(_selectedDate); // var lastDateOfNewMonth = Utils.lastDayOfMonth(_selectedDate); // updateSelectedRange(firstDateOfNewMonth, lastDateOfNewMonth); // selectedMonthsDays = Utils.daysInMonth(_selectedDate); // displayMonth = Utils.formatMonth(_selectedDate); _selectedPageDate = Utils.nextMonth(_selectedPageDate); var firstDateOfNewMonth = Utils.firstDayOfMonth(_selectedPageDate); var lastDateOfNewMonth = Utils.lastDayOfMonth(_selectedPageDate); updateSelectedRange(firstDateOfNewMonth, lastDateOfNewMonth); selectedMonthsDays = Utils.daysInMonth(_selectedPageDate); displayMonth = Utils.formatMonth(_selectedPageDate); }); } void previousMonth() { setState(() { // _selectedDate = Utils.previousMonth(_selectedDate); // var firstDateOfNewMonth = Utils.firstDayOfMonth(_selectedDate); // var lastDateOfNewMonth = Utils.lastDayOfMonth(_selectedDate); // updateSelectedRange(firstDateOfNewMonth, lastDateOfNewMonth); // selectedMonthsDays = Utils.daysInMonth(_selectedDate); // displayMonth = Utils.formatMonth(_selectedDate); _selectedPageDate = Utils.previousMonth(_selectedPageDate); var firstDateOfNewMonth = Utils.firstDayOfMonth(_selectedPageDate); var lastDateOfNewMonth = Utils.lastDayOfMonth(_selectedPageDate); updateSelectedRange(firstDateOfNewMonth, lastDateOfNewMonth); selectedMonthsDays = Utils.daysInMonth(_selectedPageDate); displayMonth = Utils.formatMonth(_selectedPageDate); }); } void nextWeek() { setState(() { // _selectedDate = Utils.nextWeek(_selectedDate); // var firstDayOfCurrentWeek = Utils.firstDayOfWeek(_selectedDate); // var lastDayOfCurrentWeek = Utils.lastDayOfWeek(_selectedDate); // updateSelectedRange(firstDayOfCurrentWeek, lastDayOfCurrentWeek); // selectedWeeksDays = // Utils.daysInRange(firstDayOfCurrentWeek, lastDayOfCurrentWeek) // .toList() // .sublist(0, 7); // displayMonth = Utils.formatMonth(_selectedDate); _selectedPageDate = Utils.nextWeek(_selectedPageDate); var firstDayOfCurrentWeek = Utils.firstDayOfWeek(_selectedPageDate); var lastDayOfCurrentWeek = Utils.lastDayOfWeek(_selectedPageDate); // var firstDateOfNewMonth = Utils.firstDayOfMonth(_selectedDate); // var lastDateOfNewMonth = Utils.lastDayOfMonth(_selectedDate); // updateSelectedRange(firstDateOfNewMonth, lastDateOfNewMonth); updateSelectedRange(firstDayOfCurrentWeek, lastDayOfCurrentWeek); selectedWeeksDays = Utils.daysInRange(firstDayOfCurrentWeek, lastDayOfCurrentWeek) .toList() .sublist(0, 7); selectedMonthsDays = Utils.daysInMonth(_selectedPageDate); displayMonth = Utils.formatMonth(_selectedPageDate); }); // _launchDateSelectionCallback(_selectedDate); _launchDateSelectionCallback(_selectedPageDate); } void previousWeek() { setState(() { // _selectedDate = Utils.previousWeek(_selectedDate); // var firstDayOfCurrentWeek = Utils.firstDayOfWeek(_selectedDate); // var lastDayOfCurrentWeek = Utils.lastDayOfWeek(_selectedDate); // updateSelectedRange(firstDayOfCurrentWeek, lastDayOfCurrentWeek); // selectedWeeksDays = // Utils.daysInRange(firstDayOfCurrentWeek, lastDayOfCurrentWeek) // .toList() // .sublist(0, 7); // displayMonth = Utils.formatMonth(_selectedDate); _selectedPageDate = Utils.previousWeek(_selectedPageDate); var firstDayOfCurrentWeek = Utils.firstDayOfWeek(_selectedPageDate); var lastDayOfCurrentWeek = Utils.lastDayOfWeek(_selectedPageDate); updateSelectedRange(firstDayOfCurrentWeek, lastDayOfCurrentWeek); selectedWeeksDays = Utils.daysInRange(firstDayOfCurrentWeek, lastDayOfCurrentWeek) .toList() .sublist(0, 7); selectedMonthsDays = Utils.daysInMonth(_selectedPageDate); displayMonth = Utils.formatMonth(_selectedPageDate); }); // _launchDateSelectionCallback(_selectedDate); _launchDateSelectionCallback(_selectedPageDate); } void updateSelectedRange(DateTime start, DateTime end) { var selectedRange = new Tuple2(start, end); if (widget.onSelectedRangeChange != null) { widget.onSelectedRangeChange(selectedRange); } } Future selectDateFromPicker() async { DateTime selected = await showDatePicker( context: context, initialDate: _selectedDate ?? new DateTime.now(), firstDate: new DateTime(1960), lastDate: new DateTime(2050), ); if (selected != null) { _selectedDate = selected; _selectedPageDate = _selectedDate; var firstDateOfNewMonth = Utils.firstDayOfMonth(_selectedDate); var lastDateOfNewMonth = Utils.lastDayOfMonth(_selectedDate); var firstDayOfCurrentWeek = Utils.firstDayOfWeek(_selectedDate); var lastDayOfCurrentWeek = Utils.lastDayOfWeek(_selectedDate); ///todo setState(() { selectedWeeksDays = Utils.daysInRange(firstDayOfCurrentWeek, lastDayOfCurrentWeek) .toList(); updateSelectedRange(firstDateOfNewMonth, lastDateOfNewMonth); selectedMonthsDays = Utils.daysInMonth(_selectedPageDate); displayMonth = Utils.formatMonth(_selectedDate); }); // updating selected date range based on selected week // updateSelectedRange(firstDayOfCurrentWeek, lastDayOfCurrentWeek); _launchDateSelectionCallback(_selectedDate); } } var gestureStart; var gestureDirection; void beginSwipe(DragStartDetails gestureDetails) { gestureStart = gestureDetails.globalPosition.dx; } void getDirection(DragUpdateDetails gestureDetails) { if (gestureDetails.globalPosition.dx < gestureStart) { gestureDirection = 'rightToLeft'; } else { gestureDirection = 'leftToRight'; } } void endSwipe(DragEndDetails gestureDetails) { if (gestureDirection == 'rightToLeft') { if (isExpanded) { nextMonth(); } else { nextWeek(); } } else { if (isExpanded) { previousMonth(); } else { previousWeek(); } } } var gestureVertivalStart; var gestureVertivalDirection; void beginVerticalSwipe(DragStartDetails gestureDetails) { gestureVertivalStart = gestureDetails.globalPosition.dy; } void updateVerticalSwipe(DragUpdateDetails gestureDetails) { if (gestureDetails.globalPosition.dy < gestureVertivalStart) { gestureVertivalDirection = 'rightToTop'; } else { gestureVertivalDirection = 'leftToBotton'; } } void endVerticalSwipe(DragEndDetails gestureDetails) { if (gestureVertivalDirection == 'rightToTop') { if (widget.isExpandable) { setState(() => isExpanded = false); } } else { if (widget.isExpandable) { setState(() => isExpanded = true); } } } void toggleExpanded() { if (widget.isExpandable) { setState(() => isExpanded = !isExpanded); } } void handleSelectedDateAndUserCallback(DateTime day) { var firstDayOfCurrentWeek = Utils.firstDayOfWeek(day); var lastDayOfCurrentWeek = Utils.lastDayOfWeek(day); setState(() { _selectedDate = day; selectedWeeksDays = Utils.daysInRange(firstDayOfCurrentWeek, lastDayOfCurrentWeek) .toList(); selectedMonthsDays = Utils.daysInMonth(day); }); _launchDateSelectionCallback(day); } void _launchDateSelectionCallback(DateTime day) { if (widget.onDateSelected != null) { widget.onDateSelected(day); } } updateState(List arrCount){ this.arrCount = arrCount; setState(() { }); } // TextStyle configureDateStyle(monthStarted, monthEnded) { // TextStyle dateStyles; // if (isExpanded) { // dateStyles = monthStarted && !monthEnded // ? new TextStyle(color: MyColors.ff_1a, fontSize: dip_f(13)) // : new TextStyle(color: MyColors.ff_99, fontSize: dip_f(13)); // } else { // dateStyles = new TextStyle(color: MyColors.ff_1a, fontSize: dip_f(13)); // } // return dateStyles; // } int isMtState(DateTime dateTime) { if (_selectedPageDate.month != dateTime.month||_selectedPageDate.year != dateTime.year) { return 0; } int mtState = 0; for (int i = 0; i < arrCount.length; i++) { if(DateTime.parse('${arrCount[i].planDate}').day ==dateTime.day){ if(arrCount[i].complete>0){ mtState = 3; } if(arrCount[i].waitingMaintenance>0){ mtState = 1; } if(arrCount[i].inProgress>0){ mtState = 2; } if(arrCount[i].overdue>0){ mtState = 4; } // if(arrCount[i].statuteOverdueCount>0||arrCount[i].overdueCount>0){ // mtState = 4; // } } } return mtState; } } class ExpansionCrossFade extends StatelessWidget { final Widget collapsed; final Widget expanded; final bool isExpanded; ExpansionCrossFade({this.collapsed, this.expanded, this.isExpanded}); @override Widget build(BuildContext context) { return new Flexible( flex: 1, child: new AnimatedCrossFade( firstChild: collapsed, secondChild: expanded, firstCurve: const Interval(0.0, 1.0, curve: Curves.fastOutSlowIn), secondCurve: const Interval(0.0, 1.0, curve: Curves.fastOutSlowIn), sizeCurve: Curves.decelerate, crossFadeState: isExpanded ? CrossFadeState.showSecond : CrossFadeState.showFirst, duration: const Duration(milliseconds: 100), ), ); } }