Эх сурвалжийг харах

数据由controller统一管理

gavin.chen 2 жил өмнө
parent
commit
f48f947eca

+ 224 - 0
lib/calendar_controller/controller.dart

@@ -0,0 +1,224 @@
+import 'package:calendar_view/utils/calendar_util.dart';
+import 'package:calendar_view/utils/event_type.dart';
+import 'package:get/get.dart';
+
+class CalendarController extends GetxController {
+  CalendarController();
+
+  /// 数据项:当前年份,当前月份,当前日期
+  int currentYear = 2022; // 当前年份
+  int currentMonth = 12; // 当前月份
+  int selectedDayIndex = 0; // 当前选择的日期的下标,从0开始,范围是0-34 有时是 0-41
+  int maxDaysLength = 35; // 最大的日期数组长度,有时是42
+  List<DayStructure> daysList = []; // 当前维护的日期列表
+  ///TODO: 维护一个日程列表
+
+  /// TODO[Gavin]: i18n
+  String get currentYearMonth => '$currentYear年$currentMonth月';
+  bool get isToday => daysList[selectedDayIndex].isToday;
+  int get calendarLines => maxDaysLength ~/ 7;
+  // _initData() {
+  //   update(["calendar"]);
+  // }
+  FEventHandler<void> onDaysListChange = FEventHandler<void>();
+
+  void onTap() {}
+
+  @override
+  void onInit() {
+    super.onInit();
+
+    /// 获取当前时间判断年月
+    final DateTime now = DateTime.now();
+    currentYear = now.year;
+    currentMonth = now.month;
+    daysList = _countDaysList(currentYear, currentMonth);
+    selectToday();
+
+    /// 虚拟的日程数据
+    final List<DateTime> mockSchedule = [
+      DateTime(2022, 12, 1),
+      DateTime(2022, 12, 4),
+      DateTime(2022, 12, 5),
+      DateTime(2022, 12, 6),
+      DateTime(2022, 12, 7),
+      DateTime(2022, 12, 12),
+      DateTime(2022, 12, 13),
+      DateTime(2022, 12, 14),
+      DateTime(2022, 12, 15),
+      DateTime(2022, 12, 16),
+      DateTime(2022, 12, 17),
+      DateTime(2022, 12, 18),
+      DateTime(2022, 12, 19),
+      DateTime(2022, 12, 20),
+      DateTime(2022, 12, 27),
+      DateTime(2022, 12, 28),
+      DateTime(2022, 12, 29),
+      DateTime(2022, 12, 30),
+      DateTime(2022, 12, 31),
+    ];
+    _setSchedule(mockSchedule);
+    print("CalendarController 全局临时控制器初始化");
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    // _initData();
+  }
+
+  // @override
+  // void onClose() {
+  //   super.onClose();
+  // }
+  /// 传入起始年月,返回35个日期结构体
+  List<DayStructure> _countDaysList(int year, int month) {
+    maxDaysLength = _isNeedExtraRow(year, month) ? 42 : 35;
+    final daysList = <DayStructure>[];
+    final firstDay = DateTime(year, month, 1);
+    final firstDayWeek = firstDay.weekday;
+    final lastDay = DateTime(year, month + 1, 0);
+    final lastDayOfMonth = lastDay.day;
+    final lastDayOfLastMonth = DateTime(year, month, 0).day;
+    final today = DateTime.now();
+
+    /// 转换后的 firstDayWeek
+    final firstDayWeekIndex = (firstDayWeek) % 7;
+    int nextMonthDay = 1;
+
+    // 上个月的日期
+    for (var i = 0; i < firstDayWeekIndex; i++) {
+      daysList.add(
+        DayStructure(
+          index: i,
+          date: DateTime(
+              year, month - 1, lastDayOfLastMonth - firstDayWeekIndex + i + 1),
+          isCurrentMonth: false,
+        ),
+      );
+    }
+
+    // 当月的日期
+    for (var i = 0;
+        (i < lastDayOfMonth) && daysList.length < maxDaysLength;
+        i++) {
+      daysList.add(
+        DayStructure(
+          index: i + firstDayWeek,
+          date: DateTime(year, month, i + 1),
+          isToday:
+              today.year == year && today.month == month && today.day == i + 1,
+        ),
+      );
+    }
+
+    while (daysList.length < maxDaysLength) {
+      daysList.add(DayStructure(
+        index: daysList.length,
+        date: DateTime(month == 12 ? year + 1 : year,
+            month == 12 ? 1 : month + 1, nextMonthDay),
+        isCurrentMonth: false,
+      ));
+      nextMonthDay++;
+    }
+    return daysList;
+  }
+
+  /// 计算是否需要显示六行日期,一般为5行,但是有时候会有6行
+  bool _isNeedExtraRow(int year, int month) {
+    final firstDay = DateTime(year, month, 1);
+    final firstDayWeek = firstDay.weekday;
+    final lastDay = DateTime(year, month + 1, 0);
+    final lastDayOfMonth = lastDay.day;
+
+    /// 转换后的firstDayWeek,%7是因为DateTime的weekday是从周日开始的,而我们的日历是从周一开始的
+    final firstDayWeekIndex = (firstDayWeek) % 7;
+    return firstDayWeekIndex + lastDayOfMonth > 35;
+  }
+
+  /// 通过下标选中日期,下标从0开始,允许的范围是0-34,有时是 0-42
+  void handleSelectedDayByIndex(int index) {
+    assert(index >= 0 && index < maxDaysLength,
+        'index must be in 0-$maxDaysLength');
+    assert(daysList.length == maxDaysLength,
+        'daysList length must be maxDaysLength');
+    for (var element in daysList) {
+      if (element.index == index) {
+        element.isSelected = true;
+      } else {
+        element.isSelected = false;
+      }
+    }
+    selectedDayIndex = index;
+    onDaysListChange.emit(this, null);
+  }
+
+  /// 选中当月第一天
+  void _selectFirstDay() {
+    for (var element in daysList) {
+      if (element.isCurrentMonth) {
+        handleSelectedDayByIndex(element.index);
+        break;
+      }
+    }
+  }
+
+  /// 选中今天
+  void selectToday() {
+    /// 如果当前不是当月,则切换到当月
+    final DateTime now = DateTime.now();
+    if (currentYear != now.year || currentMonth != now.month) {
+      currentYear = now.year;
+      currentMonth = now.month;
+      daysList = _countDaysList(currentYear, currentMonth);
+    }
+    for (var element in daysList) {
+      if (element.isToday) {
+        handleSelectedDayByIndex(element.index);
+        break;
+      }
+    }
+  }
+
+  /// 给日期设置日程的值
+  void _setSchedule(List<DateTime> scheduleList) {
+    /// 如果scheduleList中存在daysList中的日期,则设置hasSchedule为true
+    for (var element in scheduleList) {
+      for (var day in daysList) {
+        if (element.year == day.date.year &&
+            element.month == day.date.month &&
+            element.day == day.date.day) {
+          day.hasSchedule = true;
+        }
+      }
+    }
+  }
+
+  /// 上个月
+  void handleLastMonth() {
+    if (currentMonth == 1) {
+      currentMonth = 12;
+      currentYear--;
+    } else {
+      currentMonth--;
+    }
+    daysList = _countDaysList(currentYear, currentMonth);
+    _selectFirstDay();
+
+    onDaysListChange.emit(this, null);
+  }
+
+  /// 下个月
+  void handleNextMonth() {
+    if (currentMonth == 12) {
+      currentMonth = 1;
+      currentYear++;
+    } else {
+      currentMonth++;
+    }
+    daysList = _countDaysList(currentYear, currentMonth);
+    _selectFirstDay();
+
+    onDaysListChange.emit(this, null);
+  }
+}

+ 32 - 30
lib/calendar_view/calendar_main_panel.dart

@@ -1,7 +1,9 @@
+import 'package:calendar_view/calendar_controller/controller.dart';
 import 'package:calendar_view/calendar_view/calendar_views/calendar_month_view.dart';
 import 'package:calendar_view/calendar_view/mini_calendar/mini_calendar.dart';
 import 'package:calendar_view/calendar_view/my_calendar/my_calendar.dart';
 import 'package:flutter/material.dart';
+import 'package:get/get.dart';
 
 /// 日历视图主体面板
 class CalendarMainPanel extends StatefulWidget {
@@ -14,7 +16,31 @@ class CalendarMainPanel extends StatefulWidget {
 enum CalendarViewType { month, week, day, list }
 
 class _CalendarMainPanelState extends State<CalendarMainPanel> {
+  /// TODO:[Gavin] 将 _viewType 也收入到 CalendarController 中
   final CalendarViewType _viewType = CalendarViewType.month;
+  String _currYearMonthStr = ''; // 当前年月
+  bool _isToday = true; // 是否是今天
+  CalendarController calendarController = Get.find<CalendarController>();
+  @override
+  void initState() {
+    super.initState();
+    _isToday = calendarController.isToday;
+    _currYearMonthStr = calendarController.currentYearMonth;
+    calendarController.onDaysListChange.addListener(_onDaysListChange);
+  }
+
+  @override
+  void dispose() {
+    super.dispose();
+    calendarController.onDaysListChange.removeListener(_onDaysListChange);
+  }
+
+  void _onDaysListChange(_, e) {
+    setState(() {
+      _isToday = calendarController.isToday;
+      _currYearMonthStr = calendarController.currentYearMonth;
+    });
+  }
 
   /// 按钮样式
   final iconButtonStyle = ButtonStyle(
@@ -84,15 +110,7 @@ class _CalendarMainPanelState extends State<CalendarMainPanel> {
               const EdgeInsets.all(0)),
           shadowColor: MaterialStateProperty.all<Color>(Colors.transparent),
         ),
-        onPressed: () {
-          // 如果不是今天则可以按下
-          ScaffoldMessenger.of(context).showSnackBar(
-            const SnackBar(
-              duration: Duration(milliseconds: 500),
-              content: Text('等待接入 Controller 的“回到今天”事件'),
-            ),
-          );
-        },
+        onPressed: _isToday ? null : calendarController.selectToday,
         // TODO[Gavin]: i18n
         child: const Text('今天'),
       ),
@@ -112,14 +130,7 @@ class _CalendarMainPanelState extends State<CalendarMainPanel> {
             height: 32,
             child: ElevatedButton(
               style: iconButtonStyle,
-              onPressed: () {
-                ScaffoldMessenger.of(context).showSnackBar(
-                  const SnackBar(
-                    duration: Duration(milliseconds: 500),
-                    content: Text('等待接入 Controller 的上个月事件'),
-                  ),
-                );
-              }, // 接入日历 Controller
+              onPressed: calendarController.handleNextMonth,
               child: const Icon(
                 Icons.keyboard_arrow_left,
                 size: 20,
@@ -132,14 +143,7 @@ class _CalendarMainPanelState extends State<CalendarMainPanel> {
             height: 32,
             child: ElevatedButton(
               style: iconButtonStyle,
-              onPressed: () {
-                ScaffoldMessenger.of(context).showSnackBar(
-                  const SnackBar(
-                    duration: Duration(milliseconds: 500),
-                    content: Text('等待接入 Controller 的下个月事件'),
-                  ),
-                );
-              }, // 接入日历 Controller
+              onPressed: calendarController.handleLastMonth,
               child: const Icon(
                 Icons.keyboard_arrow_right,
                 size: 20,
@@ -154,13 +158,11 @@ class _CalendarMainPanelState extends State<CalendarMainPanel> {
 
   /// 年月
   Widget _buildYearAndMonth() {
-    /// TODO: get year and month from controller
-    return const Align(
+    return Align(
       alignment: Alignment.center,
       child: Text(
-        /// TODO[Gavin]: i18n
-        '2022年12月',
-        style: TextStyle(
+        _currYearMonthStr,
+        style: const TextStyle(
           height: 1.2,
           fontSize: 18,
         ),

+ 8 - 0
lib/calendar_view/calendar_view.dart

@@ -1,6 +1,8 @@
+import 'package:calendar_view/calendar_controller/controller.dart';
 import 'package:calendar_view/calendar_view/calendar_left_panel.dart';
 import 'package:calendar_view/calendar_view/calendar_main_panel.dart';
 import 'package:flutter/material.dart';
+import 'package:get/get.dart';
 
 class CalendarView extends StatefulWidget {
   const CalendarView({super.key});
@@ -10,6 +12,12 @@ class CalendarView extends StatefulWidget {
 }
 
 class _CalendarViewState extends State<CalendarView> {
+  @override
+  void initState() {
+    super.initState();
+    Get.put<CalendarController>(CalendarController());
+  }
+
   @override
   Widget build(BuildContext context) {
     return Container(

+ 24 - 183
lib/calendar_view/mini_calendar/mini_calendar.dart

@@ -1,6 +1,8 @@
-import 'package:calendar_view/calendar_view/calendar_util.dart';
+import 'package:calendar_view/calendar_controller/controller.dart';
+import 'package:calendar_view/utils/calendar_util.dart';
 import 'package:calendar_view/calendar_view/mini_calendar/mini_day_item.dart';
 import 'package:flutter/material.dart';
+import 'package:get/get.dart';
 
 class MiniCalendar extends StatefulWidget {
   const MiniCalendar({super.key});
@@ -10,46 +12,28 @@ class MiniCalendar extends StatefulWidget {
 }
 
 class _MiniCalendarState extends State<MiniCalendar> {
-  int currentYear = 2022; // 当前年份
-  int currentMonth = 12; // 当前月份
-  int selectedDayIndex = 0; // 当前选择的日期的下标,从0开始,范围是0-34 有时是 0-41
-  int maxDaysLength = 35; // 最大的日期数组长度,有时是42
-  List<DayStructure> daysList = []; // 当前维护的日期列表
-
+  String currYearMonth = ''; // 当前年月
+  List<DayStructure> daysList = []; // 当前控制器的日期列表
+  CalendarController calendarController = Get.find<CalendarController>();
   @override
   void initState() {
     super.initState();
+    currYearMonth = calendarController.currentYearMonth;
+    daysList = calendarController.daysList;
+    calendarController.onDaysListChange.addListener(_onDaysListChange);
+  }
 
-    /// 获取当前时间判断年月
-    final DateTime now = DateTime.now();
-    currentYear = now.year;
-    currentMonth = now.month;
-    daysList = _countDaysList(currentYear, currentMonth);
-    _selectToday();
+  @override
+  void dispose() {
+    super.dispose();
+    calendarController.onDaysListChange.removeListener(_onDaysListChange);
+  }
 
-    /// 虚拟的日程数据
-    final List<DateTime> mockSchedule = [
-      DateTime(2022, 12, 1),
-      DateTime(2022, 12, 4),
-      DateTime(2022, 12, 5),
-      DateTime(2022, 12, 6),
-      DateTime(2022, 12, 7),
-      DateTime(2022, 12, 12),
-      DateTime(2022, 12, 13),
-      DateTime(2022, 12, 14),
-      DateTime(2022, 12, 15),
-      DateTime(2022, 12, 16),
-      DateTime(2022, 12, 17),
-      DateTime(2022, 12, 18),
-      DateTime(2022, 12, 19),
-      DateTime(2022, 12, 20),
-      DateTime(2022, 12, 27),
-      DateTime(2022, 12, 28),
-      DateTime(2022, 12, 29),
-      DateTime(2022, 12, 30),
-      DateTime(2022, 12, 31),
-    ];
-    _setSchedule(mockSchedule);
+  void _onDaysListChange(_, e) {
+    setState(() {
+      currYearMonth = calendarController.currentYearMonth;
+      daysList = calendarController.daysList;
+    });
   }
 
   @override
@@ -86,8 +70,7 @@ class _MiniCalendarState extends State<MiniCalendar> {
             width: 10,
           ),
           Text(
-            /// TODO[Gavin]: i18n
-            '$currentYear年$currentMonth月',
+            currYearMonth,
             style: const TextStyle(
               fontSize: 16,
             ),
@@ -98,7 +81,7 @@ class _MiniCalendarState extends State<MiniCalendar> {
             height: 32,
             child: ElevatedButton(
               style: iconButtonStyle,
-              onPressed: _handleLastMonth,
+              onPressed: calendarController.handleLastMonth,
               child: const Icon(
                 Icons.keyboard_arrow_left,
                 size: 20,
@@ -111,7 +94,7 @@ class _MiniCalendarState extends State<MiniCalendar> {
             height: 32,
             child: ElevatedButton(
               style: iconButtonStyle,
-              onPressed: _handleNextMonth,
+              onPressed: calendarController.handleNextMonth,
               child: const Icon(
                 Icons.keyboard_arrow_right,
                 size: 20,
@@ -200,149 +183,7 @@ class _MiniCalendarState extends State<MiniCalendar> {
   Widget _buildEachDay(DayStructure day) {
     return MiniDayItem(
       dayData: day,
-      onSelect: (v) => _handleSelectedDayByIndex(v),
+      onSelect: (v) => calendarController.handleSelectedDayByIndex(v),
     );
   }
-
-  /// 传入起始年月,返回35个日期结构体
-  List<DayStructure> _countDaysList(int year, int month) {
-    maxDaysLength = _isNeedExtraRow(year, month) ? 42 : 35;
-    final daysList = <DayStructure>[];
-    final firstDay = DateTime(year, month, 1);
-    final firstDayWeek = firstDay.weekday;
-    final lastDay = DateTime(year, month + 1, 0);
-    final lastDayOfMonth = lastDay.day;
-    final lastDayOfLastMonth = DateTime(year, month, 0).day;
-    final today = DateTime.now();
-
-    /// 转换后的 firstDayWeek
-    final firstDayWeekIndex = (firstDayWeek) % 7;
-    int nextMonthDay = 1;
-
-    // 上个月的日期
-    for (var i = 0; i < firstDayWeekIndex; i++) {
-      daysList.add(
-        DayStructure(
-          index: i,
-          date: DateTime(
-              year, month - 1, lastDayOfLastMonth - firstDayWeekIndex + i + 1),
-          isCurrentMonth: false,
-        ),
-      );
-    }
-
-    // 当月的日期
-    for (var i = 0;
-        (i < lastDayOfMonth) && daysList.length < maxDaysLength;
-        i++) {
-      daysList.add(
-        DayStructure(
-          index: i + firstDayWeek,
-          date: DateTime(year, month, i + 1),
-          isToday:
-              today.year == year && today.month == month && today.day == i + 1,
-        ),
-      );
-    }
-
-    while (daysList.length < maxDaysLength) {
-      daysList.add(DayStructure(
-        index: daysList.length,
-        date: DateTime(month == 12 ? year + 1 : year,
-            month == 12 ? 1 : month + 1, nextMonthDay),
-        isCurrentMonth: false,
-      ));
-      nextMonthDay++;
-    }
-    return daysList;
-  }
-
-  /// 计算是否需要显示六行日期,一般为5行,但是有时候会有6行
-  bool _isNeedExtraRow(int year, int month) {
-    final firstDay = DateTime(year, month, 1);
-    final firstDayWeek = firstDay.weekday;
-    final lastDay = DateTime(year, month + 1, 0);
-    final lastDayOfMonth = lastDay.day;
-
-    /// 转换后的firstDayWeek,%7是因为DateTime的weekday是从周日开始的,而我们的日历是从周一开始的
-    final firstDayWeekIndex = (firstDayWeek) % 7;
-    return firstDayWeekIndex + lastDayOfMonth > 35;
-  }
-
-  /// 通过下标选中日期,下标从0开始,允许的范围是0-34,有时是 0-42
-  void _handleSelectedDayByIndex(int index) {
-    assert(index >= 0 && index < maxDaysLength,
-        'index must be in 0-$maxDaysLength');
-    assert(daysList.length == maxDaysLength,
-        'daysList length must be maxDaysLength');
-    for (var element in daysList) {
-      if (element.index == index) {
-        element.isSelected = true;
-      } else {
-        element.isSelected = false;
-      }
-    }
-    selectedDayIndex = index;
-    setState(() {});
-  }
-
-  /// 选中当月第一天
-  void _selectFirstDay() {
-    for (var element in daysList) {
-      if (element.isCurrentMonth) {
-        _handleSelectedDayByIndex(element.index);
-        break;
-      }
-    }
-  }
-
-  /// 选中今天
-  void _selectToday() {
-    for (var element in daysList) {
-      if (element.isToday) {
-        _handleSelectedDayByIndex(element.index);
-        break;
-      }
-    }
-  }
-
-  /// 给日期设置日程的值
-  void _setSchedule(List<DateTime> scheduleList) {
-    /// 如果scheduleList中存在daysList中的日期,则设置hasSchedule为true
-    for (var element in scheduleList) {
-      for (var day in daysList) {
-        if (element.year == day.date.year &&
-            element.month == day.date.month &&
-            element.day == day.date.day) {
-          day.hasSchedule = true;
-        }
-      }
-    }
-  }
-
-  /// 上个月
-  void _handleLastMonth() {
-    if (currentMonth == 1) {
-      currentMonth = 12;
-      currentYear--;
-    } else {
-      currentMonth--;
-    }
-    daysList = _countDaysList(currentYear, currentMonth);
-    _selectFirstDay();
-    setState(() {});
-  }
-
-  /// 下个月
-  void _handleNextMonth() {
-    if (currentMonth == 12) {
-      currentMonth = 1;
-      currentYear++;
-    } else {
-      currentMonth++;
-    }
-    daysList = _countDaysList(currentYear, currentMonth);
-    _selectFirstDay();
-    setState(() {});
-  }
 }

+ 9 - 9
lib/calendar_view/mini_calendar/mini_day_item.dart

@@ -1,4 +1,4 @@
-import 'package:calendar_view/calendar_view/calendar_util.dart';
+import 'package:calendar_view/utils/calendar_util.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 
@@ -72,14 +72,14 @@ class _MyWidgetState extends State<MiniDayItem> {
 
   @override
   Widget build(BuildContext context) {
-    return MouseRegion(
-      cursor: SystemMouseCursors.click,
-      onEnter: _handleMouthEnter,
-      onExit: _handleMouthExit,
-      child: GestureDetector(
-        onTap: () {
-          widget.onSelect.call(_dayData.index);
-        },
+    return GestureDetector(
+      onTap: () {
+        widget.onSelect.call(_dayData.index);
+      },
+      child: MouseRegion(
+        cursor: SystemMouseCursors.click,
+        onEnter: _handleMouthEnter,
+        onExit: _handleMouthExit,
         child: Column(
           children: [
             Container(

+ 25 - 183
lib/calendar_view/month_calendar/month_calendar.dart

@@ -1,9 +1,11 @@
 import 'dart:html';
 
-import 'package:calendar_view/calendar_view/calendar_util.dart';
+import 'package:calendar_view/calendar_controller/controller.dart';
+import 'package:calendar_view/utils/calendar_util.dart';
 import 'package:calendar_view/calendar_view/month_calendar/month_calendar_item.dart';
 import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
+import 'package:get/get.dart';
 
 class MonthCalendar extends StatefulWidget {
   const MonthCalendar({super.key});
@@ -13,49 +15,15 @@ class MonthCalendar extends StatefulWidget {
 }
 
 class _MonthCalendarState extends State<MonthCalendar> {
-  int currentYear = 2022; // 当前年份
-  int currentMonth = 12; // 当前月份
-  int selectedDayIndex = 0; // 当前选择的日期的下标,从0开始,范围是0-34 有时是 0-41
-  int maxDaysLength = 35; // 最大的日期数组长度,有时是42
-  List<DayStructure> daysList = []; // 当前维护的日期列表
+  List<DayStructure> daysList = []; // 当前控制器的日期列表
+  CalendarController calendarController = Get.find<CalendarController>();
   int _maxScheduleLines = 3; // 最大的日程行数【需要动态计算】
   double _viewHeight = 0; // 维护一个视口高度,如果视口高度不变,那么日程的高度不需要计算
-
+  int _calendarLines = 0; // 维护一个日历行数,如果日历行数不变,那么日程的高度不需要计算
   @override
   void initState() {
     super.initState();
 
-    /// 获取当前时间判断年月
-    final DateTime now = DateTime.now();
-    currentYear = now.year;
-    currentMonth = now.month;
-    daysList = _countDaysList(currentYear, currentMonth);
-    _selectToday();
-
-    /// 虚拟的日程数据
-    final List<DateTime> mockSchedule = [
-      DateTime(2022, 12, 1),
-      DateTime(2022, 12, 4),
-      DateTime(2022, 12, 5),
-      DateTime(2022, 12, 6),
-      DateTime(2022, 12, 7),
-      DateTime(2022, 12, 12),
-      DateTime(2022, 12, 13),
-      DateTime(2022, 12, 14),
-      DateTime(2022, 12, 15),
-      DateTime(2022, 12, 16),
-      DateTime(2022, 12, 17),
-      DateTime(2022, 12, 18),
-      DateTime(2022, 12, 19),
-      DateTime(2022, 12, 20),
-      DateTime(2022, 12, 27),
-      DateTime(2022, 12, 28),
-      DateTime(2022, 12, 29),
-      DateTime(2022, 12, 30),
-      DateTime(2022, 12, 31),
-    ];
-    _setSchedule(mockSchedule);
-
     /// 监控resize事件,动态计算最大日程行数
     WidgetsBinding.instance.addPostFrameCallback((_) {
       _handleMaxScheduleLines();
@@ -69,6 +37,21 @@ class _MonthCalendarState extends State<MonthCalendar> {
         });
       });
     }
+    daysList = calendarController.daysList;
+    calendarController.onDaysListChange.addListener(_onDaysListChange);
+  }
+
+  @override
+  void dispose() {
+    super.dispose();
+    calendarController.onDaysListChange.removeListener(_onDaysListChange);
+  }
+
+  void _onDaysListChange(_, e) {
+    setState(() {
+      daysList = calendarController.daysList;
+    });
+    _handleMaxScheduleLines();
   }
 
   @override
@@ -159,162 +142,21 @@ class _MonthCalendarState extends State<MonthCalendar> {
         ),
         child: MonthDayItem(
           dayData: day,
-          onSelect: (v) => _handleSelectedDayByIndex(v),
           maxScheduleLines: _maxScheduleLines,
         ),
       ),
     );
   }
 
-  /// 传入起始年月,返回35个日期结构体
-  List<DayStructure> _countDaysList(int year, int month) {
-    maxDaysLength = _isNeedExtraRow(year, month) ? 42 : 35;
-    final daysList = <DayStructure>[];
-    final firstDay = DateTime(year, month, 1);
-    final firstDayWeek = firstDay.weekday;
-    final lastDay = DateTime(year, month + 1, 0);
-    final lastDayOfMonth = lastDay.day;
-    final lastDayOfLastMonth = DateTime(year, month, 0).day;
-    final today = DateTime.now();
-
-    /// 转换后的 firstDayWeek
-    final firstDayWeekIndex = (firstDayWeek) % 7;
-    int nextMonthDay = 1;
-
-    // 上个月的日期
-    for (var i = 0; i < firstDayWeekIndex; i++) {
-      daysList.add(
-        DayStructure(
-          index: i,
-          date: DateTime(
-              year, month - 1, lastDayOfLastMonth - firstDayWeekIndex + i + 1),
-          isCurrentMonth: false,
-        ),
-      );
-    }
-
-    // 当月的日期
-    for (var i = 0;
-        (i < lastDayOfMonth) && daysList.length < maxDaysLength;
-        i++) {
-      daysList.add(
-        DayStructure(
-          index: i + firstDayWeek,
-          date: DateTime(year, month, i + 1),
-          isToday:
-              today.year == year && today.month == month && today.day == i + 1,
-        ),
-      );
-    }
-
-    while (daysList.length < maxDaysLength) {
-      daysList.add(DayStructure(
-        index: daysList.length,
-        date: DateTime(month == 12 ? year + 1 : year,
-            month == 12 ? 1 : month + 1, nextMonthDay),
-        isCurrentMonth: false,
-      ));
-      nextMonthDay++;
-    }
-    return daysList;
-  }
-
-  /// 计算是否需要显示六行日期,一般为5行,但是有时候会有6行
-  bool _isNeedExtraRow(int year, int month) {
-    final firstDay = DateTime(year, month, 1);
-    final firstDayWeek = firstDay.weekday;
-    final lastDay = DateTime(year, month + 1, 0);
-    final lastDayOfMonth = lastDay.day;
-
-    /// 转换后的firstDayWeek,%7是因为DateTime的weekday是从周日开始的,而我们的日历是从周一开始的
-    final firstDayWeekIndex = (firstDayWeek) % 7;
-    return firstDayWeekIndex + lastDayOfMonth > 35;
-  }
-
-  /// 通过下标选中日期,下标从0开始,允许的范围是0-34,有时是 0-42
-  void _handleSelectedDayByIndex(int index) {
-    assert(index >= 0 && index < maxDaysLength,
-        'index must be in 0-$maxDaysLength');
-    assert(daysList.length == maxDaysLength,
-        'daysList length must be maxDaysLength');
-    for (var element in daysList) {
-      if (element.index == index) {
-        element.isSelected = true;
-      } else {
-        element.isSelected = false;
-      }
-    }
-    selectedDayIndex = index;
-    setState(() {});
-  }
-
-  /// 选中当月第一天
-  void _selectFirstDay() {
-    for (var element in daysList) {
-      if (element.isCurrentMonth) {
-        _handleSelectedDayByIndex(element.index);
-        break;
-      }
-    }
-  }
-
-  /// 选中今天
-  void _selectToday() {
-    for (var element in daysList) {
-      if (element.isToday) {
-        _handleSelectedDayByIndex(element.index);
-        break;
-      }
-    }
-  }
-
-  /// 给日期设置日程的值
-  void _setSchedule(List<DateTime> scheduleList) {
-    /// 如果scheduleList中存在daysList中的日期,则设置hasSchedule为true
-    for (var element in scheduleList) {
-      for (var day in daysList) {
-        if (element.year == day.date.year &&
-            element.month == day.date.month &&
-            element.day == day.date.day) {
-          day.hasSchedule = true;
-        }
-      }
-    }
-  }
-
-  /// 上个月
-  void _handleLastMonth() {
-    if (currentMonth == 1) {
-      currentMonth = 12;
-      currentYear--;
-    } else {
-      currentMonth--;
-    }
-    daysList = _countDaysList(currentYear, currentMonth);
-    _selectFirstDay();
-    setState(() {});
-  }
-
-  /// 下个月
-  void _handleNextMonth() {
-    if (currentMonth == 12) {
-      currentMonth = 1;
-      currentYear++;
-    } else {
-      currentMonth++;
-    }
-    daysList = _countDaysList(currentYear, currentMonth);
-    _selectFirstDay();
-    setState(() {});
-  }
-
   /// 动态计算日历格内的最大日程行数
   void _handleMaxScheduleLines() {
     final size = MediaQuery.of(context).size;
-    if (size.height == _viewHeight) return;
+    if (size.height == _viewHeight &&
+        calendarController.calendarLines == _calendarLines) return;
     print('计算最大日程行数');
     _viewHeight = size.height;
-    final gridRows = (maxDaysLength / 7).floor();
+    _calendarLines = calendarController.calendarLines;
+    final gridRows = calendarController.calendarLines;
     final gridHeight = size.height - 100; // 100 是日历头部的高度
     final gridItemHeight = gridHeight / gridRows;
     final scheduleAreaHeight = gridItemHeight - 30; // 30 是日期的高度

+ 28 - 37
lib/calendar_view/month_calendar/month_calendar_item.dart

@@ -1,18 +1,17 @@
-import 'package:calendar_view/calendar_view/calendar_util.dart';
-import 'package:calendar_view/calendar_view/chinese_calendar_utils.dart';
+import 'package:calendar_view/utils/calendar_util.dart';
+import 'package:calendar_view/utils/chinese_calendar_utils.dart';
 import 'package:calendar_view/calendar_view/month_calendar/schedule_list.dart';
 import 'package:flutter/material.dart';
-import 'package:intl/intl.dart';
 
 /// 月历的每一格日期
 class MonthDayItem extends StatefulWidget {
   const MonthDayItem(
       {super.key,
       required this.dayData,
-      required this.onSelect,
+      // required this.onSelect,
       required this.maxScheduleLines});
   final DayStructure dayData;
-  final ValueChanged<int> onSelect;
+  // final ValueChanged<int> onSelect;
   final int maxScheduleLines;
 
   /// 最大能容纳的日程条数
@@ -105,42 +104,34 @@ class _MyWidgetState extends State<MonthDayItem> {
 
   @override
   Widget build(BuildContext context) {
-    return MouseRegion(
-      cursor: SystemMouseCursors.click,
-      child: GestureDetector(
-        onTap: () {
-          widget.onSelect.call(_dayData.index);
-        },
-        child: Container(
-          decoration: _gridContainerDecoration,
-          child: Column(
+    return Container(
+      decoration: _gridContainerDecoration,
+      child: Column(
+        children: [
+          Row(
+            mainAxisAlignment: MainAxisAlignment.center,
             children: [
-              Row(
-                mainAxisAlignment: MainAxisAlignment.center,
-                children: [
-                  Container(
-                    decoration: _dateContainerDecoration,
-                    margin: const EdgeInsets.symmetric(vertical: 3),
-                    height: 24,
-                    width: 24,
-                    child: Center(
-                      child: Text(displayStr, style: _dayTextStyle),
-                    ),
-                  ),
-                  Container(
-                    // decoration: _dateContainerDecoration,
-                    margin: const EdgeInsets.all(3),
-                    height: 24,
-                    child: Center(
-                      child: Text(_getLunarDay(), style: _lunarDayTextStyle),
-                    ),
-                  ),
-                ],
+              Container(
+                decoration: _dateContainerDecoration,
+                margin: const EdgeInsets.symmetric(vertical: 3),
+                height: 24,
+                width: 24,
+                child: Center(
+                  child: Text(displayStr, style: _dayTextStyle),
+                ),
+              ),
+              Container(
+                // decoration: _dateContainerDecoration,
+                margin: const EdgeInsets.all(3),
+                height: 24,
+                child: Center(
+                  child: Text(_getLunarDay(), style: _lunarDayTextStyle),
+                ),
               ),
-              _buildScheduleContainer()
             ],
           ),
-        ),
+          _buildScheduleContainer()
+        ],
       ),
     );
   }

+ 66 - 40
lib/calendar_view/month_calendar/schedule_list.dart

@@ -1,6 +1,6 @@
 import 'dart:math';
 
-import 'package:calendar_view/calendar_view/calendar_util.dart';
+import 'package:calendar_view/utils/calendar_util.dart';
 import 'package:flutter/material.dart';
 
 class ScheduleList extends StatefulWidget {
@@ -57,6 +57,7 @@ class ScheduleListState extends State<ScheduleList> {
   @override
   Widget build(BuildContext context) {
     return Container(
+      padding: const EdgeInsets.symmetric(horizontal: 2),
       child: _buildScheduleTypeList(),
     );
   }
@@ -81,54 +82,79 @@ class ScheduleListState extends State<ScheduleList> {
       }
     }
     ScheduleType scheduleType = _scheduleTypeList[scheduleIndex];
-    return InkWell(
-      hoverColor: scheduleType.color.withOpacity(0.2),
-      child: Container(
-        height: widget.itemHeight,
-        padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 0),
-        // color: Colors.transparent,
-        child: Row(
-          children: [
-            Container(
-              width: 6,
-              height: 6,
-              decoration: BoxDecoration(
-                color: scheduleType.color,
-                borderRadius: BorderRadius.circular(5),
+    return Material(
+      color: Colors.transparent,
+      child: InkWell(
+        customBorder: RoundedRectangleBorder(
+          borderRadius: BorderRadius.circular(5),
+        ),
+        onTap: () => print('点击了${scheduleType.typeName}'),
+        hoverColor: const Color.fromARGB(255, 227, 228, 228),
+        child: Container(
+          height: widget.itemHeight,
+          padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 0),
+          decoration: BoxDecoration(
+            color: scheduleType.isSelected
+                ? scheduleType.color.withOpacity(0.2)
+                : Colors.transparent,
+            borderRadius: BorderRadius.circular(5),
+          ),
+          child: Row(
+            children: [
+              Container(
+                width: 6,
+                height: 6,
+                decoration: BoxDecoration(
+                  color: scheduleType.color,
+                  borderRadius: BorderRadius.circular(5),
+                ),
               ),
-            ),
-            const SizedBox(width: 10),
-            Text(
-              scheduleType.typeName,
-              style: const TextStyle(fontSize: 12),
-            ),
-          ],
+              const SizedBox(width: 10),
+              Text(
+                scheduleType.typeName,
+                style: const TextStyle(fontSize: 12),
+              ),
+            ],
+          ),
         ),
       ),
     );
   }
 
   Widget _buildMoreItemButton(int moreNum) {
-    return Container(
-      height: widget.itemHeight,
-      padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 0),
+    return Material(
       color: Colors.transparent,
-      child: Row(
-        children: [
-          Container(
-            width: 6,
-            height: 6,
-            decoration: BoxDecoration(
-              color: Colors.transparent,
-              borderRadius: BorderRadius.circular(5),
-            ),
-          ),
-          const SizedBox(width: 10),
-          Text(
-            '还有$moreNum项...',
-            style: const TextStyle(fontSize: 12),
+      child: InkWell(
+        customBorder: RoundedRectangleBorder(
+          borderRadius: BorderRadius.circular(5),
+        ),
+        onTap: () => print('点击了更多'),
+        hoverColor: const Color.fromARGB(255, 227, 228, 228),
+        child: Container(
+          height: widget.itemHeight,
+          padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 0),
+          color: Colors.transparent,
+          child: Row(
+            children: [
+              Container(
+                width: 6,
+                height: 6,
+                decoration: BoxDecoration(
+                  color: Colors.transparent,
+                  borderRadius: BorderRadius.circular(5),
+                ),
+              ),
+              const SizedBox(width: 10),
+              Text(
+                '还有$moreNum项...',
+                style: const TextStyle(
+                  fontSize: 12,
+                  color: Colors.black38,
+                ),
+              ),
+            ],
           ),
-        ],
+        ),
       ),
     );
   }

+ 1 - 1
lib/calendar_view/my_calendar/my_calendar.dart

@@ -1,4 +1,4 @@
-import 'package:calendar_view/calendar_view/calendar_util.dart';
+import 'package:calendar_view/utils/calendar_util.dart';
 import 'package:calendar_view/calendar_view/my_calendar/my_schedule_item.dart';
 import 'package:flutter/material.dart';
 

+ 1 - 1
lib/calendar_view/my_calendar/my_schedule_item.dart

@@ -1,4 +1,4 @@
-import 'package:calendar_view/calendar_view/calendar_util.dart';
+import 'package:calendar_view/utils/calendar_util.dart';
 import 'package:flutter/material.dart';
 
 class MyScheduleItem extends StatefulWidget {

+ 4 - 3
lib/main.dart

@@ -1,5 +1,6 @@
 import 'package:calendar_view/calendar_view/calendar_view.dart';
 import 'package:flutter/material.dart';
+import 'package:get/get_navigation/src/root/get_material_app.dart';
 
 void main() {
   runApp(const MyApp());
@@ -11,7 +12,7 @@ class MyApp extends StatelessWidget {
   // This widget is the root of your application.
   @override
   Widget build(BuildContext context) {
-    return MaterialApp(
+    return GetMaterialApp(
       title: 'Flutter Demo',
       theme: ThemeData(
         primarySwatch: Colors.blue,
@@ -34,8 +35,8 @@ class MyHomePage extends StatefulWidget {
 class _MyHomePageState extends State<MyHomePage> {
   @override
   Widget build(BuildContext context) {
-    return Scaffold(
-      body: const CalendarView(),
+    return const Scaffold(
+      body: CalendarView(),
     );
   }
 }

+ 1 - 0
lib/calendar_view/calendar_util.dart → lib/utils/calendar_util.dart

@@ -1,3 +1,4 @@
+
 import 'package:flutter/material.dart';
 
 /// 结构化的日期数据

+ 0 - 19
lib/calendar_view/chinese_calendar_utils.dart → lib/utils/chinese_calendar_utils.dart

@@ -665,14 +665,9 @@ class CalendarUtils {
     return CalendarInfo(
       lunarDate: lunarDate,
       solarDate: solarDate,
-      // animal: getAnimal(solarDate.year),
-      astro: toAstro(solarDate.month, solarDate.day),
       lunarYearName: toGanZhiYear(lunarDate!.year),
       lunarMonthName: toChinaMonth(lunarDate.month),
       lunarDayName: toChinaDay(lunarDate.day),
-      gzYear: gzYear,
-      gzMonth: gzMonth,
-      gzDay: gzDay,
       term: term,
       festival: _festival['${solarDate.month}-${solarDate.day}'],
       lunarFestival: _lfestival['${lunarDate.month}-${lunarDate.day}'],
@@ -710,15 +705,6 @@ class CalendarInfo {
   final String? lunarYearName;
   final String? lunarMonthName;
   final String? lunarDayName;
-
-  //生肖
-  final String? animal;
-
-  //星座
-  final String? astro;
-  final String? gzYear;
-  final String? gzMonth;
-  final String? gzDay;
   final String? term;
   final String? festival;
   final String? lunarFestival;
@@ -729,11 +715,6 @@ class CalendarInfo {
     this.lunarYearName,
     this.lunarMonthName,
     this.lunarDayName,
-    this.animal,
-    this.astro,
-    this.gzYear,
-    this.gzMonth,
-    this.gzDay,
     this.term,
     this.festival,
     this.lunarFestival,

+ 38 - 0
lib/utils/event_type.dart

@@ -0,0 +1,38 @@
+typedef FEventCallback<T> = void Function(Object sender, T e);
+
+class FEventHandler<T> {
+  List<FEventCallback<T>>? _callbacks;
+  bool _isDispoed = false;
+
+  void emit(Object sender, T e) {
+    if (_isDispoed) return;
+
+    if (_callbacks != null && _callbacks!.isNotEmpty) {
+      for (final callback in _callbacks!) {
+        callback.call(sender, e);
+      }
+    }
+  }
+
+  void addListener(FEventCallback<T> callback) {
+    if (_isDispoed) return;
+
+    _callbacks ??= [];
+    _callbacks!.add(callback);
+  }
+
+  void removeListener(FEventCallback<T> callback) {
+    if (_isDispoed) return;
+    if (_callbacks == null) return;
+
+    if (_callbacks!.contains(callback)) {
+      _callbacks!.remove(callback);
+    }
+  }
+
+  void dispose() {
+    _isDispoed = true;
+    _callbacks?.clear();
+    _callbacks = null;
+  }
+}

+ 0 - 56
lib/utils/throttle.dart

@@ -1,56 +0,0 @@
-import 'dart:async';
-
-// 节流函数列表
-Map<String, Timer> _funcThrottle = {};
-// 节流函数上次触发的时间
-Map<String, DateTime> _funcThrottleLastCall = {};
-Function? _lastFunc;
-
-/// 函数节流
-///
-/// [func]: 要执行的方法
-/// [funcTag]: 方法标识符
-/// [milliseconds]: 要迟延的毫秒时间
-Function throttle(Function func, String funcTag, [int milliseconds = 2000]) {
-  target() {
-    // print('对 $funcTag 进行函数节流');
-    String key = funcTag.toString();
-    Timer? _timer = _funcThrottle[key];
-    if (_timer == null) {
-      // 判断是否是第一次调用
-      if (_funcThrottleLastCall[key] == null) {
-        func.call();
-        _funcThrottleLastCall[key] = DateTime.now();
-      } else {
-        // 判断是否超过了延迟时间
-        if (DateTime.now()
-                .difference(_funcThrottleLastCall[key]!)
-                .inMilliseconds >
-            milliseconds) {
-          _funcThrottleLastCall[key] = DateTime.now();
-          func.call();
-        } else {
-          _lastFunc = func;
-        }
-      }
-      _timer = Timer(Duration(milliseconds: milliseconds), () {
-        final lastFunc = _lastFunc;
-        if (lastFunc != null) {
-          _lastFunc!.call();
-          _funcThrottleLastCall[key] = DateTime.now();
-          _lastFunc = null;
-        }
-        Timer? t = _funcThrottle.remove(key);
-        t?.cancel();
-        t = null;
-      });
-      _funcThrottle[key] = _timer;
-    } else {
-      _lastFunc = func;
-    }
-  }
-
-  target();
-
-  return target;
-}

+ 4 - 4
pubspec.lock

@@ -75,14 +75,14 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
-  intl:
+  get:
     dependency: "direct main"
     description:
-      name: intl
-      sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6
+      name: get
+      sha256: "2ba20a47c8f1f233bed775ba2dd0d3ac97b4cf32fc17731b3dfc672b06b0e92a"
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "0.18.0"
+    version: "4.6.5"
   js:
     dependency: transitive
     description:

+ 1 - 0
pubspec.yaml

@@ -36,6 +36,7 @@ dependencies:
   # The following adds the Cupertino Icons font to your application.
   # Use with the CupertinoIcons class for iOS style icons.
   cupertino_icons: ^1.0.2
+  get: ^4.6.5
 
 dev_dependencies:
   flutter_test: