Line data Source code
1 : import 'dart:async'; 2 : 3 : import 'package:flutter/material.dart'; 4 : 5 : import 'day_based_changable_picker.dart'; 6 : import 'utils.dart'; 7 : 8 : /// Presenter for [DayBasedChangeablePicker] to handle month changes. 9 : class DayBasedChangeablePickerPresenter { 10 : /// First date user can select. 11 : final DateTime firstDate; 12 : 13 : /// Last date user can select. 14 : final DateTime lastDate; 15 : 16 : /// Localization. 17 : final MaterialLocalizations localizations; 18 : 19 : /// If empty day cells before 1st day of showing month should be filled with 20 : /// date from the last week of the previous month. 21 : final bool showPrevMonthDates; 22 : 23 : /// If empty day cells after last day of showing month should be filled with 24 : /// date from the first week of the next month. 25 : final bool showNextMonthDates; 26 : 27 : /// Index of the first day in week. 28 : /// 0 is Sunday, 6 is Saturday. 29 : final int firstDayOfWeekIndex; 30 : 31 : /// View model stream for the [DayBasedChangeablePicker]. 32 0 : Stream<DayBasedChangeablePickerState> get data => _controller.stream; 33 : 34 : /// Last view model state of the [DayBasedChangeablePicker]. 35 0 : DayBasedChangeablePickerState? get lastVal => _lastVal; 36 : 37 : /// Creates presenter to use for [DayBasedChangeablePicker]. 38 0 : DayBasedChangeablePickerPresenter({ 39 : required this.firstDate, 40 : required this.lastDate, 41 : required this.localizations, 42 : required this.showPrevMonthDates, 43 : required this.showNextMonthDates, 44 : int? firstDayOfWeekIndex 45 : }): firstDayOfWeekIndex = firstDayOfWeekIndex 46 0 : ?? localizations.firstDayOfWeekIndex; 47 : 48 : /// Update state according to the [selectedDate] if it needs. 49 0 : void setSelectedDate(DateTime selectedDate) { 50 : // bool firstAndLastNotNull = _firstShownDate != null 51 : // && _lastShownDate != null; 52 : // 53 : // bool selectedOnCurPage = firstAndLastNotNull 54 : // && !selectedDate.isBefore(_firstShownDate) 55 : // && !selectedDate.isAfter(_lastShownDate); 56 : // if (selectedOnCurPage) return; 57 : 58 0 : changeMonth(selectedDate); 59 : } 60 : 61 : /// Update state to show previous month. 62 0 : void gotoPrevMonth() { 63 0 : DateTime oldCur = _lastVal!.currentMonth; 64 0 : DateTime newCurDate = DateTime(oldCur.year, oldCur.month - 1); 65 : 66 0 : changeMonth(newCurDate); 67 : } 68 : 69 : /// Update state to show next month. 70 0 : void gotoNextMonth() { 71 0 : DateTime oldCur = _lastVal!.currentMonth; 72 0 : DateTime newCurDate = DateTime(oldCur.year, oldCur.month + 1); 73 : 74 0 : changeMonth(newCurDate); 75 : } 76 : 77 : /// Update state to change month to the [newMonth]. 78 0 : void changeMonth(DateTime newMonth) { 79 0 : bool sameMonth = _lastVal != null 80 0 : && DatePickerUtils.sameMonth(_lastVal!.currentMonth, newMonth); 81 : if (sameMonth) return; 82 : 83 0 : int monthPage = DatePickerUtils.monthDelta(firstDate, newMonth); 84 : DateTime prevMonth = DatePickerUtils 85 0 : .addMonthsToMonthDate(firstDate, monthPage - 1); 86 : 87 : DateTime curMonth = DatePickerUtils 88 0 : .addMonthsToMonthDate(firstDate, monthPage); 89 : 90 : DateTime nextMonth = DatePickerUtils 91 0 : .addMonthsToMonthDate(firstDate, monthPage + 1); 92 : 93 0 : String prevMonthStr = localizations.formatMonthYear(prevMonth); 94 0 : String curMonthStr = localizations.formatMonthYear(curMonth); 95 0 : String nextMonthStr = localizations.formatMonthYear(nextMonth); 96 : 97 0 : bool isFirstMonth = DatePickerUtils.sameMonth(curMonth, firstDate); 98 0 : bool isLastMonth = DatePickerUtils.sameMonth(curMonth, lastDate); 99 : 100 : String? prevTooltip = isFirstMonth 101 : ? null 102 0 : : "${localizations.previousMonthTooltip} $prevMonthStr"; 103 : 104 : String? nextTooltip = isLastMonth 105 : ? null 106 0 : : "${localizations.nextMonthTooltip} $nextMonthStr"; 107 : 108 0 : DayBasedChangeablePickerState newState = DayBasedChangeablePickerState( 109 : currentMonth: curMonth, 110 : curMonthDis: curMonthStr, 111 : prevMonthDis: prevMonthStr, 112 : nextMonthDis: nextMonthStr, 113 : prevTooltip: prevTooltip, 114 : nextTooltip: nextTooltip, 115 : isFirstMonth: isFirstMonth, 116 : isLastMonth: isLastMonth 117 : ); 118 : 119 0 : _updateState(newState); 120 : } 121 : 122 : /// Closes controller. 123 0 : void dispose () { 124 0 : _controller.close(); 125 : } 126 : 127 0 : void _updateState(DayBasedChangeablePickerState newState) { 128 0 : _lastVal = newState; 129 0 : _controller.add(newState); 130 : } 131 : 132 : final StreamController<DayBasedChangeablePickerState> _controller = 133 : StreamController.broadcast(); 134 : 135 : DayBasedChangeablePickerState? _lastVal; 136 : } 137 : 138 : 139 : /// View Model for the [DayBasedChangeablePicker]. 140 : class DayBasedChangeablePickerState { 141 : 142 : /// Display name of the current month. 143 : final String curMonthDis; 144 : 145 : /// Display name of the previous month. 146 : final String prevMonthDis; 147 : 148 : /// Display name of the next month. 149 : final String nextMonthDis; 150 : 151 : /// Tooltip for the previous month icon. 152 : final String? prevTooltip; 153 : 154 : /// Tooltip for the next month icon. 155 : final String? nextTooltip; 156 : 157 : /// Tooltip for the current month icon. 158 : final DateTime currentMonth; 159 : 160 : /// If selected month is the month contains last date user can select. 161 : final bool isLastMonth; 162 : 163 : /// If selected month is the month contains first date user can select. 164 : final bool isFirstMonth; 165 : 166 : /// Creates view model for the [DayBasedChangeablePicker]. 167 0 : DayBasedChangeablePickerState({ 168 : required this.curMonthDis, 169 : required this.prevMonthDis, 170 : required this.nextMonthDis, 171 : required this.currentMonth, 172 : required this.isLastMonth, 173 : required this.isFirstMonth, 174 : this.prevTooltip, 175 : this.nextTooltip, 176 : }); 177 : }