Quellcode durchsuchen

chore: add calendar_view package (#1690)

* chore: add calendar_view package

* chore: improve calendar navigator

* style: improve readability

* chore: localization and moving constants
Richard Shiue vor 2 Jahren
Ursprung
Commit
707ea4c8c8

+ 8 - 2
frontend/app_flowy/assets/translations/en.json

@@ -166,7 +166,7 @@
         "dark": "Dark Mode",
         "system": "Adapt to System"
       },
-      "theme":"Theme"
+      "theme": "Theme"
     },
     "files": {
       "defaultLocation": "Where your data is stored now",
@@ -322,6 +322,12 @@
     }
   },
   "calendar": {
-    "menuName": "Calendar"
+    "menuName": "Calendar",
+    "navigation": {
+      "today": "Today",
+      "jumpToday": "Jump to Today",
+      "previousMonth": "Previous Month",
+      "nextMonth": "Next Month"
+    }
   }
 }

+ 3 - 25
frontend/app_flowy/lib/plugins/calendar/calendar.dart

@@ -7,6 +7,7 @@ import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
 import 'package:flutter/material.dart';
 
 import '../util.dart';
+import 'presentation/calendar_page.dart';
 
 class CalendarPluginBuilder extends PluginBuilder {
   @override
@@ -79,33 +80,10 @@ class CalendarPluginDisplay extends PluginDisplay {
       });
     });
 
-    return BlankPage(key: ValueKey(view.id));
-    // return BoardPage(key: ValueKey(view.id), view: view);
+    return CalendarPage(key: ValueKey(view.id));
+    // return CalendarPage(key: ValueKey(view.id), view: view);
   }
 
   @override
   List<NavigationItem> get navigationItems => [this];
 }
-
-// mark for removal
-class BlankPage extends StatefulWidget {
-  const BlankPage({Key? key}) : super(key: key);
-
-  @override
-  State<BlankPage> createState() => _BlankPageState();
-}
-
-class _BlankPageState extends State<BlankPage> {
-  @override
-  Widget build(BuildContext context) {
-    return SizedBox.expand(
-      child: Container(
-        color: Theme.of(context).colorScheme.surface,
-        child: Padding(
-          padding: const EdgeInsets.all(10),
-          child: Container(),
-        ),
-      ),
-    );
-  }
-}

+ 162 - 0
frontend/app_flowy/lib/plugins/calendar/presentation/calendar_page.dart

@@ -0,0 +1,162 @@
+import 'package:app_flowy/generated/locale_keys.g.dart';
+import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart';
+import 'package:calendar_view/calendar_view.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flowy_infra/image.dart';
+import 'package:flowy_infra/size.dart';
+import 'package:flowy_infra/theme_extension.dart';
+import 'package:flowy_infra_ui/style_widget/button.dart';
+import 'package:flowy_infra_ui/style_widget/icon_button.dart';
+import 'package:flowy_infra_ui/style_widget/text.dart';
+import 'package:flutter/material.dart';
+import 'package:styled_widget/styled_widget.dart';
+
+import 'layout/sizes.dart';
+import 'toolbar/calendar_toolbar.dart';
+
+class CalendarPage extends StatelessWidget {
+  const CalendarPage({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const CalendarContent();
+  }
+}
+
+class CalendarContent extends StatefulWidget {
+  const CalendarContent({super.key});
+
+  @override
+  State<CalendarContent> createState() => _CalendarContentState();
+}
+
+class _CalendarContentState extends State<CalendarContent> {
+  late EventController _eventController;
+  GlobalKey<MonthViewState>? _calendarState;
+
+  @override
+  void initState() {
+    _eventController = EventController();
+    _calendarState = GlobalKey<MonthViewState>();
+    super.initState();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return CalendarControllerProvider(
+      controller: _eventController,
+      child: Column(
+        children: [
+          // const _ToolbarBlocAdaptor(),
+          _toolbar(),
+          _buildCalendar(_eventController),
+        ],
+      ),
+    );
+  }
+
+  Widget _toolbar() {
+    return const CalendarToolbar();
+  }
+
+  Widget _buildCalendar(EventController eventController) {
+    return Expanded(
+      child: MonthView(
+        key: _calendarState,
+        controller: _eventController,
+        cellAspectRatio: 1.75,
+        borderColor: Theme.of(context).dividerColor,
+        headerBuilder: _headerNavigatorBuilder,
+        weekDayBuilder: _headerWeekDayBuilder,
+        cellBuilder: _calendarDayBuilder,
+      ),
+    );
+  }
+
+  Widget _headerNavigatorBuilder(DateTime currentMonth) {
+    return Row(
+      children: [
+        FlowyText.medium(
+          DateFormat('MMMM y', context.locale.toLanguageTag())
+              .format(currentMonth),
+        ),
+        const Spacer(),
+        FlowyIconButton(
+          width: CalendarSize.navigatorButtonWidth,
+          height: CalendarSize.navigatorButtonHeight,
+          icon: svgWidget('home/arrow_left'),
+          tooltipText: LocaleKeys.calendar_navigation_previousMonth.tr(),
+          hoverColor: AFThemeExtension.of(context).lightGreyHover,
+          onPressed: () => _calendarState?.currentState?.previousPage(),
+        ),
+        FlowyTextButton(
+          LocaleKeys.calendar_navigation_today.tr(),
+          fillColor: Colors.transparent,
+          fontWeight: FontWeight.w500,
+          tooltip: LocaleKeys.calendar_navigation_jumpToday.tr(),
+          padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 4),
+          hoverColor: AFThemeExtension.of(context).lightGreyHover,
+          onPressed: () =>
+              _calendarState?.currentState?.animateToMonth(DateTime.now()),
+        ),
+        FlowyIconButton(
+          width: CalendarSize.navigatorButtonWidth,
+          height: CalendarSize.navigatorButtonHeight,
+          icon: svgWidget('home/arrow_right'),
+          tooltipText: LocaleKeys.calendar_navigation_nextMonth.tr(),
+          hoverColor: AFThemeExtension.of(context).lightGreyHover,
+          onPressed: () => _calendarState?.currentState?.nextPage(),
+        ),
+      ],
+    );
+  }
+
+  Widget _headerWeekDayBuilder(day) {
+    final symbols = DateFormat.EEEE(context.locale.toLanguageTag()).dateSymbols;
+    final weekDayString = symbols.WEEKDAYS[day];
+    return Center(
+      child: Padding(
+        padding: CalendarSize.daysOfWeekInsets,
+        child: FlowyText.medium(
+          weekDayString,
+          color: Theme.of(context).hintColor,
+        ),
+      ),
+    );
+  }
+
+  Widget _calendarDayBuilder(date, event, isToday, isInMonth) {
+    Color dayTextColor = Theme.of(context).colorScheme.onSurface;
+    Color cellBackgroundColor = Theme.of(context).colorScheme.surface;
+    String dayString = date.day == 1
+        ? DateFormat('MMM d', context.locale.toLanguageTag()).format(date)
+        : date.day.toString();
+
+    if (isToday) {
+      dayTextColor = Theme.of(context).colorScheme.onPrimary;
+    }
+    if (!isInMonth) {
+      dayTextColor = Theme.of(context).disabledColor;
+      cellBackgroundColor = AFThemeExtension.of(context).lightGreyHover;
+    }
+    Widget day = Container(
+      decoration: BoxDecoration(
+        color: isToday ? Theme.of(context).colorScheme.primary : null,
+        borderRadius: Corners.s6Border,
+      ),
+      padding: GridSize.typeOptionContentInsets,
+      child: FlowyText.medium(
+        dayString,
+        color: dayTextColor,
+      ),
+    );
+
+    return Container(
+      color: cellBackgroundColor,
+      child: Align(
+        alignment: Alignment.topRight,
+        child: day.padding(all: 6.0),
+      ),
+    );
+  }
+}

+ 11 - 0
frontend/app_flowy/lib/plugins/calendar/presentation/layout/sizes.dart

@@ -0,0 +1,11 @@
+import 'package:flutter/widgets.dart';
+
+class CalendarSize {
+  static double scale = 1;
+
+  static double get scrollBarSize => 12 * scale;
+  static double get navigatorButtonWidth => 20 * scale;
+  static double get navigatorButtonHeight => 25 * scale;
+  static EdgeInsets get daysOfWeekInsets =>
+      EdgeInsets.symmetric(vertical: 10.0 * scale);
+}

+ 23 - 0
frontend/app_flowy/lib/plugins/calendar/presentation/toolbar/calendar_toolbar.dart

@@ -0,0 +1,23 @@
+import 'package:flowy_infra_ui/style_widget/button.dart';
+import 'package:flutter/material.dart';
+
+class CalendarToolbar extends StatelessWidget {
+  const CalendarToolbar({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return SizedBox(
+      height: 40,
+      child: Row(
+        mainAxisAlignment: MainAxisAlignment.end,
+        children: const [
+          FlowyTextButton(
+            "Settings",
+            fillColor: Colors.transparent,
+            padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 7 - 0
frontend/app_flowy/pubspec.lock

@@ -155,6 +155,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "8.3.2"
+  calendar_view:
+    dependency: "direct main"
+    description:
+      name: calendar_view
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.1"
   characters:
     dependency: transitive
     description:

+ 1 - 0
frontend/app_flowy/pubspec.yaml

@@ -93,6 +93,7 @@ dependencies:
   percent_indicator: ^4.0.1
   appflowy_editor_plugins:
     path: packages/appflowy_editor_plugins
+  calendar_view: ^1.0.1
 
 dev_dependencies:
   flutter_lints: ^2.0.1