mirrored_repositories/flutter-examples/flutter_date_pickers-master/lib
import 'dart:async';

import 'package:flutter/material.dart';

import 'day_based_changable_picker.dart';
import 'utils.dart';

/// Presenter for [DayBasedChangeablePicker] to handle month changes.
class DayBasedChangeablePickerPresenter {
  /// First date user can select.
  final DateTime firstDate;

  /// Last date user can select.
  final DateTime lastDate;
  
  /// Localization.
  final MaterialLocalizations localizations;
  
  /// If empty day cells before 1st day of showing month should be filled with
  /// date from the last week of the previous month.
  final bool showPrevMonthDates;

  /// If empty day cells after last day of showing month should be filled with
  /// date from the first week of the next month.
  final bool showNextMonthDates;
  
  /// Index of the first day in week.
  /// 0 is Sunday, 6 is Saturday.
  final int firstDayOfWeekIndex;
  
  /// View model stream for the [DayBasedChangeablePicker].
  Stream<DayBasedChangeablePickerState> get data => _controller.stream;

  /// Last view model state of the [DayBasedChangeablePicker].
  DayBasedChangeablePickerState? get lastVal => _lastVal;

  /// Creates presenter to use for [DayBasedChangeablePicker].
  DayBasedChangeablePickerPresenter({
    required this.firstDate,
    required this.lastDate,
    required this.localizations,
    required this.showPrevMonthDates,
    required this.showNextMonthDates,
    int? firstDayOfWeekIndex
  }): firstDayOfWeekIndex = firstDayOfWeekIndex
          ?? localizations.firstDayOfWeekIndex;

  /// Update state according to the [selectedDate] if it needs.
  void setSelectedDate(DateTime selectedDate) {
    // bool firstAndLastNotNull = _firstShownDate != null
    //     && _lastShownDate != null;
    //
    // bool selectedOnCurPage =  firstAndLastNotNull
    //     && !selectedDate.isBefore(_firstShownDate)
    //     && !selectedDate.isAfter(_lastShownDate);
    // if (selectedOnCurPage) return;

    changeMonth(selectedDate);
  }

  /// Update state to show previous month.
  void gotoPrevMonth() {
    DateTime oldCur = _lastVal!.currentMonth;
    DateTime newCurDate = DateTime(oldCur.year, oldCur.month - 1);

    changeMonth(newCurDate);
  }

  /// Update state to show next month.
  void gotoNextMonth() {
    DateTime oldCur = _lastVal!.currentMonth;
    DateTime newCurDate = DateTime(oldCur.year, oldCur.month + 1);

    changeMonth(newCurDate);
  }

  /// Update state to change month to the [newMonth].
  void changeMonth(DateTime newMonth) {
    bool sameMonth = _lastVal != null
        && DatePickerUtils.sameMonth(_lastVal!.currentMonth, newMonth);
    if (sameMonth) return;

    int monthPage = DatePickerUtils.monthDelta(firstDate, newMonth);
    DateTime prevMonth = DatePickerUtils
        .addMonthsToMonthDate(firstDate, monthPage - 1);

    DateTime curMonth = DatePickerUtils
        .addMonthsToMonthDate(firstDate, monthPage);

    DateTime nextMonth = DatePickerUtils
        .addMonthsToMonthDate(firstDate, monthPage + 1);

    String prevMonthStr = localizations.formatMonthYear(prevMonth);
    String curMonthStr = localizations.formatMonthYear(curMonth);
    String nextMonthStr = localizations.formatMonthYear(nextMonth);

    bool isFirstMonth = DatePickerUtils.sameMonth(curMonth, firstDate);
    bool isLastMonth = DatePickerUtils.sameMonth(curMonth, lastDate);

    String? prevTooltip = isFirstMonth
        ? null
        : "${localizations.previousMonthTooltip} $prevMonthStr";

    String? nextTooltip = isLastMonth
        ? null
        : "${localizations.nextMonthTooltip} $nextMonthStr";

    DayBasedChangeablePickerState newState = DayBasedChangeablePickerState(
        currentMonth: curMonth,
        curMonthDis: curMonthStr,
        prevMonthDis: prevMonthStr,
        nextMonthDis: nextMonthStr,
        prevTooltip: prevTooltip,
        nextTooltip: nextTooltip,
        isFirstMonth: isFirstMonth,
        isLastMonth: isLastMonth
    );

    _updateState(newState);
  }

  /// Closes controller.
  void dispose () {
    _controller.close();
  }

  void _updateState(DayBasedChangeablePickerState newState) {
    _lastVal = newState;
    _controller.add(newState);
  }

  final StreamController<DayBasedChangeablePickerState> _controller =
    StreamController.broadcast();

  DayBasedChangeablePickerState? _lastVal;
}


/// View Model for the [DayBasedChangeablePicker].
class DayBasedChangeablePickerState {

  /// Display name of the current month.
  final String curMonthDis;

  /// Display name of the previous month.
  final String prevMonthDis;

  /// Display name of the next month.
  final String nextMonthDis;

  /// Tooltip for the previous month icon.
  final String? prevTooltip;

  /// Tooltip for the next month icon.
  final String? nextTooltip;

  /// Tooltip for the current month icon.
  final DateTime currentMonth;

  /// If selected month is the month contains last date user can select.
  final bool isLastMonth;

  /// If selected month is the month contains first date user can select.
  final bool isFirstMonth;

  /// Creates view model for the [DayBasedChangeablePicker].
  DayBasedChangeablePickerState({
    required this.curMonthDis,
    required this.prevMonthDis,
    required this.nextMonthDis,
    required this.currentMonth,
    required this.isLastMonth,
    required this.isFirstMonth,
    this.prevTooltip,
    this.nextTooltip,
  });
}